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