Exemplo n.º 1
0
/* display an address
 */
char *
addrname(naddr	addr,			/* in network byte order */
	 naddr	mask,
	 int	force)			/* 0=show mask if nonstandard, */
{					/*	1=always show mask, 2=never */
#define NUM_BUFS 4
	static int bufno;
	static struct {
	    char    str[15+20];
	} bufs[NUM_BUFS];
	char *s, *sp;
	naddr dmask;
	int i;

	s = strcpy(bufs[bufno].str, naddr_ntoa(addr));
	bufno = (bufno+1) % NUM_BUFS;

	if (force == 1 || (force == 0 && mask != std_mask(addr))) {
		sp = &s[strlen(s)];

		dmask = mask & -mask;
		if (mask + dmask == 0) {
			for (i = 0; i != 32 && ((1<<i) & mask) == 0; i++)
				continue;
			sprintf(sp, "/%d", 32-i);

		} else {
			sprintf(sp, " (mask %#x)", (u_int)mask);
		}
	}

	return s;
#undef NUM_BUFS
}
Exemplo n.º 2
0
/* display an address */
char *
addrname(in_addr_t addr,	/* in network byte order */
    in_addr_t	mask,
    int	force)			/* 0=show mask if nonstandard, */
{					/*	1=always show mask, 2=never */
#define	NUM_BUFS 4
	static int bufno;
	static struct {
	/*
	 * this array can hold either of the following strings terminated
	 * by a null character:
	 * "xxx.xxx.xxx.xxx/xx"
	 * "xxx.xxx.xxx.xxx (mask xxx.xxx.xxx.xxx)"
	 *
	 */
	    char    str[2*INET_ADDRSTRLEN + sizeof (" (mask )")];
	} bufs[NUM_BUFS];
	char *s, *sp;
	in_addr_t dmask;
	int i, len;
	struct in_addr tmp_addr;

	tmp_addr.s_addr = addr;
	len = strlcpy(bufs[bufno].str, inet_ntoa(tmp_addr),
	    sizeof (bufs[bufno].str));
	s = bufs[bufno].str;
	bufno = (bufno+1) % NUM_BUFS;

	if (force == 1 || (force == 0 && mask != std_mask(addr))) {
		sp = &s[strlen(s)];

		dmask = mask & -mask;
		if (mask + dmask == 0) {
			i = ffs(mask);
			(void) snprintf(sp,
			    (sizeof (bufs[bufno].str) - len), "/%d",
			    (NBBY * sizeof (in_addr_t) + 1) - i);

		} else {
			(void) snprintf(sp,
			    (sizeof (bufs[bufno].str) - len), " (mask %s)",
			    naddr_ntoa(htonl(mask)));
		}
	}

	return (s);
#undef NUM_BUFS
}
Exemplo n.º 3
0
/* Supply dst with the contents of the routing tables.
 * If this won't fit in one packet, chop it up into several.
 */
