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