xref: /openbsd/usr.sbin/ospfd/parse.y (revision a1533359)
1 /*	$OpenBSD: parse.y,v 1.93 2018/11/01 00:18:44 sashan Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
8  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
9  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 %{
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <ifaddrs.h>
35 #include <limits.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <syslog.h>
40 
41 #include "ospf.h"
42 #include "ospfd.h"
43 #include "ospfe.h"
44 #include "log.h"
45 
46 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
47 static struct file {
48 	TAILQ_ENTRY(file)	 entry;
49 	FILE			*stream;
50 	char			*name;
51 	size_t			 ungetpos;
52 	size_t			 ungetsize;
53 	u_char			*ungetbuf;
54 	int			 eof_reached;
55 	int			 lineno;
56 	int			 errors;
57 } *file, *topfile;
58 struct file	*pushfile(const char *, int);
59 int		 popfile(void);
60 int		 check_file_secrecy(int, const char *);
61 int		 yyparse(void);
62 int		 yylex(void);
63 int		 yyerror(const char *, ...)
64     __attribute__((__format__ (printf, 1, 2)))
65     __attribute__((__nonnull__ (1)));
66 int		 kw_cmp(const void *, const void *);
67 int		 lookup(char *);
68 int		 igetc(void);
69 int		 lgetc(int);
70 void		 lungetc(int);
71 int		 findeol(void);
72 
73 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
74 struct sym {
75 	TAILQ_ENTRY(sym)	 entry;
76 	int			 used;
77 	int			 persist;
78 	char			*nam;
79 	char			*val;
80 };
81 int		 symset(const char *, const char *, int);
82 char		*symget(const char *);
83 
84 void		 clear_config(struct ospfd_conf *xconf);
85 u_int32_t	 get_rtr_id(void);
86 int		 host(const char *, struct in_addr *, struct in_addr *);
87 
88 static struct ospfd_conf	*conf;
89 static int			 errors = 0;
90 
91 struct area	*area = NULL;
92 struct iface	*iface = NULL;
93 
94 struct config_defaults {
95 	char		auth_key[MAX_SIMPLE_AUTH_LEN];
96 	struct auth_md_head	 md_list;
97 	u_int32_t	dead_interval;
98 	u_int32_t	fast_hello_interval;
99 	u_int16_t	transmit_delay;
100 	u_int16_t	hello_interval;
101 	u_int16_t	rxmt_interval;
102 	u_int16_t	metric;
103 	enum auth_type	auth_type;
104 	u_int8_t	auth_keyid;
105 	u_int8_t	priority;
106 };
107 
108 struct config_defaults	 globaldefs;
109 struct config_defaults	 areadefs;
110 struct config_defaults	 ifacedefs;
111 struct config_defaults	*defs;
112 
113 struct area	*conf_get_area(struct in_addr);
114 struct iface	*conf_get_if(struct kif *, struct kif_addr *);
115 int		 conf_check_rdomain(unsigned int);
116 
117 typedef struct {
118 	union {
119 		int64_t		 number;
120 		char		*string;
121 		struct redistribute *redist;
122 	} v;
123 	int lineno;
124 } YYSTYPE;
125 
126 %}
127 
128 %token	AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL RDOMAIN
129 %token	RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
130 %token	AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
131 %token	METRIC PASSIVE
132 %token	HELLOINTERVAL FASTHELLOINTERVAL TRANSMITDELAY
133 %token	RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
134 %token	SET TYPE
135 %token	YES NO
136 %token	MSEC MINIMAL
137 %token	DEMOTE
138 %token	INCLUDE
139 %token	ERROR
140 %token	DEPEND ON
141 %token	<v.string>	STRING
142 %token	<v.number>	NUMBER
143 %type	<v.number>	yesno no optlist optlist_l option demotecount msec
144 %type	<v.number>	deadtime
145 %type	<v.string>	string dependon
146 %type	<v.redist>	redistribute
147 
148 %%
149 
150 grammar		: /* empty */
151 		| grammar include '\n'
152 		| grammar '\n'
153 		| grammar conf_main '\n'
154 		| grammar varset '\n'
155 		| grammar area '\n'
156 		| grammar error '\n'		{ file->errors++; }
157 		;
158 
159 include		: INCLUDE STRING		{
160 			struct file	*nfile;
161 
162 			if ((nfile = pushfile($2,
163 			    !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
164 				yyerror("failed to include file %s", $2);
165 				free($2);
166 				YYERROR;
167 			}
168 			free($2);
169 
170 			file = nfile;
171 			lungetc('\n');
172 		}
173 		;
174 
175 string		: string STRING	{
176 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
177 				free($1);
178 				free($2);
179 				yyerror("string: asprintf");
180 				YYERROR;
181 			}
182 			free($1);
183 			free($2);
184 		}
185 		| STRING
186 		;
187 
188 yesno		: YES	{ $$ = 1; }
189 		| NO	{ $$ = 0; }
190 		;
191 
192 no		: /* empty */	{ $$ = 0; }
193 		| NO		{ $$ = 1; }
194 		;
195 
196 msec		: MSEC NUMBER {
197 			$$ = $2;
198 		}
199 		| NUMBER {
200 			$$ = $1 * 1000;
201 		}
202 		;
203 
204 varset		: STRING '=' string		{
205 			char *s = $1;
206 			if (conf->opts & OSPFD_OPT_VERBOSE)
207 				printf("%s = \"%s\"\n", $1, $3);
208 			while (*s++) {
209 				if (isspace((unsigned char)*s)) {
210 					yyerror("macro name cannot contain "
211 					    "whitespace");
212 					free($1);
213 					free($3);
214 					YYERROR;
215 				}
216 			}
217 			if (symset($1, $3, 0) == -1)
218 				fatal("cannot store variable");
219 			free($1);
220 			free($3);
221 		}
222 		;
223 
224 conf_main	: ROUTERID STRING {
225 			if (!inet_aton($2, &conf->rtr_id)) {
226 				yyerror("error parsing router-id");
227 				free($2);
228 				YYERROR;
229 			}
230 			free($2);
231 		}
232 		| FIBUPDATE yesno {
233 			if ($2 == 0)
234 				conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
235 			else
236 				conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
237 		}
238 		| redistribute {
239 			SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
240 			conf->redistribute = 1;
241 		}
242 		| RTLABEL STRING EXTTAG NUMBER {
243 			if ($4 < 0 || $4 > UINT_MAX) {
244 				yyerror("invalid external route tag");
245 				free($2);
246 				YYERROR;
247 			}
248 			rtlabel_tag(rtlabel_name2id($2), $4);
249 			free($2);
250 		}
251 		| RDOMAIN NUMBER {
252 			if ($2 < 0 || $2 > RT_TABLEID_MAX) {
253 				yyerror("invalid rdomain");
254 				YYERROR;
255 			}
256 			conf->rdomain = $2;
257 		}
258 		| RFC1583COMPAT yesno {
259 			conf->rfc1583compat = $2;
260 		}
261 		| SPFDELAY msec {
262 			if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
263 				yyerror("spf-delay out of range "
264 				    "(%d-%d)", MIN_SPF_DELAY,
265 				    MAX_SPF_DELAY);
266 				YYERROR;
267 			}
268 			conf->spf_delay = $2;
269 		}
270 		| SPFHOLDTIME msec {
271 			if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
272 				yyerror("spf-holdtime out of range "
273 				    "(%d-%d)", MIN_SPF_HOLDTIME,
274 				    MAX_SPF_HOLDTIME);
275 				YYERROR;
276 			}
277 			conf->spf_hold_time = $2;
278 		}
279 		| STUB ROUTER yesno {
280 			if ($3)
281 				conf->flags |= OSPFD_FLAG_STUB_ROUTER;
282 			else
283 				/* allow to force non stub mode */
284 				conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
285 		}
286 		| defaults
287 		;
288 
289 
290 redistribute	: no REDISTRIBUTE NUMBER '/' NUMBER optlist dependon {
291 			struct redistribute	*r;
292 
293 			if ((r = calloc(1, sizeof(*r))) == NULL)
294 				fatal(NULL);
295 			r->type = REDIST_ADDR;
296 			if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) {
297 				yyerror("bad network: %llu/%llu", $3, $5);
298 				free(r);
299 				YYERROR;
300 			}
301 			r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT);
302 			r->mask.s_addr = prefixlen2mask($5);
303 
304 			if ($1)
305 				r->type |= REDIST_NO;
306 			else
307 				conf->redist_label_or_prefix = 1;
308 			r->metric = $6;
309 			if ($7)
310 				strlcpy(r->dependon, $7, sizeof(r->dependon));
311 			else
312 				r->dependon[0] = '\0';
313 			free($7);
314 			$$ = r;
315 		}
316 		| no REDISTRIBUTE STRING optlist dependon {
317 			struct redistribute	*r;
318 
319 			if ((r = calloc(1, sizeof(*r))) == NULL)
320 				fatal(NULL);
321 			if (!strcmp($3, "default"))
322 				r->type = REDIST_DEFAULT;
323 			else if (!strcmp($3, "static"))
324 				r->type = REDIST_STATIC;
325 			else if (!strcmp($3, "connected"))
326 				r->type = REDIST_CONNECTED;
327 			else if (host($3, &r->addr, &r->mask)) {
328 				r->type = REDIST_ADDR;
329 				conf->redist_label_or_prefix = !$1;
330 			} else {
331 				yyerror("unknown redistribute type");
332 				free($3);
333 				free(r);
334 				YYERROR;
335 			}
336 
337 			if ($1)
338 				r->type |= REDIST_NO;
339 			r->metric = $4;
340 			if ($5)
341 				strlcpy(r->dependon, $5, sizeof(r->dependon));
342 			else
343 				r->dependon[0] = '\0';
344 			free($3);
345 			free($5);
346 			$$ = r;
347 		}
348 		| no REDISTRIBUTE RTLABEL STRING optlist dependon {
349 			struct redistribute	*r;
350 
351 			if ((r = calloc(1, sizeof(*r))) == NULL)
352 				fatal(NULL);
353 			r->type = REDIST_LABEL;
354 			r->label = rtlabel_name2id($4);
355 			if ($1)
356 				r->type |= REDIST_NO;
357 			else
358 				conf->redist_label_or_prefix = 1;
359 			r->metric = $5;
360 			if ($6)
361 				strlcpy(r->dependon, $6, sizeof(r->dependon));
362 			else
363 				r->dependon[0] = '\0';
364 			free($4);
365 			free($6);
366 			$$ = r;
367 		}
368 		;
369 
370 optlist		: /* empty */ 			{ $$ = DEFAULT_REDIST_METRIC; }
371 		| SET option 			{
372 			$$ = $2;
373 			if (($$ & LSA_METRIC_MASK) == 0)
374 				$$ |= DEFAULT_REDIST_METRIC;
375 		}
376 		| SET optnl '{' optnl optlist_l optnl '}' {
377 			$$ = $5;
378 			if (($$ & LSA_METRIC_MASK) == 0)
379 				$$ |= DEFAULT_REDIST_METRIC;
380 		}
381 		;
382 
383 optlist_l	: optlist_l comma option {
384 			if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
385 				yyerror("redistribute type already defined");
386 				YYERROR;
387 			}
388 			if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
389 				yyerror("redistribute metric already defined");
390 				YYERROR;
391 			}
392 			$$ = $1 | $3;
393 		}
394 		| option { $$ = $1; }
395 		;
396 
397 option		: METRIC NUMBER {
398 			if ($2 == 0 || $2 > MAX_METRIC) {
399 				yyerror("invalid redistribute metric");
400 				YYERROR;
401 			}
402 			$$ = $2;
403 		}
404 		| TYPE NUMBER {
405 			switch ($2) {
406 			case 1:
407 				$$ = 0;
408 				break;
409 			case 2:
410 				$$ = LSA_ASEXT_E_FLAG;
411 				break;
412 			default:
413 				yyerror("only external type 1 and 2 allowed");
414 				YYERROR;
415 			}
416 		}
417 		;
418 
419 dependon	: /* empty */		{ $$ = NULL; }
420 		| DEPEND ON STRING	{
421 			struct in_addr	 addr;
422 			struct kif	*kif;
423 
424 			if (strlen($3) >= IFNAMSIZ) {
425 				yyerror("interface name %s too long", $3);
426 				free($3);
427 				YYERROR;
428 			}
429 			bzero(&addr, sizeof(addr));
430 			if ((kif = kif_findname($3, addr, NULL)) == NULL) {
431 				yyerror("unknown interface %s", $3);
432 				free($3);
433 				YYERROR;
434 			}
435 			$$ = $3;
436 		}
437 		;
438 
439 authmd		: AUTHMD NUMBER STRING {
440 			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
441 				yyerror("auth-md key-id out of range "
442 				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
443 				free($3);
444 				YYERROR;
445 			}
446 			if (strlen($3) > MD5_DIGEST_LENGTH) {
447 				yyerror("auth-md key length out of range "
448 				    "(max length %d)",
449 				    MD5_DIGEST_LENGTH);
450 				free($3);
451 				YYERROR;
452 			}
453 			md_list_add(&defs->md_list, $2, $3);
454 			free($3);
455 		}
456 
457 authmdkeyid	: AUTHMDKEYID NUMBER {
458 			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
459 				yyerror("auth-md-keyid out of range "
460 				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
461 				YYERROR;
462 			}
463 			defs->auth_keyid = $2;
464 		}
465 
466 authtype	: AUTHTYPE STRING {
467 			enum auth_type	type;
468 
469 			if (!strcmp($2, "none"))
470 				type = AUTH_NONE;
471 			else if (!strcmp($2, "simple"))
472 				type = AUTH_SIMPLE;
473 			else if (!strcmp($2, "crypt"))
474 				type = AUTH_CRYPT;
475 			else {
476 				yyerror("unknown auth-type");
477 				free($2);
478 				YYERROR;
479 			}
480 			free($2);
481 			defs->auth_type = type;
482 		}
483 		;
484 
485 authkey		: AUTHKEY STRING {
486 			if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
487 				yyerror("auth-key too long (max length %d)",
488 				    MAX_SIMPLE_AUTH_LEN);
489 					free($2);
490 					YYERROR;
491 			}
492 			strncpy(defs->auth_key, $2,
493 			    sizeof(defs->auth_key));
494 			free($2);
495 		}
496 		;
497 
498 defaults	: METRIC NUMBER {
499 			if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
500 				yyerror("metric out of range (%d-%d)",
501 				    MIN_METRIC, MAX_METRIC);
502 				YYERROR;
503 			}
504 			defs->metric = $2;
505 		}
506 		| ROUTERPRIORITY NUMBER {
507 			if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
508 				yyerror("router-priority out of range (%d-%d)",
509 				    MIN_PRIORITY, MAX_PRIORITY);
510 				YYERROR;
511 			}
512 			defs->priority = $2;
513 		}
514 		| ROUTERDEADTIME deadtime {
515 			defs->dead_interval = $2;
516 		}
517 		| TRANSMITDELAY NUMBER {
518 			if ($2 < MIN_TRANSMIT_DELAY ||
519 			    $2 > MAX_TRANSMIT_DELAY) {
520 				yyerror("transmit-delay out of range (%d-%d)",
521 				    MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
522 				YYERROR;
523 			}
524 			defs->transmit_delay = $2;
525 		}
526 		| HELLOINTERVAL NUMBER {
527 			if ($2 < MIN_HELLO_INTERVAL ||
528 			    $2 > MAX_HELLO_INTERVAL) {
529 				yyerror("hello-interval out of range (%d-%d)",
530 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
531 				YYERROR;
532 			}
533 			defs->hello_interval = $2;
534 		}
535 		| FASTHELLOINTERVAL MSEC NUMBER {
536 			if ($3 < MIN_FAST_INTERVAL ||
537 			    $3 > MAX_FAST_INTERVAL) {
538 				yyerror("fast-hello-interval msec out of "
539 				    "range (%d-%d)", MIN_FAST_INTERVAL,
540 				    MAX_FAST_INTERVAL);
541 				YYERROR;
542 			}
543 			defs->fast_hello_interval = $3;
544 		}
545 		| RETRANSMITINTERVAL NUMBER {
546 			if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
547 				yyerror("retransmit-interval out of range "
548 				    "(%d-%d)", MIN_RXMT_INTERVAL,
549 				    MAX_RXMT_INTERVAL);
550 				YYERROR;
551 			}
552 			defs->rxmt_interval = $2;
553 		}
554 		| authtype
555 		| authkey
556 		| authmdkeyid
557 		| authmd
558 		;
559 
560 deadtime	: NUMBER {
561 			if ($1 < MIN_RTR_DEAD_TIME || $1 > MAX_RTR_DEAD_TIME) {
562 				yyerror("router-dead-time out of range (%d-%d)",
563 				    MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
564 				YYERROR;
565 			}
566 			$$ = $1;
567 		}
568 		| MINIMAL {
569 			$$ = FAST_RTR_DEAD_TIME;
570 		}
571 
572 optnl		: '\n' optnl
573 		|
574 		;
575 
576 nl		: '\n' optnl		/* one newline or more */
577 		;
578 
579 comma		: ','
580 		| /*empty*/
581 		;
582 
583 area		: AREA STRING {
584 			struct in_addr	id;
585 			if (inet_aton($2, &id) == 0) {
586 				yyerror("error parsing area");
587 				free($2);
588 				YYERROR;
589 			}
590 			free($2);
591 			area = conf_get_area(id);
592 
593 			memcpy(&areadefs, defs, sizeof(areadefs));
594 			md_list_copy(&areadefs.md_list, &defs->md_list);
595 			defs = &areadefs;
596 		} '{' optnl areaopts_l '}' {
597 			area = NULL;
598 			md_list_clr(&defs->md_list);
599 			defs = &globaldefs;
600 		}
601 		;
602 
603 demotecount	: NUMBER	{ $$ = $1; }
604 		| /*empty*/	{ $$ = 1; }
605 		;
606 
607 areaopts_l	: areaopts_l areaoptsl nl
608 		| areaoptsl optnl
609 		;
610 
611 areaoptsl	: interface
612 		| DEMOTE STRING	demotecount {
613 			if ($3 < 1 || $3 > 255) {
614 				yyerror("demote count out of range (1-255)");
615 				free($2);
616 				YYERROR;
617 			}
618 			area->demote_level = $3;
619 			if (strlcpy(area->demote_group, $2,
620 			    sizeof(area->demote_group)) >=
621 			    sizeof(area->demote_group)) {
622 				yyerror("demote group name \"%s\" too long",
623 				    $2);
624 				free($2);
625 				YYERROR;
626 			}
627 			free($2);
628 			if (carp_demote_init(area->demote_group,
629 			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
630 				yyerror("error initializing group \"%s\"",
631 				    area->demote_group);
632 				YYERROR;
633 			}
634 		}
635 		| defaults
636 		| STUB 			{ area->stub = 1; }
637 		| STUB redistribute {
638 			area->stub = 1;
639 			if ($2->type != REDIST_DEFAULT) {
640 				yyerror("bad redistribute option");
641 				YYERROR;
642 			}
643 			if (!SIMPLEQ_EMPTY(&area->redist_list)) {
644 				yyerror("area redistribute option only "
645 				    "allowed once");
646 				YYERROR;
647 			}
648 			SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry);
649 		}
650 		;
651 
652 interface	: INTERFACE STRING	{
653 			struct kif	*kif;
654 			struct kif_addr	*ka = NULL;
655 			char		*s;
656 			struct in_addr	 addr;
657 
658 			s = strchr($2, ':');
659 			if (s) {
660 				*s++ = '\0';
661 				if (inet_aton(s, &addr) == 0) {
662 					yyerror(
663 					    "error parsing interface address");
664 					free($2);
665 					YYERROR;
666 				}
667 			} else
668 				addr.s_addr = 0;
669 
670 			if ((kif = kif_findname($2, addr, &ka)) == NULL) {
671 				yyerror("unknown interface %s", $2);
672 				free($2);
673 				YYERROR;
674 			}
675 			if (ka == NULL) {
676 				if (s)
677 					yyerror("address %s not configured on "
678 					    "interface %s", s, $2);
679 				else
680 					yyerror("unnumbered interface %s", $2);
681 				free($2);
682 				YYERROR;
683 			}
684 			free($2);
685 			iface = conf_get_if(kif, ka);
686 			if (iface == NULL)
687 				YYERROR;
688 			iface->area = area;
689 			LIST_INSERT_HEAD(&area->iface_list, iface, entry);
690 
691 			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
692 			md_list_copy(&ifacedefs.md_list, &defs->md_list);
693 			defs = &ifacedefs;
694 		} interface_block {
695 			iface->dead_interval = defs->dead_interval;
696 			iface->fast_hello_interval = defs->fast_hello_interval;
697 			iface->transmit_delay = defs->transmit_delay;
698 			if (iface->dead_interval == FAST_RTR_DEAD_TIME)
699 				iface->hello_interval = 0;
700 			else
701 				iface->hello_interval = defs->hello_interval;
702 			iface->rxmt_interval = defs->rxmt_interval;
703 			iface->metric = defs->metric;
704 			iface->priority = defs->priority;
705 			iface->auth_type = defs->auth_type;
706 			iface->auth_keyid = defs->auth_keyid;
707 			memcpy(iface->auth_key, defs->auth_key,
708 			    sizeof(iface->auth_key));
709 			md_list_copy(&iface->auth_md_list, &defs->md_list);
710 			md_list_clr(&defs->md_list);
711 			iface = NULL;
712 			/* interface is always part of an area */
713 			defs = &areadefs;
714 		}
715 		;
716 
717 interface_block	: '{' optnl interfaceopts_l '}'
718 		| '{' optnl '}'
719 		|
720 		;
721 
722 interfaceopts_l	: interfaceopts_l interfaceoptsl nl
723 		| interfaceoptsl optnl
724 		;
725 
726 interfaceoptsl	: PASSIVE		{ iface->passive = 1; }
727 		| DEMOTE STRING		{
728 			if (strlcpy(iface->demote_group, $2,
729 			    sizeof(iface->demote_group)) >=
730 			    sizeof(iface->demote_group)) {
731 				yyerror("demote group name \"%s\" too long",
732 				    $2);
733 				free($2);
734 				YYERROR;
735 			}
736 			free($2);
737 			if (carp_demote_init(iface->demote_group,
738 			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
739 				yyerror("error initializing group \"%s\"",
740 				    iface->demote_group);
741 				YYERROR;
742 			}
743 		}
744 		| dependon {
745 			struct in_addr	 addr;
746 			struct kif	*kif;
747 
748 			if ($1) {
749 				strlcpy(iface->dependon, $1,
750 				       	sizeof(iface->dependon));
751 				bzero(&addr, sizeof(addr));
752 				kif = kif_findname($1, addr, NULL);
753 				iface->depend_ok = ifstate_is_up(kif);
754 			} else {
755 				iface->dependon[0] = '\0';
756 				iface->depend_ok = 1;
757 			}
758 
759 			free($1);
760 		}
761 		| defaults
762 		;
763 
764 %%
765 
766 struct keywords {
767 	const char	*k_name;
768 	int		 k_val;
769 };
770 
771 int
772 yyerror(const char *fmt, ...)
773 {
774 	va_list		 ap;
775 	char		*msg;
776 
777 	file->errors++;
778 	va_start(ap, fmt);
779 	if (vasprintf(&msg, fmt, ap) == -1)
780 		fatalx("yyerror vasprintf");
781 	va_end(ap);
782 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
783 	free(msg);
784 	return (0);
785 }
786 
787 int
788 kw_cmp(const void *k, const void *e)
789 {
790 	return (strcmp(k, ((const struct keywords *)e)->k_name));
791 }
792 
793 int
794 lookup(char *s)
795 {
796 	/* this has to be sorted always */
797 	static const struct keywords keywords[] = {
798 		{"area",		AREA},
799 		{"auth-key",		AUTHKEY},
800 		{"auth-md",		AUTHMD},
801 		{"auth-md-keyid",	AUTHMDKEYID},
802 		{"auth-type",		AUTHTYPE},
803 		{"demote",		DEMOTE},
804 		{"depend",		DEPEND},
805 		{"external-tag",	EXTTAG},
806 		{"fast-hello-interval",	FASTHELLOINTERVAL},
807 		{"fib-update",		FIBUPDATE},
808 		{"hello-interval",	HELLOINTERVAL},
809 		{"include",		INCLUDE},
810 		{"interface",		INTERFACE},
811 		{"metric",		METRIC},
812 		{"minimal",		MINIMAL},
813 		{"msec",		MSEC},
814 		{"no",			NO},
815 		{"on",			ON},
816 		{"passive",		PASSIVE},
817 		{"rdomain",		RDOMAIN},
818 		{"redistribute",	REDISTRIBUTE},
819 		{"retransmit-interval",	RETRANSMITINTERVAL},
820 		{"rfc1583compat",	RFC1583COMPAT},
821 		{"router",		ROUTER},
822 		{"router-dead-time",	ROUTERDEADTIME},
823 		{"router-id",		ROUTERID},
824 		{"router-priority",	ROUTERPRIORITY},
825 		{"rtlabel",		RTLABEL},
826 		{"set",			SET},
827 		{"spf-delay",		SPFDELAY},
828 		{"spf-holdtime",	SPFHOLDTIME},
829 		{"stub",		STUB},
830 		{"transmit-delay",	TRANSMITDELAY},
831 		{"type",		TYPE},
832 		{"yes",			YES}
833 	};
834 	const struct keywords	*p;
835 
836 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
837 	    sizeof(keywords[0]), kw_cmp);
838 
839 	if (p)
840 		return (p->k_val);
841 	else
842 		return (STRING);
843 }
844 
845 #define START_EXPAND	1
846 #define DONE_EXPAND	2
847 
848 static int	expanding;
849 
850 int
851 igetc(void)
852 {
853 	int	c;
854 
855 	while (1) {
856 		if (file->ungetpos > 0)
857 			c = file->ungetbuf[--file->ungetpos];
858 		else
859 			c = getc(file->stream);
860 
861 		if (c == START_EXPAND)
862 			expanding = 1;
863 		else if (c == DONE_EXPAND)
864 			expanding = 0;
865 		else
866 			break;
867 	}
868 	return (c);
869 }
870 
871 int
872 lgetc(int quotec)
873 {
874 	int		c, next;
875 
876 	if (quotec) {
877 		if ((c = igetc()) == EOF) {
878 			yyerror("reached end of file while parsing "
879 			    "quoted string");
880 			if (file == topfile || popfile() == EOF)
881 				return (EOF);
882 			return (quotec);
883 		}
884 		return (c);
885 	}
886 
887 	while ((c = igetc()) == '\\') {
888 		next = igetc();
889 		if (next != '\n') {
890 			c = next;
891 			break;
892 		}
893 		yylval.lineno = file->lineno;
894 		file->lineno++;
895 	}
896 
897 	if (c == EOF) {
898 		/*
899 		 * Fake EOL when hit EOF for the first time. This gets line
900 		 * count right if last line in included file is syntactically
901 		 * invalid and has no newline.
902 		 */
903 		if (file->eof_reached == 0) {
904 			file->eof_reached = 1;
905 			return ('\n');
906 		}
907 		while (c == EOF) {
908 			if (file == topfile || popfile() == EOF)
909 				return (EOF);
910 			c = igetc();
911 		}
912 	}
913 	return (c);
914 }
915 
916 void
917 lungetc(int c)
918 {
919 	if (c == EOF)
920 		return;
921 
922 	if (file->ungetpos >= file->ungetsize) {
923 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
924 		if (p == NULL)
925 			err(1, "%s", __func__);
926 		file->ungetbuf = p;
927 		file->ungetsize *= 2;
928 	}
929 	file->ungetbuf[file->ungetpos++] = c;
930 }
931 
932 int
933 findeol(void)
934 {
935 	int	c;
936 
937 	/* skip to either EOF or the first real EOL */
938 	while (1) {
939 		c = lgetc(0);
940 		if (c == '\n') {
941 			file->lineno++;
942 			break;
943 		}
944 		if (c == EOF)
945 			break;
946 	}
947 	return (ERROR);
948 }
949 
950 int
951 yylex(void)
952 {
953 	u_char	 buf[8096];
954 	u_char	*p, *val;
955 	int	 quotec, next, c;
956 	int	 token;
957 
958 top:
959 	p = buf;
960 	while ((c = lgetc(0)) == ' ' || c == '\t')
961 		; /* nothing */
962 
963 	yylval.lineno = file->lineno;
964 	if (c == '#')
965 		while ((c = lgetc(0)) != '\n' && c != EOF)
966 			; /* nothing */
967 	if (c == '$' && !expanding) {
968 		while (1) {
969 			if ((c = lgetc(0)) == EOF)
970 				return (0);
971 
972 			if (p + 1 >= buf + sizeof(buf) - 1) {
973 				yyerror("string too long");
974 				return (findeol());
975 			}
976 			if (isalnum(c) || c == '_') {
977 				*p++ = c;
978 				continue;
979 			}
980 			*p = '\0';
981 			lungetc(c);
982 			break;
983 		}
984 		val = symget(buf);
985 		if (val == NULL) {
986 			yyerror("macro '%s' not defined", buf);
987 			return (findeol());
988 		}
989 		p = val + strlen(val) - 1;
990 		lungetc(DONE_EXPAND);
991 		while (p >= val) {
992 			lungetc(*p);
993 			p--;
994 		}
995 		lungetc(START_EXPAND);
996 		goto top;
997 	}
998 
999 	switch (c) {
1000 	case '\'':
1001 	case '"':
1002 		quotec = c;
1003 		while (1) {
1004 			if ((c = lgetc(quotec)) == EOF)
1005 				return (0);
1006 			if (c == '\n') {
1007 				file->lineno++;
1008 				continue;
1009 			} else if (c == '\\') {
1010 				if ((next = lgetc(quotec)) == EOF)
1011 					return (0);
1012 				if (next == quotec || next == ' ' ||
1013 				    next == '\t')
1014 					c = next;
1015 				else if (next == '\n') {
1016 					file->lineno++;
1017 					continue;
1018 				} else
1019 					lungetc(next);
1020 			} else if (c == quotec) {
1021 				*p = '\0';
1022 				break;
1023 			} else if (c == '\0') {
1024 				yyerror("syntax error");
1025 				return (findeol());
1026 			}
1027 			if (p + 1 >= buf + sizeof(buf) - 1) {
1028 				yyerror("string too long");
1029 				return (findeol());
1030 			}
1031 			*p++ = c;
1032 		}
1033 		yylval.v.string = strdup(buf);
1034 		if (yylval.v.string == NULL)
1035 			err(1, "%s", __func__);
1036 		return (STRING);
1037 	}
1038 
1039 #define allowed_to_end_number(x) \
1040 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
1041 
1042 	if (c == '-' || isdigit(c)) {
1043 		do {
1044 			*p++ = c;
1045 			if ((unsigned)(p-buf) >= sizeof(buf)) {
1046 				yyerror("string too long");
1047 				return (findeol());
1048 			}
1049 		} while ((c = lgetc(0)) != EOF && isdigit(c));
1050 		lungetc(c);
1051 		if (p == buf + 1 && buf[0] == '-')
1052 			goto nodigits;
1053 		if (c == EOF || allowed_to_end_number(c)) {
1054 			const char *errstr = NULL;
1055 
1056 			*p = '\0';
1057 			yylval.v.number = strtonum(buf, LLONG_MIN,
1058 			    LLONG_MAX, &errstr);
1059 			if (errstr) {
1060 				yyerror("\"%s\" invalid number: %s",
1061 				    buf, errstr);
1062 				return (findeol());
1063 			}
1064 			return (NUMBER);
1065 		} else {
1066 nodigits:
1067 			while (p > buf + 1)
1068 				lungetc(*--p);
1069 			c = *--p;
1070 			if (c == '-')
1071 				return (c);
1072 		}
1073 	}
1074 
1075 #define allowed_in_string(x) \
1076 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1077 	x != '{' && x != '}' && \
1078 	x != '!' && x != '=' && x != '#' && \
1079 	x != ','))
1080 
1081 	if (isalnum(c) || c == ':' || c == '_') {
1082 		do {
1083 			*p++ = c;
1084 			if ((unsigned)(p-buf) >= sizeof(buf)) {
1085 				yyerror("string too long");
1086 				return (findeol());
1087 			}
1088 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1089 		lungetc(c);
1090 		*p = '\0';
1091 		if ((token = lookup(buf)) == STRING)
1092 			if ((yylval.v.string = strdup(buf)) == NULL)
1093 				err(1, "%s", __func__);
1094 		return (token);
1095 	}
1096 	if (c == '\n') {
1097 		yylval.lineno = file->lineno;
1098 		file->lineno++;
1099 	}
1100 	if (c == EOF)
1101 		return (0);
1102 	return (c);
1103 }
1104 
1105 int
1106 check_file_secrecy(int fd, const char *fname)
1107 {
1108 	struct stat	st;
1109 
1110 	if (fstat(fd, &st)) {
1111 		log_warn("cannot stat %s", fname);
1112 		return (-1);
1113 	}
1114 	if (st.st_uid != 0 && st.st_uid != getuid()) {
1115 		log_warnx("%s: owner not root or current user", fname);
1116 		return (-1);
1117 	}
1118 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1119 		log_warnx("%s: group writable or world read/writable", fname);
1120 		return (-1);
1121 	}
1122 	return (0);
1123 }
1124 
1125 struct file *
1126 pushfile(const char *name, int secret)
1127 {
1128 	struct file	*nfile;
1129 
1130 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1131 		log_warn("%s", __func__);
1132 		return (NULL);
1133 	}
1134 	if ((nfile->name = strdup(name)) == NULL) {
1135 		log_warn("%s", __func__);
1136 		free(nfile);
1137 		return (NULL);
1138 	}
1139 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1140 		log_warn("%s: %s", __func__, nfile->name);
1141 		free(nfile->name);
1142 		free(nfile);
1143 		return (NULL);
1144 	} else if (secret &&
1145 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1146 		fclose(nfile->stream);
1147 		free(nfile->name);
1148 		free(nfile);
1149 		return (NULL);
1150 	}
1151 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1152 	nfile->ungetsize = 16;
1153 	nfile->ungetbuf = malloc(nfile->ungetsize);
1154 	if (nfile->ungetbuf == NULL) {
1155 		log_warn("%s", __func__);
1156 		fclose(nfile->stream);
1157 		free(nfile->name);
1158 		free(nfile);
1159 		return (NULL);
1160 	}
1161 	TAILQ_INSERT_TAIL(&files, nfile, entry);
1162 	return (nfile);
1163 }
1164 
1165 int
1166 popfile(void)
1167 {
1168 	struct file	*prev;
1169 
1170 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1171 		prev->errors += file->errors;
1172 
1173 	TAILQ_REMOVE(&files, file, entry);
1174 	fclose(file->stream);
1175 	free(file->name);
1176 	free(file->ungetbuf);
1177 	free(file);
1178 	file = prev;
1179 	return (file ? 0 : EOF);
1180 }
1181 
1182 struct ospfd_conf *
1183 parse_config(char *filename, int opts)
1184 {
1185 	struct sym	*sym, *next;
1186 
1187 	if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
1188 		fatal("parse_config");
1189 	conf->opts = opts;
1190 	if (conf->opts & OSPFD_OPT_STUB_ROUTER)
1191 		conf->flags |= OSPFD_FLAG_STUB_ROUTER;
1192 
1193 	bzero(&globaldefs, sizeof(globaldefs));
1194 	defs = &globaldefs;
1195 	TAILQ_INIT(&defs->md_list);
1196 	defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
1197 	defs->fast_hello_interval = DEFAULT_FAST_INTERVAL;
1198 	defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
1199 	defs->hello_interval = DEFAULT_HELLO_INTERVAL;
1200 	defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
1201 	defs->metric = DEFAULT_METRIC;
1202 	defs->priority = DEFAULT_PRIORITY;
1203 
1204 	conf->spf_delay = DEFAULT_SPF_DELAY;
1205 	conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
1206 	conf->spf_state = SPF_IDLE;
1207 
1208 	if ((file = pushfile(filename,
1209 	    !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
1210 		free(conf);
1211 		return (NULL);
1212 	}
1213 	topfile = file;
1214 
1215 	LIST_INIT(&conf->area_list);
1216 	LIST_INIT(&conf->cand_list);
1217 	SIMPLEQ_INIT(&conf->redist_list);
1218 
1219 	yyparse();
1220 	errors = file->errors;
1221 	popfile();
1222 
1223 	/* Free macros and check which have not been used. */
1224 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1225 		if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
1226 			fprintf(stderr, "warning: macro '%s' not "
1227 			    "used\n", sym->nam);
1228 		if (!sym->persist) {
1229 			free(sym->nam);
1230 			free(sym->val);
1231 			TAILQ_REMOVE(&symhead, sym, entry);
1232 			free(sym);
1233 		}
1234 	}
1235 
1236 	/* free global config defaults */
1237 	md_list_clr(&globaldefs.md_list);
1238 
1239 	/* check that all interfaces belong to the configured rdomain */
1240 	errors += conf_check_rdomain(conf->rdomain);
1241 
1242 	if (errors) {
1243 		clear_config(conf);
1244 		return (NULL);
1245 	}
1246 
1247 	if (conf->rtr_id.s_addr == 0)
1248 		conf->rtr_id.s_addr = get_rtr_id();
1249 
1250 	return (conf);
1251 }
1252 
1253 int
1254 symset(const char *nam, const char *val, int persist)
1255 {
1256 	struct sym	*sym;
1257 
1258 	TAILQ_FOREACH(sym, &symhead, entry) {
1259 		if (strcmp(nam, sym->nam) == 0)
1260 			break;
1261 	}
1262 
1263 	if (sym != NULL) {
1264 		if (sym->persist == 1)
1265 			return (0);
1266 		else {
1267 			free(sym->nam);
1268 			free(sym->val);
1269 			TAILQ_REMOVE(&symhead, sym, entry);
1270 			free(sym);
1271 		}
1272 	}
1273 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1274 		return (-1);
1275 
1276 	sym->nam = strdup(nam);
1277 	if (sym->nam == NULL) {
1278 		free(sym);
1279 		return (-1);
1280 	}
1281 	sym->val = strdup(val);
1282 	if (sym->val == NULL) {
1283 		free(sym->nam);
1284 		free(sym);
1285 		return (-1);
1286 	}
1287 	sym->used = 0;
1288 	sym->persist = persist;
1289 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1290 	return (0);
1291 }
1292 
1293 int
1294 cmdline_symset(char *s)
1295 {
1296 	char	*sym, *val;
1297 	int	ret;
1298 
1299 	if ((val = strrchr(s, '=')) == NULL)
1300 		return (-1);
1301 	sym = strndup(s, val - s);
1302 	if (sym == NULL)
1303 		errx(1, "%s: strndup", __func__);
1304 	ret = symset(sym, val + 1, 1);
1305 	free(sym);
1306 
1307 	return (ret);
1308 }
1309 
1310 char *
1311 symget(const char *nam)
1312 {
1313 	struct sym	*sym;
1314 
1315 	TAILQ_FOREACH(sym, &symhead, entry) {
1316 		if (strcmp(nam, sym->nam) == 0) {
1317 			sym->used = 1;
1318 			return (sym->val);
1319 		}
1320 	}
1321 	return (NULL);
1322 }
1323 
1324 struct area *
1325 conf_get_area(struct in_addr id)
1326 {
1327 	struct area	*a;
1328 
1329 	a = area_find(conf, id);
1330 	if (a)
1331 		return (a);
1332 	a = area_new();
1333 	LIST_INSERT_HEAD(&conf->area_list, a, entry);
1334 
1335 	a->id.s_addr = id.s_addr;
1336 
1337 	return (a);
1338 }
1339 
1340 struct iface *
1341 conf_get_if(struct kif *kif, struct kif_addr *ka)
1342 {
1343 	struct area	*a;
1344 	struct iface	*i;
1345 
1346 	LIST_FOREACH(a, &conf->area_list, entry)
1347 		LIST_FOREACH(i, &a->iface_list, entry)
1348 			if (i->ifindex == kif->ifindex &&
1349 			    i->addr.s_addr == ka->addr.s_addr) {
1350 				yyerror("interface %s already configured",
1351 				    kif->ifname);
1352 				return (NULL);
1353 			}
1354 
1355 	i = if_new(kif, ka);
1356 	i->auth_keyid = 1;
1357 
1358 	return (i);
1359 }
1360 
1361 int
1362 conf_check_rdomain(unsigned int rdomain)
1363 {
1364 	struct area	*a;
1365 	struct iface	*i;
1366 	int		 errs = 0;
1367 
1368 	LIST_FOREACH(a, &conf->area_list, entry)
1369 		LIST_FOREACH(i, &a->iface_list, entry)
1370 			if (i->rdomain != rdomain) {
1371 				logit(LOG_CRIT,
1372 				    "interface %s not in rdomain %u",
1373 				    i->name, rdomain);
1374 				errs++;
1375 			}
1376 
1377 	return (errs);
1378 }
1379 
1380 void
1381 conf_clear_redist_list(struct redist_list *rl)
1382 {
1383 	struct redistribute *r;
1384 	while ((r = SIMPLEQ_FIRST(rl)) != NULL) {
1385 		SIMPLEQ_REMOVE_HEAD(rl, entry);
1386 		free(r);
1387 	}
1388 }
1389 
1390 void
1391 clear_config(struct ospfd_conf *xconf)
1392 {
1393 	struct area	*a;
1394 
1395 	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
1396 		LIST_REMOVE(a, entry);
1397 		area_del(a);
1398 	}
1399 
1400 	conf_clear_redist_list(&xconf->redist_list);
1401 
1402 	free(xconf);
1403 }
1404 
1405 u_int32_t
1406 get_rtr_id(void)
1407 {
1408 	struct ifaddrs		*ifap, *ifa;
1409 	u_int32_t		 ip = 0, cur, localnet;
1410 
1411 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1412 
1413 	if (getifaddrs(&ifap) == -1)
1414 		fatal("getifaddrs");
1415 
1416 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1417 		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1418 			continue;
1419 		if (ifa->ifa_addr->sa_family != AF_INET)
1420 			continue;
1421 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1422 		if ((cur & localnet) == localnet)	/* skip 127/8 */
1423 			continue;
1424 		if (ntohl(cur) < ntohl(ip) || ip == 0)
1425 			ip = cur;
1426 	}
1427 	freeifaddrs(ifap);
1428 
1429 	if (ip == 0)
1430 		fatal("router-id is 0.0.0.0");
1431 
1432 	return (ip);
1433 }
1434 
1435 int
1436 host(const char *s, struct in_addr *addr, struct in_addr *mask)
1437 {
1438 	struct in_addr		 ina;
1439 	int			 bits = 32;
1440 
1441 	bzero(&ina, sizeof(struct in_addr));
1442 	if (strrchr(s, '/') != NULL) {
1443 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1444 			return (0);
1445 	} else {
1446 		if (inet_pton(AF_INET, s, &ina) != 1)
1447 			return (0);
1448 	}
1449 
1450 	addr->s_addr = ina.s_addr;
1451 	mask->s_addr = prefixlen2mask(bits);
1452 
1453 	return (1);
1454 }
1455