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