parms.c revision 19880
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.10 $"
40
41#include "defs.h"
42#include "pathnames.h"
43
44
45struct parm *parms;
46struct intnet *intnets;
47struct tgate *tgates;
48
49
50/* use configured parameters
51 */
52void
53get_parms(struct interface *ifp)
54{
55	static warned_auth_in, warned_auth_out;
56	struct parm *parmp;
57
58	/* get all relevant parameters
59	 */
60	for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
61		if (parmp->parm_name[0] == '\0'
62		    || !strcmp(ifp->int_name, parmp->parm_name)
63		    || (parmp->parm_name[0] == '\n'
64			&& on_net(ifp->int_addr,
65				  parmp->parm_net, parmp->parm_mask))) {
66
67			/* This group of parameters is relevant,
68			 * so get its settings
69			 */
70			ifp->int_state |= parmp->parm_int_state;
71			if (parmp->parm_auth.type != RIP_AUTH_NONE)
72				bcopy(&parmp->parm_auth, &ifp->int_auth,
73				      sizeof(ifp->int_auth));
74			if (parmp->parm_rdisc_pref != 0)
75				ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
76			if (parmp->parm_rdisc_int != 0)
77				ifp->int_rdisc_int = parmp->parm_rdisc_int;
78			if (parmp->parm_d_metric != 0)
79				ifp->int_d_metric = parmp->parm_d_metric;
80		}
81	}
82
83	/* Set general defaults.
84	 *
85	 * Default poor-man's router discovery to a metric that will
86	 * be heard by old versions of `routed`.  They ignored received
87	 * routes with metric 15.
88	 */
89	if ((ifp->int_state & IS_PM_RDISC)
90	    && ifp->int_d_metric == 0)
91		ifp->int_d_metric = FAKE_METRIC;
92
93	if (ifp->int_rdisc_int == 0)
94		ifp->int_rdisc_int = DefMaxAdvertiseInterval;
95
96	if (!(ifp->int_if_flags & IFF_MULTICAST)
97	    && !(ifp->int_state & IS_REMOTE))
98		ifp->int_state |= IS_BCAST_RDISC;
99
100	if (ifp->int_if_flags & IFF_POINTOPOINT) {
101		ifp->int_state |= IS_BCAST_RDISC;
102		/* By default, point-to-point links should be passive
103		 * about router-discovery for the sake of demand-dialing.
104		 */
105		if (0 == (ifp->int_state & GROUP_IS_SOL))
106			ifp->int_state |= IS_NO_SOL_OUT;
107		if (0 == (ifp->int_state & GROUP_IS_ADV))
108			ifp->int_state |= IS_NO_ADV_OUT;
109	}
110
111	if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
112		ifp->int_state |= IS_NO_RDISC;
113	if (ifp->int_state & IS_PASSIVE)
114		ifp->int_state |= IS_NO_RIP;
115
116	if (!IS_RIP_IN_OFF(ifp->int_state)
117	    && ifp->int_auth.type != RIP_AUTH_NONE
118	    && !(ifp->int_state & IS_NO_RIPV1_IN)
119	    && !warned_auth_in) {
120		msglog("Warning: RIPv1 input via %s"
121		       " will be accepted without authentication",
122		       ifp->int_name);
123		warned_auth_in = 1;
124	}
125	if (!IS_RIP_OUT_OFF(ifp->int_state)
126	    && ifp->int_auth.type != RIP_AUTH_NONE
127	    && !(ifp->int_state & IS_NO_RIPV1_OUT)
128	    && !warned_auth_out) {
129		msglog("Warning: RIPv1 output via %s"
130		       " will be sent without authentication",
131		       ifp->int_name);
132		warned_auth_out = 1;
133		ifp->int_auth.type = RIP_AUTH_NONE;
134	}
135}
136
137
138/* Read a list of gateways from /etc/gateways and add them to our tables.
139 *
140 * This file contains a list of "remote" gateways.  That is usually
141 * a gateway which we cannot immediately determine if it is present or
142 * not as we can do for those provided by directly connected hardware.
143 *
144 * If a gateway is marked "passive" in the file, then we assume it
145 * does not understand RIP and assume it is always present.  Those
146 * not marked passive are treated as if they were directly connected
147 * and assumed to be broken if they do not send us advertisements.
148 * All remote interfaces are added to our list, and those not marked
149 * passive are sent routing updates.
150 *
151 * A passive interface can also be local, hardware interface exempt
152 * from RIP.
153 */
154void
155gwkludge(void)
156{
157	FILE *fp;
158	char *p, *lptr;
159	char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9];
160	struct interface *ifp;
161	naddr dst, netmask, gate;
162	int metric, n;
163	u_int state;
164	char *type;
165
166
167	fp = fopen(_PATH_GATEWAYS, "r");
168	if (fp == 0)
169		return;
170
171	for (;;) {
172		if (0 == fgets(lbuf, sizeof(lbuf)-1, fp))
173			break;
174		lptr = lbuf;
175		while (*lptr == ' ')
176			lptr++;
177		if (*lptr == '\n'	/* ignore null and comment lines */
178		    || *lptr == '#')
179			continue;
180		p = lptr+strlen(lptr)-1;
181		while (*p == '\n' || *p == ' ')
182			*p-- = '\0';
183
184		/* notice newfangled parameter lines
185		 */
186		if (strncasecmp("net", lptr, 3)
187		    && strncasecmp("host", lptr, 4)) {
188			p = parse_parms(lptr);
189			if (p != 0) {
190				if (strcasecmp(p,lptr))
191					msglog("bad %s in "_PATH_GATEWAYS
192					       " entry \"%s\"", p, lptr);
193				else
194					msglog("bad \"%s\" in "_PATH_GATEWAYS,
195					       lptr);
196			}
197			continue;
198		}
199
200/*  {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */
201		qual[0] = '\0';
202		n = sscanf(lptr, "%4s %129[^ \t] gateway"
203			   " %64[^ / \t] metric %u %8s\n",
204			   net_host, dname, gname, &metric, qual);
205		if (n != 4 && n != 5) {
206			msglog("bad "_PATH_GATEWAYS" entry \"%s\"; %d values",
207			       lptr, n);
208			continue;
209		}
210		if (metric >= HOPCNT_INFINITY) {
211			msglog("bad metric in "_PATH_GATEWAYS" entry \"%s\"",
212			       lptr);
213			continue;
214		}
215		if (!strcasecmp(net_host, "host")) {
216			if (!gethost(dname, &dst)) {
217				msglog("bad host \"%s\" in "_PATH_GATEWAYS
218				       " entry \"%s\"", dname, lptr);
219				continue;
220			}
221			netmask = HOST_MASK;
222		} else if (!strcasecmp(net_host, "net")) {
223			if (!getnet(dname, &dst, &netmask)) {
224				msglog("bad net \"%s\" in "_PATH_GATEWAYS
225				       " entry \"%s\"", dname, lptr);
226				continue;
227			}
228		} else {
229			msglog("bad \"%s\" in "_PATH_GATEWAYS
230			       " entry \"%s\"", lptr);
231			continue;
232		}
233
234		if (!gethost(gname, &gate)) {
235			msglog("bad gateway \"%s\" in "_PATH_GATEWAYS
236			       " entry \"%s\"", gname, lptr);
237			continue;
238		}
239
240		if (!strcasecmp(qual, type = "passive")) {
241			/* Passive entries are not placed in our tables,
242			 * only the kernel's, so we don't copy all of the
243			 * external routing information within a net.
244			 * Internal machines should use the default
245			 * route to a suitable gateway (like us).
246			 */
247			state = IS_REMOTE | IS_PASSIVE;
248			if (metric == 0)
249				metric = 1;
250
251		} else if (!strcasecmp(qual, type = "external")) {
252			/* External entries are handled by other means
253			 * such as EGP, and are placed only in the daemon
254			 * tables to prevent overriding them with something
255			 * else.
256			 */
257			strcpy(qual,"external");
258			state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
259			if (metric == 0)
260				metric = 1;
261
262		} else if (!strcasecmp(qual, "active")
263			   || qual[0] == '\0') {
264			if (metric != 0) {
265				/* Entries that are neither "passive" nor
266				 * "external" are "remote" and must behave
267				 * like physical interfaces.  If they are not
268				 * heard from regularly, they are deleted.
269				 */
270				state = IS_REMOTE;
271				type = "remote";
272			} else {
273				/* "remote" entries with a metric of 0
274				 * are aliases for our own interfaces
275				 */
276				state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
277				type = "alias";
278			}
279
280		} else {
281			msglog("bad "_PATH_GATEWAYS" entry \"%s\";"
282			       " unknown type %s", lptr, qual);
283			continue;
284		}
285
286		if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
287			state |= IS_NO_RDISC;
288		if (state & IS_PASSIVE)
289			state |= IS_NO_RIP;
290
291		ifp = check_dup(gate,dst,netmask,0);
292		if (ifp != 0) {
293			msglog("duplicate "_PATH_GATEWAYS" entry \"%s\"",lptr);
294			continue;
295		}
296
297		ifp = (struct interface *)malloc(sizeof(*ifp));
298		bzero(ifp, sizeof(*ifp));
299
300		ifp->int_state = state;
301		if (netmask == HOST_MASK)
302			ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP_RUNNING;
303		else
304			ifp->int_if_flags = IFF_UP_RUNNING;
305		ifp->int_act_time = NEVER;
306		ifp->int_addr = gate;
307		ifp->int_dstaddr = dst;
308		ifp->int_mask = netmask;
309		ifp->int_ripv1_mask = netmask;
310		ifp->int_std_mask = std_mask(gate);
311		ifp->int_net = ntohl(dst);
312		ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
313		ifp->int_std_addr = htonl(ifp->int_std_net);
314		ifp->int_metric = metric;
315		if (!(state & IS_EXTERNAL)
316		    && ifp->int_mask != ifp->int_std_mask)
317			ifp->int_state |= IS_SUBNET;
318		(void)sprintf(ifp->int_name, "%s(%s)", type, gname);
319		ifp->int_index = -1;
320
321		if_link(ifp);
322	}
323
324	/* After all of the parameter lines have been read,
325	 * apply them to any remote interfaces.
326	 */
327	for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
328		get_parms(ifp);
329
330		tot_interfaces++;
331		if (!IS_RIP_OFF(ifp->int_state))
332			rip_interfaces++;
333
334		trace_if("Add", ifp);
335	}
336}
337
338
339/* strtok(), but honoring backslash
340 */
341static int				/* -1=bad */
342parse_quote(char **linep,
343	    char *delims,
344	    char *delimp,
345	    char *buf,
346	    int	lim)
347{
348	char c, *pc, *p;
349
350
351	pc = *linep;
352	if (*pc == '\0')
353		return -1;
354
355	for (;;) {
356		if (lim == 0)
357			return -1;
358		c = *pc++;
359		if (c == '\0')
360			break;
361
362		if (c == '\\' && pc != '\0') {
363			if ((c = *pc++) == 'n') {
364				c = '\n';
365			} else if (c == 'r') {
366				c = '\r';
367			} else if (c == 't') {
368				c = '\t';
369			} else if (c == 'b') {
370				c = '\b';
371			} else if (c >= '0' && c <= '7') {
372				c -= '0';
373				if (*pc >= '0' && *pc <= '7') {
374					c = (c<<3)+(*pc++ - '0');
375					if (*pc >= '0' && *pc <= '7')
376					    c = (c<<3)+(*pc++ - '0');
377				}
378			}
379
380		} else {
381			for (p = delims; *p != '\0'; ++p) {
382				if (*p == c)
383					goto exit;
384			}
385		}
386
387		*buf++ = c;
388		--lim;
389	}
390exit:
391	if (delimp != 0)
392		*delimp = c;
393	*linep = pc-1;
394	if (lim != 0)
395		*buf = '\0';
396	return 0;
397}
398
399
400/* Parse password timestamp
401 */
402static char *
403parse_ts(time_t *tp,
404	 char **valp,
405	 char *val0,
406	 char *delimp,
407	 char *buf,
408	 u_int bufsize)
409{
410	struct tm tm;
411
412	if (0 > parse_quote(valp, "| ,\n\r", delimp,
413			    buf,bufsize)
414	    || buf[bufsize-1] != '\0'
415	    || buf[bufsize-2] != '\0') {
416		sprintf(buf,"timestamp %.25s", val0);
417		return buf;
418	}
419	strcat(buf,"\n");
420	bzero(&tm, sizeof(tm));
421	if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n",
422			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
423			&tm.tm_hour, &tm.tm_min)) {
424		sprintf(buf,"timestamp %.25s", val0);
425		return buf;
426	}
427	if (tm.tm_year <= 37)
428		tm.tm_year += 100;
429
430	if ((*tp = mktime(&tm)) == -1) {
431		sprintf(buf,"timestamp %.25s", val0);
432		return buf;
433	}
434
435	return 0;
436}
437
438
439/* Get one or more password, key ID's, and expiration dates in
440 * the format
441 *	passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min|passwd|...
442 */
443static char *				/* 0 or error message */
444get_passwds(char *tgt,
445	    char *val,
446	    struct parm *parmp,
447	    u_char type)
448{
449	static char buf[80];
450	char *val0, *p, delim;
451	struct auth_key *akp, *akp2;
452	int i;
453	u_long l;
454
455
456	if (parmp->parm_auth.type != RIP_AUTH_NONE)
457		return "duplicate authentication";
458	parmp->parm_auth.type = type;
459
460	bzero(buf, sizeof(buf));
461
462	akp = parmp->parm_auth.keys;
463	for (i = 0; i < MAX_AUTH_KEYS; i++, val++, akp++) {
464		if ((delim = *val) == '\0')
465			break;
466		val0 = val;
467		if (0 > parse_quote(&val, "| ,\n\r", &delim,
468				    (char *)akp->key, sizeof(akp->key)))
469			return tgt;
470
471		akp->end = -1;
472
473		if (delim != '|') {
474			if (type == RIP_AUTH_MD5)
475				return "missing Keyid";
476			break;
477		}
478		val0 = ++val;
479		if (0 > parse_quote(&val, "| ,\n\r", &delim, buf,sizeof(buf))
480		    || buf[sizeof(buf)-1] != '\0'
481		    || (l = strtoul(buf,&p,0)) > 255
482		    || *p != '\0') {
483			sprintf(buf,"KeyID \"%.20s\"", val0);
484			return buf;
485		}
486		for (akp2 = parmp->parm_auth.keys; akp2 < akp; akp2++) {
487			if (akp2->keyid == l) {
488				*val = '\0';
489				sprintf(buf,"duplicate KeyID \"%.20s\"", val0);
490				return buf;
491			}
492		}
493		akp->keyid = (int)l;
494
495		if (delim != '|')
496			break;
497
498		val0 = ++val;
499		if (0 != (p = parse_ts(&akp->start,&val,val0,&delim,
500				       buf,sizeof(buf))))
501			return p;
502		if (delim != '|')
503			return "missing second timestamp";
504		val0 = ++val;
505		if (0 != (p = parse_ts(&akp->end,&val,val0,&delim,
506				       buf,sizeof(buf))))
507			return p;
508		if ((u_long)akp->start > (u_long)akp->end) {
509			sprintf(buf,"out of order timestamp %.30s",val0);
510			return buf;
511		}
512
513		if (delim != '|')
514			break;
515	}
516
517	return (delim != '\0') ? tgt : 0;
518}
519
520
521/* Parse a set of parameters for an interface.
522 */
523char *					/* 0 or error message */
524parse_parms(char *line)
525{
526#define PARS(str) (!strcasecmp(tgt, str))
527#define PARSEQ(str) (!strncasecmp(tgt, str"=", sizeof(str)))
528#define CKF(g,b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break;	\
529	parm.parm_int_state |= (b);}
530	struct parm parm;
531	struct intnet *intnetp;
532	struct tgate *tg;
533	naddr addr, mask;
534	char delim, *val0, *tgt, *val, *p;
535	char buf[64];
536
537
538	/* "subnet=x.y.z.u/mask,metric" must be alone on the line */
539	if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1)
540	    && *(val = &line[sizeof("subnet=")]) != '\0') {
541		intnetp = (struct intnet*)malloc(sizeof(*intnetp));
542		intnetp->intnet_metric = 1;
543		if ((p = strrchr(val,','))) {
544			*p++ = '\0';
545			intnetp->intnet_metric = (int)strtol(p,&p,0);
546			if (*p != '\0'
547			    || intnetp->intnet_metric <= 0
548			    || intnetp->intnet_metric >= HOPCNT_INFINITY)
549				return line;
550		}
551		if (!getnet(val, &intnetp->intnet_addr, &intnetp->intnet_mask)
552		    || intnetp->intnet_mask == HOST_MASK
553		    || intnetp->intnet_addr == RIP_DEFAULT) {
554			free(intnetp);
555			return line;
556		}
557		intnetp->intnet_next = intnets;
558		intnets = intnetp;
559		return 0;
560	}
561
562	bzero(&parm, sizeof(parm));
563
564	tgt = "null";
565	for (;;) {
566		tgt = line + strspn(line, " ,\n\r");
567		if (*tgt == '\0')
568			break;
569
570		line += strcspn(tgt, "= ,\n\r");
571		delim = *line;
572		if (delim == '=') {
573			val0 = ++line;
574			if (0 > parse_quote(&line," ,\n\r",&delim,
575					    buf,sizeof(buf)))
576				return tgt;
577		}
578		if (delim != '\0')
579			*line++ = '\0';
580
581		if (PARSEQ("if")) {
582			if (parm.parm_name[0] != '\0'
583			    || strlen(buf) > IFNAMSIZ)
584				return tgt;
585			strcpy(parm.parm_name, buf);
586
587		} else if (PARSEQ("addr")) {
588			/* This is a bad idea, because the address based
589			 * sets of parameters cannot be checked for
590			 * consistency with the interface name parameters.
591			 * The parm_net stuff is needed to allow several
592			 * -F settings.
593			 */
594			if (!getnet(val, &addr, &mask)
595			    || parm.parm_name[0] != '\0')
596				return tgt;
597			parm.parm_net = addr;
598			parm.parm_mask = mask;
599			parm.parm_name[0] = '\n';
600
601		} else if (PARSEQ("passwd")) {
602			tgt = get_passwds(tgt, val0, &parm, RIP_AUTH_PW);
603			if (tgt)
604				return tgt;
605
606		} else if (PARSEQ("md5_passwd")) {
607			tgt = get_passwds(tgt, val0, &parm, RIP_AUTH_MD5);
608			if (tgt)
609				return tgt;
610
611		} else if (PARS("no_ag")) {
612			parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
613
614		} else if (PARS("no_super_ag")) {
615			parm.parm_int_state |= IS_NO_SUPER_AG;
616
617		} else if (PARS("no_ripv1_in")) {
618			parm.parm_int_state |= IS_NO_RIPV1_IN;
619
620		} else if (PARS("no_ripv2_in")) {
621			parm.parm_int_state |= IS_NO_RIPV2_IN;
622
623		} else if (PARS("ripv2_out")) {
624			if (parm.parm_int_state & IS_NO_RIPV2_OUT)
625				return tgt;
626			parm.parm_int_state |= IS_NO_RIPV1_OUT;
627
628		} else if (PARS("ripv2")) {
629			if ((parm.parm_int_state & IS_NO_RIPV2_OUT)
630			    || (parm.parm_int_state & IS_NO_RIPV2_IN))
631				return tgt;
632			parm.parm_int_state |= (IS_NO_RIPV1_IN
633						| IS_NO_RIPV1_OUT);
634
635		} else if (PARS("no_rip")) {
636			CKF(IS_PM_RDISC, IS_NO_RIP);
637
638		} else if (PARS("no_rdisc")) {
639			CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
640
641		} else if (PARS("no_solicit")) {
642			CKF(GROUP_IS_SOL, IS_NO_SOL_OUT);
643
644		} else if (PARS("send_solicit")) {
645			CKF(GROUP_IS_SOL, IS_SOL_OUT);
646
647		} else if (PARS("no_rdisc_adv")) {
648			CKF(GROUP_IS_ADV, IS_NO_ADV_OUT);
649
650		} else if (PARS("rdisc_adv")) {
651			CKF(GROUP_IS_ADV, IS_ADV_OUT);
652
653		} else if (PARS("bcast_rdisc")) {
654			parm.parm_int_state |= IS_BCAST_RDISC;
655
656		} else if (PARS("passive")) {
657			CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC);
658			parm.parm_int_state |= IS_NO_RIP;
659
660		} else if (PARSEQ("rdisc_pref")) {
661			if (parm.parm_rdisc_pref != 0
662			    || (parm.parm_rdisc_pref = (int)strtoul(buf, &p,0),
663				*p != '\0'))
664				return tgt;
665
666		} else if (PARS("pm_rdisc")) {
667			if (IS_RIP_OUT_OFF(parm.parm_int_state))
668				return tgt;
669			parm.parm_int_state |= IS_PM_RDISC;
670
671		} else if (PARSEQ("rdisc_interval")) {
672			if (parm.parm_rdisc_int != 0
673			    || (parm.parm_rdisc_int = (int)strtoul(buf,&p,0),
674				*p != '\0')
675			    || parm.parm_rdisc_int < MinMaxAdvertiseInterval
676			    || parm.parm_rdisc_int > MaxMaxAdvertiseInterval)
677				return tgt;
678
679		} else if (PARSEQ("fake_default")) {
680			if (parm.parm_d_metric != 0
681			    || IS_RIP_OUT_OFF(parm.parm_int_state)
682			    || (parm.parm_d_metric = (int)strtoul(buf,&p,0),
683				*p != '\0')
684			    || parm.parm_d_metric > HOPCNT_INFINITY-1)
685				return tgt;
686
687		} else if (PARSEQ("trust_gateway")) {
688			if (!gethost(buf,&addr))
689				return tgt;
690			tg = (struct tgate *)malloc(sizeof(*tg));
691			tg->tgate_next = tgates;
692			tg->tgate_addr = addr;
693			tgates = tg;
694			parm.parm_int_state |= IS_DISTRUST;
695
696		} else {
697			return tgt;	/* error */
698		}
699	}
700
701	return check_parms(&parm);
702#undef PARS
703#undef PARSEQ
704}
705
706
707/* check for duplicate parameter specifications */
708char *					/* 0 or error message */
709check_parms(struct parm *new)
710{
711	struct parm *parmp;
712
713	/* set implicit values
714	 */
715	if (new->parm_int_state & IS_NO_ADV_IN)
716		new->parm_int_state |= IS_NO_SOL_OUT;
717
718	/* compare with existing sets of parameters
719	 */
720	for (parmp = parms; parmp != 0; parmp = parmp->parm_next) {
721		if (strcmp(new->parm_name, parmp->parm_name))
722			continue;
723		if (!on_net(htonl(parmp->parm_net),
724			    new->parm_net, new->parm_mask)
725		    && !on_net(htonl(new->parm_net),
726			       parmp->parm_net, parmp->parm_mask))
727			continue;
728
729		if (parmp->parm_auth.type != RIP_AUTH_NONE
730		    && new->parm_auth.type != RIP_AUTH_NONE
731		    && bcmp(&parmp->parm_auth, &new->parm_auth,
732			    sizeof(parmp->parm_auth))) {
733			return "conflicting, duplicate authentication";
734		}
735
736		if ((0 != (new->parm_int_state & GROUP_IS_SOL)
737		     && 0 != (parmp->parm_int_state & GROUP_IS_SOL)
738		     && 0 != ((new->parm_int_state ^ parmp->parm_int_state)
739			      && GROUP_IS_SOL))
740		    || (0 != (new->parm_int_state & GROUP_IS_ADV)
741			&& 0 != (parmp->parm_int_state & GROUP_IS_ADV)
742			&& 0 != ((new->parm_int_state ^ parmp->parm_int_state)
743				 && GROUP_IS_ADV))
744		    || (new->parm_rdisc_pref != 0
745			&& parmp->parm_rdisc_pref != 0
746			&& new->parm_rdisc_pref != parmp->parm_rdisc_pref)
747		    || (new->parm_rdisc_int != 0
748			&& parmp->parm_rdisc_int != 0
749			&& new->parm_rdisc_int != parmp->parm_rdisc_int)) {
750			return ("conflicting, duplicate router discovery"
751				" parameters");
752
753		}
754
755		if (new->parm_d_metric != 0
756		     && parmp->parm_d_metric != 0
757		     && new->parm_d_metric != parmp->parm_d_metric) {
758			return ("conflicting, duplicate poor man's router"
759				" discovery or fake default metric");
760		}
761	}
762
763	parmp = (struct parm*)malloc(sizeof(*parmp));
764	bcopy(new, parmp, sizeof(*parmp));
765	parmp->parm_next = parms;
766	parms = parmp;
767
768	return 0;
769}
770
771
772/* get a network number as a name or a number, with an optional "/xx"
773 * netmask.
774 */
775int					/* 0=bad */
776getnet(char *name,
777       naddr *netp,			/* host byte order */
778       naddr *maskp)
779{
780	int i;
781	struct netent *np;
782	naddr mask;
783	struct in_addr in;
784	char hname[MAXHOSTNAMELEN+1];
785	char *mname, *p;
786
787
788	/* Detect and separate "1.2.3.4/24"
789	 */
790	if (0 != (mname = rindex(name,'/'))) {
791		i = (int)(mname - name);
792		if (i > sizeof(hname)-1)	/* name too long */
793			return 0;
794		bcopy(name, hname, i);
795		hname[i] = '\0';
796		mname++;
797		name = hname;
798	}
799
800	np = getnetbyname(name);
801	if (np != 0) {
802		in.s_addr = (naddr)np->n_net;
803	} else if (inet_aton(name, &in) == 1) {
804		NTOHL(in.s_addr);
805	} else if (!mname && !strcasecmp(name,"default")) {
806		in.s_addr = RIP_DEFAULT;
807	} else {
808		return 0;
809	}
810
811	if (!mname) {
812		/* we cannot use the interfaces here because we have not
813		 * looked at them yet.
814		 */
815		mask = std_mask(in.s_addr);
816		if ((~mask & in.s_addr) != 0)
817			mask = HOST_MASK;
818	} else {
819		mask = (naddr)strtoul(mname, &p, 0);
820		if (*p != '\0' || mask > 32)
821			return 0;
822		mask = HOST_MASK << (32-mask);
823	}
824
825	/* must have mask of 0 with default */
826	if (mask != 0 && in.s_addr == RIP_DEFAULT)
827		return 0;
828	/* no host bits allowed in a network number */
829	if ((~mask & in.s_addr) != 0)
830		return 0;
831	/* require non-zero network number */
832	if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
833		return 0;
834	if (in.s_addr>>24 == 0 && in.s_addr != RIP_DEFAULT)
835		return 0;
836	if (in.s_addr>>24 == 0xff)
837		return 0;
838
839	*netp = in.s_addr;
840	*maskp = mask;
841	return 1;
842}
843
844
845int					/* 0=bad */
846gethost(char *name,
847	naddr *addrp)
848{
849	struct hostent *hp;
850	struct in_addr in;
851
852
853	/* Try for a number first, even in IRIX where gethostbyname()
854	 * is smart.  This avoids hitting the name server which
855	 * might be sick because routing is.
856	 */
857	if (inet_aton(name, &in) == 1) {
858		/* get a good number, but check that it it makes some
859		 * sense.
860		 */
861		if (ntohl(in.s_addr)>>24 == 0
862		    || ntohl(in.s_addr)>>24 == 0xff)
863			return 0;
864		*addrp = in.s_addr;
865		return 1;
866	}
867
868	hp = gethostbyname(name);
869	if (hp) {
870		bcopy(hp->h_addr, addrp, sizeof(*addrp));
871		return 1;
872	}
873
874	return 0;
875}
876