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.21 (Berkeley) 08/21/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 = ntohs(n->rip_dst.sa_family); 74 #else 75 #define osa(x) ((struct osockaddr *)(&(x))) 76 n->rip_dst.sa_family = 77 ntohs(osa(n->rip_dst)->sa_family); 78 n->rip_dst.sa_len = sizeof(n->rip_dst); 79 #endif 80 n->rip_metric = ntohl(n->rip_metric); 81 /* 82 * A single entry with sa_family == AF_UNSPEC and 83 * metric ``infinity'' means ``all routes''. 84 * We respond to routers only if we are acting 85 * as a supplier, or to anyone other than a router 86 * (eg, query). 87 */ 88 if (n->rip_dst.sa_family == AF_UNSPEC && 89 n->rip_metric == HOPCNT_INFINITY && count == 0) { 90 if (supplier || (*afp->af_portmatch)(from) == 0) 91 supply(from, 0, 0, 0); 92 return; 93 } 94 if (n->rip_dst.sa_family < af_max && 95 afswitch[n->rip_dst.sa_family].af_hash) 96 rt = rtlookup(&n->rip_dst); 97 else 98 rt = 0; 99 #define min(a, b) (a < b ? a : b) 100 n->rip_metric = rt == 0 ? HOPCNT_INFINITY : 101 min(rt->rt_metric + 1, HOPCNT_INFINITY); 102 #if BSD < 198810 103 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ 104 n->rip_dst.sa_family = htons(n->rip_dst.sa_family); 105 #else 106 osa(n->rip_dst)->sa_family = 107 htons(n->rip_dst.sa_family); 108 #endif 109 n->rip_metric = htonl(n->rip_metric); 110 } 111 rip->rip_cmd = RIPCMD_RESPONSE; 112 bcopy((char *)rip, packet, size); 113 (*afp->af_output)(s, 0, from, size); 114 return; 115 116 case RIPCMD_TRACEON: 117 case RIPCMD_TRACEOFF: 118 /* verify message came from a privileged port */ 119 if ((*afp->af_portcheck)(from) == 0) 120 return; 121 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & 122 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || 123 ifp->int_flags & IFF_PASSIVE) { 124 syslog(LOG_ERR, "trace command from unknown router, %s", 125 (*afswitch[from->sa_family].af_format)(from)); 126 return; 127 } 128 ((char *)rip)[size] = '\0'; 129 if (rip->rip_cmd == RIPCMD_TRACEON) 130 traceon(rip->rip_tracefile); 131 else 132 traceoff(); 133 return; 134 135 case RIPCMD_RESPONSE: 136 /* verify message came from a router */ 137 if ((*afp->af_portmatch)(from) == 0) 138 return; 139 (*afp->af_canon)(from); 140 /* are we talking to ourselves? */ 141 ifp = if_ifwithaddr(from); 142 if (ifp) { 143 if (ifp->int_flags & IFF_PASSIVE) { 144 syslog(LOG_ERR, 145 "bogus input (from passive interface, %s)", 146 (*afswitch[from->sa_family].af_format)(from)); 147 return; 148 } 149 rt = rtfind(from); 150 if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) && 151 rt->rt_metric >= ifp->int_metric) 152 addrouteforif(ifp); 153 else 154 rt->rt_timer = 0; 155 return; 156 } 157 /* 158 * Update timer for interface on which the packet arrived. 159 * If from other end of a point-to-point link that isn't 160 * in the routing tables, (re-)add the route. 161 */ 162 if ((rt = rtfind(from)) && 163 (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) 164 rt->rt_timer = 0; 165 else if ((ifp = if_ifwithdstaddr(from)) && 166 (rt == 0 || rt->rt_metric >= ifp->int_metric)) 167 addrouteforif(ifp); 168 /* 169 * "Authenticate" router from which message originated. 170 * We accept routing packets from routers directly connected 171 * via broadcast or point-to-point networks, 172 * and from those listed in /etc/gateways. 173 */ 174 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & 175 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || 176 ifp->int_flags & IFF_PASSIVE) { 177 if (bcmp((char *)from, (char *)&badfrom, 178 sizeof(badfrom)) != 0) { 179 syslog(LOG_ERR, 180 "packet from unknown router, %s", 181 (*afswitch[from->sa_family].af_format)(from)); 182 badfrom = *from; 183 } 184 return; 185 } 186 size -= 4 * sizeof (char); 187 n = rip->rip_nets; 188 for (; size > 0; size -= sizeof (struct netinfo), n++) { 189 if (size < sizeof (struct netinfo)) 190 break; 191 #if BSD < 198810 192 if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ 193 n->rip_dst.sa_family = 194 ntohs(n->rip_dst.sa_family); 195 #else 196 n->rip_dst.sa_family = 197 ntohs(osa(n->rip_dst)->sa_family); 198 n->rip_dst.sa_len = sizeof(n->rip_dst); 199 #endif 200 n->rip_metric = ntohl(n->rip_metric); 201 if (n->rip_dst.sa_family >= af_max || 202 (afp = &afswitch[n->rip_dst.sa_family])->af_hash == 203 (int (*)())0) { 204 syslog(LOG_INFO, 205 "route in unsupported address family (%d), from %s (af %d)\n", 206 n->rip_dst.sa_family, 207 (*afswitch[from->sa_family].af_format)(from), 208 from->sa_family); 209 continue; 210 } 211 if (((*afp->af_checkhost)(&n->rip_dst)) == 0) { 212 syslog(LOG_DEBUG, 213 "bad host in route from %s (af %d)\n", 214 (*afswitch[from->sa_family].af_format)(from), 215 from->sa_family); 216 continue; 217 } 218 if (n->rip_metric == 0 || 219 (unsigned) n->rip_metric > HOPCNT_INFINITY) { 220 if (bcmp((char *)from, (char *)&badfrom2, 221 sizeof(badfrom2)) != 0) { 222 syslog(LOG_ERR, 223 "bad metric (%d) from %s\n", 224 n->rip_metric, 225 (*afswitch[from->sa_family].af_format)(from)); 226 badfrom2 = *from; 227 } 228 continue; 229 } 230 /* 231 * Adjust metric according to incoming interface. 232 */ 233 if ((unsigned) n->rip_metric < HOPCNT_INFINITY) 234 n->rip_metric += ifp->int_metric; 235 if ((unsigned) n->rip_metric > HOPCNT_INFINITY) 236 n->rip_metric = HOPCNT_INFINITY; 237 rt = rtlookup(&n->rip_dst); 238 if (rt == 0 || 239 (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == 240 (RTS_INTERNAL|RTS_INTERFACE)) { 241 /* 242 * If we're hearing a logical network route 243 * back from a peer to which we sent it, 244 * ignore it. 245 */ 246 if (rt && rt->rt_state & RTS_SUBNET && 247 (*afp->af_sendroute)(rt, from)) 248 continue; 249 if ((unsigned)n->rip_metric < HOPCNT_INFINITY) { 250 /* 251 * Look for an equivalent route that 252 * includes this one before adding 253 * this route. 254 */ 255 rt = rtfind(&n->rip_dst); 256 if (rt && equal(from, &rt->rt_router)) 257 continue; 258 rtadd(&n->rip_dst, from, n->rip_metric, 0); 259 changes++; 260 } 261 continue; 262 } 263 264 /* 265 * Update if from gateway and different, 266 * shorter, or equivalent but old route 267 * is getting stale. 268 */ 269 if (equal(from, &rt->rt_router)) { 270 if (n->rip_metric != rt->rt_metric) { 271 rtchange(rt, from, n->rip_metric); 272 changes++; 273 rt->rt_timer = 0; 274 if (rt->rt_metric >= HOPCNT_INFINITY) 275 rt->rt_timer = 276 GARBAGE_TIME - EXPIRE_TIME; 277 } else if (rt->rt_metric < HOPCNT_INFINITY) 278 rt->rt_timer = 0; 279 } else if ((unsigned) n->rip_metric < rt->rt_metric || 280 (rt->rt_metric == n->rip_metric && 281 rt->rt_timer > (EXPIRE_TIME/2) && 282 (unsigned) n->rip_metric < HOPCNT_INFINITY)) { 283 rtchange(rt, from, n->rip_metric); 284 changes++; 285 rt->rt_timer = 0; 286 } 287 } 288 break; 289 } 290 291 /* 292 * If changes have occurred, and if we have not sent a broadcast 293 * recently, send a dynamic update. This update is sent only 294 * on interfaces other than the one on which we received notice 295 * of the change. If we are within MIN_WAITTIME of a full update, 296 * don't bother sending; if we just sent a dynamic update 297 * and set a timer (nextbcast), delay until that time. 298 * If we just sent a full update, delay the dynamic update. 299 * Set a timer for a randomized value to suppress additional 300 * dynamic updates until it expires; if we delayed sending 301 * the current changes, set needupdate. 302 */ 303 if (changes && supplier && 304 now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) { 305 u_long delay; 306 extern long random(); 307 308 if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME && 309 timercmp(&nextbcast, &now, <)) { 310 if (traceactions) 311 fprintf(ftrace, "send dynamic update\n"); 312 toall(supply, RTS_CHANGED, ifp); 313 lastbcast = now; 314 needupdate = 0; 315 nextbcast.tv_sec = 0; 316 } else { 317 needupdate++; 318 if (traceactions) 319 fprintf(ftrace, "delay dynamic update\n"); 320 } 321 #define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \ 322 (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000)) 323 324 if (nextbcast.tv_sec == 0) { 325 delay = RANDOMDELAY(); 326 if (traceactions) 327 fprintf(ftrace, 328 "inhibit dynamic update for %d usec\n", 329 delay); 330 nextbcast.tv_sec = delay / 1000000; 331 nextbcast.tv_usec = delay % 1000000; 332 timevaladd(&nextbcast, &now); 333 /* 334 * If the next possibly dynamic update 335 * is within MIN_WAITTIME of the next full update, 336 * force the delay past the full update, 337 * or we might send a dynamic update just before 338 * the full update. 339 */ 340 if (nextbcast.tv_sec > lastfullupdate.tv_sec + 341 SUPPLY_INTERVAL - MIN_WAITTIME) 342 nextbcast.tv_sec = lastfullupdate.tv_sec + 343 SUPPLY_INTERVAL + 1; 344 } 345 } 346 } 347