GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospf6d/parse.y Lines: 0 333 0.0 %
Date: 2017-11-13 Branches: 0 245 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.y,v 1.30 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
31
#include <ctype.h>
32
#include <err.h>
33
#include <errno.h>
34
#include <unistd.h>
35
#include <ifaddrs.h>
36
#include <limits.h>
37
#include <netdb.h>
38
#include <stdarg.h>
39
#include <stdio.h>
40
#include <string.h>
41
#include <syslog.h>
42
43
#include "ospf6.h"
44
#include "ospf6d.h"
45
#include "ospfe.h"
46
#include "log.h"
47
48
TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
49
static struct file {
50
	TAILQ_ENTRY(file)	 entry;
51
	FILE			*stream;
52
	char			*name;
53
	int			 lineno;
54
	int			 errors;
55
} *file, *topfile;
56
struct file	*pushfile(const char *, int);
57
int		 popfile(void);
58
int		 check_file_secrecy(int, const char *);
59
int		 yyparse(void);
60
int		 yylex(void);
61
int		 yyerror(const char *, ...)
62
    __attribute__((__format__ (printf, 1, 2)))
63
    __attribute__((__nonnull__ (1)));
64
int		 kw_cmp(const void *, const void *);
65
int		 lookup(char *);
66
int		 lgetc(int);
67
int		 lungetc(int);
68
int		 findeol(void);
69
70
TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
71
struct sym {
72
	TAILQ_ENTRY(sym)	 entry;
73
	int			 used;
74
	int			 persist;
75
	char			*nam;
76
	char			*val;
77
};
78
int		 symset(const char *, const char *, int);
79
char		*symget(const char *);
80
81
void		 clear_config(struct ospfd_conf *xconf);
82
u_int32_t	 get_rtr_id(void);
83
int	 host(const char *, struct in6_addr *);
84
int	 prefix(const char *, struct in6_addr *, u_int8_t *);
85
86
static struct ospfd_conf	*conf;
87
static int			 errors = 0;
88
89
struct area	*area = NULL;
90
struct iface	*iface = NULL;
91
92
struct config_defaults {
93
	u_int16_t	dead_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
	u_int8_t	priority;
99
};
100
101
struct config_defaults	 globaldefs;
102
struct config_defaults	 areadefs;
103
struct config_defaults	 ifacedefs;
104
struct config_defaults	*defs;
105
106
struct area	*conf_get_area(struct in_addr);
107
108
typedef struct {
109
	union {
110
		int64_t		 number;
111
		char		*string;
112
		struct redistribute *redist;
113
	} v;
114
	int lineno;
115
} YYSTYPE;
116
117
%}
118
119
%token	AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL
120
%token	STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
121
%token	METRIC PASSIVE
122
%token	HELLOINTERVAL TRANSMITDELAY
123
%token	RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
124
%token	SET TYPE
125
%token	YES NO
126
%token	DEMOTE
127
%token	INCLUDE
128
%token	ERROR
129
%token	<v.string>	STRING
130
%token	<v.number>	NUMBER
131
%type	<v.number>	yesno no optlist, optlist_l option demotecount
132
%type	<v.string>	string
133
%type	<v.redist>	redistribute
134
135
%%
136
137
grammar		: /* empty */
138
		| grammar include '\n'
139
		| grammar '\n'
140
		| grammar conf_main '\n'
141
		| grammar varset '\n'
142
		| grammar area '\n'
143
		| grammar error '\n'		{ file->errors++; }
144
		;
145
146
include		: INCLUDE STRING		{
147
			struct file	*nfile;
148
149
			if ((nfile = pushfile($2, 1)) == NULL) {
150
				yyerror("failed to include file %s", $2);
151
				free($2);
152
				YYERROR;
153
			}
154
			free($2);
155
156
			file = nfile;
157
			lungetc('\n');
158
		}
159
		;
160
161
string		: string STRING	{
162
			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
163
				free($1);
164
				free($2);
165
				yyerror("string: asprintf");
166
				YYERROR;
167
			}
168
			free($1);
169
			free($2);
170
		}
171
		| STRING
172
		;
173
174
yesno		: YES	{ $$ = 1; }
175
		| NO	{ $$ = 0; }
