input.c revision 1.18 1 1.18 christos /* $NetBSD: input.c,v 1.18 1996/09/24 16:24:14 christos Exp $ */
2 1.9 cgd
3 1.1 cgd /*
4 1.5 mycroft * Copyright (c) 1983, 1988, 1993
5 1.5 mycroft * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * Redistribution and use in source and binary forms, with or without
8 1.1 cgd * modification, are permitted provided that the following conditions
9 1.1 cgd * are met:
10 1.1 cgd * 1. Redistributions of source code must retain the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer.
12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer in the
14 1.1 cgd * documentation and/or other materials provided with the distribution.
15 1.1 cgd * 3. All advertising materials mentioning features or use of this software
16 1.1 cgd * must display the following acknowledgement:
17 1.1 cgd * This product includes software developed by the University of
18 1.1 cgd * California, Berkeley and its contributors.
19 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
20 1.1 cgd * may be used to endorse or promote products derived from this software
21 1.1 cgd * without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 cgd * SUCH DAMAGE.
34 1.1 cgd */
35 1.1 cgd
36 1.18 christos #if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
37 1.9 cgd static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
38 1.18 christos #elif defined(__NetBSD__)
39 1.18 christos static char rcsid[] = "$NetBSD: input.c,v 1.18 1996/09/24 16:24:14 christos Exp $";
40 1.9 cgd #endif
41 1.1 cgd
42 1.1 cgd #include "defs.h"
43 1.17 thorpej
44 1.17 thorpej static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
45 1.17 thorpej static void input_route(struct interface *, naddr,
46 1.17 thorpej naddr, naddr, naddr, struct netinfo *);
47 1.1 cgd
48 1.15 christos
49 1.17 thorpej /* process RIP input
50 1.15 christos */
51 1.17 thorpej void
52 1.17 thorpej read_rip(int sock,
53 1.17 thorpej struct interface *ifp)
54 1.15 christos {
55 1.17 thorpej struct sockaddr_in from;
56 1.17 thorpej int fromlen, cc;
57 1.17 thorpej union pkt_buf inbuf;
58 1.15 christos
59 1.15 christos
60 1.17 thorpej for (;;) {
61 1.17 thorpej fromlen = sizeof(from);
62 1.17 thorpej cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
63 1.17 thorpej (struct sockaddr*)&from, &fromlen);
64 1.17 thorpej if (cc <= 0) {
65 1.17 thorpej if (cc < 0 && errno != EWOULDBLOCK)
66 1.17 thorpej LOGERR("recvfrom(rip)");
67 1.17 thorpej break;
68 1.17 thorpej }
69 1.17 thorpej if (fromlen != sizeof(struct sockaddr_in))
70 1.17 thorpej logbad(1,"impossible recvfrom(rip) fromlen=%d",
71 1.17 thorpej fromlen);
72 1.17 thorpej
73 1.18 christos input(&from, ifp, &inbuf.rip, cc);
74 1.15 christos }
75 1.15 christos }
76 1.15 christos
77 1.15 christos
78 1.17 thorpej /* Process a RIP packet
79 1.1 cgd */
80 1.17 thorpej static void
81 1.17 thorpej input(struct sockaddr_in *from, /* received from this IP address */
82 1.18 christos struct interface *sifp, /* interface by which it arrived */
83 1.17 thorpej struct rip *rip,
84 1.17 thorpej int size)
85 1.1 cgd {
86 1.17 thorpej # define FROM_NADDR from->sin_addr.s_addr
87 1.17 thorpej static naddr use_auth, bad_len, bad_mask;
88 1.17 thorpej static naddr unk_router, bad_router, bad_nhop;
89 1.17 thorpej
90 1.18 christos struct interface *aifp; /* interface if via 1 hop */
91 1.17 thorpej struct rt_entry *rt;
92 1.17 thorpej struct netinfo *n, *lim;
93 1.17 thorpej struct interface *ifp1;
94 1.17 thorpej naddr gate, mask, v1_mask, dst, ddst_h;
95 1.17 thorpej int i;
96 1.17 thorpej
97 1.18 christos aifp = iflookup(from->sin_addr.s_addr);
98 1.18 christos if (sifp == 0)
99 1.18 christos sifp = aifp;
100 1.17 thorpej
101 1.18 christos if (sifp != 0)
102 1.18 christos sifp->int_state |= IS_ACTIVE;
103 1.17 thorpej
104 1.18 christos trace_rip("Recv", "from", from, sifp, rip, size);
105 1.17 thorpej
106 1.17 thorpej if (rip->rip_vers == 0) {
107 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
108 1.17 thorpej msglog("RIP version 0, cmd %d, packet received"
109 1.17 thorpej " from %s",
110 1.17 thorpej rip->rip_cmd, naddr_ntoa(FROM_NADDR));
111 1.17 thorpej bad_router = from->sin_addr.s_addr;
112 1.17 thorpej return;
113 1.18 christos } else if (rip->rip_vers > RIPv2) {
114 1.18 christos rip->rip_vers = RIPv2;
115 1.17 thorpej }
116 1.17 thorpej if (size > MAXPACKETSIZE) {
117 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
118 1.17 thorpej msglog("packet at least %d bytes too long received"
119 1.17 thorpej " from %s",
120 1.17 thorpej size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
121 1.17 thorpej bad_router = from->sin_addr.s_addr;
122 1.1 cgd return;
123 1.1 cgd }
124 1.17 thorpej
125 1.17 thorpej n = rip->rip_nets;
126 1.17 thorpej lim = (struct netinfo *)((char*)rip + size);
127 1.17 thorpej
128 1.17 thorpej /* Notice authentication.
129 1.17 thorpej * As required by section 4.2 in RFC 1723, discard authenticated
130 1.17 thorpej * RIPv2 messages, but only if configured for that silliness.
131 1.17 thorpej *
132 1.17 thorpej * RIPv2 authentication is lame, since snooping on the wire makes
133 1.17 thorpej * its simple passwords evident. Also, why authenticate queries?
134 1.17 thorpej * Why should a RIPv2 implementation with authentication disabled
135 1.17 thorpej * not be able to listen to RIPv2 packets with authenication, while
136 1.17 thorpej * RIPv1 systems will listen? Crazy!
137 1.17 thorpej */
138 1.17 thorpej if (!auth_ok
139 1.18 christos && rip->rip_vers == RIPv2
140 1.17 thorpej && n < lim && n->n_family == RIP_AF_AUTH) {
141 1.17 thorpej if (from->sin_addr.s_addr != use_auth)
142 1.17 thorpej msglog("RIPv2 message with authentication"
143 1.17 thorpej " from %s discarded",
144 1.17 thorpej naddr_ntoa(FROM_NADDR));
145 1.17 thorpej use_auth = from->sin_addr.s_addr;
146 1.17 thorpej trace_pkt("discard authenticated RIPv2 message\n");
147 1.1 cgd return;
148 1.1 cgd }
149 1.15 christos
150 1.1 cgd switch (rip->rip_cmd) {
151 1.17 thorpej case RIPCMD_REQUEST:
152 1.17 thorpej /* did the request come from a router?
153 1.17 thorpej */
154 1.17 thorpej if (from->sin_port == htons(RIP_PORT)) {
155 1.17 thorpej /* yes, ignore it if RIP is off so that it does not
156 1.17 thorpej * depend on us.
157 1.17 thorpej */
158 1.17 thorpej if (rip_sock < 0) {
159 1.17 thorpej trace_pkt("ignore request while RIP off\n");
160 1.17 thorpej return;
161 1.17 thorpej }
162 1.1 cgd
163 1.17 thorpej /* Ignore the request if we talking to ourself
164 1.17 thorpej * (and not a remote gateway).
165 1.17 thorpej */
166 1.17 thorpej if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
167 1.17 thorpej trace_pkt("discard our own RIP request\n");
168 1.17 thorpej return;
169 1.17 thorpej }
170 1.17 thorpej }
171 1.17 thorpej
172 1.17 thorpej /* According to RFC 1723, we should ignore unathenticated
173 1.17 thorpej * queries. That is too silly to bother with. Sheesh!
174 1.17 thorpej * Are forwarding tables supposed to be secret? When
175 1.17 thorpej * a bad guy can infer them with test traffic?
176 1.17 thorpej * Maybe on firewalls you'd care, but not enough to
177 1.17 thorpej * give up the diagnostic facilities of remote probing.
178 1.17 thorpej */
179 1.17 thorpej
180 1.17 thorpej if (n >= lim
181 1.17 thorpej || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
182 1.17 thorpej if (from->sin_addr.s_addr != bad_len)
183 1.17 thorpej msglog("request of bad length (%d) from %s",
184 1.17 thorpej size, naddr_ntoa(FROM_NADDR));
185 1.17 thorpej bad_len = from->sin_addr.s_addr;
186 1.17 thorpej }
187 1.17 thorpej for (; n < lim; n++) {
188 1.17 thorpej n->n_metric = ntohl(n->n_metric);
189 1.17 thorpej
190 1.17 thorpej /* A single entry with family RIP_AF_UNSPEC and
191 1.17 thorpej * metric HOPCNT_INFINITY means "all routes".
192 1.1 cgd * We respond to routers only if we are acting
193 1.1 cgd * as a supplier, or to anyone other than a router
194 1.17 thorpej * (i.e. a query).
195 1.1 cgd */
196 1.17 thorpej if (n->n_family == RIP_AF_UNSPEC
197 1.17 thorpej && n->n_metric == HOPCNT_INFINITY
198 1.17 thorpej && n == rip->rip_nets
199 1.17 thorpej && n+1 == lim) {
200 1.17 thorpej if (from->sin_port != htons(RIP_PORT)) {
201 1.18 christos /* Answer a query from a utility
202 1.18 christos * program with all we know.
203 1.18 christos */
204 1.18 christos supply(from, sifp, OUT_QUERY, 0,
205 1.18 christos rip->rip_vers);
206 1.18 christos return;
207 1.17 thorpej }
208 1.18 christos /* A router trying to prime its tables.
209 1.18 christos * Filter the answer in the about same way
210 1.18 christos * broadcasts are filtered.
211 1.18 christos *
212 1.18 christos * Only answer a router if we are a supplier
213 1.18 christos * to keep an unwary host that is just starting
214 1.18 christos * from picking us as a router. Respond with
215 1.18 christos * RIPv1 instead of RIPv2 if that is what we
216 1.18 christos * are broadcasting on the interface to keep
217 1.18 christos * the remote router from getting the wrong
218 1.18 christos * initial idea of the routes we send.
219 1.18 christos */
220 1.18 christos if (!supplier
221 1.18 christos || aifp == 0
222 1.18 christos || (aifp->int_state & IS_PASSIVE)
223 1.18 christos || (aifp->int_state & IS_ALIAS)
224 1.18 christos || ((aifp->int_state & IS_NO_RIPV1_OUT)
225 1.18 christos && (aifp->int_state&IS_NO_RIPV2_OUT)))
226 1.18 christos return;
227 1.18 christos
228 1.18 christos supply(from, aifp, OUT_UNICAST, 0,
229 1.18 christos (aifp->int_state&IS_NO_RIPV1_OUT)
230 1.18 christos ? RIPv2 : RIPv1);
231 1.17 thorpej return;
232 1.17 thorpej }
233 1.17 thorpej
234 1.17 thorpej if (n->n_family != RIP_AF_INET) {
235 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
236 1.17 thorpej msglog("request from %s"
237 1.17 thorpej " for unsupported (af %d) %s",
238 1.17 thorpej naddr_ntoa(FROM_NADDR),
239 1.17 thorpej ntohs(n->n_family),
240 1.17 thorpej naddr_ntoa(n->n_dst));
241 1.17 thorpej bad_router = from->sin_addr.s_addr;
242 1.17 thorpej return;
243 1.17 thorpej }
244 1.17 thorpej
245 1.17 thorpej dst = n->n_dst;
246 1.17 thorpej if (!check_dst(dst)) {
247 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
248 1.17 thorpej msglog("bad queried destination"
249 1.17 thorpej " %s from %s",
250 1.17 thorpej naddr_ntoa(dst),
251 1.17 thorpej naddr_ntoa(FROM_NADDR));
252 1.17 thorpej bad_router = from->sin_addr.s_addr;
253 1.1 cgd return;
254 1.1 cgd }
255 1.17 thorpej
256 1.17 thorpej if (rip->rip_vers == RIPv1
257 1.17 thorpej || 0 == (mask = ntohl(n->n_mask))
258 1.17 thorpej || 0 != (ntohl(dst) & ~mask))
259 1.18 christos mask = ripv1_mask_host(dst,sifp);
260 1.17 thorpej
261 1.17 thorpej rt = rtget(dst, mask);
262 1.17 thorpej if (!rt && dst != RIP_DEFAULT)
263 1.17 thorpej rt = rtfind(n->n_dst);
264 1.17 thorpej
265 1.17 thorpej n->n_tag = 0;
266 1.17 thorpej n->n_nhop = 0;
267 1.17 thorpej if (rip->rip_vers == RIPv1) {
268 1.17 thorpej n->n_mask = 0;
269 1.17 thorpej } else {
270 1.17 thorpej n->n_mask = mask;
271 1.17 thorpej }
272 1.17 thorpej if (rt == 0) {
273 1.17 thorpej n->n_metric = HOPCNT_INFINITY;
274 1.17 thorpej } else {
275 1.17 thorpej n->n_metric = rt->rt_metric+1;
276 1.18 christos n->n_metric += (sifp!=0)?sifp->int_metric : 1;
277 1.17 thorpej if (n->n_metric > HOPCNT_INFINITY)
278 1.17 thorpej n->n_metric = HOPCNT_INFINITY;
279 1.17 thorpej if (rip->rip_vers != RIPv1) {
280 1.17 thorpej n->n_tag = rt->rt_tag;
281 1.18 christos if (sifp != 0
282 1.17 thorpej && on_net(rt->rt_gate,
283 1.18 christos sifp->int_net,
284 1.18 christos sifp->int_mask)
285 1.18 christos && rt->rt_gate != sifp->int_addr)
286 1.17 thorpej n->n_nhop = rt->rt_gate;
287 1.17 thorpej }
288 1.17 thorpej }
289 1.17 thorpej HTONL(n->n_metric);
290 1.1 cgd }
291 1.17 thorpej /* Answer about specific routes.
292 1.17 thorpej * Only answer a router if we are a supplier
293 1.17 thorpej * to keep an unwary host that is just starting
294 1.17 thorpej * from picking us an a router.
295 1.17 thorpej */
296 1.1 cgd rip->rip_cmd = RIPCMD_RESPONSE;
297 1.17 thorpej rip->rip_res1 = 0;
298 1.17 thorpej if (rip->rip_vers != RIPv1)
299 1.17 thorpej rip->rip_vers = RIPv2;
300 1.17 thorpej if (from->sin_port != htons(RIP_PORT)) {
301 1.17 thorpej /* query */
302 1.18 christos (void)output(OUT_QUERY, from, sifp, rip, size);
303 1.17 thorpej } else if (supplier) {
304 1.18 christos (void)output(OUT_UNICAST, from, sifp, rip, size);
305 1.17 thorpej }
306 1.1 cgd return;
307 1.1 cgd
308 1.1 cgd case RIPCMD_TRACEON:
309 1.1 cgd case RIPCMD_TRACEOFF:
310 1.1 cgd /* verify message came from a privileged port */
311 1.17 thorpej if (ntohs(from->sin_port) > IPPORT_RESERVED) {
312 1.17 thorpej msglog("trace command from untrusted port on %s",
313 1.17 thorpej naddr_ntoa(FROM_NADDR));
314 1.1 cgd return;
315 1.17 thorpej }
316 1.18 christos if (aifp == 0) {
317 1.17 thorpej msglog("trace command from unknown router %s",
318 1.17 thorpej naddr_ntoa(FROM_NADDR));
319 1.12 christos return;
320 1.17 thorpej }
321 1.17 thorpej if (rip->rip_cmd == RIPCMD_TRACEON) {
322 1.17 thorpej rip->rip_tracefile[size-4] = '\0';
323 1.18 christos trace_on((char*)rip->rip_tracefile, 0);
324 1.17 thorpej } else {
325 1.17 thorpej trace_off("tracing turned off by %s\n",
326 1.17 thorpej naddr_ntoa(FROM_NADDR));
327 1.17 thorpej }
328 1.1 cgd return;
329 1.1 cgd
330 1.1 cgd case RIPCMD_RESPONSE:
331 1.17 thorpej if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
332 1.17 thorpej if (from->sin_addr.s_addr != bad_len)
333 1.17 thorpej msglog("response of bad length (%d) from %s",
334 1.17 thorpej size, naddr_ntoa(FROM_NADDR));
335 1.17 thorpej bad_len = from->sin_addr.s_addr;
336 1.17 thorpej }
337 1.17 thorpej
338 1.1 cgd /* verify message came from a router */
339 1.17 thorpej if (from->sin_port != ntohs(RIP_PORT)) {
340 1.17 thorpej trace_pkt("discard RIP response from unknown port\n");
341 1.1 cgd return;
342 1.17 thorpej }
343 1.17 thorpej
344 1.17 thorpej if (rip_sock < 0) {
345 1.17 thorpej trace_pkt("discard response while RIP off\n");
346 1.17 thorpej return;
347 1.17 thorpej }
348 1.17 thorpej
349 1.17 thorpej /* Are we talking to ourself or a remote gateway?
350 1.17 thorpej */
351 1.17 thorpej ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
352 1.17 thorpej if (ifp1) {
353 1.17 thorpej if (ifp1->int_state & IS_REMOTE) {
354 1.17 thorpej if (ifp1->int_state & IS_PASSIVE) {
355 1.17 thorpej msglog("bogus input from %s on"
356 1.17 thorpej " supposedly passive %s",
357 1.17 thorpej naddr_ntoa(FROM_NADDR),
358 1.17 thorpej ifp1->int_name);
359 1.17 thorpej } else {
360 1.17 thorpej ifp1->int_act_time = now.tv_sec;
361 1.17 thorpej if (if_ok(ifp1, "remote "))
362 1.17 thorpej addrouteforif(ifp1);
363 1.17 thorpej }
364 1.17 thorpej } else {
365 1.17 thorpej trace_pkt("discard our own RIP response\n");
366 1.1 cgd }
367 1.17 thorpej return;
368 1.17 thorpej }
369 1.17 thorpej
370 1.17 thorpej /* Check the router from which message originated. We accept
371 1.17 thorpej * routing packets from routers directly connected via
372 1.17 thorpej * broadcast or point-to-point networks, and from
373 1.17 thorpej * those listed in /etc/gateways.
374 1.17 thorpej */
375 1.18 christos if (!aifp) {
376 1.17 thorpej if (from->sin_addr.s_addr != unk_router)
377 1.18 christos msglog("discard packet from unknown router %s"
378 1.17 thorpej " or via unidentified interface",
379 1.17 thorpej naddr_ntoa(FROM_NADDR));
380 1.17 thorpej unk_router = from->sin_addr.s_addr;
381 1.17 thorpej return;
382 1.17 thorpej }
383 1.18 christos if (aifp->int_state & IS_PASSIVE) {
384 1.18 christos trace_act("discard packet from %s"
385 1.18 christos " via passive interface %s\n",
386 1.17 thorpej naddr_ntoa(FROM_NADDR),
387 1.18 christos aifp->int_name);
388 1.17 thorpej return;
389 1.17 thorpej }
390 1.17 thorpej
391 1.17 thorpej /* Check required version
392 1.17 thorpej */
393 1.18 christos if (((aifp->int_state & IS_NO_RIPV1_IN)
394 1.17 thorpej && rip->rip_vers == RIPv1)
395 1.18 christos || ((aifp->int_state & IS_NO_RIPV2_IN)
396 1.17 thorpej && rip->rip_vers != RIPv1)) {
397 1.17 thorpej trace_pkt("discard RIPv%d response\n",
398 1.17 thorpej rip->rip_vers);
399 1.17 thorpej return;
400 1.17 thorpej }
401 1.17 thorpej
402 1.17 thorpej /* Ignore routes via dead interface.
403 1.17 thorpej */
404 1.18 christos if (aifp->int_state & IS_BROKE) {
405 1.17 thorpej trace_pkt("discard response via broken interface %s\n",
406 1.18 christos aifp->int_name);
407 1.17 thorpej return;
408 1.17 thorpej }
409 1.17 thorpej
410 1.18 christos /* Authenticate the packet if we have a secret.
411 1.17 thorpej */
412 1.18 christos if (aifp->int_passwd[0] != '\0') {
413 1.18 christos if (n >= lim
414 1.18 christos || n->n_family != RIP_AF_AUTH
415 1.18 christos || ((struct netauth*)n)->a_type != RIP_AUTH_PW) {
416 1.18 christos if (from->sin_addr.s_addr != use_auth)
417 1.18 christos msglog("missing password from %s",
418 1.18 christos naddr_ntoa(FROM_NADDR));
419 1.18 christos use_auth = from->sin_addr.s_addr;
420 1.18 christos return;
421 1.17 thorpej
422 1.18 christos } else if (0 != bcmp(((struct netauth*)n)->au.au_pw,
423 1.18 christos aifp->int_passwd,
424 1.18 christos sizeof(aifp->int_passwd))) {
425 1.18 christos if (from->sin_addr.s_addr != use_auth)
426 1.18 christos msglog("bad password from %s",
427 1.18 christos naddr_ntoa(FROM_NADDR));
428 1.18 christos use_auth = from->sin_addr.s_addr;
429 1.18 christos return;
430 1.18 christos }
431 1.17 thorpej }
432 1.17 thorpej
433 1.17 thorpej auth_ok:
434 1.17 thorpej
435 1.17 thorpej for (; n < lim; n++) {
436 1.17 thorpej if (n->n_family == RIP_AF_AUTH)
437 1.15 christos continue;
438 1.17 thorpej
439 1.17 thorpej NTOHL(n->n_metric);
440 1.17 thorpej dst = n->n_dst;
441 1.17 thorpej if (n->n_family != RIP_AF_INET
442 1.17 thorpej && (n->n_family != RIP_AF_UNSPEC
443 1.17 thorpej || dst != RIP_DEFAULT)) {
444 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
445 1.17 thorpej msglog("route from %s to unsupported"
446 1.17 thorpej " address family %d,"
447 1.17 thorpej " destination %s",
448 1.17 thorpej naddr_ntoa(FROM_NADDR),
449 1.17 thorpej n->n_family,
450 1.17 thorpej naddr_ntoa(dst));
451 1.17 thorpej bad_router = from->sin_addr.s_addr;
452 1.1 cgd continue;
453 1.1 cgd }
454 1.17 thorpej if (!check_dst(dst)) {
455 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
456 1.17 thorpej msglog("bad destination %s from %s",
457 1.17 thorpej naddr_ntoa(dst),
458 1.17 thorpej naddr_ntoa(FROM_NADDR));
459 1.17 thorpej bad_router = from->sin_addr.s_addr;
460 1.17 thorpej return;
461 1.1 cgd }
462 1.17 thorpej if (n->n_metric == 0
463 1.17 thorpej || n->n_metric > HOPCNT_INFINITY) {
464 1.17 thorpej if (from->sin_addr.s_addr != bad_router)
465 1.17 thorpej msglog("bad metric %d from %s"
466 1.17 thorpej " for destination %s",
467 1.17 thorpej n->n_metric,
468 1.17 thorpej naddr_ntoa(FROM_NADDR),
469 1.17 thorpej naddr_ntoa(dst));
470 1.17 thorpej bad_router = from->sin_addr.s_addr;
471 1.17 thorpej return;
472 1.1 cgd }
473 1.17 thorpej
474 1.17 thorpej /* Notice the next-hop.
475 1.1 cgd */
476 1.17 thorpej gate = from->sin_addr.s_addr;
477 1.18 christos if (n->n_nhop != 0) {
478 1.18 christos if (rip->rip_vers == RIPv2) {
479 1.18 christos n->n_nhop = 0;
480 1.17 thorpej } else {
481 1.18 christos /* Use it only if it is valid. */
482 1.18 christos if (on_net(n->n_nhop,
483 1.18 christos aifp->int_net, aifp->int_mask)
484 1.18 christos && check_dst(n->n_nhop)) {
485 1.18 christos gate = n->n_nhop;
486 1.18 christos } else {
487 1.17 thorpej if (bad_nhop != from->sin_addr.s_addr)
488 1.18 christos msglog("router %s to %s has"
489 1.18 christos " bad next hop %s",
490 1.18 christos naddr_ntoa(FROM_NADDR),
491 1.18 christos naddr_ntoa(dst),
492 1.18 christos naddr_ntoa(n->n_nhop));
493 1.17 thorpej bad_nhop = from->sin_addr.s_addr;
494 1.18 christos n->n_nhop = 0;
495 1.18 christos }
496 1.17 thorpej }
497 1.17 thorpej }
498 1.17 thorpej
499 1.17 thorpej if (rip->rip_vers == RIPv1
500 1.17 thorpej || 0 == (mask = ntohl(n->n_mask))) {
501 1.18 christos mask = ripv1_mask_host(dst,aifp);
502 1.17 thorpej } else if ((ntohl(dst) & ~mask) != 0) {
503 1.17 thorpej if (bad_mask != from->sin_addr.s_addr) {
504 1.17 thorpej msglog("router %s sent bad netmask"
505 1.17 thorpej " %#x with %s",
506 1.17 thorpej naddr_ntoa(FROM_NADDR),
507 1.17 thorpej mask,
508 1.17 thorpej naddr_ntoa(dst));
509 1.17 thorpej bad_mask = from->sin_addr.s_addr;
510 1.1 cgd }
511 1.1 cgd continue;
512 1.1 cgd }
513 1.17 thorpej if (rip->rip_vers == RIPv1)
514 1.17 thorpej n->n_tag = 0;
515 1.1 cgd
516 1.17 thorpej /* Adjust metric according to incoming interface..
517 1.17 thorpej */
518 1.18 christos n->n_metric += aifp->int_metric;
519 1.17 thorpej if (n->n_metric > HOPCNT_INFINITY)
520 1.17 thorpej n->n_metric = HOPCNT_INFINITY;
521 1.17 thorpej
522 1.17 thorpej /* Recognize and ignore a default route we faked
523 1.17 thorpej * which is being sent back to us by a machine with
524 1.17 thorpej * broken split-horizon.
525 1.17 thorpej * Be a little more paranoid than that, and reject
526 1.17 thorpej * default routes with the same metric we advertised.
527 1.17 thorpej */
528 1.18 christos if (aifp->int_d_metric != 0
529 1.17 thorpej && dst == RIP_DEFAULT
530 1.18 christos && n->n_metric >= aifp->int_d_metric)
531 1.17 thorpej continue;
532 1.17 thorpej
533 1.17 thorpej /* We can receive aggregated RIPv2 routes that must
534 1.17 thorpej * be broken down before they are transmitted by
535 1.17 thorpej * RIPv1 via an interface on a subnet.
536 1.17 thorpej * We might also receive the same routes aggregated
537 1.17 thorpej * via other RIPv2 interfaces.
538 1.17 thorpej * This could cause duplicate routes to be sent on
539 1.17 thorpej * the RIPv1 interfaces. "Longest matching variable
540 1.17 thorpej * length netmasks" lets RIPv2 listeners understand,
541 1.17 thorpej * but breaking down the aggregated routes for RIPv1
542 1.17 thorpej * listeners can produce duplicate routes.
543 1.17 thorpej *
544 1.17 thorpej * Breaking down aggregated routes here bloats
545 1.17 thorpej * the daemon table, but does not hurt the kernel
546 1.17 thorpej * table, since routes are always aggregated for
547 1.17 thorpej * the kernel.
548 1.17 thorpej *
549 1.17 thorpej * Notice that this does not break down network
550 1.17 thorpej * routes corresponding to subnets. This is part
551 1.17 thorpej * of the defense against RS_NET_SYN.
552 1.1 cgd */
553 1.17 thorpej if (have_ripv1_out
554 1.17 thorpej && (v1_mask = ripv1_mask_net(dst,0)) > mask
555 1.17 thorpej && (((rt = rtget(dst,mask)) == 0
556 1.17 thorpej || !(rt->rt_state & RS_NET_SYN)))) {
557 1.17 thorpej ddst_h = v1_mask & -v1_mask;
558 1.17 thorpej i = (v1_mask & ~mask)/ddst_h;
559 1.18 christos if (i >= 511) {
560 1.17 thorpej /* Punt if we would have to generate
561 1.17 thorpej * an unreasonable number of routes.
562 1.17 thorpej */
563 1.17 thorpej #ifdef DEBUG
564 1.18 christos msglog("accept %s from %s as 1"
565 1.18 christos " instead of %d routes",
566 1.17 thorpej addrname(dst,mask,0),
567 1.18 christos naddr_ntoa(FROM_NADDR),
568 1.18 christos i+1);
569 1.17 thorpej #endif
570 1.17 thorpej i = 0;
571 1.17 thorpej } else {
572 1.17 thorpej mask = v1_mask;
573 1.17 thorpej }
574 1.17 thorpej } else {
575 1.17 thorpej i = 0;
576 1.17 thorpej }
577 1.17 thorpej
578 1.17 thorpej for (;;) {
579 1.18 christos input_route(aifp, FROM_NADDR,
580 1.17 thorpej dst, mask, gate, n);
581 1.17 thorpej if (i-- == 0)
582 1.17 thorpej break;
583 1.17 thorpej dst = htonl(ntohl(dst) + ddst_h);
584 1.1 cgd }
585 1.1 cgd }
586 1.1 cgd break;
587 1.1 cgd }
588 1.17 thorpej }
589 1.17 thorpej
590 1.17 thorpej
591 1.17 thorpej /* Process a single input route.
592 1.17 thorpej */
593 1.17 thorpej static void
594 1.17 thorpej input_route(struct interface *ifp,
595 1.17 thorpej naddr from,
596 1.17 thorpej naddr dst,
597 1.17 thorpej naddr mask,
598 1.17 thorpej naddr gate,
599 1.17 thorpej struct netinfo *n)
600 1.17 thorpej {
601 1.17 thorpej int i;
602 1.17 thorpej struct rt_entry *rt;
603 1.17 thorpej struct rt_spare *rts, *rts0;
604 1.17 thorpej struct interface *ifp1;
605 1.17 thorpej time_t new_time;
606 1.17 thorpej
607 1.17 thorpej
608 1.17 thorpej /* See if the other guy is telling us to send our packets to him.
609 1.17 thorpej * Sometimes network routes arrive over a point-to-point link for
610 1.17 thorpej * the network containing the address(es) of the link.
611 1.17 thorpej *
612 1.17 thorpej * If our interface is broken, switch to using the other guy.
613 1.17 thorpej */
614 1.17 thorpej ifp1 = ifwithaddr(dst, 1, 1);
615 1.17 thorpej if (ifp1 != 0
616 1.17 thorpej && !(ifp1->int_state & IS_BROKE))
617 1.17 thorpej return;
618 1.17 thorpej
619 1.17 thorpej /* Look for the route in our table.
620 1.17 thorpej */
621 1.17 thorpej rt = rtget(dst, mask);
622 1.17 thorpej
623 1.17 thorpej /* Consider adding the route if we do not already have it.
624 1.17 thorpej */
625 1.17 thorpej if (rt == 0) {
626 1.17 thorpej /* Ignore unknown routes being poisoned.
627 1.17 thorpej */
628 1.17 thorpej if (n->n_metric == HOPCNT_INFINITY)
629 1.17 thorpej return;
630 1.17 thorpej
631 1.18 christos /* Ignore the route if it points to us */
632 1.18 christos if (n->n_nhop != 0
633 1.18 christos && 0 != ifwithaddr(n->n_nhop, 1, 0))
634 1.18 christos return;
635 1.18 christos
636 1.18 christos /* If something has not gone crazy and tried to fill
637 1.18 christos * our memory, accept the new route.
638 1.18 christos */
639 1.18 christos if (total_routes < MAX_ROUTES)
640 1.18 christos rtadd(dst, mask, gate, from, n->n_metric,
641 1.18 christos n->n_tag, 0, ifp);
642 1.17 thorpej return;
643 1.17 thorpej }
644 1.1 cgd
645 1.17 thorpej /* We already know about the route. Consider this update.
646 1.17 thorpej *
647 1.17 thorpej * If (rt->rt_state & RS_NET_SYN), then this route
648 1.17 thorpej * is the same as a network route we have inferred
649 1.17 thorpej * for subnets we know, in order to tell RIPv1 routers
650 1.17 thorpej * about the subnets.
651 1.17 thorpej *
652 1.17 thorpej * It is impossible to tell if the route is coming
653 1.17 thorpej * from a distant RIPv2 router with the standard
654 1.17 thorpej * netmask because that router knows about the entire
655 1.17 thorpej * network, or if it is a round-about echo of a
656 1.17 thorpej * synthetic, RIPv1 network route of our own.
657 1.17 thorpej * The worst is that both kinds of routes might be
658 1.17 thorpej * received, and the bad one might have the smaller
659 1.18 christos * metric. Partly solve this problem by never
660 1.18 christos * aggregating into such a route. Also keep it
661 1.17 thorpej * around as long as the interface exists.
662 1.1 cgd */
663 1.17 thorpej
664 1.17 thorpej rts0 = rt->rt_spares;
665 1.17 thorpej for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
666 1.17 thorpej if (rts->rts_router == from)
667 1.17 thorpej break;
668 1.17 thorpej /* Note the worst slot to reuse,
669 1.17 thorpej * other than the current slot.
670 1.17 thorpej */
671 1.17 thorpej if (rts0 == rt->rt_spares
672 1.17 thorpej || BETTER_LINK(rt, rts0, rts))
673 1.17 thorpej rts0 = rts;
674 1.17 thorpej }
675 1.17 thorpej if (i != 0) {
676 1.17 thorpej /* Found the router
677 1.17 thorpej */
678 1.17 thorpej int old_metric = rts->rts_metric;
679 1.17 thorpej
680 1.18 christos /* Keep poisoned routes around only long enough to pass
681 1.18 christos * the poison on. Get a new timestamp for good routes.
682 1.17 thorpej */
683 1.18 christos new_time =((old_metric == HOPCNT_INFINITY)
684 1.18 christos ? rts->rts_time
685 1.18 christos : now.tv_sec);
686 1.17 thorpej
687 1.17 thorpej /* If this is an update for the router we currently prefer,
688 1.17 thorpej * then note it.
689 1.17 thorpej */
690 1.17 thorpej if (i == NUM_SPARES) {
691 1.17 thorpej rtchange(rt,rt->rt_state, gate,rt->rt_router,
692 1.17 thorpej n->n_metric, n->n_tag, ifp, new_time, 0);
693 1.17 thorpej /* If the route got worse, check for something better.
694 1.1 cgd */
695 1.17 thorpej if (n->n_metric > old_metric)
696 1.17 thorpej rtswitch(rt, 0);
697 1.17 thorpej return;
698 1.17 thorpej }
699 1.17 thorpej
700 1.17 thorpej /* This is an update for a spare route.
701 1.17 thorpej * Finished if the route is unchanged.
702 1.17 thorpej */
703 1.17 thorpej if (rts->rts_gate == gate
704 1.17 thorpej && old_metric == n->n_metric
705 1.17 thorpej && rts->rts_tag == n->n_tag) {
706 1.17 thorpej rts->rts_time = new_time;
707 1.17 thorpej return;
708 1.1 cgd }
709 1.17 thorpej
710 1.17 thorpej } else {
711 1.17 thorpej /* The update is for a route we know about,
712 1.17 thorpej * but not from a familiar router.
713 1.18 christos *
714 1.18 christos * Ignore the route if it points to us.
715 1.17 thorpej */
716 1.18 christos if (n->n_nhop != 0
717 1.18 christos && 0 != ifwithaddr(n->n_nhop, 1, 0))
718 1.18 christos return;
719 1.18 christos
720 1.17 thorpej rts = rts0;
721 1.17 thorpej
722 1.17 thorpej /* Save the route as a spare only if it has
723 1.17 thorpej * a better metric than our worst spare.
724 1.17 thorpej * This also ignores poisoned routes (those
725 1.17 thorpej * received with metric HOPCNT_INFINITY).
726 1.17 thorpej */
727 1.17 thorpej if (n->n_metric >= rts->rts_metric)
728 1.17 thorpej return;
729 1.17 thorpej
730 1.17 thorpej new_time = now.tv_sec;
731 1.1 cgd }
732 1.17 thorpej
733 1.17 thorpej trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
734 1.17 thorpej
735 1.17 thorpej rts->rts_gate = gate;
736 1.17 thorpej rts->rts_router = from;
737 1.17 thorpej rts->rts_metric = n->n_metric;
738 1.17 thorpej rts->rts_tag = n->n_tag;
739 1.17 thorpej rts->rts_time = new_time;
740 1.17 thorpej rts->rts_ifp = ifp;
741 1.17 thorpej
742 1.17 thorpej /* try to switch to a better route */
743 1.17 thorpej rtswitch(rt, rts);
744 1.1 cgd }
745