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