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