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. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: src/sbin/routed/rdisc.c,v 1.5.2.1 2000/08/14 17:00:04 sheldonh Exp $ 30 */ 31 32 #include "defs.h" 33 #include <netinet/in_systm.h> 34 #include <netinet/ip.h> 35 #include <netinet/ip_icmp.h> 36 37 #if !defined(__NetBSD__) 38 static char sccsid[] __attribute__((unused)) = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; 39 #elif defined(__NetBSD__) 40 __RCSID("$NetBSD$"); 41 #endif 42 43 /* router advertisement ICMP packet */ 44 struct icmp_ad { 45 u_int8_t icmp_type; /* type of message */ 46 u_int8_t icmp_code; /* type sub code */ 47 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 48 u_int8_t icmp_ad_num; /* # of following router addresses */ 49 u_int8_t icmp_ad_asize; /* 2--words in each advertisement */ 50 u_int16_t icmp_ad_life; /* seconds of validity */ 51 struct icmp_ad_info { 52 n_long icmp_ad_addr; 53 n_long icmp_ad_pref; 54 } icmp_ad_info[1]; 55 }; 56 57 /* router solicitation ICMP packet */ 58 struct icmp_so { 59 u_int8_t icmp_type; /* type of message */ 60 u_int8_t icmp_code; /* type sub code */ 61 u_int16_t icmp_cksum; /* ones complement cksum of struct */ 62 n_long icmp_so_rsvd; 63 }; 64 65 union ad_u { 66 struct icmp icmp; 67 struct icmp_ad ad; 68 struct icmp_so so; 69 }; 70 71 72 int rdisc_sock = -1; /* router-discovery raw socket */ 73 struct interface *rdisc_sock_mcast; /* current multicast interface */ 74 75 struct timeval rdisc_timer; 76 int rdisc_ok; /* using solicited route */ 77 78 79 #define MAX_ADS 16 /* at least one per interface */ 80 struct dr { /* accumulated advertisements */ 81 struct interface *dr_ifp; 82 naddr dr_gate; /* gateway */ 83 time_t dr_ts; /* when received */ 84 time_t dr_life; /* lifetime in host byte order */ 85 n_long dr_recv_pref; /* received but biased preference */ 86 n_long dr_pref; /* preference adjusted by metric */ 87 } *cur_drp, drs[MAX_ADS]; 88 89 /* convert between signed, balanced around zero, 90 * and unsigned zero-based preferences */ 91 #define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) 92 #define UNSIGN_PREF(p) SIGN_PREF(p) 93 /* adjust unsigned preference by interface metric, 94 * without driving it to infinity */ 95 #define PREF(p, ifp) ((int)(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(const 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 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 fprintf(ftrace, "\t%s preference=%d", 133 naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 134 wp += p->ad.icmp_ad_asize; 135 } 136 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 (int)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 supplying 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 advertising, 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 != NULL) 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, solicit 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 rdisc_sol(); 342 rdisc_sort(); 343 344 /* Delete old redirected routes to keep the kernel table small, 345 * and to prevent black holes. Check that the kernel table 346 * matches the daemon table (i.e. has the default route). 347 * But only if RIP is not running and we are not dealing with 348 * a bad gateway, since otherwise age() will be called. 349 */ 350 if (rip_sock < 0 && bad_gate == 0) 351 age(0); 352 } 353 354 355 /* Zap all routes discovered via an interface that has gone bad 356 * This should only be called when !(ifp->int_state & IS_ALIAS) 357 */ 358 void 359 if_bad_rdisc(struct interface *ifp) 360 { 361 struct dr *drp; 362 363 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 364 if (drp->dr_ifp != ifp) 365 continue; 366 drp->dr_recv_pref = 0; 367 drp->dr_ts = 0; 368 drp->dr_life = 0; 369 } 370 371 /* make a note to re-solicit, turn RIP on or off, etc. */ 372 rdisc_timer.tv_sec = 0; 373 } 374 375 376 /* mark an interface ok for router discovering. 377 */ 378 void 379 if_ok_rdisc(struct interface *ifp) 380 { 381 set_rdisc_mg(ifp, 1); 382 383 ifp->int_rdisc_cnt = 0; 384 ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 385 ? MIN_WAITTIME 386 : MAX_SOLICITATION_DELAY); 387 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 388 rdisc_timer = ifp->int_rdisc_timer; 389 } 390 391 392 /* get rid of a dead discovered router 393 */ 394 static void 395 del_rdisc(struct dr *drp) 396 { 397 struct interface *ifp; 398 naddr gate; 399 int i; 400 401 402 del_redirects(gate = drp->dr_gate, 0); 403 drp->dr_ts = 0; 404 drp->dr_life = 0; 405 406 407 /* Count the other discovered routes on the interface. 408 */ 409 i = 0; 410 ifp = drp->dr_ifp; 411 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 412 if (drp->dr_ts != 0 413 && drp->dr_ifp == ifp) 414 i++; 415 } 416 417 /* If that was the last good discovered router on the interface, 418 * then solicit a new one. 419 * This is contrary to RFC 1256, but defends against black holes. 420 */ 421 if (i != 0) { 422 trace_act("discovered router %s via %s" 423 " is bad--have %d remaining", 424 naddr_ntoa(gate), ifp->int_name, i); 425 } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 426 trace_act("last discovered router %s via %s" 427 " is bad--re-solicit", 428 naddr_ntoa(gate), ifp->int_name); 429 ifp->int_rdisc_cnt = 0; 430 ifp->int_rdisc_timer.tv_sec = 0; 431 rdisc_sol(); 432 } else { 433 trace_act("last discovered router %s via %s" 434 " is bad--wait to solicit", 435 naddr_ntoa(gate), ifp->int_name); 436 } 437 } 438 439 440 /* Find the best discovered route, 441 * and discard stale routers. 442 */ 443 static void 444 rdisc_sort(void) 445 { 446 struct dr *drp, *new_drp; 447 struct rt_entry *rt; 448 struct rt_spare new; 449 struct interface *ifp; 450 u_int new_st = 0; 451 n_long new_pref = 0; 452 453 454 /* Find the best discovered route. 455 */ 456 new_drp = NULL; 457 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 458 if (drp->dr_ts == 0) 459 continue; 460 ifp = drp->dr_ifp; 461 462 /* Get rid of expired discovered routers. 463 */ 464 if (drp->dr_ts + drp->dr_life <= now.tv_sec) { 465 del_rdisc(drp); 466 continue; 467 } 468 469 LIM_SEC(rdisc_timer, drp->dr_ts+drp->dr_life+1); 470 471 /* Update preference with possibly changed interface 472 * metric. 473 */ 474 drp->dr_pref = PREF(drp->dr_recv_pref, ifp); 475 476 /* Prefer the current route to prevent thrashing. 477 * Prefer shorter lifetimes to speed the detection of 478 * bad routers. 479 * Avoid sick interfaces. 480 */ 481 if (new_drp == NULL 482 || (!((new_st ^ drp->dr_ifp->int_state) & IS_SICK) 483 && (new_pref < drp->dr_pref 484 || (new_pref == drp->dr_pref 485 && (drp == cur_drp 486 || (new_drp != cur_drp 487 && new_drp->dr_life > drp->dr_life))))) 488 || ((new_st & IS_SICK) 489 && !(drp->dr_ifp->int_state & IS_SICK))) { 490 new_drp = drp; 491 new_st = drp->dr_ifp->int_state; 492 new_pref = drp->dr_pref; 493 } 494 } 495 496 /* switch to a better default route 497 */ 498 if (new_drp != cur_drp) { 499 rt = rtget(RIP_DEFAULT, 0); 500 501 /* Stop using discovered routes if they are all bad 502 */ 503 if (new_drp == NULL) { 504 trace_act("turn off Router Discovery client"); 505 rdisc_ok = 0; 506 507 if (rt != NULL 508 && (rt->rt_state & RS_RDISC)) { 509 new = rt->rt_spares[0]; 510 new.rts_metric = HOPCNT_INFINITY; 511 new.rts_time = now.tv_sec - GARBAGE_TIME; 512 rtchange(rt, rt->rt_state & ~RS_RDISC, 513 &new, 0); 514 rtswitch(rt, 0); 515 } 516 517 } else { 518 if (cur_drp == NULL) { 519 trace_act("turn on Router Discovery client" 520 " using %s via %s", 521 naddr_ntoa(new_drp->dr_gate), 522 new_drp->dr_ifp->int_name); 523 rdisc_ok = 1; 524 525 } else { 526 trace_act("switch Router Discovery from" 527 " %s via %s to %s via %s", 528 naddr_ntoa(cur_drp->dr_gate), 529 cur_drp->dr_ifp->int_name, 530 naddr_ntoa(new_drp->dr_gate), 531 new_drp->dr_ifp->int_name); 532 } 533 534 memset(&new, 0, sizeof(new)); 535 new.rts_ifp = new_drp->dr_ifp; 536 new.rts_gate = new_drp->dr_gate; 537 new.rts_router = new_drp->dr_gate; 538 new.rts_metric = HOPCNT_INFINITY-1; 539 new.rts_time = now.tv_sec; 540 if (rt != NULL) { 541 rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); 542 } else { 543 rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); 544 } 545 } 546 547 cur_drp = new_drp; 548 } 549 550 /* turn RIP on or off */ 551 if (!rdisc_ok || rip_interfaces > 1) { 552 rip_on(0); 553 } else { 554 rip_off(); 555 } 556 } 557 558 559 /* handle a single address in an advertisement 560 */ 561 static void 562 parse_ad(naddr from, 563 naddr gate, 564 n_long pref, /* signed and in network order */ 565 u_short life, /* in host byte order */ 566 struct interface *ifp) 567 { 568 static struct msg_limit bad_gate; 569 struct dr *drp, *new_drp; 570 571 572 if (gate == RIP_DEFAULT 573 || !check_dst(gate)) { 574 msglim(&bad_gate, from,"router %s advertising bad gateway %s", 575 naddr_ntoa(from), 576 naddr_ntoa(gate)); 577 return; 578 } 579 580 /* ignore pointers to ourself and routes via unreachable networks 581 */ 582 if (ifwithaddr(gate, 1, 0) != 0) { 583 trace_pkt(" discard Router Discovery Ad pointing at us"); 584 return; 585 } 586 if (!on_net(gate, ifp->int_net, ifp->int_mask)) { 587 trace_pkt(" discard Router Discovery Ad" 588 " toward unreachable net"); 589 return; 590 } 591 592 /* Convert preference to an unsigned value 593 * and later bias it by the metric of the interface. 594 */ 595 pref = UNSIGN_PREF(ntohl(pref)); 596 597 if (pref == 0 || life < MinMaxAdvertiseInterval) { 598 pref = 0; 599 life = 0; 600 } 601 602 for (new_drp = NULL, drp = drs; drp < &drs[MAX_ADS]; drp++) { 603 /* accept new info for a familiar entry 604 */ 605 if (drp->dr_gate == gate) { 606 new_drp = drp; 607 break; 608 } 609 610 if (life == 0) 611 continue; /* do not worry about dead ads */ 612 613 if (drp->dr_ts == 0) { 614 new_drp = drp; /* use unused entry */ 615 616 } else if (new_drp == NULL) { 617 /* look for an entry worse than the new one to 618 * reuse. 619 */ 620 if ((!(ifp->int_state & IS_SICK) 621 && (drp->dr_ifp->int_state & IS_SICK)) 622 || (pref > drp->dr_pref 623 && !((ifp->int_state ^ drp->dr_ifp->int_state) 624 & IS_SICK))) 625 new_drp = drp; 626 627 } else if (new_drp->dr_ts != 0) { 628 /* look for the least valuable entry to reuse 629 */ 630 if ((!(new_drp->dr_ifp->int_state & IS_SICK) 631 && (drp->dr_ifp->int_state & IS_SICK)) 632 || (new_drp->dr_pref > drp->dr_pref 633 && !((new_drp->dr_ifp->int_state 634 ^ drp->dr_ifp->int_state) 635 & IS_SICK))) 636 new_drp = drp; 637 } 638 } 639 640 /* forget it if all of the current entries are better */ 641 if (new_drp == NULL) 642 return; 643 644 new_drp->dr_ifp = ifp; 645 new_drp->dr_gate = gate; 646 new_drp->dr_ts = now.tv_sec; 647 new_drp->dr_life = life; 648 new_drp->dr_recv_pref = pref; 649 /* bias functional preference by metric of the interface */ 650 new_drp->dr_pref = PREF(pref,ifp); 651 652 /* after hearing a good advertisement, stop asking 653 */ 654 if (!(ifp->int_state & IS_SICK)) 655 ifp->int_rdisc_cnt = MAX_SOLICITATIONS; 656 } 657 658 659 /* Compute the IP checksum 660 * This assumes the packet is less than 32K long. 661 */ 662 static u_short 663 in_cksum(u_short *p, 664 u_int len) 665 { 666 u_int sum = 0; 667 int nwords = len >> 1; 668 669 while (nwords-- != 0) 670 sum += *p++; 671 672 if (len & 1) 673 sum += *(u_char *)p; 674 675 /* end-around-carry */ 676 sum = (sum >> 16) + (sum & 0xffff); 677 sum += (sum >> 16); 678 return (~sum); 679 } 680 681 682 /* Send a router discovery advertisement or solicitation ICMP packet. 683 */ 684 static void 685 send_rdisc(union ad_u *p, 686 int p_size, 687 struct interface *ifp, 688 naddr dst, /* 0 or unicast destination */ 689 int type) /* 0=unicast, 1=bcast, 2=mcast */ 690 { 691 struct sockaddr_in in; 692 int flags; 693 const char *msg; 694 naddr tgt_mcast; 695 696 697 memset(&in, 0, sizeof(in)); 698 in.sin_addr.s_addr = dst; 699 in.sin_family = AF_INET; 700 #ifdef _HAVE_SIN_LEN 701 in.sin_len = sizeof(in); 702 #endif 703 flags = MSG_DONTROUTE; 704 705 switch (type) { 706 case 0: /* unicast */ 707 default: 708 msg = "Send"; 709 break; 710 711 case 1: /* broadcast */ 712 if (ifp->int_if_flags & IFF_POINTOPOINT) { 713 msg = "Send pt-to-pt"; 714 in.sin_addr.s_addr = ifp->int_dstaddr; 715 } else { 716 msg = "Send broadcast"; 717 in.sin_addr.s_addr = ifp->int_brdaddr; 718 } 719 break; 720 721 case 2: /* multicast */ 722 msg = "Send multicast"; 723 if (ifp->int_state & IS_DUP) { 724 trace_act("abort multicast output via %s" 725 " with duplicate address", 726 ifp->int_name); 727 return; 728 } 729 if (rdisc_sock_mcast != ifp) { 730 /* select the right interface. */ 731 #ifdef MCAST_PPP_BUG 732 /* Do not specify the primary interface explicitly 733 * if we have the multicast point-to-point kernel 734 * bug, since the kernel will do the wrong thing 735 * if the local address of a point-to-point link 736 * is the same as the address of an ordinary 737 * interface. 738 */ 739 if (ifp->int_addr == myaddr) { 740 tgt_mcast = 0; 741 } else 742 #endif 743 tgt_mcast = ifp->int_addr; 744 if (0 > setsockopt(rdisc_sock, 745 IPPROTO_IP, IP_MULTICAST_IF, 746 &tgt_mcast, sizeof(tgt_mcast))) { 747 LOGERR("setsockopt(rdisc_sock," 748 "IP_MULTICAST_IF)"); 749 rdisc_sock_mcast = NULL; 750 return; 751 } 752 rdisc_sock_mcast = ifp; 753 } 754 flags = 0; 755 break; 756 } 757 758 if (rdisc_sock < 0) 759 get_rdisc_sock(); 760 761 trace_rdisc(msg, ifp->int_addr, in.sin_addr.s_addr, ifp, 762 p, p_size); 763 764 if (0 > sendto(rdisc_sock, p, p_size, flags, 765 (struct sockaddr *)&in, sizeof(in))) { 766 if (ifp == NULL || !(ifp->int_state & IS_BROKE)) 767 msglog("sendto(%s%s%s): %s", 768 ifp != NULL ? ifp->int_name : "", 769 ifp != NULL ? ", " : "", 770 inet_ntoa(in.sin_addr), 771 strerror(errno)); 772 if (ifp != NULL) 773 if_sick(ifp); 774 } 775 } 776 777 778 /* Send an advertisement 779 */ 780 static void 781 send_adv(struct interface *ifp, 782 naddr dst, /* 0 or unicast destination */ 783 int type) /* 0=unicast, 1=bcast, 2=mcast */ 784 { 785 union ad_u u; 786 n_long pref; 787 788 789 memset(&u, 0, sizeof(u.ad)); 790 791 u.ad.icmp_type = ICMP_ROUTERADVERT; 792 u.ad.icmp_ad_num = 1; 793 u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 794 795 u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 796 797 /* Convert the configured preference to an unsigned value, 798 * bias it by the interface metric, and then send it as a 799 * signed, network byte order value. 800 */ 801 pref = UNSIGN_PREF(ifp->int_rdisc_pref); 802 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); 803 804 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 805 806 u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 807 808 send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 809 } 810 811 812 /* Advertise for Router Discovery 813 */ 814 void 815 rdisc_adv(void) 816 { 817 struct interface *ifp; 818 819 if (!supplier) 820 return; 821 822 rdisc_timer.tv_sec = now.tv_sec + NEVER; 823 824 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 825 if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 826 continue; 827 828 if (!timercmp(&ifp->int_rdisc_timer, &now, >) 829 || stopint) { 830 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 831 (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 832 ifp->int_rdisc_cnt++; 833 834 intvl_random(&ifp->int_rdisc_timer, 835 (ifp->int_rdisc_int*3)/4, 836 ifp->int_rdisc_int); 837 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 838 && (ifp->int_rdisc_timer.tv_sec 839 > MAX_INITIAL_ADVERT_INTERVAL)) { 840 ifp->int_rdisc_timer.tv_sec 841 = MAX_INITIAL_ADVERT_INTERVAL; 842 } 843 timevaladd(&ifp->int_rdisc_timer, &now); 844 } 845 846 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 847 rdisc_timer = ifp->int_rdisc_timer; 848 } 849 } 850 851 852 /* Solicit for Router Discovery 853 */ 854 void 855 rdisc_sol(void) 856 { 857 struct interface *ifp; 858 union ad_u u; 859 860 861 if (supplier) 862 return; 863 864 rdisc_timer.tv_sec = now.tv_sec + NEVER; 865 866 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 867 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 868 || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 869 continue; 870 871 if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 872 memset(&u, 0, sizeof(u.so)); 873 u.so.icmp_type = ICMP_ROUTERSOLICIT; 874 u.so.icmp_cksum = in_cksum((u_short*)&u.so, 875 sizeof(u.so)); 876 send_rdisc(&u, sizeof(u.so), ifp, 877 htonl(INADDR_ALLROUTERS_GROUP), 878 ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 879 880 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 881 continue; 882 883 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 884 ifp->int_rdisc_timer.tv_usec = 0; 885 timevaladd(&ifp->int_rdisc_timer, &now); 886 } 887 888 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 889 rdisc_timer = ifp->int_rdisc_timer; 890 } 891 } 892 893 894 /* check the IP header of a possible Router Discovery ICMP packet */ 895 static struct interface * /* 0 if bad */ 896 ck_icmp(const char *act, 897 naddr from, 898 struct interface *ifp, 899 naddr to, 900 union ad_u *p, 901 u_int len) 902 { 903 const char *type; 904 905 906 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 907 type = "advertisement"; 908 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 909 type = "solicitation"; 910 } else { 911 return 0; 912 } 913 914 if (p->icmp.icmp_code != 0) { 915 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 916 type, p->icmp.icmp_code, 917 naddr_ntoa(from), naddr_ntoa(to)); 918 return 0; 919 } 920 921 trace_rdisc(act, from, to, ifp, p, len); 922 923 if (ifp == NULL) 924 trace_pkt("unknown interface for router-discovery %s" 925 " from %s to %s", 926 type, naddr_ntoa(from), naddr_ntoa(to)); 927 928 return ifp; 929 } 930 931 932 /* read packets from the router discovery socket 933 */ 934 void 935 read_d(void) 936 { 937 static struct msg_limit bad_asize, bad_len; 938 #ifdef USE_PASSIFNAME 939 static struct msg_limit bad_name; 940 #endif 941 struct sockaddr_in from; 942 int n, cc, hlen; 943 socklen_t fromlen; 944 struct { 945 #ifdef USE_PASSIFNAME 946 char ifname[IFNAMSIZ]; 947 #endif 948 union { 949 struct ip ip; 950 u_short s[512/2]; 951 u_char b[512]; 952 } pkt; 953 } buf; 954 union ad_u *p; 955 n_long *wp; 956 struct interface *ifp; 957 958 959 for (;;) { 960 fromlen = sizeof(from); 961 cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 962 (struct sockaddr*)&from, 963 &fromlen); 964 if (cc <= 0) { 965 if (cc < 0 && errno != EWOULDBLOCK) 966 LOGERR("recvfrom(rdisc_sock)"); 967 break; 968 } 969 if (fromlen != sizeof(struct sockaddr_in)) 970 logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 971 fromlen); 972 #ifdef USE_PASSIFNAME 973 if ((cc -= sizeof(buf.ifname)) < 0) 974 logbad(0,"missing USE_PASSIFNAME; only %d bytes", 975 cc+sizeof(buf.ifname)); 976 #endif 977 978 hlen = buf.pkt.ip.ip_hl << 2; 979 if (cc < hlen + ICMP_MINLEN) 980 continue; 981 p = (union ad_u *)&buf.pkt.b[hlen]; 982 cc -= hlen; 983 984 #ifdef USE_PASSIFNAME 985 ifp = ifwithname(buf.ifname, 0); 986 if (ifp == NULL) 987 msglim(&bad_name, from.sin_addr.s_addr, 988 "impossible rdisc if_ name %.*s", 989 IFNAMSIZ, buf.ifname); 990 #else 991 /* If we could tell the interface on which a packet from 992 * address 0 arrived, we could deal with such solicitations. 993 */ 994 ifp = ((from.sin_addr.s_addr == 0) 995 ? 0 : iflookup(from.sin_addr.s_addr)); 996 #endif 997 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 998 buf.pkt.ip.ip_dst.s_addr, p, cc); 999 if (ifp == NULL) 1000 continue; 1001 if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 1002 trace_pkt(" " 1003 "discard our own Router Discovery message"); 1004 continue; 1005 } 1006 1007 switch (p->icmp.icmp_type) { 1008 case ICMP_ROUTERADVERT: 1009 if (p->ad.icmp_ad_asize*4 1010 < (int)sizeof(p->ad.icmp_ad_info[0])) { 1011 msglim(&bad_asize, from.sin_addr.s_addr, 1012 "intolerable rdisc address size=%d", 1013 p->ad.icmp_ad_asize); 1014 continue; 1015 } 1016 if (p->ad.icmp_ad_num == 0) { 1017 trace_pkt(" empty?"); 1018 continue; 1019 } 1020 if (cc != (int)(sizeof(p->ad) 1021 - sizeof(p->ad.icmp_ad_info) 1022 + (p->ad.icmp_ad_num 1023 * sizeof(p->ad.icmp_ad_info[0])))) { 1024 msglim(&bad_len, from.sin_addr.s_addr, 1025 "rdisc length %d does not match ad_num" 1026 " %d", cc, p->ad.icmp_ad_num); 1027 continue; 1028 } 1029 if (supplier) 1030 continue; 1031 if (ifp->int_state & IS_NO_ADV_IN) 1032 continue; 1033 1034 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1035 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1036 parse_ad(from.sin_addr.s_addr, 1037 wp[0], wp[1], 1038 ntohs(p->ad.icmp_ad_life), 1039 ifp); 1040 wp += p->ad.icmp_ad_asize; 1041 } 1042 break; 1043 1044 1045 case ICMP_ROUTERSOLICIT: 1046 if (!supplier) 1047 continue; 1048 if (ifp->int_state & IS_NO_ADV_OUT) 1049 continue; 1050 if (stopint) 1051 continue; 1052 1053 /* XXX 1054 * We should handle messages from address 0. 1055 */ 1056 1057 /* Respond with a point-to-point advertisement */ 1058 send_adv(ifp, from.sin_addr.s_addr, 0); 1059 break; 1060 } 1061 } 1062 1063 rdisc_sort(); 1064 } 1065