void
supply(struct sockaddr_in *dst,
       struct interface *ifp,		/* output interface */
       enum output_type type,
       int flash,			/* 1=flash update */
       int vers,			/* RIP version */
       int passwd_ok)			/* OK to include cleartext password */
{
	struct rt_entry *rt;
	int def_metric;


	ws.state = 0;
	ws.gen_limit = 1024;

	ws.to = *dst;
	ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr);
	ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask;

	if (ifp != NULL) {
		ws.to_mask = ifp->int_mask;
		ws.to_net = ifp->int_net;
		if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask))
			ws.state |= WS_ST_TO_ON_NET;

	} else {
		ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0);
		ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask;
		rt = rtfind(dst->sin_addr.s_addr);
		if (rt)
			ifp = rt->rt_ifp;
	}

	ws.npackets = 0;
	if (flash)
		ws.state |= WS_ST_FLASH;

	if ((ws.ifp = ifp) == NULL) {
		ws.metric = 1;
	} else {
		/* Adjust the advertised metric by the outgoing interface
		 * metric.
		 */
		ws.metric = ifp->int_metric+1;
	}

	ripv12_buf.rip.rip_vers = vers;

	switch (type) {
	case OUT_MULTICAST:
		if (ifp->int_if_flags & IFF_MULTICAST)
			v2buf.type = OUT_MULTICAST;
		else
			v2buf.type = NO_OUT_MULTICAST;
		v12buf.type = OUT_BROADCAST;
		break;

	case OUT_QUERY:
		ws.state |= WS_ST_QUERY;
		/* fall through */
	case OUT_BROADCAST:
	case OUT_UNICAST:
		v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
		v12buf.type = type;
		break;

	case NO_OUT_MULTICAST:
	case NO_OUT_RIPV2:
		break;			/* no output */
	}

	if (vers == RIPv2) {
		/* full RIPv2 only if cannot be heard by RIPv1 listeners */
		if (type != OUT_BROADCAST)
			ws.state |= WS_ST_RIP2_ALL;
		if ((ws.state & WS_ST_QUERY)
		    || !(ws.state & WS_ST_TO_ON_NET)) {
			ws.state |= (WS_ST_AG | WS_ST_SUPER_AG);
		} else if (ifp == NULL || !(ifp->int_state & IS_NO_AG)) {
			ws.state |= WS_ST_AG;
			if (type != OUT_BROADCAST
			    && (ifp == NULL
				|| !(ifp->int_state & IS_NO_SUPER_AG)))
				ws.state |= WS_ST_SUPER_AG;
		}
	}

	ws.a = (vers == RIPv2) ? find_auth(ifp) : 0;
	if (!passwd_ok && ws.a != NULL && ws.a->type == RIP_AUTH_PW)
		ws.a = NULL;
	clr_ws_buf(&v12buf,ws.a);
	clr_ws_buf(&v2buf,ws.a);

	/*  Fake a default route if asked and if there is not already
	 * a better, real default route.
	 */
	if (supplier && (def_metric = ifp->int_d_metric) != 0) {
		if (NULL == (rt = rtget(RIP_DEFAULT, 0))
		    || rt->rt_metric+ws.metric >= def_metric) {
			ws.state |= WS_ST_DEFAULT;
			ag_check(0, 0, 0, 0, def_metric, def_metric,
				 0, 0, 0, supply_out);
		} else {
			def_metric = rt->rt_metric+ws.metric;
		}

		/* If both RIPv2 and the poor-man's router discovery
		 * kludge are on, arrange to advertise an extra
		 * default route via RIPv1.
		 */
		if ((ws.state & WS_ST_RIP2_ALL)
		    && (ifp->int_state & IS_PM_RDISC)) {
			ripv12_buf.rip.rip_vers = RIPv1;
			v12buf.n->n_family = RIP_AF_INET;
			v12buf.n->n_dst = htonl(RIP_DEFAULT);
			v12buf.n->n_metric = htonl(def_metric);
			v12buf.n++;
		}
	}

	rn_walktree(rhead, walk_supply, 0);
	ag_flush(0,0,supply_out);

	/* Flush the packet buffers, provided they are not empty and
	 * do not contain only the password.
	 */
	if (v12buf.n != v12buf.base
	    && (v12buf.n > v12buf.base+1
		|| v12buf.base->n_family != RIP_AF_AUTH))
		supply_write(&v12buf);
	if (v2buf.n != v2buf.base
	    && (v2buf.n > v2buf.base+1
		|| v2buf.base->n_family != RIP_AF_AUTH))
		supply_write(&v2buf);

	/* If we sent nothing and this is an answer to a query, send
	 * an empty buffer.
	 */
	if (ws.npackets == 0
	    && (ws.state & WS_ST_QUERY))
		supply_write(&v12buf);
}
Exemplo n.º 4
0
/*
 * Read a list of gateways from /etc/gateways and add them to our tables.
 *
 * This file contains a list of "remote" gateways.  That is usually
 * a gateway which we cannot immediately determine if it is present or
 * not as we can do for those provided by directly connected hardware.
 *
 * If a gateway is marked "passive" in the file, then we assume it
 * does not understand RIP and assume it is always present.  Those
 * not marked passive are treated as if they were directly connected
 * and assumed to be broken if they do not send us advertisements.
 * All remote interfaces are added to our list, and those not marked
 * passive are sent routing updates.
 *
 * A passive interface can also be local, hardware interface exempt
 * from RIP.
 */
