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