176
		;
177
178
no		: /* empty */	{ $$ = 0; }
179
		| NO		{ $$ = 1; }
180
181
varset		: STRING '=' string		{
182
			char *s = $1;
183
			if (conf->opts & OSPFD_OPT_VERBOSE)
184
				printf("%s = \"%s\"\n", $1, $3);
185
			while (*s++) {
186
				if (isspace((unsigned char)*s)) {
187
					yyerror("macro name cannot contain "
188
					    "whitespace");
189
					YYERROR;
190
				}
191
			}
192
			if (symset($1, $3, 0) == -1)
193
				fatal("cannot store variable");
194
			free($1);
195
			free($3);
196
		}
197
		;
198
199
conf_main	: ROUTERID STRING {
200
			if (!inet_aton($2, &conf->rtr_id)) {
201
				yyerror("error parsing router-id");
202
				free($2);
203
				YYERROR;
204
			}
205
			free($2);
206
		}
207
		| FIBUPDATE yesno {
208
			if ($2 == 0)
209
				conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
210
			else
211
				conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
212
		}
213
		| redistribute {
214
			SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
215
			conf->redistribute = 1;
216
		}
217
		| RTLABEL STRING EXTTAG NUMBER {
218
			if ($4 < 0 || $4 > UINT_MAX) {
219
				yyerror("invalid external route tag");
220
				free($2);
221
				YYERROR;
222
			}
223
			rtlabel_tag(rtlabel_name2id($2), $4);
224
			free($2);
225
		}
226
		| SPFDELAY NUMBER {
227
			if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
228
				yyerror("spf-delay out of range "
229
				    "(%d-%d)", MIN_SPF_DELAY,
230
				    MAX_SPF_DELAY);
231
				YYERROR;
232
			}
233
			conf->spf_delay = $2;
234
		}
235
		| SPFHOLDTIME NUMBER {
236
			if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
237
				yyerror("spf-holdtime out of range "
238
				    "(%d-%d)", MIN_SPF_HOLDTIME,
239
				    MAX_SPF_HOLDTIME);
240
				YYERROR;
241
			}
242
			conf->spf_hold_time = $2;
243
		}
244
		| STUB ROUTER yesno {
245
			if ($3)
246
				conf->flags |= OSPFD_FLAG_STUB_ROUTER;
247
			else
248
				/* allow to force non stub mode */
249
				conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
250
		}
251
		| defaults
252
		;
253
254
redistribute	: no REDISTRIBUTE STRING optlist {
255
			struct redistribute	*r;
256
257
			if ((r = calloc(1, sizeof(*r))) == NULL)
258
				fatal(NULL);
259
			if (!strcmp($3, "default"))
260
				r->type = REDIST_DEFAULT;
261
			else if (!strcmp($3, "static"))
262
				r->type = REDIST_STATIC;
263
			else if (!strcmp($3, "connected"))
264
				r->type = REDIST_CONNECTED;
265
			else if (prefix($3, &r->addr, &r->prefixlen))
266
				r->type = REDIST_ADDR;
267
			else {
268
				yyerror("unknown redistribute type");
269
				free($3);
270
				free(r);
271
				YYERROR;
272
			}
273
274
			if ($1)
275
				r->type |= REDIST_NO;
276
			r->metric = $4;
277
			free($3);
278
			$$ = r;
279
		}
280
		| no REDISTRIBUTE RTLABEL STRING optlist {
281
			struct redistribute	*r;
282
283
			if ((r = calloc(1, sizeof(*r))) == NULL)
284
				fatal(NULL);
285
			r->type = REDIST_LABEL;
286
			r->label = rtlabel_name2id($4);
287
			if ($1)
288
				r->type |= REDIST_NO;
289
			r->metric = $5;
290
			free($4);
291
			$$ = r;
292
		}
293
		;
294
295
optlist		: /* empty */			{ $$ = DEFAULT_REDIST_METRIC; }
296
		| SET option			{
297
			$$ = $2;
298
			if (($$ & LSA_METRIC_MASK) == 0)
299
				$$ |= DEFAULT_REDIST_METRIC;
300
		}
