+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
#ifndef lint
-static char sccsid[] = "@(#)input.c 4.5 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)input.c 5.7 (Berkeley) %G%";
+#endif not lint
/*
* Routing Table Management Daemon
*/
#include "defs.h"
+#include <sys/syslog.h>
/*
* Process a newly received packet.
struct sockaddr *from;
int size;
{
- struct rt_entry *rt;
- struct netinfo *n;
- struct interface *ifp;
+ register struct rt_entry *rt;
+ register struct netinfo *n;
+ register struct interface *ifp;
+ struct interface *if_ifwithdstaddr();
int newsize;
- struct afswitch *afp;
+ register struct afswitch *afp;
+ static struct sockaddr badfrom;
ifp = 0;
TRACE_INPUT(ifp, from, size);
- if (from->sa_family >= AF_MAX)
+ if (from->sa_family >= af_max ||
+ (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) {
+ syslog(LOG_INFO,
+ "\"from\" address in unsupported address family (%d), cmd %d\n",
+ from->sa_family, msg->rip_cmd);
return;
- afp = &afswitch[from->sa_family];
+ }
switch (msg->rip_cmd) {
case RIPCMD_REQUEST:
/*
* A single entry with sa_family == AF_UNSPEC and
* metric ``infinity'' means ``all routes''.
+ * We respond to routers only if we are acting
+ * as a supplier, or to anyone other than a router
+ * (eg, query).
*/
if (n->rip_dst.sa_family == AF_UNSPEC &&
n->rip_metric == HOPCNT_INFINITY && size == 0) {
- supply(from, 0, ifp);
+ if (supplier || (*afp->af_portmatch)(from) == 0)
+ supply(from, 0, 0);
return;
}
- rt = rtlookup(&n->rip_dst);
+ if (n->rip_dst.sa_family < af_max &&
+ afswitch[n->rip_dst.sa_family].af_hash)
+ rt = rtlookup(&n->rip_dst);
+ else
+ rt = 0;
n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
min(rt->rt_metric+1, HOPCNT_INFINITY);
if (msg->rip_vers > 0) {
case RIPCMD_TRACEON:
case RIPCMD_TRACEOFF:
- /* verify message came from a priviledged port */
+ /* verify message came from a privileged port */
if ((*afp->af_portcheck)(from) == 0)
return;
+ if (if_iflookup(from) == 0) {
+ syslog(LOG_ERR, "trace command from unknown router, %s",
+ (*afswitch[from->sa_family].af_format)(from));
+ return;
+ }
packet[size] = '\0';
if (msg->rip_cmd == RIPCMD_TRACEON)
traceon(msg->rip_tracefile);
ifp = if_ifwithaddr(from);
if (ifp) {
rt = rtfind(from);
- if (rt == 0)
+ if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0)
addrouteforif(ifp);
else
rt->rt_timer = 0;
return;
}
+ /*
+ * Update timer for interface on which the packet arrived.
+ * If from other end of a point-to-point link that isn't
+ * in the routing tables, (re-)add the route.
+ */
+ if ((rt = rtfind(from)) &&
+ (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
+ rt->rt_timer = 0;
+ else if (ifp = if_ifwithdstaddr(from))
+ addrouteforif(ifp);
+ else if (if_iflookup(from) == 0) {
+ if (bcmp((char *)from, (char *)&badfrom,
+ sizeof(badfrom)) != 0) {
+ syslog(LOG_ERR,
+ "packet from unknown router, %s",
+ (*afswitch[from->sa_family].af_format)(from));
+ badfrom = *from;
+ }
+ return;
+ }
size -= 4 * sizeof (char);
n = msg->rip_nets;
for (; size > 0; size -= sizeof (struct netinfo), n++) {
ntohs(n->rip_dst.sa_family);
n->rip_metric = ntohl(n->rip_metric);
}
- if (n->rip_metric >= HOPCNT_INFINITY)
+ if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
+ continue;
+ if (n->rip_dst.sa_family >= af_max ||
+ (afp = &afswitch[n->rip_dst.sa_family])->af_hash ==
+ (int (*)())0) {
+ syslog(LOG_INFO,
+ "route in unsupported address family (%d), from %s (af %d)\n",
+ n->rip_dst.sa_family,
+ (*afswitch[from->sa_family].af_format)(from),
+ from->sa_family);
+ continue;
+ }
+ if (((*afp->af_checkhost)(&n->rip_dst)) == 0) {
+ syslog(LOG_DEBUG,
+ "bad host in route from %s (af %d)\n",
+ (*afswitch[from->sa_family].af_format)(from),
+ from->sa_family);
continue;
+ }
rt = rtlookup(&n->rip_dst);
- if (rt == 0) {
- rtadd(&n->rip_dst, from, n->rip_metric, 0);
+ if (rt == 0 ||
+ (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
+ (RTS_INTERNAL|RTS_INTERFACE)) {
+ rt = rtfind(&n->rip_dst);
+ if (rt && equal(from, &rt->rt_router) &&
+ rt->rt_metric == n->rip_metric)
+ continue;
+ if (n->rip_metric < HOPCNT_INFINITY)
+ rtadd(&n->rip_dst, from, n->rip_metric, 0);
continue;
}
/*
- * Update if from gateway, shorter, or getting
- * stale and equivalent.
+ * Update if from gateway and different,
+ * shorter, or getting stale and equivalent.
*/
- if (equal(from, &rt->rt_router) ||
- n->rip_metric < rt->rt_metric ||
+ if (equal(from, &rt->rt_router)) {
+ if (n->rip_metric != rt->rt_metric)
+ rtchange(rt, from, n->rip_metric);
+ rt->rt_timer = 0;
+ } else if ((unsigned) (n->rip_metric) < rt->rt_metric ||
(rt->rt_timer > (EXPIRE_TIME/2) &&
rt->rt_metric == n->rip_metric)) {
rtchange(rt, from, n->rip_metric);