1 /* 2 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 /* KAME $Id: setkey.c,v 1.5 1999/10/26 09:39:37 sakane Exp $ */ 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 void Usage __P((void)); 55 int main __P((int, char **)); 56 int get_supported __P((void)); 57 void sendkeyshort __P((u_int)); 58 void promisc __P((void)); 59 int sendkeymsg __P((void)); 60 int postproc __P((struct sadb_msg *, int)); 61 const char *numstr __P((int)); 62 void shortdump_hdr __P((void)); 63 void shortdump __P((struct sadb_msg *)); 64 65 #define MODE_SCRIPT 1 66 #define MODE_CMDDUMP 2 67 #define MODE_CMDFLUSH 3 68 69 int so; 70 71 int f_forever = 0; 72 int f_all = 0; 73 int f_debug = 0; 74 int f_verbose = 0; 75 int f_mode = 0; 76 int f_cmddump = 0; 77 int f_policy = 0; 78 int f_promisc = 0; 79 int f_hexdump = 0; 80 char *pname; 81 82 u_char m_buf[BUFSIZ]; 83 u_int m_len; 84 85 extern int lineno; 86 87 extern int parse __P((FILE **)); 88 89 void 90 Usage() 91 { 92 printf("Usage:\t%s [-dv] -c\n", pname); 93 printf("\t%s [-dv] -f (file)\n", pname); 94 printf("\t%s [-Padlv] -D\n", pname); 95 printf("\t%s [-Pdv] -F\n", pname); 96 printf("\t%s [-h] -x\n", pname); 97 pfkey_close(so); 98 exit(0); 99 } 100 101 int 102 main(ac, av) 103 int ac; 104 char **av; 105 { 106 FILE *fp = stdin; 107 int c; 108 109 pname = *av; 110 111 if (ac == 1) Usage(); 112 113 while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) { 114 switch (c) { 115 case 'c': 116 f_mode = MODE_SCRIPT; 117 fp = stdin; 118 break; 119 case 'f': 120 f_mode = MODE_SCRIPT; 121 if ((fp = fopen(optarg, "r")) == NULL) { 122 err(-1, "fopen"); 123 /*NOTREACHED*/ 124 } 125 break; 126 case 'D': 127 f_mode = MODE_CMDDUMP; 128 break; 129 case 'F': 130 f_mode = MODE_CMDFLUSH; 131 break; 132 case 'a': 133 f_all = 1; 134 break; 135 case 'l': 136 f_forever = 1; 137 break; 138 case 'h': 139 f_hexdump = 1; 140 break; 141 case 'x': 142 f_promisc = 1; 143 promisc(); 144 /*NOTREACHED*/ 145 case 'P': 146 f_policy = 1; 147 break; 148 case 'd': 149 f_debug = 1; 150 break; 151 case 'v': 152 f_verbose = 1; 153 break; 154 default: 155 Usage(); 156 /*NOTREACHED*/ 157 } 158 } 159 160 switch (f_mode) { 161 case MODE_CMDDUMP: 162 sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); 163 break; 164 case MODE_CMDFLUSH: 165 sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); 166 pfkey_close(so); 167 break; 168 case MODE_SCRIPT: 169 if (get_supported() < 0) { 170 errx(-1, "%s", ipsec_strerror()); 171 /*NOTREACHED*/ 172 } 173 parse(&fp); 174 break; 175 default: 176 Usage(); 177 } 178 179 exit(0); 180 } 181 182 int 183 get_supported() 184 { 185 int so; 186 187 if ((so = pfkey_open()) < 0) { 188 perror("pfkey_open"); 189 return -1; 190 } 191 192 /* debug mode ? */ 193 if (f_debug) 194 return 0; 195 196 if (pfkey_send_register(so, PF_UNSPEC) < 0) 197 return -1; 198 199 if (pfkey_recv_register(so) < 0) 200 return -1; 201 202 return 0; 203 } 204 205 void 206 sendkeyshort(type) 207 u_int type; 208 { 209 struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; 210 211 m_len = sizeof(struct sadb_msg); 212 213 m_msg->sadb_msg_version = PF_KEY_V2; 214 m_msg->sadb_msg_type = type; 215 m_msg->sadb_msg_errno = 0; 216 m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC; 217 m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); 218 m_msg->sadb_msg_reserved = 0; 219 m_msg->sadb_msg_reserved = 0; 220 m_msg->sadb_msg_seq = 0; 221 m_msg->sadb_msg_pid = getpid(); 222 223 sendkeymsg(); 224 225 return; 226 } 227 228 void 229 promisc() 230 { 231 struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; 232 u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ 233 int so, len; 234 235 m_len = sizeof(struct sadb_msg); 236 237 m_msg->sadb_msg_version = PF_KEY_V2; 238 m_msg->sadb_msg_type = SADB_X_PROMISC; 239 m_msg->sadb_msg_errno = 0; 240 m_msg->sadb_msg_satype = 1; 241 m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); 242 m_msg->sadb_msg_reserved = 0; 243 m_msg->sadb_msg_reserved = 0; 244 m_msg->sadb_msg_seq = 0; 245 m_msg->sadb_msg_pid = getpid(); 246 247 if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { 248 err(1, "socket(PF_KEY)"); 249 /*NOTREACHED*/ 250 } 251 252 if ((len = send(so, m_buf, m_len, 0)) < 0) { 253 err(1, "send"); 254 /*NOTREACHED*/ 255 } 256 257 while (1) { 258 struct sadb_msg *base; 259 260 if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { 261 err(1, "recv"); 262 /*NOTREACHED*/ 263 } 264 265 if (len != sizeof(*base)) 266 continue; 267 268 base = (struct sadb_msg *)rbuf; 269 if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), 270 0)) < 0) { 271 err(1, "recv"); 272 /*NOTREACHED*/ 273 } 274 if (f_hexdump) { 275 int i; 276 for (i = 0; i < len; i++) { 277 if (i % 16 == 0) 278 printf("%08x: ", i); 279 printf("%02x ", rbuf[i] & 0xff); 280 if (i % 16 == 15) 281 printf("\n"); 282 } 283 if (len % 16) 284 printf("\n"); 285 } 286 /* adjust base pointer for promisc mode */ 287 if (base->sadb_msg_type == SADB_X_PROMISC) { 288 if (sizeof(*base) < len) 289 base++; 290 else 291 base = NULL; 292 } 293 if (base) { 294 kdebug_sadb(base); 295 printf("\n"); 296 fflush(stdout); 297 } 298 } 299 } 300 301 int 302 sendkeymsg() 303 { 304 int so; 305 306 u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ 307 int len; 308 struct sadb_msg *msg; 309 310 if ((so = pfkey_open()) < 0) { 311 perror("pfkey_open"); 312 return -1; 313 } 314 315 { 316 struct timeval tv; 317 tv.tv_sec = 1; 318 tv.tv_usec = 0; 319 if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { 320 perror("setsockopt"); 321 goto end; 322 } 323 } 324 325 if (f_forever) 326 shortdump_hdr(); 327 again: 328 if (f_verbose) 329 kdebug_sadb((struct sadb_msg *)m_buf); 330 331 if ((len = send(so, m_buf, m_len, 0)) < 0) { 332 perror("send"); 333 goto end; 334 } 335 336 msg = (struct sadb_msg *)rbuf; 337 do { 338 if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { 339 perror("recv"); 340 goto end; 341 } 342 343 if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) { 344 warnx("invalid keymsg length"); 345 break; 346 } 347 348 if (f_verbose) 349 kdebug_sadb((struct sadb_msg *)rbuf); 350 if (postproc(msg, len) < 0) 351 break; 352 } while (msg->sadb_msg_errno || msg->sadb_msg_seq); 353 354 if (f_forever) { 355 fflush(stdout); 356 sleep(1); 357 goto again; 358 } 359 360 end: 361 pfkey_close(so); 362 return(0); 363 } 364 365 int 366 postproc(msg, len) 367 struct sadb_msg *msg; 368 int len; 369 { 370 371 if (msg->sadb_msg_errno != 0) { 372 char inf[80]; 373 char *errmsg = NULL; 374 375 if (f_mode == MODE_SCRIPT) 376 snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); 377 else 378 inf[0] = '\0'; 379 380 switch (msg->sadb_msg_errno) { 381 case ENOENT: 382 switch (msg->sadb_msg_type) { 383 case SADB_DELETE: 384 case SADB_GET: 385 case SADB_X_SPDDELETE: 386 errmsg = "No entry"; 387 break; 388 case SADB_DUMP: 389 errmsg = "No SAD entries"; 390 break; 391 case SADB_X_SPDDUMP: 392 errmsg = "No SPD entries"; 393 break; 394 } 395 break; 396 default: 397 errmsg = strerror(msg->sadb_msg_errno); 398 } 399 printf("%s%s.\n", inf, errmsg); 400 return(-1); 401 } 402 403 switch (msg->sadb_msg_type) { 404 case SADB_GET: 405 pfkey_sadump(msg); 406 break; 407 408 case SADB_DUMP: 409 /* filter out DEAD SAs */ 410 if (!f_all) { 411 caddr_t mhp[SADB_EXT_MAX + 1]; 412 struct sadb_sa *sa; 413 pfkey_align(msg, mhp); 414 pfkey_check(mhp); 415 if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { 416 if (sa->sadb_sa_state == SADB_SASTATE_DEAD) 417 break; 418 } 419 } 420 if (f_forever) 421 shortdump(msg); 422 else 423 pfkey_sadump(msg); 424 msg = (struct sadb_msg *)((caddr_t)msg + 425 PFKEY_UNUNIT64(msg->sadb_msg_len)); 426 if (f_verbose) 427 kdebug_sadb((struct sadb_msg *)msg); 428 break; 429 430 case SADB_X_SPDDUMP: 431 pfkey_spdump(msg); 432 if (msg->sadb_msg_seq == 0) break; 433 msg = (struct sadb_msg *)((caddr_t)msg + 434 PFKEY_UNUNIT64(msg->sadb_msg_len)); 435 if (f_verbose) 436 kdebug_sadb((struct sadb_msg *)msg); 437 break; 438 } 439 440 return(0); 441 } 442 443 /*------------------------------------------------------------*/ 444 static char *satype[] = { 445 NULL, NULL, "ah", "esp" 446 }; 447 static char *sastate[] = { 448 "L", "M", "D", "d" 449 }; 450 static char *ipproto[] = { 451 /*0*/ "ip", "icmp", "igmp", "ggp", "ip4", 452 NULL, "tcp", NULL, "egp", NULL, 453 /*10*/ NULL, NULL, NULL, NULL, NULL, 454 NULL, NULL, "udp", NULL, NULL, 455 /*20*/ NULL, NULL, "idp", NULL, NULL, 456 NULL, NULL, NULL, NULL, "tp", 457 /*30*/ NULL, NULL, NULL, NULL, NULL, 458 NULL, NULL, NULL, NULL, NULL, 459 /*40*/ NULL, "ip6", NULL, "rt6", "frag6", 460 NULL, "rsvp", "gre", NULL, NULL, 461 /*50*/ "esp", "ah", NULL, NULL, NULL, 462 NULL, NULL, NULL, "icmp6", "none", 463 /*60*/ "dst6", 464 }; 465 466 #define STR_OR_ID(x, tab) \ 467 (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) 468 469 const char * 470 numstr(x) 471 int x; 472 { 473 static char buf[20]; 474 snprintf(buf, sizeof(buf), "#%d", x); 475 return buf; 476 } 477 478 void 479 shortdump_hdr() 480 { 481 printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", 482 "time", "p", "s", "spi", "ltime", "src", "dst"); 483 } 484 485 void 486 shortdump(msg) 487 struct sadb_msg *msg; 488 { 489 caddr_t mhp[SADB_EXT_MAX + 1]; 490 char buf[1024], pbuf[10]; 491 struct sadb_sa *sa; 492 struct sadb_address *saddr; 493 struct sadb_lifetime *lts, *lth, *ltc; 494 struct sockaddr *s; 495 u_int t; 496 time_t cur = time(0); 497 498 pfkey_align(msg, mhp); 499 pfkey_check(mhp); 500 501 printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); 502 503 printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); 504 505 if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { 506 printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); 507 printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); 508 } else 509 printf("%-1s %-8s", "?", "?"); 510 511 lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; 512 lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; 513 ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; 514 if (lts && lth && ltc) { 515 if (ltc->sadb_lifetime_addtime == 0) 516 t = (u_long)0; 517 else 518 t = (u_long)(cur - ltc->sadb_lifetime_addtime); 519 if (t >= 1000) 520 strcpy(buf, " big/"); 521 else 522 snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); 523 printf("%s", buf); 524 525 t = (u_long)lth->sadb_lifetime_addtime; 526 if (t >= 1000) 527 strcpy(buf, "big"); 528 else 529 snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); 530 printf("%s", buf); 531 } else 532 printf(" ???/???"); 533 534 printf(" "); 535 536 if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { 537 if (saddr->sadb_address_proto) 538 printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); 539 s = (struct sockaddr *)(saddr + 1); 540 getnameinfo(s, s->sa_len, buf, sizeof(buf), 541 pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); 542 if (strcmp(pbuf, "0") != 0) 543 printf("%s[%s]", buf, pbuf); 544 else 545 printf("%s", buf); 546 } else 547 printf("?"); 548 549 printf(" -> "); 550 551 if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { 552 if (saddr->sadb_address_proto) 553 printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); 554 555 s = (struct sockaddr *)(saddr + 1); 556 getnameinfo(s, s->sa_len, buf, sizeof(buf), 557 pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); 558 if (strcmp(pbuf, "0") != 0) 559 printf("%s[%s]", buf, pbuf); 560 else 561 printf("%s", buf); 562 } else 563 printf("?"); 564 565 printf("\n"); 566 } 567