301
		| SET optnl '{' optnl optlist_l optnl '}'	{
302
			$$ = $5;
303
			if (($$ & LSA_METRIC_MASK) == 0)
304
				$$ |= DEFAULT_REDIST_METRIC;
305
		}
306
		;
307
308
optlist_l	: optlist_l comma option {
309
			if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
310
				yyerror("redistribute type already defined");
311
				YYERROR;
312
			}
313
			if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
314
				yyerror("redistribute metric already defined");
315
				YYERROR;
316
			}
317
			$$ = $1 | $3;
318
		}
319
		| option { $$ = $1; }
320
		;
321
322
option		: METRIC NUMBER {
323
			if ($2 == 0 || $2 > MAX_METRIC) {
324
				yyerror("invalid redistribute metric");
325
				YYERROR;
326
			}
327
			$$ = $2;
328
		}
329
		| TYPE NUMBER {
330
			switch ($2) {
331
			case 1:
332
				$$ = 0;
333
				break;
334
			case 2:
335
				$$ = LSA_ASEXT_E_FLAG;
336
				break;
337
			default:
338
				yyerror("only external type 1 and 2 allowed");
339
				YYERROR;
340
			}
341
		}
342
		;
343
344
defaults	: METRIC NUMBER {
345
			if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
346
				yyerror("metric out of range (%d-%d)",
347
				    MIN_METRIC, MAX_METRIC);
348
				YYERROR;
349
			}
350
			defs->metric = $2;
351
		}
352
		| ROUTERPRIORITY NUMBER {
353
			if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
354
				yyerror("router-priority out of range (%d-%d)",
355
				    MIN_PRIORITY, MAX_PRIORITY);
356
				YYERROR;
357
			}
358
			defs->priority = $2;
359
		}
