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