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