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... */
74 #include "ipsecPolicyTracer.h"
75 #include "ipsecMessageTracer.h"
79 int main (int, char **);
80 int get_supported (void);
81 void sendkeyshort (u_int
);
83 int postproc (struct sadb_msg
*, int);
84 int verifypriority (struct sadb_msg
*m
);
85 int fileproc (const char *);
86 const char *numstr (int);
87 void shortdump_hdr (void);
88 void shortdump (struct sadb_msg
*);
89 static void printdate (void);
90 static int32_t gmt2local (time_t);
91 void stdin_loop (void);
94 #define MODE_CMDDUMP 2
95 #define MODE_CMDFLUSH 3
96 #define MODE_PROMISC 4
111 #ifdef HAVE_POLICY_FWD
117 static void rkwarn(void);
123 printf("warning: -r and -k options are not supported in this environment\n");
128 static time_t thiszone
;
131 usage(/*int only_version*/)
133 //printf("setkey @(#) %s (%s)\n", TOP_PACKAGE_STRING, TOP_PACKAGE_URL);
134 //if (! only_version) {
135 printf("usage: setkey [-v" RK_OPTS
"] file ...\n");
136 printf(" setkey [-nv" RK_OPTS
"] -c\n");
137 printf(" setkey [-nv" RK_OPTS
"] -f filename\n");
138 printf(" setkey [-Palpv" RK_OPTS
"] -D\n");
139 printf(" setkey [-Pv] -F\n");
140 printf(" setkey [-H] -x\n");
141 printf(" setkey [-V] [-h]\n");
159 thiszone
= gmt2local(0);
161 while ((c
= getopt(argc
, argv
, "acdf:HlnvxDFPphVrk?")) != -1) {
166 /* disable filename completion */
167 rl_bind_key('\t', rl_insert
);
171 f_mode
= MODE_SCRIPT
;
172 if ((fp
= fopen(optarg
, "r")) == NULL
) {
173 IPSECPOLICYTRACEREVENT(optarg
,
174 IPSECPOLICYEVENTCODE_SETKEY_ERROR
,
175 CONSTSTR("could not open policy file"),
176 CONSTSTR("setkey -f : fopen erred"));
182 f_mode
= MODE_CMDDUMP
;
185 f_mode
= MODE_CMDFLUSH
;
203 f_mode
= MODE_PROMISC
;
216 #ifdef HAVE_POLICY_FWD
223 #ifdef HAVE_POLICY_FWD
248 if (fileproc(*argv
++) < 0) {
249 IPSECPOLICYTRACEREVENT(argv
[-1],
250 IPSECPOLICYEVENTCODE_SETKEY_ERROR
,
251 CONSTSTR("could not parse policy file"),
252 CONSTSTR("setkey: fileproc erred"));
253 err(1, "%s", argv
[-1]);
261 IPSECPOLICYTRACEREVENT(argv
[-1],
262 IPSECPOLICYEVENTCODE_SETKEY_ERROR
,
263 CONSTSTR("couldn't open pfkey socket"),
264 CONSTSTR("setkey: pfkey_open erred"));
265 perror("pfkey_open");
271 sendkeyshort(f_policy
? SADB_X_SPDDUMP
: SADB_DUMP
);
274 sendkeyshort(f_policy
? SADB_X_SPDFLUSH
: SADB_FLUSH
);
277 if (get_supported() < 0) {
278 errx(1, "%s", ipsec_strerror());
285 if (get_supported() < 0) {
286 IPSECPOLICYTRACEREVENT("STDIN",
287 IPSECPOLICYEVENTCODE_SETKEY_ERROR
,
288 CONSTSTR(ipsec_strerror()),
289 CONSTSTR("setkey: get_supported erred"));
290 errx(1, "%s", ipsec_strerror());
310 if (pfkey_send_register(so
, SADB_SATYPE_UNSPEC
) < 0)
313 if (pfkey_recv_register(so
) < 0)
322 char line
[1024], *semicolon
, *comment
;
325 memset (line
, 0, sizeof(line
));
331 rbuf
= readline ("");
337 if (fgets(rbuf
, sizeof(rbuf
), stdin
) == NULL
)
339 if (rbuf
[strlen(rbuf
)-1] == '\n')
340 rbuf
[strlen(rbuf
)-1] = '\0';
342 comment
= strchr(rbuf
, '#');
349 linelen
+= snprintf (&line
[linelen
], sizeof(line
) - linelen
,
350 "%s%s", linelen
> 0 ? " " : "", rbuf
);
352 semicolon
= strchr(line
, ';');
354 char saved_char
= *++semicolon
;
360 #ifdef HAVE_PFKEY_POLICY_PRIORITY
361 last_msg_type
= -1; /* invalid message type */
368 *semicolon
= saved_char
;
369 linelen
= strlen (semicolon
);
370 memmove (line
, semicolon
, linelen
+ 1);
371 semicolon
= strchr(line
, ';');
387 msg
.sadb_msg_version
= PF_KEY_V2
;
388 msg
.sadb_msg_type
= type
;
389 msg
.sadb_msg_errno
= 0;
390 msg
.sadb_msg_satype
= SADB_SATYPE_UNSPEC
;
391 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
392 msg
.sadb_msg_reserved
= 0;
393 msg
.sadb_msg_seq
= 0;
394 msg
.sadb_msg_pid
= getpid();
396 sendkeymsg((char *)&msg
, sizeof(msg
));
405 union { // Wcast-align fix - force alignment
406 u_int64_t force_align
;
407 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
411 msg
.sadb_msg_version
= PF_KEY_V2
;
412 msg
.sadb_msg_type
= SADB_X_PROMISC
;
413 msg
.sadb_msg_errno
= 0;
414 msg
.sadb_msg_satype
= 1;
415 msg
.sadb_msg_len
= PFKEY_UNIT64(sizeof(msg
));
416 msg
.sadb_msg_reserved
= 0;
417 msg
.sadb_msg_seq
= 0;
418 msg
.sadb_msg_pid
= getpid();
420 if ((l
= send(so
, &msg
, sizeof(msg
), 0)) < 0) {
426 struct sadb_msg
*base
;
428 if ((l
= recv(so
, u_buf
.rbuf
, sizeof(*base
), MSG_PEEK
)) < 0) {
433 if (l
!= sizeof(*base
))
436 base
= (struct sadb_msg
*)&u_buf
;
437 if ((l
= recv(so
, u_buf
.rbuf
, PFKEY_UNUNIT64(base
->sadb_msg_len
),
445 for (i
= 0; i
< l
; i
++) {
448 printf("%02x ", u_buf
.rbuf
[i
] & 0xff);
455 /* adjust base pointer for promisc mode */
456 if (base
->sadb_msg_type
== SADB_X_PROMISC
) {
457 if ((ssize_t
)sizeof(*base
) < l
)
475 union { // Wcast-align fix - force alignment
476 u_int64_t force_align
;
477 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
480 struct sadb_msg
*msg
;
490 if (setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
)) < 0) {
491 perror("setsockopt");
500 kdebug_sadb(ALIGNED_CAST(struct sadb_msg
*)buf
); // Wcast-align fix - aligned message buffer
505 for (i
= 0; i
< len
; i
++) {
508 printf("%02x ", buf
[i
] & 0xff);
516 if ((l
= send(so
, buf
, len
, 0)) < 0) {
521 msg
= (struct sadb_msg
*)&u_buf
;
523 if ((l
= recv(so
, u_buf
.rbuf
, sizeof(u_buf
.rbuf
), 0)) < 0) {
528 if (PFKEY_UNUNIT64(msg
->sadb_msg_len
) != l
) {
529 warnx("invalid keymsg length");
534 kdebug_sadb((struct sadb_msg
*)&u_buf
);
537 if (postproc(msg
, l
) < 0)
539 } while (msg
->sadb_msg_errno
|| msg
->sadb_msg_seq
);
553 struct sadb_msg
*msg
;
556 #ifdef HAVE_PFKEY_POLICY_PRIORITY
557 static int priority_support_check
= 0;
560 if (msg
->sadb_msg_errno
!= 0) {
562 const char *errmsg
= NULL
;
564 if (f_mode
== MODE_SCRIPT
)
565 snprintf(inf
, sizeof(inf
), "The result of line %d: ", lineno
);
569 switch (msg
->sadb_msg_errno
) {
571 switch (msg
->sadb_msg_type
) {
574 case SADB_X_SPDDELETE
:
578 errmsg
= "No SAD entries";
581 errmsg
= "No SPD entries";
586 errmsg
= strerror(msg
->sadb_msg_errno
);
588 printf("%s%s.\n", inf
, errmsg
);
592 switch (msg
->sadb_msg_type
) {
595 pfkey_sadump_withports(msg
);
601 /* filter out DEAD SAs */
603 caddr_t mhp
[SADB_EXT_MAX
+ 1];
605 pfkey_align(msg
, mhp
);
607 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
608 if (sa
->sadb_sa_state
== SADB_SASTATE_DEAD
)
613 /* TODO: f_withports */
617 pfkey_sadump_withports(msg
);
621 msg
= ALIGNED_CAST(struct sadb_msg
*)((caddr_t
)msg
+
622 PFKEY_UNUNIT64(msg
->sadb_msg_len
)); // Wcast-align fix (void*) - aligned msg buffer passed into function
624 kdebug_sadb((struct sadb_msg
*)msg
);
631 pfkey_spdump_withports(msg
);
638 pfkey_spdump_withports(msg
);
641 if (msg
->sadb_msg_seq
== 0) break;
642 msg
= ALIGNED_CAST(struct sadb_msg
*)((caddr_t
)msg
+ // Wcast-align fix (void*) - aligned msg buffer passed into function
643 PFKEY_UNUNIT64(msg
->sadb_msg_len
));
645 kdebug_sadb((struct sadb_msg
*)msg
);
649 #ifdef HAVE_PFKEY_POLICY_PRIORITY
651 if (last_msg_type
== SADB_X_SPDADD
&& last_priority
!= 0 &&
652 msg
->sadb_msg_pid
== getpid() && !priority_support_check
) {
653 priority_support_check
= 1;
654 if (!verifypriority(msg
))
655 printf ("WARNING: Kernel does not support policy priorities\n");
664 #ifdef HAVE_PFKEY_POLICY_PRIORITY
669 caddr_t mhp
[SADB_EXT_MAX
+ 1];
670 struct sadb_x_policy
*xpl
;
672 /* check pfkey message. */
673 if (pfkey_align(m
, mhp
)) {
674 printf("(%s\n", ipsec_strerror());
677 if (pfkey_check(mhp
)) {
678 printf("%s\n", ipsec_strerror());
682 xpl
= (struct sadb_x_policy
*) mhp
[SADB_X_EXT_POLICY
];
685 printf("no X_POLICY extension.\n");
689 /* now make sure they match */
690 if (last_priority
!= xpl
->sadb_x_policy_priority
)
699 const char *filename
;
704 struct sadb_msg
*msg
;
705 u_char rbuf
[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */
707 fd
= open(filename
, O_RDONLY
);
713 len
= read(fd
, rbuf
+ l
, sizeof(rbuf
) - l
);
722 if (l
< sizeof(struct sadb_msg
)) {
733 msg
= ALIGNED_CAST(struct sadb_msg
*)p
;
734 len
= PFKEY_UNUNIT64(msg
->sadb_msg_len
);
743 /*------------------------------------------------------------*/
744 static const char *satype
[] = {
745 NULL
, NULL
, "ah", "esp"
747 static const char *sastate
[] = {
750 static const char *ipproto
[] = {
751 /*0*/ "ip", "icmp", "igmp", "ggp", "ip4",
752 NULL
, "tcp", NULL
, "egp", NULL
,
753 /*10*/ NULL
, NULL
, NULL
, NULL
, NULL
,
754 NULL
, NULL
, "udp", NULL
, NULL
,
755 /*20*/ NULL
, NULL
, "idp", NULL
, NULL
,
756 NULL
, NULL
, NULL
, NULL
, "tp",
757 /*30*/ NULL
, NULL
, NULL
, NULL
, NULL
,
758 NULL
, NULL
, NULL
, NULL
, NULL
,
759 /*40*/ NULL
, "ip6", NULL
, "rt6", "frag6",
760 NULL
, "rsvp", "gre", NULL
, NULL
,
761 /*50*/ "esp", "ah", NULL
, NULL
, NULL
,
762 NULL
, NULL
, NULL
, "icmp6", "none",
766 #define STR_OR_ID(x, tab) \
767 (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x))
774 snprintf(buf
, sizeof(buf
), "#%d", x
);
781 printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
782 "time", "p", "s", "spi", "ltime", "src", "dst");
787 struct sadb_msg
*msg
;
789 caddr_t mhp
[SADB_EXT_MAX
+ 1];
790 char buf
[NI_MAXHOST
], pbuf
[NI_MAXSERV
];
792 struct sadb_address
*saddr
;
793 struct sadb_lifetime
*lts
, *lth
, *ltc
;
796 time_t cur
= time(0);
798 pfkey_align(msg
, mhp
);
801 printf("%02lu%02lu", (u_long
)(cur
% 3600) / 60, (u_long
)(cur
% 60));
803 printf(" %-3s", STR_OR_ID(msg
->sadb_msg_satype
, satype
));
805 if ((sa
= ALIGNED_CAST(struct sadb_sa
*)mhp
[SADB_EXT_SA
]) != NULL
) {
806 printf(" %-1s", STR_OR_ID(sa
->sadb_sa_state
, sastate
));
807 printf(" %08x", (u_int32_t
)ntohl(sa
->sadb_sa_spi
));
809 printf("%-1s %-8s", "?", "?");
811 lts
= ALIGNED_CAST(struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_SOFT
];
812 lth
= ALIGNED_CAST(struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_HARD
];
813 ltc
= ALIGNED_CAST(struct sadb_lifetime
*)mhp
[SADB_EXT_LIFETIME_CURRENT
];
814 if (lts
&& lth
&& ltc
) {
815 if (ltc
->sadb_lifetime_addtime
== 0)
818 t
= (u_long
)(cur
- ltc
->sadb_lifetime_addtime
);
820 strlcpy(buf
, " big/", sizeof(buf
));
822 snprintf(buf
, sizeof(buf
), " %3lu/", (u_long
)t
);
825 t
= (u_long
)lth
->sadb_lifetime_addtime
;
827 strlcpy(buf
, "big", sizeof(buf
));
829 snprintf(buf
, sizeof(buf
), "%-3lu", (u_long
)t
);
832 printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */
836 if ((saddr
= ALIGNED_CAST(struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_SRC
]) != NULL
) {
837 if (saddr
->sadb_address_proto
)
838 printf("%s ", STR_OR_ID(saddr
->sadb_address_proto
, ipproto
));
839 s
= (struct sockaddr
*)(saddr
+ 1);
840 getnameinfo(s
, sysdep_sa_len((struct sockaddr
*)s
), buf
, sizeof(buf
),
841 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
|NI_NUMERICSERV
);
842 if (strcmp(pbuf
, "0") != 0)
843 printf("%s[%s]", buf
, pbuf
);
851 if ((saddr
= ALIGNED_CAST(struct sadb_address
*)mhp
[SADB_EXT_ADDRESS_DST
]) != NULL
) {
852 if (saddr
->sadb_address_proto
)
853 printf("%s ", STR_OR_ID(saddr
->sadb_address_proto
, ipproto
));
855 s
= (struct sockaddr
*)(saddr
+ 1);
856 getnameinfo(s
, sysdep_sa_len(s
), buf
, sizeof(buf
),
857 pbuf
, sizeof(pbuf
), NI_NUMERICHOST
|NI_NUMERICSERV
);
858 if (strcmp(pbuf
, "0") != 0)
859 printf("%s[%s]", buf
, pbuf
);
868 /* From: tcpdump(1):gmt2local.c and util.c */
870 * Print the timestamp
878 if (gettimeofday(&tp
, NULL
) == -1) {
879 perror("gettimeofday");
885 s
= (tp
.tv_sec
+ thiszone
) % 86400;
886 (void)printf("%02d:%02d:%02d.%06u ",
887 s
/ 3600, (s
% 3600) / 60, s
% 60, (u_int32_t
)tp
.tv_usec
);
888 } else if (f_tflag
> 1) {
889 /* Unix timeval style */
890 (void)printf("%u.%06u ",
891 (u_int32_t
)tp
.tv_sec
, (u_int32_t
)tp
.tv_usec
);
898 * Returns the difference between gmt and local time in seconds.
899 * Use gmtime() and localtime() to keep things simple.
904 register int dt
, dir
;
905 register struct tm
*gmt
, *loc
;
913 dt
= (loc
->tm_hour
- gmt
->tm_hour
) * 60 * 60 +
914 (loc
->tm_min
- gmt
->tm_min
) * 60;
917 * If the year or julian day is different, we span 00:00 GMT
918 * and must add or subtract a day. Check the year first to
919 * avoid problems when the julian day wraps.
921 dir
= loc
->tm_year
- gmt
->tm_year
;
923 dir
= loc
->tm_yday
- gmt
->tm_yday
;
924 dt
+= dir
* 24 * 60 * 60;