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