1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)input.c 5.20 (Berkeley) 02/20/89"; 20 #endif /* not lint */ 21 22 /* 23 * Routing Table Management Daemon 24 */ 25 #include "defs.h" 26 #include <sys/syslog.h> 27 28 /* 29 * Process a newly received packet. 30 */ 31 rip_input(from, rip, size) 32 struct sockaddr *from; 33 register struct rip *rip; 34 int size; 35 { 36 register struct rt_entry *rt; 37 register struct netinfo *n; 38 register struct interface *ifp; 39 struct interface *if_ifwithdstaddr(); 40 int count, changes = 0; 41 register struct afswitch *afp; 42 static struct sockaddr badfrom, badfrom2; 43 44 ifp = 0; 45 TRACE_INPUT(ifp, from, (char *)rip, size); 46 if (from->sa_family >= af_max || 47 (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) { 48 syslog(LOG_INFO, 49 "\"from\" address in unsupported address family (%d), cmd %d\n", 50 from->sa_family, rip->rip_cmd); 51 return; 52 } 53 if (rip->rip_vers == 0) { 54 syslog(LOG_ERR, 55 "RIP version 0 packet received from %s! (cmd %d)", 56 (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd); 57 return; 58 } 59 switch (rip->rip_cmd) { 60 61 case RIPCMD_REQUEST: 62 n = rip->rip_nets; 63 count = size - ((char *)n - (char *)rip); 64 if (count < sizeof (struct netinfo)) 65 return; 66 for (; count > 0; n++) { 67 if (count < sizeof (struct netinfo)) 68 break; 69 count -= sizeof (struct netinfo); 70 71 #if BSD < 198810 72 if (sizeof(n->rip_dst.sa_family) > 1)/* XXX */ 73 n->rip_dst.sa_family = 74 ntohs(n->rip_dst.sa_family); 75 #endif 76 n->rip_metric = ntohl(n->rip_metric); 77 /* 78 * A single entry with sa_family == AF_UNSPEC and 79 * metric ``infinity'' means ``all routes''. 80 * We respond to routers only if we are acting 81 * as a supplier, or to anyone other than a router 82 * (eg, query). 83 */ 84 if (n->rip_dst.sa_family == AF_UNSPEC && 85 n->rip_metric == HOPCNT_INFINITY && count == 0) { 86 if (supplier || (*afp->af_portmatch)(from) == 0) 87 supply(from, 0, 0, 0); 88 return; 89 } 90 if (n->rip_dst.sa_family < af_max && 91 afswitch[n->rip_dst.sa_family].af_hash) 92 rt = rtlookup(&n->rip_dst); 93 else 94 rt = 0; 95 n->rip_metric = rt == 0 ? HOPCNT_INFINITY : 96 min(rt->rt_metric + 1, HOPCNT_INFINITY); 97 #if BSD < 198810 98 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ 99 n->rip_dst.sa_family = htons(n->rip_dst.sa_family); 100 #endif 101 n->rip_metric = htonl(n->rip_metric); 102 } 103 rip->rip_cmd = RIPCMD_RESPONSE; 104 bcopy((char *)rip, packet, size); 105 (*afp->af_output)(s, 0, from, size); 106 return; 107 108 case RIPCMD_TRACEON: 109 case RIPCMD_TRACEOFF: 110 /* verify message came from a privileged port */ 111 if ((*afp->af_portcheck)(from) == 0) 112 return; 113 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & 114 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || 115 ifp->int_flags & IFF_PASSIVE) { 116 syslog(LOG_ERR, "trace command from unknown router, %s", 117 (*afswitch[from->sa_family].af_format)(from)); 118 return; 119 } 120 ((char *)rip)[size] = '\0'; 121 if (rip->rip_cmd == RIPCMD_TRACEON) 122 traceon(rip->rip_tracefile); 123 else 124 traceoff(); 125 return; 126 127 case RIPCMD_RESPONSE: 128 /* verify message came from a router */ 129 if ((*afp->af_portmatch)(from) == 0) 130 return; 131 (*afp->af_canon)(from); 132 /* are we talking to ourselves? */ 133 ifp = if_ifwithaddr(from); 134 if (ifp) { 135 if (ifp->int_flags & IFF_PASSIVE) { 136 syslog(LOG_ERR, 137 "bogus input (from passive interface, %s)", 138 (*afswitch[from->sa_family].af_format)(from)); 139 return; 140 } 141 rt = rtfind(from); 142 if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) && 143 rt->rt_metric >= ifp->int_metric) 144 addrouteforif(ifp); 145 else 146 rt->rt_timer = 0; 147 return; 148 } 149 /* 150 * Update timer for interface on which the packet arrived. 151 * If from other end of a point-to-point link that isn't 152 * in the routing tables, (re-)add the route. 153 */ 154 if ((rt = rtfind(from)) && 155 (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) 156 rt->rt_timer = 0; 157 else if ((ifp = if_ifwithdstaddr(from)) && 158 (rt == 0 || rt->rt_metric >= ifp->int_metric)) 159 addrouteforif(ifp); 160 /* 161 * "Authenticate" router from which message originated. 162 * We accept routing packets from routers directly connected 163 * via broadcast or point-to-point networks, 164 * and from those listed in /etc/gateways. 165 */ 166 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & 167 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || 168 ifp->int_flags & IFF_PASSIVE) { 169 if (bcmp((char *)from, (char *)&badfrom, 170 sizeof(badfrom)) != 0) { 171 syslog(LOG_ERR, 172 "packet from unknown router, %s", 173 (*afswitch[from->sa_family].af_format)(from)); 174 badfrom = *from; 175 } 176 return; 177 } 178 size -= 4 * sizeof (char); 179 n = rip->rip_nets; 180 for (; size > 0; size -= sizeof (struct netinfo), n++) { 181 if (size < sizeof (struct netinfo)) 182 break; 183 #if BSD < 198810 184 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ 185 n->rip_dst.sa_family = 186 ntohs(n->rip_dst.sa_family); 187 #endif 188 n->rip_metric = ntohl(n->rip_metric); 189 if (n->rip_dst.sa_family >= af_max || 190 (afp = &afswitch[n->rip_dst.sa_family])->af_hash == 191 (int (*)())0) { 192 syslog(LOG_INFO, 193 "route in unsupported address family (%d), from %s (af %d)\n", 194 n->rip_dst.sa_family, 195 (*afswitch[from->sa_family].af_format)(from), 196 from->sa_family); 197 continue; 198 } 199 if (((*afp->af_checkhost)(&n->rip_dst)) == 0) { 200 syslog(LOG_DEBUG, 201 "bad host in route from %s (af %d)\n", 202 (*afswitch[from->sa_family].af_format)(from), 203 from->sa_family); 204 continue; 205 } 206 if (n->rip_metric == 0 || 207 (unsigned) n->rip_metric > HOPCNT_INFINITY) { 208 if (bcmp((char *)from, (char *)&badfrom2, 209 sizeof(badfrom2)) != 0) { 210 syslog(LOG_ERR, 211 "bad metric (%d) from %s\n", 212 n->rip_metric, 213 (*afswitch[from->sa_family].af_format)(from)); 214 badfrom2 = *from; 215 } 216 continue; 217 } 218 /* 219 * Adjust metric according to incoming interface. 220 */ 221 if ((unsigned) n->rip_metric < HOPCNT_INFINITY) 222 n->rip_metric += ifp->int_metric; 223 if ((unsigned) n->rip_metric > HOPCNT_INFINITY) 224 n->rip_metric = HOPCNT_INFINITY; 225 rt = rtlookup(&n->rip_dst); 226 if (rt == 0 || 227 (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == 228 (RTS_INTERNAL|RTS_INTERFACE)) { 229 /* 230 * If we're hearing a logical network route 231 * back from a peer to which we sent it, 232 * ignore it. 233 */ 234 if (rt && rt->rt_state & RTS_SUBNET && 235 (*afp->af_sendroute)(rt, from)) 236 continue; 237 if ((unsigned)n->rip_metric < HOPCNT_INFINITY) { 238 /* 239 * Look for an equivalent route that 240 * includes this one before adding 241 * this route. 242 */ 243 rt = rtfind(&n->rip_dst); 244 if (rt && equal(from, &rt->rt_router)) 245 continue; 246 rtadd(&n->rip_dst, from, n->rip_metric, 0); 247 changes++; 248 } 249 continue; 250 } 251 252 /* 253 * Update if from gateway and different, 254 * shorter, or equivalent but old route 255 * is getting stale. 256 */ 257 if (equal(from, &rt->rt_router)) { 258 if (n->rip_metric != rt->rt_metric) { 259 rtchange(rt, from, n->rip_metric); 260 changes++; 261 rt->rt_timer = 0; 262 if (rt->rt_metric >= HOPCNT_INFINITY) 263 rt->rt_timer = 264 GARBAGE_TIME - EXPIRE_TIME; 265 } else if (rt->rt_metric < HOPCNT_INFINITY) 266 rt->rt_timer = 0; 267 } else if ((unsigned) n->rip_metric < rt->rt_metric || 268 (rt->rt_metric == n->rip_metric && 269 rt->rt_timer > (EXPIRE_TIME/2) && 270 (unsigned) n->rip_metric < HOPCNT_INFINITY)) { 271 rtchange(rt, from, n->rip_metric); 272 changes++; 273 rt->rt_timer = 0; 274 } 275 } 276 break; 277 } 278 279 /* 280 * If changes have occurred, and if we have not sent a broadcast 281 * recently, send a dynamic update. This update is sent only 282 * on interfaces other than the one on which we received notice 283 * of the change. If we are within MIN_WAITTIME of a full update, 284 * don't bother sending; if we just sent a dynamic update 285 * and set a timer (nextbcast), delay until that time. 286 * If we just sent a full update, delay the dynamic update. 287 * Set a timer for a randomized value to suppress additional 288 * dynamic updates until it expires; if we delayed sending 289 * the current changes, set needupdate. 290 */ 291 if (changes && supplier && 292 now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) { 293 u_long delay; 294 extern long random(); 295 296 if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME && 297 timercmp(&nextbcast, &now, <)) { 298 if (traceactions) 299 fprintf(ftrace, "send dynamic update\n"); 300 toall(supply, RTS_CHANGED, ifp); 301 lastbcast = now; 302 needupdate = 0; 303 nextbcast.tv_sec = 0; 304 } else { 305 needupdate++; 306 if (traceactions) 307 fprintf(ftrace, "delay dynamic update\n"); 308 } 309 #define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \ 310 (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000)) 311 312 if (nextbcast.tv_sec == 0) { 313 delay = RANDOMDELAY(); 314 if (traceactions) 315 fprintf(ftrace, 316 "inhibit dynamic update for %d usec\n", 317 delay); 318 nextbcast.tv_sec = delay / 1000000; 319 nextbcast.tv_usec = delay % 1000000; 320 timevaladd(&nextbcast, &now); 321 /* 322 * If the next possibly dynamic update 323 * is within MIN_WAITTIME of the next full update, 324 * force the delay past the full update, 325 * or we might send a dynamic update just before 326 * the full update. 327 */ 328 if (nextbcast.tv_sec > lastfullupdate.tv_sec + 329 SUPPLY_INTERVAL - MIN_WAITTIME) 330 nextbcast.tv_sec = lastfullupdate.tv_sec + 331 SUPPLY_INTERVAL + 1; 332 } 333 } 334 } 335