360
		| ROUTERDEADTIME NUMBER {
361
			if ($2 < MIN_RTR_DEAD_TIME || $2 > MAX_RTR_DEAD_TIME) {
362
				yyerror("router-dead-time out of range (%d-%d)",
363
				    MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
364
				YYERROR;
365
			}
366
			defs->dead_interval = $2;
367
		}
368
		| TRANSMITDELAY NUMBER {
369
			if ($2 < MIN_TRANSMIT_DELAY ||
370
			    $2 > MAX_TRANSMIT_DELAY) {
371
				yyerror("transmit-delay out of range (%d-%d)",
372
				    MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
373
				YYERROR;
374
			}
375
			defs->transmit_delay = $2;
376
		}
377
		| HELLOINTERVAL NUMBER {
378
			if ($2 < MIN_HELLO_INTERVAL ||
379
			    $2 > MAX_HELLO_INTERVAL) {
380
				yyerror("hello-interval out of range (%d-%d)",
381
				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
382
				YYERROR;
383
			}
384
			defs->hello_interval = $2;
385
		}
386
		| RETRANSMITINTERVAL NUMBER {
387
			if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
388
				yyerror("retransmit-interval out of range "
389
				    "(%d-%d)", MIN_RXMT_INTERVAL,
390
				    MAX_RXMT_INTERVAL);
391
				YYERROR;
392
			}
393
			defs->rxmt_interval = $2;
394
		}
395
		;
396
397
optnl		: '\n' optnl
398
		|
399
		;
400
401
nl		: '\n' optnl		/* one newline or more */
402
		;
403
404
comma		: ','
405
		| /*empty*/
406
		;
407
408
area		: AREA STRING {
409
			struct in_addr	id;
410
			if (inet_aton($2, &id) == 0) {
411
				yyerror("error parsing area");
412
				free($2);
413
				YYERROR;
414
			}
415
			free($2);
416
			area = conf_get_area(id);
417
418
			memcpy(&areadefs, defs, sizeof(areadefs));
419
			defs = &areadefs;
420
		} '{' optnl areaopts_l '}' {
421
			area = NULL;
422
			defs = &globaldefs;
423
		}
424
		;
425
426
demotecount	: NUMBER	{ $$ = $1; }
427
		| /*empty*/	{ $$ = 1; }
428
		;
429
430
areaopts_l	: areaopts_l areaoptsl nl
431
		| areaoptsl optnl
432
		;
433
434
areaoptsl	: interface
435
		| DEMOTE STRING	demotecount {
436
			if ($3 < 1 || $3 > 255) {
437
				yyerror("demote count out of range (1-255)");
438
				free($2);
439
				YYERROR;
440
			}
441
			area->demote_level = $3;
442
			if (strlcpy(area->demote_group, $2,
443
			    sizeof(area->demote_group)) >=
444
			    sizeof(area->demote_group)) {
445
				yyerror("demote group name \"%s\" too long",
446
				    $2);
447
				free($2);
448
				YYERROR;
449
			}
450
			free($2);
451
			if (carp_demote_init(area->demote_group,
452
			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
453
				yyerror("error initializing group \"%s\"",
454
				    area->demote_group);
455
				YYERROR;
456
			}
457
		}
458
		| defaults
459
		;
460
461
interface	: INTERFACE STRING	{
462
			if ((iface = if_findname($2)) == NULL) {
463
				yyerror("unknown interface %s", $2);
464
				free($2);
465
				YYERROR;
466
			}
467
			if (IN6_IS_ADDR_UNSPECIFIED(&iface->addr)) {
468
				yyerror("unnumbered interface %s", $2);
469
				free($2);
470
				YYERROR;
471
			}
472
			free($2);
473
			iface->area_id.s_addr = area->id.s_addr;
474
			LIST_INSERT_HEAD(&area->iface_list, iface, entry);
475
476
			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
477
			defs = &ifacedefs;
478
		} interface_block {
479
			iface->dead_interval = defs->dead_interval;
480
			iface->transmit_delay = defs->transmit_delay;
481
			iface->hello_interval = defs->hello_interval;
482
			iface->rxmt_interval = defs->rxmt_interval;
483
			iface->metric = defs->metric;
484
			iface->priority = defs->priority;
485
			iface->cflags |= F_IFACE_CONFIGURED;
486
			iface = NULL;
487
			/* interface is always part of an area */
488
			defs = &areadefs;
489
		}
490
		;
491
492
interface_block	: '{' optnl interfaceopts_l '}'
493
		| '{' optnl '}'
494
		|
495
		;
496
497
interfaceopts_l	: interfaceopts_l interfaceoptsl nl
498
		| interfaceoptsl optnl
499
		;
500
501
interfaceoptsl	: PASSIVE		{ iface->cflags |= F_IFACE_PASSIVE; }
502
		| DEMOTE STRING		{
503
			if (strlcpy(iface->demote_group, $2,
504
			    sizeof(iface->demote_group)) >=
505
			    sizeof(iface->demote_group)) {
506
				yyerror("demote group name \"%s\" too long",
507
				    $2);
508
				free($2);
509
				YYERROR;
510
			}
511
			free($2);
512
			if (carp_demote_init(iface->demote_group,
513
			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
514
				yyerror("error initializing group \"%s\"",
515
				    iface->demote_group);
516
				YYERROR;
517
			}
518
		}
519
		| defaults
520
		;
521
522
%%
523
524
struct keywords {
525
	const char	*k_name;
526
	int		 k_val;
527
};
528
529
int
530
yyerror(const char *fmt, ...)
531
{
532
	va_list		 ap;
533
	char		*msg;
534
535
	file->errors++;
536
	va_start(ap, fmt);
537
	if (vasprintf(&msg, fmt, ap) == -1)
538
		fatalx("yyerror vasprintf");
539
	va_end(ap);
540
	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
541
	free(msg);
542
	return (0);
543
}
544
545
int
546
kw_cmp(const void *k, const void *e)
547
{
548
	return (strcmp(k, ((const struct keywords *)e)->k_name));
549
}
550
551
int
552
lookup(char *s)
553
{
554
	/* this has to be sorted always */
555
	static const struct keywords keywords[] = {
556
		{"area",		AREA},
557
		{"demote",		DEMOTE},
558
		{"external-tag",	EXTTAG},
559
		{"fib-update",		FIBUPDATE},
560
		{"hello-interval",	HELLOINTERVAL},
561
		{"include",		INCLUDE},
562
		{"interface",		INTERFACE},
563
		{"metric",		METRIC},
564
		{"no",			NO},
565
		{"passive",		PASSIVE},
566
		{"redistribute",	REDISTRIBUTE},
567
		{"retransmit-interval",	RETRANSMITINTERVAL},
568
		{"router",		ROUTER},
569
		{"router-dead-time",	ROUTERDEADTIME},
570
		{"router-id",		ROUTERID},
571
		{"router-priority",	ROUTERPRIORITY},
572
		{"rtlabel",		RTLABEL},
573
		{"set",			SET},
574
		{"spf-delay",		SPFDELAY},
575
		{"spf-holdtime",	SPFHOLDTIME},
576
		{"stub",		STUB},
577
		{"transmit-delay",	TRANSMITDELAY},
578
		{"type",		TYPE},
579
		{"yes",			YES}
580
	};
581
	const struct keywords	*p;
582
583
	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
584
	    sizeof(keywords[0]), kw_cmp);
585
586
	if (p)
587
		return (p->k_val);
588
	else
589
		return (STRING);
590
}
591
592
#define MAXPUSHBACK	128
593
594
u_char	*parsebuf;
595
int	 parseindex;
596
u_char	 pushback_buffer[MAXPUSHBACK];
597
int	 pushback_index = 0;
598
599
int
600
lgetc(int quotec)
601
{
602
	int		c, next;
603
604
	if (parsebuf) {
605
		/* Read character from the parsebuffer instead of input. */
606
		if (parseindex >= 0) {
607
			c = parsebuf[parseindex++];
608
			if (c != '\0')
609
				return (c);
610
			parsebuf = NULL;
611
		} else
612
			parseindex++;
613
	}
614
615
	if (pushback_index)
616
		return (pushback_buffer[--pushback_index]);
617
618
	if (quotec) {
619
		if ((c = getc(file->stream)) == EOF) {
620
			yyerror("reached end of file while parsing "
621
			    "quoted string");
622
			if (file == topfile || popfile() == EOF)
623
				return (EOF);
624
			return (quotec);
625
		}
626
		return (c);
627
	}
628
629
	while ((c = getc(file->stream)) == '\\') {
630
		next = getc(file->stream);
631
		if (next != '\n') {
632
			c = next;
633
			break;
634
		}
635
		yylval.lineno = file->lineno;
636
		file->lineno++;
637
	}
638
639
	while (c == EOF) {
640
		if (file == topfile || popfile() == EOF)
641
			return (EOF);
642
		c = getc(file->stream);
643
	}
644
	return (c);
645
}
646
647
int
648
lungetc(int c)
649
{
650
	if (c == EOF)
651
		return (EOF);
652
	if (parsebuf) {
653
		parseindex--;
654
		if (parseindex >= 0)
655
			return (c);
656
	}
657
	if (pushback_index < MAXPUSHBACK-1)
658
		return (pushback_buffer[pushback_index++] = c);
659
	else
660
		return (EOF);
661
}
662
663
int
664
findeol(void)
665
{
666
	int	c;
667
668
	parsebuf = NULL;
669
670
	/* skip to either EOF or the first real EOL */
671
	while (1) {
672
		if (pushback_index)
673
			c = pushback_buffer[--pushback_index];
674
		else
675
			c = lgetc(0);
676
		if (c == '\n') {
677
			file->lineno++;
678
			break;
679
		}
680
		if (c == EOF)
681
			break;
682
	}
683
	return (ERROR);
684
}
685
686
int
687
yylex(void)
688
{
689
	u_char	 buf[8096];
690
	u_char	*p, *val;
691
	int	 quotec, next, c;
692
	int	 token;
693
694
top:
695
	p = buf;
696
	while ((c = lgetc(0)) == ' ' || c == '\t')
697
		; /* nothing */
698
699
	yylval.lineno = file->lineno;
700
	if (c == '#')
701
		while ((c = lgetc(0)) != '\n' && c != EOF)
702
			; /* nothing */
703
	if (c == '$' && parsebuf == NULL) {
704
		while (1) {
705
			if ((c = lgetc(0)) == EOF)
706
				return (0);
707
708
			if (p + 1 >= buf + sizeof(buf) - 1) {
709
				yyerror("string too long");
710
				return (findeol());
711
			}
712
			if (isalnum(c) || c == '_') {
713
				*p++ = c;
714
				continue;
715
			}
716
			*p = '\0';
717
			lungetc(c);
718
			break;
719
		}
720
		val = symget(buf);
721
		if (val == NULL) {
722
			yyerror("macro '%s' not defined", buf);
723
			return (findeol());
724
		}
725
		parsebuf = val;
726
		parseindex = 0;
727
		goto top;
728
	}
729
730
	switch (c) {
731
	case '\'':
732
	case '"':
733
		quotec = c;
734
		while (1) {
735
			if ((c = lgetc(quotec)) == EOF)
736
				return (0);
737
			if (c == '\n') {
738
				file->lineno++;
739
				continue;
740
			} else if (c == '\\') {
741
				if ((next = lgetc(quotec)) == EOF)
742
					return (0);
743
				if (next == quotec || c == ' ' || c == '\t')
744
					c = next;
745
				else if (next == '\n') {
746
					file->lineno++;
747
					continue;
748
				} else
749
					lungetc(next);
750
			} else if (c == quotec) {
751
				*p = '\0';
752
				break;
753
			} else if (c == '\0') {
754
				yyerror("syntax error");
755
				return (findeol());
756
			}
757
			if (p + 1 >= buf + sizeof(buf) - 1) {
758
				yyerror("string too long");
759
				return (findeol());
760
			}
761
			*p++ = c;
762
		}
763
		yylval.v.string = strdup(buf);
764
		if (yylval.v.string == NULL)
765
			err(1, "yylex: strdup");
766
		return (STRING);
767
	}
768
769
#define allowed_to_end_number(x) \
770
	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
771
772
	if (c == '-' || isdigit(c)) {
773
		do {
774
			*p++ = c;
775
			if ((unsigned)(p-buf) >= sizeof(buf)) {
776
				yyerror("string too long");
777
				return (findeol());
778
			}
779
		} while ((c = lgetc(0)) != EOF && isdigit(c));
780
		lungetc(c);
781
		if (p == buf + 1 && buf[0] == '-')
782
			goto nodigits;
783
		if (c == EOF || allowed_to_end_number(c)) {
784
			const char *errstr = NULL;
785
786
			*p = '\0';
787
			yylval.v.number = strtonum(buf, LLONG_MIN,
788
			    LLONG_MAX, &errstr);
789
			if (errstr) {
790
				yyerror("\"%s\" invalid number: %s",
791
				    buf, errstr);
792
				return (findeol());
793
			}
794
			return (NUMBER);
795
		} else {
796
nodigits:
797
			while (p > buf + 1)
798
				lungetc(*--p);
799
			c = *--p;
800
			if (c == '-')
801
				return (c);
802
		}
803
	}
804
805
#define allowed_in_string(x) \
806
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
807
	x != '{' && x != '}' && \
808
	x != '!' && x != '=' && x != '#' && \
809
	x != ','))
810
811
	if (isalnum(c) || c == ':' || c == '_') {
812
		do {
813
			*p++ = c;
814
			if ((unsigned)(p-buf) >= sizeof(buf)) {
815
				yyerror("string too long");
816
				return (findeol());
817
			}
818
		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
819
		lungetc(c);
820
		*p = '\0';
821
		if ((token = lookup(buf)) == STRING)
822
			if ((yylval.v.string = strdup(buf)) == NULL)
823
				err(1, "yylex: strdup");
824
		return (token);
825
	}
826
	if (c == '\n') {
827
		yylval.lineno = file->lineno;
828
		file->lineno++;
829
	}
830
	if (c == EOF)
831
		return (0);
832
	return (c);
833
}
834
835
int
836
check_file_secrecy(int fd, const char *fname)
837
{
838
	struct stat	st;
839
840
	if (fstat(fd, &st)) {
841
		log_warn("cannot stat %s", fname);
842
		return (-1);
843
	}
844
	if (st.st_uid != 0 && st.st_uid != getuid()) {
845
		log_warnx("%s: owner not root or current user", fname);
846
		return (-1);
847
	}
848
	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
849
		log_warnx("%s: group writable or world read/writable", fname);
850
		return (-1);
851
	}
852
	return (0);
853
}
854
855
struct file *
856
pushfile(const char *name, int secret)
857
{
858
	struct file	*nfile;
859
860
	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
861
		log_warn("malloc");
862
		return (NULL);
863
	}
864
	if ((nfile->name = strdup(name)) == NULL) {
865
		log_warn("malloc");
866
		free(nfile);
867
		return (NULL);
868
	}
869
	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
870
		log_warn("%s", nfile->name);
871
		free(nfile->name);
872
		free(nfile);
873
		return (NULL);
874
	} else if (secret &&
875
	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
876
		fclose(nfile->stream);
877
		free(nfile->name);
878
		free(nfile);
879
		return (NULL);
880
	}
