1086 lines
35 KiB
C
1086 lines
35 KiB
C
/*
|
|
* CENTER FOR THEORY AND SIMULATION IN SCIENCE AND ENGINEERING
|
|
* CORNELL UNIVERSITY
|
|
*
|
|
* Portions of this software may fall under the following
|
|
* copyrights:
|
|
*
|
|
* Copyright (c) 1983 Regents of the University of California.
|
|
* All rights reserved. The Berkeley software License Agreement
|
|
* specifies the terms and conditions for redistribution.
|
|
*
|
|
* GATED - based on Kirton's EGP, UC Berkeley's routing daemon (routed),
|
|
* and DCN's HELLO routing Protocol.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char *rcsid = "$Header: /proj/irix6.5.7m/isms/eoe/cmd/bsd/gated/RCS/rt_init.c,v 1.11 1996/03/26 21:20:05 vjs Exp $";
|
|
#endif not lint
|
|
|
|
/* rt_init.c
|
|
*
|
|
* Initialization functions for routing tables - interface routes, reading
|
|
* kernel routes, non-routing gateways, and routes to be advised in EGP
|
|
* NR Update messages.
|
|
*
|
|
* Functions: rt_init, rt_readkernel, rt_ifinit, rt_dumbinit, rt_NRadvise_init
|
|
*/
|
|
|
|
#ifdef vax11c
|
|
#include "config.h"
|
|
#endif vax11c
|
|
#include <sys/types.h>
|
|
#include <sys/mbuf.h> /* needed by <net/route.h> */
|
|
#include <sys/time.h>
|
|
#ifdef vax11c
|
|
#include <sys/ttychars.h>
|
|
#include <sys/ttydev.h>
|
|
#endif vax11c
|
|
#include <sys/ioctl.h>
|
|
#ifndef vax11c
|
|
#include <sys/uio.h>
|
|
#endif vax11c
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/ip_icmp.h>
|
|
|
|
#include <stdio.h>
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <strings.h>
|
|
#include <nlist.h>
|
|
#include <syslog.h>
|
|
|
|
#ifdef vax11c
|
|
#define DONT_INCLUDE_IF_ARP
|
|
#endif vax11c
|
|
#include <net/if.h>
|
|
#include <net/route.h>
|
|
|
|
#include "routed.h"
|
|
#include "defs.h"
|
|
#include "egp.h"
|
|
#include "egp_param.h"
|
|
#include "if.h"
|
|
#include "rt_table.h"
|
|
#include "rt_control.h"
|
|
#include "af.h"
|
|
#include "trace.h"
|
|
#ifndef NSS
|
|
#include "rip.h"
|
|
#include "hello.h"
|
|
#endif NSS
|
|
|
|
/*
|
|
* rt_init() initializes exterior and interior routing tables doubly linked
|
|
* lists.
|
|
*/
|
|
|
|
#ifndef sgi
|
|
extern off_t lseek();
|
|
#endif
|
|
|
|
rt_init()
|
|
{
|
|
register struct rthash *rh;
|
|
register struct restricthash *ac;
|
|
|
|
#ifdef lint
|
|
bzero((char *)&rtstat, sizeof(rtstat)); /* make lint happy */
|
|
#endif lint
|
|
|
|
for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
|
|
rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
|
|
for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
|
|
rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
|
|
for (ac = rt_restrict; ac < &rt_restrict[ROUTEHASHSIZ]; ac++)
|
|
ac->rt_forw = ac->rt_back = (struct restrictlist *)ac;
|
|
}
|
|
|
|
#ifndef NSS
|
|
/*
|
|
* rt_readkernel() initializes the GATED routing tables from the current kernel
|
|
* routing tables through /dev/kmem.
|
|
* This is necessary to ensure consistency when the GATED process is terminated
|
|
* and restarted while the supporting host continues to run. This may be done
|
|
* if configuration information needs to be changed.
|
|
*/
|
|
|
|
#ifdef sgi
|
|
#include <sys/sysctl.h>
|
|
#else /* sgi */
|
|
struct nlist nl[] = {
|
|
#define N_RTHOST 0
|
|
{ "_rthost" },
|
|
#define N_RTNET 1
|
|
{ "_rtnet"},
|
|
#define N_RTHASHSIZE 2
|
|
{ "_rthashsize"},
|
|
#ifndef vax11c
|
|
#define N_VERSION 3
|
|
{ "_version" },
|
|
#else vax11c
|
|
#define N_MULTINET_VERSION 3
|
|
{ "_multinet_version" },
|
|
#define N_MULTINET_PRODUCT_NAME 4
|
|
{ "_multinet_product_name" },
|
|
#endif vax11c
|
|
{ "" },
|
|
};
|
|
#endif /* sgi */
|
|
|
|
|
|
rt_readkernel()
|
|
{
|
|
#ifdef sgi
|
|
int doinghost;
|
|
size_t needed;
|
|
int mib[6];
|
|
char *buf, *next, *lim;
|
|
struct sockaddr *sa;
|
|
struct rt_msghdr *rtm;
|
|
struct k_rtentry {
|
|
struct sockaddr k_rt_dst; /* key */
|
|
struct sockaddr k_rt_gateway; /* value */
|
|
short k_rt_flags; /* up/down?, host/net */
|
|
} k_rt;
|
|
struct k_rtentry *rt = &k_rt;
|
|
|
|
mib[0] = CTL_NET;
|
|
mib[1] = PF_ROUTE;
|
|
mib[2] = 0;
|
|
mib[3] = 0;
|
|
mib[4] = NET_RT_DUMP;
|
|
mib[5] = 0;
|
|
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
|
|
p_error("route-sysctl-estimate");
|
|
quit();
|
|
}
|
|
if ((buf = malloc(needed)) == 0) {
|
|
p_error("out of space");
|
|
quit();
|
|
}
|
|
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
|
|
p_error("sysctl of routing table");
|
|
quit();
|
|
}
|
|
#else /* sgi */
|
|
/*
|
|
* ..routed/table.h redefines some of the elements of
|
|
* struct rtentry defined in <net/route.h>. In order for the code from routed
|
|
* to be able to be utilized part of the kernel structure has been redefined
|
|
* with a preceding k_.
|
|
*/
|
|
struct k_rtentry {
|
|
u_long k_rt_hash; /* to speed lookups */
|
|
struct sockaddr k_rt_dst; /* key */
|
|
struct sockaddr k_rt_gateway; /* value */
|
|
short k_rt_flags; /* up/down?, host/net */
|
|
} *rt;
|
|
|
|
int i, hashsize, kmem, doinghost, rtbufsize;
|
|
#if defined(ULTRIX3_X)
|
|
struct rtentry *next, m_buf, **base;
|
|
#else defined(ULTRIX3_X)
|
|
struct mbuf *next, m_buf, **base;
|
|
#endif defined(ULTRIX3_X)
|
|
|
|
#ifndef vax11c
|
|
(void) nlist("/vmunix", nl);
|
|
#else vax11c
|
|
{
|
|
extern char *Network_Image_File;
|
|
(void)multinet_kernel_nlist(Network_Image_File, nl);
|
|
}
|
|
#define read(kmem,buf,size) klread(buf,size)
|
|
#define lseek(kmem,offset,how) klseek(offset)
|
|
#endif vax11c
|
|
if ((nl[N_RTHOST].n_value == 0) || (nl[N_RTNET].n_value == 0)) {
|
|
syslog(LOG_ERR, "rt_readkernel: rthost and rtnet not in namelist\n");
|
|
quit();
|
|
}
|
|
#ifndef vax11c
|
|
kmem = open("/dev/kmem", 0);
|
|
if (kmem < 0) {
|
|
p_error("rt_readkernel: /dev/kmem");
|
|
quit();
|
|
}
|
|
if ( nl[N_VERSION].n_value ) {
|
|
char *p;
|
|
|
|
if ( (version_kernel = calloc(1, RIPPACKETSIZE)) == 0 ) {
|
|
p_error("rt_readkernel: calloc:");
|
|
quit();
|
|
}
|
|
(void) lseek(kmem, (off_t) nl[N_VERSION].n_value, 0);
|
|
(void) read(kmem, version_kernel, RIPPACKETSIZE-1);
|
|
if ( p = index(version_kernel, '\n') ) {
|
|
*p = NULL;
|
|
}
|
|
if ( (p = malloc((unsigned int)strlen(version_kernel))) == 0 ) {
|
|
p_error("rt_readkernel: malloc:");
|
|
quit();
|
|
}
|
|
(void) strcpy(p, version_kernel);
|
|
free(version_kernel);
|
|
version_kernel = p;
|
|
TRACE_INT("\nrt_readkernel: _version = %s\n", version_kernel);
|
|
} else {
|
|
version_kernel = NULL;
|
|
}
|
|
#else vax11c
|
|
if (nl[N_MULTINET_VERSION].n_value && nl[N_MULTINET_PRODUCT_NAME].n_value) {
|
|
char *p;
|
|
if ((version_kernel = calloc(1, RIPPACKETSIZE)) == 0) {
|
|
p_error("rt_readkernel: calloc:");
|
|
quit();
|
|
}
|
|
(void) lseek(kmem, (off_t) nl[N_MULTINET_PRODUCT_NAME].n_value, 0);
|
|
(void) read(kmem, version_kernel, RIPPACKETSIZE-2);
|
|
strcat(version_kernel, " ");
|
|
(void) lseek(kmem, (off_t) nl[N_MULTINET_VERSION].n_value, 0);
|
|
(void) read(kmem, version_kernel+strlen(version_kernel),
|
|
RIPPACKETSIZE-1-strlen(version_kernel));
|
|
if ((p = malloc(strlen(version_kernel))) == 0) {
|
|
p_error("rt_readkernel: malloc:");
|
|
quit();
|
|
}
|
|
(void) strcpy(p, version_kernel);
|
|
free(version_kernel);
|
|
version_kernel = p;
|
|
TRACE_INT("rt_readkernel: _version = %s\n", version_kernel);
|
|
} else {
|
|
version_kernel = NULL;
|
|
}
|
|
#endif vax11c
|
|
if (nl[N_RTHASHSIZE].n_value != 0) {
|
|
(void) lseek(kmem, (off_t) nl[N_RTHASHSIZE].n_value, 0);
|
|
(void) read(kmem, (char *)&hashsize, sizeof(hashsize));
|
|
} else {
|
|
#if (BSD42 || SUN3_3PLUS) && RTHASHSIZ
|
|
hashsize = RTHASHSIZ;
|
|
#else
|
|
syslog(LOG_ERR, "rt_readkernel: rthashsize not in namelist\n");
|
|
quit();
|
|
#endif
|
|
}
|
|
|
|
/* set up to read table of net hash chains */
|
|
|
|
#if defined(ULTRIX3_X)
|
|
rtbufsize = hashsize * sizeof(struct rtentry *);
|
|
base = (struct rtentry **)malloc((unsigned int)rtbufsize);
|
|
#else /*!defined(ULTRIX3_X)*/
|
|
rtbufsize = hashsize * sizeof(struct mbuf *);
|
|
base = (struct mbuf **)malloc((unsigned int)rtbufsize);
|
|
#endif /*!defined(ULTRIX3_X)*/
|
|
if (base == NULL) {
|
|
syslog(LOG_ERR, "rt_readkernel: can't malloc %d bytes", rtbufsize);
|
|
quit();
|
|
}
|
|
|
|
if ((lseek(kmem, (off_t)nl[N_RTNET].n_value, 0) == -1) ||
|
|
(read(kmem, (char *)base, rtbufsize) != rtbufsize)) {
|
|
syslog(LOG_ERR, "rt_readkernel: error reading kmem\n");
|
|
quit();
|
|
}
|
|
#endif /* sgi */
|
|
TRACE_RT("\nrt_readkernel: Initial routes read from kernel (if any):\n");
|
|
doinghost = 0;
|
|
|
|
doitagain:
|
|
#ifdef sgi
|
|
lim = buf + needed;
|
|
for (next = buf; next < lim; next += rtm->rtm_msglen) {
|
|
rtm = (struct rt_msghdr *)next;
|
|
/* Skip this entry if it does not have both gateway and dst.
|
|
* Also skip it if is a host route and we are not loading the
|
|
* gated host hash table, or vice versa.
|
|
*/
|
|
if ((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)
|
|
&& (((rtm->rtm_flags & RTF_HOST) && doinghost)
|
|
|| (!(rtm->rtm_flags & RTF_HOST) && !doinghost))) {
|
|
#if RTAX_DST != 0 || RTAX_GATEWAY != 1
|
|
? this assumes RTAX_DST == 0 and RTA_GATEWAY == 1;
|
|
#endif
|
|
sa = (struct sockaddr*)(rtm + 1);
|
|
#ifdef _HAVE_SA_LEN
|
|
bcopy(sa, sa->sa_len, &k_rt.k_rt_dst);
|
|
sa = (struct sockaddr*)(sa->sa_len + (char*)sa);
|
|
bcopy(sa, sa->sa_len, &k_rt.k_rt_gateway);
|
|
#else
|
|
k_rt.k_rt_dst = sa[0];
|
|
k_rt.k_rt_gateway = sa[1];
|
|
#endif
|
|
k_rt.k_rt_flags = rtm->rtm_flags & (RTF_UP | RTF_GATEWAY | RTF_HOST);
|
|
#else /* sgi */
|
|
for (i = 0; i < hashsize; i++) {
|
|
#if defined(ULTRIX3_X)
|
|
for (next = base[i]; next != NULL; next = m_buf.rt_next) {
|
|
if ((lseek(kmem, (off_t)next, 0) == -1) ||
|
|
(read(kmem, (char *)&m_buf, sizeof(m_buf)) != sizeof(m_buf))) {
|
|
quit();
|
|
}
|
|
rt = (struct k_rtentry *) &m_buf;
|
|
#else defined(ULTRIX3_X)
|
|
for (next = base[i]; next != NULL; next = m_buf.m_next) {
|
|
if ((lseek(kmem, (off_t)next, 0) == -1) ||
|
|
(read(kmem, (char *)&m_buf, MMINOFF + sizeof(struct k_rtentry)) != (MMINOFF + sizeof (struct k_rtentry)))) {
|
|
quit();
|
|
}
|
|
rt = mtod(&m_buf, struct k_rtentry *);
|
|
#endif defined(ULTRIX3_X)
|
|
#endif /* sgi */
|
|
#ifdef why_do_it_this_way
|
|
if (!(rt->k_rt_flags & RTF_GATEWAY))
|
|
continue;
|
|
#else why_do_it_this_way
|
|
if ( ((struct sockaddr_in *)&rt->k_rt_dst)->sin_addr.s_addr == htonl(LOOPBACKNET) ) {
|
|
continue;
|
|
}
|
|
#endif why_do_it_this_way
|
|
if (rt->k_rt_gateway.sa_family != AF_INET)
|
|
continue;
|
|
install = FALSE; /* don't install routes in kernel */
|
|
{
|
|
register struct interface *ifp;
|
|
int interior = 0, saveinstall, addgood = 0;
|
|
struct rt_entry dup_rt;
|
|
struct rt_entry *foundit;
|
|
|
|
if (doinghost != 0) {
|
|
if (!(foundit = rt_lookup((int)HOSTTABLE, (struct sockaddr_in *)&rt->k_rt_dst))) {
|
|
addgood = (int) rt_add((int)HOSTTABLE, &rt->k_rt_dst, &rt->k_rt_gateway,
|
|
mapmetric(RIP_TO_HELLO, (u_short)(RIPHOPCNT_INFINITY - 1)), 0, RTPROTO_KERNEL,
|
|
RTPROTO_KERNEL, 0, 0);
|
|
}
|
|
if (foundit || !(addgood)) {
|
|
bzero((char *)&dup_rt, sizeof(struct rt_entry));
|
|
dup_rt.rt_dst = rt->k_rt_dst;
|
|
dup_rt.rt_router = rt->k_rt_gateway;
|
|
dup_rt.rt_flags = rt->k_rt_flags;
|
|
saveinstall = install;
|
|
install = TRUE;
|
|
rt_delete(&dup_rt, KERNEL_ONLY);
|
|
install = saveinstall;
|
|
}
|
|
} else {
|
|
/*
|
|
* Check for and ignore martian nets
|
|
*/
|
|
if ( is_martian(((struct sockaddr_in *)&rt->k_rt_dst)->sin_addr) ) {
|
|
TRACE_EXT("rt_readkernel: ignoring invalid net %s at %s",
|
|
inet_ntoa(((struct sockaddr_in *)&rt->k_rt_dst)->sin_addr), strtime);
|
|
#ifdef sgi
|
|
/*
|
|
* Leave this entry in the kernel but do not add it
|
|
* to the gated table.
|
|
*/
|
|
continue;
|
|
#else /* sgi */
|
|
bzero((char *)&dup_rt, sizeof(struct rt_entry));
|
|
dup_rt.rt_dst = rt->k_rt_dst;
|
|
dup_rt.rt_router = rt->k_rt_gateway;
|
|
dup_rt.rt_flags = rt->k_rt_flags;
|
|
dup_rt.rt_proto = RTPROTO_KERNEL;
|
|
dup_rt.rt_fromproto = RTPROTO_KERNEL;
|
|
dup_rt.rt_state = RTS_EXTERIOR;
|
|
saveinstall = install;
|
|
install = TRUE;
|
|
rt_delete(&dup_rt, KERNEL_ONLY);
|
|
install = saveinstall;
|
|
continue;
|
|
#endif /* sgi */
|
|
}
|
|
for (ifp = ifnet; ifp; ifp = ifp->int_next)
|
|
if ( gd_inet_wholenetof(((struct sockaddr_in *)&rt->k_rt_dst)->sin_addr)
|
|
== gd_inet_wholenetof(in_addr_ofs(&ifp->int_addr)) ) {
|
|
interior++;
|
|
break;
|
|
}
|
|
if (interior) {
|
|
if (!(foundit = rt_lookup((int)INTERIOR, (struct sockaddr_in *)&rt->k_rt_dst))) {
|
|
addgood = (int) rt_add((int)INTERIOR,
|
|
&rt->k_rt_dst,
|
|
&rt->k_rt_gateway,
|
|
mapmetric(RIP_TO_HELLO, (u_short)(RIPHOPCNT_INFINITY - 1)),
|
|
0,
|
|
RTPROTO_KERNEL, RTPROTO_KERNEL, 0, 0);
|
|
}
|
|
if (foundit || !(addgood)) {
|
|
bzero((char *)&dup_rt, sizeof(struct rt_entry));
|
|
dup_rt.rt_dst = rt->k_rt_dst;
|
|
dup_rt.rt_router = rt->k_rt_gateway;
|
|
dup_rt.rt_flags = rt->k_rt_flags;
|
|
saveinstall = install;
|
|
install = TRUE;
|
|
rt_delete(&dup_rt, KERNEL_ONLY);
|
|
install = saveinstall;
|
|
}
|
|
} else {
|
|
if (!(foundit = rt_lookup((int)EXTERIOR, (struct sockaddr_in *)&rt->k_rt_dst))) {
|
|
addgood = (int) rt_add((int)EXTERIOR, &rt->k_rt_dst, &rt->k_rt_gateway,
|
|
mapmetric(EGP_TO_HELLO, (u_short)(HOPCNT_INFINITY - 1)), 0, RTPROTO_KERNEL,
|
|
RTPROTO_KERNEL, 0, 0);
|
|
}
|
|
if (foundit || !(addgood)) {
|
|
bzero((char *)&dup_rt, sizeof(struct rt_entry));
|
|
dup_rt.rt_dst = rt->k_rt_dst;
|
|
dup_rt.rt_router = rt->k_rt_gateway;
|
|
dup_rt.rt_flags = rt->k_rt_flags;
|
|
saveinstall = install;
|
|
install = TRUE;
|
|
rt_delete(&dup_rt, KERNEL_ONLY);
|
|
install = saveinstall;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* set up to read the host hash chain. */
|
|
if (doinghost == 0) {
|
|
#ifndef sgi
|
|
(void) lseek(kmem, (off_t)0 ,0);
|
|
if ((lseek(kmem, (off_t)nl[N_RTHOST].n_value, 0) == -1) ||
|
|
(read(kmem, (char *)base, rtbufsize) != rtbufsize)) {
|
|
syslog(LOG_ERR, "rt_readkernel: error reading kmem\n");
|
|
quit();
|
|
}
|
|
#endif /* sgi */
|
|
doinghost++;
|
|
goto doitagain;
|
|
}
|
|
#ifndef sgi
|
|
#ifndef vax11c
|
|
(void) close(kmem);
|
|
#endif vax11c
|
|
free((char *)base);
|
|
return;
|
|
#endif /* sgi */
|
|
}
|
|
|
|
/*
|
|
* rt_dumbinit() reads the initialization file EGPINITFILE to
|
|
* initialize:
|
|
* - the interior route table with routes to known non-routing gateways on a
|
|
* shared net, these routes are static and not updated;
|
|
* - a default gateway prior to another default being heard (if active default);
|
|
* It installs them in the kernel if they were not previously read from the
|
|
* kernel.
|
|
*/
|
|
|
|
rt_dumbinit(fp)
|
|
FILE *fp;
|
|
{
|
|
char keyword[MAXHOSTNAMELENGTH+1];
|
|
char netname[MAXHOSTNAMELENGTH+1];
|
|
char gname[MAXHOSTNAMELENGTH+1];
|
|
char proto_type[MAXHOSTNAMELENGTH+1];
|
|
char deftype[MAXHOSTNAMELENGTH+1];
|
|
char buf[BUFSIZ];
|
|
struct sockaddr_in netaddr, gateway, defaultdst;
|
|
struct rt_entry *rt;
|
|
int metric, error = FALSE, old_install, line, ptype = 0;
|
|
int tableadd;
|
|
|
|
bzero((char *)&netaddr, sizeof(netaddr));
|
|
bzero((char *)&gateway, sizeof(gateway));
|
|
bzero((char *)&defaultdst, sizeof(defaultdst));
|
|
|
|
TRACE_RT("rt_dumbinit: non-routing gateway routes (if any):\n");
|
|
|
|
rewind(fp);
|
|
line = 0;
|
|
|
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
|
line++;
|
|
if ((buf[0] == '#') || (buf[0] == '\n')) {
|
|
continue;
|
|
}
|
|
if (sscanf(buf, "%s", keyword) != 1) {
|
|
continue;
|
|
}
|
|
if ((strcasecmp(keyword, "net") == 0) ||
|
|
(strcasecmp(keyword, "host") == 0)) {
|
|
if (sscanf(buf, "%*s %s gateway %s metric %d %s", netname, gname, &metric, proto_type) != 4) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: syntax error line %d\n", line);
|
|
TRACE_TRC("rt_dumbinit: syntax error line %d\n", line);
|
|
error = TRUE;
|
|
} else if (!getnetorhostname(keyword, netname, &netaddr)) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: invalid %s name or address %s\n", keyword, netname);
|
|
TRACE_TRC("rt_dumbinit: invalid %s name or address %s\n", keyword, netname);
|
|
error = TRUE;
|
|
} else if (!getnetorhostname("host", gname, &gateway)) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: invalid gateway name or address %s\n", gname);
|
|
TRACE_TRC("rt_dumbinit: invalid gateway name or address %s\n", gname);
|
|
error = TRUE;
|
|
} else {
|
|
/* Initialize routings tables with non-routing gateway */
|
|
/*
|
|
* first delete any old route in exterior
|
|
* route table read from kernel if not a host route.
|
|
*/
|
|
old_install = install;
|
|
if (strcasecmp(keyword, "host") == 0) {
|
|
tableadd = HOSTTABLE;
|
|
} else {
|
|
tableadd = INTERIOR;
|
|
rt = rt_lookup((int)EXTERIOR, &netaddr);
|
|
if (rt != NULL) {
|
|
if (equal(&rt->rt_router, &gateway)) {
|
|
install = FALSE; /* already in kernel */
|
|
}
|
|
rt_delete(rt, KERNEL_INTR);
|
|
}
|
|
}
|
|
rt = rt_lookup(tableadd, &netaddr);
|
|
if (rt != NULL) {
|
|
if (equal(&rt->rt_router, &gateway)) {
|
|
install = FALSE; /* already in kernel */
|
|
}
|
|
rt_delete(rt, KERNEL_INTR);
|
|
}
|
|
if (strcasecmp("rip", proto_type) == 0) {
|
|
ptype = RTPROTO_RIP;
|
|
metric = mapmetric(RIP_TO_HELLO, (u_short)metric);
|
|
} else if (strcasecmp("hello", proto_type) == 0) {
|
|
ptype = RTPROTO_HELLO;
|
|
} else if (strcasecmp("egp", proto_type) == 0) {
|
|
ptype = RTPROTO_EGP;
|
|
metric = mapmetric(EGP_TO_HELLO, (u_short)metric);
|
|
tableadd = EXTERIOR;
|
|
} else {
|
|
syslog(LOG_WARNING, "unsupported protocol %s line %d\n", proto_type, line);
|
|
TRACE_TRC("unsupported protocol %s line %d\n", proto_type, line);
|
|
error = TRUE;
|
|
continue;
|
|
}
|
|
(void) rt_add(tableadd, (struct sockaddr *)&netaddr, (struct sockaddr *)&gateway, metric,
|
|
RTS_STATIC|RTS_PASSIVE, ptype, ptype, 0, 0);
|
|
install = old_install;
|
|
}
|
|
} /* end "net" || "host" entry */
|
|
else if (strcasecmp(keyword, "defaultgateway") == 0) {
|
|
if (sscanf(buf, "%*s %s %s %s", gname, proto_type, deftype) != 3) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: syntax error, line %d", line);
|
|
TRACE_TRC("rt_dumbinit: syntax error, line %d\n", line);
|
|
error = TRUE;
|
|
}
|
|
if (!strcasecmp(deftype, "metric")) {
|
|
if (sscanf(buf, "%*s %*s %*s %*s %d %s", &metric, deftype) != 2) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: syntax error, line %d", line);
|
|
TRACE_TRC("rt_dumbinit: syntax error, line %d\n", line);
|
|
error = TRUE;
|
|
}
|
|
if (metric < 0 || metric > DELAY_INFINITY) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: invalid metric: %d, line %d",
|
|
metric, line);
|
|
TRACE_TRC("rt_dumbinit: invalid metric: %d, line %d\n",
|
|
metric, line);
|
|
error = TRUE;
|
|
}
|
|
} else {
|
|
metric = -1;
|
|
}
|
|
if (!getnetorhostname("host", gname, &gateway)) {
|
|
syslog(LOG_WARNING, "rt_dumbinit: invalid gateway name or address %s",
|
|
gname);
|
|
TRACE_TRC("rt_dumbinit: invalid gateway name or address %s\n",
|
|
gname);
|
|
error = TRUE;
|
|
} else { /* Initialize default gateway */
|
|
/*
|
|
* check if a kernel entry exists for default
|
|
* route, if not add new default else change
|
|
* to new default
|
|
*/
|
|
defaultdst.sin_family = AF_INET;
|
|
defaultdst.sin_addr.s_addr = DEFAULTNET;
|
|
if (strcasecmp("rip", proto_type) == 0) {
|
|
ptype = RTPROTO_RIP;
|
|
if ( metric < 0 ) {
|
|
metric = RIPHOPCNT_INFINITY - 1;
|
|
}
|
|
metric = mapmetric(RIP_TO_HELLO, (u_short) metric);
|
|
} else if (strcasecmp("hello", proto_type) == 0) {
|
|
ptype = RTPROTO_HELLO;
|
|
if ( metric < 0 ) {
|
|
metric = DELAY_INFINITY - 100;
|
|
}
|
|
} else if (strcasecmp("egp", proto_type) == 0) {
|
|
ptype = RTPROTO_EGP;
|
|
if ( metric < 0 ) {
|
|
metric = HOPCNT_INFINITY - 1;
|
|
}
|
|
metric = mapmetric(EGP_TO_HELLO, (u_short) metric);
|
|
} else {
|
|
syslog(LOG_WARNING, "unsupported protocol %s line %d",
|
|
proto_type, line);
|
|
TRACE_TRC("unsupported protocol %s line %d\n",
|
|
proto_type, line);
|
|
error = TRUE;
|
|
continue;
|
|
}
|
|
if (strcasecmp("passive", deftype) == 0) {
|
|
/*
|
|
* get rid of all left over defaults from initialization.
|
|
*/
|
|
while (rt = rt_lookup((int)EXTERIOR, &defaultdst)) {
|
|
rt_delete(rt, KERNEL_INTR);
|
|
}
|
|
rt = rt_lookup((int)INTERIOR, &defaultdst);
|
|
if (rt == NULL) {
|
|
if( !(rt = rt_add((int)INTERIOR, (struct sockaddr *)&defaultdst, (struct sockaddr *)&gateway, metric,
|
|
RTS_PASSIVE, ptype, ptype, 0, 0)) ) {
|
|
syslog(LOG_ERR, "rt_dumbinit: error adding default route\n");
|
|
TRACE_INT("rt_dumbinit: error adding default route\n");
|
|
error = TRUE;
|
|
continue;
|
|
}
|
|
} else {
|
|
(void) rt_change(rt, (struct sockaddr *)&gateway, metric, ptype, ptype, 0, 0);
|
|
rt->rt_state |= RTS_PASSIVE;
|
|
}
|
|
if ((default_gateway = (struct rt_entry *)malloc(sizeof(struct rt_entry))) == NULL) {
|
|
syslog(LOG_ERR, "rt_dumbinit: out of memory");
|
|
quit();
|
|
}
|
|
bcopy((char *)rt, (char *)default_gateway, sizeof(struct rt_entry));
|
|
} else if (strcasecmp("active", deftype) == 0) {
|
|
/*
|
|
* get rid of all left over defaults from initialization.
|
|
*/
|
|
while (rt = rt_lookup((int)INTERIOR, &defaultdst)) {
|
|
rt_delete(rt, KERNEL_INTR);
|
|
}
|
|
rt = rt_lookup((int)EXTERIOR, &defaultdst);
|
|
if (rt == NULL) {
|
|
if ( !(rt = rt_add((int)EXTERIOR, (struct sockaddr *)&defaultdst, (struct sockaddr *)&gateway, metric,
|
|
RTS_PASSIVE, ptype, ptype, 0, 0)) ) {
|
|
syslog(LOG_ERR, "rt_dumbinit: error adding default route\n");
|
|
TRACE_INT("rt_dumbinit: error adding default route\n");
|
|
error = TRUE;
|
|
continue;
|
|
}
|
|
} else {
|
|
(void) rt_change(rt, (struct sockaddr *)&gateway, metric, ptype, ptype, 0, 0);
|
|
rt->rt_state |= RTS_PASSIVE;
|
|
}
|
|
if ((default_gateway = (struct rt_entry *)malloc(sizeof(struct rt_entry))) == NULL) {
|
|
syslog(LOG_ERR, "rt_dumbinit: out of memory");
|
|
quit();
|
|
}
|
|
bcopy((char *)rt, (char *)default_gateway, sizeof(struct rt_entry));
|
|
} else {
|
|
syslog(LOG_WARNING, "unsupported default type %s line %d",
|
|
deftype, line);
|
|
TRACE_TRC("unsupported default type %s line %d\n",
|
|
deftype, line);
|
|
error = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
} /* end "defaultgateway" entry */
|
|
} /* end while */
|
|
if (error) {
|
|
syslog(LOG_EMERG, "rt_dumbinit: %s: initialization error\n", EGPINITFILE);
|
|
quit();
|
|
}
|
|
}
|
|
#endif NSS
|
|
|
|
/*
|
|
* rt_NRadvise_init() reads the initialization file EGPINITFILE to
|
|
* determine user specification of nets allowed to be advised in Network
|
|
* Reachability messages. If any such nets are specified, only those specified
|
|
* are allowed to be advised.
|
|
* These nets must still meet the normal rules. i.e. they should be either
|
|
* direct nets or nets reached via non-routing gateways of the same autonomous
|
|
* sytem reported in EGPINITFILE. If the net is not one of these it is
|
|
* ignored.
|
|
*
|
|
* EGPINITFILE relevant format is:
|
|
* egpnetsreachable name name .... name
|
|
*/
|
|
|
|
rt_NRadvise_init(fp)
|
|
FILE *fp;
|
|
{
|
|
char keyword[MAXHOSTNAMELENGTH+1];
|
|
char netname[MAXHOSTNAMELENGTH+1];
|
|
char line[256], *lp;
|
|
struct sockaddr_in netaddr;
|
|
struct advlist *templist;
|
|
struct advlist *tailof;
|
|
int error = FALSE;
|
|
int net_count = 0;
|
|
|
|
adlist = (struct advlist *) NULL;
|
|
srcriplist = (struct advlist *) NULL;
|
|
srchellolist = (struct advlist *) NULL;
|
|
trustedhelloerlist = (struct advlist *) NULL;
|
|
trustedripperlist = (struct advlist *) NULL;
|
|
templist = (struct advlist *) NULL;
|
|
tailof = (struct advlist *) NULL;
|
|
bzero((char *)&netaddr, sizeof(netaddr));
|
|
netaddr.sin_family = AF_INET;
|
|
|
|
rewind(fp);
|
|
/*
|
|
* read first word of line and compare to key words
|
|
*/
|
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
lp = line;
|
|
if (gettoken(&lp, keyword, sizeof(keyword)) == 0)
|
|
continue;
|
|
if ((strcasecmp(keyword, "egpnetsreachable") == 0) ||
|
|
(strcasecmp(keyword, "noripoutinterface") == 0) ||
|
|
(strcasecmp(keyword, "noripfrominterface") == 0) ||
|
|
(strcasecmp(keyword, "nohellooutinterface") == 0) ||
|
|
(strcasecmp(keyword, "nohellofrominterface") == 0) ||
|
|
(strcasecmp(keyword, "trustedripgateways") == 0) ||
|
|
(strcasecmp(keyword, "trustedhellogateways") == 0) ||
|
|
(strcasecmp(keyword, "passiveinterfaces") == 0) ||
|
|
(strcasecmp(keyword, "sourcehellogateways") == 0) ||
|
|
(strcasecmp(keyword, "martiannets") == 0) ||
|
|
(strcasecmp(keyword, "sourceripgateways") == 0)) {
|
|
|
|
TRACE_INT("%s ", keyword);
|
|
/*
|
|
* Don't allow egpnetsreachable if we have restriction
|
|
* lists. If we have no restriction lists we will
|
|
* allow it as a "soft" level of restriction.
|
|
*/
|
|
if ((strcasecmp(keyword, "egpnetsreachable") == 0) &&
|
|
((announcethesenets != 0) || (donotannounce != 0))) {
|
|
printf("ignored with announce or noannounce restrictions.\n");
|
|
goto nextone;
|
|
}
|
|
/*
|
|
* read successive net strings into destination until end of line
|
|
*/
|
|
while (gettoken(&lp, netname, sizeof(netname)) > 0) {
|
|
TRACE_INT("%s ", netname);
|
|
if (!getnetorhostname(
|
|
((strcasecmp(keyword,"egpnetsreachable") == 0) || (strcasecmp(keyword,"martiannets") == 0))
|
|
? "net" : "host", netname, &netaddr)) {
|
|
syslog(LOG_WARNING, "NRadvise_init: invalid name or address %s",
|
|
netname);
|
|
error = TRUE;
|
|
} else {
|
|
struct advlist *al;
|
|
int rprotoflag = 0;
|
|
struct interface *ifp;
|
|
|
|
if (strcasecmp(keyword, "noripoutinterface") == 0) {
|
|
rprotoflag = IFF_NORIPOUT;
|
|
}
|
|
if (strcasecmp(keyword, "noripfrominterface") == 0) {
|
|
rprotoflag = IFF_NORIPIN;
|
|
}
|
|
if (strcasecmp(keyword, "nohellooutinterface") == 0) {
|
|
rprotoflag = IFF_NOHELLOOUT;
|
|
}
|
|
if (strcasecmp(keyword,"nohellofrominterface") == 0) {
|
|
rprotoflag = IFF_NOHELLOIN;
|
|
}
|
|
if (strcasecmp(keyword,"passiveinterfaces") == 0) {
|
|
rprotoflag = IFF_NOAGE;
|
|
}
|
|
if (rprotoflag != 0) {
|
|
if ((ifp = if_ifwithaddr((struct sockaddr *)&netaddr)) <= (struct interface *)0) {
|
|
syslog(LOG_WARNING, "bad interface in control list.\n");
|
|
error = TRUE;
|
|
} else {
|
|
ifp->int_flags |= rprotoflag;
|
|
}
|
|
} else {
|
|
if ((al = (struct advlist *)malloc(sizeof
|
|
(struct advlist))) == NULL) {
|
|
syslog(LOG_EMERG, "out of memory\n");
|
|
quit();
|
|
}
|
|
al->next = templist;
|
|
if (templist == NULL) {
|
|
tailof = al;
|
|
}
|
|
templist = al;
|
|
al->destnet = netaddr.sin_addr;
|
|
net_count++;
|
|
}
|
|
}
|
|
}
|
|
TRACE_INT("\n");
|
|
if (strcasecmp(keyword, "egpnetsreachable") == 0) {
|
|
n_remote_nets += net_count;
|
|
if (adlist) {
|
|
tailof->next = adlist;
|
|
}
|
|
adlist = templist;
|
|
}
|
|
if (strcasecmp(keyword, "martiannets") == 0) {
|
|
if (martians) {
|
|
tailof->next = martians;
|
|
}
|
|
martians = templist;
|
|
}
|
|
else if (strcasecmp(keyword, "sourceripgateways") == 0) {
|
|
if (srcriplist) {
|
|
tailof->next = srcriplist;
|
|
}
|
|
srcriplist = templist;
|
|
}
|
|
else if (strcasecmp(keyword, "sourcehellogateways") == 0) {
|
|
if (srchellolist) {
|
|
tailof->next = srchellolist;
|
|
}
|
|
srchellolist = templist;
|
|
}
|
|
else if (strcasecmp(keyword, "trustedhellogateways") == 0) {
|
|
if (trustedhelloerlist) {
|
|
tailof->next = trustedhelloerlist;
|
|
}
|
|
trustedhelloerlist = templist;
|
|
}
|
|
else if (strcasecmp(keyword, "trustedripgateways") == 0) {
|
|
if (trustedripperlist) {
|
|
tailof->next = trustedripperlist;
|
|
}
|
|
trustedripperlist = templist;
|
|
}
|
|
templist = (struct advlist *) NULL;
|
|
} /* end if "THE WORLD" */
|
|
nextone: ;
|
|
} /*end while*/
|
|
if (error) {
|
|
syslog(LOG_EMERG, "rt_NRadvise_init: %s: initialization error\n",
|
|
EGPINITFILE);
|
|
quit();
|
|
}
|
|
}
|
|
|
|
init_options(fp)
|
|
FILE *fp;
|
|
{
|
|
char keyword[MAXHOSTNAMELENGTH+1];
|
|
char option[MAXHOSTNAMELENGTH+1];
|
|
char line[256], *lp;
|
|
int route_proto = FALSE,
|
|
error = FALSE,
|
|
egp_conv = 0;
|
|
|
|
/*
|
|
* standard initializations - might as well be done here
|
|
*/
|
|
#ifndef NSS
|
|
doing_egp = FALSE;
|
|
doing_rip = TRUE;
|
|
doing_hello = FALSE;
|
|
rip_supplier = hello_supplier = -1;
|
|
rip_gateway = hello_gateway = FALSE;
|
|
rip_default = hello_default = 0;
|
|
rip_pointopoint = FALSE;
|
|
hello_pointopoint = FALSE;
|
|
#else NSS
|
|
doing_egp = TRUE;
|
|
#endif NSS
|
|
conv_factor = HOPCNT_INFINITY;
|
|
rt_maxage = RT_MINAGE;
|
|
egpsleep = MINHELLOINT + HELLOMARGIN;
|
|
n_remote_nets = 0;
|
|
#ifndef NSS
|
|
/*
|
|
* initialize the hello_default net.
|
|
*/
|
|
bzero((char *)&hello_dfltnet, sizeof(hello_dfltnet));
|
|
hello_dfltnet.sin_family = AF_INET;
|
|
hello_dfltnet.sin_addr.s_addr = htonl((u_long)HELLO_DEFAULT);
|
|
#endif NSS
|
|
|
|
rewind(fp);
|
|
|
|
TRACE_INT("init_options: Reading configuration protocol options:\n");
|
|
|
|
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
lp = line;
|
|
if (gettoken(&lp, keyword, sizeof(keyword)) == 0)
|
|
continue;
|
|
route_proto = 0;
|
|
if (strcasecmp(keyword, "EGP") == 0) {
|
|
route_proto = IPPROTO_EGP;
|
|
#ifndef NSS
|
|
} else if (strcasecmp(keyword, "RIP") == 0) {
|
|
route_proto = IPPROTO_RIP;
|
|
} else if (strcasecmp(keyword, "HELLO") == 0) {
|
|
route_proto = IPPROTO_HELLO;
|
|
#endif NSS
|
|
} else if (strcasecmp(keyword, "defaultegpmetric") == 0) {
|
|
route_proto++;
|
|
egp_conv++;
|
|
}
|
|
|
|
if (route_proto != 0) {
|
|
TRACE_INT("%s options: ", keyword);
|
|
while (gettoken(&lp, option, sizeof(option))) {
|
|
TRACE_INT("%s ", option);
|
|
if (egp_conv) {
|
|
if ((conv_factor = atoi(option)) < 0 ||
|
|
conv_factor > HOPCNT_INFINITY - 1) {
|
|
error = TRUE;
|
|
syslog(LOG_WARNING, "EGP conversion factor error - %d\n",
|
|
conv_factor);
|
|
}
|
|
break;
|
|
}
|
|
if (strcasecmp(option, "yes") == 0) {
|
|
switch (route_proto) {
|
|
#ifndef NSS
|
|
case IPPROTO_RIP:
|
|
doing_rip = TRUE;
|
|
break;
|
|
case IPPROTO_HELLO:
|
|
doing_hello = TRUE;
|
|
break;
|
|
#endif NSS
|
|
case IPPROTO_EGP:
|
|
doing_egp = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (strcasecmp(option, "no") == 0) {
|
|
switch (route_proto) {
|
|
#ifndef NSS
|
|
case IPPROTO_RIP:
|
|
doing_rip = FALSE;
|
|
rip_supplier = FALSE;
|
|
break;
|
|
case IPPROTO_HELLO:
|
|
doing_hello = FALSE;
|
|
hello_supplier = FALSE;
|
|
break;
|
|
#endif NSS
|
|
case IPPROTO_EGP:
|
|
doing_egp = FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
#ifndef NSS
|
|
if (strcasecmp(option, "quiet") == 0) {
|
|
switch (route_proto) {
|
|
case IPPROTO_RIP:
|
|
doing_rip = TRUE;
|
|
rip_supplier = FALSE;
|
|
break;
|
|
case IPPROTO_HELLO:
|
|
doing_hello = TRUE;
|
|
hello_supplier = FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (strcasecmp(option, "supplier") == 0) {
|
|
switch (route_proto) {
|
|
case IPPROTO_RIP:
|
|
doing_rip = TRUE;
|
|
rip_supplier = TRUE;
|
|
break;
|
|
case IPPROTO_HELLO:
|
|
doing_hello = TRUE;
|
|
hello_supplier = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (!strcasecmp(option, "pointopoint") ||
|
|
!strcasecmp(option, "pointtopoint")) {
|
|
switch (route_proto) {
|
|
case IPPROTO_RIP:
|
|
doing_rip = TRUE;
|
|
rip_supplier = TRUE;
|
|
rip_pointopoint = TRUE;
|
|
break;
|
|
case IPPROTO_HELLO:
|
|
doing_hello = TRUE;
|
|
hello_supplier = TRUE;
|
|
hello_pointopoint = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (strcasecmp(option, "gateway") == 0) {
|
|
(void) gettoken(&lp, option, sizeof(option));
|
|
switch (route_proto) {
|
|
case IPPROTO_RIP:
|
|
doing_rip = TRUE;
|
|
rip_supplier = TRUE;
|
|
rip_gateway = TRUE;
|
|
rip_default = atoi(option);
|
|
if (rip_default < 0 || rip_default >= RIPHOPCNT_INFINITY) {
|
|
error = TRUE;
|
|
syslog(LOG_WARNING, "RIP default metric error - %d\n",
|
|
rip_default);
|
|
}
|
|
if (!(error))
|
|
TRACE_INT("%d ", rip_default);
|
|
break;
|
|
case IPPROTO_HELLO:
|
|
doing_hello = TRUE;
|
|
hello_supplier = TRUE;
|
|
hello_gateway = TRUE;
|
|
hello_default = atoi(option);
|
|
if (hello_default < 0 || hello_default >= DELAY_INFINITY) {
|
|
error = TRUE;
|
|
syslog(LOG_WARNING, "HELLO default metric error - %d\n",
|
|
hello_default);
|
|
}
|
|
if (!(error))
|
|
TRACE_INT("%d ",hello_default);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
#endif NSS
|
|
} /* end while gettoken */
|
|
TRACE_INT("\n");
|
|
} /* end if "route_proto" */
|
|
} /*end while*/
|
|
if (error) {
|
|
syslog(LOG_EMERG, "init_options: %s: initialization error\n", EGPINITFILE);
|
|
quit();
|
|
}
|
|
init_display_config("init_options: RIP", doing_rip, rip_supplier, rip_gateway, rip_pointopoint, rip_default);
|
|
init_display_config("init_options: HELLO", doing_hello, hello_supplier, hello_gateway, hello_pointopoint, hello_default);
|
|
init_display_config("init_options: EGP", doing_egp, -1, 0, 0, 0);
|
|
}
|
|
|
|
init_display_config(s, doing, supplier, gateway, p2p, metric)
|
|
char *s;
|
|
int doing, supplier, gateway, p2p, metric;
|
|
{
|
|
|
|
TRACE_INT("%s ", s);
|
|
if (doing) {
|
|
if ( p2p ) {
|
|
TRACE_INT("pointopoint");
|
|
} else if ( gateway ) {
|
|
TRACE_INT("gateway %d", metric);
|
|
} else if ( supplier == TRUE ) {
|
|
TRACE_INT("supplier");
|
|
} else if ( supplier == FALSE ) {
|
|
TRACE_INT("quiet");
|
|
} else {
|
|
TRACE_INT("yes");
|
|
}
|
|
} else {
|
|
TRACE_INT("no");
|
|
}
|
|
TRACE_INT("\n");
|
|
}
|
|
|