void
gwkludge(void)
{
#define	STR2(x)	#x
#define	STR(x)	STR2(x)

#define	NETHOST_LEN	4
#define	DNAME_LEN	MAXHOSTNAMELEN
#define	GNAME_LEN	MAXHOSTNAMELEN
#define	QUAL_LEN	8

	FILE *fp;
	char *p, *lptr;
	const char *cp;
	char lbuf[PARMS_MAXLINELEN], net_host[NETHOST_LEN + 1];
	char dname[MAXHOSTNAMELEN + 1];
	char gname[MAXHOSTNAMELEN + 1], qual[QUAL_LEN +1];
	struct interface *ifp;
	uint32_t dst, netmask, gate;
	int n;
	uint32_t lnum;
	struct stat sb;
	uint32_t state, metric;
	boolean_t default_dst;


	fp = fopen(PATH_GATEWAYS, "r");
	if (fp == NULL)
		return;

	if (0 > fstat(fileno(fp), &sb)) {
		msglog("fstat() failed: %s for  "PATH_GATEWAYS,
		    rip_strerror(errno));
		(void) fclose(fp);
		return;
	}

	for (lnum = 1; ; lnum++) {
		if (NULL == fgets(lbuf, sizeof (lbuf), fp))
			break;

		/* Eliminate the /n character at the end of the lbuf */
		if (strlen(lbuf) > 0)
			lbuf[strlen(lbuf) - 1] = '\0';

		/* Move lptr to the first non-space character */
		for (lptr = lbuf; isspace(*lptr); lptr++)
			;

		if (*lptr == '#' || *lptr == '\0')
			continue;

		/* Move p to the end of the line */
		p = lptr + strlen(lptr) - 1;

		/* Skip all trailing spaces except escaped space */
		while (p > lptr && (isspace(*p) && *(p-1) != '\\'))
			p--;

		/* truncate the line to remove trailing spaces */
		*++p = '\0';

		/* notice newfangled parameter lines */
		if (strncasecmp("net", lptr, 3) != 0 &&
		    strncasecmp("host", lptr, 4) != 0) {
			cp = parse_parms(lptr, (sb.st_uid == 0 &&
			    !(sb.st_mode&(S_IRWXG|S_IRWXO))));
			if (cp != 0)
				msglog("%s in line %u of "PATH_GATEWAYS,
				    cp, lnum);
			continue;
		}

		/*
		 * Processes lines of the follwoing format:
		 * net|host <name>[/mask] gateway <Gname> metric <value>
		 * passive|active|extern
		 */
		qual[0] = '\0';
		n = sscanf(lptr, "%"STR(NETHOST_LEN)"s %"STR(DNAME_LEN)
		    "[^ \t] gateway %"STR(GNAME_LEN)"[^ / \t] metric %u %"
		    STR(QUAL_LEN)"s\n", net_host, dname, gname, &metric, qual);
		if (n != 4 && n != 5) {
			msglog("bad "PATH_GATEWAYS" entry \"%s\"; %d values",
			    lptr, n);
			continue;
		}
		if (metric >= HOPCNT_INFINITY) {
			msglog("bad metric in "PATH_GATEWAYS" entry \"%s\"",
			    lptr);
			continue;
		}
		default_dst = _B_FALSE;
		if (strcasecmp(net_host, "host") == 0) {
			if (!gethost(dname, &dst)) {
				msglog("bad host \"%s\" in "PATH_GATEWAYS
				    " entry \"%s\"", dname, lptr);
				continue;
			}
			netmask = HOST_MASK;
		} else if (strcasecmp(net_host, "net") == 0) {
			if (!getnet(dname, &dst, &netmask)) {
				msglog("bad net \"%s\" in "PATH_GATEWAYS
				    " entry \"%s\"", dname, lptr);
				continue;
			}
			default_dst = (dst == RIP_DEFAULT);
			dst = htonl(dst); /* make network # into IP address */
		} else {
			msglog("bad \"%s\" in "PATH_GATEWAYS
			    " entry \"%s\"", net_host, lptr);
			continue;
		}

		if (!gethost(gname, &gate)) {
			msglog("bad gateway \"%s\" in "PATH_GATEWAYS
			    " entry \"%s\"", gname, lptr);
			continue;
		}

		if (strcasecmp(qual, "passive") == 0) {
			/*
			 * Passive entries are not placed in our tables,
			 * only the kernel's, so we don't copy all of the
			 * external routing information within a net.
			 * Internal machines should use the default
			 * route to a suitable gateway (like us).
			 */
			state = IS_REMOTE | IS_PASSIVE;
			if (metric == 0)
				metric = 1;

		} else if (strcasecmp(qual, "external") == 0) {
			/*
			 * External entries are handled by other means
			 * such as EGP, and are placed only in the daemon
			 * tables to prevent overriding them with something
			 * else.
			 */
			(void) strlcpy(qual, "external", sizeof (qual));
			state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
			if (metric == 0)
				metric = 1;

		} else if (strcasecmp(qual, "active") == 0 ||
		    qual[0] == '\0') {

			if (default_dst) {
				msglog("bad net \"%s\" in "PATH_GATEWAYS
				    " entry \"%s\"-- cannot be default",
				    dname, lptr);
				continue;
			}

			if (metric != 0) {
				/*
				 * Entries that are neither "passive" nor
				 * "external" are "remote" and must behave
				 * like physical interfaces.  If they are not
				 * heard from regularly, they are deleted.
				 */
				state = IS_REMOTE;
			} else {
				/*
				 * "remote" entries with a metric of 0
				 * are aliases for our own interfaces
				 */
				state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
			}

		} else {
			msglog("bad "PATH_GATEWAYS" entry \"%s\";"
			    " unknown type %s", lptr, qual);
			continue;
		}

		if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
			state |= IS_NO_RDISC;
		if (state & IS_PASSIVE)
			state |= IS_NO_RIP;


		if (default_dst) {
			addroutefordefault(dst, gate, netmask, metric,
			    ((state & IS_EXTERNAL)? RTS_EXTERNAL : 0));
			continue;
		}

		ifp = check_dup(NULL, gate, dst, netmask, 0, _B_FALSE);
		if (ifp != NULL) {
			msglog("duplicate "PATH_GATEWAYS" entry \"%s\"", lptr);
			continue;
		}

		ifp = rtmalloc(sizeof (*ifp), "gwkludge()");
		(void) memset(ifp, 0, sizeof (*ifp));

		ifp->int_state = state;
		if (netmask == HOST_MASK)
			ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP;
		else
			ifp->int_if_flags = IFF_UP;
		ifp->int_act_time = NEVER;
		ifp->int_addr = gate;
		ifp->int_dstaddr = dst;
		ifp->int_mask = netmask;
		ifp->int_ripv1_mask = netmask;
		ifp->int_std_mask = std_mask(gate);
		ifp->int_net = ntohl(dst);
		ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
		ifp->int_std_addr = htonl(ifp->int_std_net);
		ifp->int_metric = metric;
		if (!(state & IS_EXTERNAL) &&
		    ifp->int_mask != ifp->int_std_mask)
			ifp->int_state |= IS_SUBNET;
		(void) snprintf(ifp->int_name, sizeof (ifp->int_name),
		    "remote(%s)", gname);

		if_link(ifp, 0);
	}

	(void) fclose(fp);

	/*
	 * After all of the parameter lines have been read,
	 * apply them to any remote interfaces.
	 */
	for (ifp = ifnet; NULL != ifp; ifp = ifp->int_next) {
		get_parms(ifp);

		tot_interfaces++;
		if (!IS_RIP_OFF(ifp->int_state))
			rip_interfaces++;
		if (!IS_RIP_OUT_OFF(ifp->int_state))
			ripout_interfaces++;

		trace_if("Add", ifp);
	}

}
Exemplo n.º 5
0
/*
 * Handle an incoming RIP packet.
 */