881
	nfile->lineno = 1;
882
	TAILQ_INSERT_TAIL(&files, nfile, entry);
883
	return (nfile);
884
}
885
886
int
887
popfile(void)
888
{
889
	struct file	*prev;
890
891
	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
892
		prev->errors += file->errors;
893
894
	TAILQ_REMOVE(&files, file, entry);
895
	fclose(file->stream);
896
	free(file->name);
897
	free(file);
898
	file = prev;
899
	return (file ? 0 : EOF);
900
}
901
902
struct ospfd_conf *
903
parse_config(char *filename, int opts)
904
{
905
	struct sym	*sym, *next;
906
907
	if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
908
		fatal("parse_config");
909
	conf->opts = opts;
910
	if (conf->opts & OSPFD_OPT_STUB_ROUTER)
911
		conf->flags |= OSPFD_FLAG_STUB_ROUTER;
912
913
	bzero(&globaldefs, sizeof(globaldefs));
914
	defs = &globaldefs;
915
	defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
916
	defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
917
	defs->hello_interval = DEFAULT_HELLO_INTERVAL;
918
	defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
919
	defs->metric = DEFAULT_METRIC;
920
	defs->priority = DEFAULT_PRIORITY;
921
922
	conf->spf_delay = DEFAULT_SPF_DELAY;
923
	conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
924
	conf->spf_state = SPF_IDLE;
925
926
	if ((file = pushfile(filename, !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
927
		free(conf);
928
		return (NULL);
929
	}
930
	topfile = file;
931
932
	LIST_INIT(&conf->area_list);
933
	LIST_INIT(&conf->cand_list);
934
	SIMPLEQ_INIT(&conf->redist_list);
935
936
	yyparse();
937
	errors = file->errors;
938
	popfile();
939
940
	/* Free macros and check which have not been used. */
941
	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
942
		if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
943
			fprintf(stderr, "warning: macro '%s' not "
944
			    "used\n", sym->nam);
945
		if (!sym->persist) {
946
			free(sym->nam);
947
			free(sym->val);
948
			TAILQ_REMOVE(&symhead, sym, entry);
949
			free(sym);
950
		}
951
	}
952
953
	/* free global config defaults */
954
	if (errors) {
955
		clear_config(conf);
956
		return (NULL);
957
	}
958
959
	if (conf->rtr_id.s_addr == 0)
960
		conf->rtr_id.s_addr = get_rtr_id();
961
962
	return (conf);
963
}
964
965
int
966
symset(const char *nam, const char *val, int persist)
967
{
968
	struct sym	*sym;
969
970
	TAILQ_FOREACH(sym, &symhead, entry) {
971
		if (strcmp(nam, sym->nam) == 0)
972
			break;
973
	}
974
975
	if (sym != NULL) {
976
		if (sym->persist == 1)
977
			return (0);
978
		else {
979
			free(sym->nam);
980
			free(sym->val);
981
			TAILQ_REMOVE(&symhead, sym, entry);
982
			free(sym);
983
		}
984
	}
985
	if ((sym = calloc(1, sizeof(*sym))) == NULL)
986
		return (-1);
987
988
	sym->nam = strdup(nam);
989
	if (sym->nam == NULL) {
990
		free(sym);
991
		return (-1);
992
	}
993
	sym->val = strdup(val);
994
	if (sym->val == NULL) {
995
		free(sym->nam);
996
		free(sym);
997
		return (-1);
998
	}
999
	sym->used = 0;
1000
	sym->persist = persist;
1001
	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1002
	return (0);
1003
}
1004
1005
int
1006
cmdline_symset(char *s)
1007
{
1008
	char	*sym, *val;
1009
	int	ret;
1010
	size_t	len;
1011
1012
	if ((val = strrchr(s, '=')) == NULL)
1013
		return (-1);
1014
1015
	len = strlen(s) - strlen(val) + 1;
1016
	if ((sym = malloc(len)) == NULL)
1017
		errx(1, "cmdline_symset: malloc");
1018
1019
	strlcpy(sym, s, len);
1020
1021
	ret = symset(sym, val + 1, 1);
1022
	free(sym);
1023
1024
	return (ret);
1025
}
1026
1027
char *
1028
symget(const char *nam)
1029
{
1030
	struct sym	*sym;
1031
1032
	TAILQ_FOREACH(sym, &symhead, entry) {
1033
		if (strcmp(nam, sym->nam) == 0) {
1034
			sym->used = 1;
1035
			return (sym->val);
1036
		}
1037
	}
1038
	return (NULL);
1039
}
1040
1041
struct area *
1042
conf_get_area(struct in_addr id)
1043
{
1044
	struct area	*a;
1045
1046
	a = area_find(conf, id);
1047
	if (a)
1048
		return (a);
1049
	a = area_new();
1050
	LIST_INSERT_HEAD(&conf->area_list, a, entry);
1051
1052
	a->id.s_addr = id.s_addr;
1053
1054
	return (a);
1055
}
1056
1057
void
1058
clear_config(struct ospfd_conf *xconf)
1059
{
1060
	struct area	*a;
1061
1062
	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
1063
		LIST_REMOVE(a, entry);
1064
		area_del(a);
1065
	}
1066
1067
	free(xconf);
1068
}
1069
1070
u_int32_t
1071
get_rtr_id(void)
1072
{
1073
	struct ifaddrs		*ifap, *ifa;
1074
	u_int32_t		 ip = 0, cur, localnet;
1075
1076
	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1077
1078
	if (getifaddrs(&ifap) == -1)
1079
		fatal("getifaddrs");
1080
1081
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1082
		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1083
			continue;
1084
		if (ifa->ifa_addr->sa_family != AF_INET)
1085
			continue;
1086
		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1087
		if ((cur & localnet) == localnet)	/* skip 127/8 */
1088
			continue;
1089
		if (ntohl(cur) < ntohl(ip) || ip == 0)
1090
			ip = cur;
1091
	}
