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