Commit | Line | Data |
---|---|---|
5ff67f98 | 1 | /* |
0f7c421b | 2 | * Copyright (c) 1983, 1988 Regents of the University of California. |
0eb85d71 KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
b8c620d6 KB |
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. | |
5ff67f98 DF |
16 | */ |
17 | ||
2e74322d | 18 | #ifndef lint |
787d3210 | 19 | static char sccsid[] = "@(#)input.c 5.20 (Berkeley) %G%"; |
0eb85d71 | 20 | #endif /* not lint */ |
2e74322d SL |
21 | |
22 | /* | |
23 | * Routing Table Management Daemon | |
24 | */ | |
7fe7fe74 | 25 | #include "defs.h" |
17fe297f | 26 | #include <sys/syslog.h> |
2e74322d SL |
27 | |
28 | /* | |
29 | * Process a newly received packet. | |
30 | */ | |
787d3210 | 31 | rip_input(from, rip, size) |
2e74322d | 32 | struct sockaddr *from; |
787d3210 | 33 | register struct rip *rip; |
2e74322d SL |
34 | int size; |
35 | { | |
20df59f1 MK |
36 | register struct rt_entry *rt; |
37 | register struct netinfo *n; | |
38 | register struct interface *ifp; | |
39 | struct interface *if_ifwithdstaddr(); | |
4033c8f6 | 40 | int count, changes = 0; |
20df59f1 | 41 | register struct afswitch *afp; |
09b9aef2 | 42 | static struct sockaddr badfrom, badfrom2; |
2e74322d SL |
43 | |
44 | ifp = 0; | |
787d3210 | 45 | TRACE_INPUT(ifp, from, (char *)rip, size); |
17fe297f MK |
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", | |
787d3210 | 50 | from->sa_family, rip->rip_cmd); |
2e74322d | 51 | return; |
17fe297f | 52 | } |
787d3210 | 53 | if (rip->rip_vers == 0) { |
4033c8f6 MK |
54 | syslog(LOG_ERR, |
55 | "RIP version 0 packet received from %s! (cmd %d)", | |
787d3210 | 56 | (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd); |
4033c8f6 MK |
57 | return; |
58 | } | |
787d3210 | 59 | switch (rip->rip_cmd) { |
2e74322d SL |
60 | |
61 | case RIPCMD_REQUEST: | |
787d3210 MK |
62 | n = rip->rip_nets; |
63 | count = size - ((char *)n - (char *)rip); | |
4033c8f6 MK |
64 | if (count < sizeof (struct netinfo)) |
65 | return; | |
66 | for (; count > 0; n++) { | |
67 | if (count < sizeof (struct netinfo)) | |
2e74322d | 68 | break; |
4033c8f6 | 69 | count -= sizeof (struct netinfo); |
2e74322d | 70 | |
4033c8f6 MK |
71 | #if BSD < 198810 |
72 | if (sizeof(n->rip_dst.sa_family) > 1)/* XXX */ | |
55d340a4 SL |
73 | n->rip_dst.sa_family = |
74 | ntohs(n->rip_dst.sa_family); | |
4033c8f6 MK |
75 | #endif |
76 | n->rip_metric = ntohl(n->rip_metric); | |
2e74322d SL |
77 | /* |
78 | * A single entry with sa_family == AF_UNSPEC and | |
79 | * metric ``infinity'' means ``all routes''. | |
17fe297f MK |
80 | * We respond to routers only if we are acting |
81 | * as a supplier, or to anyone other than a router | |
82 | * (eg, query). | |
2e74322d SL |
83 | */ |
84 | if (n->rip_dst.sa_family == AF_UNSPEC && | |
4033c8f6 | 85 | n->rip_metric == HOPCNT_INFINITY && count == 0) { |
17deb420 | 86 | if (supplier || (*afp->af_portmatch)(from) == 0) |
4033c8f6 | 87 | supply(from, 0, 0, 0); |
2e74322d SL |
88 | return; |
89 | } | |
17deb420 MK |
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; | |
2e74322d | 95 | n->rip_metric = rt == 0 ? HOPCNT_INFINITY : |
cdf21aa5 | 96 | min(rt->rt_metric + 1, HOPCNT_INFINITY); |
4033c8f6 MK |
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); | |
2e74322d | 102 | } |
787d3210 MK |
103 | rip->rip_cmd = RIPCMD_RESPONSE; |
104 | bcopy((char *)rip, packet, size); | |
4033c8f6 | 105 | (*afp->af_output)(s, 0, from, size); |
2e74322d SL |
106 | return; |
107 | ||
108 | case RIPCMD_TRACEON: | |
109 | case RIPCMD_TRACEOFF: | |
b7e4f8be | 110 | /* verify message came from a privileged port */ |
2e74322d SL |
111 | if ((*afp->af_portcheck)(from) == 0) |
112 | return; | |
71786f50 | 113 | if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & |
98a1809a MK |
114 | (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || |
115 | ifp->int_flags & IFF_PASSIVE) { | |
09069ad0 | 116 | syslog(LOG_ERR, "trace command from unknown router, %s", |
eb39c032 | 117 | (*afswitch[from->sa_family].af_format)(from)); |
09069ad0 MK |
118 | return; |
119 | } | |
787d3210 MK |
120 | ((char *)rip)[size] = '\0'; |
121 | if (rip->rip_cmd == RIPCMD_TRACEON) | |
122 | traceon(rip->rip_tracefile); | |
2e74322d SL |
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) { | |
0f7c421b MK |
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 | } | |
2e74322d | 141 | rt = rtfind(from); |
7892134c MK |
142 | if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) && |
143 | rt->rt_metric >= ifp->int_metric) | |
2e74322d SL |
144 | addrouteforif(ifp); |
145 | else | |
146 | rt->rt_timer = 0; | |
147 | return; | |
148 | } | |
f1e15e15 MK |
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 | */ | |
09069ad0 MK |
154 | if ((rt = rtfind(from)) && |
155 | (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) | |
b7e4f8be | 156 | rt->rt_timer = 0; |
7892134c MK |
157 | else if ((ifp = if_ifwithdstaddr(from)) && |
158 | (rt == 0 || rt->rt_metric >= ifp->int_metric)) | |
f1e15e15 | 159 | addrouteforif(ifp); |
71786f50 MK |
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 & | |
98a1809a MK |
167 | (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || |
168 | ifp->int_flags & IFF_PASSIVE) { | |
eb39c032 MK |
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 | } | |
09069ad0 MK |
176 | return; |
177 | } | |
2e74322d | 178 | size -= 4 * sizeof (char); |
787d3210 | 179 | n = rip->rip_nets; |
2e74322d SL |
180 | for (; size > 0; size -= sizeof (struct netinfo), n++) { |
181 | if (size < sizeof (struct netinfo)) | |
182 | break; | |
4033c8f6 MK |
183 | #if BSD < 198810 |
184 | if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ | |
55d340a4 SL |
185 | n->rip_dst.sa_family = |
186 | ntohs(n->rip_dst.sa_family); | |
4033c8f6 MK |
187 | #endif |
188 | n->rip_metric = ntohl(n->rip_metric); | |
17fe297f MK |
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); | |
ed36994a | 197 | continue; |
17fe297f MK |
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); | |
2e74322d | 204 | continue; |
17fe297f | 205 | } |
09b9aef2 MK |
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 | } | |
7892134c MK |
218 | /* |
219 | * Adjust metric according to incoming interface. | |
220 | */ | |
cdf21aa5 | 221 | if ((unsigned) n->rip_metric < HOPCNT_INFINITY) |
7892134c | 222 | n->rip_metric += ifp->int_metric; |
cdf21aa5 MK |
223 | if ((unsigned) n->rip_metric > HOPCNT_INFINITY) |
224 | n->rip_metric = HOPCNT_INFINITY; | |
2e74322d | 225 | rt = rtlookup(&n->rip_dst); |
97cb3618 MK |
226 | if (rt == 0 || |
227 | (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == | |
228 | (RTS_INTERNAL|RTS_INTERFACE)) { | |
7892134c MK |
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; | |
0f7c421b MK |
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; | |
20df59f1 | 246 | rtadd(&n->rip_dst, from, n->rip_metric, 0); |
4033c8f6 | 247 | changes++; |
0f7c421b | 248 | } |
2e74322d SL |
249 | continue; |
250 | } | |
251 | ||
252 | /* | |
38ca17a8 | 253 | * Update if from gateway and different, |
0f7c421b MK |
254 | * shorter, or equivalent but old route |
255 | * is getting stale. | |
2e74322d | 256 | */ |
15e56604 | 257 | if (equal(from, &rt->rt_router)) { |
88709531 | 258 | if (n->rip_metric != rt->rt_metric) { |
15e56604 | 259 | rtchange(rt, from, n->rip_metric); |
4033c8f6 | 260 | changes++; |
0f7c421b | 261 | rt->rt_timer = 0; |
7892134c | 262 | if (rt->rt_metric >= HOPCNT_INFINITY) |
88709531 MK |
263 | rt->rt_timer = |
264 | GARBAGE_TIME - EXPIRE_TIME; | |
265 | } else if (rt->rt_metric < HOPCNT_INFINITY) | |
585e6328 | 266 | rt->rt_timer = 0; |
cdf21aa5 | 267 | } else if ((unsigned) n->rip_metric < rt->rt_metric || |
0f7c421b MK |
268 | (rt->rt_metric == n->rip_metric && |
269 | rt->rt_timer > (EXPIRE_TIME/2) && | |
cdf21aa5 | 270 | (unsigned) n->rip_metric < HOPCNT_INFINITY)) { |
2e74322d | 271 | rtchange(rt, from, n->rip_metric); |
4033c8f6 | 272 | changes++; |
2e74322d SL |
273 | rt->rt_timer = 0; |
274 | } | |
275 | } | |
4033c8f6 MK |
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 | } | |
2e74322d SL |
333 | } |
334 | } |