GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospfd/parse.y Lines: 133 340 39.1 %
Date: 2017-11-07 Branches: 80 251 31.9 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.y,v 1.83 2017/01/05 13:53:09 krw 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
	int			 lineno;
52
	int			 errors;
53
} *file, *topfile;
54
struct file	*pushfile(const char *, int);
55
int		 popfile(void);
56
int		 check_file_secrecy(int, const char *);
57
int		 yyparse(void);
58
int		 yylex(void);
59
int		 yyerror(const char *, ...)
60
    __attribute__((__format__ (printf, 1, 2)))
61
    __attribute__((__nonnull__ (1)));
62
int		 kw_cmp(const void *, const void *);
63
int		 lookup(char *);
64
int		 lgetc(int);
65
int		 lungetc(int);
66
int		 findeol(void);
67
68
TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
69
struct sym {
70
	TAILQ_ENTRY(sym)	 entry;
71
	int			 used;
72
	int			 persist;
73
	char			*nam;
74
	char			*val;
75
};
76
int		 symset(const char *, const char *, int);
77
char		*symget(const char *);
78
79
void		 clear_config(struct ospfd_conf *xconf);
80
u_int32_t	 get_rtr_id(void);
81
int		 host(const char *, struct in_addr *, struct in_addr *);
82
83
static struct ospfd_conf	*conf;
84
static int			 errors = 0;
85
86
struct area	*area = NULL;
87
struct iface	*iface = NULL;
88
89
struct config_defaults {
90
	char		auth_key[MAX_SIMPLE_AUTH_LEN];
91
	struct auth_md_head	 md_list;
92
	u_int32_t	dead_interval;
93
	u_int32_t	fast_hello_interval;
94
	u_int16_t	transmit_delay;
95
	u_int16_t	hello_interval;
96
	u_int16_t	rxmt_interval;
97
	u_int16_t	metric;
98
	enum auth_type	auth_type;
99
	u_int8_t	auth_keyid;
100
	u_int8_t	priority;
101
};
102
103
struct config_defaults	 globaldefs;
104
struct config_defaults	 areadefs;
105
struct config_defaults	 ifacedefs;
106
struct config_defaults	*defs;
107
108
struct area	*conf_get_area(struct in_addr);
109
struct iface	*conf_get_if(struct kif *, struct kif_addr *);
110
int		 conf_check_rdomain(unsigned int);
111
112
typedef struct {
113
	union {
114
		int64_t		 number;
115
		char		*string;
116
		struct redistribute *redist;
117
	} v;
118
	int lineno;
119
} YYSTYPE;
120
121
%}
122
123
%token	AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL RDOMAIN
124
%token	RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
125
%token	AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
126
%token	METRIC PASSIVE
127
%token	HELLOINTERVAL FASTHELLOINTERVAL TRANSMITDELAY
128
%token	RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
129
%token	SET TYPE
130
%token	YES NO
131
%token	MSEC MINIMAL
132
%token	DEMOTE
133
%token	INCLUDE
134
%token	ERROR
135
%token	<v.string>	STRING
136
%token	<v.number>	NUMBER
137
%type	<v.number>	yesno no optlist optlist_l option demotecount msec
138
%type	<v.number>	deadtime
139
%type	<v.string>	string
140
%type	<v.redist>	redistribute
141
142
%%
143
144
grammar		: /* empty */
145
		| grammar include '\n'
146
		| grammar '\n'
147
		| grammar conf_main '\n'
148
		| grammar varset '\n'
149
		| grammar area '\n'
150
		| grammar error '\n'		{ file->errors++; }
151
		;
152
153
include		: INCLUDE STRING		{
154
			struct file	*nfile;
155
156
			if ((nfile = pushfile($2, 1)) == NULL) {
157
				yyerror("failed to include file %s", $2);
158
				free($2);
159
				YYERROR;
160
			}
161
			free($2);
162
163
			file = nfile;
164
			lungetc('\n');
165
		}
166
		;
167
168
string		: string STRING	{
169
			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
170
				free($1);
171
				free($2);
172
				yyerror("string: asprintf");
173
				YYERROR;
174
			}
175
			free($1);
176
			free($2);
177
		}
178
		| STRING
179
		;
180
181
yesno		: YES	{ $$ = 1; }
182
		| NO	{ $$ = 0; }
183
		;
184
185
no		: /* empty */	{ $$ = 0; }
186
		| NO		{ $$ = 1; }
187
		;
188
189
msec		: MSEC NUMBER {
190
			$$ = $2;
191
		}
192
		| NUMBER {
193
			$$ = $1 * 1000;
194
		}
195
		;
196
197
varset		: STRING '=' string		{
198
			char *s = $1;
199
			if (conf->opts & OSPFD_OPT_VERBOSE)
200
				printf("%s = \"%s\"\n", $1, $3);
201
			while (*s++) {
202
				if (isspace((unsigned char)*s)) {
203
					yyerror("macro name cannot contain "
204
					    "whitespace");
205
					YYERROR;
206
				}
207
			}
208
			if (symset($1, $3, 0) == -1)
209
				fatal("cannot store variable");
210
			free($1);
211
			free($3);
212
		}