static void
rip_input(struct sockaddr_in *from, int size, uint_t ifindex)
{
	struct netinfo *n, *lim;
	struct in_addr in;
	const char *name;
	char net_buf[80];
	uchar_t hash[RIP_AUTH_MD5_LEN];
	MD5_CTX md5_ctx;
	uchar_t md5_authed = 0;
	in_addr_t mask, dmask;
	struct in_addr tmp_addr;
	char *sp;
	char  ifname[IF_NAMESIZE+1];
	int i;
	struct hostent *hp;
	struct netent *np;
	struct netauth *na;
	char srcaddr[MAXHOSTNAMELEN + sizeof (" (123.123.123.123)") + 1];
	char ifstring[IF_NAMESIZE + 3*sizeof (ifindex) + sizeof (" ()") + 1];

	if (!nflag && (hp = gethostbyaddr((char *)&from->sin_addr,
	    sizeof (struct in_addr), AF_INET)) != NULL) {
		(void) snprintf(srcaddr, sizeof (srcaddr), "%s (%s)",
		    hp->h_name, inet_ntoa(from->sin_addr));
	} else {
		/* safe; cannot overflow destination */
		(void) strcpy(srcaddr, inet_ntoa(from->sin_addr));
	}
	if (ifindex == 0) {
		(void) printf("%s:", srcaddr);
	} else {
		if (if_indextoname(ifindex, ifname) != NULL)
			(void) snprintf(ifstring, sizeof (ifstring), "%s (%d)",
			    ifname, ifindex);
		else
			(void) snprintf(ifstring, sizeof (ifstring), "%d",
			    ifindex);
		(void) printf(gettext("%1$s received on interface %2$s:"),
		    srcaddr, ifstring);
	}

	if (IMSG.rip_cmd != RIPCMD_RESPONSE) {
		(void) printf(gettext("\n    unexpected response type %d\n"),
		    IMSG.rip_cmd);
		return;
	}
	(void) printf(gettext(" RIPv%1$d%2$s %3$d bytes\n"), IMSG.rip_vers,
	    (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "",
	    size);
	if (size > MAXPACKETSIZE) {
		if (size > sizeof (imsg_buf) - sizeof (*n)) {
			(void) printf(
			    gettext("       at least %d bytes too long\n"),
			    size-MAXPACKETSIZE);
			size = sizeof (imsg_buf) - sizeof (*n);
		} else {
			(void) printf(gettext("       %d bytes too long\n"),
			    size-MAXPACKETSIZE);
		}
	} else if (size%sizeof (*n) != sizeof (struct rip)%sizeof (*n)) {
		(void) printf(gettext("    response of bad length=%d\n"), size);
	}

	n = IMSG.rip_nets;
	lim = n + (size - 4) / sizeof (struct netinfo);
	for (; n < lim; n++) {
		name = "";
		if (n->n_family == RIP_AF_INET) {
			in.s_addr = n->n_dst;
			(void) strlcpy(net_buf, inet_ntoa(in),
			    sizeof (net_buf));

			tmp_addr.s_addr = (n->n_mask);
			mask = ntohl(n->n_mask);
			dmask = mask & -mask;
			if (mask != 0) {
				sp = &net_buf[strlen(net_buf)];
				if (IMSG.rip_vers == RIPv1) {
					(void) snprintf(sp,
					    (sizeof (net_buf) -
					    strlen(net_buf)),
					    gettext(" mask=%s ? "),
					    inet_ntoa(tmp_addr));
					mask = 0;
				} else if (mask + dmask == 0) {
					i = ffs(mask) - 1;
					(void) snprintf(sp,
					    (sizeof (net_buf) -
					    strlen(net_buf)), "/%d", 32-i);
				} else {
					(void) snprintf(sp,
					    (sizeof (net_buf) -
						strlen(net_buf)),
					    gettext(" (mask %s)"),
					    inet_ntoa(tmp_addr));
				}
			}

			if (!nflag) {
				if (mask == 0) {
					mask = std_mask(in.s_addr);
					if ((ntohl(in.s_addr) & ~mask) != 0)
						mask = 0;
				}
				/*
				 * Without a netmask, do not worry about
				 * whether the destination is a host or a
				 * network. Try both and use the first name
				 * we get.
				 *
				 * If we have a netmask we can make a
				 * good guess.
				 */
				if ((in.s_addr & ~mask) == 0) {
					np = getnetbyaddr((long)in.s_addr,
					    AF_INET);
					if (np != NULL)
						name = np->n_name;
					else if (in.s_addr == 0)
						name = "default";
				}
				if (name[0] == '\0' &&
				    ((in.s_addr & ~mask) != 0 ||
				    mask == 0xffffffff)) {
					hp = gethostbyaddr((char *)&in,
					    sizeof (in), AF_INET);
					if (hp != NULL)
						name = hp->h_name;
				}
			}

		} else if (n->n_family == RIP_AF_AUTH) {
			na = (struct netauth *)n;
			if (na->a_type == RIP_AUTH_PW &&
			    n == IMSG.rip_nets) {
				(void) printf(
				    gettext("  Password Authentication:"
				    " \"%s\"\n"),
				    qstring(na->au.au_pw,
				    RIP_AUTH_PW_LEN));
				continue;
			}

			if (na->a_type == RIP_AUTH_MD5 &&
			    n == IMSG.rip_nets) {
				(void) printf(gettext("  MD5 Auth"
				    " len=%1$d KeyID=%2$d"
				    " auth_len=%3$d"
				    " seqno=%4$#x"
				    " rsvd=%5$#x,%6$#x\n"),
				    ntohs(na->au.a_md5.md5_pkt_len),
				    na->au.a_md5.md5_keyid,
				    na->au.a_md5.md5_auth_len,
				    (int)ntohl(na->au.a_md5.md5_seqno),
				    na->au.a_md5.rsvd[0],
				    na->au.a_md5.rsvd[1]);
				md5_authed = 1;
				continue;
			}
			(void) printf(gettext("  Authentication type %d: "),
			    ntohs(na->a_type));
			for (i = 0; i < sizeof (na->au.au_pw); i++)
				(void) printf("%02x ",
				    na->au.au_pw[i]);
			(void) putchar('\n');
			if (md5_authed && n+1 > lim &&
			    na->a_type == RIP_AUTH_TRAILER) {
				MD5Init(&md5_ctx);
				MD5Update(&md5_ctx, (uchar_t *)&IMSG,
				    (char *)na-(char *)&IMSG);
				MD5Update(&md5_ctx,
				    (uchar_t *)passwd, RIP_AUTH_MD5_LEN);
				MD5Final(hash, &md5_ctx);
				(void) printf(gettext("    %s hash\n"),
				    memcmp(hash, na->au.au_pw, sizeof (hash)) ?
				    gettext("WRONG") : gettext("correct"));
			} else if (md5_authed && n+1 > lim &&
			    na->a_type != RIP_AUTH_TRAILER) {
				(void) printf(gettext("Error -"
				"authentication entry missing hash\n"));
			}
			continue;

		} else {
			tmp_addr.s_addr = n->n_dst;
			(void) snprintf(net_buf, sizeof (net_buf),
			    gettext("(address family %1$u) %2$s"),
			    ntohs(n->n_family), inet_ntoa(tmp_addr));
		}

		(void) printf(gettext("  %1$-18s metric %2$2lu %3$-10s"),
		    net_buf, ntohl(n->n_metric), name);

		if (n->n_nhop != 0) {
			in.s_addr = n->n_nhop;
			if (nflag)
				hp = NULL;
			else
				hp = gethostbyaddr((char *)&in, sizeof (in),
				    AF_INET);
			(void) printf(gettext(" nhop=%1$-15s%2$s"),
			    (hp != NULL) ? hp->h_name : inet_ntoa(in),
			    (IMSG.rip_vers == RIPv1) ? " ?" : "");
		}
		if (n->n_tag != 0)
			(void) printf(gettext(" tag=%1$#x%2$s"), n->n_tag,
			    (IMSG.rip_vers == RIPv1) ? " ?" : "");
		(void) putchar('\n');
	}
}