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