1 /* $KAME$ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/socket.h> 36 #include <sys/uio.h> 37 #include <sys/time.h> 38 39 #include <string.h> 40 41 #include <net/route.h> 42 43 #include <netinet/in_systm.h> 44 #include <netinet/in.h> 45 #include <netinet/ip.h> 46 #include <netinet/ip6.h> 47 #include <netinet/icmp6.h> 48 49 #include <arpa/inet.h> 50 51 #ifdef IPSEC 52 #include <netinet6/ipsec.h> 53 #endif 54 55 #include <stdio.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <stdlib.h> 59 #include <unistd.h> 60 #include <syslog.h> 61 62 #include "rrenumd.h" 63 64 #define LL_ALLROUTERS "ff02::2" 65 #define SL_ALLROUTERS "ff05::2" 66 67 #ifndef IN6_IS_SCOPE_LINKLOCAL 68 #define IN6_IS_SCOPE_LINKLOCAL(a) \ 69 ((IN6_IS_ADDR_LINKLOCAL(a)) || \ 70 (IN6_IS_ADDR_MC_LINKLOCAL(a))) 71 #endif /* IN6_IS_SCOPE_LINKLOCAL */ 72 73 struct flags { 74 u_long debug : 1; 75 u_long fg : 1; 76 #ifdef IPSEC 77 #ifdef IPSEC_POLICY_IPSEC 78 u_long policy : 1; 79 #else /* IPSEC_POLICY_IPSEC */ 80 u_long auth : 1; 81 u_long encrypt : 1; 82 #endif /* IPSEC_POLICY_IPSEC */ 83 #endif /*IPSEC*/ 84 }; 85 86 struct msghdr sndmhdr; 87 struct msghdr rcvmhdr; 88 struct sockaddr_in6 from; 89 struct sockaddr_in6 sin6_ll_allrouters; 90 91 int s4, s6; 92 int with_v4dest, with_v6dest; 93 struct in6_addr prefix; /* ADHOC */ 94 int prefixlen = 64; /* ADHOC */ 95 96 extern int parse(FILE **fp); 97 98 /* Print usage. Don't call this after daemonized. */ 99 static void 100 show_usage() 101 { 102 fprintf(stderr, "usage: rrenumd [-c conf_file|-s] [-df" 103 #ifdef IPSEC 104 #ifdef IPSEC_POLICY_IPSEC 105 "] [-P policy" 106 #else /* IPSEC_POLICY_IPSEC */ 107 "AE" 108 #endif /* IPSEC_POLICY_IPSEC */ 109 #endif /* IPSEC */ 110 "]\n"); 111 exit(1); 112 } 113 114 void 115 init_sin6(struct sockaddr_in6 *sin6, const char *addr_ascii) 116 { 117 memset(sin6, 0, sizeof(*sin6)); 118 sin6->sin6_len = sizeof(*sin6); 119 sin6->sin6_family = AF_INET6; 120 if (inet_pton(AF_INET6, addr_ascii, &sin6->sin6_addr) != 1) 121 ; /* XXX do something */ 122 } 123 124 #if 0 /* XXX: not necessary ?? */ 125 void 126 join_multi(const char *addrname) 127 { 128 struct ipv6_mreq mreq; 129 130 if (inet_pton(AF_INET6, addrname, &mreq.ipv6mr_multiaddr.s6_addr) 131 != 1) { 132 syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", 133 __FUNCTION__); 134 exit(1); 135 } 136 /* ADHOC: currently join only one */ 137 { 138 if ((mreq.ipv6mr_interface = if_nametoindex(ifname)) == 0) { 139 syslog(LOG_ERR, "<%s> ifname %s should be invalid: %s", 140 __FUNCTION__, ifname, strerror(errno)); 141 exit(1); 142 } 143 if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, 144 &mreq, 145 sizeof(mreq)) < 0) { 146 syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", 147 __FUNCTION__, ifname, strerror(errno)); 148 exit(1); 149 } 150 } 151 } 152 #endif 153 154 void 155 init_globals() 156 { 157 static struct iovec rcviov; 158 static u_char rprdata[4500]; /* maximal MTU of connected links */ 159 static u_char *rcvcmsgbuf = NULL; 160 static u_char *sndcmsgbuf = NULL; 161 int sndcmsglen, rcvcmsglen; 162 163 /* init ll_allrouters */ 164 init_sin6(&sin6_ll_allrouters, LL_ALLROUTERS); 165 166 /* initialize msghdr for receiving packets */ 167 rcviov.iov_base = (caddr_t)rprdata; 168 rcviov.iov_len = sizeof(rprdata); 169 rcvmhdr.msg_namelen = sizeof(struct sockaddr_in6); 170 rcvmhdr.msg_iov = &rcviov; 171 rcvmhdr.msg_iovlen = 1; 172 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 173 CMSG_SPACE(sizeof(int)); 174 if (rcvcmsgbuf == NULL && 175 (rcvcmsgbuf = (u_char *)malloc(rcvcmsglen)) == NULL) { 176 syslog(LOG_ERR, "<%s>: malloc failed", __FUNCTION__); 177 exit(1); 178 } 179 rcvmhdr.msg_control = (caddr_t)rcvcmsgbuf; 180 rcvmhdr.msg_controllen = rcvcmsglen; 181 182 /* initialize msghdr for sending packets */ 183 sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 184 sndmhdr.msg_iovlen = 1; 185 sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 186 CMSG_SPACE(sizeof(int)); 187 if (sndcmsgbuf == NULL && 188 (sndcmsgbuf = (u_char *)malloc(sndcmsglen)) == NULL) { 189 syslog(LOG_ERR, "<%s>: malloc failed", __FUNCTION__); 190 exit(1); 191 } 192 sndmhdr.msg_control = (caddr_t)sndcmsgbuf; 193 sndmhdr.msg_controllen = sndcmsglen; 194 } 195 196 void 197 config(FILE **fpp) 198 { 199 struct payload_list *pl; 200 struct iovec *iov; 201 struct icmp6_router_renum *irr; 202 struct rr_pco_match *rpm; 203 204 if (parse(fpp) < 0) { 205 syslog(LOG_ERR, "<%s> parse failed", __FUNCTION__); 206 exit(1); 207 } 208 209 /* initialize fields not configured by parser */ 210 for (pl = pl_head; pl; pl = pl->pl_next) { 211 iov = (struct iovec *)&pl->pl_sndiov; 212 irr = (struct icmp6_router_renum *)&pl->pl_irr; 213 rpm = (struct rr_pco_match *)&pl->pl_rpm; 214 215 irr->rr_type = ICMP6_ROUTER_RENUMBERING; 216 irr->rr_code = 0; 217 /* 218 * now we don't support multiple PCOs in a rr message. 219 * so segment number is not supported. 220 */ 221 /* TODO: rr flags config in parser */ 222 irr->rr_flags |= ICMP6_RR_FLAGS_SPECSITE; 223 /* TODO: max delay config in parser */ 224 225 /* 226 * means only 1 use_prefix is contained as router-renum-05.txt. 227 * now we don't support multiple PCOs in a rr message, 228 * nor multiple use_prefix in one PCO. 229 */ 230 rpm->rpm_len = 4*1 +3; 231 rpm->rpm_ordinal = 0; 232 iov->iov_base = (caddr_t)irr; 233 iov->iov_len = sizeof(struct icmp6_router_renum) 234 + sizeof(struct rr_pco_match) 235 + sizeof(struct rr_pco_use); 236 } 237 } 238 239 void 240 sock6_open(struct flags *flags 241 #ifdef IPSEC_POLICY_IPSEC 242 , char *policy 243 #endif /* IPSEC_POLICY_IPSEC */ 244 ) 245 { 246 struct icmp6_filter filt; 247 int on; 248 #ifdef IPSEC 249 #ifndef IPSEC_POLICY_IPSEC 250 int optval; 251 #endif 252 #endif 253 254 if (with_v6dest == 0) 255 return; 256 if (with_v6dest && 257 (s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 258 syslog(LOG_ERR, "<%s> socket(v6): %s", __FUNCTION__, 259 strerror(errno)); 260 exit(1); 261 } 262 263 /* 264 * join all routers multicast addresses. 265 */ 266 #if 0 /* XXX: not necessary ?? */ 267 join_multi(LL_ALLROUTERS); 268 join_multi(SL_ALLROUTERS); 269 #endif 270 271 /* set icmpv6 filter */ 272 ICMP6_FILTER_SETBLOCKALL(&filt); 273 ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); 274 if (setsockopt(s6, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 275 sizeof(filt)) < 0) { 276 syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", 277 __FUNCTION__, strerror(errno)); 278 exit(1); 279 } 280 281 /* specify to tell receiving interface */ 282 on = 1; 283 if (setsockopt(s6, IPPROTO_IPV6, IPV6_PKTINFO, &on, 284 sizeof(on)) < 0) { 285 syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", 286 __FUNCTION__, strerror(errno)); 287 exit(1); 288 } 289 290 #ifdef IPSEC 291 #ifdef IPSEC_POLICY_IPSEC 292 if (flags->policy) { 293 char *buf; 294 buf = ipsec_set_policy(policy, strlen(policy)); 295 if (buf == NULL) 296 errx(1, "%s", ipsec_strerror()); 297 /* XXX should handle in/out bound policy. */ 298 if (setsockopt(s6, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 299 buf, ipsec_get_policylen(buf)) < 0) 300 err(1, NULL); 301 free(buf); 302 } 303 #else /* IPSEC_POLICY_IPSEC */ 304 if (flags->auth) { 305 optval = IPSEC_LEVEL_REQUIRE; 306 if (setsockopt(s6, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 307 &optval, sizeof(optval)) == -1) { 308 syslog(LOG_ERR, "<%s> IPV6_AUTH_TRANS_LEVEL: %s", 309 __FUNCTION__, strerror(errno)); 310 exit(1); 311 } 312 } 313 if (flags->encrypt) { 314 optval = IPSEC_LEVEL_REQUIRE; 315 if (setsockopt(s6, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 316 &optval, sizeof(optval)) == -1) { 317 syslog(LOG_ERR, "<%s> IPV6_ESP_TRANS_LEVEL: %s", 318 __FUNCTION__, strerror(errno)); 319 exit(1); 320 } 321 } 322 #endif /* IPSEC_POLICY_IPSEC */ 323 #endif /* IPSEC */ 324 325 return; 326 } 327 328 void 329 sock4_open(struct flags *flags 330 #ifdef IPSEC_POLICY_IPSEC 331 , char *policy 332 #endif /* IPSEC_POLICY_IPSEC */ 333 ) 334 { 335 #ifdef IPSEC 336 #ifndef IPSEC_POLICY_IPSEC 337 int optval; 338 #endif 339 #endif 340 341 if (with_v4dest == 0) 342 return; 343 if ((s4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 344 syslog(LOG_ERR, "<%s> socket(v4): %s", __FUNCTION__, 345 strerror(errno)); 346 exit(1); 347 } 348 349 #if 0 /* XXX: not necessary ?? */ 350 /* 351 * join all routers multicast addresses. 352 */ 353 some_join_function(); 354 #endif 355 356 #ifdef IPSEC 357 #ifdef IPSEC_POLICY_IPSEC 358 if (flags->policy) { 359 char *buf; 360 buf = ipsec_set_policy(policy, strlen(policy)); 361 if (buf == NULL) 362 errx(1, "%s", ipsec_strerror()); 363 /* XXX should handle in/out bound policy. */ 364 if (setsockopt(s4, IPPROTO_IP, IP_IPSEC_POLICY, 365 buf, ipsec_get_policylen(buf)) < 0) 366 err(1, NULL); 367 free(buf); 368 } 369 #else /* IPSEC_POLICY_IPSEC */ 370 if (flags->auth) { 371 optval = IPSEC_LEVEL_REQUIRE; 372 if (setsockopt(s4, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, 373 &optval, sizeof(optval)) == -1) { 374 syslog(LOG_ERR, "<%s> IP_AUTH_TRANS_LEVEL: %s", 375 __FUNCTION__, strerror(errno)); 376 exit(1); 377 } 378 } 379 if (flags->encrypt) { 380 optval = IPSEC_LEVEL_REQUIRE; 381 if (setsockopt(s4, IPPROTO_IP, IP_ESP_TRANS_LEVEL, 382 &optval, sizeof(optval)) == -1) { 383 syslog(LOG_ERR, "<%s> IP_ESP_TRANS_LEVEL: %s", 384 __FUNCTION__, strerror(errno)); 385 exit(1); 386 } 387 } 388 #endif /* IPSEC_POLICY_IPSEC */ 389 #endif /* IPSEC */ 390 391 return; 392 } 393 394 void 395 rrenum_output(struct payload_list *pl, struct dst_list *dl) 396 { 397 int i, msglen = 0; 398 struct cmsghdr *cm; 399 struct in6_pktinfo *pi; 400 struct sockaddr_in6 *sin6 = NULL; 401 402 sndmhdr.msg_name = (caddr_t)dl->dl_dst; 403 if (dl->dl_dst->sa_family == AF_INET6) 404 sin6 = (struct sockaddr_in6 *)dl->dl_dst; 405 406 if (sin6 != NULL && 407 IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 408 int hoplimit = 255; 409 410 cm = CMSG_FIRSTHDR(&sndmhdr); 411 /* specify the outgoing interface */ 412 cm->cmsg_level = IPPROTO_IPV6; 413 cm->cmsg_type = IPV6_PKTINFO; 414 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 415 pi = (struct in6_pktinfo *)CMSG_DATA(cm); 416 memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ 417 pi->ipi6_ifindex = sin6->sin6_scope_id; 418 msglen += CMSG_LEN(sizeof(struct in6_pktinfo)); 419 420 /* specify the hop limit of the packet if dest is link local */ 421 /* not defined by router-renum-05.txt, but maybe its OK */ 422 cm = CMSG_NXTHDR(&sndmhdr, cm); 423 cm->cmsg_level = IPPROTO_IPV6; 424 cm->cmsg_type = IPV6_HOPLIMIT; 425 cm->cmsg_len = CMSG_LEN(sizeof(int)); 426 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 427 msglen += CMSG_LEN(sizeof(int)); 428 } 429 sndmhdr.msg_controllen = msglen; 430 if (sndmhdr.msg_controllen == 0) 431 sndmhdr.msg_control = 0; 432 433 sndmhdr.msg_iov = &pl->pl_sndiov; 434 i = sendmsg(dl->dl_dst->sa_family == AF_INET ? s4 : s6, &sndmhdr, 0); 435 436 if (i < 0 || i != sndmhdr.msg_iov->iov_len) 437 syslog(LOG_ERR, "<%s> sendmsg: %s", __FUNCTION__, 438 strerror(errno)); 439 } 440 441 void 442 rrenum_snd_eachdst(struct payload_list *pl) 443 { 444 struct dst_list *dl; 445 446 for (dl = dl_head; dl; dl = dl->dl_next) { 447 rrenum_output(pl, dl); 448 } 449 } 450 451 void 452 rrenum_snd_fullsequence() 453 { 454 struct payload_list *pl; 455 456 for (pl = pl_head; pl; pl = pl->pl_next) { 457 rrenum_snd_eachdst(pl); 458 } 459 } 460 461 void 462 rrenum_input(int s) 463 { 464 int i; 465 struct icmp6_router_renum *rr; 466 467 /* get message */ 468 if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { 469 syslog(LOG_ERR, "<%s> recvmsg: %s", __FUNCTION__, 470 strerror(errno)); 471 return; 472 } 473 if (s == s4) 474 i -= sizeof(struct ip); 475 if (i < sizeof(struct icmp6_router_renum)) { 476 syslog(LOG_ERR, "<%s> packet size(%d) is too short", 477 __FUNCTION__, i); 478 return; 479 } 480 if (s == s4) { 481 struct ip *ip = (struct ip *)rcvmhdr.msg_iov->iov_base; 482 483 rr = (struct icmp6_router_renum *)(ip + 1); 484 } else /* s == s6 */ 485 rr = (struct icmp6_router_renum *)rcvmhdr.msg_iov->iov_base; 486 487 switch(rr->rr_code) { 488 case ICMP6_ROUTER_RENUMBERING_COMMAND: 489 /* COMMAND will be processed by rtadvd */ 490 break; 491 case ICMP6_ROUTER_RENUMBERING_RESULT: 492 /* TODO: receiving result message */ 493 break; 494 default: 495 syslog(LOG_ERR, "<%s> received unknown code %d", 496 __FUNCTION__, rr->rr_code); 497 break; 498 } 499 } 500 501 int 502 main(int argc, char *argv[]) 503 { 504 FILE *fp = stdin; 505 fd_set fdset; 506 struct timeval timeout; 507 int ch, i, maxfd = 0, send_counter = 0; 508 struct flags flags; 509 struct payload_list *pl; 510 #ifdef IPSEC_POLICY_IPSEC 511 char *policy = NULL; 512 #endif 513 514 memset(&flags, 0, sizeof(flags)); 515 openlog("rrenumd", LOG_PID, LOG_DAEMON); 516 517 /* get options */ 518 while ((ch = getopt(argc, argv, "c:sdf" 519 #ifdef IPSEC 520 #ifdef IPSEC_POLICY_IPSEC 521 "P" 522 #else /* IPSEC_POLICY_IPSEC */ 523 "AE" 524 #endif /* IPSEC_POLICY_IPSEC */ 525 #endif /* IPSEC */ 526 )) != -1){ 527 switch (ch) { 528 case 'c': 529 if((fp = fopen(optarg, "r")) == NULL) { 530 syslog(LOG_ERR, 531 "<%s> config file %s open failed", 532 __FUNCTION__, optarg); 533 exit(1); 534 } 535 break; 536 case 's': 537 fp = stdin; 538 break; 539 case 'd': 540 flags.debug = 1; 541 break; 542 case 'f': 543 flags.fg = 1; 544 break; 545 #ifdef IPSEC 546 #ifdef IPSEC_POLICY_IPSEC 547 case 'P': 548 flags.policy = 1; 549 policy = strdup(optarg); 550 break; 551 #else /* IPSEC_POLICY_IPSEC */ 552 case 'A': 553 flags.auth = 1; 554 break; 555 case 'E': 556 flags.encrypt = 1; 557 break; 558 #endif /* IPSEC_POLICY_IPSEC */ 559 #endif /*IPSEC*/ 560 default: 561 show_usage(); 562 } 563 } 564 argc -= optind; 565 argv += optind; 566 567 /* set log level */ 568 if (flags.debug == 0) 569 (void)setlogmask(LOG_UPTO(LOG_ERR)); 570 if (flags.debug == 1) 571 (void)setlogmask(LOG_UPTO(LOG_INFO)); 572 573 /* init global variables */ 574 init_globals(); 575 576 config(&fp); 577 578 sock6_open(&flags 579 #ifdef IPSEC_POLICY_IPSEC 580 , policy 581 #endif /* IPSEC_POLICY_IPSEC */ 582 ); 583 sock4_open(&flags 584 #ifdef IPSEC_POLICY_IPSEC 585 , policy 586 #endif /* IPSEC_POLICY_IPSEC */ 587 ); 588 589 if (!flags.fg) 590 daemon(0, 0); 591 592 FD_ZERO(&fdset); 593 if (with_v6dest) { 594 FD_SET(s6, &fdset); 595 if (s6 > maxfd) 596 maxfd = s6; 597 } 598 if (with_v4dest) { 599 FD_SET(s4, &fdset); 600 if (s4 > maxfd) 601 maxfd = s4; 602 } 603 604 /* ADHOC: timeout each 30seconds */ 605 memset(&timeout, 0, sizeof(timeout)); 606 timeout.tv_sec = 30; 607 608 /* init temporal payload_list and send_counter*/ 609 pl = pl_head; 610 send_counter = retry + 1; 611 while (1) { 612 struct fd_set select_fd = fdset; /* reinitialize */ 613 614 if ((i = select(maxfd + 1, &select_fd, NULL, NULL, 615 &timeout)) < 0){ 616 syslog(LOG_ERR, "<%s> select: %s", 617 __FUNCTION__, strerror(errno)); 618 continue; 619 } 620 if (i == 0) { /* timeout */ 621 if (pl == NULL) 622 exit(0); 623 rrenum_snd_eachdst(pl); 624 send_counter--; 625 if (send_counter == 0) { 626 pl = pl->pl_next; 627 send_counter = retry + 1; 628 } 629 } 630 if (FD_ISSET(s4, &select_fd)) 631 rrenum_input(s4); 632 if (FD_ISSET(s6, &select_fd)) 633 rrenum_input(s6); 634 } 635 } 636