xref: /original-bsd/sbin/routed/input.c (revision 092d9b4e)
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