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