1 /* $NetBSD: setkey.c,v 1.13 2009/03/06 11:45:03 tteras Exp $ */
3 /* $KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $ */
6 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
43 #include <sys/sysctl.h>
45 #include <netinet/in.h>
46 #include <net/pfkeyv2.h>
62 #include <readline/readline.h>
63 #include <readline/history.h>
68 #include "package_version.h"
69 #define extern /* so that variables in extern.h are not extern... */
72 #define strlcpy(d,s,l) (strncpy(d,s,l), (d)[(l)-1] = '\0')
74 void usage
__P((int));
75 int main
__P((int, char **));
76 int get_supported
__P((void));
77 void sendkeyshort
__P((u_int
));
78 void promisc
__P((void));
79 int postproc
__P((struct sadb_msg
*, int));
80 int verifypriority
__P((struct sadb_msg
*m
));
81 int fileproc
__P((const char *));
82 const char *numstr
__P((int));
83 void shortdump_hdr
__P((void));
84 void shortdump
__P((struct sadb_msg
*));
85 static void printdate
__P((void));
86 static int32_t gmt2local
__P((time_t));
87 void stdin_loop
__P((void));
90 #define MODE_CMDDUMP 2
91 #define MODE_CMDFLUSH 3
92 #define MODE_PROMISC 4
107 #ifdef HAVE_POLICY_FWD
113 static void rkwarn(void);
119 printf("warning: -r and -k options are not supported in this environment\n");
124 static time_t thiszone
;
127 usage(int only_version
)
129 printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING
, TOP_PACKAGE_URL
);
130 if (! only_version
) {
131 printf("usage: setkey [-v" RK_OPTS
"] file ...\n");
132 printf(" setkey [-nv" RK_OPTS
"] -c\n");
133 printf(" setkey [-nv" RK_OPTS
"] -f filename\n");
134 printf(" setkey [-Palpv" RK_OPTS
"] -D\n");
135 printf(" setkey [-Pv] -F\n");
136 printf(" setkey [-H] -x\n");
137 printf(" setkey [-V] [-h]\n");
155 thiszone
= gmt2local(0);
157 while ((c
= getopt(argc
, argv
, "acdf:HlnvxDFPphVrk?")) != -1) {
162 /* disable filename completion */
163 rl_bind_key('\t', rl_insert
);
167 f_mode
= MODE_SCRIPT
;
168 if ((fp
= fopen(optarg
, "r")) == NULL
) {
174 f_mode
= MODE_CMDDUMP
;
177 f_mode
= MODE_CMDFLUSH
;
195 f_mode
= MODE_PROMISC
;
208 #ifdef HAVE_POLICY_FWD
215 #ifdef HAVE_POLICY_FWD
240 if (fileproc(*argv
++) < 0) {
241 err(1, "%s", argv
[-1]);
249 perror("pfkey_open");
255 sendkeyshort(f_policy
? SADB_X_SPDDUMP
: SADB_DUMP
);
258 sendkeyshort(f_policy
? SADB_X_SPDFLUSH
: SADB_FLUSH
);
261 if (get_supported() < 0) {
262 errx(1, "%s", ipsec_strerror());
269 if (get_supported() < 0) {
270 errx(1, "%s", ipsec_strerror());
290 if (pfkey_send_register(so
, SADB_SATYPE_UNSPEC
) < 0)
293 if (pfkey_recv_register(so
) < 0)
302 char line
[1024], *semicolon
, *comment
;
305 memset (line
, 0, sizeof(line
));
311 rbuf
= readline ("");
317 if (fgets(rbuf
, sizeof(rbuf
), stdin
) == NULL
)
319 if (rbuf
[strlen(rbuf
)-1] == '\n')
320 rbuf
[strlen(rbuf
)-1] = '\0';
322 comment
= strchr(rbuf
, '#');
329 linelen
+= snprintf (&line
[linelen
], sizeof(line
) - linelen
,
330 "%s%s", linelen
> 0 ? " " : "", rbuf
);
332 semicolon
= strchr(line
, ';');
334 char saved_char
= *++semicolon
;
340 #ifdef HAVE_PFKEY_POLICY_PRIORITY
341 last_msg_type
= -1; /* invalid message type */
348 *semicolon
= saved_char
;
349 linelen
= strlen (semicolon
);
350 memmove (line
, semicolon
, linelen
+ 1);
351 semicolon
= strchr(line
, ';');
367 msg
.sadb_msg_version
= PF_KEY_V2
;
368 msg
.sadb_msg_type
= type
;
369 msg
.sadb_msg_errno
= 0;
370 msg
.sadb_msg_satype
= SADB_SATYPE_UNSPEC
;
371 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
372 msg
.sadb_msg_reserved
= 0;
373 msg
.sadb_msg_seq
= 0;
374 msg
.sadb_msg_pid
= getpid();
376 sendkeymsg((char *)&msg
, sizeof(msg
));
385 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
388 msg
.sadb_msg_version
= PF_KEY_V2
;
389 msg
.sadb_msg_type
= SADB_X_PROMISC
;
390 msg
.sadb_msg_errno
= 0;
391 msg
.sadb_msg_satype
= 1;
392 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
393 msg
.sadb_msg_reserved
= 0;
394 msg
.sadb_msg_seq
= 0;
395 msg
.sadb_msg_pid
= getpid();
397 if ((l
= send(so
, &msg
, sizeof(msg
), 0)) < 0) {
403 struct sadb_msg
*base
;
405 if ((l
= recv(so
, rbuf
, sizeof(*base
), MSG_PEEK
)) < 0) {
410 if (l
!= sizeof(*base
))
413 base
= (struct sadb_msg
*)rbuf
;
414 if ((l
= recv(so
, rbuf
, PFKEY_UNUNIT64(base
->sadb_msg_len
),
422 for (i
= 0; i
< l
; i
++) {
425 printf("%02x ", rbuf
[i
] & 0xff);
432 /* adjust base pointer for promisc mode */
433 if (base
->sadb_msg_type
== SADB_X_PROMISC
) {
434 if ((ssize_t
)sizeof(*base
) < l
)
447 /* Generate 'spi' array with SPIs matching 'satype', 'srcs', and 'dsts'
448 * Return value is dynamically generated array of SPIs, also number of
449 * SPIs through num_spi pointer.
450 * On any error, set *num_spi to 0 and return NULL.
453 sendkeymsg_spigrep(satype
, srcs
, dsts
, num_spi
)
455 struct addrinfo
*srcs
;
456 struct addrinfo
*dsts
;
459 struct sadb_msg msg
, *m
;
463 u_char rbuf
[1024 * 32];
464 caddr_t mhp
[SADB_EXT_MAX
+ 1];
465 struct sadb_address
*saddr
;
469 u_int32_t
*spi
= NULL
;
470 int max_spi
= 0, fail
= 0;
482 if (setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
)) < 0) {
483 perror("setsockopt");
488 msg
.sadb_msg_version
= PF_KEY_V2
;
489 msg
.sadb_msg_type
= SADB_DUMP
;
490 msg
.sadb_msg_errno
= 0;
491 msg
.sadb_msg_satype
= satype
;
492 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
493 msg
.sadb_msg_reserved
= 0;
494 msg
.sadb_msg_seq
= 0;
495 msg
.sadb_msg_pid
= getpid();
505 for (i
= 0; i
< len
; i
++) {
508 printf("%02x ", buf
[i
] & 0xff);
516 if ((l
= send(so
, buf
, len
, 0)) < 0) {
521 m
= (struct sadb_msg
*)rbuf
;
523 if ((l
= recv(so
, rbuf
, sizeof(rbuf
), 0)) < 0) {
529 if (PFKEY_UNUNIT64(m
->sadb_msg_len
) != l
) {
530 warnx("invalid keymsg length");
540 if (m
->sadb_msg_type
!= SADB_DUMP
) {
541 warnx("unexpected message type");
546 if (m
->sadb_msg_errno
!= 0) {
547 warnx("error encountered");
553 if (m
->sadb_msg_satype
!= satype
)
560 saddr
= (struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_SRC
];
563 s
= (struct sockaddr
*)(saddr
+ 1);
564 for (a
= srcs
; a
; a
= a
->ai_next
)
565 if (memcmp(a
->ai_addr
, s
, a
->ai_addrlen
) == 0)
571 saddr
= (struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_DST
];
574 s
= (struct sockaddr
*)(saddr
+ 1);
575 for (a
= dsts
; a
; a
= a
->ai_next
)
576 if (memcmp(a
->ai_addr
, s
, a
->ai_addrlen
) == 0)
581 if (*num_spi
>= max_spi
) {
583 spi
= realloc(spi
, max_spi
* sizeof(u_int32_t
));
586 sa
= (struct sadb_sa
*)mhp
[SADB_EXT_SA
];
588 spi
[(*num_spi
)++] = (u_int32_t
)ntohl(sa
->sadb_sa_spi
);
590 m
= (struct sadb_msg
*)((caddr_t
)m
+ PFKEY_UNUNIT64(m
->sadb_msg_len
));
597 } while (m
->sadb_msg_seq
);
613 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
615 struct sadb_msg
*msg
;
625 if (setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
)) < 0) {
626 perror("setsockopt");
635 kdebug_sadb((struct sadb_msg
*)buf
);
640 for (i
= 0; i
< len
; i
++) {
643 printf("%02x ", buf
[i
] & 0xff);
651 if ((l
= send(so
, buf
, len
, 0)) < 0) {
656 msg
= (struct sadb_msg
*)rbuf
;
658 if ((l
= recv(so
, rbuf
, sizeof(rbuf
), 0)) < 0) {
663 if (PFKEY_UNUNIT64(msg
->sadb_msg_len
) != l
) {
664 warnx("invalid keymsg length");
672 if (postproc(msg
, l
) < 0)
674 } while (msg
->sadb_msg_errno
|| msg
->sadb_msg_seq
);
688 struct sadb_msg
*msg
;
691 #ifdef HAVE_PFKEY_POLICY_PRIORITY
692 static int priority_support_check
= 0;
695 if (msg
->sadb_msg_errno
!= 0) {
697 const char *errmsg
= NULL
;
699 if (f_mode
== MODE_SCRIPT
)
700 snprintf(inf
, sizeof(inf
), "The result of line %d: ", lineno
);
704 switch (msg
->sadb_msg_errno
) {
706 switch (msg
->sadb_msg_type
) {
709 case SADB_X_SPDDELETE
:
713 errmsg
= "No SAD entries";
716 errmsg
= "No SPD entries";
721 errmsg
= strerror(msg
->sadb_msg_errno
);
723 printf("%s%s.\n", inf
, errmsg
);
727 switch (msg
->sadb_msg_type
) {
730 pfkey_sadump_withports(msg
);
736 /* filter out DEAD SAs */
738 caddr_t mhp
[SADB_EXT_MAX
+ 1];
740 pfkey_align(msg
, mhp
);
742 if ((sa
= (struct sadb_sa
*)mhp
[SADB_EXT_SA
]) != NULL
) {
743 if (sa
->sadb_sa_state
== SADB_SASTATE_DEAD
)
748 /* TODO: f_withports */
752 pfkey_sadump_withports(msg
);
756 msg
= (struct sadb_msg
*)((caddr_t
)msg
+
757 PFKEY_UNUNIT64(msg
->sadb_msg_len
));
759 kdebug_sadb((struct sadb_msg
*)msg
);
766 pfkey_spdump_withports(msg
);
773 pfkey_spdump_withports(msg
);
776 if (msg
->sadb_msg_seq
== 0) break;
777 msg
= (struct sadb_msg
*)((caddr_t
)msg
+
778 PFKEY_UNUNIT64(msg
->sadb_msg_len
));
780 kdebug_sadb((struct sadb_msg
*)msg
);
784 #ifdef HAVE_PFKEY_POLICY_PRIORITY
786 if (last_msg_type
== SADB_X_SPDADD
&& last_priority
!= 0 &&
787 msg
->sadb_msg_pid
== getpid() && !priority_support_check
) {
788 priority_support_check
= 1;
789 if (!verifypriority(msg
))
790 printf ("WARNING: Kernel does not support policy priorities\n");
799 #ifdef HAVE_PFKEY_POLICY_PRIORITY
804 caddr_t mhp
[SADB_EXT_MAX
+ 1];
805 struct sadb_x_policy
*xpl
;
807 /* check pfkey message. */
808 if (pfkey_align(m
, mhp
)) {
809 printf("(%s\n", ipsec_strerror());
812 if (pfkey_check(mhp
)) {
813 printf("%s\n", ipsec_strerror());
817 xpl
= (struct sadb_x_policy
*) mhp
[SADB_X_EXT_POLICY
];
820 printf("no X_POLICY extension.\n");
824 /* now make sure they match */
825 if (last_priority
!= xpl
->sadb_x_policy_priority
)
834 const char *filename
;
839 struct sadb_msg
*msg
;
840 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
842 fd
= open(filename
, O_RDONLY
);
848 len
= read(fd
, rbuf
+ l
, sizeof(rbuf
) - l
);
857 if (l
< sizeof(struct sadb_msg
)) {
868 msg
= (struct sadb_msg
*)p
;
869 len
= PFKEY_UNUNIT64(msg
->sadb_msg_len
);
878 /*------------------------------------------------------------*/
879 static const char *satype
[] = {
880 NULL
, NULL
, "ah", "esp"
882 static const char *sastate
[] = {
885 static const char *ipproto
[] = {
886 /*0*/ "ip", "icmp", "igmp", "ggp", "ip4",
887 NULL
, "tcp", NULL
, "egp", NULL
,
888 /*10*/ NULL
, NULL
, NULL
, NULL
, NULL
,
889 NULL
, NULL
, "udp", NULL
, NULL
,
890 /*20*/ NULL
, NULL
, "idp", NULL
, NULL
,
891 NULL
, NULL
, NULL
, NULL
, "tp",
892 /*30*/ NULL
, NULL
, NULL
, NULL
, NULL
,
893 NULL
, NULL
, NULL
, NULL
, NULL
,
894 /*40*/ NULL
, "ip6", NULL
, "rt6", "frag6",
895 NULL
, "rsvp", "gre", NULL
, NULL
,
896 /*50*/ "esp", "ah", NULL
, NULL
, NULL
,
897 NULL
, NULL
, NULL
, "icmp6", "none",
901 #define STR_OR_ID(x, tab) \
902 (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x))
909 snprintf(buf
, sizeof(buf
), "#%d", x
);
916 printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
917 "time", "p", "s", "spi", "ltime", "src", "dst");
922 struct sadb_msg
*msg
;
924 caddr_t mhp
[SADB_EXT_MAX
+ 1];
925 char buf
[NI_MAXHOST
], pbuf
[NI_MAXSERV
];
927 struct sadb_address
*saddr
;
928 struct sadb_lifetime
*lts
, *lth
, *ltc
;
931 time_t cur
= time(0);
933 pfkey_align(msg
, mhp
);
936 printf("%02lu%02lu", (u_long
)(cur
% 3600) / 60, (u_long
)(cur
% 60));
938 printf(" %-3s", STR_OR_ID(msg
->sadb_msg_satype
, satype
));
940 if ((sa
= (struct sadb_sa
*)mhp
[SADB_EXT_SA
]) != NULL
) {
941 printf(" %-1s", STR_OR_ID(sa
->sadb_sa_state
, sastate
));
942 printf(" %08x", (u_int32_t
)ntohl(sa
->sadb_sa_spi
));
944 printf("%-1s %-8s", "?", "?");
946 lts
= (struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_SOFT
];
947 lth
= (struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_HARD
];
948 ltc
= (struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_CURRENT
];
949 if (lts
&& lth
&& ltc
) {
950 if (ltc
->sadb_lifetime_addtime
== 0)
953 t
= (u_long
)(cur
- ltc
->sadb_lifetime_addtime
);
955 strlcpy(buf
, " big/", sizeof(buf
));
957 snprintf(buf
, sizeof(buf
), " %3lu/", (u_long
)t
);
960 t
= (u_long
)lth
->sadb_lifetime_addtime
;
962 strlcpy(buf
, "big", sizeof(buf
));
964 snprintf(buf
, sizeof(buf
), "%-3lu", (u_long
)t
);
967 printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */
971 if ((saddr
= (struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_SRC
]) != NULL
) {
972 if (saddr
->sadb_address_proto
)
973 printf("%s ", STR_OR_ID(saddr
->sadb_address_proto
, ipproto
));
974 s
= (struct sockaddr
*)(saddr
+ 1);
975 getnameinfo(s
, sysdep_sa_len(s
), buf
, sizeof(buf
),
976 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
|NI_NUMERICSERV
);
977 if (strcmp(pbuf
, "0") != 0)
978 printf("%s[%s]", buf
, pbuf
);
986 if ((saddr
= (struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_DST
]) != NULL
) {
987 if (saddr
->sadb_address_proto
)
988 printf("%s ", STR_OR_ID(saddr
->sadb_address_proto
, ipproto
));
990 s
= (struct sockaddr
*)(saddr
+ 1);
991 getnameinfo(s
, sysdep_sa_len(s
), buf
, sizeof(buf
),
992 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
|NI_NUMERICSERV
);
993 if (strcmp(pbuf
, "0") != 0)
994 printf("%s[%s]", buf
, pbuf
);
1003 /* From: tcpdump(1):gmt2local.c and util.c */
1005 * Print the timestamp
1013 if (gettimeofday(&tp
, NULL
) == -1) {
1014 perror("gettimeofday");
1020 s
= (tp
.tv_sec
+ thiszone
) % 86400;
1021 (void)printf("%02d:%02d:%02d.%06u ",
1022 s
/ 3600, (s
% 3600) / 60, s
% 60, (u_int32_t
)tp
.tv_usec
);
1023 } else if (f_tflag
> 1) {
1024 /* Unix timeval style */
1025 (void)printf("%u.%06u ",
1026 (u_int32_t
)tp
.tv_sec
, (u_int32_t
)tp
.tv_usec
);
1033 * Returns the difference between gmt and local time in seconds.
1034 * Use gmtime() and localtime() to keep things simple.
1039 register int dt
, dir
;
1040 register struct tm
*gmt
, *loc
;
1047 loc
= localtime(&t
);
1048 dt
= (loc
->tm_hour
- gmt
->tm_hour
) * 60 * 60 +
1049 (loc
->tm_min
- gmt
->tm_min
) * 60;
1052 * If the year or julian day is different, we span 00:00 GMT
1053 * and must add or subtract a day. Check the year first to
1054 * avoid problems when the julian day wraps.
1056 dir
= loc
->tm_year
- gmt
->tm_year
;
1058 dir
= loc
->tm_yday
- gmt
->tm_yday
;
1059 dt
+= dir
* 24 * 60 * 60;