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