summaryrefslogtreecommitdiffstats
path: root/sbin/routed/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/routed/input.c')
-rw-r--r--sbin/routed/input.c615
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
+}
OpenPOWER on IntegriCloud