1 /* $FreeBSD$ */ 2 /* $KAME: setkey.c,v 1.14 2000/06/10 06:47:09 sakane 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 67 #define MODE_SCRIPT 1 68 #define MODE_CMDDUMP 2 69 #define MODE_CMDFLUSH 3 70 #define MODE_PROMISC 4 71 72 int so; 73 74 int f_forever = 0; 75 int f_all = 0; 76 int f_debug = 0; 77 int f_verbose = 0; 78 int f_mode = 0; 79 int f_cmddump = 0; 80 int f_policy = 0; 81 int f_hexdump = 0; 82 char *pname; 83 84 u_char m_buf[BUFSIZ]; 85 u_int m_len; 86 87 extern int lineno; 88 89 extern int parse __P((FILE **)); 90 91 void 92 Usage() 93 { 94 printf("Usage:\t%s [-dv] -c\n", pname); 95 printf("\t%s [-dv] -f (file)\n", pname); 96 printf("\t%s [-Padlv] -D\n", pname); 97 printf("\t%s [-Pdv] -F\n", pname); 98 printf("\t%s [-h] -x\n", pname); 99 pfkey_close(so); 100 exit(1); 101 } 102 103 int 104 main(ac, av) 105 int ac; 106 char **av; 107 { 108 FILE *fp = stdin; 109 int c; 110 111 pname = *av; 112 113 if (ac == 1) Usage(); 114 115 while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) { 116 switch (c) { 117 case 'c': 118 f_mode = MODE_SCRIPT; 119 fp = stdin; 120 break; 121 case 'f': 122 f_mode = MODE_SCRIPT; 123 if ((fp = fopen(optarg, "r")) == NULL) { 124 err(-1, "fopen"); 125 /*NOTREACHED*/ 126 } 127 break; 128 case 'D': 129 f_mode = MODE_CMDDUMP; 130 break; 131 case 'F': 132 f_mode = MODE_CMDFLUSH; 133 break; 134 case 'a': 135 f_all = 1; 136 break; 137 case 'l': 138 f_forever = 1; 139 break; 140 case 'h': 141 f_hexdump = 1; 142 break; 143 case 'x': 144 f_mode = MODE_PROMISC; 145 break; 146 case 'P': 147 f_policy = 1; 148 break; 149 case 'd': 150 f_debug = 1; 151 break; 152 case 'v': 153 f_verbose = 1; 154 break; 155 default: 156 Usage(); 157 /*NOTREACHED*/ 158 } 159 } 160 161 switch (f_mode) { 162 case MODE_CMDDUMP: 163 sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); 164 break; 165 case MODE_CMDFLUSH: 166 sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); 167 pfkey_close(so); 168 break; 169 case MODE_SCRIPT: 170 if (get_supported() < 0) { 171 errx(-1, "%s", ipsec_strerror()); 172 /*NOTREACHED*/ 173 } 174 if (parse(&fp)) 175 exit (1); 176 break; 177 case MODE_PROMISC: 178 promisc(); 179 /*NOTREACHED*/ 180 default: 181 Usage(); 182 /*NOTREACHED*/ 183 } 184 185 exit(0); 186 } 187 188 int 189 get_supported() 190 { 191 int so; 192 193 if ((so = pfkey_open()) < 0) { 194 perror("pfkey_open"); 195 return -1; 196 } 197 198 /* debug mode ? */ 199 if (f_debug) 200 return 0; 201 202 if (pfkey_send_register(so, PF_UNSPEC) < 0) 203 return -1; 204 205 if (pfkey_recv_register(so) < 0) 206 return -1; 207 208 return 0; 209 } 210 211 void 212 sendkeyshort(type) 213 u_int type; 214 { 215 struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; 216 217 m_len = sizeof(struct sadb_msg); 218 219 m_msg->sadb_msg_version = PF_KEY_V2; 220 m_msg->sadb_msg_type = type; 221 m_msg->sadb_msg_errno = 0; 222 m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC; 223 m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); 224 m_msg->sadb_msg_reserved = 0; 225 m_msg->sadb_msg_seq = 0; 226 m_msg->sadb_msg_pid = getpid(); 227 228 sendkeymsg(); 229 230 return; 231 } 232 233 void 234 promisc() 235 { 236 struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; 237 u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ 238 int so, len; 239 240 m_len = sizeof(struct sadb_msg); 241 242 m_msg->sadb_msg_version = PF_KEY_V2; 243 m_msg->sadb_msg_type = SADB_X_PROMISC; 244 m_msg->sadb_msg_errno = 0; 245 m_msg->sadb_msg_satype = 1; 246 m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); 247 m_msg->sadb_msg_reserved = 0; 248 m_msg->sadb_msg_seq = 0; 249 m_msg->sadb_msg_pid = getpid(); 250 251 if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { 252 err(1, "socket(PF_KEY)"); 253 /*NOTREACHED*/ 254 } 255 256 if ((len = send(so, m_buf, m_len, 0)) < 0) { 257 err(1, "send"); 258 /*NOTREACHED*/ 259 } 260 261 while (1) { 262 struct sadb_msg *base; 263 264 if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { 265 err(1, "recv"); 266 /*NOTREACHED*/ 267 } 268 269 if (len != sizeof(*base)) 270 continue; 271 272 base = (struct sadb_msg *)rbuf; 273 if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), 274 0)) < 0) { 275 err(1, "recv"); 276 /*NOTREACHED*/ 277 } 278 if (f_hexdump) { 279 int i; 280 for (i = 0; i < len; i++) { 281 if (i % 16 == 0) 282 printf("%08x: ", i); 283 printf("%02x ", rbuf[i] & 0xff); 284 if (i % 16 == 15) 285 printf("\n"); 286 } 287 if (len % 16) 288 printf("\n"); 289 } 290 /* adjust base pointer for promisc mode */ 291 if (base->sadb_msg_type == SADB_X_PROMISC) { 292 if (sizeof(*base) < len) 293 base++; 294 else 295 base = NULL; 296 } 297 if (base) { 298 kdebug_sadb(base); 299 printf("\n"); 300 fflush(stdout); 301 } 302 } 303 } 304 305 int 306 sendkeymsg() 307 { 308 int so; 309 310 u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ 311 int len; 312 struct sadb_msg *msg; 313 314 if ((so = pfkey_open()) < 0) { 315 perror("pfkey_open"); 316 return -1; 317 } 318 319 { 320 struct timeval tv; 321 tv.tv_sec = 1; 322 tv.tv_usec = 0; 323 if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { 324 perror("setsockopt"); 325 goto end; 326 } 327 } 328 329 if (f_forever) 330 shortdump_hdr(); 331 again: 332 if (f_verbose) { 333 kdebug_sadb((struct sadb_msg *)m_buf); 334 printf("\n"); 335 } 336 337 if ((len = send(so, m_buf, m_len, 0)) < 0) { 338 perror("send"); 339 goto end; 340 } 341 342 msg = (struct sadb_msg *)rbuf; 343 do { 344 if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { 345 perror("recv"); 346 goto end; 347 } 348 349 if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) { 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, len) < 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 pfkey_close(so); 370 return(0); 371 } 372 373 int 374 postproc(msg, len) 375 struct sadb_msg *msg; 376 int len; 377 { 378 379 if (msg->sadb_msg_errno != 0) { 380 char inf[80]; 381 char *errmsg = NULL; 382 383 if (f_mode == MODE_SCRIPT) 384 snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); 385 else 386 inf[0] = '\0'; 387 388 switch (msg->sadb_msg_errno) { 389 case ENOENT: 390 switch (msg->sadb_msg_type) { 391 case SADB_DELETE: 392 case SADB_GET: 393 case SADB_X_SPDDELETE: 394 errmsg = "No entry"; 395 break; 396 case SADB_DUMP: 397 errmsg = "No SAD entries"; 398 break; 399 case SADB_X_SPDDUMP: 400 errmsg = "No SPD entries"; 401 break; 402 } 403 break; 404 default: 405 errmsg = strerror(msg->sadb_msg_errno); 406 } 407 printf("%s%s.\n", inf, errmsg); 408 return(-1); 409 } 410 411 switch (msg->sadb_msg_type) { 412 case SADB_GET: 413 pfkey_sadump(msg); 414 break; 415 416 case SADB_DUMP: 417 /* filter out DEAD SAs */ 418 if (!f_all) { 419 caddr_t mhp[SADB_EXT_MAX + 1]; 420 struct sadb_sa *sa; 421 pfkey_align(msg, mhp); 422 pfkey_check(mhp); 423 if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { 424 if (sa->sadb_sa_state == SADB_SASTATE_DEAD) 425 break; 426 } 427 } 428 if (f_forever) 429 shortdump(msg); 430 else 431 pfkey_sadump(msg); 432 msg = (struct sadb_msg *)((caddr_t)msg + 433 PFKEY_UNUNIT64(msg->sadb_msg_len)); 434 if (f_verbose) { 435 kdebug_sadb((struct sadb_msg *)msg); 436 printf("\n"); 437 } 438 break; 439 440 case SADB_X_SPDDUMP: 441 pfkey_spdump(msg); 442 if (msg->sadb_msg_seq == 0) break; 443 msg = (struct sadb_msg *)((caddr_t)msg + 444 PFKEY_UNUNIT64(msg->sadb_msg_len)); 445 if (f_verbose) { 446 kdebug_sadb((struct sadb_msg *)msg); 447 printf("\n"); 448 } 449 break; 450 } 451 452 return(0); 453 } 454 455 /*------------------------------------------------------------*/ 456 static char *satype[] = { 457 NULL, NULL, "ah", "esp" 458 }; 459 static char *sastate[] = { 460 "L", "M", "D", "d" 461 }; 462 static char *ipproto[] = { 463 /*0*/ "ip", "icmp", "igmp", "ggp", "ip4", 464 NULL, "tcp", NULL, "egp", NULL, 465 /*10*/ NULL, NULL, NULL, NULL, NULL, 466 NULL, NULL, "udp", NULL, NULL, 467 /*20*/ NULL, NULL, "idp", NULL, NULL, 468 NULL, NULL, NULL, NULL, "tp", 469 /*30*/ NULL, NULL, NULL, NULL, NULL, 470 NULL, NULL, NULL, NULL, NULL, 471 /*40*/ NULL, "ip6", NULL, "rt6", "frag6", 472 NULL, "rsvp", "gre", NULL, NULL, 473 /*50*/ "esp", "ah", NULL, NULL, NULL, 474 NULL, NULL, NULL, "icmp6", "none", 475 /*60*/ "dst6", 476 }; 477 478 #define STR_OR_ID(x, tab) \ 479 (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) 480 481 const char * 482 numstr(x) 483 int x; 484 { 485 static char buf[20]; 486 snprintf(buf, sizeof(buf), "#%d", x); 487 return buf; 488 } 489 490 void 491 shortdump_hdr() 492 { 493 printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", 494 "time", "p", "s", "spi", "ltime", "src", "dst"); 495 } 496 497 void 498 shortdump(msg) 499 struct sadb_msg *msg; 500 { 501 caddr_t mhp[SADB_EXT_MAX + 1]; 502 char buf[1024], pbuf[10]; 503 struct sadb_sa *sa; 504 struct sadb_address *saddr; 505 struct sadb_lifetime *lts, *lth, *ltc; 506 struct sockaddr *s; 507 u_int t; 508 time_t cur = time(0); 509 510 pfkey_align(msg, mhp); 511 pfkey_check(mhp); 512 513 printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); 514 515 printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); 516 517 if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { 518 printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); 519 printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); 520 } else 521 printf("%-1s %-8s", "?", "?"); 522 523 lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; 524 lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; 525 ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; 526 if (lts && lth && ltc) { 527 if (ltc->sadb_lifetime_addtime == 0) 528 t = (u_long)0; 529 else 530 t = (u_long)(cur - ltc->sadb_lifetime_addtime); 531 if (t >= 1000) 532 strcpy(buf, " big/"); 533 else 534 snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); 535 printf("%s", buf); 536 537 t = (u_long)lth->sadb_lifetime_addtime; 538 if (t >= 1000) 539 strcpy(buf, "big"); 540 else 541 snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); 542 printf("%s", buf); 543 } else 544 printf(" ???/???"); 545 546 printf(" "); 547 548 if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { 549 if (saddr->sadb_address_proto) 550 printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); 551 s = (struct sockaddr *)(saddr + 1); 552 getnameinfo(s, s->sa_len, buf, sizeof(buf), 553 pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); 554 if (strcmp(pbuf, "0") != 0) 555 printf("%s[%s]", buf, pbuf); 556 else 557 printf("%s", buf); 558 } else 559 printf("?"); 560 561 printf(" -> "); 562 563 if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { 564 if (saddr->sadb_address_proto) 565 printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); 566 567 s = (struct sockaddr *)(saddr + 1); 568 getnameinfo(s, s->sa_len, buf, sizeof(buf), 569 pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); 570 if (strcmp(pbuf, "0") != 0) 571 printf("%s[%s]", buf, pbuf); 572 else 573 printf("%s", buf); 574 } else 575 printf("?"); 576 577 printf("\n"); 578 } 579