parms.c revision 18316
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
35static char sccsid[] = "@(#)if.c	8.1 (Berkeley) 6/5/93";
36#elif defined(__NetBSD__)
37static char rcsid[] = "$NetBSD$";
38#endif
39#ident "$Revision: 1.9 $"
40
41#include "defs.h"
42#include "pathnames.h"
43
44
45struct parm *parms;
46struct intnet *intnets;
47
48
49/* use configured parameters
50 */
51void
52get_parms(struct interface *ifp)
53{
54	struct parm *parmp;
55
56	/* get all relevant parameters
57	 */
58	for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
59		if ((parmp->parm_name[0] == '\0'
60		     && on_net(ifp->int_addr,
61			       parmp->parm_addr_h, parmp->parm_mask))
62		    || (parmp->parm_name[0] != '\0'
63			&& !strcmp(ifp->int_name, parmp->parm_name))) {
64			/* this group of parameters is relevant,
65			 * so get its settings
66			 */
67			ifp->int_state |= parmp->parm_int_state;
68			if (parmp->parm_passwd[0] != '\0')
69				bcopy(parmp->parm_passwd, ifp->int_passwd,
70				      sizeof(ifp->int_passwd));
71			if (parmp->parm_rdisc_pref != 0)
72				ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
73			if (parmp->parm_rdisc_int != 0)
74				ifp->int_rdisc_int = parmp->parm_rdisc_int;
75			if (parmp->parm_d_metric != 0)
76				ifp->int_d_metric = parmp->parm_d_metric;
77			}
78	}
79	/* default poor-man's router discovery to a metric that will
80	 * be heard by old versions of routed.
81	 */
82	if ((ifp->int_state & IS_PM_RDISC)
83	    && ifp->int_d_metric == 0)
84		ifp->int_d_metric = HOPCNT_INFINITY-2;
85
86	if (IS_RIP_IN_OFF(ifp->int_state))
87		ifp->int_state |= IS_NO_RIP_OUT;
88
89	if (ifp->int_rdisc_int == 0)
90		ifp->int_rdisc_int = DefMaxAdvertiseInterval;
91
92	if (!(ifp->int_if_flags & IFF_MULTICAST)
93	    && !(ifp->int_if_flags & IFF_POINTOPOINT))
94		ifp->int_state |= IS_NO_RIPV2_OUT;
95
96	if (!(ifp->int_if_flags & IFF_MULTICAST))
97		ifp->int_state |= IS_BCAST_RDISC;
98
99	if (ifp->int_if_flags & IFF_POINTOPOINT) {
100		ifp->int_state |= IS_BCAST_RDISC;
101		/* By default, point-to-point links should be passive
102		 * about router-discovery for the sake of demand-dialing.
103		 */
104		if (0 == (ifp->int_state & GROUP_IS_SOL))
105			ifp->int_state |= IS_NO_SOL_OUT;
106		if (0 == (ifp->int_state & GROUP_IS_ADV))
107			ifp->int_state |= IS_NO_ADV_OUT;
108	}
109
110	if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
111		ifp->int_state |= IS_NO_RDISC;
112	if (ifp->int_state & IS_PASSIVE)
113		ifp->int_state |= (IS_NO_RIP | IS_NO_RDISC);
114	if ((ifp->int_state & (IS_NO_RIP | IS_NO_RDISC))
115	    == (IS_NO_RIP|IS_NO_RDISC))
116		ifp->int_state |= IS_PASSIVE;
117}
118
119
120/* Read a list of gateways from /etc/gateways and add them to our tables.
121 *
122 * This file contains a list of "remote" gateways.  That is usually
123 * a gateway which we cannot immediately determine if it is present or
124 * not as we can do for those provided by directly connected hardware.
125 *
126 * If a gateway is marked "passive" in the file, then we assume it
127 * does not understand RIP and assume it is always present.  Those
128 * not marked passive are treated as if they were directly connected
129 * and assumed to be broken if they do not send us advertisements.
130 * All remote interfaces are added to our list, and those not marked
131 * passive are sent routing updates.
132 *
133 * A passive interface can also be local, hardware interface exempt
134 * from RIP.
135 */
136void
137gwkludge(void)
138{
139	FILE *fp;
140	char *p, *lptr;
141	char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9];
142	struct interface *ifp;
143	naddr dst, netmask, gate;
144	int metric, n;
145	u_int state;
146	char *type;
147	struct parm *parmp;
148
149
150	fp = fopen(_PATH_GATEWAYS, "r");
151	if (fp == 0)
152		return;
153
154	for (;;) {
155		if (0 == fgets(lbuf, sizeof(lbuf)-1, fp))
156			break;
157		lptr = lbuf;
158		while (*lptr == ' ')
159			lptr++;
160		if (*lptr == '\n'	/* ignore null and comment lines */
161		    || *lptr == '#')
162			continue;
163		p = lptr+strlen(lptr)-1;
164		while (*p == '\n'
165		       || *p == ' ')
166			*p-- = '\0';
167
168		/* notice newfangled parameter lines
169		 */
170		if (strncasecmp("net", lptr, 3)
171		    && strncasecmp("host", lptr, 4)) {
172			p = parse_parms(lptr);
173			if (p != 0) {
174				if (strcmp(p,lptr))
175					msglog("bad \"%s\" in "_PATH_GATEWAYS
176					       " entry \"%s\"", lptr, p);
177				else
178					msglog("bad \"%s\" in "_PATH_GATEWAYS,
179					       lptr);
180			}
181			continue;
182		}
183
184/*  {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
185		n = sscanf(lptr, "%4s %129[^ \t] gateway"
186			   " %64[^ / \t] metric %d %8s\n",
187			   net_host, dname, gname, &metric, qual);
188		if (n != 5) {
189			msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
190			continue;
191		}
192		if (metric < 0 || metric >= HOPCNT_INFINITY) {
193			msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"",
194			       lptr);
195			continue;
196		}
197		if (!strcmp(net_host, "host")) {
198			if (!gethost(dname, &dst)) {
199				msglog("bad host \"%s\" in "_PATH_GATEWAYS
200				       " entry \"%s\"", dname, lptr);
201				continue;
202			}
203			netmask = HOST_MASK;
204		} else if (!strcmp(net_host, "net")) {
205			if (!getnet(dname, &dst, &netmask)) {
206				msglog("bad net \"%s\" in "_PATH_GATEWAYS
207				       " entry \"%s\"", dname, lptr);
208				continue;
209			}
210		} else {
211			msglog("bad \"%s\" in "_PATH_GATEWAYS
212			       " entry \"%s\"", lptr);
213			continue;
214		}
215
216		if (!gethost(gname, &gate)) {
217			msglog("bad gateway \"%s\" in "_PATH_GATEWAYS
218			       " entry \"%s\"", gname, lptr);
219			continue;
220		}
221
222		if (strcmp(qual, type = "passive") == 0) {
223			/* Passive entries are not placed in our tables,
224			 * only the kernel's, so we don't copy all of the
225			 * external routing information within a net.
226			 * Internal machines should use the default
227			 * route to a suitable gateway (like us).
228			 */
229			state = IS_REMOTE | IS_PASSIVE;
230			if (metric == 0)
231				metric = 1;
232
233		} else if (strcmp(qual, type = "external") == 0) {
234			/* External entries are handled by other means
235			 * such as EGP, and are placed only in the daemon
236			 * tables to prevent overriding them with something
237			 * else.
238			 */
239			state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
240			if (metric == 0)
241				metric = 1;
242
243		} else if (qual[0] == '\0') {
244			if (metric != 0) {
245				/* Entries that are neither "passive" nor
246				 * "external" are "remote" and must behave
247				 * like physical interfaces.  If they are not
248				 * heard from regularly, they are deleted.
249				 */
250				state = IS_REMOTE;
251				type = "remote";
252			} else {
253				/* "remote" entries with a metric of 0
254				 * are aliases for our own interfaces
255				 */
256				state = IS_REMOTE | IS_PASSIVE;
257				type = "alias";
258			}
259
260		} else {
261			msglog("bad "_PATH_GATEWAYS" entry \"%s\"", lptr);
262			continue;
263		}
264
265		/* Remember to advertise the corresponding logical network.
266		 */
267		if (!(state & IS_EXTERNAL)
268		    && netmask != std_mask(dst))
269			state |= IS_SUBNET;
270
271		if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
272			state |= IS_NO_RDISC;
273		if (state & IS_PASSIVE)
274			state |= (IS_NO_RIP | IS_NO_RDISC);
275		if ((state & (IS_NO_RIP | IS_NO_RDISC))
276		    == (IS_NO_RIP|IS_NO_RDISC))
277			state |= IS_PASSIVE;
278
279		parmp = (struct parm*)malloc(sizeof(*parmp));
280		bzero(parmp, sizeof(*parmp));
281		parmp->parm_next = parms;
282		parms = parmp;
283		parmp->parm_addr_h = ntohl(dst);
284		parmp->parm_mask = -1;
285		parmp->parm_d_metric = 0;
286		parmp->parm_int_state = state;
287
288		/* See if this new interface duplicates an existing
289		 * interface.
290		 */
291		for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
292			if (ifp->int_mask == netmask
293			    && ((ifp->int_addr == dst
294				 && netmask != HOST_MASK)
295				|| (ifp->int_dstaddr == dst
296				    && netmask == HOST_MASK)))
297				break;
298		}
299		if (ifp != 0) {
300			/* Let one of our real interfaces be marked passive.
301			 */
302			if ((state & IS_PASSIVE) && !(state & IS_EXTERNAL)) {
303				ifp->int_state |= state;
304			} else {
305				msglog("%s is duplicated in "_PATH_GATEWAYS
306				       " by %s",
307				       ifp->int_name, lptr);
308			}
309			continue;
310		}
311
312		tot_interfaces++;
313
314		ifp = (struct interface *)malloc(sizeof(*ifp));
315		bzero(ifp, sizeof(*ifp));
316		if (ifnet != 0) {
317			ifp->int_next = ifnet;
318			ifnet->int_prev = ifp;
319		}
320		ifnet = ifp;
321
322		ifp->int_state = state;
323		ifp->int_net = ntohl(dst) & netmask;
324		ifp->int_mask = netmask;
325		if (netmask == HOST_MASK)
326			ifp->int_if_flags |= IFF_POINTOPOINT;
327		ifp->int_dstaddr = dst;
328		ifp->int_addr = gate;
329		ifp->int_metric = metric;
330		(void)sprintf(ifp->int_name, "%s-%s", type, naddr_ntoa(dst));
331		ifp->int_index = -1;
332
333		get_parms(ifp);
334
335		trace_if("Add", ifp);
336	}
337}
338
339
340/* parse a set of parameters for an interface
341 */
342char *					/* 0 or error message */
343parse_parms(char *line)
344{
345#define PARS(str) (0 == (tgt = str, strcasecmp(tok, tgt)))
346#define PARSE(str) (0 == (tgt = str, strncasecmp(tok, str "=", sizeof(str))))
347#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break;	\
348	parm.parm_int_state |= (b);}
349#define DELIMS " ,\t\n"
350	struct parm parm;
351	struct intnet *intnetp;
352	char *tok, *tgt, *p;
353
354
355	/* "subnet=x.y.z.u/mask" must be alone on the line */
356	if (!strncasecmp("subnet=",line,7)) {
357		intnetp = (struct intnet*)malloc(sizeof(*intnetp));
358		intnetp->intnet_metric = 1;
359		if ((p = strrchr(line,','))) {
360			*p++ = '\0';
361			intnetp->intnet_metric = (int)strtol(p,&p,0);
362			if (*p != '\0'
363			    || intnetp->intnet_metric <= 0
364			    || intnetp->intnet_metric >= HOPCNT_INFINITY)
365				return line;
366		}
367		if (!getnet(&line[7], &intnetp->intnet_addr,
368			    &intnetp->intnet_mask)
369		    || intnetp->intnet_mask == HOST_MASK
370		    || intnetp->intnet_addr == RIP_DEFAULT) {
371			free(intnetp);
372			return line;
373		}
374		intnetp->intnet_next = intnets;
375		intnets = intnetp;
376		return 0;
377	}
378
379	bzero(&parm, sizeof(parm));
380
381	tgt = "null";
382	for (tok = strtok(line, DELIMS);
383	     tok != 0 && tok[0] != '\0';
384	     tgt = 0, tok = strtok(0,DELIMS)) {
385		if (PARSE("if")) {
386			if (parm.parm_name[0] != '\0'
387			    || tok[3] == '\0'
388			    || strlen(tok) > IFNAMSIZ+3)
389				break;
390			strcpy(parm.parm_name, tok+3);
391
392		} else if (PARSE("passwd")) {
393			if (tok[7] == '\0'
394			    || strlen(tok) > RIP_AUTH_PW_LEN+7)
395				break;
396			strcpy(parm.parm_passwd, tok+7);
397
398		} else if (PARS("no_ag")) {
399			parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
400
401		} else if (PARS("no_super_ag")) {
402			parm.parm_int_state |= IS_NO_SUPER_AG;
403
404		} else if (PARS("no_ripv1_in")) {
405			parm.parm_int_state |= IS_NO_RIPV1_IN;
406
407		} else if (PARS("no_ripv2_in")) {
408			parm.parm_int_state |= IS_NO_RIPV2_IN;
409
410		} else if (PARS("ripv2_out")) {
411			if (parm.parm_int_state & IS_NO_RIPV2_OUT)
412				break;
413			parm.parm_int_state |= IS_NO_RIPV1_OUT;
414
415		} else if (PARS("no_rip")) {
416			parm.parm_int_state |= IS_NO_RIP;
417
418		} else if (PARS("no_rdisc")) {
419			CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
420
421		} else if (PARS("no_solicit")) {
422			CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
423
424		} else if (PARS("send_solicit")) {
425			CKF(GROUP_IS_SOL, IS_SOL_OUT);
426
427		} else if (PARS("no_rdisc_adv")) {
428			CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
429
430		} else if (PARS("rdisc_adv")) {
431			CKF(GROUP_IS_ADV, IS_ADV_OUT);
432
433		} else if (PARS("bcast_rdisc")) {
434			parm.parm_int_state |= IS_BCAST_RDISC;
435
436		} else if (PARS("passive")) {
437			CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
438			parm.parm_int_state |= IS_NO_RIP;
439
440		} else if (PARSE("rdisc_pref")) {
441			if (parm.parm_rdisc_pref != 0
442			    || tok[11] == '\0'
443			    || (parm.parm_rdisc_pref = (int)strtol(&tok[11],
444								   &p,0),
445				*p != '\0'))
446				break;
447
448		} else if (PARS("pm_rdisc")) {
449			parm.parm_int_state |= IS_PM_RDISC;
450
451		} else if (PARSE("rdisc_interval")) {
452			if (parm.parm_rdisc_int != 0
453			    || tok[15] == '\0'
454			    || (parm.parm_rdisc_int = (int)strtol(&tok[15],
455								  &p,0),
456				*p != '\0')
457			    || parm.parm_rdisc_int < MinMaxAdvertiseInterval
458			    || parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
459				break;
460
461		} else if (PARSE("fake_default")) {
462			if (parm.parm_d_metric != 0
463			    || tok[13] == '\0'
464			    || (parm.parm_d_metric=(int)strtol(&tok[13],&p,0),
465				*p != '\0')
466			    || parm.parm_d_metric > HOPCNT_INFINITY-1)
467				break;
468
469		} else {
470			tgt = tok;
471			break;
472		}
473	}
474	if (tgt != 0)
475		return tgt;
476
477	return check_parms(&parm);
478#undef DELIMS
479#undef PARS
480#undef PARSE
481}
482
483
484/* check for duplicate parameter specifications */
485char *					/* 0 or error message */
486check_parms(struct parm *new)
487{
488	struct parm *parmp;
489
490
491	/* set implicit values
492	 */
493	if (!supplier && supplier_set)
494		new->parm_int_state |= (IS_NO_RIPV1_OUT
495					| IS_NO_RIPV2_OUT
496					| IS_NO_ADV_OUT);
497	if (new->parm_int_state & IS_NO_ADV_IN)
498		new->parm_int_state |= IS_NO_SOL_OUT;
499
500	if ((new->parm_int_state & (IS_NO_RIP | IS_NO_RDISC))
501	    == (IS_NO_RIP | IS_NO_RDISC))
502		new->parm_int_state |= IS_PASSIVE;
503
504	/* compare with existing sets of parameters
505	 */
506	for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
507		if (strcmp(new->parm_name, parmp->parm_name))
508			continue;
509		if (!on_net(htonl(parmp->parm_addr_h),
510			    new->parm_addr_h, new->parm_mask)
511		    && !on_net(htonl(new->parm_addr_h),
512			       parmp->parm_addr_h, parmp->parm_mask))
513			continue;
514
515		if (strcmp(parmp->parm_passwd, new->parm_passwd)
516		    || (0 != (new->parm_int_state & GROUP_IS_SOL)
517			&& 0 != (parmp->parm_int_state & GROUP_IS_SOL)
518			&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
519				 && GROUP_IS_SOL))
520		    || (0 != (new->parm_int_state & GROUP_IS_ADV)
521			&& 0 != (parmp->parm_int_state & GROUP_IS_ADV)
522			&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
523				 && GROUP_IS_ADV))
524		    || (new->parm_rdisc_pref != 0
525			&& parmp->parm_rdisc_pref != 0
526			&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
527		    || (new->parm_rdisc_int != 0
528			&& parmp->parm_rdisc_int != 0
529			&& new->parm_rdisc_int != parmp->parm_rdisc_int)
530		    || (new->parm_d_metric != 0
531			&& parmp->parm_d_metric != 0
532			&& new->parm_d_metric != parmp->parm_d_metric))
533			return "duplicate";
534	}
535
536	parmp = (struct parm*)malloc(sizeof(*parmp));
537	bcopy(new, parmp, sizeof(*parmp));
538	parmp->parm_next = parms;
539	parms = parmp;
540
541	return 0;
542}
543
544
545/* get a network number as a name or a number, with an optional "/xx"
546 * netmask.
547 */
548int					/* 0=bad */
549getnet(char *name,
550       naddr *addrp,			/* host byte order */
551       naddr *maskp)
552{
553	int i;
554	struct netent *np;
555	naddr mask;
556	struct in_addr in;
557	char hname[MAXHOSTNAMELEN+1];
558	char *mname, *p;
559
560
561	/* Detect and separate "1.2.3.4/24"
562	 */
563	if (0 != (mname = rindex(name,'/'))) {
564		i = (int)(mname - name);
565		if (i > sizeof(hname)-1)	/* name too long */
566			return 0;
567		bcopy(name, hname, i);
568		hname[i] = '\0';
569		mname++;
570		name = hname;
571	}
572
573	np = getnetbyname(name);
574	if (np != 0) {
575		in.s_addr = (naddr)np->n_net;
576	} else if (inet_aton(name, &in) == 1) {
577		HTONL(in.s_addr);
578	} else {
579		return 0;
580	}
581
582	if (mname == 0) {
583		/* we cannot use the interfaces here because we have not
584		 * looked at them yet.
585		 */
586		mask = std_mask(in.s_addr);
587		if ((~mask & ntohl(in.s_addr)) != 0)
588			mask = HOST_MASK;
589	} else {
590		mask = (naddr)strtoul(mname, &p, 0);
591		if (*p != '\0' || mask > 32)
592			return 0;
593		mask = HOST_MASK << (32-mask);
594	}
595	if (mask != 0 && in.s_addr == RIP_DEFAULT)
596		return 0;
597	if ((~mask & ntohl(in.s_addr)) != 0)
598		return 0;
599
600	*addrp = in.s_addr;
601	*maskp = mask;
602	return 1;
603}
604
605
606int					/* 0=bad */
607gethost(char *name,
608	naddr *addrp)
609{
610	struct hostent *hp;
611	struct in_addr in;
612
613
614	/* Try for a number first, even in IRIX where gethostbyname()
615	 * is smart.  This avoids hitting the name server which
616	 * might be sick because routing is.
617	 */
618	if (inet_aton(name, &in) == 1) {
619		*addrp = in.s_addr;
620		return 1;
621	}
622
623	hp = gethostbyname(name);
624	if (hp) {
625		bcopy(hp->h_addr, addrp, sizeof(*addrp));
626		return 1;
627	}
628
629	return 0;
630}
631