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.18 (Berkeley) 06/18/88"; 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, size) 32 struct sockaddr *from; 33 int size; 34 { 35 register struct rt_entry *rt; 36 register struct netinfo *n; 37 register struct interface *ifp; 38 struct interface *if_ifwithdstaddr(); 39 int newsize; 40 register struct afswitch *afp; 41 static struct sockaddr badfrom, badfrom2; 42 43 ifp = 0; 44 TRACE_INPUT(ifp, from, size); 45 if (from->sa_family >= af_max || 46 (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) { 47 syslog(LOG_INFO, 48 "\"from\" address in unsupported address family (%d), cmd %d\n", 49 from->sa_family, msg->rip_cmd); 50 return; 51 } 52 switch (msg->rip_cmd) { 53 54 case RIPCMD_REQUEST: 55 newsize = 0; 56 size -= 4 * sizeof (char); 57 n = msg->rip_nets; 58 while (size > 0) { 59 if (size < sizeof (struct netinfo)) 60 break; 61 size -= sizeof (struct netinfo); 62 63 if (msg->rip_vers > 0) { 64 n->rip_dst.sa_family = 65 ntohs(n->rip_dst.sa_family); 66 n->rip_metric = ntohl(n->rip_metric); 67 } 68 /* 69 * A single entry with sa_family == AF_UNSPEC and 70 * metric ``infinity'' means ``all routes''. 71 * We respond to routers only if we are acting 72 * as a supplier, or to anyone other than a router 73 * (eg, query). 74 */ 75 if (n->rip_dst.sa_family == AF_UNSPEC && 76 n->rip_metric == HOPCNT_INFINITY && size == 0) { 77 if (supplier || (*afp->af_portmatch)(from) == 0) 78 supply(from, 0, 0); 79 return; 80 } 81 if (n->rip_dst.sa_family < af_max && 82 afswitch[n->rip_dst.sa_family].af_hash) 83 rt = rtlookup(&n->rip_dst); 84 else 85 rt = 0; 86 n->rip_metric = rt == 0 ? HOPCNT_INFINITY : 87 min(rt->rt_metric + 1, HOPCNT_INFINITY); 88 if (msg->rip_vers > 0) { 89 n->rip_dst.sa_family = 90 htons(n->rip_dst.sa_family); 91 n->rip_metric = htonl(n->rip_metric); 92 } 93 n++, newsize += sizeof (struct netinfo); 94 } 95 if (newsize > 0) { 96 msg->rip_cmd = RIPCMD_RESPONSE; 97 newsize += sizeof (int); 98 (*afp->af_output)(s, 0, from, newsize); 99 } 100 return; 101 102 case RIPCMD_TRACEON: 103 case RIPCMD_TRACEOFF: 104 /* verify message came from a privileged port */ 105 if ((*afp->af_portcheck)(from) == 0) 106 return; 107 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & 108 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || 109 ifp->int_flags & IFF_PASSIVE) { 110 syslog(LOG_ERR, "trace command from unknown router, %s", 111 (*afswitch[from->sa_family].af_format)(from)); 112 return; 113 } 114 packet[size] = '\0'; 115 if (msg->rip_cmd == RIPCMD_TRACEON) 116 traceon(msg->rip_tracefile); 117 else 118 traceoff(); 119 return; 120 121 case RIPCMD_RESPONSE: 122 /* verify message came from a router */ 123 if ((*afp->af_portmatch)(from) == 0) 124 return; 125 (*afp->af_canon)(from); 126 /* are we talking to ourselves? */ 127 ifp = if_ifwithaddr(from); 128 if (ifp) { 129 if (ifp->int_flags & IFF_PASSIVE) { 130 syslog(LOG_ERR, 131 "bogus input (from passive interface, %s)", 132 (*afswitch[from->sa_family].af_format)(from)); 133 return; 134 } 135 rt = rtfind(from); 136 if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) && 137 rt->rt_metric >= ifp->int_metric) 138 addrouteforif(ifp); 139 else 140 rt->rt_timer = 0; 141 return; 142 } 143 /* 144 * Update timer for interface on which the packet arrived. 145 * If from other end of a point-to-point link that isn't 146 * in the routing tables, (re-)add the route. 147 */ 148 if ((rt = rtfind(from)) && 149 (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) 150 rt->rt_timer = 0; 151 else if ((ifp = if_ifwithdstaddr(from)) && 152 (rt == 0 || rt->rt_metric >= ifp->int_metric)) 153 addrouteforif(ifp); 154 /* 155 * "Authenticate" router from which message originated. 156 * We accept routing packets from routers directly connected 157 * via broadcast or point-to-point networks, 158 * and from those listed in /etc/gateways. 159 */ 160 if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & 161 (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || 162 ifp->int_flags & IFF_PASSIVE) { 163 if (bcmp((char *)from, (char *)&badfrom, 164 sizeof(badfrom)) != 0) { 165 syslog(LOG_ERR, 166 "packet from unknown router, %s", 167 (*afswitch[from->sa_family].af_format)(from)); 168 badfrom = *from; 169 } 170 return; 171 } 172 size -= 4 * sizeof (char); 173 n = msg->rip_nets; 174 for (; size > 0; size -= sizeof (struct netinfo), n++) { 175 if (size < sizeof (struct netinfo)) 176 break; 177 if (msg->rip_vers > 0) { 178 n->rip_dst.sa_family = 179 ntohs(n->rip_dst.sa_family); 180 n->rip_metric = ntohl(n->rip_metric); 181 } 182 if (n->rip_dst.sa_family >= af_max || 183 (afp = &afswitch[n->rip_dst.sa_family])->af_hash == 184 (int (*)())0) { 185 syslog(LOG_INFO, 186 "route in unsupported address family (%d), from %s (af %d)\n", 187 n->rip_dst.sa_family, 188 (*afswitch[from->sa_family].af_format)(from), 189 from->sa_family); 190 continue; 191 } 192 if (((*afp->af_checkhost)(&n->rip_dst)) == 0) { 193 syslog(LOG_DEBUG, 194 "bad host in route from %s (af %d)\n", 195 (*afswitch[from->sa_family].af_format)(from), 196 from->sa_family); 197 continue; 198 } 199 if (n->rip_metric == 0 || 200 (unsigned) n->rip_metric > HOPCNT_INFINITY) { 201 if (bcmp((char *)from, (char *)&badfrom2, 202 sizeof(badfrom2)) != 0) { 203 syslog(LOG_ERR, 204 "bad metric (%d) from %s\n", 205 n->rip_metric, 206 (*afswitch[from->sa_family].af_format)(from)); 207 badfrom2 = *from; 208 } 209 continue; 210 } 211 /* 212 * Adjust metric according to incoming interface. 213 */ 214 if ((unsigned) n->rip_metric < HOPCNT_INFINITY) 215 n->rip_metric += ifp->int_metric; 216 if ((unsigned) n->rip_metric > HOPCNT_INFINITY) 217 n->rip_metric = HOPCNT_INFINITY; 218 rt = rtlookup(&n->rip_dst); 219 if (rt == 0 || 220 (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == 221 (RTS_INTERNAL|RTS_INTERFACE)) { 222 /* 223 * If we're hearing a logical network route 224 * back from a peer to which we sent it, 225 * ignore it. 226 */ 227 if (rt && rt->rt_state & RTS_SUBNET && 228 (*afp->af_sendroute)(rt, from)) 229 continue; 230 if ((unsigned)n->rip_metric < HOPCNT_INFINITY) { 231 /* 232 * Look for an equivalent route that 233 * includes this one before adding 234 * this route. 235 */ 236 rt = rtfind(&n->rip_dst); 237 if (rt && equal(from, &rt->rt_router)) 238 continue; 239 rtadd(&n->rip_dst, from, n->rip_metric, 0); 240 } 241 continue; 242 } 243 244 /* 245 * Update if from gateway and different, 246 * shorter, or equivalent but old route 247 * is getting stale. 248 */ 249 if (equal(from, &rt->rt_router)) { 250 if (n->rip_metric != rt->rt_metric) { 251 rtchange(rt, from, n->rip_metric); 252 rt->rt_timer = 0; 253 if (rt->rt_metric >= HOPCNT_INFINITY) 254 rt->rt_timer = 255 GARBAGE_TIME - EXPIRE_TIME; 256 } else if (rt->rt_metric < HOPCNT_INFINITY) 257 rt->rt_timer = 0; 258 } else if ((unsigned) n->rip_metric < rt->rt_metric || 259 (rt->rt_metric == n->rip_metric && 260 rt->rt_timer > (EXPIRE_TIME/2) && 261 (unsigned) n->rip_metric < HOPCNT_INFINITY)) { 262 rtchange(rt, from, n->rip_metric); 263 rt->rt_timer = 0; 264 } 265 } 266 return; 267 } 268 } 269