1092
	freeifaddrs(ifap);
1093
1094
	if (ip == 0)
1095
		fatal("router-id is 0.0.0.0");
1096
1097
	return (ip);
1098
}
1099
1100
int
1101
host(const char *s, struct in6_addr *addr)
1102
{
1103
	struct addrinfo	hints, *r;
1104
1105
	if (s == NULL)
1106
		return (0);
1107
1108
	bzero(addr, sizeof(struct in6_addr));
1109
	bzero(&hints, sizeof(hints));
1110
	hints.ai_family = AF_INET6;
1111
	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1112
	hints.ai_flags = AI_NUMERICHOST;
1113
	if (getaddrinfo(s, "0", &hints, &r) == 0) {
1114
		*addr = ((struct sockaddr_in6 *)r->ai_addr)->sin6_addr;
1115
		/* XXX address scope !!! */
1116
		/* ((struct sockaddr_in6 *)r->ai_addr)->sin6_scope_id */
1117
		freeaddrinfo(r);
1118
		return (1);
1119
	}
1120
	return (0);
1121
}
1122
1123
int
1124
prefix(const char *s, struct in6_addr *addr, u_int8_t *plen)
1125
{
1126
	char		*p, *ps;
1127
	const char	*errstr;
1128
	int		 mask;
1129
1130
	if (s == NULL)
1131
		return (0);
1132
1133
	if ((p = strrchr(s, '/')) != NULL) {
1134
		mask = strtonum(p + 1, 0, 128, &errstr);
1135
		if (errstr)
1136
			errx(1, "invalid netmask: %s", errstr);
1137
1138
		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
1139
			err(1, "parse_prefix: malloc");
1140
		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
1141
1142
		if (host(ps, addr) == 0) {
1143
			free(ps);
1144
			return (0);
1145
		}
1146
1147
		inet6applymask(addr, addr, mask);
1148
		*plen = mask;
1149
		return (1);
1150
	}
1151
	*plen = 128;
1152
	return (host(s, addr));
1153
}