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