1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 *
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgment:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $FreeBSD: src/sbin/routed/parms.c,v 1.9 2000/08/11 08:24:38 sheldonh Exp $
37 */
38
39 #include "defs.h"
40 #include "pathnames.h"
41 #include <sys/stat.h>
42 #include <arpa/inet.h>
43 #include <ctype.h>
44
45 #define PARMS_MAXLINELEN 500
46 static struct parm *parms;
47 struct intnet *intnets;
48 struct r1net *r1nets;
49 struct tgate *tgates;
50
51 static void addroutefordefault(in_addr_t, in_addr_t, in_addr_t,
52 uint32_t, uint16_t);
53
54 /* use configured parameters */
55 void
get_parms(struct interface * ifp)56 get_parms(struct interface *ifp)
57 {
58 static boolean_t warned_auth_in, warned_auth_out;
59 struct parm *parmp;
60 int i, num_passwds = 0;
61
62 if (ifp == NULL)
63 return;
64
65 /* get all relevant parameters */
66 for (parmp = parms; parmp != NULL; parmp = parmp->parm_next) {
67 if (parmp->parm_name[0] == '\0' ||
68 strcmp(ifp->int_name, parmp->parm_name) == 0 ||
69 (parmp->parm_name[0] == '\n' &&
70 on_net(ifp->int_addr,
71 parmp->parm_net, parmp->parm_mask))) {
72
73 /*
74 * This group of parameters is relevant,
75 * so get its settings
76 */
77 ifp->int_state |= parmp->parm_int_state;
78 for (i = 0; i < MAX_AUTH_KEYS; i++) {
79 if (parmp->parm_auth[i].type == RIP_AUTH_NONE ||
80 num_passwds >= MAX_AUTH_KEYS)
81 break;
82 ifp->int_auth[num_passwds++] =
83 parmp->parm_auth[i];
84 }
85 if (parmp->parm_rdisc_pref != 0)
86 ifp->int_rdisc_pref = parmp->parm_rdisc_pref;
87 if (parmp->parm_rdisc_int != 0)
88 ifp->int_rdisc_int = parmp->parm_rdisc_int;
89 if (parmp->parm_d_metric != 0)
90 ifp->int_d_metric = parmp->parm_d_metric;
91 if (parmp->parm_ripout_addr != 0)
92 ifp->int_ripout_addr = parmp->parm_ripout_addr;
93 }
94 }
95
96 /*
97 * Set general defaults.
98 *
99 * Default poor-man's router discovery to a metric that will
100 * be heard by old versions of `routed`. They ignored received
101 * routes with metric 15.
102 */
103 if ((ifp->int_state & IS_PM_RDISC) && ifp->int_d_metric == 0)
104 ifp->int_d_metric = FAKE_METRIC;
105
106 if (ifp->int_rdisc_int == 0)
107 ifp->int_rdisc_int = DEF_MAXADVERTISEINTERVAL;
108
109 if (!(ifp->int_if_flags & IFF_MULTICAST) &&
110 !(ifp->int_state & IS_REMOTE))
111 ifp->int_state |= IS_BCAST_RDISC;
112
113 if (ifp->int_if_flags & IFF_POINTOPOINT) {
114 ifp->int_state |= IS_BCAST_RDISC;
115 /*
116 * By default, point-to-point links should be passive
117 * about router-discovery for the sake of demand-dialing.
118 */
119 if (!(ifp->int_state & GROUP_IS_SOL_OUT))
120 ifp->int_state |= IS_NO_SOL_OUT;
121 if (!(ifp->int_state & GROUP_IS_ADV_OUT))
122 ifp->int_state |= IS_NO_ADV_OUT;
123 }
124
125 if (0 != (ifp->int_state & (IS_PASSIVE | IS_REMOTE)))
126 ifp->int_state |= IS_NO_RDISC;
127 if (ifp->int_state & IS_PASSIVE)
128 ifp->int_state |= IS_NO_RIP;
129
130 if (!IS_RIP_IN_OFF(ifp->int_state) &&
131 ifp->int_auth[0].type != RIP_AUTH_NONE &&
132 !(ifp->int_state & IS_NO_RIPV1_IN) && !warned_auth_in) {
133 writelog(LOG_WARNING, "RIPv1 input via %s"
134 " will be accepted without authentication",
135 ifp->int_name);
136 warned_auth_in = _B_TRUE;
137 }
138 if (!IS_RIP_OUT_OFF(ifp->int_state) &&
139 ifp->int_auth[0].type != RIP_AUTH_NONE &&
140 !(ifp->int_state & IS_NO_RIPV1_OUT)) {
141 if (!warned_auth_out) {
142 writelog(LOG_WARNING, "RIPv1 output via %s"
143 " will be sent without authentication",
144 ifp->int_name);
145 warned_auth_out = _B_TRUE;
146 }
147 }
148
149 /*
150 * If not overriden by the rip_neighbor option, set the
151 * default address to which RIP packets will be sent on
152 * this interface.
153 */
154 if (ifp->int_ripout_addr == 0) {
155 if (ifp->int_state & IS_REMOTE) {
156 /*
157 * By definition we always send RIP packets to
158 * the address assigned to a remote interface.
159 */
160 ifp->int_ripout_addr = ifp->int_addr;
161 } else if ((ifp->int_state & IS_NO_RIPV1_OUT) &&
162 (ifp->int_if_flags & IFF_MULTICAST) &&
163 !(ifp->int_state & IS_NO_RIP_MCAST)) {
164 /*
165 * If the interface is being used for RIPv2
166 * and it supports multicast, and if the user
167 * has not explicitely turned off multicast
168 * RIP output, send to the all RIP routers
169 * multicast address.
170 */
171 ifp->int_ripout_addr = htonl(INADDR_RIP_GROUP);
172 } else if (ifp->int_if_flags & IFF_POINTOPOINT) {
173 /*
174 * For point-to-point interfaces which don't
175 * fall into the two categories above, just
176 * send to the destination address of the
177 * interface.
178 */
179 ifp->int_ripout_addr = ifp->int_dstaddr;
180 } else {
181 /* Otherwise, use the broadcast address. */
182 ifp->int_ripout_addr = ifp->int_brdaddr;
183 }
184 }
185 }
186
187
188 /*
189 * Read a list of gateways from /etc/gateways and add them to our tables.
190 *
191 * This file contains a list of "remote" gateways. That is usually
192 * a gateway which we cannot immediately determine if it is present or
193 * not as we can do for those provided by directly connected hardware.
194 *
195 * If a gateway is marked "passive" in the file, then we assume it
196 * does not understand RIP and assume it is always present. Those
197 * not marked passive are treated as if they were directly connected
198 * and assumed to be broken if they do not send us advertisements.
199 * All remote interfaces are added to our list, and those not marked
200 * passive are sent routing updates.
201 *
202 * A passive interface can also be local, hardware interface exempt
203 * from RIP.
204 */
205 void
gwkludge(void)206 gwkludge(void)
207 {
208 #define STR2(x) #x
209 #define STR(x) STR2(x)
210
211 #define NETHOST_LEN 4
212 #define DNAME_LEN MAXHOSTNAMELEN
213 #define GNAME_LEN MAXHOSTNAMELEN
214 #define QUAL_LEN 8
215
216 FILE *fp;
217 char *p, *lptr;
218 const char *cp;
219 char lbuf[PARMS_MAXLINELEN], net_host[NETHOST_LEN + 1];
220 char dname[MAXHOSTNAMELEN + 1];
221 char gname[MAXHOSTNAMELEN + 1], qual[QUAL_LEN +1];
222 struct interface *ifp;
223 uint32_t dst, netmask, gate;
224 int n;
225 uint32_t lnum;
226 struct stat sb;
227 uint32_t state, metric;
228 boolean_t default_dst;
229
230
231 fp = fopen(PATH_GATEWAYS, "r");
232 if (fp == NULL)
233 return;
234
235 if (0 > fstat(fileno(fp), &sb)) {
236 msglog("fstat() failed: %s for "PATH_GATEWAYS,
237 rip_strerror(errno));
238 (void) fclose(fp);
239 return;
240 }
241
242 for (lnum = 1; ; lnum++) {
243 if (NULL == fgets(lbuf, sizeof (lbuf), fp))
244 break;
245
246 /* Eliminate the /n character at the end of the lbuf */
247 if (strlen(lbuf) > 0)
248 lbuf[strlen(lbuf) - 1] = '\0';
249
250 /* Move lptr to the first non-space character */
251 for (lptr = lbuf; isspace(*lptr); lptr++)
252 ;
253
254 if (*lptr == '#' || *lptr == '\0')
255 continue;
256
257 /* Move p to the end of the line */
258 p = lptr + strlen(lptr) - 1;
259
260 /* Skip all trailing spaces except escaped space */
261 while (p > lptr && (isspace(*p) && *(p-1) != '\\'))
262 p--;
263
264 /* truncate the line to remove trailing spaces */
265 *++p = '\0';
266
267 /* notice newfangled parameter lines */
268 if (strncasecmp("net", lptr, 3) != 0 &&
269 strncasecmp("host", lptr, 4) != 0) {
270 cp = parse_parms(lptr, (sb.st_uid == 0 &&
271 !(sb.st_mode&(S_IRWXG|S_IRWXO))));
272 if (cp != 0)
273 msglog("%s in line %u of "PATH_GATEWAYS,
274 cp, lnum);
275 continue;
276 }
277
278 /*
279 * Processes lines of the follwoing format:
280 * net|host <name>[/mask] gateway <Gname> metric <value>
281 * passive|active|extern
282 */
283 qual[0] = '\0';
284 n = sscanf(lptr, "%"STR(NETHOST_LEN)"s %"STR(DNAME_LEN)
285 "[^ \t] gateway %"STR(GNAME_LEN)"[^ / \t] metric %u %"
286 STR(QUAL_LEN)"s\n", net_host, dname, gname, &metric, qual);
287 if (n != 4 && n != 5) {
288 msglog("bad "PATH_GATEWAYS" entry \"%s\"; %d values",
289 lptr, n);
290 continue;
291 }
292 if (metric >= HOPCNT_INFINITY) {
293 msglog("bad metric in "PATH_GATEWAYS" entry \"%s\"",
294 lptr);
295 continue;
296 }
297 default_dst = _B_FALSE;
298 if (strcasecmp(net_host, "host") == 0) {
299 if (!gethost(dname, &dst)) {
300 msglog("bad host \"%s\" in "PATH_GATEWAYS
301 " entry \"%s\"", dname, lptr);
302 continue;
303 }
304 netmask = HOST_MASK;
305 } else if (strcasecmp(net_host, "net") == 0) {
306 if (!getnet(dname, &dst, &netmask)) {
307 msglog("bad net \"%s\" in "PATH_GATEWAYS
308 " entry \"%s\"", dname, lptr);
309 continue;
310 }
311 default_dst = (dst == RIP_DEFAULT);
312 dst = htonl(dst); /* make network # into IP address */
313 } else {
314 msglog("bad \"%s\" in "PATH_GATEWAYS
315 " entry \"%s\"", net_host, lptr);
316 continue;
317 }
318
319 if (!gethost(gname, &gate)) {
320 msglog("bad gateway \"%s\" in "PATH_GATEWAYS
321 " entry \"%s\"", gname, lptr);
322 continue;
323 }
324
325 if (strcasecmp(qual, "passive") == 0) {
326 /*
327 * Passive entries are not placed in our tables,
328 * only the kernel's, so we don't copy all of the
329 * external routing information within a net.
330 * Internal machines should use the default
331 * route to a suitable gateway (like us).
332 */
333 state = IS_REMOTE | IS_PASSIVE;
334 if (metric == 0)
335 metric = 1;
336
337 } else if (strcasecmp(qual, "external") == 0) {
338 /*
339 * External entries are handled by other means
340 * such as EGP, and are placed only in the daemon
341 * tables to prevent overriding them with something
342 * else.
343 */
344 (void) strlcpy(qual, "external", sizeof (qual));
345 state = IS_REMOTE | IS_PASSIVE | IS_EXTERNAL;
346 if (metric == 0)
347 metric = 1;
348
349 } else if (strcasecmp(qual, "active") == 0 ||
350 qual[0] == '\0') {
351
352 if (default_dst) {
353 msglog("bad net \"%s\" in "PATH_GATEWAYS
354 " entry \"%s\"-- cannot be default",
355 dname, lptr);
356 continue;
357 }
358
359 if (metric != 0) {
360 /*
361 * Entries that are neither "passive" nor
362 * "external" are "remote" and must behave
363 * like physical interfaces. If they are not
364 * heard from regularly, they are deleted.
365 */
366 state = IS_REMOTE;
367 } else {
368 /*
369 * "remote" entries with a metric of 0
370 * are aliases for our own interfaces
371 */
372 state = IS_REMOTE | IS_PASSIVE | IS_ALIAS;
373 }
374
375 } else {
376 msglog("bad "PATH_GATEWAYS" entry \"%s\";"
377 " unknown type %s", lptr, qual);
378 continue;
379 }
380
381 if (0 != (state & (IS_PASSIVE | IS_REMOTE)))
382 state |= IS_NO_RDISC;
383 if (state & IS_PASSIVE)
384 state |= IS_NO_RIP;
385
386
387 if (default_dst) {
388 addroutefordefault(dst, gate, netmask, metric,
389 ((state & IS_EXTERNAL)? RTS_EXTERNAL : 0));
390 continue;
391 }
392
393 ifp = check_dup(NULL, gate, dst, netmask, 0, _B_FALSE);
394 if (ifp != NULL) {
395 msglog("duplicate "PATH_GATEWAYS" entry \"%s\"", lptr);
396 continue;
397 }
398
399 ifp = rtmalloc(sizeof (*ifp), "gwkludge()");
400 (void) memset(ifp, 0, sizeof (*ifp));
401
402 ifp->int_state = state;
403 if (netmask == HOST_MASK)
404 ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP;
405 else
406 ifp->int_if_flags = IFF_UP;
407 ifp->int_act_time = NEVER;
408 ifp->int_addr = gate;
409 ifp->int_dstaddr = dst;
410 ifp->int_mask = netmask;
411 ifp->int_ripv1_mask = netmask;
412 ifp->int_std_mask = std_mask(gate);
413 ifp->int_net = ntohl(dst);
414 ifp->int_std_net = ifp->int_net & ifp->int_std_mask;
415 ifp->int_std_addr = htonl(ifp->int_std_net);
416 ifp->int_metric = metric;
417 if (!(state & IS_EXTERNAL) &&
418 ifp->int_mask != ifp->int_std_mask)
419 ifp->int_state |= IS_SUBNET;
420 (void) snprintf(ifp->int_name, sizeof (ifp->int_name),
421 "remote(%s)", gname);
422
423 if_link(ifp, 0);
424 }
425
426 (void) fclose(fp);
427
428 /*
429 * After all of the parameter lines have been read,
430 * apply them to any remote interfaces.
431 */
432 for (ifp = ifnet; NULL != ifp; ifp = ifp->int_next) {
433 get_parms(ifp);
434
435 tot_interfaces++;
436 if (!IS_RIP_OFF(ifp->int_state))
437 rip_interfaces++;
438 if (!IS_RIP_OUT_OFF(ifp->int_state))
439 ripout_interfaces++;
440
441 trace_if("Add", ifp);
442 }
443
444 }
445
446 /* Parse password timestamp */
447 static char *
parse_ts(time_t * tp,char ** valp,char * val0,char * delimp,char * buf,uint_t bufsize)448 parse_ts(time_t *tp,
449 char **valp,
450 char *val0,
451 char *delimp,
452 char *buf,
453 uint_t bufsize)
454 {
455 struct tm tm;
456
457 if (0 > parse_quote(valp, "| ,", delimp, buf, bufsize) ||
458 buf[bufsize-1] != '\0' || buf[bufsize-2] != '\0') {
459 (void) snprintf(buf, bufsize, "bad timestamp %.25s", val0);
460 return (buf);
461 }
462 (void) strlcat(buf, "\n", bufsize);
463 (void) memset(&tm, 0, sizeof (tm));
464 if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n",
465 (unsigned *)&tm.tm_year, (unsigned *)&tm.tm_mon,
466 (unsigned *)&tm.tm_mday, (unsigned *)&tm.tm_hour,
467 (unsigned *)&tm.tm_min) ||
468 tm.tm_mon < 1 || tm.tm_mon > 12 ||
469 tm.tm_mday < 1 || tm.tm_mday > 31) {
470 (void) snprintf(buf, bufsize, "bad timestamp %.25s", val0);
471 return (buf);
472 }
473 tm.tm_mon--;
474 /* assume small years are in the 3rd millenium */
475 if (tm.tm_year <= 37)
476 tm.tm_year += 100;
477
478 if (tm.tm_year >= 1900)
479 tm.tm_year -= 1900;
480
481 if ((*tp = mktime(&tm)) == -1) {
482 (void) snprintf(buf, bufsize, "bad timestamp %.25s", val0);
483 return (buf);
484 }
485
486 return (NULL);
487 }
488
489
490 /*
491 * Get a password, key ID, and expiration date in the format
492 * passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min
493 * returns NULL or error message
494 */
495 static const char *
get_passwd(char * tgt,char * val,struct parm * parmp,uint16_t type,boolean_t safe)496 get_passwd(char *tgt,
497 char *val,
498 struct parm *parmp,
499 uint16_t type,
500 boolean_t safe) /* 1=from secure file */
501 {
502 static char buf[80];
503 char *val0, *p, delim;
504 struct auth k, *ap, *ap2;
505 int i;
506 ulong_t l;
507
508
509 if (!safe)
510 return ("ignore unsafe password");
511
512 for (ap = parmp->parm_auth, i = 0; ap->type != RIP_AUTH_NONE;
513 i++, ap++) {
514 if (i >= MAX_AUTH_KEYS)
515 return ("too many passwords");
516 }
517
518 (void) memset(&k, 0, sizeof (k));
519 k.type = type;
520 k.end = -1-DAY;
521
522 val0 = val;
523 if (0 > parse_quote(&val, "| ,", &delim,
524 (char *)k.key, sizeof (k.key)))
525 return (tgt);
526
527 if (delim != '|') {
528 if (type == RIP_AUTH_MD5)
529 return ("missing Keyid");
530 } else {
531 val0 = ++val;
532 buf[sizeof (buf)-1] = '\0';
533 if (0 > parse_quote(&val, "| ,", &delim, buf,
534 sizeof (buf)) ||
535 buf[sizeof (buf) - 1] != '\0' ||
536 (l = strtoul(buf, &p, 0)) > 255 ||
537 p == buf || *p != '\0') {
538 (void) snprintf(buf, sizeof (buf),
539 "bad KeyID \"%.20s\"", val0);
540 return (buf);
541 }
542 for (ap2 = parmp->parm_auth; ap2 < ap; ap2++) {
543 if (ap2->keyid == l) {
544 (void) snprintf(buf, sizeof (buf),
545 "duplicate KeyID \"%.20s\"",
546 val0);
547 return (buf);
548 }
549 }
550 k.keyid = (int)l;
551
552 if (delim == '|') {
553 val0 = ++val;
554 if (NULL != (p = parse_ts(&k.start, &val, val0, &delim,
555 buf, sizeof (buf))))
556 return (p);
557 if (delim != '|')
558 return ("missing second timestamp");
559 val0 = ++val;
560 if (NULL != (p = parse_ts(&k.end, &val, val0, &delim,
561 buf, sizeof (buf))))
562 return (p);
563 if ((ulong_t)k.start > (ulong_t)k.end) {
564 (void) snprintf(buf, sizeof (buf),
565 "out of order timestamp %.30s", val0);
566 return (buf);
567 }
568 }
569 }
570 if (delim != '\0')
571 return (tgt);
572
573 (void) memmove(ap, &k, sizeof (*ap));
574 return (NULL);
575 }
576
577
578 static const char *
bad_str(const char * estr)579 bad_str(const char *estr)
580 {
581 static char buf[100+8];
582
583 (void) snprintf(buf, sizeof (buf), "bad \"%.100s\"", estr);
584 return (buf);
585 }
586
587
588 /*
589 * Parse a set of parameters for an interface.
590 * returns NULL or error message
591 */
592 const char *
parse_parms(char * line,boolean_t safe)593 parse_parms(char *line,
594 boolean_t safe) /* 1=from secure file */
595 {
596 #define PARS(str) (strcasecmp(tgt, str) == 0)
597 #define PARSEQ(str) (strncasecmp(tgt, str"=", sizeof (str)) == 0)
598 /*
599 * This macro checks for conflicting configurations options
600 * For eg one can set either the IS_NO_SOL_OUT flag bit or the IS_SOL_OUT flag
601 * bit, but not both.
602 */
603 #define CKF(g, b) {if (0 != (parm.parm_int_state & ((g) & ~(b)))) break; \
604 parm.parm_int_state |= (b); }
605 struct parm parm;
606 struct intnet *intnetp;
607 struct r1net *r1netp;
608 struct tgate *tg;
609 uint32_t addr, mask;
610 char delim, *val0 = 0, *tgt, *val, *p;
611 const char *msg;
612 char buf[PARMS_MAXLINELEN], buf2[PARMS_MAXLINELEN];
613 int i;
614
615
616 /* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */
617 if (strncasecmp(line, "subnet=", sizeof ("subnet=") - 1) == 0 &&
618 *(val = &line[sizeof ("subnet=") -1 ]) != '\0') {
619 if (0 > parse_quote(&val, ",", &delim, buf, sizeof (buf)))
620 return (bad_str(line));
621 intnetp = rtmalloc(sizeof (*intnetp),
622 "parse_parms subnet");
623 intnetp->intnet_metric = 1;
624 if (delim == ',') {
625 intnetp->intnet_metric = (int)strtol(val+1, &p, 0);
626 if (*p != '\0' || intnetp->intnet_metric <= 0 ||
627 val+1 == p ||
628 intnetp->intnet_metric >= HOPCNT_INFINITY) {
629 free(intnetp);
630 return (bad_str(line));
631 }
632 }
633 if (!getnet(buf, &intnetp->intnet_addr,
634 &intnetp->intnet_mask) ||
635 intnetp->intnet_mask == HOST_MASK ||
636 intnetp->intnet_addr == RIP_DEFAULT) {
637 free(intnetp);
638 return (bad_str(line));
639 }
640 intnetp->intnet_addr = htonl(intnetp->intnet_addr);
641 intnetp->intnet_next = intnets;
642 intnets = intnetp;
643 return (NULL);
644 }
645
646 /*
647 * "ripv1_mask=x.y.z.u/mask1,mask2" must be alone on the line.
648 * This requires that x.y.z.u/mask1 be considered a subnet of
649 * x.y.z.u/mask2, as if x.y.z.u/mask2 were a class-full network.
650 */
651 if (!strncasecmp(line, "ripv1_mask=", sizeof ("ripv1_mask=") - 1) &&
652 *(val = &line[sizeof ("ripv1_mask=")-1]) != '\0') {
653 if (0 > parse_quote(&val, ",", &delim, buf, sizeof (buf)) ||
654 delim == '\0')
655 return (bad_str(line));
656 if ((i = (int)strtol(val+1, &p, 0)) <= 0 || i > 32 ||
657 *p != '\0')
658 return (bad_str(line));
659 r1netp = rtmalloc(sizeof (*r1netp), "parse_parms ripv1_mask");
660 r1netp->r1net_mask = HOST_MASK << (32-i);
661 if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match) ||
662 r1netp->r1net_net == RIP_DEFAULT ||
663 r1netp->r1net_mask > r1netp->r1net_match) {
664 free(r1netp);
665 return (bad_str(line));
666 }
667 r1netp->r1net_next = r1nets;
668 r1nets = r1netp;
669 return (NULL);
670 }
671
672 (void) memset(&parm, 0, sizeof (parm));
673 /*
674 * Support of the following for Solaris backward compatibility
675 * norip <ifname>
676 * noripin <ifname>
677 * noripout <ifname>
678 */
679 if (strncasecmp("norip", line, 5) == 0) {
680 char cmd[64], ifname[64];
681 int n;
682
683 n = sscanf(line, "%63s %63s\n", cmd, ifname);
684 if (n != 2) {
685 /* Not enough parameters */
686 return (bad_str(line));
687 }
688
689 /*
690 * Get the interface name and turn on the appropriate
691 * interface flags
692 */
693 (void) strlcpy(parm.parm_name, ifname, sizeof (parm.parm_name));
694 if (strcasecmp("norip", cmd) == 0) {
695 parm.parm_int_state |= IS_NO_RIP;
696 } else if (strcasecmp("noripin", cmd) == 0) {
697 parm.parm_int_state |= IS_NO_RIP_IN;
698 } else if (strcasecmp("noripout", cmd) == 0) {
699 parm.parm_int_state |= IS_NO_RIP_OUT;
700 } else {
701 /* Bad command */
702 return (bad_str(line));
703 }
704 /*
705 * Look for duplication, and if new,
706 * link to the rest of the parm entries.
707 */
708 return (insert_parm(&parm));
709 }
710
711 for (;;) {
712 tgt = line + strspn(line, " ,\n\r");
713 if (*tgt == '\0' || *tgt == '#')
714 break;
715 line = tgt+strcspn(tgt, "= #,\n\r");
716 delim = *line;
717 if (delim == '=') {
718 val0 = ++line;
719 if (0 > parse_quote(&line, " #,", &delim,
720 buf, sizeof (buf)))
721 return (bad_str(tgt));
722 }
723 if (delim != '\0') {
724 for (;;) {
725 *line = '\0';
726 if (delim == '#')
727 break;
728 ++line;
729 if (!isspace(delim) ||
730 ((delim = *line), !isspace(delim)))
731 break;
732 }
733 }
734
735 if (PARSEQ("if")) {
736 if (parm.parm_name[0] != '\0' ||
737 strlen(buf) > IF_NAME_LEN)
738 return (bad_str(tgt));
739 (void) strlcpy(parm.parm_name, buf,
740 sizeof (parm.parm_name));
741
742 } else if (PARSEQ("addr")) {
743 /*
744 * This is a bad idea, because the address based
745 * sets of parameters cannot be checked for
746 * consistency with the interface name parameters.
747 * The parm_net stuff is needed to allow several
748 * -F settings.
749 */
750 if (!getnet(val0, &addr, &mask) ||
751 parm.parm_name[0] != '\0')
752 return (bad_str(tgt));
753 parm.parm_net = addr;
754 parm.parm_mask = mask;
755 parm.parm_name[0] = '\n';
756
757 } else if (PARSEQ("passwd")) {
758 /*
759 * since cleartext passwords are so weak allow
760 * them anywhere
761 */
762 msg = get_passwd(tgt, val0, &parm, RIP_AUTH_PW, 1);
763 if (msg) {
764 *val0 = '\0';
765 return (bad_str(msg));
766 }
767
768 } else if (PARSEQ("md5_passwd")) {
769 msg = get_passwd(tgt, val0, &parm, RIP_AUTH_MD5, safe);
770 if (msg) {
771 *val0 = '\0';
772 return (bad_str(msg));
773 }
774
775 } else if (PARS("no_ag")) {
776 parm.parm_int_state |= (IS_NO_AG | IS_NO_SUPER_AG);
777
778 } else if (PARS("no_host")) {
779 parm.parm_int_state |= IS_NO_HOST;
780
781 } else if (PARS("no_super_ag")) {
782 parm.parm_int_state |= IS_NO_SUPER_AG;
783
784 } else if (PARS("no_ripv1_in")) {
785 parm.parm_int_state |= IS_NO_RIPV1_IN;
786
787 } else if (PARS("no_ripv2_in")) {
788 parm.parm_int_state |= IS_NO_RIPV2_IN;
789
790 } else if (PARS("ripv2_out")) {
791 if (parm.parm_int_state & IS_NO_RIPV2_OUT)
792 return (bad_str(tgt));
793 parm.parm_int_state |= IS_NO_RIPV1_OUT;
794
795 } else if (PARS("ripv2")) {
796 if ((parm.parm_int_state & IS_NO_RIPV2_OUT) ||
797 (parm.parm_int_state & IS_NO_RIPV2_IN))
798 return (bad_str(tgt));
799 parm.parm_int_state |= (IS_NO_RIPV1_IN
800 | IS_NO_RIPV1_OUT);
801
802 } else if (PARS("no_rip")) {
803 CKF(IS_PM_RDISC, IS_NO_RIP);
804
805 } else if (PARS("no_rip_mcast")) {
806 parm.parm_int_state |= IS_NO_RIP_MCAST;
807
808 } else if (PARS("no_rdisc")) {
809 CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
810
811 } else if (PARS("no_solicit")) {
812 CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT);
813
814 } else if (PARS("send_solicit")) {
815 CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT);
816
817 } else if (PARS("no_rdisc_adv")) {
818 CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT);
819
820 } else if (PARS("rdisc_adv")) {
821 CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT);
822
823 } else if (PARS("bcast_rdisc")) {
824 parm.parm_int_state |= IS_BCAST_RDISC;
825
826 } else if (PARS("passive")) {
827 CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC);
828 parm.parm_int_state |= IS_NO_RIP | IS_PASSIVE;
829
830 } else if (PARSEQ("rdisc_pref")) {
831 if (parm.parm_rdisc_pref != 0 ||
832 (parm.parm_rdisc_pref = (int)strtol(buf, &p, 0),
833 *p != '\0') || (buf == p))
834 return (bad_str(tgt));
835
836 } else if (PARS("pm_rdisc")) {
837 if (IS_RIP_OUT_OFF(parm.parm_int_state))
838 return (bad_str(tgt));
839 parm.parm_int_state |= IS_PM_RDISC;
840
841 } else if (PARSEQ("rdisc_interval")) {
842 if (parm.parm_rdisc_int != 0 ||
843 (parm.parm_rdisc_int = (int)strtoul(buf, &p, 0),
844 *p != '\0') || (buf == p) ||
845 parm.parm_rdisc_int < MIN_MAXADVERTISEINTERVAL ||
846 parm.parm_rdisc_int > MAX_MAXADVERTISEINTERVAL)
847 return (bad_str(tgt));
848
849 } else if (PARSEQ("fake_default")) {
850 if (parm.parm_d_metric != 0 ||
851 IS_RIP_OUT_OFF(parm.parm_int_state) ||
852 (parm.parm_d_metric = (int)strtoul(buf, &p, 0),
853 *p != '\0') || (buf == p) ||
854 parm.parm_d_metric > HOPCNT_INFINITY-1)
855 return (bad_str(tgt));
856
857 } else if (PARSEQ("trust_gateway")) {
858 /* look for trust_gateway=x.y.z|net/mask|...) */
859 p = buf;
860 if (0 > parse_quote(&p, "|", &delim, buf2,
861 sizeof (buf2)) || !gethost(buf2, &addr))
862 return (bad_str(tgt));
863 tg = rtmalloc(sizeof (*tg),
864 "parse_parms trust_gateway");
865 (void) memset(tg, 0, sizeof (*tg));
866 tg->tgate_addr = addr;
867 i = 0;
868 /* The default is to trust all routes. */
869 while (delim == '|') {
870 p++;
871 if (i >= MAX_TGATE_NETS ||
872 0 > parse_quote(&p, "|", &delim, buf2,
873 sizeof (buf2)) ||
874 !getnet(buf2, &tg->tgate_nets[i].net,
875 &tg->tgate_nets[i].mask) ||
876 tg->tgate_nets[i].net == RIP_DEFAULT ||
877 tg->tgate_nets[i].mask == 0) {
878 free(tg);
879 return (bad_str(tgt));
880 }
881 i++;
882 }
883 tg->tgate_next = tgates;
884 tgates = tg;
885 parm.parm_int_state |= IS_DISTRUST;
886
887 } else if (PARS("redirect_ok")) {
888 parm.parm_int_state |= IS_REDIRECT_OK;
889
890 } else if (PARSEQ("rip_neighbor")) {
891 if (parm.parm_name[0] == '\0' ||
892 gethost(buf, &parm.parm_ripout_addr) != 1)
893 return (bad_str(tgt));
894
895 } else {
896 return (bad_str(tgt)); /* error */
897 }
898 }
899
900 return (insert_parm(&parm));
901 #undef PARS
902 #undef PARSEQ
903 #undef CKF
904 }
905
906
907 /*
908 * Insert parameter specifications into the parms list. Returns NULL if
909 * successful, or an error message otherwise.
910 */
911 const char *
insert_parm(struct parm * new)912 insert_parm(struct parm *new)
913 {
914 struct parm *parmp, **parmpp;
915 int i, num_passwds;
916
917 /* set implicit values */
918 if (new->parm_int_state & (IS_NO_ADV_IN|IS_NO_SOL_OUT))
919 new->parm_int_state |= IS_NO_ADV_IN|IS_NO_SOL_OUT;
920
921 for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) {
922 if (new->parm_auth[i].type != RIP_AUTH_NONE)
923 num_passwds++;
924 }
925
926 /* compare with existing sets of parameters */
927 for (parmpp = &parms; (parmp = *parmpp) != 0;
928 parmpp = &parmp->parm_next) {
929 if (strcmp(new->parm_name, parmp->parm_name) != 0)
930 continue;
931 if (!on_net(htonl(parmp->parm_net), new->parm_net,
932 new->parm_mask) &&
933 !on_net(htonl(new->parm_net), parmp->parm_net,
934 parmp->parm_mask))
935 continue;
936
937 for (i = 0; i < MAX_AUTH_KEYS; i++) {
938 if (parmp->parm_auth[i].type != RIP_AUTH_NONE)
939 num_passwds++;
940 }
941 if (num_passwds > MAX_AUTH_KEYS)
942 return ("too many conflicting passwords");
943
944 if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT) &&
945 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT) &&
946 0 != ((new->parm_int_state ^ parmp->parm_int_state) &&
947 GROUP_IS_SOL_OUT)) ||
948 (0 != (new->parm_int_state & GROUP_IS_ADV_OUT) &&
949 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT) &&
950 0 != ((new->parm_int_state ^ parmp->parm_int_state) &&
951 GROUP_IS_ADV_OUT)) ||
952 (new->parm_rdisc_pref != 0 &&
953 parmp->parm_rdisc_pref != 0 &&
954 new->parm_rdisc_pref != parmp->parm_rdisc_pref) ||
955 (new->parm_rdisc_int != 0 &&
956 parmp->parm_rdisc_int != 0 &&
957 new->parm_rdisc_int != parmp->parm_rdisc_int)) {
958 return ("conflicting, duplicate router discovery"
959 " parameters");
960
961 }
962
963 if (new->parm_d_metric != 0 && parmp->parm_d_metric != 0 &&
964 new->parm_d_metric != parmp->parm_d_metric) {
965 return ("conflicting, duplicate poor man's router"
966 " discovery or fake default metric");
967 }
968 }
969
970 /*
971 * link new entry on the list so that when the entries are scanned,
972 * they affect the result in the order the operator specified.
973 */
974 parmp = rtmalloc(sizeof (*parmp), "insert_parm");
975 (void) memcpy(parmp, new, sizeof (*parmp));
976 *parmpp = parmp;
977
978 return (NULL);
979 }
980
981 int /* 0=bad */
gethost(char * name,in_addr_t * addrp)982 gethost(char *name, in_addr_t *addrp)
983 {
984 struct hostent *hp;
985 struct in_addr in;
986
987
988 /*
989 * Try for a number first. This avoids hitting the name
990 * server which might be sick because routing is.
991 */
992 if ((in.s_addr = inet_addr(name)) != (in_addr_t)-1) {
993 /*
994 * get a good number, but check that it makes some
995 * sense.
996 */
997 if ((ntohl(in.s_addr) >> 24) == 0 ||
998 (ntohl(in.s_addr) >> 24) == 0xff)
999 return (0);
1000 *addrp = in.s_addr;
1001 return (1);
1002 }
1003
1004 hp = gethostbyname(name);
1005 if (hp != NULL) {
1006 (void) memcpy(addrp, hp->h_addr, sizeof (*addrp));
1007 return (1);
1008 }
1009
1010 return (0);
1011 }
1012
1013
1014 static void
addroutefordefault(in_addr_t dst,in_addr_t gate,in_addr_t mask,uint32_t metric,uint16_t rts_flags)1015 addroutefordefault(in_addr_t dst, in_addr_t gate, in_addr_t mask,
1016 uint32_t metric, uint16_t rts_flags)
1017 {
1018 struct rt_spare new;
1019 struct interface *ifp;
1020 uint16_t rt_newstate = RS_STATIC;
1021
1022
1023 ifp = iflookup(gate);
1024 if (ifp == NULL) {
1025 msglog("unreachable gateway %s in "PATH_GATEWAYS,
1026 naddr_ntoa(gate));
1027 return;
1028 }
1029
1030 trace_misc("addroutefordefault: found interface %s", ifp->int_name);
1031
1032 (void) memset(&new, 0, sizeof (new));
1033 new.rts_ifp = ifp;
1034 new.rts_router = gate;
1035 new.rts_gate = gate;
1036 new.rts_metric = metric;
1037 new.rts_time = now.tv_sec;
1038 new.rts_flags = rts_flags;
1039 new.rts_origin = RO_FILE;
1040
1041 input_route(dst, mask, &new, NULL, rt_newstate);
1042 }
1043