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