1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * Copyright (c) 1983, 1988, 1993 6*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 7*0Sstevel@tonic-gate * 8*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 9*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 10*0Sstevel@tonic-gate * are met: 11*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 12*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 13*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 14*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 15*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 16*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 17*0Sstevel@tonic-gate * must display the following acknowledgment: 18*0Sstevel@tonic-gate * This product includes software developed by the University of 19*0Sstevel@tonic-gate * California, Berkeley and its contributors. 20*0Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 21*0Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 22*0Sstevel@tonic-gate * without specific prior written permission. 23*0Sstevel@tonic-gate * 24*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34*0Sstevel@tonic-gate * SUCH DAMAGE. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * $FreeBSD: src/sbin/routed/output.c,v 1.7 2000/08/11 08:24:38 sheldonh Exp $ 37*0Sstevel@tonic-gate */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate #include "defs.h" 42*0Sstevel@tonic-gate #include <md5.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate uint_t update_seqno; 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate /* 48*0Sstevel@tonic-gate * walk the tree of routes with this for output 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate static struct { 51*0Sstevel@tonic-gate struct sockaddr_in to; 52*0Sstevel@tonic-gate in_addr_t to_mask; 53*0Sstevel@tonic-gate in_addr_t to_net; 54*0Sstevel@tonic-gate in_addr_t to_std_mask; 55*0Sstevel@tonic-gate in_addr_t to_std_net; 56*0Sstevel@tonic-gate struct interface *ifp; /* usually output interface */ 57*0Sstevel@tonic-gate struct auth *a; 58*0Sstevel@tonic-gate uint8_t metric; /* adjust metrics by interface */ 59*0Sstevel@tonic-gate uint32_t npackets; 60*0Sstevel@tonic-gate uint32_t gen_limit; 61*0Sstevel@tonic-gate #define WS_GEN_LIMIT_MAX 1024 62*0Sstevel@tonic-gate uint16_t state; 63*0Sstevel@tonic-gate #define WS_ST_FLASH 0x001 /* send only changed routes */ 64*0Sstevel@tonic-gate #define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ 65*0Sstevel@tonic-gate #define WS_ST_AG 0x004 /* ok to aggregate subnets */ 66*0Sstevel@tonic-gate #define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ 67*0Sstevel@tonic-gate #define WS_ST_QUERY 0x010 /* responding to a query */ 68*0Sstevel@tonic-gate #define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ 69*0Sstevel@tonic-gate #define WS_ST_DEFAULT 0x040 /* faking a default */ 70*0Sstevel@tonic-gate } ws; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ 73*0Sstevel@tonic-gate struct ws_buf v12buf; 74*0Sstevel@tonic-gate static union pkt_buf ripv12_buf; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* Another for only RIPv2 listeners */ 77*0Sstevel@tonic-gate static struct ws_buf v2buf; 78*0Sstevel@tonic-gate static union pkt_buf rip_v2_buf; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate void 83*0Sstevel@tonic-gate bufinit(void) 84*0Sstevel@tonic-gate { 85*0Sstevel@tonic-gate ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE; 86*0Sstevel@tonic-gate v12buf.buf = &ripv12_buf.rip; 87*0Sstevel@tonic-gate v12buf.base = &v12buf.buf->rip_nets[0]; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE; 90*0Sstevel@tonic-gate rip_v2_buf.rip.rip_vers = RIPv2; 91*0Sstevel@tonic-gate v2buf.buf = &rip_v2_buf.rip; 92*0Sstevel@tonic-gate v2buf.base = &v2buf.buf->rip_nets[0]; 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * Send the contents of the global buffer via the non-multicast socket 98*0Sstevel@tonic-gate */ 99*0Sstevel@tonic-gate int /* <0 on failure */ 100*0Sstevel@tonic-gate output(enum output_type type, 101*0Sstevel@tonic-gate struct sockaddr_in *dst, /* send to here */ 102*0Sstevel@tonic-gate struct interface *ifp, 103*0Sstevel@tonic-gate struct rip *buf, 104*0Sstevel@tonic-gate int size) /* this many bytes */ 105*0Sstevel@tonic-gate { 106*0Sstevel@tonic-gate struct sockaddr_in sin; 107*0Sstevel@tonic-gate int flags; 108*0Sstevel@tonic-gate const char *msg; 109*0Sstevel@tonic-gate int res; 110*0Sstevel@tonic-gate int ifindex; 111*0Sstevel@tonic-gate struct in_addr addr; 112*0Sstevel@tonic-gate static int rip_sock_ifindex; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate sin = *dst; 115*0Sstevel@tonic-gate if (sin.sin_port == 0) 116*0Sstevel@tonic-gate sin.sin_port = htons(RIP_PORT); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate flags = 0; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (ifp == NULL && type == OUT_MULTICAST) { 121*0Sstevel@tonic-gate msglog("Cannot send RIP message to %s", 122*0Sstevel@tonic-gate inet_ntoa(sin.sin_addr)); 123*0Sstevel@tonic-gate return (-1); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate switch (type) { 127*0Sstevel@tonic-gate case OUT_QUERY: 128*0Sstevel@tonic-gate msg = "Answer Query"; 129*0Sstevel@tonic-gate break; 130*0Sstevel@tonic-gate case OUT_UNICAST: 131*0Sstevel@tonic-gate msg = "Send"; 132*0Sstevel@tonic-gate flags = MSG_DONTROUTE; 133*0Sstevel@tonic-gate break; 134*0Sstevel@tonic-gate case OUT_BROADCAST: 135*0Sstevel@tonic-gate msg = "Send bcast"; 136*0Sstevel@tonic-gate break; 137*0Sstevel@tonic-gate case OUT_MULTICAST: 138*0Sstevel@tonic-gate msg = "Send mcast"; 139*0Sstevel@tonic-gate break; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate case NO_OUT_MULTICAST: 142*0Sstevel@tonic-gate case NO_OUT_RIPV2: 143*0Sstevel@tonic-gate default: 144*0Sstevel@tonic-gate #ifdef DEBUG 145*0Sstevel@tonic-gate abort(); 146*0Sstevel@tonic-gate #endif 147*0Sstevel@tonic-gate return (-1); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* 151*0Sstevel@tonic-gate * Note that we intentionally reset IP_XMIT_IF to zero if 152*0Sstevel@tonic-gate * we're doing multicast. The kernel ignores IP_MULTICAST_IF 153*0Sstevel@tonic-gate * if IP_XMIT_IF is set, and we can't deal with alias source 154*0Sstevel@tonic-gate * addresses without it. 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate ifindex = (type != OUT_MULTICAST && type != OUT_QUERY && 157*0Sstevel@tonic-gate ifp != NULL && ifp->int_phys != NULL) ? 158*0Sstevel@tonic-gate ifp->int_phys->phyi_index : 0; 159*0Sstevel@tonic-gate if (rip_sock_ifindex != ifindex) { 160*0Sstevel@tonic-gate if (setsockopt(rip_sock, IPPROTO_IP, IP_XMIT_IF, &ifindex, 161*0Sstevel@tonic-gate sizeof (ifindex)) == -1) { 162*0Sstevel@tonic-gate LOGERR("setsockopt(rip_sock, IP_XMIT_IF)"); 163*0Sstevel@tonic-gate return (-1); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate rip_sock_ifindex = ifindex; 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate if (rip_sock_interface != ifp) { 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * For multicast, we have to choose the source 171*0Sstevel@tonic-gate * address. This is either the local address 172*0Sstevel@tonic-gate * (non-point-to-point) or the remote address. 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate if (ifp != NULL) { 175*0Sstevel@tonic-gate addr.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 176*0Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 177*0Sstevel@tonic-gate if (type == OUT_MULTICAST && 178*0Sstevel@tonic-gate setsockopt(rip_sock, IPPROTO_IP, 179*0Sstevel@tonic-gate IP_MULTICAST_IF, &addr, sizeof (addr)) == -1) { 180*0Sstevel@tonic-gate LOGERR("setsockopt(rip_sock, IP_MULTICAST_IF)"); 181*0Sstevel@tonic-gate return (-1); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate rip_sock_interface = ifp; 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate trace_rip(msg, "to", &sin, ifp, buf, size); 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate res = sendto(rip_sock, buf, size, flags, 190*0Sstevel@tonic-gate (struct sockaddr *)&sin, sizeof (sin)); 191*0Sstevel@tonic-gate if (res < 0 && 192*0Sstevel@tonic-gate (ifp == NULL || !(ifp->int_state & IS_BROKE))) { 193*0Sstevel@tonic-gate writelog(LOG_WARNING, "%s sendto(%s%s%s.%d): %s", msg, 194*0Sstevel@tonic-gate ifp != NULL ? ifp->int_name : "", 195*0Sstevel@tonic-gate ifp != NULL ? ", " : "", 196*0Sstevel@tonic-gate inet_ntoa(sin.sin_addr), 197*0Sstevel@tonic-gate ntohs(sin.sin_port), 198*0Sstevel@tonic-gate rip_strerror(errno)); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate return (res); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* 206*0Sstevel@tonic-gate * Find the first key for a packet to send. 207*0Sstevel@tonic-gate * Try for a key that is eligible and has not expired, but settle for 208*0Sstevel@tonic-gate * the last key if they have all expired. 209*0Sstevel@tonic-gate * If no key is ready yet, give up. 210*0Sstevel@tonic-gate */ 211*0Sstevel@tonic-gate struct auth * 212*0Sstevel@tonic-gate find_auth(struct interface *ifp) 213*0Sstevel@tonic-gate { 214*0Sstevel@tonic-gate struct auth *ap, *res = NULL; 215*0Sstevel@tonic-gate int i; 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate if (ifp == NULL) 219*0Sstevel@tonic-gate return (NULL); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate if ((ap = ifp->int_auth) == NULL) 222*0Sstevel@tonic-gate return (NULL); 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate for (i = 0; i < MAX_AUTH_KEYS; i++, ap++) { 225*0Sstevel@tonic-gate /* stop looking after the last key */ 226*0Sstevel@tonic-gate if (ap->type == RIP_AUTH_NONE) 227*0Sstevel@tonic-gate break; 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate /* ignore keys that are not ready yet */ 230*0Sstevel@tonic-gate if ((ulong_t)ap->start > (ulong_t)clk.tv_sec) 231*0Sstevel@tonic-gate continue; 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate if ((ulong_t)ap->end < (ulong_t)clk.tv_sec) { 234*0Sstevel@tonic-gate /* note best expired password as a fall-back */ 235*0Sstevel@tonic-gate if (res == NULL || 236*0Sstevel@tonic-gate (((ulong_t)ap->end > (ulong_t)res->end)) && 237*0Sstevel@tonic-gate ((ulong_t)res->end < (ulong_t)clk.tv_sec)) 238*0Sstevel@tonic-gate res = ap; 239*0Sstevel@tonic-gate continue; 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* note key with the best future */ 243*0Sstevel@tonic-gate if (res == NULL || (ulong_t)res->end < (ulong_t)ap->end) 244*0Sstevel@tonic-gate res = ap; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate return (res); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate void 251*0Sstevel@tonic-gate clr_ws_buf(struct ws_buf *wb, struct auth *ap) 252*0Sstevel@tonic-gate { 253*0Sstevel@tonic-gate struct netauth *na; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate wb->lim = wb->base + NETS_LEN; 256*0Sstevel@tonic-gate wb->n = wb->base; 257*0Sstevel@tonic-gate (void) memset(wb->n, 0, NETS_LEN*sizeof (*wb->n)); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * (start to) install authentication if appropriate 261*0Sstevel@tonic-gate */ 262*0Sstevel@tonic-gate if (ap == NULL) 263*0Sstevel@tonic-gate return; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate na = (struct netauth *)wb->n; 266*0Sstevel@tonic-gate if (ap->type == RIP_AUTH_PW) { 267*0Sstevel@tonic-gate na->a_family = RIP_AF_AUTH; 268*0Sstevel@tonic-gate na->a_type = RIP_AUTH_PW; 269*0Sstevel@tonic-gate (void) memcpy(na->au.au_pw, ap->key, sizeof (na->au.au_pw)); 270*0Sstevel@tonic-gate wb->n++; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate } else if (ap->type == RIP_AUTH_MD5) { 273*0Sstevel@tonic-gate na->a_family = RIP_AF_AUTH; 274*0Sstevel@tonic-gate na->a_type = RIP_AUTH_MD5; 275*0Sstevel@tonic-gate na->au.a_md5.md5_keyid = ap->keyid; 276*0Sstevel@tonic-gate na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; 277*0Sstevel@tonic-gate na->au.a_md5.md5_seqno = htonl(clk.tv_sec); 278*0Sstevel@tonic-gate wb->n++; 279*0Sstevel@tonic-gate wb->lim--; /* make room for trailer */ 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate void 285*0Sstevel@tonic-gate end_md5_auth(struct ws_buf *wb, struct auth *ap) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate struct netauth *na, *na2; 288*0Sstevel@tonic-gate MD5_CTX md5_ctx; 289*0Sstevel@tonic-gate int len; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate na = (struct netauth *)wb->base; 292*0Sstevel@tonic-gate na2 = (struct netauth *)wb->n; 293*0Sstevel@tonic-gate len = (char *)na2-(char *)wb->buf; 294*0Sstevel@tonic-gate na2->a_family = RIP_AF_AUTH; 295*0Sstevel@tonic-gate na2->a_type = RIP_AUTH_TRAILER; 296*0Sstevel@tonic-gate na->au.a_md5.md5_pkt_len = htons(len); 297*0Sstevel@tonic-gate MD5Init(&md5_ctx); 298*0Sstevel@tonic-gate /* len+4 to include auth trailer's family/type in MD5 sum */ 299*0Sstevel@tonic-gate MD5Update(&md5_ctx, (uchar_t *)wb->buf, len + 4); 300*0Sstevel@tonic-gate MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); 301*0Sstevel@tonic-gate MD5Final(na2->au.au_pw, &md5_ctx); 302*0Sstevel@tonic-gate wb->n++; 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate /* 307*0Sstevel@tonic-gate * Send the buffer 308*0Sstevel@tonic-gate */ 309*0Sstevel@tonic-gate static void 310*0Sstevel@tonic-gate supply_write(struct ws_buf *wb) 311*0Sstevel@tonic-gate { 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * Output multicast only if legal. 314*0Sstevel@tonic-gate * If we would multicast and it would be illegal, then discard the 315*0Sstevel@tonic-gate * packet. 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate switch (wb->type) { 318*0Sstevel@tonic-gate case NO_OUT_MULTICAST: 319*0Sstevel@tonic-gate trace_pkt("skip multicast to %s because impossible", 320*0Sstevel@tonic-gate naddr_ntoa(ws.to.sin_addr.s_addr)); 321*0Sstevel@tonic-gate break; 322*0Sstevel@tonic-gate case NO_OUT_RIPV2: 323*0Sstevel@tonic-gate break; 324*0Sstevel@tonic-gate default: 325*0Sstevel@tonic-gate if (ws.a != NULL && ws.a->type == RIP_AUTH_MD5) 326*0Sstevel@tonic-gate end_md5_auth(wb, ws.a); 327*0Sstevel@tonic-gate if (output(wb->type, &ws.to, ws.ifp, wb->buf, 328*0Sstevel@tonic-gate ((char *)wb->n - (char *)wb->buf)) < 0 && ws.ifp != NULL) 329*0Sstevel@tonic-gate if_sick(ws.ifp, _B_FALSE); 330*0Sstevel@tonic-gate ws.npackets++; 331*0Sstevel@tonic-gate break; 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate clr_ws_buf(wb, ws.a); 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * Put an entry into the packet 340*0Sstevel@tonic-gate */ 341*0Sstevel@tonic-gate static void 342*0Sstevel@tonic-gate supply_out(struct ag_info *ag) 343*0Sstevel@tonic-gate { 344*0Sstevel@tonic-gate uint32_t dstcount; 345*0Sstevel@tonic-gate in_addr_t mask, v1_mask, dst_h, ddst_h = 0; 346*0Sstevel@tonic-gate struct ws_buf *wb; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Skip this route if doing a flash update and it and the routes 351*0Sstevel@tonic-gate * it aggregates have not changed recently. 352*0Sstevel@tonic-gate */ 353*0Sstevel@tonic-gate if (ag->ag_seqno < update_seqno && (ws.state & WS_ST_FLASH)) 354*0Sstevel@tonic-gate return; 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate dst_h = ag->ag_dst_h; 357*0Sstevel@tonic-gate mask = ag->ag_mask; 358*0Sstevel@tonic-gate v1_mask = ripv1_mask_host(htonl(dst_h), 359*0Sstevel@tonic-gate (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : NULL); 360*0Sstevel@tonic-gate dstcount = 0; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * If we are sending RIPv2 packets that cannot (or must not) be 364*0Sstevel@tonic-gate * heard by RIPv1 listeners, do not worry about sub- or supernets. 365*0Sstevel@tonic-gate * Subnets (from other networks) can only be sent via multicast. 366*0Sstevel@tonic-gate * A pair of subnet routes might have been promoted so that they 367*0Sstevel@tonic-gate * are legal to send by RIPv1. 368*0Sstevel@tonic-gate * If RIPv1 is off, use the multicast buffer. 369*0Sstevel@tonic-gate */ 370*0Sstevel@tonic-gate if ((ws.state & WS_ST_RIP2_ALL) || 371*0Sstevel@tonic-gate ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) { 372*0Sstevel@tonic-gate /* use the RIPv2-only buffer */ 373*0Sstevel@tonic-gate wb = &v2buf; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate } else { 376*0Sstevel@tonic-gate /* 377*0Sstevel@tonic-gate * use the RIPv1-or-RIPv2 buffer 378*0Sstevel@tonic-gate */ 379*0Sstevel@tonic-gate wb = &v12buf; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /* 382*0Sstevel@tonic-gate * Convert supernet route into corresponding set of network 383*0Sstevel@tonic-gate * routes for RIPv1, but leave non-contiguous netmasks 384*0Sstevel@tonic-gate * to ag_check(). 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate if (v1_mask > mask && 387*0Sstevel@tonic-gate mask + (mask & -mask) == 0) { 388*0Sstevel@tonic-gate ddst_h = v1_mask & -v1_mask; 389*0Sstevel@tonic-gate dstcount = (v1_mask & ~mask)/ddst_h; 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate if (dstcount > ws.gen_limit) { 392*0Sstevel@tonic-gate /* 393*0Sstevel@tonic-gate * Punt if we would have to generate an 394*0Sstevel@tonic-gate * unreasonable number of routes. 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate if (TRACECONTENTS) 397*0Sstevel@tonic-gate trace_misc("sending %s-->%s as 1" 398*0Sstevel@tonic-gate " instead of %d routes", 399*0Sstevel@tonic-gate addrname(htonl(dst_h), mask, 1), 400*0Sstevel@tonic-gate naddr_ntoa(ws.to.sin_addr.s_addr), 401*0Sstevel@tonic-gate dstcount + 1); 402*0Sstevel@tonic-gate dstcount = 0; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate } else { 405*0Sstevel@tonic-gate mask = v1_mask; 406*0Sstevel@tonic-gate ws.gen_limit -= dstcount; 407*0Sstevel@tonic-gate } 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate do { 412*0Sstevel@tonic-gate wb->n->n_family = RIP_AF_INET; 413*0Sstevel@tonic-gate wb->n->n_dst = htonl(dst_h); 414*0Sstevel@tonic-gate /* 415*0Sstevel@tonic-gate * If the route is from router-discovery or we are 416*0Sstevel@tonic-gate * shutting down, or this is a broken/sick interface, 417*0Sstevel@tonic-gate * admit only a bad metric. 418*0Sstevel@tonic-gate */ 419*0Sstevel@tonic-gate wb->n->n_metric = ((stopint || ag->ag_metric < 1 || 420*0Sstevel@tonic-gate (ag->ag_ifp && (ag->ag_ifp->int_state & 421*0Sstevel@tonic-gate (IS_BROKE|IS_SICK)))) ? HOPCNT_INFINITY : ag->ag_metric); 422*0Sstevel@tonic-gate wb->n->n_metric = htonl(wb->n->n_metric); 423*0Sstevel@tonic-gate /* 424*0Sstevel@tonic-gate * Any non-zero bits in the supposedly unused RIPv1 fields 425*0Sstevel@tonic-gate * cause the old `routed` to ignore the route. 426*0Sstevel@tonic-gate * That means the mask and so forth cannot be sent 427*0Sstevel@tonic-gate * in the hybrid RIPv1/RIPv2 mode. 428*0Sstevel@tonic-gate */ 429*0Sstevel@tonic-gate if (ws.state & WS_ST_RIP2_ALL) { 430*0Sstevel@tonic-gate if (ag->ag_nhop != 0 && 431*0Sstevel@tonic-gate ((ws.state & WS_ST_QUERY) || 432*0Sstevel@tonic-gate (ag->ag_nhop != ws.ifp->int_addr && 433*0Sstevel@tonic-gate on_net(ag->ag_nhop, ws.ifp->int_net, 434*0Sstevel@tonic-gate ws.ifp->int_mask)) && 435*0Sstevel@tonic-gate ifwithaddr(ag->ag_nhop, _B_FALSE, _B_FALSE) == 436*0Sstevel@tonic-gate NULL)) 437*0Sstevel@tonic-gate wb->n->n_nhop = ag->ag_nhop; 438*0Sstevel@tonic-gate wb->n->n_mask = htonl(mask); 439*0Sstevel@tonic-gate wb->n->n_tag = ag->ag_tag; 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate dst_h += ddst_h; 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate if (++wb->n >= wb->lim) 444*0Sstevel@tonic-gate supply_write(wb); 445*0Sstevel@tonic-gate } while (dstcount-- > 0); 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * Supply one route from the table 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate /* ARGSUSED */ 453*0Sstevel@tonic-gate static int 454*0Sstevel@tonic-gate walk_supply(struct radix_node *rn, void *argp) 455*0Sstevel@tonic-gate { 456*0Sstevel@tonic-gate #define RT ((struct rt_entry *)rn) 457*0Sstevel@tonic-gate ushort_t ags; 458*0Sstevel@tonic-gate uint8_t metric, pref; 459*0Sstevel@tonic-gate in_addr_t dst, nhop; 460*0Sstevel@tonic-gate struct rt_spare *rts; 461*0Sstevel@tonic-gate uint_t sparecount; 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate /* 465*0Sstevel@tonic-gate * Do not advertise external remote interfaces or passive interfaces. 466*0Sstevel@tonic-gate */ 467*0Sstevel@tonic-gate if ((RT->rt_state & RS_IF) && RT->rt_ifp != NULL && 468*0Sstevel@tonic-gate (RT->rt_ifp->int_state & IS_PASSIVE) && 469*0Sstevel@tonic-gate !(RT->rt_state & RS_MHOME)) 470*0Sstevel@tonic-gate return (0); 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * Do not advertise routes learnt from /etc/gateways. 473*0Sstevel@tonic-gate */ 474*0Sstevel@tonic-gate if (RT->rt_spares[0].rts_origin == RO_FILE) 475*0Sstevel@tonic-gate return (0); 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate /* 478*0Sstevel@tonic-gate * Do not advertise routes which would lead to forwarding on a 479*0Sstevel@tonic-gate * non-forwarding interface. 480*0Sstevel@tonic-gate */ 481*0Sstevel@tonic-gate if (RT->rt_state & RS_NOPROPAGATE) 482*0Sstevel@tonic-gate return (0); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate /* 485*0Sstevel@tonic-gate * If being quiet about our ability to forward, then 486*0Sstevel@tonic-gate * do not say anything unless responding to a query, 487*0Sstevel@tonic-gate * except about our main interface. 488*0Sstevel@tonic-gate */ 489*0Sstevel@tonic-gate if (!should_supply(NULL) && !(ws.state & WS_ST_QUERY) && 490*0Sstevel@tonic-gate !(RT->rt_state & RS_MHOME)) 491*0Sstevel@tonic-gate return (0); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate dst = RT->rt_dst; 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * do not collide with the fake default route 497*0Sstevel@tonic-gate */ 498*0Sstevel@tonic-gate if (dst == RIP_DEFAULT && (ws.state & WS_ST_DEFAULT)) 499*0Sstevel@tonic-gate return (0); 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate if (RT->rt_state & RS_NET_SYN) { 502*0Sstevel@tonic-gate if (RT->rt_state & RS_NET_INT) { 503*0Sstevel@tonic-gate /* 504*0Sstevel@tonic-gate * Do not send manual synthetic network routes 505*0Sstevel@tonic-gate * into the subnet. 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate if (on_net(ws.to.sin_addr.s_addr, 508*0Sstevel@tonic-gate ntohl(dst), RT->rt_mask)) 509*0Sstevel@tonic-gate return (0); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate } else { 512*0Sstevel@tonic-gate /* 513*0Sstevel@tonic-gate * Do not send automatic synthetic network routes 514*0Sstevel@tonic-gate * if they are not needed because no RIPv1 listeners 515*0Sstevel@tonic-gate * can hear them. 516*0Sstevel@tonic-gate */ 517*0Sstevel@tonic-gate if (ws.state & WS_ST_RIP2_ALL) 518*0Sstevel@tonic-gate return (0); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate /* 521*0Sstevel@tonic-gate * Do not send automatic synthetic network routes to 522*0Sstevel@tonic-gate * the real subnet. 523*0Sstevel@tonic-gate */ 524*0Sstevel@tonic-gate if (on_net(ws.to.sin_addr.s_addr, 525*0Sstevel@tonic-gate ntohl(dst), RT->rt_mask)) 526*0Sstevel@tonic-gate return (0); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate nhop = 0; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate } else { 531*0Sstevel@tonic-gate /* 532*0Sstevel@tonic-gate * Advertise the next hop if this is not a route for one 533*0Sstevel@tonic-gate * of our interfaces and the next hop is on the same 534*0Sstevel@tonic-gate * network as the target. 535*0Sstevel@tonic-gate * The final determination is made by supply_out(). 536*0Sstevel@tonic-gate */ 537*0Sstevel@tonic-gate if (!(RT->rt_state & RS_IF) && !(RT->rt_state & RS_MHOME) && 538*0Sstevel@tonic-gate RT->rt_gate != loopaddr) 539*0Sstevel@tonic-gate nhop = RT->rt_gate; 540*0Sstevel@tonic-gate else 541*0Sstevel@tonic-gate nhop = 0; 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate metric = RT->rt_metric; 545*0Sstevel@tonic-gate ags = 0; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate if (!RT_ISHOST(RT)) { 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * Always suppress network routes into other, existing 550*0Sstevel@tonic-gate * network routes 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate ags |= AGS_SUPPRESS; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * Generate supernets if allowed. 556*0Sstevel@tonic-gate * If we can be heard by RIPv1 systems, we will 557*0Sstevel@tonic-gate * later convert back to ordinary nets. 558*0Sstevel@tonic-gate * This unifies dealing with received supernets. 559*0Sstevel@tonic-gate */ 560*0Sstevel@tonic-gate if ((ws.state & WS_ST_AG) && ((RT->rt_state & RS_SUBNET) || 561*0Sstevel@tonic-gate (ws.state & WS_ST_SUPER_AG))) 562*0Sstevel@tonic-gate ags |= AGS_AGGREGATE; 563*0Sstevel@tonic-gate } else if (!(RT->rt_state & RS_MHOME)) { 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * We should always suppress (into existing network routes) 566*0Sstevel@tonic-gate * the host routes for the local end of our point-to-point 567*0Sstevel@tonic-gate * links. 568*0Sstevel@tonic-gate * If we are suppressing host routes in general, then do so. 569*0Sstevel@tonic-gate * Avoid advertising host routes onto their own network, 570*0Sstevel@tonic-gate * where they should be handled by proxy-ARP. 571*0Sstevel@tonic-gate */ 572*0Sstevel@tonic-gate if ((RT->rt_state & RS_LOCAL) || ridhosts || 573*0Sstevel@tonic-gate on_net(dst, ws.to_net, ws.to_mask)) 574*0Sstevel@tonic-gate ags |= AGS_SUPPRESS; 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * Aggregate stray host routes into network routes if allowed. 578*0Sstevel@tonic-gate * We cannot aggregate host routes into small network routes 579*0Sstevel@tonic-gate * without confusing RIPv1 listeners into thinking the 580*0Sstevel@tonic-gate * network routes are host routes. 581*0Sstevel@tonic-gate */ 582*0Sstevel@tonic-gate if ((ws.state & WS_ST_AG) && (ws.state & WS_ST_RIP2_ALL)) 583*0Sstevel@tonic-gate ags |= AGS_AGGREGATE; 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * Do not send RIPv1 advertisements of subnets to other 588*0Sstevel@tonic-gate * networks. If possible, multicast them by RIPv2. 589*0Sstevel@tonic-gate */ 590*0Sstevel@tonic-gate if ((RT->rt_state & RS_SUBNET) && !(ws.state & WS_ST_RIP2_ALL) && 591*0Sstevel@tonic-gate !on_net(dst, ws.to_std_net, ws.to_std_mask)) 592*0Sstevel@tonic-gate ags |= AGS_RIPV2 | AGS_AGGREGATE; 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * Do not send a route back to where it came from, except in 597*0Sstevel@tonic-gate * response to a query. This is "split-horizon". That means not 598*0Sstevel@tonic-gate * advertising back to the same network and so via the same interface. 599*0Sstevel@tonic-gate * 600*0Sstevel@tonic-gate * We want to suppress routes that might have been fragmented 601*0Sstevel@tonic-gate * from this route by a RIPv1 router and sent back to us, and so we 602*0Sstevel@tonic-gate * cannot forget this route here. Let the split-horizon route 603*0Sstevel@tonic-gate * suppress the fragmented routes and then itself be forgotten. 604*0Sstevel@tonic-gate * 605*0Sstevel@tonic-gate * Include the routes for both ends of point-to-point interfaces 606*0Sstevel@tonic-gate * among those suppressed by split-horizon, since the other side 607*0Sstevel@tonic-gate * should knows them as well as we do. 608*0Sstevel@tonic-gate * 609*0Sstevel@tonic-gate * Notice spare routes with the same metric that we are about to 610*0Sstevel@tonic-gate * advertise, to split the horizon on redundant, inactive paths. 611*0Sstevel@tonic-gate */ 612*0Sstevel@tonic-gate if (ws.ifp != NULL && !(ws.state & WS_ST_QUERY) && 613*0Sstevel@tonic-gate (ws.state & WS_ST_TO_ON_NET) && (!(RT->rt_state & RS_IF) || 614*0Sstevel@tonic-gate (ws.ifp->int_if_flags & IFF_POINTOPOINT))) { 615*0Sstevel@tonic-gate for (rts = RT->rt_spares, sparecount = 0; 616*0Sstevel@tonic-gate sparecount < RT->rt_num_spares; sparecount++, rts++) { 617*0Sstevel@tonic-gate if (rts->rts_metric > metric || rts->rts_ifp != ws.ifp) 618*0Sstevel@tonic-gate continue; 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * If we do not mark the route with AGS_SPLIT_HZ here, 622*0Sstevel@tonic-gate * it will be poisoned-reverse, or advertised back 623*0Sstevel@tonic-gate * toward its source with an infinite metric. 624*0Sstevel@tonic-gate * If we have recently advertised the route with a 625*0Sstevel@tonic-gate * better metric than we now have, then we should 626*0Sstevel@tonic-gate * poison-reverse the route before suppressing it for 627*0Sstevel@tonic-gate * split-horizon. 628*0Sstevel@tonic-gate * 629*0Sstevel@tonic-gate * In almost all cases, if there is no spare for the 630*0Sstevel@tonic-gate * route then it is either old and dead or a brand 631*0Sstevel@tonic-gate * new route. If it is brand new, there is no need 632*0Sstevel@tonic-gate * for poison-reverse. If it is old and dead, it 633*0Sstevel@tonic-gate * is already poisoned. 634*0Sstevel@tonic-gate */ 635*0Sstevel@tonic-gate if (RT->rt_poison_time < now_expire || 636*0Sstevel@tonic-gate RT->rt_poison_metric >= metric || 637*0Sstevel@tonic-gate RT->rt_spares[1].rts_gate == 0) { 638*0Sstevel@tonic-gate ags |= AGS_SPLIT_HZ; 639*0Sstevel@tonic-gate ags &= ~AGS_SUPPRESS; 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate metric = HOPCNT_INFINITY; 642*0Sstevel@tonic-gate break; 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate /* 647*0Sstevel@tonic-gate * Keep track of the best metric with which the 648*0Sstevel@tonic-gate * route has been advertised recently. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate if (RT->rt_poison_metric >= metric || 651*0Sstevel@tonic-gate RT->rt_poison_time < now_expire) { 652*0Sstevel@tonic-gate RT->rt_poison_time = now.tv_sec; 653*0Sstevel@tonic-gate RT->rt_poison_metric = metric; 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate /* 657*0Sstevel@tonic-gate * Adjust the outgoing metric by the cost of the link. 658*0Sstevel@tonic-gate * Avoid aggregation when a route is counting to infinity. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate pref = RT->rt_poison_metric + ws.metric; 661*0Sstevel@tonic-gate metric += ws.metric; 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * If this is a static route pointing to the same interface 665*0Sstevel@tonic-gate * upon which we are sending out the RIP RESPONSE 666*0Sstevel@tonic-gate * adjust the preference so that we don't aggregate into this 667*0Sstevel@tonic-gate * route. Note that the maximum possible hop count on a route 668*0Sstevel@tonic-gate * per RFC 2453 is 16 (HOPCNT_INFINITY) 669*0Sstevel@tonic-gate */ 670*0Sstevel@tonic-gate if ((RT->rt_state & RS_STATIC) && (ws.ifp == RT->rt_ifp)) 671*0Sstevel@tonic-gate pref = (HOPCNT_INFINITY+1); 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate /* 674*0Sstevel@tonic-gate * Do not advertise stable routes that will be ignored, 675*0Sstevel@tonic-gate * unless we are answering a query. 676*0Sstevel@tonic-gate * If the route recently was advertised with a metric that 677*0Sstevel@tonic-gate * would have been less than infinity through this interface, 678*0Sstevel@tonic-gate * we need to continue to advertise it in order to poison it. 679*0Sstevel@tonic-gate */ 680*0Sstevel@tonic-gate if (metric >= HOPCNT_INFINITY) { 681*0Sstevel@tonic-gate if (!(ws.state & WS_ST_QUERY) && (pref >= HOPCNT_INFINITY || 682*0Sstevel@tonic-gate RT->rt_poison_time < now_garbage)) 683*0Sstevel@tonic-gate return (0); 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate metric = HOPCNT_INFINITY; 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* 689*0Sstevel@tonic-gate * supply this route out on the wire- we only care about dest/mask 690*0Sstevel@tonic-gate * and so can ignore all rt_spares[i] with i > 0 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate ag_check(dst, RT->rt_mask, 0, RT->rt_ifp, nhop, metric, pref, 693*0Sstevel@tonic-gate RT->rt_seqno, RT->rt_tag, ags, supply_out); 694*0Sstevel@tonic-gate return (0); 695*0Sstevel@tonic-gate #undef RT 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate /* 700*0Sstevel@tonic-gate * Supply dst with the contents of the routing tables. 701*0Sstevel@tonic-gate * If this won't fit in one packet, chop it up into several. 702*0Sstevel@tonic-gate */ 703*0Sstevel@tonic-gate void 704*0Sstevel@tonic-gate supply(struct sockaddr_in *dst, 705*0Sstevel@tonic-gate struct interface *ifp, /* output interface */ 706*0Sstevel@tonic-gate enum output_type type, 707*0Sstevel@tonic-gate int flash, /* 1=flash update */ 708*0Sstevel@tonic-gate int vers, /* RIP version */ 709*0Sstevel@tonic-gate boolean_t passwd_ok) /* OK to include cleartext password */ 710*0Sstevel@tonic-gate { 711*0Sstevel@tonic-gate struct rt_entry *rt; 712*0Sstevel@tonic-gate uint8_t def_metric; 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate ws.state = 0; 716*0Sstevel@tonic-gate ws.gen_limit = WS_GEN_LIMIT_MAX; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate ws.to = *dst; 719*0Sstevel@tonic-gate ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); 720*0Sstevel@tonic-gate ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate if (ifp != NULL) { 723*0Sstevel@tonic-gate ws.to_mask = ifp->int_mask; 724*0Sstevel@tonic-gate ws.to_net = ifp->int_net; 725*0Sstevel@tonic-gate if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask) || 726*0Sstevel@tonic-gate type == OUT_MULTICAST) 727*0Sstevel@tonic-gate ws.state |= WS_ST_TO_ON_NET; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate } else { 730*0Sstevel@tonic-gate ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, NULL); 731*0Sstevel@tonic-gate ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; 732*0Sstevel@tonic-gate rt = rtfind(dst->sin_addr.s_addr); 733*0Sstevel@tonic-gate if (rt != NULL) 734*0Sstevel@tonic-gate ifp = rt->rt_ifp; 735*0Sstevel@tonic-gate else 736*0Sstevel@tonic-gate return; 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate ws.npackets = 0; 740*0Sstevel@tonic-gate if (flash) 741*0Sstevel@tonic-gate ws.state |= WS_ST_FLASH; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate ws.ifp = ifp; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* 746*0Sstevel@tonic-gate * Routes in the table were already adjusted by their respective 747*0Sstevel@tonic-gate * destination interface costs (which are zero by default) on 748*0Sstevel@tonic-gate * input. The following is the value by which each route's metric 749*0Sstevel@tonic-gate * will be bumped up on output. 750*0Sstevel@tonic-gate */ 751*0Sstevel@tonic-gate ws.metric = 1; 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate ripv12_buf.rip.rip_vers = vers; 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate switch (type) { 756*0Sstevel@tonic-gate case OUT_MULTICAST: 757*0Sstevel@tonic-gate if (ifp->int_if_flags & IFF_MULTICAST) 758*0Sstevel@tonic-gate v2buf.type = OUT_MULTICAST; 759*0Sstevel@tonic-gate else 760*0Sstevel@tonic-gate v2buf.type = NO_OUT_MULTICAST; 761*0Sstevel@tonic-gate v12buf.type = OUT_BROADCAST; 762*0Sstevel@tonic-gate break; 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate case OUT_QUERY: 765*0Sstevel@tonic-gate ws.state |= WS_ST_QUERY; 766*0Sstevel@tonic-gate /* FALLTHROUGH */ 767*0Sstevel@tonic-gate case OUT_BROADCAST: 768*0Sstevel@tonic-gate case OUT_UNICAST: 769*0Sstevel@tonic-gate v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; 770*0Sstevel@tonic-gate v12buf.type = type; 771*0Sstevel@tonic-gate break; 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate case NO_OUT_MULTICAST: 774*0Sstevel@tonic-gate case NO_OUT_RIPV2: 775*0Sstevel@tonic-gate return; /* no output */ 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate if (vers == RIPv2) { 779*0Sstevel@tonic-gate /* full RIPv2 only if cannot be heard by RIPv1 listeners */ 780*0Sstevel@tonic-gate if (type != OUT_BROADCAST) 781*0Sstevel@tonic-gate ws.state |= WS_ST_RIP2_ALL; 782*0Sstevel@tonic-gate if ((ws.state & WS_ST_QUERY) || !(ws.state & WS_ST_TO_ON_NET)) { 783*0Sstevel@tonic-gate ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); 784*0Sstevel@tonic-gate } else if (ifp == NULL || !(ifp->int_state & IS_NO_AG)) { 785*0Sstevel@tonic-gate ws.state |= WS_ST_AG; 786*0Sstevel@tonic-gate if (type != OUT_BROADCAST && (ifp == NULL || 787*0Sstevel@tonic-gate !(ifp->int_state & IS_NO_SUPER_AG))) 788*0Sstevel@tonic-gate ws.state |= WS_ST_SUPER_AG; 789*0Sstevel@tonic-gate } 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* See if this packet needs authenticating */ 792*0Sstevel@tonic-gate ws.a = find_auth(ifp); 793*0Sstevel@tonic-gate if (!passwd_ok && ws.a != NULL && ws.a->type == RIP_AUTH_PW) 794*0Sstevel@tonic-gate ws.a = NULL; 795*0Sstevel@tonic-gate if (ws.a != NULL && (ulong_t)ws.a->end < (ulong_t)clk.tv_sec && 796*0Sstevel@tonic-gate !ws.a->warnedflag) { 797*0Sstevel@tonic-gate /* 798*0Sstevel@tonic-gate * If the best key is an expired one, we may as 799*0Sstevel@tonic-gate * well use it. Log this event. 800*0Sstevel@tonic-gate */ 801*0Sstevel@tonic-gate writelog(LOG_WARNING, 802*0Sstevel@tonic-gate "Using expired auth while transmitting to %s", 803*0Sstevel@tonic-gate naddr_ntoa(ws.to.sin_addr.s_addr)); 804*0Sstevel@tonic-gate ws.a->warnedflag = 1; 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate } else { 807*0Sstevel@tonic-gate ws.a = NULL; 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate clr_ws_buf(&v12buf, ws.a); 811*0Sstevel@tonic-gate clr_ws_buf(&v2buf, ws.a); 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate /* 814*0Sstevel@tonic-gate * Fake a default route if asked and if there is not already 815*0Sstevel@tonic-gate * a better, real default route. 816*0Sstevel@tonic-gate */ 817*0Sstevel@tonic-gate if (should_supply(NULL) && (def_metric = ifp->int_d_metric) != 0) { 818*0Sstevel@tonic-gate if (NULL == (rt = rtget(RIP_DEFAULT, 0)) || 819*0Sstevel@tonic-gate rt->rt_metric+ws.metric >= def_metric) { 820*0Sstevel@tonic-gate ws.state |= WS_ST_DEFAULT; 821*0Sstevel@tonic-gate ag_check(0, 0, 0, NULL, 0, def_metric, def_metric, 822*0Sstevel@tonic-gate 0, 0, 0, supply_out); 823*0Sstevel@tonic-gate } else { 824*0Sstevel@tonic-gate def_metric = rt->rt_metric+ws.metric; 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate /* 828*0Sstevel@tonic-gate * If both RIPv2 and the poor-man's router discovery 829*0Sstevel@tonic-gate * kludge are on, arrange to advertise an extra 830*0Sstevel@tonic-gate * default route via RIPv1. 831*0Sstevel@tonic-gate */ 832*0Sstevel@tonic-gate if ((ws.state & WS_ST_RIP2_ALL) && 833*0Sstevel@tonic-gate (ifp->int_state & IS_PM_RDISC)) { 834*0Sstevel@tonic-gate ripv12_buf.rip.rip_vers = RIPv1; 835*0Sstevel@tonic-gate v12buf.n->n_family = RIP_AF_INET; 836*0Sstevel@tonic-gate v12buf.n->n_dst = htonl(RIP_DEFAULT); 837*0Sstevel@tonic-gate v12buf.n->n_metric = htonl(def_metric); 838*0Sstevel@tonic-gate v12buf.n++; 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate (void) rn_walktree(rhead, walk_supply, NULL); 843*0Sstevel@tonic-gate ag_flush(0, 0, supply_out); 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate /* 846*0Sstevel@tonic-gate * Flush the packet buffers, provided they are not empty and 847*0Sstevel@tonic-gate * do not contain only the password. 848*0Sstevel@tonic-gate */ 849*0Sstevel@tonic-gate if (v12buf.n != v12buf.base && 850*0Sstevel@tonic-gate (v12buf.n > v12buf.base+1 || 851*0Sstevel@tonic-gate v12buf.base->n_family != RIP_AF_AUTH)) 852*0Sstevel@tonic-gate supply_write(&v12buf); 853*0Sstevel@tonic-gate if (v2buf.n != v2buf.base && (v2buf.n > v2buf.base+1 || 854*0Sstevel@tonic-gate v2buf.base->n_family != RIP_AF_AUTH)) 855*0Sstevel@tonic-gate supply_write(&v2buf); 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate /* 858*0Sstevel@tonic-gate * If we sent nothing and this is an answer to a query, send 859*0Sstevel@tonic-gate * an empty buffer. 860*0Sstevel@tonic-gate */ 861*0Sstevel@tonic-gate if (ws.npackets == 0 && (ws.state & WS_ST_QUERY)) { 862*0Sstevel@tonic-gate supply_write(&v2buf); 863*0Sstevel@tonic-gate if (ws.npackets == 0) 864*0Sstevel@tonic-gate supply_write(&v12buf); 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate /* 870*0Sstevel@tonic-gate * send all of the routing table or just do a flash update 871*0Sstevel@tonic-gate */ 872*0Sstevel@tonic-gate void 873*0Sstevel@tonic-gate rip_bcast(int flash) 874*0Sstevel@tonic-gate { 875*0Sstevel@tonic-gate static struct sockaddr_in dst = {AF_INET}; 876*0Sstevel@tonic-gate struct interface *ifp; 877*0Sstevel@tonic-gate enum output_type type; 878*0Sstevel@tonic-gate int vers; 879*0Sstevel@tonic-gate struct timeval rtime; 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate need_flash = _B_FALSE; 883*0Sstevel@tonic-gate intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); 884*0Sstevel@tonic-gate no_flash = rtime; 885*0Sstevel@tonic-gate timevaladd(&no_flash, &now); 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate if (!rip_enabled) 888*0Sstevel@tonic-gate return; 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate trace_act("send %s and inhibit dynamic updates for %.3f sec", 891*0Sstevel@tonic-gate flash ? "dynamic update" : "all routes", 892*0Sstevel@tonic-gate rtime.tv_sec + ((double)rtime.tv_usec)/1000000.0); 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 895*0Sstevel@tonic-gate /* 896*0Sstevel@tonic-gate * Skip interfaces not doing RIP or for which IP 897*0Sstevel@tonic-gate * forwarding isn't turned on. Skip duplicate 898*0Sstevel@tonic-gate * interfaces, we don't want to generate duplicate 899*0Sstevel@tonic-gate * packets. Do try broken interfaces to see if they 900*0Sstevel@tonic-gate * have healed. 901*0Sstevel@tonic-gate */ 902*0Sstevel@tonic-gate if (IS_RIP_OUT_OFF(ifp->int_state) || 903*0Sstevel@tonic-gate (ifp->int_state & IS_DUP) || 904*0Sstevel@tonic-gate !IS_IFF_ROUTING(ifp->int_if_flags)) 905*0Sstevel@tonic-gate continue; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate /* skip turned off interfaces */ 908*0Sstevel@tonic-gate if (!IS_IFF_UP(ifp->int_if_flags)) 909*0Sstevel@tonic-gate continue; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate /* skip interfaces we shouldn't use */ 912*0Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) 913*0Sstevel@tonic-gate continue; 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; 916*0Sstevel@tonic-gate dst.sin_addr.s_addr = ifp->int_ripout_addr; 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate /* 919*0Sstevel@tonic-gate * Ignore the interface if it's not broadcast, 920*0Sstevel@tonic-gate * point-to-point, or remote. It must be non-broadcast 921*0Sstevel@tonic-gate * multiaccess, and therefore unsupported. 922*0Sstevel@tonic-gate */ 923*0Sstevel@tonic-gate if (!(ifp->int_if_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) && 924*0Sstevel@tonic-gate !(ifp->int_state & IS_REMOTE)) 925*0Sstevel@tonic-gate continue; 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate type = (ifp->int_if_flags & IFF_BROADCAST) ? 928*0Sstevel@tonic-gate OUT_BROADCAST : OUT_UNICAST; 929*0Sstevel@tonic-gate if (vers == RIPv2 && (ifp->int_if_flags & IFF_MULTICAST) && 930*0Sstevel@tonic-gate !(ifp->int_state & IS_NO_RIP_MCAST)) 931*0Sstevel@tonic-gate type = OUT_MULTICAST; 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate supply(&dst, ifp, type, flash, vers, _B_TRUE); 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate update_seqno++; /* all routes are up to date */ 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate /* 941*0Sstevel@tonic-gate * Ask for routes 942*0Sstevel@tonic-gate * Do it only once to an interface, and not even after the interface 943*0Sstevel@tonic-gate * was broken and recovered. 944*0Sstevel@tonic-gate */ 945*0Sstevel@tonic-gate void 946*0Sstevel@tonic-gate rip_query(void) 947*0Sstevel@tonic-gate { 948*0Sstevel@tonic-gate static struct sockaddr_in dst = {AF_INET}; 949*0Sstevel@tonic-gate struct interface *ifp; 950*0Sstevel@tonic-gate struct rip buf; 951*0Sstevel@tonic-gate enum output_type type; 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate if (!rip_enabled) 955*0Sstevel@tonic-gate return; 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate (void) memset(&buf, 0, sizeof (buf)); 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate for (ifp = ifnet; ifp; ifp = ifp->int_next) { 960*0Sstevel@tonic-gate /* 961*0Sstevel@tonic-gate * Skip interfaces those already queried. Do not ask 962*0Sstevel@tonic-gate * via interfaces through which we don't accept input. 963*0Sstevel@tonic-gate * Do not ask via interfaces that cannot send RIP 964*0Sstevel@tonic-gate * packets. Don't send queries on duplicate 965*0Sstevel@tonic-gate * interfaces, that would generate duplicate packets 966*0Sstevel@tonic-gate * on link. Do try broken interfaces to see if they 967*0Sstevel@tonic-gate * have healed. 968*0Sstevel@tonic-gate */ 969*0Sstevel@tonic-gate if (IS_RIP_IN_OFF(ifp->int_state) || 970*0Sstevel@tonic-gate (ifp->int_state & IS_DUP) || 971*0Sstevel@tonic-gate ifp->int_query_time != NEVER) 972*0Sstevel@tonic-gate continue; 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate /* skip turned off interfaces */ 975*0Sstevel@tonic-gate if (!IS_IFF_UP(ifp->int_if_flags)) 976*0Sstevel@tonic-gate continue; 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate /* skip interfaces we shouldn't use */ 979*0Sstevel@tonic-gate if (IS_IFF_QUIET(ifp->int_if_flags)) 980*0Sstevel@tonic-gate continue; 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate /* 983*0Sstevel@tonic-gate * Ignore the interface if it's not broadcast, 984*0Sstevel@tonic-gate * point-to-point, or remote. It must be non-broadcast 985*0Sstevel@tonic-gate * multiaccess, and therefore unsupported. 986*0Sstevel@tonic-gate */ 987*0Sstevel@tonic-gate if (!(ifp->int_if_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) && 988*0Sstevel@tonic-gate !(ifp->int_state & IS_REMOTE)) 989*0Sstevel@tonic-gate continue; 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate buf.rip_cmd = RIPCMD_REQUEST; 992*0Sstevel@tonic-gate buf.rip_nets[0].n_family = RIP_AF_UNSPEC; 993*0Sstevel@tonic-gate buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate /* 996*0Sstevel@tonic-gate * Send a RIPv1 query only if allowed and if we will 997*0Sstevel@tonic-gate * listen to RIPv1 routers. 998*0Sstevel@tonic-gate */ 999*0Sstevel@tonic-gate if ((ifp->int_state & IS_NO_RIPV1_OUT) || 1000*0Sstevel@tonic-gate (ifp->int_state & IS_NO_RIPV1_IN)) { 1001*0Sstevel@tonic-gate buf.rip_vers = RIPv2; 1002*0Sstevel@tonic-gate } else { 1003*0Sstevel@tonic-gate buf.rip_vers = RIPv1; 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate dst.sin_addr.s_addr = ifp->int_ripout_addr; 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate type = (ifp->int_if_flags & IFF_BROADCAST) ? 1009*0Sstevel@tonic-gate OUT_BROADCAST : OUT_UNICAST; 1010*0Sstevel@tonic-gate if (buf.rip_vers == RIPv2 && 1011*0Sstevel@tonic-gate (ifp->int_if_flags & IFF_MULTICAST) && 1012*0Sstevel@tonic-gate !(ifp->int_state & IS_NO_RIP_MCAST)) 1013*0Sstevel@tonic-gate type = OUT_MULTICAST; 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate ifp->int_query_time = now.tv_sec+SUPPLY_INTERVAL; 1016*0Sstevel@tonic-gate if (output(type, &dst, ifp, &buf, sizeof (buf)) < 0) 1017*0Sstevel@tonic-gate if_sick(ifp, _B_FALSE); 1018*0Sstevel@tonic-gate } 1019*0Sstevel@tonic-gate } 1020