1 /* 2 * Copyright (c) 1995 3 * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; 37 #endif 38 static const char rcsid[] = 39 "$Id$"; 40 #endif /* not lint */ 41 42 #include "defs.h" 43 #include <netinet/in_systm.h> 44 #include <netinet/ip.h> 45 #include <netinet/ip_icmp.h> 46 47 /* router advertisement ICMP packet */ 48 struct icmp_ad { 49 u_int8_t icmp_type; /* type of message */ 50 u_int8_t icmp_code; /* type sub code */ 51 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 52 u_int8_t icmp_ad_num; /* # of following router addresses */ 53 u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 54 u_int16_t icmp_ad_life; /* seconds of validity */ 55 struct icmp_ad_info { 56 n_long icmp_ad_addr; 57 n_long icmp_ad_pref; 58 } icmp_ad_info[1]; 59 }; 60 61 /* router solicitation ICMP packet */ 62 struct icmp_so { 63 u_int8_t icmp_type; /* type of message */ 64 u_int8_t icmp_code; /* type sub code */ 65 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 66 n_long icmp_so_rsvd; 67 }; 68 69 union ad_u { 70 struct icmp icmp; 71 struct icmp_ad ad; 72 struct icmp_so so; 73 }; 74 75 76 int rdisc_sock = -1; /* router-discovery raw socket */ 77 struct interface *rdisc_sock_mcast; /* current multicast interface */ 78 79 struct timeval rdisc_timer; 80 int rdisc_ok; /* using solicited route */ 81 82 83 #define MAX_ADS 5 84 struct dr { /* accumulated advertisements */ 85 struct interface *dr_ifp; 86 naddr dr_gate; /* gateway */ 87 time_t dr_ts; /* when received */ 88 time_t dr_life; /* lifetime */ 89 n_long dr_recv_pref; /* received but biased preference */ 90 n_long dr_pref; /* preference adjusted by metric */ 91 } *cur_drp, drs[MAX_ADS]; 92 93 /* adjust preference by interface metric without driving it to infinity */ 94 #define PREF(p, ifp) ((p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ 95 : (p) - ((ifp)->int_metric)) 96 97 static void rdisc_sort(void); 98 99 100 /* dump an ICMP Router Discovery Advertisement Message 101 */ 102 static void 103 trace_rdisc(char *act, 104 naddr from, 105 naddr to, 106 struct interface *ifp, 107 union ad_u *p, 108 u_int len) 109 { 110 int i; 111 n_long *wp, *lim; 112 113 114 if (!TRACEPACKETS || ftrace == 0) 115 return; 116 117 lastlog(); 118 119 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 120 (void)fprintf(ftrace, "%s Router Ad" 121 " from %s to %s via %s life=%d\n", 122 act, naddr_ntoa(from), naddr_ntoa(to), 123 ifp ? ifp->int_name : "?", 124 ntohs(p->ad.icmp_ad_life)); 125 if (!TRACECONTENTS) 126 return; 127 128 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 129 lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 130 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 131 (void)fprintf(ftrace, "\t%s preference=%d", 132 naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 133 wp += p->ad.icmp_ad_asize; 134 } 135 (void)fputc('\n',ftrace); 136 137 } else { 138 trace_act("%s Router Solic. from %s to %s via %s value=%#x", 139 act, naddr_ntoa(from), naddr_ntoa(to), 140 ifp ? ifp->int_name : "?", 141 ntohl(p->so.icmp_so_rsvd)); 142 } 143 } 144 145 /* prepare Router Discovery socket. 146 */ 147 static void 148 get_rdisc_sock(void) 149 { 150 if (rdisc_sock < 0) { 151 rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 152 if (rdisc_sock < 0) 153 BADERR(1,"rdisc_sock = socket()"); 154 fix_sock(rdisc_sock,"rdisc_sock"); 155 fix_select(); 156 } 157 } 158 159 160 /* Pick multicast group for router-discovery socket 161 */ 162 void 163 set_rdisc_mg(struct interface *ifp, 164 int on) /* 0=turn it off */ 165 { 166 struct ip_mreq m; 167 168 if (rdisc_sock < 0) { 169 /* Create the raw socket so that we can hear at least 170 * broadcast router discovery packets. 171 */ 172 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 173 || !on) 174 return; 175 get_rdisc_sock(); 176 } 177 178 if (!(ifp->int_if_flags & IFF_MULTICAST)) { 179 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 180 return; 181 } 182 183 #ifdef MCAST_PPP_BUG 184 if (ifp->int_if_flags & IFF_POINTOPOINT) 185 return; 186 #endif 187 bzero(&m, sizeof(m)); 188 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 189 ? ifp->int_dstaddr 190 : ifp->int_addr); 191 if (supplier 192 || (ifp->int_state & IS_NO_ADV_IN) 193 || !on) { 194 /* stop listening to advertisements 195 */ 196 if (ifp->int_state & IS_ALL_HOSTS) { 197 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 198 if (setsockopt(rdisc_sock, IPPROTO_IP, 199 IP_DROP_MEMBERSHIP, 200 &m, sizeof(m)) < 0) 201 LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); 202 ifp->int_state &= ~IS_ALL_HOSTS; 203 } 204 205 } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 206 /* start listening to advertisements 207 */ 208 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 209 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 210 &m, sizeof(m)) < 0) { 211 LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); 212 } else { 213 ifp->int_state |= IS_ALL_HOSTS; 214 } 215 } 216 217 if (!supplier 218 || (ifp->int_state & IS_NO_ADV_OUT) 219 || !on) { 220 /* stop listening to solicitations 221 */ 222 if (ifp->int_state & IS_ALL_ROUTERS) { 223 m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 224 if (setsockopt(rdisc_sock, IPPROTO_IP, 225 IP_DROP_MEMBERSHIP, 226 &m, sizeof(m)) < 0) 227 LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); 228 ifp->int_state &= ~IS_ALL_ROUTERS; 229 } 230 231 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 232 /* start hearing solicitations 233 */ 234 m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 235 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 236 &m, sizeof(m)) < 0) { 237 LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); 238 } else { 239 ifp->int_state |= IS_ALL_ROUTERS; 240 } 241 } 242 } 243 244 245 /* start supplying routes 246 */ 247 void 248 set_supplier(void) 249 { 250 struct interface *ifp; 251 struct dr *drp; 252 253 if (supplier_set) 254 return; 255 256 trace_act("start supplying routes"); 257 258 /* Forget discovered routes. 259 */ 260 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 261 drp->dr_recv_pref = 0; 262 drp->dr_life = 0; 263 } 264 rdisc_age(0); 265 266 supplier_set = 1; 267 supplier = 1; 268 269 /* Do not start advertising until we have heard some RIP routes */ 270 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 271 272 /* Switch router discovery multicast groups from soliciting 273 * to advertising. 274 */ 275 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 276 if (ifp->int_state & IS_BROKE) 277 continue; 278 ifp->int_rdisc_cnt = 0; 279 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 280 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 281 set_rdisc_mg(ifp, 1); 282 } 283 284 /* get rid of any redirects */ 285 del_redirects(0,0); 286 } 287 288 289 /* age discovered routes and find the best one 290 */ 291 void 292 rdisc_age(naddr bad_gate) 293 { 294 time_t sec; 295 struct dr *drp; 296 297 298 /* If only advertising, then do only that. */ 299 if (supplier) { 300 /* if switching from client to server, get rid of old 301 * default routes. 302 */ 303 if (cur_drp != 0) 304 rdisc_sort(); 305 rdisc_adv(); 306 return; 307 } 308 309 /* If we are being told about a bad router, 310 * then age the discovered default route, and if there is 311 * no alternative, solicit a replacement. 312 */ 313 if (bad_gate != 0) { 314 /* Look for the bad discovered default route. 315 * Age it and note its interface. 316 */ 317 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 318 if (drp->dr_ts == 0) 319 continue; 320 321 /* When we find the bad router, then age the route 322 * to at most SUPPLY_INTERVAL. 323 * This is contrary to RFC 1256, but defends against 324 * black holes. 325 */ 326 if (drp->dr_gate == bad_gate) { 327 sec = (now.tv_sec - drp->dr_life 328 + SUPPLY_INTERVAL); 329 if (drp->dr_ts > sec) { 330 trace_act("age 0.0.0.0 --> %s via %s", 331 naddr_ntoa(drp->dr_gate), 332 drp->dr_ifp->int_name); 333 drp->dr_ts = sec; 334 } 335 break; 336 } 337 } 338 } 339 340 /* delete old redirected routes to keep the kernel table small 341 */ 342 sec = (cur_drp == 0) ? MaxMaxAdvertiseInterval : cur_drp->dr_life; 343 del_redirects(bad_gate, now.tv_sec-sec); 344 345 rdisc_sol(); 346 347 rdisc_sort(); 348 } 349 350 351 /* Zap all routes discovered via an interface that has gone bad 352 * This should only be called when !(ifp->int_state & IS_ALIAS) 353 */ 354 void 355 if_bad_rdisc(struct interface *ifp) 356 { 357 struct dr *drp; 358 359 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 360 if (drp->dr_ifp != ifp) 361 continue; 362 drp->dr_recv_pref = 0; 363 drp->dr_life = 0; 364 } 365 366 rdisc_sort(); 367 } 368 369 370 /* mark an interface ok for router discovering. 371 */ 372 void 373 if_ok_rdisc(struct interface *ifp) 374 { 375 set_rdisc_mg(ifp, 1); 376 377 ifp->int_rdisc_cnt = 0; 378 ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 379 ? MIN_WAITTIME 380 : MAX_SOLICITATION_DELAY); 381 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 382 rdisc_timer = ifp->int_rdisc_timer; 383 } 384 385 386 /* get rid of a dead discovered router 387 */ 388 static void 389 del_rdisc(struct dr *drp) 390 { 391 struct interface *ifp; 392 int i; 393 394 395 del_redirects(drp->dr_gate, 0); 396 drp->dr_ts = 0; 397 drp->dr_life = 0; 398 399 400 /* Count the other discovered routes on the interface. 401 */ 402 i = 0; 403 ifp = drp->dr_ifp; 404 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 405 if (drp->dr_ts != 0 406 && drp->dr_ifp == ifp) 407 i++; 408 } 409 410 /* If that was the last good discovered router on the interface, 411 * then solicit a new one. 412 * This is contrary to RFC 1256, but defends against black holes. 413 */ 414 if (i == 0 415 && ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 416 trace_act("discovered route is bad--re-solicit routers via %s", 417 ifp->int_name); 418 ifp->int_rdisc_cnt = 0; 419 ifp->int_rdisc_timer.tv_sec = 0; 420 rdisc_sol(); 421 } 422 } 423 424 425 /* Find the best discovered route, 426 * and discard stale routers. 427 */ 428 static void 429 rdisc_sort(void) 430 { 431 struct dr *drp, *new_drp; 432 struct rt_entry *rt; 433 struct interface *ifp; 434 u_int new_st; 435 n_long new_pref; 436 437 438 /* Find the best discovered route. 439 */ 440 new_drp = 0; 441 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 442 if (drp->dr_ts == 0) 443 continue; 444 ifp = drp->dr_ifp; 445 446 /* Get rid of expired discovered routers. 447 */ 448 if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 449 del_rdisc(drp); 450 continue; 451 } 452 453 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 454 455 /* Update preference with possibly changed interface 456 * metric. 457 */ 458 drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 459 460 /* Prefer the current route to prevent thrashing. 461 * Prefer shorter lifetimes to speed the detection of 462 * bad routers. 463 * Avoid sick interfaces. 464 */ 465 if (new_drp == 0 466 || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 467 && (new_pref < drp->dr_pref 468 || (new_pref == drp->dr_pref 469 && (drp == cur_drp 470 || (new_drp != cur_drp 471 && new_drp->dr_life > drp->dr_life))))) 472 || ((new_st & IS_SICK) 473 && !(drp->dr_ifp->int_state & IS_SICK))) { 474 new_drp = drp; 475 new_st = drp->dr_ifp->int_state; 476 new_pref = drp->dr_pref; 477 } 478 } 479 480 /* switch to a better default route 481 */ 482 if (new_drp != cur_drp) { 483 rt = rtget(RIP_DEFAULT, 0); 484 485 /* Stop using discovered routes if they are all bad 486 */ 487 if (new_drp == 0) { 488 trace_act("turn off Router Discovery client"); 489 rdisc_ok = 0; 490 491 if (rt != 0 492 && (rt->rt_state & RS_RDISC)) { 493 rtchange(rt, rt->rt_state & ~RS_RDISC, 494 rt->rt_gate, rt->rt_router, 495 HOPCNT_INFINITY, 0, rt->rt_ifp, 496 now.tv_sec - GARBAGE_TIME, 0); 497 rtswitch(rt, 0); 498 } 499 500 /* turn on RIP if permitted */ 501 rip_on(0); 502 503 } else { 504 if (cur_drp == 0) { 505 trace_act("turn on Router Discovery client" 506 " using %s via %s", 507 naddr_ntoa(new_drp->dr_gate), 508 new_drp->dr_ifp->int_name); 509 510 rdisc_ok = 1; 511 512 } else { 513 trace_act("switch Router Discovery from" 514 " %s via %s to %s via %s", 515 naddr_ntoa(cur_drp->dr_gate), 516 cur_drp->dr_ifp->int_name, 517 naddr_ntoa(new_drp->dr_gate), 518 new_drp->dr_ifp->int_name); 519 } 520 521 if (rt != 0) { 522 rtchange(rt, rt->rt_state | RS_RDISC, 523 new_drp->dr_gate, new_drp->dr_gate, 524 0,0, new_drp->dr_ifp, 525 now.tv_sec, 0); 526 } else { 527 rtadd(RIP_DEFAULT, 0, 528 new_drp->dr_gate, new_drp->dr_gate, 529 HOPCNT_INFINITY-1, 0, 530 RS_RDISC, new_drp->dr_ifp); 531 } 532 533 /* Now turn off RIP and delete RIP routes, 534 * which might otherwise include the default 535 * we just modified. 536 */ 537 rip_off(); 538 } 539 540 cur_drp = new_drp; 541 } 542 } 543 544 545 /* handle a single address in an advertisement 546 */ 547 static void 548 parse_ad(naddr from, 549 naddr gate, 550 n_long pref, 551 u_short life, 552 struct interface *ifp) 553 { 554 static struct msg_limit bad_gate; 555 struct dr *drp, *new_drp; 556 557 558 if (gate == RIP_DEFAULT 559 || !check_dst(gate)) { 560 msglim(&bad_gate, from,"router %s advertising bad gateway %s", 561 naddr_ntoa(from), 562 naddr_ntoa(gate)); 563 return; 564 } 565 566 /* ignore pointers to ourself and routes via unreachable networks 567 */ 568 if (ifwithaddr(gate, 1, 0) != 0) { 569 trace_pkt(" discard Router Discovery Ad pointing at us"); 570 return; 571 } 572 if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 573 trace_pkt(" discard Router Discovery Ad" 574 " toward unreachable net"); 575 return; 576 } 577 578 /* Convert preference to an unsigned value 579 * and later bias it by the metric of the interface. 580 */ 581 pref = ntohl(pref) ^ MIN_PreferenceLevel; 582 583 if (pref == 0 || life == 0) { 584 pref = 0; 585 life = 0; 586 } 587 588 for (new_drp = 0, drp = drs; drp < &drs[MAX_ADS]; drp++) { 589 /* accept new info for a familiar entry 590 */ 591 if (drp->dr_gate == gate) { 592 new_drp = drp; 593 break; 594 } 595 596 if (life == 0) 597 continue; /* do not worry about dead ads */ 598 599 if (drp->dr_ts == 0) { 600 new_drp = drp; /* use unused entry */ 601 602 } else if (new_drp == 0) { 603 /* look for an entry worse than the new one to 604 * reuse. 605 */ 606 if ((!(ifp->int_state & IS_SICK) 607 && (drp->dr_ifp->int_state & IS_SICK)) 608 || (pref > drp->dr_pref 609 && !((ifp->int_state ^ drp->dr_ifp->int_state) 610 & IS_SICK))) 611 new_drp = drp; 612 613 } else if (new_drp->dr_ts != 0) { 614 /* look for the least valuable entry to reuse 615 */ 616 if ((!(new_drp->dr_ifp->int_state & IS_SICK) 617 && (drp->dr_ifp->int_state & IS_SICK)) 618 || (new_drp->dr_pref > drp->dr_pref 619 && !((new_drp->dr_ifp->int_state 620 ^ drp->dr_ifp->int_state) 621 & IS_SICK))) 622 new_drp = drp; 623 } 624 } 625 626 /* forget it if all of the current entries are better */ 627 if (new_drp == 0) 628 return; 629 630 new_drp->dr_ifp = ifp; 631 new_drp->dr_gate = gate; 632 new_drp->dr_ts = now.tv_sec; 633 new_drp->dr_life = ntohs(life); 634 new_drp->dr_recv_pref = pref; 635 /* bias functional preference by metric of the interface */ 636 new_drp->dr_pref = PREF(pref,ifp); 637 638 /* after hearing a good advertisement, stop asking 639 */ 640 if (!(ifp->int_state & IS_SICK)) 641 ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 642 } 643 644 645 /* Compute the IP checksum 646 * This assumes the packet is less than 32K long. 647 */ 648 static u_short 649 in_cksum(u_short *p, 650 u_int len) 651 { 652 u_int sum = 0; 653 int nwords = len >> 1; 654 655 while (nwords-- != 0) 656 sum += *p++; 657 658 if (len & 1) 659 sum += *(u_char *)p; 660 661 /* end-around-carry */ 662 sum = (sum >> 16) + (sum & 0xffff); 663 sum += (sum >> 16); 664 return (~sum); 665 } 666 667 668 /* Send a router discovery advertisement or solicitation ICMP packet. 669 */ 670 static void 671 send_rdisc(union ad_u *p, 672 int p_size, 673 struct interface *ifp, 674 naddr dst, /* 0 or UNICAST destination */ 675 int type) /* 0=unicast, 1=bcast, 2=mcast */ 676 { 677 struct sockaddr_in sin; 678 int flags; 679 char *msg; 680 naddr tgt_mcast; 681 682 683 bzero(&sin, sizeof(sin)); 684 sin.sin_addr.s_addr = dst; 685 sin.sin_family = AF_INET; 686 #ifdef _HAVE_SIN_LEN 687 sin.sin_len = sizeof(sin); 688 #endif 689 flags = MSG_DONTROUTE; 690 691 switch (type) { 692 case 0: /* UNICAST */ 693 default: 694 msg = "Send"; 695 break; 696 697 case 1: /* broadcast */ 698 if (ifp->int_if_flags & IFF_POINTOPOINT) { 699 msg = "Send pt-to-pt"; 700 sin.sin_addr.s_addr = ifp->int_dstaddr; 701 } else { 702 msg = "Send broadcast"; 703 sin.sin_addr.s_addr = ifp->int_brdaddr; 704 } 705 break; 706 707 case 2: /* multicast */ 708 msg = "Send multicast"; 709 if (ifp->int_state & IS_DUP) { 710 trace_act("abort multicast output via %s" 711 " with duplicate address", 712 ifp->int_name); 713 return; 714 } 715 if (rdisc_sock_mcast != ifp) { 716 /* select the right interface. */ 717 #ifdef MCAST_PPP_BUG 718 /* Do not specify the primary interface explicitly 719 * if we have the multicast point-to-point kernel 720 * bug, since the kernel will do the wrong thing 721 * if the local address of a point-to-point link 722 * is the same as the address of an ordinary 723 * interface. 724 */ 725 if (ifp->int_addr == myaddr) { 726 tgt_mcast = 0; 727 } else 728 #endif 729 tgt_mcast = ifp->int_addr; 730 if (0 > setsockopt(rdisc_sock, 731 IPPROTO_IP, IP_MULTICAST_IF, 732 &tgt_mcast, sizeof(tgt_mcast))) { 733 LOGERR("setsockopt(rdisc_sock," 734 "IP_MULTICAST_IF)"); 735 rdisc_sock_mcast = 0; 736 return; 737 } 738 rdisc_sock_mcast = ifp; 739 } 740 flags = 0; 741 break; 742 } 743 744 if (rdisc_sock < 0) 745 get_rdisc_sock(); 746 747 trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, 748 p, p_size); 749 750 if (0 > sendto(rdisc_sock, p, p_size, flags, 751 (struct sockaddr *)&sin, sizeof(sin))) { 752 if (ifp == 0 || !(ifp->int_state & IS_BROKE)) 753 msglog("sendto(%s%s%s): %s", 754 ifp != 0 ? ifp->int_name : "", 755 ifp != 0 ? ", " : "", 756 inet_ntoa(sin.sin_addr), 757 strerror(errno)); 758 if (ifp != 0) 759 if_sick(ifp); 760 } 761 } 762 763 764 /* Send an advertisement 765 */ 766 static void 767 send_adv(struct interface *ifp, 768 naddr dst, /* 0 or UNICAST destination */ 769 int type) /* 0=unicast, 1=bcast, 2=mcast */ 770 { 771 union ad_u u; 772 n_long pref; 773 774 775 bzero(&u,sizeof(u.ad)); 776 777 u.ad.icmp_type = ICMP_ROUTERADVERT; 778 u.ad.icmp_ad_num = 1; 779 u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 780 781 u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 782 pref = ifp->int_rdisc_pref ^ MIN_PreferenceLevel; 783 pref = PREF(pref, ifp) ^ MIN_PreferenceLevel; 784 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(pref); 785 786 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 787 788 u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 789 790 send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 791 } 792 793 794 /* Advertise for Router Discovery 795 */ 796 void 797 rdisc_adv(void) 798 { 799 struct interface *ifp; 800 801 if (!supplier) 802 return; 803 804 rdisc_timer.tv_sec = now.tv_sec + NEVER; 805 806 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 807 if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 808 continue; 809 810 if (!timercmp(&ifp->int_rdisc_timer, &now, >) 811 || stopint) { 812 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 813 (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 814 ifp->int_rdisc_cnt++; 815 816 intvl_random(&ifp->int_rdisc_timer, 817 (ifp->int_rdisc_int*3)/4, 818 ifp->int_rdisc_int); 819 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 820 && (ifp->int_rdisc_timer.tv_sec 821 > MAX_INITIAL_ADVERT_INTERVAL)) { 822 ifp->int_rdisc_timer.tv_sec 823 = MAX_INITIAL_ADVERT_INTERVAL; 824 } 825 timevaladd(&ifp->int_rdisc_timer, &now); 826 } 827 828 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 829 rdisc_timer = ifp->int_rdisc_timer; 830 } 831 } 832 833 834 /* Solicit for Router Discovery 835 */ 836 void 837 rdisc_sol(void) 838 { 839 struct interface *ifp; 840 union ad_u u; 841 842 843 if (supplier) 844 return; 845 846 rdisc_timer.tv_sec = now.tv_sec + NEVER; 847 848 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 849 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 850 || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 851 continue; 852 853 if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 854 bzero(&u,sizeof(u.so)); 855 u.so.icmp_type = ICMP_ROUTERSOLICIT; 856 u.so.icmp_cksum = in_cksum((u_short*)&u.so, 857 sizeof(u.so)); 858 send_rdisc(&u, sizeof(u.so), ifp, 859 htonl(INADDR_ALLROUTERS_GROUP), 860 ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 861 862 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 863 continue; 864 865 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 866 ifp->int_rdisc_timer.tv_usec = 0; 867 timevaladd(&ifp->int_rdisc_timer, &now); 868 } 869 870 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 871 rdisc_timer = ifp->int_rdisc_timer; 872 } 873 } 874 875 876 /* check the IP header of a possible Router Discovery ICMP packet */ 877 static struct interface * /* 0 if bad */ 878 ck_icmp(char *act, 879 naddr from, 880 struct interface *ifp, 881 naddr to, 882 union ad_u *p, 883 u_int len) 884 { 885 char *type; 886 887 888 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 889 type = "advertisement"; 890 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 891 type = "solicitation"; 892 } else { 893 return 0; 894 } 895 896 if (p->icmp.icmp_code != 0) { 897 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 898 type, p->icmp.icmp_code, 899 naddr_ntoa(from), naddr_ntoa(to)); 900 return 0; 901 } 902 903 trace_rdisc(act, from, to, ifp, p, len); 904 905 if (ifp == 0) 906 trace_pkt("unknown interface for router-discovery %s" 907 " from %s to %s", 908 type, naddr_ntoa(from), naddr_ntoa(to)); 909 910 return ifp; 911 } 912 913 914 /* read packets from the router discovery socket 915 */ 916 void 917 read_d(void) 918 { 919 static struct msg_limit bad_asize, bad_len; 920 #ifdef USE_PASSIFNAME 921 static struct msg_limit bad_name; 922 #endif 923 struct sockaddr_in from; 924 int n, fromlen, cc, hlen; 925 struct { 926 #ifdef USE_PASSIFNAME 927 char ifname[IFNAMSIZ]; 928 #endif 929 union { 930 struct ip ip; 931 u_short s[512/2]; 932 u_char b[512]; 933 } pkt; 934 } buf; 935 union ad_u *p; 936 n_long *wp; 937 struct interface *ifp; 938 939 940 for (;;) { 941 fromlen = sizeof(from); 942 cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 943 (struct sockaddr*)&from, 944 &fromlen); 945 if (cc <= 0) { 946 if (cc < 0 && errno != EWOULDBLOCK) 947 LOGERR("recvfrom(rdisc_sock)"); 948 break; 949 } 950 if (fromlen != sizeof(struct sockaddr_in)) 951 logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 952 fromlen); 953 #ifdef USE_PASSIFNAME 954 if ((cc -= sizeof(buf.ifname)) < 0) 955 logbad(0,"missing USE_PASSIFNAME; only %d bytes", 956 cc+sizeof(buf.ifname)); 957 #endif 958 959 hlen = buf.pkt.ip.ip_hl << 2; 960 if (cc < hlen + ICMP_MINLEN) 961 continue; 962 p = (union ad_u *)&buf.pkt.b[hlen]; 963 cc -= hlen; 964 965 #ifdef USE_PASSIFNAME 966 ifp = ifwithname(buf.ifname, 0); 967 if (ifp == 0) 968 msglim(&bad_name, from.sin_addr.s_addr, 969 "impossible rdisc if_ name %.*s", 970 IFNAMSIZ, buf.ifname); 971 #else 972 /* If we could tell the interface on which a packet from 973 * address 0 arrived, we could deal with such solicitations. 974 */ 975 ifp = ((from.sin_addr.s_addr == 0) 976 ? 0 : iflookup(from.sin_addr.s_addr)); 977 #endif 978 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 979 buf.pkt.ip.ip_dst.s_addr, p, cc); 980 if (ifp == 0) 981 continue; 982 if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 983 trace_pkt(" " 984 "discard our own Router Discovery message"); 985 continue; 986 } 987 988 switch (p->icmp.icmp_type) { 989 case ICMP_ROUTERADVERT: 990 if (p->ad.icmp_ad_asize*4 991 < sizeof(p->ad.icmp_ad_info[0])) { 992 msglim(&bad_asize, from.sin_addr.s_addr, 993 "intolerable rdisc address size=%d", 994 p->ad.icmp_ad_asize); 995 continue; 996 } 997 if (p->ad.icmp_ad_num == 0) { 998 trace_pkt(" empty?"); 999 continue; 1000 } 1001 if (cc != (sizeof(p->ad) - sizeof(p->ad.icmp_ad_info) 1002 + (p->ad.icmp_ad_num 1003 * sizeof(p->ad.icmp_ad_info[0])))) { 1004 msglim(&bad_len, from.sin_addr.s_addr, 1005 "rdisc length %d does not match ad_num" 1006 " %d", cc, p->ad.icmp_ad_num); 1007 continue; 1008 } 1009 if (supplier) 1010 continue; 1011 if (ifp->int_state & IS_NO_ADV_IN) 1012 continue; 1013 1014 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1015 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1016 parse_ad(from.sin_addr.s_addr, 1017 wp[0], wp[1], 1018 ntohs(p->ad.icmp_ad_life), 1019 ifp); 1020 wp += p->ad.icmp_ad_asize; 1021 } 1022 break; 1023 1024 1025 case ICMP_ROUTERSOLICIT: 1026 if (!supplier) 1027 continue; 1028 if (ifp->int_state & IS_NO_ADV_OUT) 1029 continue; 1030 1031 /* XXX 1032 * We should handle messages from address 0. 1033 */ 1034 1035 /* Respond with a point-to-point advertisement */ 1036 send_adv(ifp, from.sin_addr.s_addr, 0); 1037 break; 1038 } 1039 } 1040 1041 rdisc_sort(); 1042 } 1043