213
		;
214
215
conf_main	: ROUTERID STRING {
216
			if (!inet_aton($2, &conf->rtr_id)) {
217
				yyerror("error parsing router-id");
218
				free($2);
219
				YYERROR;
220
			}
221
			free($2);
222
		}
223
		| FIBUPDATE yesno {
224
			if ($2 == 0)
225
				conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
226
			else
227
				conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
228
		}
229
		| redistribute {
230
			SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
231
			conf->redistribute = 1;
232
		}
233
		| RTLABEL STRING EXTTAG NUMBER {
234
			if ($4 < 0 || $4 > UINT_MAX) {
235
				yyerror("invalid external route tag");
236
				free($2);
237
				YYERROR;
238
			}
239
			rtlabel_tag(rtlabel_name2id($2), $4);
240
			free($2);
241
		}
242
		| RDOMAIN NUMBER {
243
			if ($2 < 0 || $2 > RT_TABLEID_MAX) {
244
				yyerror("invalid rdomain");
245
				YYERROR;
246
			}
247
			conf->rdomain = $2;
248
		}
249
		| RFC1583COMPAT yesno {
250
			conf->rfc1583compat = $2;
251
		}
252
		| SPFDELAY msec {
253
			if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
254
				yyerror("spf-delay out of range "
255
				    "(%d-%d)", MIN_SPF_DELAY,
256
				    MAX_SPF_DELAY);
257
				YYERROR;
258
			}
259
			conf->spf_delay = $2;
260
		}
261
		| SPFHOLDTIME msec {
262
			if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
263
				yyerror("spf-holdtime out of range "
264
				    "(%d-%d)", MIN_SPF_HOLDTIME,
265
				    MAX_SPF_HOLDTIME);
266
				YYERROR;
267
			}
268
			conf->spf_hold_time = $2;
269
		}
270
		| STUB ROUTER yesno {
271
			if ($3)
272
				conf->flags |= OSPFD_FLAG_STUB_ROUTER;
273
			else
274
				/* allow to force non stub mode */
275
				conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
276
		}
277
		| defaults
278
		;
279
280
281
redistribute	: no REDISTRIBUTE NUMBER '/' NUMBER optlist {
282
			struct redistribute	*r;
283
284
			if ((r = calloc(1, sizeof(*r))) == NULL)
285
				fatal(NULL);
286
			r->type = REDIST_ADDR;
287
			if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) {
288
				yyerror("bad network: %llu/%llu", $3, $5);
289
				free(r);
290
				YYERROR;
291
			}
292
			r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT);
293
			r->mask.s_addr = prefixlen2mask($5);
294
295
			if ($1)
296
				r->type |= REDIST_NO;
297
			r->metric = $6;
298
			$$ = r;
299
		}
300
		| no REDISTRIBUTE STRING optlist {
301
			struct redistribute	*r;
302
303
			if ((r = calloc(1, sizeof(*r))) == NULL)
304
				fatal(NULL);
305
			if (!strcmp($3, "default"))
306
				r->type = REDIST_DEFAULT;
307
			else if (!strcmp($3, "static"))
308
				r->type = REDIST_STATIC;
309
			else if (!strcmp($3, "connected"))
310
				r->type = REDIST_CONNECTED;
311
			else if (host($3, &r->addr, &r->mask))
312
				r->type = REDIST_ADDR;
313
			else {
314
				yyerror("unknown redistribute type");
315
				free($3);
316
				free(r);
317
				YYERROR;
318
			}
319
320
			if ($1)
321
				r->type |= REDIST_NO;
322
			r->metric = $4;
323
			free($3);
324
			$$ = r;
325
		}
326
		| no REDISTRIBUTE RTLABEL STRING optlist {
327
			struct redistribute	*r;
328
329
			if ((r = calloc(1, sizeof(*r))) == NULL)
330
				fatal(NULL);
331
			r->type = REDIST_LABEL;
332
			r->label = rtlabel_name2id($4);
333
			if ($1)
334
				r->type |= REDIST_NO;
335
			r->metric = $5;
336
			free($4);
337
338
			$$ = r;
339
		}
340
		;
341
342
optlist		: /* empty */ 			{ $$ = DEFAULT_REDIST_METRIC; }
343
		| SET option			{
344
			$$ = $2;
345
			if (($$ & LSA_METRIC_MASK) == 0)
346
				$$ |= DEFAULT_REDIST_METRIC;
347
		}
348
		| SET optnl '{' optnl optlist_l optnl '}'	{
349
			$$ = $5;
350
			if (($$ & LSA_METRIC_MASK) == 0)
351
				$$ |= DEFAULT_REDIST_METRIC;
352
		}
353
		;
354
355
optlist_l	: optlist_l comma option {
356
			if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
357
				yyerror("redistribute type already defined");
358
				YYERROR;
359
			}
360
			if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
361
				yyerror("redistribute metric already defined");
362
				YYERROR;
363
			}
364
			$$ = $1 | $3;
365
		}
366
		| option { $$ = $1; }
367
		;
