xref: /original-bsd/sbin/routed/startup.c (revision 014fe330)
1 #ifndef lint
2 static char sccsid[] = "@(#)startup.c	4.4 (Berkeley) 05/25/83";
3 #endif
4 
5 /*
6  * Routing Table Management Daemon
7  */
8 #include "defs.h"
9 #include <net/if.h>
10 #include <nlist.h>
11 
12 struct	interface *ifnet;
13 int	kmem = -1;
14 int	lookforinterfaces = 1;
15 int	performnlist = 1;
16 int	externalinterfaces = 0;		/* # of remote and local interfaces */
17 
18 struct nlist nl[] = {
19 #define	N_IFNET		0
20 	{ "_ifnet" },
21 	{ "" },
22 };
23 
24 /*
25  * Probe the kernel through /dev/kmem to find the network
26  * interfaces which have configured themselves.  If the
27  * interface is present but not yet up (for example an
28  * ARPANET IMP), set the lookforinterfaces flag so we'll
29  * come back later and look again.
30  */
31 ifinit()
32 {
33 	struct interface *ifp;
34 	struct ifnet ifs, *next;
35 	char name[32], *cp, *index();
36 
37 	if (performnlist) {
38 		nlist("/vmunix", nl);
39 		if (nl[N_IFNET].n_value == 0) {
40 			printf("ifnet: not in namelist\n");
41 			goto bad;
42 		}
43 		performnlist = 0;
44 	}
45 	if (kmem < 0) {
46 		kmem = open("/dev/kmem", 0);
47 		if (kmem < 0) {
48 			perror("/dev/kmem");
49 			goto bad;
50 		}
51 	}
52 	if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
53 	    read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
54 		printf("ifnet: error reading kmem\n");
55 		goto bad;
56 	}
57 	lookforinterfaces = 0;
58 	while (next) {
59 		if (lseek(kmem, (long)next, 0) == -1 ||
60 		    read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) {
61 			perror("read");
62 			goto bad;
63 		}
64 		next = ifs.if_next;
65 		if ((ifs.if_flags & IFF_UP) == 0) {
66 			lookforinterfaces = 1;
67 			continue;
68 		}
69 		/* already known to us? */
70 		if (if_ifwithaddr(&ifs.if_addr))
71 			continue;
72 		/* argh, this'll have to change sometime */
73 		if (ifs.if_addr.sa_family != AF_INET)
74 			continue;
75 		/* no one cares about software loopback interfaces */
76 		if (ifs.if_net == LOOPBACKNET)
77 			continue;
78 		ifp = (struct interface *)malloc(sizeof (struct interface));
79 		if (ifp == 0) {
80 			printf("routed: out of memory\n");
81 			break;
82 		}
83 		/*
84 		 * Count the # of directly connected networks
85 		 * and point to point links which aren't looped
86 		 * back to ourself.  This is used below to
87 		 * decide if we should be a routing ``supplier''.
88 		 */
89 		if ((ifs.if_flags & IFF_POINTOPOINT) == 0 ||
90 		    if_ifwithaddr(&ifs.if_dstaddr) == 0)
91 			externalinterfaces++;
92 		lseek(kmem, ifs.if_name, 0);
93 		read(kmem, name, sizeof (name));
94 		name[sizeof (name) - 1] = '\0';
95 		cp = index(name, '\0');
96 		*cp++ = ifs.if_unit + '0';
97 		*cp = '\0';
98 		ifp->int_name = malloc(strlen(name) + 1);
99 		if (ifp->int_name == 0) {
100 			fprintf(stderr, "routed: ifinit: out of memory\n");
101 			goto bad;		/* ??? */
102 		}
103 		strcpy(ifp->int_name, name);
104 		ifp->int_addr = ifs.if_addr;
105 		ifp->int_flags = ifs.if_flags | IFF_INTERFACE;
106 		/* this works because broadaddr overlaps dstaddr */
107 		ifp->int_broadaddr = ifs.if_broadaddr;
108 		ifp->int_net = ifs.if_net;
109 		ifp->int_metric = 0;
110 		ifp->int_next = ifnet;
111 		ifnet = ifp;
112 		traceinit(ifp);
113 		addrouteforif(ifp);
114 	}
115 	if (externalinterfaces > 1 && supplier < 0)
116 		supplier = 1;
117 	return;
118 bad:
119 	sleep(60);
120 	close(kmem), close(s);
121 	execv("/etc/routed", argv0);
122 	_exit(0177);
123 }
124 
125 addrouteforif(ifp)
126 	struct interface *ifp;
127 {
128 	struct sockaddr_in net;
129 	struct sockaddr *dst;
130 	int state, metric;
131 	struct rt_entry *rt;
132 
133 	if (ifp->int_flags & IFF_POINTOPOINT)
134 		dst = &ifp->int_dstaddr;
135 	else {
136 		bzero((char *)&net, sizeof (net));
137 		net.sin_family = AF_INET;
138 		net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
139 		dst = (struct sockaddr *)&net;
140 	}
141 	rt = rtlookup(dst);
142 	rtadd(dst, &ifp->int_addr, ifp->int_metric,
143 		ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
144 	if (rt)
145 		rtdelete(rt);
146 }
147 
148 /*
149  * As a concession to the ARPANET we read a list of gateways
150  * from /etc/gateways and add them to our tables.  This file
151  * exists at each ARPANET gateway and indicates a set of ``remote''
152  * gateways (i.e. a gateway which we can't immediately determine
153  * if it's present or not as we can do for those directly connected
154  * at the hardware level).  If a gateway is marked ``passive''
155  * in the file, then we assume it doesn't have a routing process
156  * of our design and simply assume it's always present.  Those
157  * not marked passive are treated as if they were directly
158  * connected -- they're added into the interface list so we'll
159  * send them routing updates.
160  */
161 gwkludge()
162 {
163 	struct sockaddr_in dst, gate;
164 	FILE *fp;
165 	char *type, *dname, *gname, *qual, buf[BUFSIZ];
166 	struct interface *ifp;
167 	int metric;
168 
169 	fp = fopen("/etc/gateways", "r");
170 	if (fp == NULL)
171 		return;
172 	qual = buf;
173 	dname = buf + 64;
174 	gname = buf + ((BUFSIZ - 64) / 3);
175 	type = buf + (((BUFSIZ - 64) * 2) / 3);
176 	bzero((char *)&dst, sizeof (dst));
177 	bzero((char *)&gate, sizeof (gate));
178 	/* format: {net | host} XX gateway XX metric DD [passive]\n */
179 #define	readentry(fp) \
180 	fscanf((fp), "%s %s gateway %s metric %d %s\n", \
181 		type, dname, gname, &metric, qual)
182 	for (;;) {
183 		if (readentry(fp) == EOF)
184 			break;
185 		if (!getnetorhostname(type, dname, &dst))
186 			continue;
187 		if (!gethostnameornumber(gname, &gate))
188 			continue;
189 		ifp = (struct interface *)malloc(sizeof (*ifp));
190 		bzero((char *)ifp, sizeof (*ifp));
191 		ifp->int_flags = IFF_REMOTE;
192 		/* can't identify broadcast capability */
193 		ifp->int_net = inet_netof(dst.sin_addr);
194 		if (strcmp(type, "host") == 0) {
195 			ifp->int_flags |= IFF_POINTOPOINT;
196 			ifp->int_dstaddr = *((struct sockaddr *)&dst);
197 		}
198 		if (strcmp(qual, "passive") == 0)
199 			ifp->int_flags |= IFF_PASSIVE;
200 		else
201 			/* assume no duplicate entries */
202 			externalinterfaces++;
203 		ifp->int_addr = *((struct sockaddr *)&gate);
204 		ifp->int_metric = metric;
205 		ifp->int_next = ifnet;
206 		ifnet = ifp;
207 		addrouteforif(ifp);
208 	}
209 	fclose(fp);
210 }
211 
212 getnetorhostname(type, name, sin)
213 	char *type, *name;
214 	struct sockaddr_in *sin;
215 {
216 
217 	if (strcmp(type, "net") == 0) {
218 		struct netent *np = getnetbyname(name);
219 		int n;
220 
221 		if (np == 0)
222 			n = inet_network(name);
223 		else {
224 			if (np->n_addrtype != AF_INET)
225 				return (0);
226 			n = np->n_net;
227 		}
228 		sin->sin_family = AF_INET;
229 		sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
230 		return (1);
231 	}
232 	if (strcmp(type, "host") == 0) {
233 		struct hostent *hp = gethostbyname(name);
234 
235 		if (hp == 0)
236 			sin->sin_addr.s_addr = inet_addr(name);
237 		else {
238 			if (hp->h_addrtype != AF_INET)
239 				return (0);
240 			bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
241 		}
242 		sin->sin_family = AF_INET;
243 		return (1);
244 	}
245 	return (0);
246 }
247 
248 gethostnameornumber(name, sin)
249 	char *name;
250 	struct sockaddr_in *sin;
251 {
252 	struct hostent *hp;
253 
254 	hp = gethostbyname(name);
255 	if (hp) {
256 		bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
257 		sin->sin_family = hp->h_addrtype;
258 		return (1);
259 	}
260 	sin->sin_addr.s_addr = inet_addr(name);
261 	sin->sin_family = AF_INET;
262 	return (sin->sin_addr.s_addr != -1);
263 }
264