xref: /freebsd/sbin/setkey/setkey.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*	$FreeBSD$	*/
2 /*	$KAME: setkey.c,v 1.14 2000/06/10 06:47:09 sakane Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <err.h>
38 #include <net/route.h>
39 #include <netinet/in.h>
40 #include <net/pfkeyv2.h>
41 #include <netkey/keydb.h>
42 #include <netkey/key_debug.h>
43 #include <netinet6/ipsec.h>
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <limits.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <netdb.h>
53 
54 #include "libpfkey.h"
55 
56 void Usage __P((void));
57 int main __P((int, char **));
58 int get_supported __P((void));
59 void sendkeyshort __P((u_int));
60 void promisc __P((void));
61 int sendkeymsg __P((void));
62 int postproc __P((struct sadb_msg *, int));
63 const char *numstr __P((int));
64 void shortdump_hdr __P((void));
65 void shortdump __P((struct sadb_msg *));
66 
67 #define MODE_SCRIPT	1
68 #define MODE_CMDDUMP	2
69 #define MODE_CMDFLUSH	3
70 #define MODE_PROMISC	4
71 
72 int so;
73 
74 int f_forever = 0;
75 int f_all = 0;
76 int f_debug = 0;
77 int f_verbose = 0;
78 int f_mode = 0;
79 int f_cmddump = 0;
80 int f_policy = 0;
81 int f_hexdump = 0;
82 char *pname;
83 
84 u_char m_buf[BUFSIZ];
85 u_int m_len;
86 
87 extern int lineno;
88 
89 extern int parse __P((FILE **));
90 
91 void
92 Usage()
93 {
94 	printf("Usage:\t%s [-dv] -c\n", pname);
95 	printf("\t%s [-dv] -f (file)\n", pname);
96 	printf("\t%s [-Padlv] -D\n", pname);
97 	printf("\t%s [-Pdv] -F\n", pname);
98 	printf("\t%s [-h] -x\n", pname);
99 	pfkey_close(so);
100 	exit(1);
101 }
102 
103 int
104 main(ac, av)
105 	int ac;
106 	char **av;
107 {
108 	FILE *fp = stdin;
109 	int c;
110 
111 	pname = *av;
112 
113 	if (ac == 1) Usage();
114 
115 	while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) {
116 		switch (c) {
117 		case 'c':
118 			f_mode = MODE_SCRIPT;
119 			fp = stdin;
120 			break;
121 		case 'f':
122 			f_mode = MODE_SCRIPT;
123 			if ((fp = fopen(optarg, "r")) == NULL) {
124 				err(-1, "fopen");
125 				/*NOTREACHED*/
126 			}
127 			break;
128 		case 'D':
129 			f_mode = MODE_CMDDUMP;
130 			break;
131 		case 'F':
132 			f_mode = MODE_CMDFLUSH;
133 			break;
134 		case 'a':
135 			f_all = 1;
136 			break;
137 		case 'l':
138 			f_forever = 1;
139 			break;
140 		case 'h':
141 			f_hexdump = 1;
142 			break;
143 		case 'x':
144 			f_mode = MODE_PROMISC;
145 			break;
146 		case 'P':
147 			f_policy = 1;
148 			break;
149 		case 'd':
150 			f_debug = 1;
151 			break;
152 		case 'v':
153 			f_verbose = 1;
154 			break;
155 		default:
156 			Usage();
157 			/*NOTREACHED*/
158 		}
159 	}
160 
161 	switch (f_mode) {
162 	case MODE_CMDDUMP:
163 		sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP);
164 		break;
165 	case MODE_CMDFLUSH:
166 		sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH);
167 		pfkey_close(so);
168 		break;
169 	case MODE_SCRIPT:
170 		if (get_supported() < 0) {
171 			errx(-1, "%s", ipsec_strerror());
172 			/*NOTREACHED*/
173 		}
174 		if (parse(&fp))
175 			exit (1);
176 		break;
177 	case MODE_PROMISC:
178 		promisc();
179 		/*NOTREACHED*/
180 	default:
181 		Usage();
182 		/*NOTREACHED*/
183 	}
184 
185 	exit(0);
186 }
187 
188 int
189 get_supported()
190 {
191 	int so;
192 
193 	if ((so = pfkey_open()) < 0) {
194 		perror("pfkey_open");
195 		return -1;
196 	}
197 
198 	/* debug mode ? */
199 	if (f_debug)
200 		return 0;
201 
202 	if (pfkey_send_register(so, PF_UNSPEC) < 0)
203 		return -1;
204 
205 	if (pfkey_recv_register(so) < 0)
206 		return -1;
207 
208 	return 0;
209 }
210 
211 void
212 sendkeyshort(type)
213         u_int type;
214 {
215 	struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
216 
217 	m_len = sizeof(struct sadb_msg);
218 
219 	m_msg->sadb_msg_version = PF_KEY_V2;
220 	m_msg->sadb_msg_type = type;
221 	m_msg->sadb_msg_errno = 0;
222 	m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
223 	m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
224 	m_msg->sadb_msg_reserved = 0;
225 	m_msg->sadb_msg_seq = 0;
226 	m_msg->sadb_msg_pid = getpid();
227 
228 	sendkeymsg();
229 
230 	return;
231 }
232 
233 void
234 promisc()
235 {
236 	struct sadb_msg *m_msg = (struct sadb_msg *)m_buf;
237 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
238 	int so, len;
239 
240 	m_len = sizeof(struct sadb_msg);
241 
242 	m_msg->sadb_msg_version = PF_KEY_V2;
243 	m_msg->sadb_msg_type = SADB_X_PROMISC;
244 	m_msg->sadb_msg_errno = 0;
245 	m_msg->sadb_msg_satype = 1;
246 	m_msg->sadb_msg_len = PFKEY_UNIT64(m_len);
247 	m_msg->sadb_msg_reserved = 0;
248 	m_msg->sadb_msg_seq = 0;
249 	m_msg->sadb_msg_pid = getpid();
250 
251 	if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
252 		err(1, "socket(PF_KEY)");
253 		/*NOTREACHED*/
254 	}
255 
256 	if ((len = send(so, m_buf, m_len, 0)) < 0) {
257 		err(1, "send");
258 		/*NOTREACHED*/
259 	}
260 
261 	while (1) {
262 		struct sadb_msg *base;
263 
264 		if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) {
265 			err(1, "recv");
266 			/*NOTREACHED*/
267 		}
268 
269 		if (len != sizeof(*base))
270 			continue;
271 
272 		base = (struct sadb_msg *)rbuf;
273 		if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len),
274 				0)) < 0) {
275 			err(1, "recv");
276 			/*NOTREACHED*/
277 		}
278 		if (f_hexdump) {
279 			int i;
280 			for (i = 0; i < len; i++) {
281 				if (i % 16 == 0)
282 					printf("%08x: ", i);
283 				printf("%02x ", rbuf[i] & 0xff);
284 				if (i % 16 == 15)
285 					printf("\n");
286 			}
287 			if (len % 16)
288 				printf("\n");
289 		}
290 		/* adjust base pointer for promisc mode */
291 		if (base->sadb_msg_type == SADB_X_PROMISC) {
292 			if (sizeof(*base) < len)
293 				base++;
294 			else
295 				base = NULL;
296 		}
297 		if (base) {
298 			kdebug_sadb(base);
299 			printf("\n");
300 			fflush(stdout);
301 		}
302 	}
303 }
304 
305 int
306 sendkeymsg()
307 {
308 	int so;
309 
310 	u_char rbuf[1024 * 32];	/* XXX: Enough ? Should I do MSG_PEEK ? */
311 	int len;
312 	struct sadb_msg *msg;
313 
314 	if ((so = pfkey_open()) < 0) {
315 		perror("pfkey_open");
316 		return -1;
317 	}
318 
319     {
320 	struct timeval tv;
321 	tv.tv_sec = 1;
322 	tv.tv_usec = 0;
323 	if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
324 		perror("setsockopt");
325 		goto end;
326 	}
327     }
328 
329 	if (f_forever)
330 		shortdump_hdr();
331 again:
332 	if (f_verbose) {
333 		kdebug_sadb((struct sadb_msg *)m_buf);
334 		printf("\n");
335 	}
336 
337 	if ((len = send(so, m_buf, m_len, 0)) < 0) {
338 		perror("send");
339 		goto end;
340 	}
341 
342 	msg = (struct sadb_msg *)rbuf;
343 	do {
344 		if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
345 			perror("recv");
346 			goto end;
347 		}
348 
349 		if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) {
350 			warnx("invalid keymsg length");
351 			break;
352 		}
353 
354 		if (f_verbose) {
355 			kdebug_sadb((struct sadb_msg *)rbuf);
356 			printf("\n");
357 		}
358 		if (postproc(msg, len) < 0)
359 			break;
360 	} while (msg->sadb_msg_errno || msg->sadb_msg_seq);
361 
362 	if (f_forever) {
363 		fflush(stdout);
364 		sleep(1);
365 		goto again;
366 	}
367 
368 end:
369 	pfkey_close(so);
370 	return(0);
371 }
372 
373 int
374 postproc(msg, len)
375 	struct sadb_msg *msg;
376 	int len;
377 {
378 
379 	if (msg->sadb_msg_errno != 0) {
380 		char inf[80];
381 		char *errmsg = NULL;
382 
383 		if (f_mode == MODE_SCRIPT)
384 			snprintf(inf, sizeof(inf), "The result of line %d: ", lineno);
385 		else
386 			inf[0] = '\0';
387 
388 		switch (msg->sadb_msg_errno) {
389 		case ENOENT:
390 			switch (msg->sadb_msg_type) {
391 			case SADB_DELETE:
392 			case SADB_GET:
393 			case SADB_X_SPDDELETE:
394 				errmsg = "No entry";
395 				break;
396 			case SADB_DUMP:
397 				errmsg = "No SAD entries";
398 				break;
399 			case SADB_X_SPDDUMP:
400 				errmsg = "No SPD entries";
401 				break;
402 			}
403 			break;
404 		default:
405 			errmsg = strerror(msg->sadb_msg_errno);
406 		}
407 		printf("%s%s.\n", inf, errmsg);
408 		return(-1);
409 	}
410 
411 	switch (msg->sadb_msg_type) {
412 	case SADB_GET:
413 		pfkey_sadump(msg);
414 		break;
415 
416 	case SADB_DUMP:
417 		/* filter out DEAD SAs */
418 		if (!f_all) {
419 			caddr_t mhp[SADB_EXT_MAX + 1];
420 			struct sadb_sa *sa;
421 			pfkey_align(msg, mhp);
422 			pfkey_check(mhp);
423 			if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
424 				if (sa->sadb_sa_state == SADB_SASTATE_DEAD)
425 					break;
426 			}
427 		}
428 		if (f_forever)
429 			shortdump(msg);
430 		else
431 			pfkey_sadump(msg);
432 		msg = (struct sadb_msg *)((caddr_t)msg +
433 				     PFKEY_UNUNIT64(msg->sadb_msg_len));
434 		if (f_verbose) {
435 			kdebug_sadb((struct sadb_msg *)msg);
436 			printf("\n");
437 		}
438 		break;
439 
440 	case SADB_X_SPDDUMP:
441 		pfkey_spdump(msg);
442 		if (msg->sadb_msg_seq == 0) break;
443 		msg = (struct sadb_msg *)((caddr_t)msg +
444 				     PFKEY_UNUNIT64(msg->sadb_msg_len));
445 		if (f_verbose) {
446 			kdebug_sadb((struct sadb_msg *)msg);
447 			printf("\n");
448 		}
449 		break;
450 	}
451 
452 	return(0);
453 }
454 
455 /*------------------------------------------------------------*/
456 static char *satype[] = {
457 	NULL, NULL, "ah", "esp"
458 };
459 static char *sastate[] = {
460 	"L", "M", "D", "d"
461 };
462 static char *ipproto[] = {
463 /*0*/	"ip", "icmp", "igmp", "ggp", "ip4",
464 	NULL, "tcp", NULL, "egp", NULL,
465 /*10*/	NULL, NULL, NULL, NULL, NULL,
466 	NULL, NULL, "udp", NULL, NULL,
467 /*20*/	NULL, NULL, "idp", NULL, NULL,
468 	NULL, NULL, NULL, NULL, "tp",
469 /*30*/	NULL, NULL, NULL, NULL, NULL,
470 	NULL, NULL, NULL, NULL, NULL,
471 /*40*/	NULL, "ip6", NULL, "rt6", "frag6",
472 	NULL, "rsvp", "gre", NULL, NULL,
473 /*50*/	"esp", "ah", NULL, NULL, NULL,
474 	NULL, NULL, NULL, "icmp6", "none",
475 /*60*/	"dst6",
476 };
477 
478 #define STR_OR_ID(x, tab) \
479 	(((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)])	? tab[(x)] : numstr(x))
480 
481 const char *
482 numstr(x)
483 	int x;
484 {
485 	static char buf[20];
486 	snprintf(buf, sizeof(buf), "#%d", x);
487 	return buf;
488 }
489 
490 void
491 shortdump_hdr()
492 {
493 	printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n",
494 		"time", "p", "s", "spi", "ltime", "src", "dst");
495 }
496 
497 void
498 shortdump(msg)
499 	struct sadb_msg *msg;
500 {
501 	caddr_t mhp[SADB_EXT_MAX + 1];
502 	char buf[1024], pbuf[10];
503 	struct sadb_sa *sa;
504 	struct sadb_address *saddr;
505 	struct sadb_lifetime *lts, *lth, *ltc;
506 	struct sockaddr *s;
507 	u_int t;
508 	time_t cur = time(0);
509 
510 	pfkey_align(msg, mhp);
511 	pfkey_check(mhp);
512 
513 	printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60));
514 
515 	printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype));
516 
517 	if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) {
518 		printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate));
519 		printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi));
520 	} else
521 		printf("%-1s %-8s", "?", "?");
522 
523 	lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT];
524 	lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD];
525 	ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT];
526 	if (lts && lth && ltc) {
527 		if (ltc->sadb_lifetime_addtime == 0)
528 			t = (u_long)0;
529 		else
530 			t = (u_long)(cur - ltc->sadb_lifetime_addtime);
531 		if (t >= 1000)
532 			strcpy(buf, " big/");
533 		else
534 			snprintf(buf, sizeof(buf), " %3lu/", (u_long)t);
535 		printf("%s", buf);
536 
537 		t = (u_long)lth->sadb_lifetime_addtime;
538 		if (t >= 1000)
539 			strcpy(buf, "big");
540 		else
541 			snprintf(buf, sizeof(buf), "%-3lu", (u_long)t);
542 		printf("%s", buf);
543 	} else
544 		printf(" ???/???");
545 
546 	printf(" ");
547 
548 	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) {
549 		if (saddr->sadb_address_proto)
550 			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
551 		s = (struct sockaddr *)(saddr + 1);
552 		getnameinfo(s, s->sa_len, buf, sizeof(buf),
553 			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
554 		if (strcmp(pbuf, "0") != 0)
555 			printf("%s[%s]", buf, pbuf);
556 		else
557 			printf("%s", buf);
558 	} else
559 		printf("?");
560 
561 	printf(" -> ");
562 
563 	if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) {
564 		if (saddr->sadb_address_proto)
565 			printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto));
566 
567 		s = (struct sockaddr *)(saddr + 1);
568 		getnameinfo(s, s->sa_len, buf, sizeof(buf),
569 			pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV);
570 		if (strcmp(pbuf, "0") != 0)
571 			printf("%s[%s]", buf, pbuf);
572 		else
573 			printf("%s", buf);
574 	} else
575 		printf("?");
576 
577 	printf("\n");
578 }
579