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