368
369
option		: METRIC NUMBER {
370
			if ($2 == 0 || $2 > MAX_METRIC) {
371
				yyerror("invalid redistribute metric");
372
				YYERROR;
373
			}
374
			$$ = $2;
375
		}
376
		| TYPE NUMBER {
377
			switch ($2) {
378
			case 1:
379
				$$ = 0;
380
				break;
381
			case 2:
382
				$$ = LSA_ASEXT_E_FLAG;
383
				break;
384
			default:
385
				yyerror("only external type 1 and 2 allowed");
386
				YYERROR;
387
			}
388
		}
389
		;
390
391
authmd		: AUTHMD NUMBER STRING {
392
			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
393
				yyerror("auth-md key-id out of range "
394
				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
395
				free($3);
396
				YYERROR;
397
			}
398
			if (strlen($3) > MD5_DIGEST_LENGTH) {
399
				yyerror("auth-md key length out of range "
400
				    "(max length %d)",
401
				    MD5_DIGEST_LENGTH);
402
				free($3);
403
				YYERROR;
404
			}
405
			md_list_add(&defs->md_list, $2, $3);
406
			free($3);
407
		}
408
409
authmdkeyid	: AUTHMDKEYID NUMBER {
410
			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
411
				yyerror("auth-md-keyid out of range "
412
				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
413
				YYERROR;
414
			}
415
			defs->auth_keyid = $2;
416
		}
417
418
authtype	: AUTHTYPE STRING {
419
			enum auth_type	type;
420
421
			if (!strcmp($2, "none"))
422
				type = AUTH_NONE;
423
			else if (!strcmp($2, "simple"))
424
				type = AUTH_SIMPLE;
425
			else if (!strcmp($2, "crypt"))
426
				type = AUTH_CRYPT;
427
			else {
428
				yyerror("unknown auth-type");
429
				free($2);
430
				YYERROR;
431
			}
432
			free($2);
433
			defs->auth_type = type;
434
		}
435
		;
436
437
authkey		: AUTHKEY STRING {
438
			if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
439
				yyerror("auth-key too long (max length %d)",
440
				    MAX_SIMPLE_AUTH_LEN);
441
					free($2);
442
					YYERROR;
443
			}
444
			strncpy(defs->auth_key, $2,
445
			    sizeof(defs->auth_key));
446
			free($2);
447
		}
448
		;
449
450
defaults	: METRIC NUMBER {
451
			if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
452
				yyerror("metric out of range (%d-%d)",
453
				    MIN_METRIC, MAX_METRIC);
454
				YYERROR;
455
			}
456
			defs->metric = $2;
457
		}
458
		| ROUTERPRIORITY NUMBER {
459
			if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
460
				yyerror("router-priority out of range (%d-%d)",
461
				    MIN_PRIORITY, MAX_PRIORITY);
462
				YYERROR;
463
			}
464
			defs->priority = $2;
465
		}
466
		| ROUTERDEADTIME deadtime {
467
			defs->dead_interval = $2;
468
		}
