1 /* $NetBSD: rdisc.c,v 1.14 2002/11/30 04:04:23 christos 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.14 2002/11/30 04:04:23 christos 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+(ifp)->int_adj_outmetric)\ 103 ? ((p) != 0 ? 1 : 0) \ 104 : (p) - ((ifp)->int_metric+(ifp)->int_adj_outmetric)) 105 106 static void rdisc_sort(void); 107 108 109 /* dump an ICMP Router Discovery Advertisement Message 110 */ 111 static void 112 trace_rdisc(const char *act, 113 naddr from, 114 naddr to, 115 struct interface *ifp, 116 union ad_u *p, 117 u_int len) 118 { 119 int i; 120 n_long *wp, *lim; 121 122 123 if (!TRACEPACKETS || ftrace == 0) 124 return; 125 126 lastlog(); 127 128 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 129 (void)fprintf(ftrace, "%s Router Ad" 130 " from %s to %s via %s life=%d\n", 131 act, naddr_ntoa(from), naddr_ntoa(to), 132 ifp ? ifp->int_name : "?", 133 ntohs(p->ad.icmp_ad_life)); 134 if (!TRACECONTENTS) 135 return; 136 137 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 138 lim = &wp[(len - sizeof(p->ad)) / sizeof(*wp)]; 139 for (i = 0; i < p->ad.icmp_ad_num && wp <= lim; i++) { 140 (void)fprintf(ftrace, "\t%s preference=%d", 141 naddr_ntoa(wp[0]), (int)ntohl(wp[1])); 142 wp += p->ad.icmp_ad_asize; 143 } 144 (void)fputc('\n',ftrace); 145 146 } else { 147 trace_act("%s Router Solic. from %s to %s via %s value=%#x", 148 act, naddr_ntoa(from), naddr_ntoa(to), 149 ifp ? ifp->int_name : "?", 150 (int)ntohl(p->so.icmp_so_rsvd)); 151 } 152 } 153 154 /* prepare Router Discovery socket. 155 */ 156 static void 157 get_rdisc_sock(void) 158 { 159 if (rdisc_sock < 0) { 160 rdisc_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 161 if (rdisc_sock < 0) 162 BADERR(1,"rdisc_sock = socket()"); 163 fix_sock(rdisc_sock,"rdisc_sock"); 164 fix_select(); 165 } 166 } 167 168 169 /* Pick multicast group for router-discovery socket 170 */ 171 void 172 set_rdisc_mg(struct interface *ifp, 173 int on) /* 0=turn it off */ 174 { 175 struct ip_mreq m; 176 177 if (rdisc_sock < 0) { 178 /* Create the raw socket so that we can hear at least 179 * broadcast router discovery packets. 180 */ 181 if ((ifp->int_state & IS_NO_RDISC) == IS_NO_RDISC 182 || !on) 183 return; 184 get_rdisc_sock(); 185 } 186 187 if (!(ifp->int_if_flags & IFF_MULTICAST)) { 188 ifp->int_state &= ~(IS_ALL_HOSTS | IS_ALL_ROUTERS); 189 return; 190 } 191 192 #ifdef MCAST_PPP_BUG 193 if (ifp->int_if_flags & IFF_POINTOPOINT) 194 return; 195 #endif 196 memset(&m, 0, sizeof(m)); 197 #ifdef MCAST_IFINDEX 198 m.imr_interface.s_addr = htonl(ifp->int_index); 199 #else 200 m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 201 ? ifp->int_dstaddr 202 : ifp->int_addr); 203 #endif 204 if (supplier 205 || (ifp->int_state & IS_NO_ADV_IN) 206 || !on) { 207 /* stop listening to advertisements 208 */ 209 if (ifp->int_state & IS_ALL_HOSTS) { 210 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 211 if (setsockopt(rdisc_sock, IPPROTO_IP, 212 IP_DROP_MEMBERSHIP, 213 &m, sizeof(m)) < 0) 214 LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); 215 ifp->int_state &= ~IS_ALL_HOSTS; 216 } 217 218 } else if (!(ifp->int_state & IS_ALL_HOSTS)) { 219 /* start listening to advertisements 220 */ 221 m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 222 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 223 &m, sizeof(m)) < 0) { 224 LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); 225 } else { 226 ifp->int_state |= IS_ALL_HOSTS; 227 } 228 } 229 230 if (!supplier 231 || (ifp->int_state & IS_NO_ADV_OUT) 232 || !on) { 233 /* stop listening to solicitations 234 */ 235 if (ifp->int_state & IS_ALL_ROUTERS) { 236 m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 237 if (setsockopt(rdisc_sock, IPPROTO_IP, 238 IP_DROP_MEMBERSHIP, 239 &m, sizeof(m)) < 0) 240 LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); 241 ifp->int_state &= ~IS_ALL_ROUTERS; 242 } 243 244 } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { 245 /* start hearing solicitations 246 */ 247 m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); 248 if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 249 &m, sizeof(m)) < 0) { 250 LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); 251 } else { 252 ifp->int_state |= IS_ALL_ROUTERS; 253 } 254 } 255 } 256 257 258 /* start supplying routes 259 */ 260 void 261 set_supplier(void) 262 { 263 struct interface *ifp; 264 struct dr *drp; 265 266 if (supplier_set) 267 return; 268 269 trace_act("start supplying routes"); 270 271 /* Forget discovered routes. 272 */ 273 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 274 drp->dr_recv_pref = 0; 275 drp->dr_life = 0; 276 } 277 rdisc_age(0); 278 279 supplier_set = 1; 280 supplier = 1; 281 282 /* Do not start advertising until we have heard some RIP routes */ 283 LIM_SEC(rdisc_timer, now.tv_sec+MIN_WAITTIME); 284 285 /* Switch router discovery multicast groups from soliciting 286 * to advertising. 287 */ 288 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 289 if (ifp->int_state & IS_BROKE) 290 continue; 291 ifp->int_rdisc_cnt = 0; 292 ifp->int_rdisc_timer.tv_usec = rdisc_timer.tv_usec; 293 ifp->int_rdisc_timer.tv_sec = now.tv_sec+MIN_WAITTIME; 294 set_rdisc_mg(ifp, 1); 295 } 296 297 /* get rid of any redirects */ 298 del_redirects(0,0); 299 } 300 301 302 /* age discovered routes and find the best one 303 */ 304 void 305 rdisc_age(naddr bad_gate) 306 { 307 time_t sec; 308 struct dr *drp; 309 310 311 /* If only advertising, then do only that. */ 312 if (supplier) { 313 /* If switching from client to server, get rid of old 314 * default routes. 315 */ 316 if (cur_drp != 0) 317 rdisc_sort(); 318 rdisc_adv(); 319 return; 320 } 321 322 /* If we are being told about a bad router, 323 * then age the discovered default route, and if there is 324 * no alternative, solicit a replacement. 325 */ 326 if (bad_gate != 0) { 327 /* Look for the bad discovered default route. 328 * Age it and note its interface. 329 */ 330 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 331 if (drp->dr_ts == 0) 332 continue; 333 334 /* When we find the bad router, then age the route 335 * to at most SUPPLY_INTERVAL. 336 * This is contrary to RFC 1256, but defends against 337 * black holes. 338 */ 339 if (drp->dr_gate == bad_gate) { 340 sec = (now.tv_sec - drp->dr_life 341 + SUPPLY_INTERVAL); 342 if (drp->dr_ts > sec) { 343 trace_act("age 0.0.0.0 --> %s via %s", 344 naddr_ntoa(drp->dr_gate), 345 drp->dr_ifp->int_name); 346 drp->dr_ts = sec; 347 } 348 break; 349 } 350 } 351 } 352 353 rdisc_sol(); 354 rdisc_sort(); 355 356 /* Delete old redirected routes to keep the kernel table small, 357 * and to prevent black holes. Check that the kernel table 358 * matches the daemon table (i.e. has the default route). 359 * But only if RIP is not running and we are not dealing with 360 * a bad gateway, since otherwise age() will be called. 361 */ 362 if (rip_sock < 0 && bad_gate == 0) 363 age(0); 364 } 365 366 367 /* Zap all routes discovered via an interface that has gone bad 368 * This should only be called when !(ifp->int_state & IS_ALIAS) 369 */ 370 void 371 if_bad_rdisc(struct interface *ifp) 372 { 373 struct dr *drp; 374 375 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 376 if (drp->dr_ifp != ifp) 377 continue; 378 drp->dr_recv_pref = 0; 379 drp->dr_ts = 0; 380 drp->dr_life = 0; 381 } 382 383 /* make a note to re-solicit, turn RIP on or off, etc. */ 384 rdisc_timer.tv_sec = 0; 385 } 386 387 388 /* mark an interface ok for router discovering. 389 */ 390 void 391 if_ok_rdisc(struct interface *ifp) 392 { 393 set_rdisc_mg(ifp, 1); 394 395 ifp->int_rdisc_cnt = 0; 396 ifp->int_rdisc_timer.tv_sec = now.tv_sec + (supplier 397 ? MIN_WAITTIME 398 : MAX_SOLICITATION_DELAY); 399 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 400 rdisc_timer = ifp->int_rdisc_timer; 401 } 402 403 404 /* get rid of a dead discovered router 405 */ 406 static void 407 del_rdisc(struct dr *drp) 408 { 409 struct interface *ifp; 410 naddr gate; 411 int i; 412 413 414 del_redirects(gate = drp->dr_gate, 0); 415 drp->dr_ts = 0; 416 drp->dr_life = 0; 417 418 419 /* Count the other discovered routes on the interface. 420 */ 421 i = 0; 422 ifp = drp->dr_ifp; 423 for (drp = drs; drp < &drs[MAX_ADS]; drp++) { 424 if (drp->dr_ts != 0 425 && drp->dr_ifp == ifp) 426 i++; 427 } 428 429 /* If that was the last good discovered router on the interface, 430 * then solicit a new one. 431 * This is contrary to RFC 1256, but defends against black holes. 432 */ 433 if (i != 0) { 434 trace_act("discovered router %s via %s" 435 " is bad--have %d remaining", 436 naddr_ntoa(gate), ifp->int_name, i); 437 } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { 438 trace_act("last discovered router %s via %s" 439 " is bad--re-solicit", 440 naddr_ntoa(gate), ifp->int_name); 441 ifp->int_rdisc_cnt = 0; 442 ifp->int_rdisc_timer.tv_sec = 0; 443 rdisc_sol(); 444 } else { 445 trace_act("last discovered router %s via %s" 446 " is bad--wait to solicit", 447 naddr_ntoa(gate), ifp->int_name); 448 } 449 } 450 451 452 /* Find the best discovered route, 453 * and discard stale routers. 454 */ 455 static void 456 rdisc_sort(void) 457 { 458 struct dr *drp, *new_drp; 459 struct rt_entry *rt; 460 struct rt_spare new; 461 struct interface *ifp; 462 u_int new_st = 0; 463 n_long new_pref = 0; 464 465 466 /* Find the best discovered route. 467 */ 468 new_drp = 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 memset(&new, 0, 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, /* in host byte order */ 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 valuable 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 = 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 rsin; 704 int flags; 705 const char *msg; 706 naddr tgt_mcast; 707 708 709 memset(&rsin, 0, sizeof(rsin)); 710 rsin.sin_addr.s_addr = dst; 711 rsin.sin_family = AF_INET; 712 #ifdef _HAVE_SIN_LEN 713 rsin.sin_len = sizeof(rsin); 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 rsin.sin_addr.s_addr = ifp->int_dstaddr; 727 } else { 728 msg = "Send broadcast"; 729 rsin.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_IFINDEX 744 /* specify ifindex */ 745 tgt_mcast = htonl(ifp->int_index); 746 #else 747 #ifdef MCAST_PPP_BUG 748 /* Do not specify the primary interface explicitly 749 * if we have the multicast point-to-point kernel 750 * bug, since the kernel will do the wrong thing 751 * if the local address of a point-to-point link 752 * is the same as the address of an ordinary 753 * interface. 754 */ 755 if (ifp->int_addr == myaddr) { 756 tgt_mcast = 0; 757 } else 758 #endif 759 tgt_mcast = ifp->int_addr; 760 #endif 761 if (0 > setsockopt(rdisc_sock, 762 IPPROTO_IP, IP_MULTICAST_IF, 763 &tgt_mcast, sizeof(tgt_mcast))) { 764 LOGERR("setsockopt(rdisc_sock," 765 "IP_MULTICAST_IF)"); 766 rdisc_sock_mcast = 0; 767 return; 768 } 769 rdisc_sock_mcast = ifp; 770 } 771 flags = 0; 772 break; 773 } 774 775 if (rdisc_sock < 0) 776 get_rdisc_sock(); 777 778 trace_rdisc(msg, ifp->int_addr, rsin.sin_addr.s_addr, ifp, 779 p, p_size); 780 781 if (0 > sendto(rdisc_sock, p, p_size, flags, 782 (struct sockaddr *)&rsin, sizeof(rsin))) { 783 if (ifp == 0 || !(ifp->int_state & IS_BROKE)) 784 msglog("sendto(%s%s%s): %s", 785 ifp != 0 ? ifp->int_name : "", 786 ifp != 0 ? ", " : "", 787 inet_ntoa(rsin.sin_addr), 788 strerror(errno)); 789 if (ifp != 0) 790 if_sick(ifp); 791 } 792 } 793 794 795 /* Send an advertisement 796 */ 797 static void 798 send_adv(struct interface *ifp, 799 naddr dst, /* 0 or unicast destination */ 800 int type) /* 0=unicast, 1=bcast, 2=mcast */ 801 { 802 union ad_u u; 803 n_long pref; 804 805 806 memset(&u, 0, sizeof(u.ad)); 807 808 u.ad.icmp_type = ICMP_ROUTERADVERT; 809 u.ad.icmp_ad_num = 1; 810 u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; 811 812 u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); 813 814 /* Convert the configured preference to an unsigned value, 815 * bias it by the interface metric, and then send it as a 816 * signed, network byte order value. 817 */ 818 pref = UNSIGN_PREF(ifp->int_rdisc_pref); 819 u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); 820 821 u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; 822 823 u.ad.icmp_cksum = in_cksum((u_short*)&u.ad, sizeof(u.ad)); 824 825 send_rdisc(&u, sizeof(u.ad), ifp, dst, type); 826 } 827 828 829 /* Advertise for Router Discovery 830 */ 831 void 832 rdisc_adv(void) 833 { 834 struct interface *ifp; 835 836 if (!supplier) 837 return; 838 839 rdisc_timer.tv_sec = now.tv_sec + NEVER; 840 841 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 842 if (0 != (ifp->int_state & (IS_NO_ADV_OUT | IS_BROKE))) 843 continue; 844 845 if (!timercmp(&ifp->int_rdisc_timer, &now, >) 846 || stopint) { 847 send_adv(ifp, htonl(INADDR_ALLHOSTS_GROUP), 848 (ifp->int_state&IS_BCAST_RDISC) ? 1 : 2); 849 ifp->int_rdisc_cnt++; 850 851 intvl_random(&ifp->int_rdisc_timer, 852 (ifp->int_rdisc_int*3)/4, 853 ifp->int_rdisc_int); 854 if (ifp->int_rdisc_cnt < MAX_INITIAL_ADVERTS 855 && (ifp->int_rdisc_timer.tv_sec 856 > MAX_INITIAL_ADVERT_INTERVAL)) { 857 ifp->int_rdisc_timer.tv_sec 858 = MAX_INITIAL_ADVERT_INTERVAL; 859 } 860 timevaladd(&ifp->int_rdisc_timer, &now); 861 } 862 863 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 864 rdisc_timer = ifp->int_rdisc_timer; 865 } 866 } 867 868 869 /* Solicit for Router Discovery 870 */ 871 void 872 rdisc_sol(void) 873 { 874 struct interface *ifp; 875 union ad_u u; 876 877 878 if (supplier) 879 return; 880 881 rdisc_timer.tv_sec = now.tv_sec + NEVER; 882 883 for (ifp = ifnet; ifp; ifp = ifp->int_next) { 884 if (0 != (ifp->int_state & (IS_NO_SOL_OUT | IS_BROKE)) 885 || ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 886 continue; 887 888 if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { 889 memset(&u, 0, sizeof(u.so)); 890 u.so.icmp_type = ICMP_ROUTERSOLICIT; 891 u.so.icmp_cksum = in_cksum((u_short*)&u.so, 892 sizeof(u.so)); 893 send_rdisc(&u, sizeof(u.so), ifp, 894 htonl(INADDR_ALLROUTERS_GROUP), 895 ((ifp->int_state&IS_BCAST_RDISC) ? 1 : 2)); 896 897 if (++ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) 898 continue; 899 900 ifp->int_rdisc_timer.tv_sec = SOLICITATION_INTERVAL; 901 ifp->int_rdisc_timer.tv_usec = 0; 902 timevaladd(&ifp->int_rdisc_timer, &now); 903 } 904 905 if (timercmp(&rdisc_timer, &ifp->int_rdisc_timer, >)) 906 rdisc_timer = ifp->int_rdisc_timer; 907 } 908 } 909 910 911 /* check the IP header of a possible Router Discovery ICMP packet */ 912 static struct interface * /* 0 if bad */ 913 ck_icmp(const char *act, 914 naddr from, 915 struct interface *ifp, 916 naddr to, 917 union ad_u *p, 918 u_int len) 919 { 920 const char *type; 921 922 923 if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { 924 type = "advertisement"; 925 } else if (p->icmp.icmp_type == ICMP_ROUTERSOLICIT) { 926 type = "solicitation"; 927 } else { 928 return 0; 929 } 930 931 if (p->icmp.icmp_code != 0) { 932 trace_pkt("unrecognized ICMP Router %s code=%d from %s to %s", 933 type, p->icmp.icmp_code, 934 naddr_ntoa(from), naddr_ntoa(to)); 935 return 0; 936 } 937 938 trace_rdisc(act, from, to, ifp, p, len); 939 940 if (ifp == 0) 941 trace_pkt("unknown interface for router-discovery %s" 942 " from %s to %s", 943 type, naddr_ntoa(from), naddr_ntoa(to)); 944 945 return ifp; 946 } 947 948 949 /* read packets from the router discovery socket 950 */ 951 void 952 read_d(void) 953 { 954 static struct msg_limit bad_asize, bad_len; 955 #ifdef USE_PASSIFNAME 956 static struct msg_limit bad_name; 957 #endif 958 struct sockaddr_in from; 959 int n, fromlen, cc, hlen; 960 struct { 961 #ifdef USE_PASSIFNAME 962 char ifname[IFNAMSIZ]; 963 #endif 964 union { 965 struct ip ip; 966 u_short s[512/2]; 967 u_char b[512]; 968 } pkt; 969 } buf; 970 union ad_u *p; 971 n_long *wp; 972 struct interface *ifp; 973 974 975 for (;;) { 976 fromlen = sizeof(from); 977 cc = recvfrom(rdisc_sock, &buf, sizeof(buf), 0, 978 (struct sockaddr*)&from, 979 &fromlen); 980 if (cc <= 0) { 981 if (cc < 0 && errno != EWOULDBLOCK) 982 LOGERR("recvfrom(rdisc_sock)"); 983 break; 984 } 985 if (fromlen != sizeof(struct sockaddr_in)) 986 logbad(1,"impossible recvfrom(rdisc_sock) fromlen=%d", 987 fromlen); 988 #ifdef USE_PASSIFNAME 989 if ((cc -= sizeof(buf.ifname)) < 0) 990 logbad(0,"missing USE_PASSIFNAME; only %d bytes", 991 cc+sizeof(buf.ifname)); 992 #endif 993 994 hlen = buf.pkt.ip.ip_hl << 2; 995 if (cc < hlen + ICMP_MINLEN) 996 continue; 997 p = (union ad_u *)&buf.pkt.b[hlen]; 998 cc -= hlen; 999 1000 #ifdef USE_PASSIFNAME 1001 ifp = ifwithname(buf.ifname, 0); 1002 if (ifp == 0) 1003 msglim(&bad_name, from.sin_addr.s_addr, 1004 "impossible rdisc if_ name %.*s", 1005 IFNAMSIZ, buf.ifname); 1006 #else 1007 /* If we could tell the interface on which a packet from 1008 * address 0 arrived, we could deal with such solicitations. 1009 */ 1010 ifp = ((from.sin_addr.s_addr == 0) 1011 ? 0 : iflookup(from.sin_addr.s_addr)); 1012 #endif 1013 ifp = ck_icmp("Recv", from.sin_addr.s_addr, ifp, 1014 buf.pkt.ip.ip_dst.s_addr, p, cc); 1015 if (ifp == 0) 1016 continue; 1017 if (ifwithaddr(from.sin_addr.s_addr, 0, 0)) { 1018 trace_pkt(" " 1019 "discard our own Router Discovery message"); 1020 continue; 1021 } 1022 1023 switch (p->icmp.icmp_type) { 1024 case ICMP_ROUTERADVERT: 1025 if (p->ad.icmp_ad_asize*4 1026 < (int)sizeof(p->ad.icmp_ad_info[0])) { 1027 msglim(&bad_asize, from.sin_addr.s_addr, 1028 "intolerable rdisc address size=%d", 1029 p->ad.icmp_ad_asize); 1030 continue; 1031 } 1032 if (p->ad.icmp_ad_num == 0) { 1033 trace_pkt(" empty?"); 1034 continue; 1035 } 1036 if (cc != (int)(sizeof(p->ad) 1037 - sizeof(p->ad.icmp_ad_info) 1038 + (p->ad.icmp_ad_num 1039 * sizeof(p->ad.icmp_ad_info[0])))) { 1040 msglim(&bad_len, from.sin_addr.s_addr, 1041 "rdisc length %d does not match ad_num" 1042 " %d", cc, p->ad.icmp_ad_num); 1043 continue; 1044 } 1045 if (supplier) 1046 continue; 1047 if (ifp->int_state & IS_NO_ADV_IN) 1048 continue; 1049 1050 wp = &p->ad.icmp_ad_info[0].icmp_ad_addr; 1051 for (n = 0; n < p->ad.icmp_ad_num; n++) { 1052 parse_ad(from.sin_addr.s_addr, 1053 wp[0], wp[1], 1054 ntohs(p->ad.icmp_ad_life), 1055 ifp); 1056 wp += p->ad.icmp_ad_asize; 1057 } 1058 break; 1059 1060 1061 case ICMP_ROUTERSOLICIT: 1062 if (!supplier) 1063 continue; 1064 if (ifp->int_state & IS_NO_ADV_OUT) 1065 continue; 1066 if (stopint) 1067 continue; 1068 1069 /* XXX 1070 * We should handle messages from address 0. 1071 */ 1072 1073 /* Respond with a point-to-point advertisement */ 1074 send_adv(ifp, from.sin_addr.s_addr, 0); 1075 break; 1076 } 1077 } 1078 1079 rdisc_sort(); 1080 } 1081