1 /* $KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $ */
4 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
41 #include <sys/sysctl.h>
43 #include <netinet/in.h>
44 #include <net/pfkeyv2.h>
45 #ifdef HAVE_NETINET6_IPSEC
46 # include <netinet6/ipsec.h>
48 # include <netinet/ipsec.h>
64 #include <readline/readline.h>
65 #include <readline/history.h>
71 //#include "package_version.h"
72 #define extern /* so that variables in extern.h are not extern... */
76 int main (int, char **);
77 int get_supported (void);
78 void sendkeyshort (u_int
);
80 int postproc (struct sadb_msg
*, int);
81 int verifypriority (struct sadb_msg
*m
);
82 int fileproc (const char *);
83 const char *numstr (int);
84 void shortdump_hdr (void);
85 void shortdump (struct sadb_msg
*);
86 static void printdate (void);
87 static int32_t gmt2local (time_t);
88 void stdin_loop (void);
91 #define MODE_CMDDUMP 2
92 #define MODE_CMDFLUSH 3
93 #define MODE_PROMISC 4
108 #ifdef HAVE_POLICY_FWD
114 static void rkwarn(void);
120 printf("warning: -r and -k options are not supported in this environment\n");
125 static time_t thiszone
;
128 usage(/*int only_version*/)
130 //printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL);
131 //if (! only_version) {
132 printf("usage: setkey [-v" RK_OPTS
"] file ...\n");
133 printf(" setkey [-nv" RK_OPTS
"] -c\n");
134 printf(" setkey [-nv" RK_OPTS
"] -f filename\n");
135 printf(" setkey [-Palpv" RK_OPTS
"] -D\n");
136 printf(" setkey [-Pv] -F\n");
137 printf(" setkey [-H] -x\n");
138 printf(" setkey [-V] [-h]\n");
156 thiszone
= gmt2local(0);
158 while ((c
= getopt(argc
, argv
, "acdf:HlnvxDFPphVrk?")) != -1) {
163 /* disable filename completion */
164 rl_bind_key('\t', rl_insert
);
168 f_mode
= MODE_SCRIPT
;
169 if ((fp
= fopen(optarg
, "r")) == NULL
) {
175 f_mode
= MODE_CMDDUMP
;
178 f_mode
= MODE_CMDFLUSH
;
196 f_mode
= MODE_PROMISC
;
209 #ifdef HAVE_POLICY_FWD
216 #ifdef HAVE_POLICY_FWD
241 if (fileproc(*argv
++) < 0) {
242 err(1, "%s", argv
[-1]);
250 perror("pfkey_open");
256 sendkeyshort(f_policy
? SADB_X_SPDDUMP
: SADB_DUMP
);
259 sendkeyshort(f_policy
? SADB_X_SPDFLUSH
: SADB_FLUSH
);
262 if (get_supported() < 0) {
263 errx(1, "%s", ipsec_strerror());
270 if (get_supported() < 0) {
271 errx(1, "%s", ipsec_strerror());
291 if (pfkey_send_register(so
, SADB_SATYPE_UNSPEC
) < 0)
294 if (pfkey_recv_register(so
) < 0)
303 char line
[1024], *semicolon
, *comment
;
306 memset (line
, 0, sizeof(line
));
312 rbuf
= readline ("");
318 if (fgets(rbuf
, sizeof(rbuf
), stdin
) == NULL
)
320 if (rbuf
[strlen(rbuf
)-1] == '\n')
321 rbuf
[strlen(rbuf
)-1] = '\0';
323 comment
= strchr(rbuf
, '#');
330 linelen
+= snprintf (&line
[linelen
], sizeof(line
) - linelen
,
331 "%s%s", linelen
> 0 ? " " : "", rbuf
);
333 semicolon
= strchr(line
, ';');
335 char saved_char
= *++semicolon
;
341 #ifdef HAVE_PFKEY_POLICY_PRIORITY
342 last_msg_type
= -1; /* invalid message type */
349 *semicolon
= saved_char
;
350 linelen
= strlen (semicolon
);
351 memmove (line
, semicolon
, linelen
+ 1);
352 semicolon
= strchr(line
, ';');
368 msg
.sadb_msg_version
= PF_KEY_V2
;
369 msg
.sadb_msg_type
= type
;
370 msg
.sadb_msg_errno
= 0;
371 msg
.sadb_msg_satype
= SADB_SATYPE_UNSPEC
;
372 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
373 msg
.sadb_msg_reserved
= 0;
374 msg
.sadb_msg_seq
= 0;
375 msg
.sadb_msg_pid
= getpid();
377 sendkeymsg((char *)&msg
, sizeof(msg
));
386 union { // Wcast-align fix - force alignment
387 u_int64_t force_align
;
388 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
392 msg
.sadb_msg_version
= PF_KEY_V2
;
393 msg
.sadb_msg_type
= SADB_X_PROMISC
;
394 msg
.sadb_msg_errno
= 0;
395 msg
.sadb_msg_satype
= 1;
396 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
397 msg
.sadb_msg_reserved
= 0;
398 msg
.sadb_msg_seq
= 0;
399 msg
.sadb_msg_pid
= getpid();
401 if ((l
= send(so
, &msg
, sizeof(msg
), 0)) < 0) {
407 struct sadb_msg
*base
;
409 if ((l
= recv(so
, u_buf
.rbuf
, sizeof(*base
), MSG_PEEK
)) < 0) {
414 if (l
!= sizeof(*base
))
417 base
= (struct sadb_msg
*)&u_buf
;
418 if ((l
= recv(so
, u_buf
.rbuf
, PFKEY_UNUNIT64(base
->sadb_msg_len
),
426 for (i
= 0; i
< l
; i
++) {
429 printf("%02x ", u_buf
.rbuf
[i
] & 0xff);
436 /* adjust base pointer for promisc mode */
437 if (base
->sadb_msg_type
== SADB_X_PROMISC
) {
438 if ((ssize_t
)sizeof(*base
) < l
)
456 union { // Wcast-align fix - force alignment
457 u_int64_t force_align
;
458 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
461 struct sadb_msg
*msg
;
471 if (setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
)) < 0) {
472 perror("setsockopt");
481 kdebug_sadb(ALIGNED_CAST(struct sadb_msg
*)buf
); // Wcast-align fix - aligned message buffer
486 for (i
= 0; i
< len
; i
++) {
489 printf("%02x ", buf
[i
] & 0xff);
497 if ((l
= send(so
, buf
, len
, 0)) < 0) {
502 msg
= (struct sadb_msg
*)&u_buf
;
504 if ((l
= recv(so
, u_buf
.rbuf
, sizeof(u_buf
.rbuf
), 0)) < 0) {
509 if (PFKEY_UNUNIT64(msg
->sadb_msg_len
) != l
) {
510 warnx("invalid keymsg length");
515 kdebug_sadb((struct sadb_msg
*)&u_buf
);
518 if (postproc(msg
, l
) < 0)
520 } while (msg
->sadb_msg_errno
|| msg
->sadb_msg_seq
);
534 struct sadb_msg
*msg
;
537 #ifdef HAVE_PFKEY_POLICY_PRIORITY
538 static int priority_support_check
= 0;
541 if (msg
->sadb_msg_errno
!= 0) {
543 const char *errmsg
= NULL
;
545 if (f_mode
== MODE_SCRIPT
)
546 snprintf(inf
, sizeof(inf
), "The result of line %d: ", lineno
);
550 switch (msg
->sadb_msg_errno
) {
552 switch (msg
->sadb_msg_type
) {
555 case SADB_X_SPDDELETE
:
559 errmsg
= "No SAD entries";
562 errmsg
= "No SPD entries";
567 errmsg
= strerror(msg
->sadb_msg_errno
);
569 printf("%s%s.\n", inf
, errmsg
);
573 switch (msg
->sadb_msg_type
) {
576 pfkey_sadump_withports(msg
);
582 /* filter out DEAD SAs */
584 caddr_t mhp
[SADB_EXT_MAX
+ 1];
586 pfkey_align(msg
, mhp
);
588 if ((sa
= ALIGNED_CAST(struct sadb_sa
*)mhp
[SADB_EXT_SA
]) != NULL
) { // Wcast-align (void*) - buffer of pointers to aligned structs in malloc'd buffer
589 if (sa
->sadb_sa_state
== SADB_SASTATE_DEAD
)
594 /* TODO: f_withports */
598 pfkey_sadump_withports(msg
);
602 msg
= ALIGNED_CAST(struct sadb_msg
*)((caddr_t
)msg
+
603 PFKEY_UNUNIT64(msg
->sadb_msg_len
)); // Wcast-align fix (void*) - aligned msg buffer passed into function
605 kdebug_sadb((struct sadb_msg
*)msg
);
612 pfkey_spdump_withports(msg
);
619 pfkey_spdump_withports(msg
);
622 if (msg
->sadb_msg_seq
== 0) break;
623 msg
= ALIGNED_CAST(struct sadb_msg
*)((caddr_t
)msg
+ // Wcast-align fix (void*) - aligned msg buffer passed into function
624 PFKEY_UNUNIT64(msg
->sadb_msg_len
));
626 kdebug_sadb((struct sadb_msg
*)msg
);
630 #ifdef HAVE_PFKEY_POLICY_PRIORITY
632 if (last_msg_type
== SADB_X_SPDADD
&& last_priority
!= 0 &&
633 msg
->sadb_msg_pid
== getpid() && !priority_support_check
) {
634 priority_support_check
= 1;
635 if (!verifypriority(msg
))
636 printf ("WARNING: Kernel does not support policy priorities\n");
645 #ifdef HAVE_PFKEY_POLICY_PRIORITY
650 caddr_t mhp
[SADB_EXT_MAX
+ 1];
651 struct sadb_x_policy
*xpl
;
653 /* check pfkey message. */
654 if (pfkey_align(m
, mhp
)) {
655 printf("(%s\n", ipsec_strerror());
658 if (pfkey_check(mhp
)) {
659 printf("%s\n", ipsec_strerror());
663 xpl
= (struct sadb_x_policy
*) mhp
[SADB_X_EXT_POLICY
];
666 printf("no X_POLICY extension.\n");
670 /* now make sure they match */
671 if (last_priority
!= xpl
->sadb_x_policy_priority
)
680 const char *filename
;
685 struct sadb_msg
*msg
;
686 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
688 fd
= open(filename
, O_RDONLY
);
694 len
= read(fd
, rbuf
+ l
, sizeof(rbuf
) - l
);
703 if (l
< sizeof(struct sadb_msg
)) {
714 msg
= ALIGNED_CAST(struct sadb_msg
*)p
;
715 len
= PFKEY_UNUNIT64(msg
->sadb_msg_len
);
724 /*------------------------------------------------------------*/
725 static const char *satype
[] = {
726 NULL
, NULL
, "ah", "esp"
728 static const char *sastate
[] = {
731 static const char *ipproto
[] = {
732 /*0*/ "ip", "icmp", "igmp", "ggp", "ip4",
733 NULL
, "tcp", NULL
, "egp", NULL
,
734 /*10*/ NULL
, NULL
, NULL
, NULL
, NULL
,
735 NULL
, NULL
, "udp", NULL
, NULL
,
736 /*20*/ NULL
, NULL
, "idp", NULL
, NULL
,
737 NULL
, NULL
, NULL
, NULL
, "tp",
738 /*30*/ NULL
, NULL
, NULL
, NULL
, NULL
,
739 NULL
, NULL
, NULL
, NULL
, NULL
,
740 /*40*/ NULL
, "ip6", NULL
, "rt6", "frag6",
741 NULL
, "rsvp", "gre", NULL
, NULL
,
742 /*50*/ "esp", "ah", NULL
, NULL
, NULL
,
743 NULL
, NULL
, NULL
, "icmp6", "none",
747 #define STR_OR_ID(x, tab) \
748 (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x))
755 snprintf(buf
, sizeof(buf
), "#%d", x
);
762 printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
763 "time", "p", "s", "spi", "ltime", "src", "dst");
768 struct sadb_msg
*msg
;
770 caddr_t mhp
[SADB_EXT_MAX
+ 1];
771 char buf
[NI_MAXHOST
], pbuf
[NI_MAXSERV
];
773 struct sadb_address
*saddr
;
774 struct sadb_lifetime
*lts
, *lth
, *ltc
;
777 time_t cur
= time(0);
779 pfkey_align(msg
, mhp
);
782 printf("%02lu%02lu", (u_long
)(cur
% 3600) / 60, (u_long
)(cur
% 60));
784 printf(" %-3s", STR_OR_ID(msg
->sadb_msg_satype
, satype
));
786 if ((sa
= ALIGNED_CAST(struct sadb_sa
*)mhp
[SADB_EXT_SA
]) != NULL
) {
787 printf(" %-1s", STR_OR_ID(sa
->sadb_sa_state
, sastate
));
788 printf(" %08x", (u_int32_t
)ntohl(sa
->sadb_sa_spi
));
790 printf("%-1s %-8s", "?", "?");
792 lts
= ALIGNED_CAST(struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_SOFT
];
793 lth
= ALIGNED_CAST(struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_HARD
];
794 ltc
= ALIGNED_CAST(struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_CURRENT
];
795 if (lts
&& lth
&& ltc
) {
796 if (ltc
->sadb_lifetime_addtime
== 0)
799 t
= (u_long
)(cur
- ltc
->sadb_lifetime_addtime
);
801 strlcpy(buf
, " big/", sizeof(buf
));
803 snprintf(buf
, sizeof(buf
), " %3lu/", (u_long
)t
);
806 t
= (u_long
)lth
->sadb_lifetime_addtime
;
808 strlcpy(buf
, "big", sizeof(buf
));
810 snprintf(buf
, sizeof(buf
), "%-3lu", (u_long
)t
);
813 printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */
817 if ((saddr
= ALIGNED_CAST(struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_SRC
]) != NULL
) {
818 if (saddr
->sadb_address_proto
)
819 printf("%s ", STR_OR_ID(saddr
->sadb_address_proto
, ipproto
));
820 s
= (struct sockaddr
*)(saddr
+ 1);
821 getnameinfo(s
, sysdep_sa_len((struct sockaddr
*)s
), buf
, sizeof(buf
),
822 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
|NI_NUMERICSERV
);
823 if (strcmp(pbuf
, "0") != 0)
824 printf("%s[%s]", buf
, pbuf
);
832 if ((saddr
= ALIGNED_CAST(struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_DST
]) != NULL
) {
833 if (saddr
->sadb_address_proto
)
834 printf("%s ", STR_OR_ID(saddr
->sadb_address_proto
, ipproto
));
836 s
= (struct sockaddr
*)(saddr
+ 1);
837 getnameinfo(s
, sysdep_sa_len(s
), buf
, sizeof(buf
),
838 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
|NI_NUMERICSERV
);
839 if (strcmp(pbuf
, "0") != 0)
840 printf("%s[%s]", buf
, pbuf
);
849 /* From: tcpdump(1):gmt2local.c and util.c */
851 * Print the timestamp
859 if (gettimeofday(&tp
, NULL
) == -1) {
860 perror("gettimeofday");
866 s
= (tp
.tv_sec
+ thiszone
) % 86400;
867 (void)printf("%02d:%02d:%02d.%06u ",
868 s
/ 3600, (s
% 3600) / 60, s
% 60, (u_int32_t
)tp
.tv_usec
);
869 } else if (f_tflag
> 1) {
870 /* Unix timeval style */
871 (void)printf("%u.%06u ",
872 (u_int32_t
)tp
.tv_sec
, (u_int32_t
)tp
.tv_usec
);
879 * Returns the difference between gmt and local time in seconds.
880 * Use gmtime() and localtime() to keep things simple.
885 register int dt
, dir
;
886 register struct tm
*gmt
, *loc
;
894 dt
= (loc
->tm_hour
- gmt
->tm_hour
) * 60 * 60 +
895 (loc
->tm_min
- gmt
->tm_min
) * 60;
898 * If the year or julian day is different, we span 00:00 GMT
899 * and must add or subtract a day. Check the year first to
900 * avoid problems when the julian day wraps.
902 dir
= loc
->tm_year
- gmt
->tm_year
;
904 dir
= loc
->tm_yday
- gmt
->tm_yday
;
905 dt
+= dir
* 24 * 60 * 60;