469
		| TRANSMITDELAY NUMBER {
470
			if ($2 < MIN_TRANSMIT_DELAY ||
471
			    $2 > MAX_TRANSMIT_DELAY) {
472
				yyerror("transmit-delay out of range (%d-%d)",
473
				    MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
474
				YYERROR;
475
			}
476
			defs->transmit_delay = $2;
477
		}
478
		| HELLOINTERVAL NUMBER {
479
			if ($2 < MIN_HELLO_INTERVAL ||
480
			    $2 > MAX_HELLO_INTERVAL) {
481
				yyerror("hello-interval out of range (%d-%d)",
482
				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
483
				YYERROR;
484
			}
485
			defs->hello_interval = $2;
486
		}
487
		| FASTHELLOINTERVAL MSEC NUMBER {
488
			if ($3 < MIN_FAST_INTERVAL ||
489
			    $3 > MAX_FAST_INTERVAL) {
490
				yyerror("fast-hello-interval msec out of "
491
				    "range (%d-%d)", MIN_FAST_INTERVAL,
492
				    MAX_FAST_INTERVAL);
493
				YYERROR;
494
			}
495
			defs->fast_hello_interval = $3;
496
		}
497
		| RETRANSMITINTERVAL NUMBER {
498
			if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
499
				yyerror("retransmit-interval out of range "
500
				    "(%d-%d)", MIN_RXMT_INTERVAL,
501
				    MAX_RXMT_INTERVAL);
502
				YYERROR;
503
			}
504
			defs->rxmt_interval = $2;
505
		}
506
		| authtype
507
		| authkey
508
		| authmdkeyid
509
		| authmd
510
		;
511
512
deadtime	: NUMBER {
513
			if ($1 < MIN_RTR_DEAD_TIME || $1 > MAX_RTR_DEAD_TIME) {
514
				yyerror("router-dead-time out of range (%d-%d)",
515
				    MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
516
				YYERROR;
517
			}
518
			$$ = $1;
519
		}
520
		| MINIMAL {
521
			$$ = FAST_RTR_DEAD_TIME;
522
		}
523
524
optnl		: '\n' optnl
525
		|
526
		;
527
528
nl		: '\n' optnl		/* one newline or more */
529
		;
530
531
comma		: ','
532
		| /*empty*/
533
		;
534
535
area		: AREA STRING {
536
			struct in_addr	id;
537
			if (inet_aton($2, &id) == 0) {
538
				yyerror("error parsing area");
539
				free($2);
540
				YYERROR;
541
			}
542
			free($2);
543
			area = conf_get_area(id);
544
545
			memcpy(&areadefs, defs, sizeof(areadefs));
546
			md_list_copy(&areadefs.md_list, &defs->md_list);
547
			defs = &areadefs;
548
		} '{' optnl areaopts_l '}' {
549
			area = NULL;
550
			md_list_clr(&defs->md_list);
551
			defs = &globaldefs;
552
		}
553
		;
554
555
demotecount	: NUMBER	{ $$ = $1; }
556
		| /*empty*/	{ $$ = 1; }
557
		;
558
559
areaopts_l	: areaopts_l areaoptsl nl
560
		| areaoptsl optnl
561
		;
562
563
areaoptsl	: interface
564
		| DEMOTE STRING	demotecount {
565
			if ($3 < 1 || $3 > 255) {
566
				yyerror("demote count out of range (1-255)");
567
				free($2);
568
				YYERROR;
569
			}
570
			area->demote_level = $3;
571
			if (strlcpy(area->demote_group, $2,
572
			    sizeof(area->demote_group)) >=
573
			    sizeof(area->demote_group)) {
574
				yyerror("demote group name \"%s\" too long",
575
				    $2);
576
				free($2);
577
				YYERROR;
578
			}
579
			free($2);
580
			if (carp_demote_init(area->demote_group,
581
			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
582
				yyerror("error initializing group \"%s\"",
583
				    area->demote_group);
584
				YYERROR;
585
			}
586
		}
587
		| defaults
588
		| STUB 			{ area->stub = 1; }
589
		| STUB redistribute {
590
			area->stub = 1;
591
			if ($2->type != REDIST_DEFAULT) {
592
				yyerror("bad redistribute option");
593
				YYERROR;
594
			}
595
			if (!SIMPLEQ_EMPTY(&area->redist_list)) {
596
				yyerror("area redistribute option only "
597
				    "allowed once");
598
				YYERROR;
599
			}
600
			SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry);
601
		}
602
		;
603
604
interface	: INTERFACE STRING	{
605
			struct kif	*kif;
606
			struct kif_addr	*ka = NULL;
607
			char		*s;
608
			struct in_addr	 addr;
609
610
			s = strchr($2, ':');
611
			if (s) {
612
				*s++ = '\0';
613
				if (inet_aton(s, &addr) == 0) {
614
					yyerror(
615
					    "error parsing interface address");
616
					free($2);
617
					YYERROR;
618
				}
619
			} else
620
				addr.s_addr = 0;
621
622
			if ((kif = kif_findname($2, addr, &ka)) == NULL) {
623
				yyerror("unknown interface %s", $2);
624
				free($2);
625
				YYERROR;
626
			}
627
			if (ka == NULL) {
628
				if (s)
629
					yyerror("address %s not configured on "
630
					    "interface %s", s, $2);
631
				else
632
					yyerror("unnumbered interface %s", $2);
633
				free($2);
634
				YYERROR;
635
			}
636
			free($2);
637
			iface = conf_get_if(kif, ka);
638
			if (iface == NULL)
639
				YYERROR;
640
			iface->area = area;
641
			LIST_INSERT_HEAD(&area->iface_list, iface, entry);
642
643
			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
644
			md_list_copy(&ifacedefs.md_list, &defs->md_list);
645
			defs = &ifacedefs;
646
		} interface_block {
647
			iface->dead_interval = defs->dead_interval;
648
			iface->fast_hello_interval = defs->fast_hello_interval;
649
			iface->transmit_delay = defs->transmit_delay;
650
			if (iface->dead_interval == FAST_RTR_DEAD_TIME)
651
				iface->hello_interval = 0;
652
			else
653
				iface->hello_interval = defs->hello_interval;
654
			iface->rxmt_interval = defs->rxmt_interval;
655
			iface->metric = defs->metric;
656
			iface->priority = defs->priority;
657
			iface->auth_type = defs->auth_type;
658
			iface->auth_keyid = defs->auth_keyid;
659
			memcpy(iface->auth_key, defs->auth_key,
660
			    sizeof(iface->auth_key));
661
			md_list_copy(&iface->auth_md_list, &defs->md_list);
662
			md_list_clr(&defs->md_list);
663
			iface = NULL;
664
			/* interface is always part of an area */
665
			defs = &areadefs;
666
		}
667
		;
668
669
interface_block	: '{' optnl interfaceopts_l '}'
670
		| '{' optnl '}'
671
		|
672
		;
673
674
interfaceopts_l	: interfaceopts_l interfaceoptsl nl
675
		| interfaceoptsl optnl
676
		;
677
678
interfaceoptsl	: PASSIVE		{ iface->passive = 1; }
679
		| DEMOTE STRING		{
680
			if (strlcpy(iface->demote_group, $2,
681
			    sizeof(iface->demote_group)) >=
682
			    sizeof(iface->demote_group)) {
683
				yyerror("demote group name \"%s\" too long",
684
				    $2);
685
				free($2);
686
				YYERROR;
687
			}
688
			free($2);
689
			if (carp_demote_init(iface->demote_group,
690
			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
691
				yyerror("error initializing group \"%s\"",
692
				    iface->demote_group);
693
				YYERROR;
694
			}
695
		}
696
		| defaults
697
		;
698
699
%%
700
701
struct keywords {
702
	const char	*k_name;
703
	int		 k_val;
704
};
705
706
int
707
yyerror(const char *fmt, ...)
708
{
709
	va_list		 ap;
710
	char		*msg;
711
712
	file->errors++;
713
	va_start(ap, fmt);
714
	if (vasprintf(&msg, fmt, ap) == -1)
715
		fatalx("yyerror vasprintf");
716
	va_end(ap);
717
	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
718
	free(msg);
719
	return (0);
720
}
721
722
int
723
kw_cmp(const void *k, const void *e)
724
{
725
1600
	return (strcmp(k, ((const struct keywords *)e)->k_name));
726
}
727
728
int
729
lookup(char *s)
730
{
731
	/* this has to be sorted always */
732
	static const struct keywords keywords[] = {
733
		{"area",		AREA},
734
		{"auth-key",		AUTHKEY},
735
		{"auth-md",		AUTHMD},
736
		{"auth-md-keyid",	AUTHMDKEYID},
737
		{"auth-type",		AUTHTYPE},
738
		{"demote",		DEMOTE},
739
		{"external-tag",	EXTTAG},
740
		{"fast-hello-interval",	FASTHELLOINTERVAL},
741
		{"fib-update",		FIBUPDATE},
742
		{"hello-interval",	HELLOINTERVAL},
743
		{"include",		INCLUDE},
744
		{"interface",		INTERFACE},
745
		{"metric",		METRIC},
746
		{"minimal",		MINIMAL},
747
		{"msec",		MSEC},
748
		{"no",			NO},
749
		{"passive",		PASSIVE},
750
		{"rdomain",		RDOMAIN},
751
		{"redistribute",	REDISTRIBUTE},
752
		{"retransmit-interval",	RETRANSMITINTERVAL},
753
		{"rfc1583compat",	RFC1583COMPAT},
754
		{"router",		ROUTER},
755
		{"router-dead-time",	ROUTERDEADTIME},
756
		{"router-id",		ROUTERID},
757
		{"router-priority",	ROUTERPRIORITY},
758
		{"rtlabel",		RTLABEL},
759
		{"set",			SET},
760
		{"spf-delay",		SPFDELAY},
761
		{"spf-holdtime",	SPFHOLDTIME},
762
		{"stub",		STUB},
763
		{"transmit-delay",	TRANSMITDELAY},
764
		{"type",		TYPE},
765
		{"yes",			YES}
766
	};
767
	const struct keywords	*p;
768
769
320
	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
770
	    sizeof(keywords[0]), kw_cmp);
771
772
160
	if (p)
773
112
		return (p->k_val);
774
	else
775
48
		return (STRING);
776
160
}
777
778
#define MAXPUSHBACK	128
779
780
u_char	*parsebuf;
781
int	 parseindex;
782
u_char	 pushback_buffer[MAXPUSHBACK];
783
int	 pushback_index = 0;
784
785
int
786
lgetc(int quotec)
787
{
788
	int		c, next;
789
790
5328
	if (parsebuf) {
791
		/* Read character from the parsebuffer instead of input. */
792
		if (parseindex >= 0) {
793
			c = parsebuf[parseindex++];
794
			if (c != '\0')
795
				return (c);
796
			parsebuf = NULL;
797
		} else
798
			parseindex++;
799
	}
800
801
2664
	if (pushback_index)
802
288
		return (pushback_buffer[--pushback_index]);
803
804
2376
	if (quotec) {
805
		if ((c = getc(file->stream)) == EOF) {
806
			yyerror("reached end of file while parsing "
807
			    "quoted string");
808
			if (file == topfile || popfile() == EOF)
809
				return (EOF);
810
			return (quotec);
811
		}
812
		return (c);
813
	}
814
815

9504
	while ((c = getc(file->stream)) == '\\') {
816
		next = getc(file->stream);
817
		if (next != '\n') {
818
			c = next;
819
			break;
820
		}
821
		yylval.lineno = file->lineno;
822
		file->lineno++;
823
	}
824
825
2376
	while (c == EOF) {
826

16
		if (file == topfile || popfile() == EOF)
827
16
			return (EOF);
828
		c = getc(file->stream);
829
	}
830
2360
	return (c);
831
2664
}
832
833
int
834
lungetc(int c)
835
{
836
576
	if (c == EOF)
837
		return (EOF);
838
288
	if (parsebuf) {
839
		parseindex--;
840
		if (parseindex >= 0)
841
			return (c);
842
	}
843
288
	if (pushback_index < MAXPUSHBACK-1)
844
288
		return (pushback_buffer[pushback_index++] = c);
845
	else
846
		return (EOF);
847
288
}
848
849
int
850
findeol(void)
851
{
852
	int	c;
853
854
	parsebuf = NULL;
855
856
	/* skip to either EOF or the first real EOL */
857
	while (1) {
858
		if (pushback_index)
859
			c = pushback_buffer[--pushback_index];
860
		else
861
			c = lgetc(0);
862
		if (c == '\n') {
863
			file->lineno++;
864
			break;
865
		}
866
		if (c == EOF)
867
			break;
868
	}
869
	return (ERROR);
870
}
871
872
int
873
yylex(void)
874
{
875
896
	u_char	 buf[8096];
876
	u_char	*p, *val;
877
	int	 quotec, next, c;
878
448
	int	 token;
879
880
top:
881
448
	p = buf;
882
1200
	while ((c = lgetc(0)) == ' ' || c == '\t')
883
		; /* nothing */
884
885
448
	yylval.lineno = file->lineno;
886
448
	if (c == '#')
887
		while ((c = lgetc(0)) != '\n' && c != EOF)
888
			; /* nothing */
889
448
	if (c == '$' && parsebuf == NULL) {
890
		while (1) {
891
			if ((c = lgetc(0)) == EOF)
892
				return (0);
893
894
			if (p + 1 >= buf + sizeof(buf) - 1) {
895
				yyerror("string too long");
896
				return (findeol());
897
			}
898
			if (isalnum(c) || c == '_') {
899
				*p++ = c;
900
				continue;
901
			}
902
			*p = '\0';
903
			lungetc(c);
904
			break;
905
		}
906
		val = symget(buf);
907
		if (val == NULL) {
908
			yyerror("macro '%s' not defined", buf);
909
			return (findeol());
910
		}
911
		parsebuf = val;
912
		parseindex = 0;
913
		goto top;
914
	}
915
916
448
	switch (c) {
917
	case '\'':
918
	case '"':
919
		quotec = c;
920
		while (1) {
921
			if ((c = lgetc(quotec)) == EOF)
922
				return (0);
923
			if (c == '\n') {
924
				file->lineno++;
925
				continue;
926
			} else if (c == '\\') {
927
				if ((next = lgetc(quotec)) == EOF)
928
					return (0);
929
				if (next == quotec || c == ' ' || c == '\t')
930
					c = next;
931
				else if (next == '\n') {
932
					file->lineno++;
933
					continue;
934
				} else
935
					lungetc(next);
936
			} else if (c == quotec) {
937
				*p = '\0';
938
				break;
939
			} else if (c == '\0') {
940
				yyerror("syntax error");
941
				return (findeol());
942
			}
943
			if (p + 1 >= buf + sizeof(buf) - 1) {
944
				yyerror("string too long");
945
				return (findeol());
946
			}
947
			*p++ = c;
948
		}
949
		yylval.v.string = strdup(buf);
950
		if (yylval.v.string == NULL)
951
			err(1, "yylex: strdup");
952
		return (STRING);
953
	}
954
955
#define allowed_to_end_number(x) \
956
	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
957
958

896
	if (c == '-' || isdigit(c)) {
959
		do {
960
152
			*p++ = c;
961
152
			if ((unsigned)(p-buf) >= sizeof(buf)) {
962
				yyerror("string too long");
963
				return (findeol());
964
			}
965

304
		} while ((c = lgetc(0)) != EOF && isdigit(c));
966
96
		lungetc(c);
967

136
		if (p == buf + 1 && buf[0] == '-')
968
			goto nodigits;
969

192
		if (c == EOF || allowed_to_end_number(c)) {
970
64
			const char *errstr = NULL;
971
972
64
			*p = '\0';
973
64
			yylval.v.number = strtonum(buf, LLONG_MIN,
974
			    LLONG_MAX, &errstr);
975
64
			if (errstr) {
976
				yyerror("\"%s\" invalid number: %s",
977
				    buf, errstr);
978
				return (findeol());
979
			}
980
64
			return (NUMBER);
981
64
		} else {
982
nodigits:
983
96
			while (p > buf + 1)
984
32
				lungetc(*--p);
985
			c = *--p;
986
32
			if (c == '-')
987
				return (c);
988
		}
989
	}
990
991
#define allowed_in_string(x) \
992
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
993
	x != '{' && x != '}' && \
994
	x != '!' && x != '=' && x != '#' && \
995
	x != ','))
996
997
384
	if (isalnum(c) || c == ':' || c == '_') {
998
		do {
999
1760
			*p++ = c;
1000
1760
			if ((unsigned)(p-buf) >= sizeof(buf)) {
1001
				yyerror("string too long");
1002
				return (findeol());
1003
			}
1004

3920
		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1005
160
		lungetc(c);
1006
160
		*p = '\0';
1007
160
		if ((token = lookup(buf)) == STRING)
1008
48
			if ((yylval.v.string = strdup(buf)) == NULL)
1009
				err(1, "yylex: strdup");
1010
160
		return (token);
1011
	}
1012
224
	if (c == '\n') {
1013
144
		yylval.lineno = file->lineno;
1014
144
		file->lineno++;
1015
144
	}
1016
224
	if (c == EOF)
1017
16
		return (0);
1018
208
	return (c);
1019
448
}
1020
1021
int
1022
check_file_secrecy(int fd, const char *fname)
1023
{
1024
32
	struct stat	st;
1025
1026
16
	if (fstat(fd, &st)) {
1027
		log_warn("cannot stat %s", fname);
1028
		return (-1);
1029
	}
1030

16
	if (st.st_uid != 0 && st.st_uid != getuid()) {
1031
		log_warnx("%s: owner not root or current user", fname);
1032
		return (-1);
1033
	}
1034
16
	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1035
		log_warnx("%s: group writable or world read/writable", fname);
1036
		return (-1);
1037
	}
1038
16
	return (0);
1039
16
}
1040
1041
struct file *
1042
pushfile(const char *name, int secret)
1043
{
1044
	struct file	*nfile;
1045
1046
32
	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1047
		log_warn("malloc");
1048
		return (NULL);
1049
	}
