diff options
Diffstat (limited to 'sbin/routed/input.c')
-rw-r--r-- | sbin/routed/input.c | 615 |
1 files changed, 404 insertions, 211 deletions
diff --git a/sbin/routed/input.c b/sbin/routed/input.c index a854c41..24a02b9 100644 --- a/sbin/routed/input.c +++ b/sbin/routed/input.c @@ -36,24 +36,34 @@ static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; #elif defined(__NetBSD__) static char rcsid[] = "$NetBSD$"; #endif -#ident "$Revision: 1.16 $" +#ident "$Revision: 1.17 $" #include "defs.h" -static void input(struct sockaddr_in *, struct interface*, struct rip *, int); +static void input(struct sockaddr_in *, struct interface *, struct interface *, + struct rip *, int); static void input_route(struct interface *, naddr, naddr, naddr, naddr, struct netinfo *); +static int ck_passwd(struct interface *, struct rip *, void *, + naddr, struct msg_limit *); /* process RIP input */ void read_rip(int sock, - struct interface *ifp) + struct interface *sifp) { + static struct msg_limit bad_name; struct sockaddr_in from; + struct interface *aifp; int fromlen, cc; - union pkt_buf inbuf; + struct { +#ifdef USE_PASSIFNAME + char ifname[IFNAMSIZ]; +#endif + union pkt_buf pbuf; + } inbuf; for (;;) { @@ -69,7 +79,54 @@ read_rip(int sock, logbad(1,"impossible recvfrom(rip) fromlen=%d", fromlen); - input(&from, ifp, &inbuf.rip, cc); + /* aifp is the "authenticated" interface via which the packet + * arrived. In fact, it is only the interface on which + * the packet should have arrived based on is source + * address. + * sifp is interface associated with the socket through which + * the packet was received. + */ +#ifdef USE_PASSIFNAME + if ((cc -= sizeof(inbuf.ifname)) < 0) + logbad(0,"missing USE_PASSIFNAME; only %d bytes", + cc+sizeof(inbuf.ifname)); + + /* check the remote interfaces first */ + for (aifp = remote_if; aifp; aifp = aifp->int_rlink) { + if (aifp->int_addr == from.sin_addr.s_addr) + break; + } + if (aifp == 0) { + aifp = ifwithname(inbuf.ifname, 0); + if (aifp == 0) { + /* maybe it is a new interface */ + ifinit(); + aifp = ifwithname(inbuf.ifname, 0); + if (aifp == 0) { + msglim(&bad_name, from.sin_addr.s_addr, + "impossible interface name" + " %.*s", IFNAMSIZ, + inbuf.ifname); + } + } + + /* If it came via the wrong interface, do not + * trust it. + */ + if (((aifp->int_if_flags & IFF_POINTOPOINT) + && aifp->int_dstaddr != from.sin_addr.s_addr) + || (!(aifp->int_if_flags & IFF_POINTOPOINT) + && !on_net(from.sin_addr.s_addr, + aifp->int_net, aifp->int_mask))) + aifp = 0; + } +#else + aifp = iflookup(from.sin_addr.s_addr); +#endif + if (sifp == 0) + sifp = aifp; + + input(&from, sifp, aifp, &inbuf.pbuf.rip, cc); } } @@ -78,58 +135,53 @@ read_rip(int sock, */ static void input(struct sockaddr_in *from, /* received from this IP address */ - struct interface *sifp, /* interface by which it arrived */ + struct interface *sifp, /* interface of incoming socket */ + struct interface *aifp, /* "authenticated" interface */ struct rip *rip, - int size) + int cc) { # define FROM_NADDR from->sin_addr.s_addr - static naddr use_auth, bad_len, bad_mask; - static naddr unk_router, bad_router, bad_nhop; + static struct msg_limit use_auth, bad_len, bad_mask; + static struct msg_limit unk_router, bad_router, bad_nhop; - struct interface *aifp; /* interface if via 1 hop */ struct rt_entry *rt; struct netinfo *n, *lim; struct interface *ifp1; naddr gate, mask, v1_mask, dst, ddst_h; + struct auth_key *ap; int i; - aifp = iflookup(from->sin_addr.s_addr); - if (sifp == 0) - sifp = aifp; - - if (sifp != 0) - sifp->int_state |= IS_ACTIVE; + /* Notice when we hear from a remote gateway + */ + if (aifp != 0 + && (aifp->int_state & IS_REMOTE)) + aifp->int_act_time = now.tv_sec; - trace_rip("Recv", "from", from, sifp, rip, size); + trace_rip("Recv", "from", from, sifp, rip, cc); if (rip->rip_vers == 0) { - if (from->sin_addr.s_addr != bad_router) - msglog("RIP version 0, cmd %d, packet received" - " from %s", - rip->rip_cmd, naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; + msglim(&bad_router, FROM_NADDR, + "RIP version 0, cmd %d, packet received from %s", + rip->rip_cmd, naddr_ntoa(FROM_NADDR)); return; } else if (rip->rip_vers > RIPv2) { rip->rip_vers = RIPv2; } - if (size > MAXPACKETSIZE) { - if (from->sin_addr.s_addr != bad_router) - msglog("packet at least %d bytes too long received" - " from %s", - size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; + if (cc > OVER_MAXPACKETSIZE) { + msglim(&bad_router, FROM_NADDR, + "packet at least %d bytes too long received from %s", + cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR)); return; } n = rip->rip_nets; - lim = (struct netinfo *)((char*)rip + size); + lim = (struct netinfo *)((char*)rip + cc); /* Notice authentication. * As required by section 4.2 in RFC 1723, discard authenticated * RIPv2 messages, but only if configured for that silliness. * - * RIPv2 authentication is lame, since snooping on the wire makes - * its simple passwords evident. Also, why authenticate queries? + * RIPv2 authentication is lame. Why authenticate queries? * Why should a RIPv2 implementation with authentication disabled * not be able to listen to RIPv2 packets with authenication, while * RIPv1 systems will listen? Crazy! @@ -137,54 +189,93 @@ input(struct sockaddr_in *from, /* received from this IP address */ if (!auth_ok && rip->rip_vers == RIPv2 && n < lim && n->n_family == RIP_AF_AUTH) { - if (from->sin_addr.s_addr != use_auth) - msglog("RIPv2 message with authentication" - " from %s discarded", - naddr_ntoa(FROM_NADDR)); - use_auth = from->sin_addr.s_addr; - trace_pkt("discard authenticated RIPv2 message\n"); + msglim(&use_auth, FROM_NADDR, + "RIPv2 message with authentication from %s discarded", + naddr_ntoa(FROM_NADDR)); return; } switch (rip->rip_cmd) { case RIPCMD_REQUEST: - /* did the request come from a router? + /* For mere requests, be a little sloppy about the source */ - if (from->sin_port == htons(RIP_PORT)) { - /* yes, ignore it if RIP is off so that it does not - * depend on us. - */ - if (rip_sock < 0) { - trace_pkt("ignore request while RIP off\n"); + if (aifp == 0) + aifp = sifp; + + /* Are we talking to ourself or a remote gateway? + */ + ifp1 = ifwithaddr(FROM_NADDR, 0, 1); + if (ifp1) { + if (ifp1->int_state & IS_REMOTE) { + /* remote gateway */ + aifp = ifp1; + if (check_remote(aifp)) { + aifp->int_act_time = now.tv_sec; + (void)if_ok(aifp, "remote "); + } + } else if (from->sin_port == htons(RIP_PORT)) { + trace_pkt(" discard our own RIP request"); return; } + } - /* Ignore the request if we talking to ourself - * (and not a remote gateway). + /* did the request come from a router? + */ + if (from->sin_port == htons(RIP_PORT)) { + /* yes, ignore the request if RIP is off so that + * the router does not depend on us. */ - if (ifwithaddr(FROM_NADDR, 0, 0) != 0) { - trace_pkt("discard our own RIP request\n"); + if (rip_sock < 0 + || (aifp != 0 + && IS_RIP_OUT_OFF(aifp->int_state))) { + trace_pkt(" discard request while RIP off"); return; } } /* According to RFC 1723, we should ignore unathenticated * queries. That is too silly to bother with. Sheesh! - * Are forwarding tables supposed to be secret? When - * a bad guy can infer them with test traffic? + * Are forwarding tables supposed to be secret, when + * a bad guy can infer them with test traffic? When RIP + * is still the most common router-discovery protocol + * and so hosts need to send queries that will be answered? + * What about `rtquery`? * Maybe on firewalls you'd care, but not enough to * give up the diagnostic facilities of remote probing. */ - if (n >= lim - || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - if (from->sin_addr.s_addr != bad_len) - msglog("request of bad length (%d) from %s", - size, naddr_ntoa(FROM_NADDR)); - bad_len = from->sin_addr.s_addr; + if (n >= lim) { + msglim(&bad_len, FROM_NADDR, "empty request from %s", + naddr_ntoa(FROM_NADDR)); + return; + } + if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { + msglim(&bad_len, FROM_NADDR, + "request of bad length (%d) from %s", + cc, naddr_ntoa(FROM_NADDR)); + } + + if (rip->rip_vers == RIPv2 + && (aifp == 0 || (aifp->int_state & IS_NO_RIPV1_OUT))) { + v12buf.buf->rip_vers = RIPv2; + /* If we have a secret but it is a cleartext secret, + * do not disclose our secret unless the other guy + * already knows it. + */ + if (aifp != 0 + && aifp->int_auth.type == RIP_AUTH_PW + && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth)) + ap = 0; + else + ap = find_auth(aifp); + } else { + v12buf.buf->rip_vers = RIPv1; + ap = 0; } - for (; n < lim; n++) { - n->n_metric = ntohl(n->n_metric); + clr_ws_buf(&v12buf, ap, aifp); + + do { + NTOHL(n->n_metric); /* A single entry with family RIP_AF_UNSPEC and * metric HOPCNT_INFINITY means "all routes". @@ -193,17 +284,16 @@ input(struct sockaddr_in *from, /* received from this IP address */ * (i.e. a query). */ if (n->n_family == RIP_AF_UNSPEC - && n->n_metric == HOPCNT_INFINITY - && n == rip->rip_nets - && n+1 == lim) { + && n->n_metric == HOPCNT_INFINITY) { if (from->sin_port != htons(RIP_PORT)) { /* Answer a query from a utility * program with all we know. */ - supply(from, sifp, OUT_QUERY, 0, - rip->rip_vers); + supply(from, aifp, OUT_QUERY, 0, + rip->rip_vers, ap != 0); return; } + /* A router trying to prime its tables. * Filter the answer in the about same way * broadcasts are filtered. @@ -216,91 +306,115 @@ input(struct sockaddr_in *from, /* received from this IP address */ * the remote router from getting the wrong * initial idea of the routes we send. */ + if (aifp == 0) { + trace_pkt("ignore distant router"); + return; + } if (!supplier - || aifp == 0 - || (aifp->int_state & IS_PASSIVE) - || (aifp->int_state & IS_ALIAS) - || ((aifp->int_state & IS_NO_RIPV1_OUT) - && (aifp->int_state&IS_NO_RIPV2_OUT))) + || IS_RIP_OFF(aifp->int_state)) { + trace_pkt("ignore; not supplying"); return; + } supply(from, aifp, OUT_UNICAST, 0, (aifp->int_state&IS_NO_RIPV1_OUT) - ? RIPv2 : RIPv1); + ? RIPv2 : RIPv1, + ap != 0); return; } + /* Ignore authentication */ + if (n->n_family == RIP_AF_AUTH) + continue; + if (n->n_family != RIP_AF_INET) { - if (from->sin_addr.s_addr != bad_router) - msglog("request from %s" - " for unsupported (af %d) %s", - naddr_ntoa(FROM_NADDR), - ntohs(n->n_family), - naddr_ntoa(n->n_dst)); - bad_router = from->sin_addr.s_addr; + msglim(&bad_router, FROM_NADDR, + "request from %s for unsupported (af" + " %d) %s", + naddr_ntoa(FROM_NADDR), + ntohs(n->n_family), + naddr_ntoa(n->n_dst)); return; } + /* We are being asked about a specific destination. + */ dst = n->n_dst; if (!check_dst(dst)) { - if (from->sin_addr.s_addr != bad_router) - msglog("bad queried destination" - " %s from %s", - naddr_ntoa(dst), - naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; + msglim(&bad_router, FROM_NADDR, + "bad queried destination %s from %s", + naddr_ntoa(dst), + naddr_ntoa(FROM_NADDR)); return; } + /* decide what mask was intended */ if (rip->rip_vers == RIPv1 || 0 == (mask = ntohl(n->n_mask)) || 0 != (ntohl(dst) & ~mask)) - mask = ripv1_mask_host(dst,sifp); + mask = ripv1_mask_host(dst, aifp); + /* try to find the answer */ rt = rtget(dst, mask); if (!rt && dst != RIP_DEFAULT) rt = rtfind(n->n_dst); - n->n_tag = 0; - n->n_nhop = 0; - if (rip->rip_vers == RIPv1) { - n->n_mask = 0; - } else { - n->n_mask = mask; - } + if (v12buf.buf->rip_vers != RIPv1) + v12buf.n->n_mask = mask; if (rt == 0) { - n->n_metric = HOPCNT_INFINITY; + /* we do not have the answer */ + v12buf.n->n_metric = HOPCNT_INFINITY; } else { - n->n_metric = rt->rt_metric+1; - n->n_metric += (sifp!=0)?sifp->int_metric : 1; - if (n->n_metric > HOPCNT_INFINITY) - n->n_metric = HOPCNT_INFINITY; - if (rip->rip_vers != RIPv1) { - n->n_tag = rt->rt_tag; - if (sifp != 0 + /* we have the answer, so compute the + * right metric and next hop. + */ + v12buf.n->n_family = RIP_AF_INET; + v12buf.n->n_dst = dst; + v12buf.n->n_metric = (rt->rt_metric+1 + + ((aifp!=0) + ? aifp->int_metric + : 1)); + if (v12buf.n->n_metric > HOPCNT_INFINITY) + v12buf.n->n_metric = HOPCNT_INFINITY; + if (v12buf.buf->rip_vers != RIPv1) { + v12buf.n->n_tag = rt->rt_tag; + v12buf.n->n_mask = mask; + if (aifp != 0 && on_net(rt->rt_gate, - sifp->int_net, - sifp->int_mask) - && rt->rt_gate != sifp->int_addr) - n->n_nhop = rt->rt_gate; + aifp->int_net, + aifp->int_mask) + && rt->rt_gate != aifp->int_addr) + v12buf.n->n_nhop = rt->rt_gate; } } - HTONL(n->n_metric); - } - /* Answer about specific routes. - * Only answer a router if we are a supplier - * to keep an unwary host that is just starting - * from picking us an a router. + HTONL(v12buf.n->n_metric); + + /* Stop paying attention if we fill the output buffer. + */ + if (++v12buf.n >= v12buf.lim) + break; + } while (++n < lim); + + /* Send the answer about specific routes. */ - rip->rip_cmd = RIPCMD_RESPONSE; - rip->rip_res1 = 0; - if (rip->rip_vers != RIPv1) - rip->rip_vers = RIPv2; + if (ap != 0 && aifp->int_auth.type == RIP_AUTH_MD5) + end_md5_auth(&v12buf, ap); + if (from->sin_port != htons(RIP_PORT)) { /* query */ - (void)output(OUT_QUERY, from, sifp, rip, size); + (void)output(OUT_QUERY, from, aifp, + v12buf.buf, + ((char *)v12buf.n - (char*)v12buf.buf)); } else if (supplier) { - (void)output(OUT_UNICAST, from, sifp, rip, size); + (void)output(OUT_UNICAST, from, aifp, + v12buf.buf, + ((char *)v12buf.n - (char*)v12buf.buf)); + } else { + /* Only answer a router if we are a supplier + * to keep an unwary host that is just starting + * from picking us an a router. + */ + ; } return; @@ -318,7 +432,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ return; } if (rip->rip_cmd == RIPCMD_TRACEON) { - rip->rip_tracefile[size-4] = '\0'; + rip->rip_tracefile[cc-4] = '\0'; trace_on((char*)rip->rip_tracefile, 0); } else { trace_off("tracing turned off by %s\n", @@ -327,21 +441,22 @@ input(struct sockaddr_in *from, /* received from this IP address */ return; case RIPCMD_RESPONSE: - if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { - if (from->sin_addr.s_addr != bad_len) - msglog("response of bad length (%d) from %s", - size, naddr_ntoa(FROM_NADDR)); - bad_len = from->sin_addr.s_addr; + if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) { + msglim(&bad_len, FROM_NADDR, + "response of bad length (%d) from %s", + cc, naddr_ntoa(FROM_NADDR)); } /* verify message came from a router */ if (from->sin_port != ntohs(RIP_PORT)) { - trace_pkt("discard RIP response from unknown port\n"); + msglim(&bad_router, FROM_NADDR, + " discard RIP response from unknown port" + " %d", from->sin_port); return; } if (rip_sock < 0) { - trace_pkt("discard response while RIP off\n"); + trace_pkt(" discard response while RIP off"); return; } @@ -350,50 +465,47 @@ input(struct sockaddr_in *from, /* received from this IP address */ ifp1 = ifwithaddr(FROM_NADDR, 0, 1); if (ifp1) { if (ifp1->int_state & IS_REMOTE) { - if (ifp1->int_state & IS_PASSIVE) { - msglog("bogus input from %s on" - " supposedly passive %s", - naddr_ntoa(FROM_NADDR), - ifp1->int_name); - } else { - ifp1->int_act_time = now.tv_sec; - if (if_ok(ifp1, "remote ")) - addrouteforif(ifp1); + /* remote gateway */ + aifp = ifp1; + if (check_remote(aifp)) { + aifp->int_act_time = now.tv_sec; + (void)if_ok(aifp, "remote "); } } else { - trace_pkt("discard our own RIP response\n"); + trace_pkt(" discard our own RIP response"); + return; } - return; } - /* Check the router from which message originated. We accept - * routing packets from routers directly connected via - * broadcast or point-to-point networks, and from + /* Accept routing packets from routers directly connected + * via broadcast or point-to-point networks, and from * those listed in /etc/gateways. */ - if (!aifp) { - if (from->sin_addr.s_addr != unk_router) - msglog("discard packet from unknown router %s" - " or via unidentified interface", - naddr_ntoa(FROM_NADDR)); - unk_router = from->sin_addr.s_addr; + if (aifp == 0) { + msglim(&unk_router, FROM_NADDR, + " discard response from %s" + " via unexpected interface", + naddr_ntoa(FROM_NADDR)); return; } - if (aifp->int_state & IS_PASSIVE) { - trace_act("discard packet from %s" - " via passive interface %s\n", - naddr_ntoa(FROM_NADDR), - aifp->int_name); + if (IS_RIP_IN_OFF(aifp->int_state)) { + trace_pkt(" discard RIPv%d response" + " via disabled interface %s", + rip->rip_vers, aifp->int_name); + return; + } + + if (n >= lim) { + msglim(&bad_len, FROM_NADDR, "empty response from %s", + naddr_ntoa(FROM_NADDR)); return; } - /* Check required version - */ if (((aifp->int_state & IS_NO_RIPV1_IN) && rip->rip_vers == RIPv1) || ((aifp->int_state & IS_NO_RIPV2_IN) && rip->rip_vers != RIPv1)) { - trace_pkt("discard RIPv%d response\n", + trace_pkt(" discard RIPv%d response", rip->rip_vers); return; } @@ -401,35 +513,39 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* Ignore routes via dead interface. */ if (aifp->int_state & IS_BROKE) { - trace_pkt("discard response via broken interface %s\n", + trace_pkt("%sdiscard response via broken interface %s", aifp->int_name); return; } - /* Authenticate the packet if we have a secret. + /* If the interface cares, ignore bad routers. + * Trace but do not log this problem because when it + * happens it happens a lot. */ - if (aifp->int_passwd[0] != '\0') { - if (n >= lim - || n->n_family != RIP_AF_AUTH - || ((struct netauth*)n)->a_type != RIP_AUTH_PW) { - if (from->sin_addr.s_addr != use_auth) - msglog("missing password from %s", - naddr_ntoa(FROM_NADDR)); - use_auth = from->sin_addr.s_addr; - return; + if (aifp->int_state & IS_DISTRUST) { + struct tgate *tg = tgates; + while (tg->tgate_addr != FROM_NADDR) { + tg = tg->tgate_next; + if (tg == 0) { + trace_pkt(" discard RIP response" + " from untrusted router %s", + naddr_ntoa(FROM_NADDR)); + return; + } + } + } - } else if (0 != bcmp(((struct netauth*)n)->au.au_pw, - aifp->int_passwd, - sizeof(aifp->int_passwd))) { - if (from->sin_addr.s_addr != use_auth) - msglog("bad password from %s", - naddr_ntoa(FROM_NADDR)); - use_auth = from->sin_addr.s_addr; + /* Authenticate the packet if we have a secret. + * If we do not, ignore the silliness in RFC 1723 + * and accept it regardless. + */ + if (aifp->int_auth.type != RIP_AUTH_NONE + && rip->rip_vers != RIPv1) { + if (!ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth)) return; - } } - for (; n < lim; n++) { + do { if (n->n_family == RIP_AF_AUTH) continue; @@ -438,39 +554,35 @@ input(struct sockaddr_in *from, /* received from this IP address */ if (n->n_family != RIP_AF_INET && (n->n_family != RIP_AF_UNSPEC || dst != RIP_DEFAULT)) { - if (from->sin_addr.s_addr != bad_router) - msglog("route from %s to unsupported" - " address family %d," - " destination %s", - naddr_ntoa(FROM_NADDR), - n->n_family, - naddr_ntoa(dst)); - bad_router = from->sin_addr.s_addr; + msglim(&bad_router, FROM_NADDR, + "route from %s to unsupported" + " address family=%d destination=%s", + naddr_ntoa(FROM_NADDR), + n->n_family, + naddr_ntoa(dst)); continue; } if (!check_dst(dst)) { - if (from->sin_addr.s_addr != bad_router) - msglog("bad destination %s from %s", - naddr_ntoa(dst), - naddr_ntoa(FROM_NADDR)); - bad_router = from->sin_addr.s_addr; + msglim(&bad_router, FROM_NADDR, + "bad destination %s from %s", + naddr_ntoa(dst), + naddr_ntoa(FROM_NADDR)); return; } if (n->n_metric == 0 || n->n_metric > HOPCNT_INFINITY) { - if (from->sin_addr.s_addr != bad_router) - msglog("bad metric %d from %s" - " for destination %s", - n->n_metric, - naddr_ntoa(FROM_NADDR), - naddr_ntoa(dst)); - bad_router = from->sin_addr.s_addr; + msglim(&bad_router, FROM_NADDR, + "bad metric %d from %s" + " for destination %s", + n->n_metric, + naddr_ntoa(FROM_NADDR), + naddr_ntoa(dst)); return; } /* Notice the next-hop. */ - gate = from->sin_addr.s_addr; + gate = FROM_NADDR; if (n->n_nhop != 0) { if (rip->rip_vers == RIPv2) { n->n_nhop = 0; @@ -481,14 +593,13 @@ input(struct sockaddr_in *from, /* received from this IP address */ && check_dst(n->n_nhop)) { gate = n->n_nhop; } else { - if (bad_nhop != from->sin_addr.s_addr) - msglog("router %s to %s has" - " bad next hop %s", - naddr_ntoa(FROM_NADDR), - naddr_ntoa(dst), - naddr_ntoa(n->n_nhop)); - bad_nhop = from->sin_addr.s_addr; - n->n_nhop = 0; + msglim(&bad_nhop, FROM_NADDR, + "router %s to %s" + " has bad next hop %s", + naddr_ntoa(FROM_NADDR), + naddr_ntoa(dst), + naddr_ntoa(n->n_nhop)); + n->n_nhop = 0; } } } @@ -497,14 +608,12 @@ input(struct sockaddr_in *from, /* received from this IP address */ || 0 == (mask = ntohl(n->n_mask))) { mask = ripv1_mask_host(dst,aifp); } else if ((ntohl(dst) & ~mask) != 0) { - if (bad_mask != from->sin_addr.s_addr) { - msglog("router %s sent bad netmask" - " %#x with %s", - naddr_ntoa(FROM_NADDR), - mask, - naddr_ntoa(dst)); - bad_mask = from->sin_addr.s_addr; - } + msglim(&bad_mask, FROM_NADDR, + "router %s sent bad netmask" + " %#x with %s", + naddr_ntoa(FROM_NADDR), + mask, + naddr_ntoa(dst)); continue; } if (rip->rip_vers == RIPv1) @@ -548,9 +657,9 @@ input(struct sockaddr_in *from, /* received from this IP address */ * of the defense against RS_NET_SYN. */ if (have_ripv1_out - && (v1_mask = ripv1_mask_net(dst,0)) > mask && (((rt = rtget(dst,mask)) == 0 - || !(rt->rt_state & RS_NET_SYN)))) { + || !(rt->rt_state & RS_NET_SYN))) + && (v1_mask = ripv1_mask_net(dst,0)) > mask) { ddst_h = v1_mask & -v1_mask; i = (v1_mask & ~mask)/ddst_h; if (i >= 511) { @@ -579,9 +688,10 @@ input(struct sockaddr_in *from, /* received from this IP address */ break; dst = htonl(ntohl(dst) + ddst_h); } - } + } while (++n < lim); break; } +#undef FROM_NADDR } @@ -610,7 +720,8 @@ input_route(struct interface *ifp, */ ifp1 = ifwithaddr(dst, 1, 1); if (ifp1 != 0 - && !(ifp1->int_state & IS_BROKE)) + && (!(ifp1->int_state & IS_BROKE) + || (ifp1->int_state & IS_PASSIVE))) return; /* Look for the route in our table. @@ -739,3 +850,85 @@ input_route(struct interface *ifp, /* try to switch to a better route */ rtswitch(rt, rts); } + + +static int /* 0 if bad */ +ck_passwd(struct interface *aifp, + struct rip *rip, + void *lim, + naddr from, + struct msg_limit *use_authp) +{ +# define NA (rip->rip_auths) +# define DAY (24*60*60) + struct netauth *na2; + struct auth_key *akp = aifp->int_auth.keys; + MD5_CTX md5_ctx; + u_char hash[RIP_AUTH_PW_LEN]; + int i; + + + if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) { + msglim(use_authp, from, "missing password from %s", + naddr_ntoa(from)); + return 0; + } + + if (NA->a_type != aifp->int_auth.type) { + msglim(use_authp, from, "wrong type of password from %s", + naddr_ntoa(from)); + return 0; + } + + if (NA->a_type == RIP_AUTH_PW) { + /* accept any current cleartext password + */ + for (i = 0; i < MAX_AUTH_KEYS; i++, akp++) { + if ((u_long)akp->start-DAY > (u_long)clk.tv_sec + || (u_long)akp->end+DAY < (u_long)clk.tv_sec) + continue; + + if (!bcmp(NA->au.au_pw, akp->key, RIP_AUTH_PW_LEN)) + return 1; + } + + } else { + /* accept any current MD5 secret with the right key ID + */ + for (i = 0; i < MAX_AUTH_KEYS; i++, akp++) { + if (NA->au.a_md5.md5_keyid == akp->keyid + && (u_long)akp->start-DAY <= (u_long)clk.tv_sec + && (u_long)akp->end+DAY >= (u_long)clk.tv_sec) + break; + } + + if (i < MAX_AUTH_KEYS) { + na2 = (struct netauth *)((char *)(NA+1) + + NA->au.a_md5.md5_pkt_len); + if (NA->au.a_md5.md5_pkt_len % sizeof(*NA) != 0 + || lim < (void *)(na2+1)) { + msglim(use_authp, from, + "bad MD5 RIP-II pkt length %d from %s", + NA->au.a_md5.md5_pkt_len, + naddr_ntoa(from)); + return 0; + } + MD5Init(&md5_ctx); + MD5Update(&md5_ctx, (u_char *)NA, + (char *)na2->au.au_pw - (char *)NA); + MD5Update(&md5_ctx, + (u_char *)akp->key, sizeof(akp->key)); + MD5Final(hash, &md5_ctx); + if (na2->a_family == RIP_AF_AUTH + && na2->a_type == 1 + && NA->au.a_md5.md5_auth_len == RIP_AUTH_PW_LEN + && !bcmp(hash, na2->au.au_pw, sizeof(hash))) + return 1; + } + } + + msglim(use_authp, from, "bad password from %s", + naddr_ntoa(from)); + return 0; +#undef NA +} |