diff options
author | Mark Murray <markm@FreeBSD.org> | 1999-05-02 10:51:54 +0000 |
---|---|---|
committer | Mark Murray <markm@FreeBSD.org> | 1999-05-02 10:51:54 +0000 |
commit | 2c7a97817b8e83a80ed67bbeb294334140b7d26d (patch) | |
tree | c0dd10cc2471be0527b6700410ae4edfbb6d940c /sbin/routed/input.c | |
parent | cdb877c33d6cc233b12f3f889f372a15d70559e4 (diff) | |
download | src-test2-2c7a97817b8e83a80ed67bbeb294334140b7d26d.tar.gz src-test2-2c7a97817b8e83a80ed67bbeb294334140b7d26d.zip |
Notes
Diffstat (limited to 'sbin/routed/input.c')
-rw-r--r-- | sbin/routed/input.c | 271 |
1 files changed, 176 insertions, 95 deletions
diff --git a/sbin/routed/input.c b/sbin/routed/input.c index 0e2c16fd7414..55162fcd87be 100644 --- a/sbin/routed/input.c +++ b/sbin/routed/input.c @@ -11,7 +11,7 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: + * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors @@ -31,19 +31,19 @@ * SUCH DAMAGE. */ -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; +#include "defs.h" + +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)input.c 8.1 (Berkeley) 6/5/93"; #elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; +#include <sys/cdefs.h> +__RCSID("$NetBSD$"); #endif -#ident "$Revision: 1.21 $" - -#include "defs.h" +#ident "$Revision: 2.17 $" 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 void input_route(naddr, naddr, struct rt_spare *, struct netinfo *); static int ck_passwd(struct interface *, struct rip *, void *, naddr, struct msg_limit *); @@ -140,14 +140,17 @@ input(struct sockaddr_in *from, /* received from this IP address */ { # define FROM_NADDR from->sin_addr.s_addr static struct msg_limit use_auth, bad_len, bad_mask; - static struct msg_limit unk_router, bad_router, bad_nhop; + static struct msg_limit unk_router, bad_router, bad_nhop; struct rt_entry *rt; + struct rt_spare new; struct netinfo *n, *lim; struct interface *ifp1; - naddr gate, mask, v1_mask, dst, ddst_h; + naddr gate, mask, v1_mask, dst, ddst_h = 0; struct auth *ap; - int i; + struct tgate *tg = 0; + struct tgate_net *tn; + int i, j; /* Notice when we hear from a remote gateway */ @@ -165,7 +168,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ } else if (rip->rip_vers > RIPv2) { rip->rip_vers = RIPv2; } - if (cc > OVER_MAXPACKETSIZE) { + if (cc > (int)OVER_MAXPACKETSIZE) { msglim(&bad_router, FROM_NADDR, "packet at least %d bytes too long received from %s", cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR)); @@ -181,7 +184,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ * * 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 + * not be able to listen to RIPv2 packets with authentication, while * RIPv1 systems will listen? Crazy! */ if (!auth_ok @@ -231,7 +234,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ } } - /* According to RFC 1723, we should ignore unathenticated + /* According to RFC 1723, we should ignore unauthenticated * 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? When RIP @@ -282,10 +285,10 @@ input(struct sockaddr_in *from, /* received from this IP address */ */ if (n->n_family == RIP_AF_UNSPEC && n->n_metric == HOPCNT_INFINITY) { + /* Answer a query from a utility program + * with all we know. + */ if (from->sin_port != htons(RIP_PORT)) { - /* Answer a query from a utility - * program with all we know. - */ supply(from, aifp, OUT_QUERY, 0, rip->rip_vers, ap != 0); return; @@ -297,11 +300,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ * * Only answer a router if we are a supplier * to keep an unwary host that is just starting - * from picking us as a router. Respond with - * RIPv1 instead of RIPv2 if that is what we - * are broadcasting on the interface to keep - * the remote router from getting the wrong - * initial idea of the routes we send. + * from picking us as a router. */ if (aifp == 0) { trace_pkt("ignore distant router"); @@ -313,8 +312,36 @@ input(struct sockaddr_in *from, /* received from this IP address */ return; } + /* Do not answer a RIPv1 router if + * we are sending RIPv2. But do offer + * poor man's router discovery. + */ + if ((aifp->int_state & IS_NO_RIPV1_OUT) + && rip->rip_vers == RIPv1) { + if (!(aifp->int_state & IS_PM_RDISC)) { + trace_pkt("ignore; sending RIPv2"); + return; + } + + v12buf.n->n_family = RIP_AF_INET; + v12buf.n->n_dst = RIP_DEFAULT; + i = aifp->int_d_metric; + if (0 != (rt = rtget(RIP_DEFAULT, 0))) + i = MIN(i, (rt->rt_metric + +aifp->int_metric+1)); + v12buf.n->n_metric = htonl(i); + v12buf.n++; + break; + } + + /* Respond with RIPv1 instead of RIPv2 if + * that is what we are broadcasting on the + * interface to keep the remote router from + * getting the wrong initial idea of the + * routes we send. + */ supply(from, aifp, OUT_UNICAST, 0, - (aifp->int_state&IS_NO_RIPV1_OUT) + (aifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1, ap != 0); return; @@ -326,8 +353,8 @@ input(struct sockaddr_in *from, /* received from this IP address */ if (n->n_family != RIP_AF_INET) { msglim(&bad_router, FROM_NADDR, - "request from %s for unsupported (af" - " %d) %s", + "request from %s for unsupported" + " (af %d) %s", naddr_ntoa(FROM_NADDR), ntohs(n->n_family), naddr_ntoa(n->n_dst)); @@ -417,7 +444,13 @@ input(struct sockaddr_in *from, /* received from this IP address */ case RIPCMD_TRACEON: case RIPCMD_TRACEOFF: - /* verify message came from a privileged port */ + /* Notice that trace messages are turned off for all possible + * abuse if _PATH_TRACE is undefined in pathnames.h. + * Notice also that because of the way the trace file is + * handled in trace.c, no abuse is plausible even if + * _PATH_TRACE_ is defined. + * + * First verify message came from a privileged port. */ if (ntohs(from->sin_port) > IPPORT_RESERVED) { msglog("trace command from untrusted port on %s", naddr_ntoa(FROM_NADDR)); @@ -433,7 +466,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ set_tracefile((char*)rip->rip_tracefile, "trace command: %s\n", 0); } else { - trace_off("tracing turned off by %s\n", + trace_off("tracing turned off by %s", naddr_ntoa(FROM_NADDR)); } return; @@ -511,7 +544,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* Ignore routes via dead interface. */ if (aifp->int_state & IS_BROKE) { - trace_pkt("%sdiscard response via broken interface %s", + trace_pkt("discard response via broken interface %s", aifp->int_name); return; } @@ -521,7 +554,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ * happens, it happens frequently. */ if (aifp->int_state & IS_DISTRUST) { - struct tgate *tg = tgates; + tg = tgates; while (tg->tgate_addr != FROM_NADDR) { tg = tg->tgate_next; if (tg == 0) { @@ -581,7 +614,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ */ gate = FROM_NADDR; if (n->n_nhop != 0) { - if (rip->rip_vers == RIPv2) { + if (rip->rip_vers == RIPv1) { n->n_nhop = 0; } else { /* Use it only if it is valid. */ @@ -607,9 +640,9 @@ input(struct sockaddr_in *from, /* received from this IP address */ } else if ((ntohl(dst) & ~mask) != 0) { msglim(&bad_mask, FROM_NADDR, "router %s sent bad netmask" - " %#x with %s", + " %#lx with %s", naddr_ntoa(FROM_NADDR), - mask, + (u_long)mask, naddr_ntoa(dst)); continue; } @@ -622,6 +655,20 @@ input(struct sockaddr_in *from, /* received from this IP address */ if (n->n_metric > HOPCNT_INFINITY) n->n_metric = HOPCNT_INFINITY; + /* Should we trust this route from this router? */ + if (tg && (tn = tg->tgate_nets)->mask != 0) { + for (i = 0; i < MAX_TGATE_NETS; i++, tn++) { + if (on_net(dst, tn->net, tn->mask) + && tn->mask <= mask) + break; + } + if (i >= MAX_TGATE_NETS || tn->mask == 0) { + trace_pkt(" ignored unauthorized %s", + addrname(dst,mask,0)); + continue; + } + } + /* Recognize and ignore a default route we faked * which is being sent back to us by a machine with * broken split-horizon. @@ -630,7 +677,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ */ if (aifp->int_d_metric != 0 && dst == RIP_DEFAULT - && n->n_metric >= aifp->int_d_metric) + && (int)n->n_metric >= aifp->int_d_metric) continue; /* We can receive aggregated RIPv2 routes that must @@ -663,13 +710,12 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* Punt if we would have to generate * an unreasonable number of routes. */ -#ifdef DEBUG - msglog("accept %s from %s as 1" - " instead of %d routes", - addrname(dst,mask,0), - naddr_ntoa(FROM_NADDR), - i+1); -#endif + if (TRACECONTENTS) + trace_misc("accept %s-->%s as 1" + " instead of %d routes", + addrname(dst,mask,0), + naddr_ntoa(FROM_NADDR), + i+1); i = 0; } else { mask = v1_mask; @@ -678,10 +724,17 @@ input(struct sockaddr_in *from, /* received from this IP address */ i = 0; } + new.rts_gate = gate; + new.rts_router = FROM_NADDR; + new.rts_metric = n->n_metric; + new.rts_tag = n->n_tag; + new.rts_time = now.tv_sec; + new.rts_ifp = aifp; + new.rts_de_ag = i; + j = 0; for (;;) { - input_route(aifp, FROM_NADDR, - dst, mask, gate, n); - if (i-- == 0) + input_route(dst, mask, &new, n); + if (++j > i) break; dst = htonl(ntohl(dst) + ddst_h); } @@ -695,18 +748,15 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* Process a single input route. */ static void -input_route(struct interface *ifp, - naddr from, - naddr dst, +input_route(naddr dst, /* network order */ naddr mask, - naddr gate, + struct rt_spare *new, struct netinfo *n) { int i; struct rt_entry *rt; struct rt_spare *rts, *rts0; struct interface *ifp1; - time_t new_time; /* See if the other guy is telling us to send our packets to him. @@ -730,7 +780,7 @@ input_route(struct interface *ifp, if (rt == 0) { /* Ignore unknown routes being poisoned. */ - if (n->n_metric == HOPCNT_INFINITY) + if (new->rts_metric == HOPCNT_INFINITY) return; /* Ignore the route if it points to us */ @@ -742,8 +792,7 @@ input_route(struct interface *ifp, * our memory, accept the new route. */ if (total_routes < MAX_ROUTES) - rtadd(dst, mask, gate, from, n->n_metric, - n->n_tag, 0, ifp); + rtadd(dst, mask, 0, new); return; } @@ -768,7 +817,7 @@ input_route(struct interface *ifp, rts0 = rt->rt_spares; for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) { - if (rts->rts_router == from) + if (rts->rts_router == new->rts_router) break; /* Note the worst slot to reuse, * other than the current slot. @@ -778,26 +827,34 @@ input_route(struct interface *ifp, rts0 = rts; } if (i != 0) { - /* Found the router + /* Found a route from the router already in the table. + */ + + /* If the new route is a route broken down from an + * aggregated route, and if the previous route is either + * not a broken down route or was broken down from a finer + * netmask, and if the previous route is current, + * then forget this one. */ - int old_metric = rts->rts_metric; + if (new->rts_de_ag > rts->rts_de_ag + && now_stale <= rts->rts_time) + return; /* Keep poisoned routes around only long enough to pass - * the poison on. Get a new timestamp for good routes. + * the poison on. Use a new timestamp for good routes. */ - new_time =((old_metric == HOPCNT_INFINITY) - ? rts->rts_time - : now.tv_sec); + if (rts->rts_metric == HOPCNT_INFINITY + && new->rts_metric == HOPCNT_INFINITY) + new->rts_time = rts->rts_time; /* If this is an update for the router we currently prefer, * then note it. */ if (i == NUM_SPARES) { - rtchange(rt,rt->rt_state, gate,rt->rt_router, - n->n_metric, n->n_tag, ifp, new_time, 0); + rtchange(rt, rt->rt_state, new, 0); /* If the route got worse, check for something better. */ - if (n->n_metric > old_metric) + if (new->rts_metric > rts->rts_metric) rtswitch(rt, 0); return; } @@ -805,10 +862,17 @@ input_route(struct interface *ifp, /* This is an update for a spare route. * Finished if the route is unchanged. */ - if (rts->rts_gate == gate - && old_metric == n->n_metric - && rts->rts_tag == n->n_tag) { - rts->rts_time = new_time; + if (rts->rts_gate == new->rts_gate + && rts->rts_metric == new->rts_metric + && rts->rts_tag == new->rts_tag) { + trace_upslot(rt, rts, new); + *rts = *new; + return; + } + /* Forget it if it has gone bad. + */ + if (new->rts_metric == HOPCNT_INFINITY) { + rts_delete(rt, rts); return; } @@ -822,6 +886,7 @@ input_route(struct interface *ifp, && 0 != ifwithaddr(n->n_nhop, 1, 0)) return; + /* the loop above set rts0=worst spare */ rts = rts0; /* Save the route as a spare only if it has @@ -829,20 +894,12 @@ input_route(struct interface *ifp, * This also ignores poisoned routes (those * received with metric HOPCNT_INFINITY). */ - if (n->n_metric >= rts->rts_metric) + if (new->rts_metric >= rts->rts_metric) return; - - new_time = now.tv_sec; } - trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time); - - rts->rts_gate = gate; - rts->rts_router = from; - rts->rts_metric = n->n_metric; - rts->rts_tag = n->n_tag; - rts->rts_time = new_time; - rts->rts_ifp = ifp; + trace_upslot(rt, rts, new); + *rts = *new; /* try to switch to a better route */ rtswitch(rt, rts); @@ -861,7 +918,7 @@ ck_passwd(struct interface *aifp, struct auth *ap; MD5_CTX md5_ctx; u_char hash[RIP_AUTH_PW_LEN]; - int i; + int i, len; if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) { @@ -879,7 +936,7 @@ ck_passwd(struct interface *aifp, continue; if (NA->a_type == RIP_AUTH_PW) { - if (!bcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN)) + if (!memcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN)) return 1; } else { @@ -888,28 +945,52 @@ ck_passwd(struct interface *aifp, if (NA->au.a_md5.md5_keyid != ap->keyid) continue; - 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)) { + len = ntohs(NA->au.a_md5.md5_pkt_len); + if ((len-sizeof(*rip)) % sizeof(*NA) != 0 + || len != (char *)lim-(char*)rip-(int)sizeof(*NA)) { msglim(use_authp, from, - "bad MD5 RIP-II pkt length %d from %s", - NA->au.a_md5.md5_pkt_len, + "wrong MD5 RIPv2 packet length of %d" + " instead of %d from %s", + len, (int)((char *)lim-(char *)rip + -sizeof(*NA)), naddr_ntoa(from)); return 0; } + na2 = (struct netauth *)((char *)rip+len); + + /* Given a good hash value, these are not security + * problems so be generous and accept the routes, + * after complaining. + */ + if (TRACEPACKETS) { + if (NA->au.a_md5.md5_auth_len + != RIP_AUTH_MD5_LEN) + msglim(use_authp, from, + "unknown MD5 RIPv2 auth len %#x" + " instead of %#x from %s", + NA->au.a_md5.md5_auth_len, + RIP_AUTH_MD5_LEN, + naddr_ntoa(from)); + if (na2->a_family != RIP_AF_AUTH) + msglim(use_authp, from, + "unknown MD5 RIPv2 family %#x" + " instead of %#x from %s", + na2->a_family, RIP_AF_AUTH, + naddr_ntoa(from)); + if (na2->a_type != ntohs(1)) + msglim(use_authp, from, + "MD5 RIPv2 hash has %#x" + " instead of %#x from %s", + na2->a_type, ntohs(1), + naddr_ntoa(from)); + } + MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)NA, - (char *)na2->au.au_pw - (char *)NA); - MD5Update(&md5_ctx, - (u_char *)ap->key, sizeof(ap->key)); + MD5Update(&md5_ctx, (u_char *)rip, len); + MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); 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 0; - return 1; + if (!memcmp(hash, na2->au.au_pw, sizeof(hash))) + return 1; } } |