1050
16
	if ((nfile->name = strdup(name)) == NULL) {
1051
		log_warn("malloc");
1052
		free(nfile);
1053
		return (NULL);
1054
	}
1055
16
	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1056
		log_warn("%s", nfile->name);
1057
		free(nfile->name);
1058
		free(nfile);
1059
		return (NULL);
1060

32
	} else if (secret &&
1061
48
	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1062
		fclose(nfile->stream);
1063
		free(nfile->name);
1064
		free(nfile);
1065
		return (NULL);
1066
	}
1067
16
	nfile->lineno = 1;
1068
16
	TAILQ_INSERT_TAIL(&files, nfile, entry);
1069
16
	return (nfile);
1070
16
}
1071
1072
int
1073
popfile(void)
1074
{
1075
	struct file	*prev;
1076
1077
32
	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1078
		prev->errors += file->errors;
1079
1080
32
	TAILQ_REMOVE(&files, file, entry);
1081
16
	fclose(file->stream);
1082
16
	free(file->name);
1083
16
	free(file);
1084
16
	file = prev;
1085
16
	return (file ? 0 : EOF);
1086
}
1087
1088
struct ospfd_conf *
1089
parse_config(char *filename, int opts)
1090
{
1091
	struct sym	*sym, *next;
1092
1093
32
	if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
1094
		fatal("parse_config");
1095
16
	conf->opts = opts;
1096
16
	if (conf->opts & OSPFD_OPT_STUB_ROUTER)
1097
16
		conf->flags |= OSPFD_FLAG_STUB_ROUTER;
1098
1099
16
	bzero(&globaldefs, sizeof(globaldefs));
1100
16
	defs = &globaldefs;
1101
16
	TAILQ_INIT(&defs->md_list);
1102
16
	defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
1103
16
	defs->fast_hello_interval = DEFAULT_FAST_INTERVAL;
1104
16
	defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
1105
16
	defs->hello_interval = DEFAULT_HELLO_INTERVAL;
1106
16
	defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
1107
16
	defs->metric = DEFAULT_METRIC;
1108
16
	defs->priority = DEFAULT_PRIORITY;
1109
1110
16
	conf->spf_delay = DEFAULT_SPF_DELAY;
1111
16
	conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
1112
16
	conf->spf_state = SPF_IDLE;
1113
1114
16
	if ((file = pushfile(filename, !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
1115
		free(conf);
1116
		return (NULL);
1117
	}
1118
16
	topfile = file;
1119
1120
16
	LIST_INIT(&conf->area_list);
1121
16
	LIST_INIT(&conf->cand_list);
1122
16
	SIMPLEQ_INIT(&conf->redist_list);
1123
1124
16
	yyparse();
1125
16
	errors = file->errors;
1126
16
	popfile();
1127
1128
	/* Free macros and check which have not been used. */
1129
32
	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1130
		if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
1131
			fprintf(stderr, "warning: macro '%s' not "
1132
			    "used\n", sym->nam);
1133
		if (!sym->persist) {
1134
			free(sym->nam);
1135
			free(sym->val);
1136
			TAILQ_REMOVE(&symhead, sym, entry);
1137
			free(sym);
1138
		}
1139
	}
1140
1141
	/* free global config defaults */
1142
16
	md_list_clr(&globaldefs.md_list);
1143
1144
	/* check that all interfaces belong to the configured rdomain */
1145
16
	errors += conf_check_rdomain(conf->rdomain);
1146
1147
16
	if (errors) {
1148
		clear_config(conf);
1149
		return (NULL);
1150
	}
1151
1152
16
	if (conf->rtr_id.s_addr == 0)
1153
		conf->rtr_id.s_addr = get_rtr_id();
1154
1155
16
	return (conf);
1156
16
}
1157
1158
int
1159
symset(const char *nam, const char *val, int persist)
1160
{
1161
	struct sym	*sym;
1162
1163
	TAILQ_FOREACH(sym, &symhead, entry) {
1164
		if (strcmp(nam, sym->nam) == 0)
1165
			break;
1166
	}
1167
1168
	if (sym != NULL) {
1169
		if (sym->persist == 1)
1170
			return (0);
1171
		else {
1172
			free(sym->nam);
1173
			free(sym->val);
1174
			TAILQ_REMOVE(&symhead, sym, entry);
1175
			free(sym);
1176
		}
1177
	}
1178
	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1179
		return (-1);
1180
1181
	sym->nam = strdup(nam);
1182
	if (sym->nam == NULL) {
1183
		free(sym);
1184
		return (-1);
1185
	}
1186
	sym->val = strdup(val);
1187
	if (sym->val == NULL) {
1188
		free(sym->nam);
1189
		free(sym);
1190
		return (-1);
1191
	}
1192
	sym->used = 0;
1193
	sym->persist = persist;
1194
	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1195
	return (0);
1196
}
1197
1198
int
1199
cmdline_symset(char *s)
1200
{
1201
	char	*sym, *val;
1202
	int	ret;
1203
	size_t	len;
1204
1205
	if ((val = strrchr(s, '=')) == NULL)
1206
		return (-1);
1207
1208
	len = strlen(s) - strlen(val) + 1;
1209
	if ((sym = malloc(len)) == NULL)
1210
		errx(1, "cmdline_symset: malloc");
1211
1212
	strlcpy(sym, s, len);
1213
1214
	ret = symset(sym, val + 1, 1);
1215
	free(sym);
1216
1217
	return (ret);
1218
}
1219
1220
char *
1221
symget(const char *nam)
1222
{
1223
	struct sym	*sym;
1224
1225
	TAILQ_FOREACH(sym, &symhead, entry) {
1226
		if (strcmp(nam, sym->nam) == 0) {
1227
			sym->used = 1;
1228
			return (sym->val);
1229
		}
1230
	}
1231
	return (NULL);
1232
}
1233
1234
struct area *
1235
conf_get_area(struct in_addr id)
1236
{
1237
	struct area	*a;
1238
1239
32
	a = area_find(conf, id);
1240
16
	if (a)
1241
		return (a);
1242
16
	a = area_new();
1243
32
	LIST_INSERT_HEAD(&conf->area_list, a, entry);
1244
1245
16
	a->id.s_addr = id.s_addr;
1246
1247
16
	return (a);
1248
16
}
1249
1250
struct iface *
1251
conf_get_if(struct kif *kif, struct kif_addr *ka)
1252
{
1253
	struct area	*a;
1254
	struct iface	*i;
1255
1256
80
	LIST_FOREACH(a, &conf->area_list, entry)
1257
32
		LIST_FOREACH(i, &a->iface_list, entry)
1258
			if (i->ifindex == kif->ifindex &&
1259
			    i->addr.s_addr == ka->addr.s_addr) {
1260
				yyerror("interface %s already configured",
1261
				    kif->ifname);
1262
				return (NULL);
1263
			}
1264
1265
16
	i = if_new(kif, ka);
1266
16
	i->auth_keyid = 1;
1267
1268
16
	return (i);
1269
16
}
1270
1271
int
1272
conf_check_rdomain(unsigned int rdomain)
1273
{
1274
	struct area	*a;
1275
	struct iface	*i;
1276
	int		 errs = 0;
1277
1278
80
	LIST_FOREACH(a, &conf->area_list, entry)
1279
64
		LIST_FOREACH(i, &a->iface_list, entry)
1280
16
			if (i->rdomain != rdomain) {
1281
				logit(LOG_CRIT,
1282
				    "interface %s not in rdomain %u",
1283
				    i->name, rdomain);
1284
				errs++;
1285
			}
1286
1287
16
	return (errs);
1288
}
1289
1290
void
1291
clear_config(struct ospfd_conf *xconf)
1292
{
1293
	struct area	*a;
1294
1295
	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
1296
		LIST_REMOVE(a, entry);
1297
		area_del(a);
1298
	}
1299
1300
	free(xconf);
1301
}
1302
1303
u_int32_t
1304
get_rtr_id(void)
1305
{
1306
	struct ifaddrs		*ifap, *ifa;
1307
	u_int32_t		 ip = 0, cur, localnet;
1308
1309
	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1310
1311
	if (getifaddrs(&ifap) == -1)
1312
		fatal("getifaddrs");
1313
1314
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1315
		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1316
			continue;
1317
		if (ifa->ifa_addr->sa_family != AF_INET)
1318
			continue;
1319
		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1320
		if ((cur & localnet) == localnet)	/* skip 127/8 */
1321
			continue;
1322
		if (ntohl(cur) < ntohl(ip) || ip == 0)
1323
			ip = cur;
1324
	}
1325
	freeifaddrs(ifap);
1326
1327
	if (ip == 0)
1328
		fatal("router-id is 0.0.0.0");
1329
1330
	return (ip);
1331
}
1332
1333
int
1334
host(const char *s, struct in_addr *addr, struct in_addr *mask)
1335
{
1336
	struct in_addr		 ina;
1337
	int			 bits = 32;
1338
1339
	bzero(&ina, sizeof(struct in_addr));
1340
	if (strrchr(s, '/') != NULL) {
1341
		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1342
			return (0);
1343
	} else {
1344
		if (inet_pton(AF_INET, s, &ina) != 1)
1345
			return (0);
1346
	}
1347
1348
	addr->s_addr = ina.s_addr;
1349
	mask->s_addr = prefixlen2mask(bits);
1350
1351
	return (1);
1352
}