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