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