1 /* $OpenBSD: parse.y,v 1.74 2024/08/22 08:17:54 florian Exp $ */
2
3 /*
4 * Copyright (c) 2013, 2015, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8 * Copyright (c) 2001 Markus Friedl. All rights reserved.
9 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
10 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
11 *
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 %{
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
30 #include <ctype.h>
31 #include <err.h>
32 #include <unistd.h>
33 #include <ifaddrs.h>
34 #include <net/if_types.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <syslog.h>
38 #include <errno.h>
39 #include <netdb.h>
40
41 #include "ldpd.h"
42 #include "ldpe.h"
43 #include "lde.h"
44 #include "log.h"
45
46 struct file {
47 TAILQ_ENTRY(file) entry;
48 FILE *stream;
49 char *name;
50 size_t ungetpos;
51 size_t ungetsize;
52 u_char *ungetbuf;
53 int eof_reached;
54 int lineno;
55 int errors;
56 };
57 TAILQ_HEAD(files, file);
58
59 struct sym {
60 TAILQ_ENTRY(sym) entry;
61 int used;
62 int persist;
63 char *nam;
64 char *val;
65 };
66 TAILQ_HEAD(symhead, sym);
67
68 struct config_defaults {
69 uint16_t keepalive;
70 uint16_t lhello_holdtime;
71 uint16_t lhello_interval;
72 uint16_t thello_holdtime;
73 uint16_t thello_interval;
74 union ldpd_addr trans_addr;
75 int afflags;
76 uint8_t pwflags;
77 };
78
79 typedef struct {
80 union {
81 int64_t number;
82 char *string;
83 struct in_addr routerid;
84 struct ldp_auth *auth;
85 } v;
86 int lineno;
87 } YYSTYPE;
88
89 static int yyerror(const char *, ...)
90 __attribute__((__format__ (printf, 1, 2)))
91 __attribute__((__nonnull__ (1)));
92 static int kw_cmp(const void *, const void *);
93 static int lookup(char *);
94 static int igetc(void);
95 static int lgetc(int);
96 void lungetc(int);
97 static int findeol(void);
98 static int yylex(void);
99 static int check_file_secrecy(int, const char *);
100 static struct file *pushfile(const char *, int);
101 static int popfile(void);
102 static int yyparse(void);
103 static int symset(const char *, const char *, int);
104 static char *symget(const char *);
105 static struct iface *conf_get_if(struct kif *);
106 static struct tnbr *conf_get_tnbr(union ldpd_addr *);
107 static struct nbr_params *conf_get_nbrp(struct in_addr);
108 static struct l2vpn *conf_get_l2vpn(char *);
109 static struct l2vpn_if *conf_get_l2vpn_if(struct l2vpn *, struct kif *);
110 static struct l2vpn_pw *conf_get_l2vpn_pw(struct l2vpn *, struct kif *);
111 int conf_check_rdomain(unsigned int);
112 static void clear_config(struct ldpd_conf *xconf);
113 static uint32_t get_rtr_id(void);
114 static int get_address(const char *, union ldpd_addr *);
115 static int get_af_address(const char *, int *, union ldpd_addr *);
116 static int str2key(char *, const char *, int);
117
118 static struct file *file, *topfile;
119 static struct files files = TAILQ_HEAD_INITIALIZER(files);
120 static struct symhead symhead = TAILQ_HEAD_INITIALIZER(symhead);
121 static struct ldpd_conf *conf;
122 static int errors;
123
124 static int af;
125 static struct ldpd_af_conf *af_conf;
126 static struct iface *iface;
127 static struct iface_af *ia;
128 static struct tnbr *tnbr;
129 static struct nbr_params *nbrp;
130 static struct l2vpn *l2vpn;
131 static struct l2vpn_pw *pw;
132
133 static struct config_defaults globaldefs;
134 static struct config_defaults afdefs;
135 static struct config_defaults ifacedefs;
136 static struct config_defaults tnbrdefs;
137 static struct config_defaults pwdefs;
138 static struct config_defaults *defs;
139
140 %}
141
142 %token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE RDOMAIN EXPNULL
143 %token LHELLOHOLDTIME LHELLOINTERVAL
144 %token THELLOHOLDTIME THELLOINTERVAL
145 %token THELLOACCEPT AF IPV4 IPV6 INET INET6 GTSMENABLE GTSMHOPS
146 %token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP
147 %token NEIGHBOR
148 %token TCP MD5SIG PASSWORD KEY
149 %token L2VPN TYPE VPLS PWTYPE MTU BRIDGE
150 %token ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD
151 %token PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID
152 %token EXTTAG
153 %token YES NO
154 %token INCLUDE
155 %token ERROR
156 %token <v.string> STRING
157 %token <v.number> NUMBER
158 %type <v.number> yesno ldp_af l2vpn_type pw_type
159 %type <v.string> string
160 %type <v.routerid> routerid
161 %type <v.auth> auth tcpmd5 optnbrprefix
162
163 %%
164
165 grammar : /* empty */
166 | grammar include '\n'
167 | grammar '\n'
168 | grammar conf_main '\n'
169 | grammar varset '\n'
170 | grammar af '\n'
171 | grammar neighbor '\n'
172 | grammar l2vpn '\n'
173 | grammar error '\n' { file->errors++; }
174 ;
175
176 include : INCLUDE STRING {
177 struct file *nfile;
178
179 if ((nfile = pushfile($2,
180 !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) {
181 yyerror("failed to include file %s", $2);
182 free($2);
183 YYERROR;
184 }
185 free($2);
186
187 file = nfile;
188 lungetc('\n');
189 }
190 ;
191
192 string : string STRING {
193 if (asprintf(&$$, "%s %s", $1, $2) == -1) {
194 free($1);
195 free($2);
196 yyerror("string: asprintf");
197 YYERROR;
198 }
199 free($1);
200 free($2);
201 }
202 | STRING
203 ;
204
205 routerid : STRING {
206 if (inet_pton(AF_INET, $1, &$$) != 1) {
207 yyerror("%s: error parsing router id", $1);
208 free($1);
209 YYERROR;
210 }
211 if (bad_addr_v4($$)) {
212 yyerror("%s: invalid router id", $1);
213 free($1);
214 YYERROR;
215 }
216 free($1);
217
218 break;
219 }
220 ;
221
222 yesno : YES { $$ = 1; }
223 | NO { $$ = 0; }
224 ;
225
226 ldp_af : IPV4 { $$ = AF_INET; }
227 | IPV6 { $$ = AF_INET6; }
228 ;
229
230 l2vpn_type : VPLS { $$ = L2VPN_TYPE_VPLS; }
231 ;
232
233 pw_type : ETHERNET { $$ = PW_TYPE_ETHERNET; }
234 | ETHERNETTAGGED { $$ = PW_TYPE_ETHERNET_TAGGED; }
235 ;
236
237 varset : STRING '=' string {
238 char *s = $1;
239 if (global.cmd_opts & LDPD_OPT_VERBOSE)
240 printf("%s = \"%s\"\n", $1, $3);
241 while (*s++) {
242 if (isspace((unsigned char)*s)) {
243 yyerror("macro name cannot contain "
244 "whitespace");
245 free($1);
246 free($3);
247 YYERROR;
248 }
249 }
250 if (symset($1, $3, 0) == -1)
251 fatal("cannot store variable");
252 free($1);
253 free($3);
254 }
255 ;
256
257 conf_main : ROUTERID routerid {
258 conf->rtr_id = $2;
259 }
260 | FIBUPDATE yesno {
261 if ($2 == 0)
262 conf->flags |= F_LDPD_NO_FIB_UPDATE;
263 else
264 conf->flags &= ~F_LDPD_NO_FIB_UPDATE;
265 }
266 | RDOMAIN NUMBER {
267 if ($2 < 0 || $2 > RT_TABLEID_MAX) {
268 yyerror("invalid rdomain");
269 YYERROR;
270 }
271 conf->rdomain = $2;
272 }
273 | TRANSPREFERENCE ldp_af {
274 conf->trans_pref = $2;
275
276 switch (conf->trans_pref) {
277 case AF_INET:
278 conf->trans_pref = DUAL_STACK_LDPOV4;
279 break;
280 case AF_INET6:
281 conf->trans_pref = DUAL_STACK_LDPOV6;
282 break;
283 default:
284 yyerror("invalid address-family");
285 YYERROR;
286 }
287 }
288 | DSCISCOINTEROP yesno {
289 if ($2 == 1)
290 conf->flags |= F_LDPD_DS_CISCO_INTEROP;
291 else
292 conf->flags &= ~F_LDPD_DS_CISCO_INTEROP;
293 }
294 | auth {
295 LIST_INSERT_HEAD(&conf->auth_list, $1, entry);
296 }
297 | af_defaults
298 | iface_defaults
299 | tnbr_defaults
300 ;
301
302 af : AF ldp_af {
303 af = $2;
304 switch (af) {
305 case AF_INET:
306 af_conf = &conf->ipv4;
307 break;
308 case AF_INET6:
309 af_conf = &conf->ipv6;
310 break;
311 default:
312 yyerror("invalid address-family");
313 YYERROR;
314 }
315
316 afdefs = *defs;
317 defs = &afdefs;
318 } af_block {
319 af_conf->keepalive = defs->keepalive;
320 af_conf->thello_holdtime = defs->thello_holdtime;
321 af_conf->thello_interval = defs->thello_interval;
322 af_conf->flags = defs->afflags;
323 af_conf->flags |= F_LDPD_AF_ENABLED;
324 af_conf = NULL;
325 af = AF_UNSPEC;
326 defs = &globaldefs;
327 }
328 ;
329
330 af_block : '{' optnl afopts_l '}'
331 | '{' optnl '}'
332 |
333 ;
334
335 afopts_l : afopts_l afoptsl nl
336 | afoptsl optnl
337 ;
338
339 afoptsl : TRANSADDRESS STRING {
340 if (get_address($2, &af_conf->trans_addr) == -1) {
341 yyerror("error parsing transport-address");
342 free($2);
343 YYERROR;
344 }
345 free($2);
346 if (bad_addr(af, &af_conf->trans_addr)) {
347 yyerror("invalid transport-address");
348 YYERROR;
349 }
350 if (af == AF_INET6 &&
351 IN6_IS_SCOPE_EMBED(&af_conf->trans_addr.v6)) {
352 yyerror("ipv6 transport-address can not be "
353 "link-local");
354 YYERROR;
355 }
356 }
357 | GTSMENABLE yesno {
358 if ($2 == 0)
359 defs->afflags |= F_LDPD_AF_NO_GTSM;
360 }
361 | af_defaults
362 | iface_defaults
363 | tnbr_defaults
364 | interface
365 | tneighbor
366 ;
367
368 af_defaults : THELLOACCEPT yesno {
369 if ($2 == 0)
370 defs->afflags &= ~F_LDPD_AF_THELLO_ACCEPT;
371 else
372 defs->afflags |= F_LDPD_AF_THELLO_ACCEPT;
373 }
374 | EXPNULL yesno {
375 if ($2 == 0)
376 defs->afflags &= ~F_LDPD_AF_EXPNULL;
377 else
378 defs->afflags |= F_LDPD_AF_EXPNULL;
379 }
380 | KEEPALIVE NUMBER {
381 if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) {
382 yyerror("keepalive out of range (%d-%d)",
383 MIN_KEEPALIVE, MAX_KEEPALIVE);
384 YYERROR;
385 }
386 defs->keepalive = $2;
387 }
388 ;
389
390 iface_defaults : LHELLOHOLDTIME NUMBER {
391 if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) {
392 yyerror("hello-holdtime out of range (%d-%d)",
393 MIN_HOLDTIME, MAX_HOLDTIME);
394 YYERROR;
395 }
396 defs->lhello_holdtime = $2;
397 }
398 | LHELLOINTERVAL NUMBER {
399 if ($2 < MIN_HELLO_INTERVAL ||
400 $2 > MAX_HELLO_INTERVAL) {
401 yyerror("hello-interval out of range (%d-%d)",
402 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
403 YYERROR;
404 }
405 defs->lhello_interval = $2;
406 }
407 ;
408
409 tnbr_defaults : THELLOHOLDTIME NUMBER {
410 if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) {
411 yyerror("hello-holdtime out of range (%d-%d)",
412 MIN_HOLDTIME, MAX_HOLDTIME);
413 YYERROR;
414 }
415 defs->thello_holdtime = $2;
416 }
417 | THELLOINTERVAL NUMBER {
418 if ($2 < MIN_HELLO_INTERVAL ||
419 $2 > MAX_HELLO_INTERVAL) {
420 yyerror("hello-interval out of range (%d-%d)",
421 MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
422 YYERROR;
423 }
424 defs->thello_interval = $2;
425 }
426 ;
427
428 tcpmd5 : TCP MD5SIG PASSWORD STRING {
429 size_t len;
430
431 $$ = calloc(1, sizeof(*$$));
432 if ($$ == NULL) {
433 free($4);
434 yyerror("unable to allocate md5 key");
435 YYERROR;
436 }
437
438 len = strlen($4);
439 if (len > sizeof($$->md5key)) {
440 free($$);
441 free($4);
442 yyerror("tcp md5sig password too long: "
443 "max %zu", sizeof($$->md5key));
444 YYERROR;
445 }
446
447 memcpy($$->md5key, $4, len);
448 $$->md5key_len = len;
449
450 free($4);
451 }
452 | TCP MD5SIG KEY STRING {
453 int len;
454
455 $$ = calloc(1, sizeof(*$$));
456 if ($$ == NULL) {
457 free($4);
458 yyerror("unable to allocate md5 key");
459 YYERROR;
460 }
461
462 len = str2key($$->md5key, $4, sizeof($$->md5key));
463 if (len == -1) {
464 free($$);
465 free($4);
466 yyerror("invalid hex string");
467 YYERROR;
468 }
469 if ((size_t)len > sizeof($$->md5key_len)) {
470 free($$);
471 free($4);
472 yyerror("tcp md5sig key too long: %d "
473 "max %zu", len, sizeof($$->md5key));
474 YYERROR;
475 }
476
477 $$->md5key_len = len;
478
479 free($4);
480 }
481 | NO TCP MD5SIG {
482 $$ = calloc(1, sizeof(*$$));
483 if ($$ == NULL) {
484 yyerror("unable to allocate no md5 key");
485 YYERROR;
486 }
487 $$->md5key_len = 0;
488 }
489 ;
490
491 optnbrprefix : STRING {
492 $$ = calloc(1, sizeof(*$$));
493 if ($$ == NULL) {
494 yyerror("unable to allocate auth");
495 free($1);
496 YYERROR;
497 }
498
499 $$->idlen = inet_net_pton(AF_INET, $1,
500 &$$->id, sizeof($$->id));
501 if ($$->idlen == -1) {
502 yyerror("%s: %s", $1, strerror(errno));
503 free($1);
504 YYERROR;
505 }
506 }
507 | /* empty */ {
508 $$ = NULL;
509 }
510 ;
511
512 auth : tcpmd5 optnbrprefix {
513 $$ = $1;
514 if ($2 != NULL) {
515 $$->id = $2->id;
516 $$->idlen = $2->idlen;
517 free($2);
518 } else {
519 $$->id.s_addr = 0;
520 $$->idlen = 0;
521 }
522 }
523 ;
524
525 nbr_opts : KEEPALIVE NUMBER {
526 if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) {
527 yyerror("keepalive out of range (%d-%d)",
528 MIN_KEEPALIVE, MAX_KEEPALIVE);
529 YYERROR;
530 }
531 nbrp->keepalive = $2;
532 nbrp->flags |= F_NBRP_KEEPALIVE;
533 }
534 | tcpmd5 {
535 /* this is syntactic sugar... */
536 $1->id = nbrp->lsr_id;
537 $1->idlen = 32;
538 LIST_INSERT_HEAD(&conf->auth_list, $1, entry);
539 }
540 | GTSMENABLE yesno {
541 nbrp->flags |= F_NBRP_GTSM;
542 nbrp->gtsm_enabled = $2;
543 }
544 | GTSMHOPS NUMBER {
545 if ($2 < 1 || $2 > 255) {
546 yyerror("invalid number of hops %lld", $2);
547 YYERROR;
548 }
549 nbrp->gtsm_hops = $2;
550 nbrp->flags |= F_NBRP_GTSM_HOPS;
551 }
552 ;
553
554 pw_defaults : STATUSTLV yesno {
555 if ($2 == 1)
556 defs->pwflags |= F_PW_STATUSTLV_CONF;
557 else
558 defs->pwflags &= ~F_PW_STATUSTLV_CONF;
559 }
560 | CONTROLWORD yesno {
561 if ($2 == 1)
562 defs->pwflags |= F_PW_CWORD_CONF;
563 else
564 defs->pwflags &= ~F_PW_CWORD_CONF;
565 }
566 ;
567
568 pwopts : PWID NUMBER {
569 if ($2 < MIN_PWID_ID ||
570 $2 > MAX_PWID_ID) {
571 yyerror("pw-id out of range (%d-%d)",
572 MIN_PWID_ID, MAX_PWID_ID);
573 YYERROR;
574 }
575
576 pw->pwid = $2;
577 }
578 | NEIGHBORID routerid {
579 pw->lsr_id = $2;
580 }
581 | NEIGHBORADDR STRING {
582 int family;
583 union ldpd_addr addr;
584
585 if (get_af_address($2, &family, &addr) == -1) {
586 yyerror("error parsing neighbor address");
587 free($2);
588 YYERROR;
589 }
590 free($2);
591 if (bad_addr(family, &addr)) {
592 yyerror("invalid neighbor address");
593 YYERROR;
594 }
595 if (family == AF_INET6 &&
596 IN6_IS_SCOPE_EMBED(&addr.v6)) {
597 yyerror("neighbor address can not be "
598 "link-local");
599 YYERROR;
600 }
601
602 pw->af = family;
603 pw->addr = addr;
604 }
605 | pw_defaults
606 ;
607
608 pseudowire : PSEUDOWIRE STRING {
609 struct kif *kif;
610
611 if ((kif = kif_findname($2)) == NULL) {
612 yyerror("unknown interface %s", $2);
613 free($2);
614 YYERROR;
615 }
616 free($2);
617
618 if (kif->if_type != IFT_MPLSTUNNEL &&
619 kmpw_find(kif->ifname) == -1) {
620 yyerror("unsupported interface type on "
621 "interface %s", kif->ifname);
622 YYERROR;
623 }
624
625 pw = conf_get_l2vpn_pw(l2vpn, kif);
626 if (pw == NULL)
627 YYERROR;
628
629 pwdefs = *defs;
630 defs = &pwdefs;
631 } pw_block {
632 struct l2vpn *l;
633 struct l2vpn_pw *p;
634
635 /* check for errors */
636 if (pw->pwid == 0) {
637 yyerror("missing pseudowire id");
638 YYERROR;
639 }
640 if (pw->lsr_id.s_addr == INADDR_ANY) {
641 yyerror("missing pseudowire neighbor-id");
642 YYERROR;
643 }
644 LIST_FOREACH(l, &conf->l2vpn_list, entry) {
645 LIST_FOREACH(p, &l->pw_list, entry) {
646 if (pw != p &&
647 pw->pwid == p->pwid &&
648 pw->af == p->af &&
649 pw->lsr_id.s_addr ==
650 p->lsr_id.s_addr) {
651 yyerror("pseudowire already "
652 "configured");
653 YYERROR;
654 }
655 }
656 }
657
658 /*
659 * If the neighbor address is not specified, use the
660 * neighbor id.
661 */
662 if (pw->af == AF_UNSPEC) {
663 pw->af = AF_INET;
664 pw->addr.v4 = pw->lsr_id;
665 }
666
667 pw->flags = defs->pwflags;
668 pw = NULL;
669 defs = &globaldefs;
670 }
671 ;
672
673 pw_block : '{' optnl pwopts_l '}'
674 | '{' optnl '}'
675 | /* nothing */
676 ;
677
678 pwopts_l : pwopts_l pwopts nl
679 | pwopts optnl
680 ;
681
682 l2vpnopts : PWTYPE pw_type {
683 l2vpn->pw_type = $2;
684 }
685 | MTU NUMBER {
686 if ($2 < MIN_L2VPN_MTU ||
687 $2 > MAX_L2VPN_MTU) {
688 yyerror("l2vpn mtu out of range (%d-%d)",
689 MIN_L2VPN_MTU, MAX_L2VPN_MTU);
690 YYERROR;
691 }
692 l2vpn->mtu = $2;
693 }
694 | pw_defaults
695 | BRIDGE STRING {
696 struct l2vpn *l;
697 struct kif *kif;
698
699 if ((kif = kif_findname($2)) == NULL) {
700 yyerror("unknown interface %s", $2);
701 free($2);
702 YYERROR;
703 }
704 free($2);
705
706 if (l2vpn->br_ifindex != 0) {
707 yyerror("bridge interface cannot be "
708 "redefined on l2vpn %s", l2vpn->name);
709 YYERROR;
710 }
711
712 if (kif->if_type != IFT_BRIDGE) {
713 yyerror("unsupported interface type on "
714 "interface %s", kif->ifname);
715 YYERROR;
716 }
717
718 LIST_FOREACH(l, &conf->l2vpn_list, entry) {
719 if (l->br_ifindex == kif->ifindex) {
720 yyerror("bridge %s is already being "
721 "used by l2vpn %s", kif->ifname,
722 l->name);
723 YYERROR;
724 }
725 }
726
727 l2vpn->br_ifindex = kif->ifindex;
728 strlcpy(l2vpn->br_ifname, kif->ifname,
729 sizeof(l2vpn->br_ifname));
730 }
731 | INTERFACE STRING {
732 struct kif *kif;
733 struct l2vpn_if *lif;
734
735 if ((kif = kif_findname($2)) == NULL) {
736 yyerror("unknown interface %s", $2);
737 free($2);
738 YYERROR;
739 }
740 free($2);
741
742 lif = conf_get_l2vpn_if(l2vpn, kif);
743 if (lif == NULL)
744 YYERROR;
745 }
746 | pseudowire
747 ;
748
749 optnl : '\n' optnl
750 |
751 ;
752
753 nl : '\n' optnl /* one newline or more */
754 ;
755
756 interface : INTERFACE STRING {
757 struct kif *kif;
758
759 if ((kif = kif_findname($2)) == NULL) {
760 yyerror("unknown interface %s", $2);
761 free($2);
762 YYERROR;
763 }
764 free($2);
765
766 iface = conf_get_if(kif);
767 if (iface == NULL)
768 YYERROR;
769
770 ia = iface_af_get(iface, af);
771 if (ia->enabled) {
772 yyerror("interface %s already configured for "
773 "address-family %s", kif->ifname,
774 af_name(af));
775 YYERROR;
776 }
777 ia->enabled = 1;
778
779 ifacedefs = *defs;
780 defs = &ifacedefs;
781 } interface_block {
782 ia->hello_holdtime = defs->lhello_holdtime;
783 ia->hello_interval = defs->lhello_interval;
784 iface = NULL;
785 defs = &afdefs;
786 }
787 ;
788
789 interface_block : '{' optnl interfaceopts_l '}'
790 | '{' optnl '}'
791 | /* nothing */
792 ;
793
794 interfaceopts_l : interfaceopts_l iface_defaults nl
795 | iface_defaults optnl
796 ;
797
798 tneighbor : TNEIGHBOR STRING {
799 union ldpd_addr addr;
800
801 if (get_address($2, &addr) == -1) {
802 yyerror("error parsing targeted-neighbor "
803 "address");
804 free($2);
805 YYERROR;
806 }
807 free($2);
808 if (bad_addr(af, &addr)) {
809 yyerror("invalid targeted-neighbor address");
810 YYERROR;
811 }
812 if (af == AF_INET6 &&
813 IN6_IS_SCOPE_EMBED(&addr.v6)) {
814 yyerror("targeted-neighbor address can not be "
815 "link-local");
816 YYERROR;
817 }
818
819 tnbr = conf_get_tnbr(&addr);
820 if (tnbr == NULL)
821 YYERROR;
822
823 tnbrdefs = *defs;
824 defs = &tnbrdefs;
825 } tneighbor_block {
826 tnbr->hello_holdtime = defs->thello_holdtime;
827 tnbr->hello_interval = defs->thello_interval;
828 tnbr = NULL;
829 defs = &afdefs;
830 }
831 ;
832
833 tneighbor_block : '{' optnl tneighboropts_l '}'
834 | '{' optnl '}'
835 | /* nothing */
836 ;
837
838 tneighboropts_l : tneighboropts_l tnbr_defaults nl
839 | tnbr_defaults optnl
840 ;
841
842 neighbor : NEIGHBOR routerid {
843 nbrp = conf_get_nbrp($2);
844 if (nbrp == NULL)
845 YYERROR;
846 } neighbor_block {
847 nbrp = NULL;
848 }
849 ;
850
851 neighbor_block : '{' optnl neighboropts_l '}'
852 | '{' optnl '}'
853 | /* nothing */
854 ;
855
856 neighboropts_l : neighboropts_l nbr_opts nl
857 | nbr_opts optnl
858 ;
859
860 l2vpn : L2VPN STRING TYPE l2vpn_type {
861 l2vpn = conf_get_l2vpn($2);
862 if (l2vpn == NULL)
863 YYERROR;
864 l2vpn->type = $4;
865 } l2vpn_block {
866 l2vpn = NULL;
867 }
868 ;
869
870 l2vpn_block : '{' optnl l2vpnopts_l '}'
871 | '{' optnl '}'
872 | /* nothing */
873 ;
874
875 l2vpnopts_l : l2vpnopts_l l2vpnopts nl
876 | l2vpnopts optnl
877 ;
878
879 %%
880
881 struct keywords {
882 const char *k_name;
883 int k_val;
884 };
885
886 static int
yyerror(const char * fmt,...)887 yyerror(const char *fmt, ...)
888 {
889 va_list ap;
890 char *msg;
891
892 file->errors++;
893 va_start(ap, fmt);
894 if (vasprintf(&msg, fmt, ap) == -1)
895 fatalx("yyerror vasprintf");
896 va_end(ap);
897 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
898 free(msg);
899 return (0);
900 }
901
902 static int
kw_cmp(const void * k,const void * e)903 kw_cmp(const void *k, const void *e)
904 {
905 return (strcmp(k, ((const struct keywords *)e)->k_name));
906 }
907
908 static int
lookup(char * s)909 lookup(char *s)
910 {
911 /* this has to be sorted always */
912 static const struct keywords keywords[] = {
913 {"address-family", AF},
914 {"bridge", BRIDGE},
915 {"control-word", CONTROLWORD},
916 {"ds-cisco-interop", DSCISCOINTEROP},
917 {"ethernet", ETHERNET},
918 {"ethernet-tagged", ETHERNETTAGGED},
919 {"explicit-null", EXPNULL},
920 {"fib-update", FIBUPDATE},
921 {"gtsm-enable", GTSMENABLE},
922 {"gtsm-hops", GTSMHOPS},
923 {"include", INCLUDE},
924 {"inet", INET},
925 {"inet6", INET6},
926 {"interface", INTERFACE},
927 {"ipv4", IPV4},
928 {"ipv6", IPV6},
929 {"keepalive", KEEPALIVE},
930 {"key", KEY},
931 {"l2vpn", L2VPN},
932 {"link-hello-holdtime", LHELLOHOLDTIME},
933 {"link-hello-interval", LHELLOINTERVAL},
934 {"md5sig", MD5SIG},
935 {"mtu", MTU},
936 {"neighbor", NEIGHBOR},
937 {"neighbor-addr", NEIGHBORADDR},
938 {"neighbor-id", NEIGHBORID},
939 {"no", NO},
940 {"password", PASSWORD},
941 {"pseudowire", PSEUDOWIRE},
942 {"pw-id", PWID},
943 {"pw-type", PWTYPE},
944 {"rdomain", RDOMAIN},
945 {"router-id", ROUTERID},
946 {"status-tlv", STATUSTLV},
947 {"targeted-hello-accept", THELLOACCEPT},
948 {"targeted-hello-holdtime", THELLOHOLDTIME},
949 {"targeted-hello-interval", THELLOINTERVAL},
950 {"targeted-neighbor", TNEIGHBOR},
951 {"tcp", TCP},
952 {"transport-address", TRANSADDRESS},
953 {"transport-preference", TRANSPREFERENCE},
954 {"type", TYPE},
955 {"vpls", VPLS},
956 {"yes", YES}
957 };
958 const struct keywords *p;
959
960 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
961 sizeof(keywords[0]), kw_cmp);
962
963 if (p)
964 return (p->k_val);
965 else
966 return (STRING);
967 }
968
969 #define START_EXPAND 1
970 #define DONE_EXPAND 2
971
972 static int expanding;
973
974 int
igetc(void)975 igetc(void)
976 {
977 int c;
978
979 while (1) {
980 if (file->ungetpos > 0)
981 c = file->ungetbuf[--file->ungetpos];
982 else
983 c = getc(file->stream);
984
985 if (c == START_EXPAND)
986 expanding = 1;
987 else if (c == DONE_EXPAND)
988 expanding = 0;
989 else
990 break;
991 }
992 return (c);
993 }
994
995 static int
lgetc(int quotec)996 lgetc(int quotec)
997 {
998 int c, next;
999
1000 if (quotec) {
1001 if ((c = igetc()) == EOF) {
1002 yyerror("reached end of file while parsing "
1003 "quoted string");
1004 if (file == topfile || popfile() == EOF)
1005 return (EOF);
1006 return (quotec);
1007 }
1008 return (c);
1009 }
1010
1011 while ((c = igetc()) == '\\') {
1012 next = igetc();
1013 if (next != '\n') {
1014 c = next;
1015 break;
1016 }
1017 yylval.lineno = file->lineno;
1018 file->lineno++;
1019 }
1020
1021 if (c == EOF) {
1022 /*
1023 * Fake EOL when hit EOF for the first time. This gets line
1024 * count right if last line in included file is syntactically
1025 * invalid and has no newline.
1026 */
1027 if (file->eof_reached == 0) {
1028 file->eof_reached = 1;
1029 return ('\n');
1030 }
1031 while (c == EOF) {
1032 if (file == topfile || popfile() == EOF)
1033 return (EOF);
1034 c = igetc();
1035 }
1036 }
1037 return (c);
1038 }
1039
1040 void
lungetc(int c)1041 lungetc(int c)
1042 {
1043 if (c == EOF)
1044 return;
1045
1046 if (file->ungetpos >= file->ungetsize) {
1047 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
1048 if (p == NULL)
1049 err(1, "%s", __func__);
1050 file->ungetbuf = p;
1051 file->ungetsize *= 2;
1052 }
1053 file->ungetbuf[file->ungetpos++] = c;
1054 }
1055
1056 static int
findeol(void)1057 findeol(void)
1058 {
1059 int c;
1060
1061 /* skip to either EOF or the first real EOL */
1062 while (1) {
1063 c = lgetc(0);
1064 if (c == '\n') {
1065 file->lineno++;
1066 break;
1067 }
1068 if (c == EOF)
1069 break;
1070 }
1071 return (ERROR);
1072 }
1073
1074 static int
yylex(void)1075 yylex(void)
1076 {
1077 char buf[8096];
1078 char *p, *val;
1079 int quotec, next, c;
1080 int token;
1081
1082 top:
1083 p = buf;
1084 while ((c = lgetc(0)) == ' ' || c == '\t')
1085 ; /* nothing */
1086
1087 yylval.lineno = file->lineno;
1088 if (c == '#')
1089 while ((c = lgetc(0)) != '\n' && c != EOF)
1090 ; /* nothing */
1091 if (c == '$' && !expanding) {
1092 while (1) {
1093 if ((c = lgetc(0)) == EOF)
1094 return (0);
1095
1096 if (p + 1 >= buf + sizeof(buf) - 1) {
1097 yyerror("string too long");
1098 return (findeol());
1099 }
1100 if (isalnum(c) || c == '_') {
1101 *p++ = c;
1102 continue;
1103 }
1104 *p = '\0';
1105 lungetc(c);
1106 break;
1107 }
1108 val = symget(buf);
1109 if (val == NULL) {
1110 yyerror("macro '%s' not defined", buf);
1111 return (findeol());
1112 }
1113 p = val + strlen(val) - 1;
1114 lungetc(DONE_EXPAND);
1115 while (p >= val) {
1116 lungetc((unsigned char)*p);
1117 p--;
1118 }
1119 lungetc(START_EXPAND);
1120 goto top;
1121 }
1122
1123 switch (c) {
1124 case '\'':
1125 case '"':
1126 quotec = c;
1127 while (1) {
1128 if ((c = lgetc(quotec)) == EOF)
1129 return (0);
1130 if (c == '\n') {
1131 file->lineno++;
1132 continue;
1133 } else if (c == '\\') {
1134 if ((next = lgetc(quotec)) == EOF)
1135 return (0);
1136 if (next == quotec || next == ' ' ||
1137 next == '\t')
1138 c = next;
1139 else if (next == '\n') {
1140 file->lineno++;
1141 continue;
1142 } else
1143 lungetc(next);
1144 } else if (c == quotec) {
1145 *p = '\0';
1146 break;
1147 } else if (c == '\0') {
1148 yyerror("syntax error");
1149 return (findeol());
1150 }
1151 if (p + 1 >= buf + sizeof(buf) - 1) {
1152 yyerror("string too long");
1153 return (findeol());
1154 }
1155 *p++ = c;
1156 }
1157 yylval.v.string = strdup(buf);
1158 if (yylval.v.string == NULL)
1159 err(1, "%s", __func__);
1160 return (STRING);
1161 }
1162
1163 #define allowed_to_end_number(x) \
1164 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
1165
1166 if (c == '-' || isdigit(c)) {
1167 do {
1168 *p++ = c;
1169 if ((size_t)(p-buf) >= sizeof(buf)) {
1170 yyerror("string too long");
1171 return (findeol());
1172 }
1173 } while ((c = lgetc(0)) != EOF && isdigit(c));
1174 lungetc(c);
1175 if (p == buf + 1 && buf[0] == '-')
1176 goto nodigits;
1177 if (c == EOF || allowed_to_end_number(c)) {
1178 const char *errstr = NULL;
1179
1180 *p = '\0';
1181 yylval.v.number = strtonum(buf, LLONG_MIN,
1182 LLONG_MAX, &errstr);
1183 if (errstr) {
1184 yyerror("\"%s\" invalid number: %s",
1185 buf, errstr);
1186 return (findeol());
1187 }
1188 return (NUMBER);
1189 } else {
1190 nodigits:
1191 while (p > buf + 1)
1192 lungetc((unsigned char)*--p);
1193 c = (unsigned char)*--p;
1194 if (c == '-')
1195 return (c);
1196 }
1197 }
1198
1199 #define allowed_in_string(x) \
1200 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1201 x != '{' && x != '}' && \
1202 x != '!' && x != '=' && x != '#' && \
1203 x != ','))
1204
1205 if (isalnum(c) || c == ':' || c == '_') {
1206 do {
1207 *p++ = c;
1208 if ((size_t)(p-buf) >= sizeof(buf)) {
1209 yyerror("string too long");
1210 return (findeol());
1211 }
1212 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1213 lungetc(c);
1214 *p = '\0';
1215 if ((token = lookup(buf)) == STRING)
1216 if ((yylval.v.string = strdup(buf)) == NULL)
1217 err(1, "%s", __func__);
1218 return (token);
1219 }
1220 if (c == '\n') {
1221 yylval.lineno = file->lineno;
1222 file->lineno++;
1223 }
1224 if (c == EOF)
1225 return (0);
1226 return (c);
1227 }
1228
1229 static int
check_file_secrecy(int fd,const char * fname)1230 check_file_secrecy(int fd, const char *fname)
1231 {
1232 struct stat st;
1233
1234 if (fstat(fd, &st)) {
1235 log_warn("cannot stat %s", fname);
1236 return (-1);
1237 }
1238 if (st.st_uid != 0 && st.st_uid != getuid()) {
1239 log_warnx("%s: owner not root or current user", fname);
1240 return (-1);
1241 }
1242 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1243 log_warnx("%s: group writable or world read/writable", fname);
1244 return (-1);
1245 }
1246 return (0);
1247 }
1248
1249 static struct file *
pushfile(const char * name,int secret)1250 pushfile(const char *name, int secret)
1251 {
1252 struct file *nfile;
1253
1254 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1255 log_warn("%s", __func__);
1256 return (NULL);
1257 }
1258 if ((nfile->name = strdup(name)) == NULL) {
1259 log_warn("%s", __func__);
1260 free(nfile);
1261 return (NULL);
1262 }
1263 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1264 log_warn("%s: %s", __func__, nfile->name);
1265 free(nfile->name);
1266 free(nfile);
1267 return (NULL);
1268 } else if (secret &&
1269 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1270 fclose(nfile->stream);
1271 free(nfile->name);
1272 free(nfile);
1273 return (NULL);
1274 }
1275 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
1276 nfile->ungetsize = 16;
1277 nfile->ungetbuf = malloc(nfile->ungetsize);
1278 if (nfile->ungetbuf == NULL) {
1279 log_warn("%s", __func__);
1280 fclose(nfile->stream);
1281 free(nfile->name);
1282 free(nfile);
1283 return (NULL);
1284 }
1285 TAILQ_INSERT_TAIL(&files, nfile, entry);
1286 return (nfile);
1287 }
1288
1289 static int
popfile(void)1290 popfile(void)
1291 {
1292 struct file *prev;
1293
1294 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1295 prev->errors += file->errors;
1296
1297 TAILQ_REMOVE(&files, file, entry);
1298 fclose(file->stream);
1299 free(file->name);
1300 free(file->ungetbuf);
1301 free(file);
1302 file = prev;
1303 return (file ? 0 : EOF);
1304 }
1305
1306 struct ldpd_conf *
parse_config(char * filename)1307 parse_config(char *filename)
1308 {
1309 struct sym *sym, *next;
1310
1311 conf = config_new_empty();
1312 conf->rdomain = 0;
1313 conf->trans_pref = DUAL_STACK_LDPOV6;
1314
1315 defs = &globaldefs;
1316 defs->keepalive = DEFAULT_KEEPALIVE;
1317 defs->lhello_holdtime = LINK_DFLT_HOLDTIME;
1318 defs->lhello_interval = DEFAULT_HELLO_INTERVAL;
1319 defs->thello_holdtime = TARGETED_DFLT_HOLDTIME;
1320 defs->thello_interval = DEFAULT_HELLO_INTERVAL;
1321 defs->pwflags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF;
1322
1323 if ((file = pushfile(filename,
1324 !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) {
1325 free(conf);
1326 return (NULL);
1327 }
1328 topfile = file;
1329
1330 yyparse();
1331 errors = file->errors;
1332 popfile();
1333
1334 /* Free macros and check which have not been used. */
1335 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1336 if ((global.cmd_opts & LDPD_OPT_VERBOSE2) && !sym->used)
1337 fprintf(stderr, "warning: macro '%s' not "
1338 "used\n", sym->nam);
1339 if (!sym->persist) {
1340 free(sym->nam);
1341 free(sym->val);
1342 TAILQ_REMOVE(&symhead, sym, entry);
1343 free(sym);
1344 }
1345 }
1346
1347 /* check that all interfaces belong to the configured rdomain */
1348 errors += conf_check_rdomain(conf->rdomain);
1349
1350 /* free global config defaults */
1351 if (errors) {
1352 clear_config(conf);
1353 return (NULL);
1354 }
1355
1356 if (conf->rtr_id.s_addr == INADDR_ANY)
1357 conf->rtr_id.s_addr = get_rtr_id();
1358
1359 /* if the ipv4 transport-address is not set, use the router-id */
1360 if ((conf->ipv4.flags & F_LDPD_AF_ENABLED) &&
1361 conf->ipv4.trans_addr.v4.s_addr == INADDR_ANY)
1362 conf->ipv4.trans_addr.v4 = conf->rtr_id;
1363
1364 return (conf);
1365 }
1366
1367 static int
symset(const char * nam,const char * val,int persist)1368 symset(const char *nam, const char *val, int persist)
1369 {
1370 struct sym *sym;
1371
1372 TAILQ_FOREACH(sym, &symhead, entry) {
1373 if (strcmp(nam, sym->nam) == 0)
1374 break;
1375 }
1376
1377 if (sym != NULL) {
1378 if (sym->persist == 1)
1379 return (0);
1380 else {
1381 free(sym->nam);
1382 free(sym->val);
1383 TAILQ_REMOVE(&symhead, sym, entry);
1384 free(sym);
1385 }
1386 }
1387 if ((sym = calloc(1, sizeof(*sym))) == NULL)
1388 return (-1);
1389
1390 sym->nam = strdup(nam);
1391 if (sym->nam == NULL) {
1392 free(sym);
1393 return (-1);
1394 }
1395 sym->val = strdup(val);
1396 if (sym->val == NULL) {
1397 free(sym->nam);
1398 free(sym);
1399 return (-1);
1400 }
1401 sym->used = 0;
1402 sym->persist = persist;
1403 TAILQ_INSERT_TAIL(&symhead, sym, entry);
1404 return (0);
1405 }
1406
1407 int
cmdline_symset(char * s)1408 cmdline_symset(char *s)
1409 {
1410 char *sym, *val;
1411 int ret;
1412
1413 if ((val = strrchr(s, '=')) == NULL)
1414 return (-1);
1415 sym = strndup(s, val - s);
1416 if (sym == NULL)
1417 errx(1, "%s: strndup", __func__);
1418 ret = symset(sym, val + 1, 1);
1419 free(sym);
1420
1421 return (ret);
1422 }
1423
1424 static char *
symget(const char * nam)1425 symget(const char *nam)
1426 {
1427 struct sym *sym;
1428
1429 TAILQ_FOREACH(sym, &symhead, entry) {
1430 if (strcmp(nam, sym->nam) == 0) {
1431 sym->used = 1;
1432 return (sym->val);
1433 }
1434 }
1435 return (NULL);
1436 }
1437
1438 static struct iface *
conf_get_if(struct kif * kif)1439 conf_get_if(struct kif *kif)
1440 {
1441 struct iface *i;
1442 struct l2vpn *l;
1443
1444 if (kif->if_type == IFT_LOOP ||
1445 kif->if_type == IFT_CARP ||
1446 kif->if_type == IFT_BRIDGE ||
1447 kif->if_type == IFT_MPLSTUNNEL) {
1448 yyerror("unsupported interface type on interface %s",
1449 kif->ifname);
1450 return (NULL);
1451 }
1452
1453 LIST_FOREACH(l, &conf->l2vpn_list, entry)
1454 if (l2vpn_if_find(l, kif->ifindex)) {
1455 yyerror("interface %s already configured under "
1456 "l2vpn %s", kif->ifname, l->name);
1457 return (NULL);
1458 }
1459
1460 LIST_FOREACH(i, &conf->iface_list, entry)
1461 if (i->ifindex == kif->ifindex)
1462 return (i);
1463
1464 i = if_new(kif);
1465 LIST_INSERT_HEAD(&conf->iface_list, i, entry);
1466 return (i);
1467 }
1468
1469 static struct tnbr *
conf_get_tnbr(union ldpd_addr * addr)1470 conf_get_tnbr(union ldpd_addr *addr)
1471 {
1472 struct tnbr *t;
1473
1474 t = tnbr_find(conf, af, addr);
1475 if (t) {
1476 yyerror("targeted neighbor %s already configured",
1477 log_addr(af, addr));
1478 return (NULL);
1479 }
1480
1481 t = tnbr_new(conf, af, addr);
1482 t->flags |= F_TNBR_CONFIGURED;
1483 LIST_INSERT_HEAD(&conf->tnbr_list, t, entry);
1484 return (t);
1485 }
1486
1487 static struct nbr_params *
conf_get_nbrp(struct in_addr lsr_id)1488 conf_get_nbrp(struct in_addr lsr_id)
1489 {
1490 struct nbr_params *n;
1491
1492 LIST_FOREACH(n, &conf->nbrp_list, entry) {
1493 if (n->lsr_id.s_addr == lsr_id.s_addr) {
1494 yyerror("neighbor %s already configured",
1495 inet_ntoa(lsr_id));
1496 return (NULL);
1497 }
1498 }
1499
1500 n = nbr_params_new(lsr_id);
1501 LIST_INSERT_HEAD(&conf->nbrp_list, n, entry);
1502 return (n);
1503 }
1504
1505 static struct l2vpn *
conf_get_l2vpn(char * name)1506 conf_get_l2vpn(char *name)
1507 {
1508 struct l2vpn *l;
1509
1510 if (l2vpn_find(conf, name)) {
1511 yyerror("l2vpn %s already configured", name);
1512 return (NULL);
1513 }
1514
1515 l = l2vpn_new(name);
1516 LIST_INSERT_HEAD(&conf->l2vpn_list, l, entry);
1517 return (l);
1518 }
1519
1520 static struct l2vpn_if *
conf_get_l2vpn_if(struct l2vpn * l,struct kif * kif)1521 conf_get_l2vpn_if(struct l2vpn *l, struct kif *kif)
1522 {
1523 struct iface *i;
1524 struct l2vpn *ltmp;
1525 struct l2vpn_if *f;
1526
1527 if (kif->if_type == IFT_LOOP ||
1528 kif->if_type == IFT_CARP ||
1529 kif->if_type == IFT_BRIDGE ||
1530 kif->if_type == IFT_MPLSTUNNEL) {
1531 yyerror("unsupported interface type on interface %s",
1532 kif->ifname);
1533 return (NULL);
1534 }
1535
1536 LIST_FOREACH(ltmp, &conf->l2vpn_list, entry)
1537 if (l2vpn_if_find(ltmp, kif->ifindex)) {
1538 yyerror("interface %s already configured under "
1539 "l2vpn %s", kif->ifname, ltmp->name);
1540 return (NULL);
1541 }
1542
1543 LIST_FOREACH(i, &conf->iface_list, entry) {
1544 if (i->ifindex == kif->ifindex) {
1545 yyerror("interface %s already configured",
1546 kif->ifname);
1547 return (NULL);
1548 }
1549 }
1550
1551 f = l2vpn_if_new(l, kif);
1552 LIST_INSERT_HEAD(&l2vpn->if_list, f, entry);
1553 return (f);
1554 }
1555
1556 static struct l2vpn_pw *
conf_get_l2vpn_pw(struct l2vpn * l,struct kif * kif)1557 conf_get_l2vpn_pw(struct l2vpn *l, struct kif *kif)
1558 {
1559 struct l2vpn *ltmp;
1560 struct l2vpn_pw *p;
1561
1562 LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) {
1563 if (l2vpn_pw_find(ltmp, kif->ifindex)) {
1564 yyerror("pseudowire %s is already being "
1565 "used by l2vpn %s", kif->ifname, ltmp->name);
1566 return (NULL);
1567 }
1568 }
1569
1570 p = l2vpn_pw_new(l, kif);
1571 LIST_INSERT_HEAD(&l2vpn->pw_list, p, entry);
1572 return (p);
1573 }
1574
1575 int
conf_check_rdomain(unsigned int rdomain)1576 conf_check_rdomain(unsigned int rdomain)
1577 {
1578 struct iface *i;
1579 int errs = 0;
1580
1581 LIST_FOREACH(i, &conf->iface_list, entry) {
1582 if (i->rdomain != rdomain) {
1583 logit(LOG_CRIT, "interface %s not in rdomain %u",
1584 i->name, rdomain);
1585 errs++;
1586 }
1587 }
1588
1589 return (errs);
1590 }
1591
1592 static void
clear_config(struct ldpd_conf * xconf)1593 clear_config(struct ldpd_conf *xconf)
1594 {
1595 struct iface *i;
1596 struct tnbr *t;
1597 struct nbr_params *n;
1598 struct l2vpn *l;
1599 struct l2vpn_if *f;
1600 struct l2vpn_pw *p;
1601
1602 while ((i = LIST_FIRST(&xconf->iface_list)) != NULL) {
1603 LIST_REMOVE(i, entry);
1604 free(i);
1605 }
1606
1607 while ((t = LIST_FIRST(&xconf->tnbr_list)) != NULL) {
1608 LIST_REMOVE(t, entry);
1609 free(t);
1610 }
1611
1612 while ((n = LIST_FIRST(&xconf->nbrp_list)) != NULL) {
1613 LIST_REMOVE(n, entry);
1614 free(n);
1615 }
1616
1617 while ((l = LIST_FIRST(&xconf->l2vpn_list)) != NULL) {
1618 while ((f = LIST_FIRST(&l->if_list)) != NULL) {
1619 LIST_REMOVE(f, entry);
1620 free(f);
1621 }
1622 while ((p = LIST_FIRST(&l->pw_list)) != NULL) {
1623 LIST_REMOVE(p, entry);
1624 free(p);
1625 }
1626 LIST_REMOVE(l, entry);
1627 free(l);
1628 }
1629
1630 free(xconf);
1631 }
1632
1633 static uint32_t
get_rtr_id(void)1634 get_rtr_id(void)
1635 {
1636 struct ifaddrs *ifap, *ifa;
1637 uint32_t ip = 0, cur, localnet;
1638
1639 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1640
1641 if (getifaddrs(&ifap) == -1) {
1642 log_warn("getifaddrs");
1643 return (0);
1644 }
1645
1646 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1647 if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1648 continue;
1649 if (ifa->ifa_addr->sa_family != AF_INET)
1650 continue;
1651 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1652 if ((cur & localnet) == localnet) /* skip 127/8 */
1653 continue;
1654 if (ntohl(cur) < ntohl(ip) || ip == 0)
1655 ip = cur;
1656 }
1657 freeifaddrs(ifap);
1658
1659 return (ip);
1660 }
1661
1662 static int
get_address(const char * s,union ldpd_addr * addr)1663 get_address(const char *s, union ldpd_addr *addr)
1664 {
1665 switch (af) {
1666 case AF_INET:
1667 if (inet_pton(AF_INET, s, &addr->v4) != 1)
1668 return (-1);
1669 break;
1670 case AF_INET6:
1671 if (inet_pton(AF_INET6, s, &addr->v6) != 1)
1672 return (-1);
1673 break;
1674 default:
1675 return (-1);
1676 }
1677
1678 return (0);
1679 }
1680
1681 static int
get_af_address(const char * s,int * family,union ldpd_addr * addr)1682 get_af_address(const char *s, int *family, union ldpd_addr *addr)
1683 {
1684 if (inet_pton(AF_INET, s, &addr->v4) == 1) {
1685 *family = AF_INET;
1686 return (0);
1687 }
1688
1689 if (inet_pton(AF_INET6, s, &addr->v6) == 1) {
1690 *family = AF_INET6;
1691 return (0);
1692 }
1693
1694 return (-1);
1695 }
1696
1697 static int
hexchar(int ch)1698 hexchar(int ch)
1699 {
1700 if (ch >= '0' && ch <= '9')
1701 return (ch - '0');
1702 if (ch >= 'a' && ch <= 'f')
1703 return (ch - 'a');
1704 if (ch >= 'A' && ch <= 'F')
1705 return (ch - 'A');
1706
1707 return (-1);
1708 }
1709
1710 static int
str2key(char * dst,const char * src,int dstlen)1711 str2key(char *dst, const char *src, int dstlen)
1712 {
1713 int i = 0;
1714 int digit;
1715
1716 while (*src != '\0') {
1717 digit = hexchar(*src);
1718 if (digit == -1)
1719 return (-1);
1720
1721 if (i < dstlen)
1722 *dst = digit << 4;
1723
1724 src++;
1725 if (*src == '\0')
1726 return (-1);
1727 digit = hexchar(*src);
1728 if (digit == -1)
1729 return (-1);
1730
1731 if (i < dstlen)
1732 *dst |= digit;
1733
1734 src++;
1735 i++;
1736 }
1737
1738 return (i);
1739 }
1740