1 /* $FreeBSD$ */ 2 /* $KAME: setkey.c,v 1.28 2003/06/27 07:15:45 itojun 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 <netipsec/keydb.h> 42 #include <netipsec/key_debug.h> 43 #include <netipsec/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(void); 57 int main(int, char **); 58 int get_supported(void); 59 void sendkeyshort(u_int); 60 void promisc(void); 61 int sendkeymsg(char *, size_t); 62 int postproc(struct sadb_msg *, int); 63 const char *numstr(int); 64 void shortdump_hdr(void); 65 void shortdump(struct sadb_msg *); 66 static void printdate(void); 67 static int32_t gmt2local(time_t); 68 69 #define MODE_SCRIPT 1 70 #define MODE_CMDDUMP 2 71 #define MODE_CMDFLUSH 3 72 #define MODE_PROMISC 4 73 74 int so; 75 76 int f_forever = 0; 77 int f_all = 0; 78 int f_verbose = 0; 79 int f_mode = 0; 80 int f_cmddump = 0; 81 int f_policy = 0; 82 int f_hexdump = 0; 83 int f_tflag = 0; 84 static time_t thiszone; 85 86 extern int lineno; 87 88 extern int parse(FILE **); 89 90 void 91 usage() 92 { 93 94 printf("usage: setkey [-v] -c\n"); 95 printf(" setkey [-v] -f filename\n"); 96 printf(" setkey [-Palv] -D\n"); 97 printf(" setkey [-Pv] -F\n"); 98 printf(" setkey [-h] -x\n"); 99 exit(1); 100 } 101 102 int 103 main(ac, av) 104 int ac; 105 char **av; 106 { 107 FILE *fp = stdin; 108 int c; 109 110 if (ac == 1) { 111 usage(); 112 /* NOTREACHED */ 113 } 114 115 thiszone = gmt2local(0); 116 117 while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { 118 switch (c) { 119 case 'c': 120 f_mode = MODE_SCRIPT; 121 fp = stdin; 122 break; 123 case 'f': 124 f_mode = MODE_SCRIPT; 125 if ((fp = fopen(optarg, "r")) == NULL) { 126 err(-1, "fopen"); 127 /*NOTREACHED*/ 128 } 129 break; 130 case 'D': 131 f_mode = MODE_CMDDUMP; 132 break; 133 case 'F': 134 f_mode = MODE_CMDFLUSH; 135 break; 136 case 'a': 137 f_all = 1; 138 break; 139 case 'l': 140 f_forever = 1; 141 break; 142 case 'h': 143 f_hexdump = 1; 144 break; 145 case 'x': 146 f_mode = MODE_PROMISC; 147 f_tflag++; 148 break; 149 case 'P': 150 f_policy = 1; 151 break; 152 case 'v': 153 f_verbose = 1; 154 break; 155 default: 156 usage(); 157 /*NOTREACHED*/ 158 } 159 } 160 161 so = pfkey_open(); 162 if (so < 0) { 163 perror("pfkey_open"); 164 exit(1); 165 } 166 167 switch (f_mode) { 168 case MODE_CMDDUMP: 169 sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); 170 break; 171 case MODE_CMDFLUSH: 172 sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); 173 break; 174 case MODE_SCRIPT: 175 if (get_supported() < 0) { 176 errx(-1, "%s", ipsec_strerror()); 177 /*NOTREACHED*/ 178 } 179 if (parse(&fp)) 180 exit (1); 181 break; 182 case MODE_PROMISC: 183 promisc(); 184 /*NOTREACHED*/ 185 default: 186 usage(); 187 /*NOTREACHED*/ 188 } 189 190 exit(0); 191 } 192 193 int 194 get_supported() 195 { 196 197 if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) 198 return -1; 199 200 if (pfkey_recv_register(so) < 0) 201 return -1; 202 203 return 0; 204 } 205 206 void 207 sendkeyshort(type) 208 u_int type; 209 { 210 struct sadb_msg msg; 211 212 msg.sadb_msg_version = PF_KEY_V2; 213 msg.sadb_msg_type = type; 214 msg.sadb_msg_errno = 0; 215 msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; 216 msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); 217 msg.sadb_msg_reserved = 0; 218 msg.sadb_msg_seq = 0; 219 msg.sadb_msg_pid = getpid(); 220 221 sendkeymsg((char *)&msg, sizeof(msg)); 222 223 return; 224 } 225 226 void 227 promisc() 228 { 229 struct sadb_msg msg; 230 u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ 231 ssize_t l; 232 233 msg.sadb_msg_version = PF_KEY_V2; 234 msg.sadb_msg_type = SADB_X_PROMISC; 235 msg.sadb_msg_errno = 0; 236 msg.sadb_msg_satype = 1; 237 msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); 238 msg.sadb_msg_reserved = 0; 239 msg.sadb_msg_seq = 0; 240 msg.sadb_msg_pid = getpid(); 241 242 if ((l = send(so, &msg, sizeof(msg), 0)) < 0) { 243 err(1, "send"); 244 /*NOTREACHED*/ 245 } 246 247 while (1) { 248 struct sadb_msg *base; 249 250 if ((l = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { 251 err(1, "recv"); 252 /*NOTREACHED*/ 253 } 254 255 if (l != sizeof(*base)) 256 continue; 257 258 base = (struct sadb_msg *)rbuf; 259 if ((l = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), 260 0)) < 0) { 261 err(1, "recv"); 262 /*NOTREACHED*/ 263 } 264 printdate(); 265 if (f_hexdump) { 266 int i; 267 for (i = 0; i < l; i++) { 268 if (i % 16 == 0) 269 printf("%08x: ", i); 270 printf("%02x ", rbuf[i] & 0xff); 271 if (i % 16 == 15) 272 printf("\n"); 273 } 274 if (l % 16) 275 printf("\n"); 276 } 277 /* adjust base pointer for promisc mode */ 278 if (base->sadb_msg_type == SADB_X_PROMISC) { 279 if ((ssize_t)sizeof(*base) < l) 280 base++; 281 else 282 base = NULL; 283 } 284 if (base) { 285 kdebug_sadb(base); 286 printf("\n"); 287 fflush(stdout); 288 } 289 } 290 } 291 292 int 293 sendkeymsg(buf, len) 294 char *buf; 295 size_t len; 296 { 297 u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ 298 ssize_t l; 299 struct sadb_msg *msg; 300 301 { 302 struct timeval tv; 303 tv.tv_sec = 1; 304 tv.tv_usec = 0; 305 if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { 306 perror("setsockopt"); 307 goto end; 308 } 309 } 310 311 if (f_forever) 312 shortdump_hdr(); 313 again: 314 if (f_verbose) { 315 kdebug_sadb((struct sadb_msg *)buf); 316 printf("\n"); 317 } 318 if (f_hexdump) { 319 int i; 320 for (i = 0; i < len; i++) { 321 if (i % 16 == 0) 322 printf("%08x: ", i); 323 printf("%02x ", buf[i] & 0xff); 324 if (i % 16 == 15) 325 printf("\n"); 326 } 327 if (len % 16) 328 printf("\n"); 329 } 330 331 if ((l = send(so, buf, len, 0)) < 0) { 332 perror("send"); 333 goto end; 334 } 335 336 msg = (struct sadb_msg *)rbuf; 337 do { 338 if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { 339 perror("recv"); 340 goto end; 341 } 342 343 if (PFKEY_UNUNIT64(msg->sadb_msg_len) != l) { 344 warnx("invalid keymsg length"); 345 break; 346 } 347 348 if (f_verbose) { 349 kdebug_sadb((struct sadb_msg *)rbuf); 350 printf("\n"); 351 } 352 if (postproc(msg, l) < 0) 353 break; 354 } while (msg->sadb_msg_errno || msg->sadb_msg_seq); 355 356 if (f_forever) { 357 fflush(stdout); 358 sleep(1); 359 goto again; 360 } 361 362 end: 363 return(0); 364 } 365 366 int 367 postproc(msg, len) 368 struct sadb_msg *msg; 369 int len; 370 { 371 372 if (msg->sadb_msg_errno != 0) { 373 char inf[80]; 374 const char *errmsg = NULL; 375 376 if (f_mode == MODE_SCRIPT) 377 snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); 378 else 379 inf[0] = '\0'; 380 381 switch (msg->sadb_msg_errno) { 382 case ENOENT: 383 switch (msg->sadb_msg_type) { 384 case SADB_DELETE: 385 case SADB_GET: 386 case SADB_X_SPDDELETE: 387 errmsg = "No entry"; 388 break; 389 case SADB_DUMP: 390 errmsg = "No SAD entries"; 391 break; 392 case SADB_X_SPDDUMP: 393 errmsg = "No SPD entries"; 394 break; 395 } 396 break; 397 default: 398 errmsg = strerror(msg->sadb_msg_errno); 399 } 400 printf("%s%s.\n", inf, errmsg); 401 return(-1); 402 } 403 404 switch (msg->sadb_msg_type) { 405 case SADB_GET: 406 pfkey_sadump(msg); 407 break; 408 409 case SADB_DUMP: 410 /* filter out DEAD SAs */ 411 if (!f_all) { 412 caddr_t mhp[SADB_EXT_MAX + 1]; 413 struct sadb_sa *sa; 414 pfkey_align(msg, mhp); 415 pfkey_check(mhp); 416 if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { 417 if (sa->sadb_sa_state == SADB_SASTATE_DEAD) 418 break; 419 } 420 } 421 if (f_forever) 422 shortdump(msg); 423 else 424 pfkey_sadump(msg); 425 msg = (struct sadb_msg *)((caddr_t)msg + 426 PFKEY_UNUNIT64(msg->sadb_msg_len)); 427 if (f_verbose) { 428 kdebug_sadb((struct sadb_msg *)msg); 429 printf("\n"); 430 } 431 break; 432 433 case SADB_X_SPDDUMP: 434 pfkey_spdump(msg); 435 if (msg->sadb_msg_seq == 0) break; 436 msg = (struct sadb_msg *)((caddr_t)msg + 437 PFKEY_UNUNIT64(msg->sadb_msg_len)); 438 if (f_verbose) { 439 kdebug_sadb((struct sadb_msg *)msg); 440 printf("\n"); 441 } 442 break; 443 } 444 445 return(0); 446 } 447 448 /*------------------------------------------------------------*/ 449 static const char *satype[] = { 450 NULL, NULL, "ah", "esp" 451 }; 452 static const char *sastate[] = { 453 "L", "M", "D", "d" 454 }; 455 static const char *ipproto[] = { 456 /*0*/ "ip", "icmp", "igmp", "ggp", "ip4", 457 NULL, "tcp", NULL, "egp", NULL, 458 /*10*/ NULL, NULL, NULL, NULL, NULL, 459 NULL, NULL, "udp", NULL, NULL, 460 /*20*/ NULL, NULL, "idp", NULL, NULL, 461 NULL, NULL, NULL, NULL, "tp", 462 /*30*/ NULL, NULL, NULL, NULL, NULL, 463 NULL, NULL, NULL, NULL, NULL, 464 /*40*/ NULL, "ip6", NULL, "rt6", "frag6", 465 NULL, "rsvp", "gre", NULL, NULL, 466 /*50*/ "esp", "ah", NULL, NULL, NULL, 467 NULL, NULL, NULL, "icmp6", "none", 468 /*60*/ "dst6", 469 }; 470 471 #define STR_OR_ID(x, tab) \ 472 (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) 473 474 const char * 475 numstr(x) 476 int x; 477 { 478 static char buf[20]; 479 snprintf(buf, sizeof(buf), "#%d", x); 480 return buf; 481 } 482 483 void 484 shortdump_hdr() 485 { 486 printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", 487 "time", "p", "s", "spi", "ltime", "src", "dst"); 488 } 489 490 void 491 shortdump(msg) 492 struct sadb_msg *msg; 493 { 494 caddr_t mhp[SADB_EXT_MAX + 1]; 495 char buf[NI_MAXHOST], pbuf[NI_MAXSERV]; 496 struct sadb_sa *sa; 497 struct sadb_address *saddr; 498 struct sadb_lifetime *lts, *lth, *ltc; 499 struct sockaddr *s; 500 u_int t; 501 time_t cur = time(0); 502 503 pfkey_align(msg, mhp); 504 pfkey_check(mhp); 505 506 printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); 507 508 printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); 509 510 if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { 511 printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); 512 printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); 513 } else 514 printf("%-1s %-8s", "?", "?"); 515 516 lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; 517 lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; 518 ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; 519 if (lts && lth && ltc) { 520 if (ltc->sadb_lifetime_addtime == 0) 521 t = (u_long)0; 522 else 523 t = (u_long)(cur - ltc->sadb_lifetime_addtime); 524 if (t >= 1000) 525 strlcpy(buf, " big/", sizeof(buf)); 526 else 527 snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); 528 printf("%s", buf); 529 530 t = (u_long)lth->sadb_lifetime_addtime; 531 if (t >= 1000) 532 strlcpy(buf, "big", sizeof(buf)); 533 else 534 snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); 535 printf("%s", buf); 536 } else 537 printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ 538 539 printf(" "); 540 541 if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { 542 if (saddr->sadb_address_proto) 543 printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); 544 s = (struct sockaddr *)(saddr + 1); 545 getnameinfo(s, s->sa_len, buf, sizeof(buf), 546 pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); 547 if (strcmp(pbuf, "0") != 0) 548 printf("%s[%s]", buf, pbuf); 549 else 550 printf("%s", buf); 551 } else 552 printf("?"); 553 554 printf(" -> "); 555 556 if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { 557 if (saddr->sadb_address_proto) 558 printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); 559 560 s = (struct sockaddr *)(saddr + 1); 561 getnameinfo(s, s->sa_len, buf, sizeof(buf), 562 pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); 563 if (strcmp(pbuf, "0") != 0) 564 printf("%s[%s]", buf, pbuf); 565 else 566 printf("%s", buf); 567 } else 568 printf("?"); 569 570 printf("\n"); 571 } 572 573 /* From: tcpdump(1):gmt2local.c and util.c */ 574 /* 575 * Print the timestamp 576 */ 577 static void 578 printdate() 579 { 580 struct timeval tp; 581 int s; 582 583 if (gettimeofday(&tp, NULL) == -1) { 584 perror("gettimeofday"); 585 return; 586 } 587 588 if (f_tflag == 1) { 589 /* Default */ 590 s = (tp.tv_sec + thiszone ) % 86400; 591 (void)printf("%02d:%02d:%02d.%06u ", 592 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); 593 } else if (f_tflag > 1) { 594 /* Unix timeval style */ 595 (void)printf("%u.%06u ", 596 (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); 597 } 598 599 printf("\n"); 600 } 601 602 /* 603 * Returns the difference between gmt and local time in seconds. 604 * Use gmtime() and localtime() to keep things simple. 605 */ 606 int32_t 607 gmt2local(time_t t) 608 { 609 register int dt, dir; 610 register struct tm *gmt, *loc; 611 struct tm sgmt; 612 613 if (t == 0) 614 t = time(NULL); 615 gmt = &sgmt; 616 *gmt = *gmtime(&t); 617 loc = localtime(&t); 618 dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + 619 (loc->tm_min - gmt->tm_min) * 60; 620 621 /* 622 * If the year or julian day is different, we span 00:00 GMT 623 * and must add or subtract a day. Check the year first to 624 * avoid problems when the julian day wraps. 625 */ 626 dir = loc->tm_year - gmt->tm_year; 627 if (dir == 0) 628 dir = loc->tm_yday - gmt->tm_yday; 629 dt += dir * 24 * 60 * 60; 630 631 return (dt); 632 } 633