1*f885c9d9Sflorian /* $OpenBSD: parse.y,v 1.74 2024/08/22 08:17:54 florian Exp $ */ 2ab0c2486Smichele 3ab0c2486Smichele /* 45dc9330aSrenato * Copyright (c) 2013, 2015, 2016 Renato Westphal <renato@openbsd.org> 5ab0c2486Smichele * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 6ab0c2486Smichele * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 7ab0c2486Smichele * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 8ab0c2486Smichele * Copyright (c) 2001 Markus Friedl. All rights reserved. 9ab0c2486Smichele * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 10ab0c2486Smichele * Copyright (c) 2001 Theo de Raadt. All rights reserved. 11ab0c2486Smichele * 12ab0c2486Smichele * Permission to use, copy, modify, and distribute this software for any 13ab0c2486Smichele * purpose with or without fee is hereby granted, provided that the above 14ab0c2486Smichele * copyright notice and this permission notice appear in all copies. 15ab0c2486Smichele * 16ab0c2486Smichele * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17ab0c2486Smichele * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18ab0c2486Smichele * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19ab0c2486Smichele * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20ab0c2486Smichele * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21ab0c2486Smichele * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22ab0c2486Smichele * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23ab0c2486Smichele */ 24ab0c2486Smichele 25ab0c2486Smichele %{ 26ab0c2486Smichele #include <sys/stat.h> 277ee91690Sdlg #include <sys/types.h> 287ee91690Sdlg #include <sys/socket.h> 29ab0c2486Smichele #include <arpa/inet.h> 30ab0c2486Smichele #include <ctype.h> 31ab0c2486Smichele #include <err.h> 32ab0c2486Smichele #include <unistd.h> 33ab0c2486Smichele #include <ifaddrs.h> 34af2666a1Sclaudio #include <net/if_types.h> 35ab0c2486Smichele #include <limits.h> 36ab0c2486Smichele #include <stdio.h> 374a1d3eaaSsthen #include <syslog.h> 387ee91690Sdlg #include <errno.h> 397ee91690Sdlg #include <netdb.h> 40ab0c2486Smichele 41ab0c2486Smichele #include "ldpd.h" 42ab0c2486Smichele #include "ldpe.h" 435411bbb6Srenato #include "lde.h" 44ab0c2486Smichele #include "log.h" 45ab0c2486Smichele 46c28a25a1Srenato struct file { 47ab0c2486Smichele TAILQ_ENTRY(file) entry; 48ab0c2486Smichele FILE *stream; 49ab0c2486Smichele char *name; 506dbe86f5Sdenis size_t ungetpos; 516dbe86f5Sdenis size_t ungetsize; 526dbe86f5Sdenis u_char *ungetbuf; 536dbe86f5Sdenis int eof_reached; 54ab0c2486Smichele int lineno; 55ab0c2486Smichele int errors; 56c28a25a1Srenato }; 57c28a25a1Srenato TAILQ_HEAD(files, file); 58ab0c2486Smichele 59ab0c2486Smichele struct sym { 60ab0c2486Smichele TAILQ_ENTRY(sym) entry; 61ab0c2486Smichele int used; 62ab0c2486Smichele int persist; 63ab0c2486Smichele char *nam; 64ab0c2486Smichele char *val; 65ab0c2486Smichele }; 66c28a25a1Srenato TAILQ_HEAD(symhead, sym); 67ab0c2486Smichele 68ab0c2486Smichele struct config_defaults { 69a8c39dc0Srenato uint16_t keepalive; 703de94509Srenato uint16_t lhello_holdtime; 713de94509Srenato uint16_t lhello_interval; 723de94509Srenato uint16_t thello_holdtime; 733de94509Srenato uint16_t thello_interval; 74a8c39dc0Srenato union ldpd_addr trans_addr; 75a8c39dc0Srenato int afflags; 763de94509Srenato uint8_t pwflags; 77ab0c2486Smichele }; 78ab0c2486Smichele 79ab0c2486Smichele typedef struct { 80ab0c2486Smichele union { 81ab0c2486Smichele int64_t number; 82ab0c2486Smichele char *string; 8309ad9801Sdlg struct in_addr routerid; 847ee91690Sdlg struct ldp_auth *auth; 85ab0c2486Smichele } v; 86ab0c2486Smichele int lineno; 87ab0c2486Smichele } YYSTYPE; 88ab0c2486Smichele 89c28a25a1Srenato static int yyerror(const char *, ...) 90c28a25a1Srenato __attribute__((__format__ (printf, 1, 2))) 91c28a25a1Srenato __attribute__((__nonnull__ (1))); 92c28a25a1Srenato static int kw_cmp(const void *, const void *); 93c28a25a1Srenato static int lookup(char *); 946dbe86f5Sdenis static int igetc(void); 95c28a25a1Srenato static int lgetc(int); 966dbe86f5Sdenis void lungetc(int); 97c28a25a1Srenato static int findeol(void); 98c28a25a1Srenato static int yylex(void); 99c28a25a1Srenato static int check_file_secrecy(int, const char *); 100c28a25a1Srenato static struct file *pushfile(const char *, int); 101c28a25a1Srenato static int popfile(void); 102c28a25a1Srenato static int yyparse(void); 103c28a25a1Srenato static int symset(const char *, const char *, int); 104c28a25a1Srenato static char *symget(const char *); 105c28a25a1Srenato static struct iface *conf_get_if(struct kif *); 106c28a25a1Srenato static struct tnbr *conf_get_tnbr(union ldpd_addr *); 107c28a25a1Srenato static struct nbr_params *conf_get_nbrp(struct in_addr); 108c28a25a1Srenato static struct l2vpn *conf_get_l2vpn(char *); 109c28a25a1Srenato static struct l2vpn_if *conf_get_l2vpn_if(struct l2vpn *, struct kif *); 110c28a25a1Srenato static struct l2vpn_pw *conf_get_l2vpn_pw(struct l2vpn *, struct kif *); 1118622bd53Srenato int conf_check_rdomain(unsigned int); 112c28a25a1Srenato static void clear_config(struct ldpd_conf *xconf); 113c28a25a1Srenato static uint32_t get_rtr_id(void); 114c28a25a1Srenato static int get_address(const char *, union ldpd_addr *); 115c28a25a1Srenato static int get_af_address(const char *, int *, union ldpd_addr *); 1167ee91690Sdlg static int str2key(char *, const char *, int); 117c28a25a1Srenato 118c28a25a1Srenato static struct file *file, *topfile; 119c28a25a1Srenato static struct files files = TAILQ_HEAD_INITIALIZER(files); 120c28a25a1Srenato static struct symhead symhead = TAILQ_HEAD_INITIALIZER(symhead); 121c28a25a1Srenato static struct ldpd_conf *conf; 122c28a25a1Srenato static int errors; 123c28a25a1Srenato 124c28a25a1Srenato static int af; 125c28a25a1Srenato static struct ldpd_af_conf *af_conf; 126c28a25a1Srenato static struct iface *iface; 127c28a25a1Srenato static struct iface_af *ia; 128c28a25a1Srenato static struct tnbr *tnbr; 129c28a25a1Srenato static struct nbr_params *nbrp; 130c28a25a1Srenato static struct l2vpn *l2vpn; 131c28a25a1Srenato static struct l2vpn_pw *pw; 132c28a25a1Srenato 133c28a25a1Srenato static struct config_defaults globaldefs; 134c28a25a1Srenato static struct config_defaults afdefs; 135c28a25a1Srenato static struct config_defaults ifacedefs; 136c28a25a1Srenato static struct config_defaults tnbrdefs; 137c28a25a1Srenato static struct config_defaults pwdefs; 138c28a25a1Srenato static struct config_defaults *defs; 139c28a25a1Srenato 140ab0c2486Smichele %} 141ab0c2486Smichele 1428622bd53Srenato %token INTERFACE TNEIGHBOR ROUTERID FIBUPDATE RDOMAIN EXPNULL 14383dcf737Sclaudio %token LHELLOHOLDTIME LHELLOINTERVAL 14483dcf737Sclaudio %token THELLOHOLDTIME THELLOINTERVAL 1457ee91690Sdlg %token THELLOACCEPT AF IPV4 IPV6 INET INET6 GTSMENABLE GTSMHOPS 146a8c39dc0Srenato %token KEEPALIVE TRANSADDRESS TRANSPREFERENCE DSCISCOINTEROP 1477ee91690Sdlg %token NEIGHBOR 1487ee91690Sdlg %token TCP MD5SIG PASSWORD KEY 1496399cec1Srenato %token L2VPN TYPE VPLS PWTYPE MTU BRIDGE 1506399cec1Srenato %token ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD 151a8c39dc0Srenato %token PSEUDOWIRE NEIGHBORID NEIGHBORADDR PWID 152fda3abacSclaudio %token EXTTAG 153ab0c2486Smichele %token YES NO 15466a1cd4fSrenato %token INCLUDE 155ab0c2486Smichele %token ERROR 156ab0c2486Smichele %token <v.string> STRING 157ab0c2486Smichele %token <v.number> NUMBER 158a8c39dc0Srenato %type <v.number> yesno ldp_af l2vpn_type pw_type 159ab0c2486Smichele %type <v.string> string 16009ad9801Sdlg %type <v.routerid> routerid 1617ee91690Sdlg %type <v.auth> auth tcpmd5 optnbrprefix 162ab0c2486Smichele 163ab0c2486Smichele %% 164ab0c2486Smichele 165ab0c2486Smichele grammar : /* empty */ 16666a1cd4fSrenato | grammar include '\n' 167ab0c2486Smichele | grammar '\n' 168ab0c2486Smichele | grammar conf_main '\n' 169ab0c2486Smichele | grammar varset '\n' 170a8c39dc0Srenato | grammar af '\n' 171627846caSrenato | grammar neighbor '\n' 1726399cec1Srenato | grammar l2vpn '\n' 173ab0c2486Smichele | grammar error '\n' { file->errors++; } 174ab0c2486Smichele ; 175ab0c2486Smichele 17666a1cd4fSrenato include : INCLUDE STRING { 17766a1cd4fSrenato struct file *nfile; 17866a1cd4fSrenato 1796dbe86f5Sdenis if ((nfile = pushfile($2, 1806dbe86f5Sdenis !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) { 18166a1cd4fSrenato yyerror("failed to include file %s", $2); 18266a1cd4fSrenato free($2); 18366a1cd4fSrenato YYERROR; 18466a1cd4fSrenato } 18566a1cd4fSrenato free($2); 18666a1cd4fSrenato 18766a1cd4fSrenato file = nfile; 18866a1cd4fSrenato lungetc('\n'); 18966a1cd4fSrenato } 19066a1cd4fSrenato ; 19166a1cd4fSrenato 192ab0c2486Smichele string : string STRING { 193ab0c2486Smichele if (asprintf(&$$, "%s %s", $1, $2) == -1) { 194ab0c2486Smichele free($1); 195ab0c2486Smichele free($2); 196ab0c2486Smichele yyerror("string: asprintf"); 197ab0c2486Smichele YYERROR; 198ab0c2486Smichele } 199ab0c2486Smichele free($1); 200ab0c2486Smichele free($2); 201ab0c2486Smichele } 202ab0c2486Smichele | STRING 203ab0c2486Smichele ; 204ab0c2486Smichele 20509ad9801Sdlg routerid : STRING { 206*f885c9d9Sflorian if (inet_pton(AF_INET, $1, &$$) != 1) { 20709ad9801Sdlg yyerror("%s: error parsing router id", $1); 20809ad9801Sdlg free($1); 20909ad9801Sdlg YYERROR; 21009ad9801Sdlg } 21109ad9801Sdlg if (bad_addr_v4($$)) { 21209ad9801Sdlg yyerror("%s: invalid router id", $1); 21309ad9801Sdlg free($1); 21409ad9801Sdlg YYERROR; 21509ad9801Sdlg } 21609ad9801Sdlg free($1); 21709ad9801Sdlg 21809ad9801Sdlg break; 21909ad9801Sdlg } 22009ad9801Sdlg ; 22109ad9801Sdlg 222ab0c2486Smichele yesno : YES { $$ = 1; } 223ab0c2486Smichele | NO { $$ = 0; } 224ab0c2486Smichele ; 225ab0c2486Smichele 226a8c39dc0Srenato ldp_af : IPV4 { $$ = AF_INET; } 227a8c39dc0Srenato | IPV6 { $$ = AF_INET6; } 228a8c39dc0Srenato ; 229a8c39dc0Srenato 2306399cec1Srenato l2vpn_type : VPLS { $$ = L2VPN_TYPE_VPLS; } 2316399cec1Srenato ; 2326399cec1Srenato 2336399cec1Srenato pw_type : ETHERNET { $$ = PW_TYPE_ETHERNET; } 2346399cec1Srenato | ETHERNETTAGGED { $$ = PW_TYPE_ETHERNET_TAGGED; } 2356399cec1Srenato ; 2366399cec1Srenato 237ab0c2486Smichele varset : STRING '=' string { 2380c7b4ca6Sbenno char *s = $1; 2393de94509Srenato if (global.cmd_opts & LDPD_OPT_VERBOSE) 240ab0c2486Smichele printf("%s = \"%s\"\n", $1, $3); 2410c7b4ca6Sbenno while (*s++) { 2420c7b4ca6Sbenno if (isspace((unsigned char)*s)) { 2430c7b4ca6Sbenno yyerror("macro name cannot contain " 2440c7b4ca6Sbenno "whitespace"); 24516a0a906Skrw free($1); 24616a0a906Skrw free($3); 2470c7b4ca6Sbenno YYERROR; 2480c7b4ca6Sbenno } 2490c7b4ca6Sbenno } 250ab0c2486Smichele if (symset($1, $3, 0) == -1) 251ab0c2486Smichele fatal("cannot store variable"); 252ab0c2486Smichele free($1); 253ab0c2486Smichele free($3); 254ab0c2486Smichele } 255ab0c2486Smichele ; 256ab0c2486Smichele 25709ad9801Sdlg conf_main : ROUTERID routerid { 25809ad9801Sdlg conf->rtr_id = $2; 259ab0c2486Smichele } 260970465c0Sclaudio | FIBUPDATE yesno { 261ab0c2486Smichele if ($2 == 0) 2623de94509Srenato conf->flags |= F_LDPD_NO_FIB_UPDATE; 263ab0c2486Smichele else 2643de94509Srenato conf->flags &= ~F_LDPD_NO_FIB_UPDATE; 265ab0c2486Smichele } 2668622bd53Srenato | RDOMAIN NUMBER { 2678622bd53Srenato if ($2 < 0 || $2 > RT_TABLEID_MAX) { 2688622bd53Srenato yyerror("invalid rdomain"); 2698622bd53Srenato YYERROR; 2708622bd53Srenato } 2718622bd53Srenato conf->rdomain = $2; 2728622bd53Srenato } 273a8c39dc0Srenato | TRANSPREFERENCE ldp_af { 274a8c39dc0Srenato conf->trans_pref = $2; 275a8c39dc0Srenato 276a8c39dc0Srenato switch (conf->trans_pref) { 277a8c39dc0Srenato case AF_INET: 278a8c39dc0Srenato conf->trans_pref = DUAL_STACK_LDPOV4; 279a8c39dc0Srenato break; 280a8c39dc0Srenato case AF_INET6: 281a8c39dc0Srenato conf->trans_pref = DUAL_STACK_LDPOV6; 282a8c39dc0Srenato break; 283a8c39dc0Srenato default: 284a8c39dc0Srenato yyerror("invalid address-family"); 285a8c39dc0Srenato YYERROR; 286a8c39dc0Srenato } 287a8c39dc0Srenato } 288a8c39dc0Srenato | DSCISCOINTEROP yesno { 289a8c39dc0Srenato if ($2 == 1) 290a8c39dc0Srenato conf->flags |= F_LDPD_DS_CISCO_INTEROP; 29183dcf737Sclaudio else 292a8c39dc0Srenato conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; 293a8c39dc0Srenato } 2947ee91690Sdlg | auth { 2957ee91690Sdlg LIST_INSERT_HEAD(&conf->auth_list, $1, entry); 2967ee91690Sdlg } 297a8c39dc0Srenato | af_defaults 298a8c39dc0Srenato | iface_defaults 299a8c39dc0Srenato | tnbr_defaults 300a8c39dc0Srenato ; 301a8c39dc0Srenato 302a8c39dc0Srenato af : AF ldp_af { 303a8c39dc0Srenato af = $2; 304a8c39dc0Srenato switch (af) { 305a8c39dc0Srenato case AF_INET: 306a8c39dc0Srenato af_conf = &conf->ipv4; 307a8c39dc0Srenato break; 308a8c39dc0Srenato case AF_INET6: 309a8c39dc0Srenato af_conf = &conf->ipv6; 310a8c39dc0Srenato break; 311a8c39dc0Srenato default: 312a8c39dc0Srenato yyerror("invalid address-family"); 313a8c39dc0Srenato YYERROR; 314a8c39dc0Srenato } 315a8c39dc0Srenato 316a8c39dc0Srenato afdefs = *defs; 317a8c39dc0Srenato defs = &afdefs; 318a8c39dc0Srenato } af_block { 319a8c39dc0Srenato af_conf->keepalive = defs->keepalive; 320a8c39dc0Srenato af_conf->thello_holdtime = defs->thello_holdtime; 321a8c39dc0Srenato af_conf->thello_interval = defs->thello_interval; 322a8c39dc0Srenato af_conf->flags = defs->afflags; 323a8c39dc0Srenato af_conf->flags |= F_LDPD_AF_ENABLED; 324a8c39dc0Srenato af_conf = NULL; 325a8c39dc0Srenato af = AF_UNSPEC; 326a8c39dc0Srenato defs = &globaldefs; 327a8c39dc0Srenato } 328a8c39dc0Srenato ; 329a8c39dc0Srenato 330a8c39dc0Srenato af_block : '{' optnl afopts_l '}' 331a8c39dc0Srenato | '{' optnl '}' 332a8c39dc0Srenato | 333a8c39dc0Srenato ; 334a8c39dc0Srenato 335a8c39dc0Srenato afopts_l : afopts_l afoptsl nl 336a8c39dc0Srenato | afoptsl optnl 337a8c39dc0Srenato ; 338a8c39dc0Srenato 339a8c39dc0Srenato afoptsl : TRANSADDRESS STRING { 340a8c39dc0Srenato if (get_address($2, &af_conf->trans_addr) == -1) { 341a8c39dc0Srenato yyerror("error parsing transport-address"); 342a8c39dc0Srenato free($2); 343a8c39dc0Srenato YYERROR; 344a8c39dc0Srenato } 345a8c39dc0Srenato free($2); 346a8c39dc0Srenato if (bad_addr(af, &af_conf->trans_addr)) { 347a8c39dc0Srenato yyerror("invalid transport-address"); 348a8c39dc0Srenato YYERROR; 349a8c39dc0Srenato } 350a8c39dc0Srenato if (af == AF_INET6 && 351a8c39dc0Srenato IN6_IS_SCOPE_EMBED(&af_conf->trans_addr.v6)) { 352a8c39dc0Srenato yyerror("ipv6 transport-address can not be " 353a8c39dc0Srenato "link-local"); 354a8c39dc0Srenato YYERROR; 355a8c39dc0Srenato } 356a8c39dc0Srenato } 3575ff72af8Srenato | GTSMENABLE yesno { 3585ff72af8Srenato if ($2 == 0) 3595ff72af8Srenato defs->afflags |= F_LDPD_AF_NO_GTSM; 3605ff72af8Srenato } 361a8c39dc0Srenato | af_defaults 362a8c39dc0Srenato | iface_defaults 363a8c39dc0Srenato | tnbr_defaults 364a8c39dc0Srenato | interface 365a8c39dc0Srenato | tneighbor 366a8c39dc0Srenato ; 367a8c39dc0Srenato 368a8c39dc0Srenato af_defaults : THELLOACCEPT yesno { 369a8c39dc0Srenato if ($2 == 0) 370a8c39dc0Srenato defs->afflags &= ~F_LDPD_AF_THELLO_ACCEPT; 371a8c39dc0Srenato else 372a8c39dc0Srenato defs->afflags |= F_LDPD_AF_THELLO_ACCEPT; 3733de94509Srenato } 3743de94509Srenato | EXPNULL yesno { 3753de94509Srenato if ($2 == 0) 376a8c39dc0Srenato defs->afflags &= ~F_LDPD_AF_EXPNULL; 3773de94509Srenato else 378a8c39dc0Srenato defs->afflags |= F_LDPD_AF_EXPNULL; 37983dcf737Sclaudio } 380a7bbe4e3Sclaudio | KEEPALIVE NUMBER { 3813d39db89Srenato if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { 382a7bbe4e3Sclaudio yyerror("keepalive out of range (%d-%d)", 383a7bbe4e3Sclaudio MIN_KEEPALIVE, MAX_KEEPALIVE); 384a7bbe4e3Sclaudio YYERROR; 385a7bbe4e3Sclaudio } 386a8c39dc0Srenato defs->keepalive = $2; 387a7bbe4e3Sclaudio } 388ab0c2486Smichele ; 38999170248Srenato 39083dcf737Sclaudio iface_defaults : LHELLOHOLDTIME NUMBER { 39119fce358Srenato if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) { 39219fce358Srenato yyerror("hello-holdtime out of range (%d-%d)", 393ab0c2486Smichele MIN_HOLDTIME, MAX_HOLDTIME); 394ab0c2486Smichele YYERROR; 395ab0c2486Smichele } 39683dcf737Sclaudio defs->lhello_holdtime = $2; 397ab0c2486Smichele } 39883dcf737Sclaudio | LHELLOINTERVAL NUMBER { 399ab0c2486Smichele if ($2 < MIN_HELLO_INTERVAL || 400ab0c2486Smichele $2 > MAX_HELLO_INTERVAL) { 401ab0c2486Smichele yyerror("hello-interval out of range (%d-%d)", 402ab0c2486Smichele MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 403ab0c2486Smichele YYERROR; 404ab0c2486Smichele } 40583dcf737Sclaudio defs->lhello_interval = $2; 40683dcf737Sclaudio } 40783dcf737Sclaudio ; 40883dcf737Sclaudio 40983dcf737Sclaudio tnbr_defaults : THELLOHOLDTIME NUMBER { 41019fce358Srenato if ($2 < MIN_HOLDTIME || $2 > MAX_HOLDTIME) { 41119fce358Srenato yyerror("hello-holdtime out of range (%d-%d)", 41283dcf737Sclaudio MIN_HOLDTIME, MAX_HOLDTIME); 41383dcf737Sclaudio YYERROR; 41483dcf737Sclaudio } 41583dcf737Sclaudio defs->thello_holdtime = $2; 41683dcf737Sclaudio } 41783dcf737Sclaudio | THELLOINTERVAL NUMBER { 41883dcf737Sclaudio if ($2 < MIN_HELLO_INTERVAL || 41983dcf737Sclaudio $2 > MAX_HELLO_INTERVAL) { 42083dcf737Sclaudio yyerror("hello-interval out of range (%d-%d)", 42183dcf737Sclaudio MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL); 42283dcf737Sclaudio YYERROR; 42383dcf737Sclaudio } 42483dcf737Sclaudio defs->thello_interval = $2; 425ab0c2486Smichele } 426ab0c2486Smichele ; 427ab0c2486Smichele 4287ee91690Sdlg tcpmd5 : TCP MD5SIG PASSWORD STRING { 4297ee91690Sdlg size_t len; 4307ee91690Sdlg 4317ee91690Sdlg $$ = calloc(1, sizeof(*$$)); 4327ee91690Sdlg if ($$ == NULL) { 4337ee91690Sdlg free($4); 4347ee91690Sdlg yyerror("unable to allocate md5 key"); 4357ee91690Sdlg YYERROR; 4367ee91690Sdlg } 4377ee91690Sdlg 4387ee91690Sdlg len = strlen($4); 4397ee91690Sdlg if (len > sizeof($$->md5key)) { 4407ee91690Sdlg free($$); 4417ee91690Sdlg free($4); 4427ee91690Sdlg yyerror("tcp md5sig password too long: " 4437ee91690Sdlg "max %zu", sizeof($$->md5key)); 4447ee91690Sdlg YYERROR; 4457ee91690Sdlg } 4467ee91690Sdlg 4477ee91690Sdlg memcpy($$->md5key, $4, len); 4487ee91690Sdlg $$->md5key_len = len; 4497ee91690Sdlg 4507ee91690Sdlg free($4); 4517ee91690Sdlg } 4527ee91690Sdlg | TCP MD5SIG KEY STRING { 4537ee91690Sdlg int len; 4547ee91690Sdlg 4557ee91690Sdlg $$ = calloc(1, sizeof(*$$)); 4567ee91690Sdlg if ($$ == NULL) { 4577ee91690Sdlg free($4); 4587ee91690Sdlg yyerror("unable to allocate md5 key"); 4597ee91690Sdlg YYERROR; 4607ee91690Sdlg } 4617ee91690Sdlg 4627ee91690Sdlg len = str2key($$->md5key, $4, sizeof($$->md5key)); 4637ee91690Sdlg if (len == -1) { 4647ee91690Sdlg free($$); 4657ee91690Sdlg free($4); 4667ee91690Sdlg yyerror("invalid hex string"); 4677ee91690Sdlg YYERROR; 4687ee91690Sdlg } 4697ee91690Sdlg if ((size_t)len > sizeof($$->md5key_len)) { 4707ee91690Sdlg free($$); 4717ee91690Sdlg free($4); 4727ee91690Sdlg yyerror("tcp md5sig key too long: %d " 4737ee91690Sdlg "max %zu", len, sizeof($$->md5key)); 4747ee91690Sdlg YYERROR; 4757ee91690Sdlg } 4767ee91690Sdlg 4777ee91690Sdlg $$->md5key_len = len; 4787ee91690Sdlg 4797ee91690Sdlg free($4); 4807ee91690Sdlg } 4817ee91690Sdlg | NO TCP MD5SIG { 4827ee91690Sdlg $$ = calloc(1, sizeof(*$$)); 4837ee91690Sdlg if ($$ == NULL) { 4847ee91690Sdlg yyerror("unable to allocate no md5 key"); 4857ee91690Sdlg YYERROR; 4867ee91690Sdlg } 4877ee91690Sdlg $$->md5key_len = 0; 4887ee91690Sdlg } 4897ee91690Sdlg ; 4907ee91690Sdlg 4917ee91690Sdlg optnbrprefix : STRING { 4927ee91690Sdlg $$ = calloc(1, sizeof(*$$)); 4937ee91690Sdlg if ($$ == NULL) { 4947ee91690Sdlg yyerror("unable to allocate auth"); 4957ee91690Sdlg free($1); 4967ee91690Sdlg YYERROR; 4977ee91690Sdlg } 4987ee91690Sdlg 4997ee91690Sdlg $$->idlen = inet_net_pton(AF_INET, $1, 5007ee91690Sdlg &$$->id, sizeof($$->id)); 5017ee91690Sdlg if ($$->idlen == -1) { 5027ee91690Sdlg yyerror("%s: %s", $1, strerror(errno)); 5037ee91690Sdlg free($1); 5047ee91690Sdlg YYERROR; 5057ee91690Sdlg } 5067ee91690Sdlg } 5077ee91690Sdlg | /* empty */ { 5087ee91690Sdlg $$ = NULL; 5097ee91690Sdlg } 5107ee91690Sdlg ; 5117ee91690Sdlg 5127ee91690Sdlg auth : tcpmd5 optnbrprefix { 5137ee91690Sdlg $$ = $1; 5147ee91690Sdlg if ($2 != NULL) { 5157ee91690Sdlg $$->id = $2->id; 5167ee91690Sdlg $$->idlen = $2->idlen; 5177ee91690Sdlg free($2); 5187ee91690Sdlg } else { 5197ee91690Sdlg $$->id.s_addr = 0; 5207ee91690Sdlg $$->idlen = 0; 5217ee91690Sdlg } 5227ee91690Sdlg } 5237ee91690Sdlg ; 5247ee91690Sdlg 5253d39db89Srenato nbr_opts : KEEPALIVE NUMBER { 5263d39db89Srenato if ($2 < MIN_KEEPALIVE || $2 > MAX_KEEPALIVE) { 5273d39db89Srenato yyerror("keepalive out of range (%d-%d)", 5283d39db89Srenato MIN_KEEPALIVE, MAX_KEEPALIVE); 5293d39db89Srenato YYERROR; 5303d39db89Srenato } 5313d39db89Srenato nbrp->keepalive = $2; 5323d39db89Srenato nbrp->flags |= F_NBRP_KEEPALIVE; 5333d39db89Srenato } 5347ee91690Sdlg | tcpmd5 { 5357ee91690Sdlg /* this is syntactic sugar... */ 5367ee91690Sdlg $1->id = nbrp->lsr_id; 5377ee91690Sdlg $1->idlen = 32; 5387ee91690Sdlg LIST_INSERT_HEAD(&conf->auth_list, $1, entry); 539627846caSrenato } 5405ff72af8Srenato | GTSMENABLE yesno { 5415ff72af8Srenato nbrp->flags |= F_NBRP_GTSM; 5425ff72af8Srenato nbrp->gtsm_enabled = $2; 5435ff72af8Srenato } 5445ff72af8Srenato | GTSMHOPS NUMBER { 5455ff72af8Srenato if ($2 < 1 || $2 > 255) { 5465ff72af8Srenato yyerror("invalid number of hops %lld", $2); 5475ff72af8Srenato YYERROR; 5485ff72af8Srenato } 5495ff72af8Srenato nbrp->gtsm_hops = $2; 5505ff72af8Srenato nbrp->flags |= F_NBRP_GTSM_HOPS; 5515ff72af8Srenato } 552627846caSrenato ; 553627846caSrenato 5546399cec1Srenato pw_defaults : STATUSTLV yesno { 555a2da3f43Srenato if ($2 == 1) 5566399cec1Srenato defs->pwflags |= F_PW_STATUSTLV_CONF; 557a2da3f43Srenato else 5586399cec1Srenato defs->pwflags &= ~F_PW_STATUSTLV_CONF; 5596399cec1Srenato } 5606399cec1Srenato | CONTROLWORD yesno { 561a2da3f43Srenato if ($2 == 1) 5622d825b92Srenato defs->pwflags |= F_PW_CWORD_CONF; 563a2da3f43Srenato else 5642d825b92Srenato defs->pwflags &= ~F_PW_CWORD_CONF; 5656399cec1Srenato } 5666399cec1Srenato ; 5676399cec1Srenato 5686399cec1Srenato pwopts : PWID NUMBER { 5696399cec1Srenato if ($2 < MIN_PWID_ID || 5706399cec1Srenato $2 > MAX_PWID_ID) { 5716399cec1Srenato yyerror("pw-id out of range (%d-%d)", 5726399cec1Srenato MIN_PWID_ID, MAX_PWID_ID); 5736399cec1Srenato YYERROR; 5746399cec1Srenato } 5756399cec1Srenato 5766399cec1Srenato pw->pwid = $2; 5776399cec1Srenato } 57809ad9801Sdlg | NEIGHBORID routerid { 57909ad9801Sdlg pw->lsr_id = $2; 5806399cec1Srenato } 581a8c39dc0Srenato | NEIGHBORADDR STRING { 582a8c39dc0Srenato int family; 583a8c39dc0Srenato union ldpd_addr addr; 584a8c39dc0Srenato 585a8c39dc0Srenato if (get_af_address($2, &family, &addr) == -1) { 586a8c39dc0Srenato yyerror("error parsing neighbor address"); 587a8c39dc0Srenato free($2); 588a8c39dc0Srenato YYERROR; 589a8c39dc0Srenato } 590a8c39dc0Srenato free($2); 591a8c39dc0Srenato if (bad_addr(family, &addr)) { 592a8c39dc0Srenato yyerror("invalid neighbor address"); 593a8c39dc0Srenato YYERROR; 594a8c39dc0Srenato } 595a8c39dc0Srenato if (family == AF_INET6 && 596a8c39dc0Srenato IN6_IS_SCOPE_EMBED(&addr.v6)) { 597a8c39dc0Srenato yyerror("neighbor address can not be " 598a8c39dc0Srenato "link-local"); 599a8c39dc0Srenato YYERROR; 600a8c39dc0Srenato } 601a8c39dc0Srenato 602a8c39dc0Srenato pw->af = family; 603a8c39dc0Srenato pw->addr = addr; 604a8c39dc0Srenato } 6056399cec1Srenato | pw_defaults 6066399cec1Srenato ; 6076399cec1Srenato 6086399cec1Srenato pseudowire : PSEUDOWIRE STRING { 6096399cec1Srenato struct kif *kif; 6106399cec1Srenato 6116399cec1Srenato if ((kif = kif_findname($2)) == NULL) { 6126399cec1Srenato yyerror("unknown interface %s", $2); 6136399cec1Srenato free($2); 6146399cec1Srenato YYERROR; 6156399cec1Srenato } 6166399cec1Srenato free($2); 6176399cec1Srenato 61817bf3978Sdlg if (kif->if_type != IFT_MPLSTUNNEL && 61917bf3978Sdlg kmpw_find(kif->ifname) == -1) { 6206399cec1Srenato yyerror("unsupported interface type on " 6216399cec1Srenato "interface %s", kif->ifname); 6226399cec1Srenato YYERROR; 6236399cec1Srenato } 6246399cec1Srenato 6256399cec1Srenato pw = conf_get_l2vpn_pw(l2vpn, kif); 6266399cec1Srenato if (pw == NULL) 6276399cec1Srenato YYERROR; 6286399cec1Srenato 6297aa09c5dSrenato pwdefs = *defs; 6306399cec1Srenato defs = &pwdefs; 6316399cec1Srenato } pw_block { 6326399cec1Srenato struct l2vpn *l; 6336399cec1Srenato struct l2vpn_pw *p; 6346399cec1Srenato 63556dfb329Srenato /* check for errors */ 63656dfb329Srenato if (pw->pwid == 0) { 63756dfb329Srenato yyerror("missing pseudowire id"); 63856dfb329Srenato YYERROR; 63956dfb329Srenato } 64072bfe95eSrenato if (pw->lsr_id.s_addr == INADDR_ANY) { 641a8c39dc0Srenato yyerror("missing pseudowire neighbor-id"); 64256dfb329Srenato YYERROR; 64356dfb329Srenato } 64419fce358Srenato LIST_FOREACH(l, &conf->l2vpn_list, entry) { 64519fce358Srenato LIST_FOREACH(p, &l->pw_list, entry) { 6466399cec1Srenato if (pw != p && 6476399cec1Srenato pw->pwid == p->pwid && 648a8c39dc0Srenato pw->af == p->af && 649a8c39dc0Srenato pw->lsr_id.s_addr == 650a8c39dc0Srenato p->lsr_id.s_addr) { 6516399cec1Srenato yyerror("pseudowire already " 6526399cec1Srenato "configured"); 6536399cec1Srenato YYERROR; 6546399cec1Srenato } 65519fce358Srenato } 65619fce358Srenato } 6576399cec1Srenato 658a8c39dc0Srenato /* 659a8c39dc0Srenato * If the neighbor address is not specified, use the 660a8c39dc0Srenato * neighbor id. 661a8c39dc0Srenato */ 662a8c39dc0Srenato if (pw->af == AF_UNSPEC) { 663a8c39dc0Srenato pw->af = AF_INET; 664a8c39dc0Srenato pw->addr.v4 = pw->lsr_id; 665a8c39dc0Srenato } 666a8c39dc0Srenato 6676399cec1Srenato pw->flags = defs->pwflags; 6686399cec1Srenato pw = NULL; 66919fce358Srenato defs = &globaldefs; 6706399cec1Srenato } 6716399cec1Srenato ; 6726399cec1Srenato 6736399cec1Srenato pw_block : '{' optnl pwopts_l '}' 6746399cec1Srenato | '{' optnl '}' 6756399cec1Srenato | /* nothing */ 6766399cec1Srenato ; 6776399cec1Srenato 6786399cec1Srenato pwopts_l : pwopts_l pwopts nl 6796399cec1Srenato | pwopts optnl 6806399cec1Srenato ; 6816399cec1Srenato 6826399cec1Srenato l2vpnopts : PWTYPE pw_type { 6836399cec1Srenato l2vpn->pw_type = $2; 6846399cec1Srenato } 6856399cec1Srenato | MTU NUMBER { 6866399cec1Srenato if ($2 < MIN_L2VPN_MTU || 6876399cec1Srenato $2 > MAX_L2VPN_MTU) { 6886399cec1Srenato yyerror("l2vpn mtu out of range (%d-%d)", 6896399cec1Srenato MIN_L2VPN_MTU, MAX_L2VPN_MTU); 6906399cec1Srenato YYERROR; 6916399cec1Srenato } 6926399cec1Srenato l2vpn->mtu = $2; 6936399cec1Srenato } 6946399cec1Srenato | pw_defaults 6956399cec1Srenato | BRIDGE STRING { 6966399cec1Srenato struct l2vpn *l; 6976399cec1Srenato struct kif *kif; 6986399cec1Srenato 6996399cec1Srenato if ((kif = kif_findname($2)) == NULL) { 7006399cec1Srenato yyerror("unknown interface %s", $2); 7016399cec1Srenato free($2); 7026399cec1Srenato YYERROR; 7036399cec1Srenato } 7046399cec1Srenato free($2); 7056399cec1Srenato 7066399cec1Srenato if (l2vpn->br_ifindex != 0) { 7076399cec1Srenato yyerror("bridge interface cannot be " 7086399cec1Srenato "redefined on l2vpn %s", l2vpn->name); 7096399cec1Srenato YYERROR; 7106399cec1Srenato } 7116399cec1Srenato 7120f882be7Sstsp if (kif->if_type != IFT_BRIDGE) { 7136399cec1Srenato yyerror("unsupported interface type on " 7146399cec1Srenato "interface %s", kif->ifname); 7156399cec1Srenato YYERROR; 7166399cec1Srenato } 7176399cec1Srenato 7186399cec1Srenato LIST_FOREACH(l, &conf->l2vpn_list, entry) { 7196399cec1Srenato if (l->br_ifindex == kif->ifindex) { 7206399cec1Srenato yyerror("bridge %s is already being " 7216399cec1Srenato "used by l2vpn %s", kif->ifname, 7226399cec1Srenato l->name); 7236399cec1Srenato YYERROR; 7246399cec1Srenato } 7256399cec1Srenato } 7266399cec1Srenato 7276399cec1Srenato l2vpn->br_ifindex = kif->ifindex; 7286399cec1Srenato strlcpy(l2vpn->br_ifname, kif->ifname, 7296399cec1Srenato sizeof(l2vpn->br_ifname)); 7306399cec1Srenato } 7316399cec1Srenato | INTERFACE STRING { 7326399cec1Srenato struct kif *kif; 7336399cec1Srenato struct l2vpn_if *lif; 7346399cec1Srenato 7356399cec1Srenato if ((kif = kif_findname($2)) == NULL) { 7366399cec1Srenato yyerror("unknown interface %s", $2); 7376399cec1Srenato free($2); 7386399cec1Srenato YYERROR; 7396399cec1Srenato } 7406399cec1Srenato free($2); 7416399cec1Srenato 7426399cec1Srenato lif = conf_get_l2vpn_if(l2vpn, kif); 7436399cec1Srenato if (lif == NULL) 7446399cec1Srenato YYERROR; 7456399cec1Srenato } 7466399cec1Srenato | pseudowire 7476399cec1Srenato ; 7486399cec1Srenato 749ab0c2486Smichele optnl : '\n' optnl 750ab0c2486Smichele | 751ab0c2486Smichele ; 752ab0c2486Smichele 753ab0c2486Smichele nl : '\n' optnl /* one newline or more */ 754ab0c2486Smichele ; 755ab0c2486Smichele 756ab0c2486Smichele interface : INTERFACE STRING { 757ab0c2486Smichele struct kif *kif; 758ab0c2486Smichele 759814e607dSclaudio if ((kif = kif_findname($2)) == NULL) { 760ab0c2486Smichele yyerror("unknown interface %s", $2); 761ab0c2486Smichele free($2); 762ab0c2486Smichele YYERROR; 763ab0c2486Smichele } 764ab0c2486Smichele free($2); 76519fce358Srenato 766814e607dSclaudio iface = conf_get_if(kif); 767ab0c2486Smichele if (iface == NULL) 768ab0c2486Smichele YYERROR; 769ab0c2486Smichele 770a8c39dc0Srenato ia = iface_af_get(iface, af); 771a8c39dc0Srenato if (ia->enabled) { 772a8c39dc0Srenato yyerror("interface %s already configured for " 773a8c39dc0Srenato "address-family %s", kif->ifname, 774a8c39dc0Srenato af_name(af)); 775a8c39dc0Srenato YYERROR; 776a8c39dc0Srenato } 777a8c39dc0Srenato ia->enabled = 1; 778a8c39dc0Srenato 7797aa09c5dSrenato ifacedefs = *defs; 780ab0c2486Smichele defs = &ifacedefs; 781ab0c2486Smichele } interface_block { 782a8c39dc0Srenato ia->hello_holdtime = defs->lhello_holdtime; 783a8c39dc0Srenato ia->hello_interval = defs->lhello_interval; 784ab0c2486Smichele iface = NULL; 785a8c39dc0Srenato defs = &afdefs; 786ab0c2486Smichele } 787ab0c2486Smichele ; 788ab0c2486Smichele 789ab0c2486Smichele interface_block : '{' optnl interfaceopts_l '}' 790ab0c2486Smichele | '{' optnl '}' 7918d295d64Sclaudio | /* nothing */ 792ab0c2486Smichele ; 793ab0c2486Smichele 79483dcf737Sclaudio interfaceopts_l : interfaceopts_l iface_defaults nl 79583dcf737Sclaudio | iface_defaults optnl 79683dcf737Sclaudio ; 79783dcf737Sclaudio 79883dcf737Sclaudio tneighbor : TNEIGHBOR STRING { 799a8c39dc0Srenato union ldpd_addr addr; 80083dcf737Sclaudio 801a8c39dc0Srenato if (get_address($2, &addr) == -1) { 80219fce358Srenato yyerror("error parsing targeted-neighbor " 80319fce358Srenato "address"); 80483dcf737Sclaudio free($2); 80583dcf737Sclaudio YYERROR; 80683dcf737Sclaudio } 80783dcf737Sclaudio free($2); 808a8c39dc0Srenato if (bad_addr(af, &addr)) { 80919fce358Srenato yyerror("invalid targeted-neighbor address"); 810e2fb924eSrenato YYERROR; 811e2fb924eSrenato } 812a8c39dc0Srenato if (af == AF_INET6 && 813a8c39dc0Srenato IN6_IS_SCOPE_EMBED(&addr.v6)) { 814a8c39dc0Srenato yyerror("targeted-neighbor address can not be " 815a8c39dc0Srenato "link-local"); 816a8c39dc0Srenato YYERROR; 817a8c39dc0Srenato } 81883dcf737Sclaudio 819a8c39dc0Srenato tnbr = conf_get_tnbr(&addr); 82083dcf737Sclaudio if (tnbr == NULL) 82183dcf737Sclaudio YYERROR; 82299170248Srenato 8237aa09c5dSrenato tnbrdefs = *defs; 82483dcf737Sclaudio defs = &tnbrdefs; 82583dcf737Sclaudio } tneighbor_block { 82683dcf737Sclaudio tnbr->hello_holdtime = defs->thello_holdtime; 82783dcf737Sclaudio tnbr->hello_interval = defs->thello_interval; 82883dcf737Sclaudio tnbr = NULL; 829a8c39dc0Srenato defs = &afdefs; 83083dcf737Sclaudio } 83183dcf737Sclaudio ; 83283dcf737Sclaudio 83383dcf737Sclaudio tneighbor_block : '{' optnl tneighboropts_l '}' 83483dcf737Sclaudio | '{' optnl '}' 83583dcf737Sclaudio | /* nothing */ 83683dcf737Sclaudio ; 83783dcf737Sclaudio 83883dcf737Sclaudio tneighboropts_l : tneighboropts_l tnbr_defaults nl 83983dcf737Sclaudio | tnbr_defaults optnl 840ab0c2486Smichele ; 841ab0c2486Smichele 84209ad9801Sdlg neighbor : NEIGHBOR routerid { 84309ad9801Sdlg nbrp = conf_get_nbrp($2); 844627846caSrenato if (nbrp == NULL) 845627846caSrenato YYERROR; 846627846caSrenato } neighbor_block { 847627846caSrenato nbrp = NULL; 848627846caSrenato } 849627846caSrenato ; 850627846caSrenato 851627846caSrenato neighbor_block : '{' optnl neighboropts_l '}' 852627846caSrenato | '{' optnl '}' 853627846caSrenato | /* nothing */ 854627846caSrenato ; 855627846caSrenato 856627846caSrenato neighboropts_l : neighboropts_l nbr_opts nl 857627846caSrenato | nbr_opts optnl 858627846caSrenato ; 859627846caSrenato 8606399cec1Srenato l2vpn : L2VPN STRING TYPE l2vpn_type { 8616399cec1Srenato l2vpn = conf_get_l2vpn($2); 8626399cec1Srenato if (l2vpn == NULL) 8636399cec1Srenato YYERROR; 8646399cec1Srenato l2vpn->type = $4; 8656399cec1Srenato } l2vpn_block { 8666399cec1Srenato l2vpn = NULL; 8676399cec1Srenato } 8686399cec1Srenato ; 8696399cec1Srenato 8706399cec1Srenato l2vpn_block : '{' optnl l2vpnopts_l '}' 8716399cec1Srenato | '{' optnl '}' 8726399cec1Srenato | /* nothing */ 8736399cec1Srenato ; 8746399cec1Srenato 8756399cec1Srenato l2vpnopts_l : l2vpnopts_l l2vpnopts nl 8766399cec1Srenato | l2vpnopts optnl 8776399cec1Srenato ; 8786399cec1Srenato 879ab0c2486Smichele %% 880ab0c2486Smichele 881ab0c2486Smichele struct keywords { 882ab0c2486Smichele const char *k_name; 883ab0c2486Smichele int k_val; 884ab0c2486Smichele }; 885ab0c2486Smichele 886c28a25a1Srenato static int 887ab0c2486Smichele yyerror(const char *fmt, ...) 888ab0c2486Smichele { 889ab0c2486Smichele va_list ap; 890e3490c9cSbluhm char *msg; 891ab0c2486Smichele 892ab0c2486Smichele file->errors++; 893ab0c2486Smichele va_start(ap, fmt); 894e3490c9cSbluhm if (vasprintf(&msg, fmt, ap) == -1) 895e3490c9cSbluhm fatalx("yyerror vasprintf"); 896ab0c2486Smichele va_end(ap); 897e3490c9cSbluhm logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 898e3490c9cSbluhm free(msg); 899ab0c2486Smichele return (0); 900ab0c2486Smichele } 901ab0c2486Smichele 902c28a25a1Srenato static int 903ab0c2486Smichele kw_cmp(const void *k, const void *e) 904ab0c2486Smichele { 905ab0c2486Smichele return (strcmp(k, ((const struct keywords *)e)->k_name)); 906ab0c2486Smichele } 907ab0c2486Smichele 908c28a25a1Srenato static int 909ab0c2486Smichele lookup(char *s) 910ab0c2486Smichele { 911ab0c2486Smichele /* this has to be sorted always */ 912ab0c2486Smichele static const struct keywords keywords[] = { 913a8c39dc0Srenato {"address-family", AF}, 9146399cec1Srenato {"bridge", BRIDGE}, 9156399cec1Srenato {"control-word", CONTROLWORD}, 916a8c39dc0Srenato {"ds-cisco-interop", DSCISCOINTEROP}, 9176399cec1Srenato {"ethernet", ETHERNET}, 9186399cec1Srenato {"ethernet-tagged", ETHERNETTAGGED}, 9193de94509Srenato {"explicit-null", EXPNULL}, 920970465c0Sclaudio {"fib-update", FIBUPDATE}, 9215ff72af8Srenato {"gtsm-enable", GTSMENABLE}, 9225ff72af8Srenato {"gtsm-hops", GTSMHOPS}, 92366a1cd4fSrenato {"include", INCLUDE}, 9247ee91690Sdlg {"inet", INET}, 9257ee91690Sdlg {"inet6", INET6}, 926ab0c2486Smichele {"interface", INTERFACE}, 927a8c39dc0Srenato {"ipv4", IPV4}, 928a8c39dc0Srenato {"ipv6", IPV6}, 929ab0c2486Smichele {"keepalive", KEEPALIVE}, 9307ee91690Sdlg {"key", KEY}, 9316399cec1Srenato {"l2vpn", L2VPN}, 93283dcf737Sclaudio {"link-hello-holdtime", LHELLOHOLDTIME}, 93383dcf737Sclaudio {"link-hello-interval", LHELLOINTERVAL}, 9347ee91690Sdlg {"md5sig", MD5SIG}, 9356399cec1Srenato {"mtu", MTU}, 936627846caSrenato {"neighbor", NEIGHBOR}, 937a8c39dc0Srenato {"neighbor-addr", NEIGHBORADDR}, 938a8c39dc0Srenato {"neighbor-id", NEIGHBORID}, 9396a647450Sclaudio {"no", NO}, 940627846caSrenato {"password", PASSWORD}, 9416399cec1Srenato {"pseudowire", PSEUDOWIRE}, 9426399cec1Srenato {"pw-id", PWID}, 9436399cec1Srenato {"pw-type", PWTYPE}, 9448622bd53Srenato {"rdomain", RDOMAIN}, 945ab0c2486Smichele {"router-id", ROUTERID}, 9466399cec1Srenato {"status-tlv", STATUSTLV}, 94783dcf737Sclaudio {"targeted-hello-accept", THELLOACCEPT}, 94883dcf737Sclaudio {"targeted-hello-holdtime", THELLOHOLDTIME}, 94983dcf737Sclaudio {"targeted-hello-interval", THELLOINTERVAL}, 95083dcf737Sclaudio {"targeted-neighbor", TNEIGHBOR}, 9517ee91690Sdlg {"tcp", TCP}, 95286408800Srenato {"transport-address", TRANSADDRESS}, 953a8c39dc0Srenato {"transport-preference", TRANSPREFERENCE}, 9546399cec1Srenato {"type", TYPE}, 9556399cec1Srenato {"vpls", VPLS}, 956ab0c2486Smichele {"yes", YES} 957ab0c2486Smichele }; 958ab0c2486Smichele const struct keywords *p; 959ab0c2486Smichele 960ab0c2486Smichele p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 961ab0c2486Smichele sizeof(keywords[0]), kw_cmp); 962ab0c2486Smichele 963ab0c2486Smichele if (p) 964ab0c2486Smichele return (p->k_val); 965ab0c2486Smichele else 966ab0c2486Smichele return (STRING); 967ab0c2486Smichele } 968ab0c2486Smichele 9696dbe86f5Sdenis #define START_EXPAND 1 9706dbe86f5Sdenis #define DONE_EXPAND 2 9716dbe86f5Sdenis 9726dbe86f5Sdenis static int expanding; 9736dbe86f5Sdenis 9746dbe86f5Sdenis int 9756dbe86f5Sdenis igetc(void) 9766dbe86f5Sdenis { 9776dbe86f5Sdenis int c; 9786dbe86f5Sdenis 9796dbe86f5Sdenis while (1) { 9806dbe86f5Sdenis if (file->ungetpos > 0) 9816dbe86f5Sdenis c = file->ungetbuf[--file->ungetpos]; 9826dbe86f5Sdenis else 9836dbe86f5Sdenis c = getc(file->stream); 9846dbe86f5Sdenis 9856dbe86f5Sdenis if (c == START_EXPAND) 9866dbe86f5Sdenis expanding = 1; 9876dbe86f5Sdenis else if (c == DONE_EXPAND) 9886dbe86f5Sdenis expanding = 0; 9896dbe86f5Sdenis else 9906dbe86f5Sdenis break; 9916dbe86f5Sdenis } 9926dbe86f5Sdenis return (c); 9936dbe86f5Sdenis } 9946dbe86f5Sdenis 995c28a25a1Srenato static int 996ab0c2486Smichele lgetc(int quotec) 997ab0c2486Smichele { 998ab0c2486Smichele int c, next; 999ab0c2486Smichele 1000ab0c2486Smichele if (quotec) { 10016dbe86f5Sdenis if ((c = igetc()) == EOF) { 1002ab0c2486Smichele yyerror("reached end of file while parsing " 1003ab0c2486Smichele "quoted string"); 1004ab0c2486Smichele if (file == topfile || popfile() == EOF) 1005ab0c2486Smichele return (EOF); 1006ab0c2486Smichele return (quotec); 1007ab0c2486Smichele } 1008ab0c2486Smichele return (c); 1009ab0c2486Smichele } 1010ab0c2486Smichele 10116dbe86f5Sdenis while ((c = igetc()) == '\\') { 10126dbe86f5Sdenis next = igetc(); 1013ab0c2486Smichele if (next != '\n') { 1014ab0c2486Smichele c = next; 1015ab0c2486Smichele break; 1016ab0c2486Smichele } 1017ab0c2486Smichele yylval.lineno = file->lineno; 1018ab0c2486Smichele file->lineno++; 1019ab0c2486Smichele } 1020ab0c2486Smichele 10216dbe86f5Sdenis if (c == EOF) { 10226dbe86f5Sdenis /* 10236dbe86f5Sdenis * Fake EOL when hit EOF for the first time. This gets line 10246dbe86f5Sdenis * count right if last line in included file is syntactically 10256dbe86f5Sdenis * invalid and has no newline. 10266dbe86f5Sdenis */ 10276dbe86f5Sdenis if (file->eof_reached == 0) { 10286dbe86f5Sdenis file->eof_reached = 1; 10296dbe86f5Sdenis return ('\n'); 10306dbe86f5Sdenis } 1031ab0c2486Smichele while (c == EOF) { 1032ab0c2486Smichele if (file == topfile || popfile() == EOF) 1033ab0c2486Smichele return (EOF); 10346dbe86f5Sdenis c = igetc(); 10356dbe86f5Sdenis } 1036ab0c2486Smichele } 1037ab0c2486Smichele return (c); 1038ab0c2486Smichele } 1039ab0c2486Smichele 10406dbe86f5Sdenis void 1041ab0c2486Smichele lungetc(int c) 1042ab0c2486Smichele { 1043ab0c2486Smichele if (c == EOF) 10446dbe86f5Sdenis return; 10456dbe86f5Sdenis 10466dbe86f5Sdenis if (file->ungetpos >= file->ungetsize) { 10476dbe86f5Sdenis void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); 10486dbe86f5Sdenis if (p == NULL) 1049a062aa9dSkrw err(1, "%s", __func__); 10506dbe86f5Sdenis file->ungetbuf = p; 10516dbe86f5Sdenis file->ungetsize *= 2; 1052ab0c2486Smichele } 10536dbe86f5Sdenis file->ungetbuf[file->ungetpos++] = c; 1054ab0c2486Smichele } 1055ab0c2486Smichele 1056c28a25a1Srenato static int 1057ab0c2486Smichele findeol(void) 1058ab0c2486Smichele { 1059ab0c2486Smichele int c; 1060ab0c2486Smichele 1061ab0c2486Smichele /* skip to either EOF or the first real EOL */ 1062ab0c2486Smichele while (1) { 1063ab0c2486Smichele c = lgetc(0); 1064ab0c2486Smichele if (c == '\n') { 1065ab0c2486Smichele file->lineno++; 1066ab0c2486Smichele break; 1067ab0c2486Smichele } 1068ab0c2486Smichele if (c == EOF) 1069ab0c2486Smichele break; 1070ab0c2486Smichele } 1071ab0c2486Smichele return (ERROR); 1072ab0c2486Smichele } 1073ab0c2486Smichele 1074c28a25a1Srenato static int 1075ab0c2486Smichele yylex(void) 1076ab0c2486Smichele { 107708f6ba19Snaddy char buf[8096]; 107808f6ba19Snaddy char *p, *val; 1079ab0c2486Smichele int quotec, next, c; 1080ab0c2486Smichele int token; 1081ab0c2486Smichele 1082ab0c2486Smichele top: 1083ab0c2486Smichele p = buf; 1084ab0c2486Smichele while ((c = lgetc(0)) == ' ' || c == '\t') 1085ab0c2486Smichele ; /* nothing */ 1086ab0c2486Smichele 1087ab0c2486Smichele yylval.lineno = file->lineno; 1088ab0c2486Smichele if (c == '#') 1089ab0c2486Smichele while ((c = lgetc(0)) != '\n' && c != EOF) 1090ab0c2486Smichele ; /* nothing */ 10916dbe86f5Sdenis if (c == '$' && !expanding) { 1092ab0c2486Smichele while (1) { 1093ab0c2486Smichele if ((c = lgetc(0)) == EOF) 1094ab0c2486Smichele return (0); 1095ab0c2486Smichele 1096ab0c2486Smichele if (p + 1 >= buf + sizeof(buf) - 1) { 1097ab0c2486Smichele yyerror("string too long"); 1098ab0c2486Smichele return (findeol()); 1099ab0c2486Smichele } 1100ab0c2486Smichele if (isalnum(c) || c == '_') { 1101015d7b4dSbenno *p++ = c; 1102ab0c2486Smichele continue; 1103ab0c2486Smichele } 1104ab0c2486Smichele *p = '\0'; 1105ab0c2486Smichele lungetc(c); 1106ab0c2486Smichele break; 1107ab0c2486Smichele } 1108ab0c2486Smichele val = symget(buf); 1109ab0c2486Smichele if (val == NULL) { 1110ab0c2486Smichele yyerror("macro '%s' not defined", buf); 1111ab0c2486Smichele return (findeol()); 1112ab0c2486Smichele } 11136dbe86f5Sdenis p = val + strlen(val) - 1; 11146dbe86f5Sdenis lungetc(DONE_EXPAND); 11156dbe86f5Sdenis while (p >= val) { 111608f6ba19Snaddy lungetc((unsigned char)*p); 11176dbe86f5Sdenis p--; 11186dbe86f5Sdenis } 11196dbe86f5Sdenis lungetc(START_EXPAND); 1120ab0c2486Smichele goto top; 1121ab0c2486Smichele } 1122ab0c2486Smichele 1123ab0c2486Smichele switch (c) { 1124ab0c2486Smichele case '\'': 1125ab0c2486Smichele case '"': 1126ab0c2486Smichele quotec = c; 1127ab0c2486Smichele while (1) { 1128ab0c2486Smichele if ((c = lgetc(quotec)) == EOF) 1129ab0c2486Smichele return (0); 1130ab0c2486Smichele if (c == '\n') { 1131ab0c2486Smichele file->lineno++; 1132ab0c2486Smichele continue; 1133ab0c2486Smichele } else if (c == '\\') { 1134ab0c2486Smichele if ((next = lgetc(quotec)) == EOF) 1135ab0c2486Smichele return (0); 1136a1533359Ssashan if (next == quotec || next == ' ' || 1137a1533359Ssashan next == '\t') 1138ab0c2486Smichele c = next; 1139daf24110Shenning else if (next == '\n') { 1140daf24110Shenning file->lineno++; 1141ab0c2486Smichele continue; 1142daf24110Shenning } else 1143ab0c2486Smichele lungetc(next); 1144ab0c2486Smichele } else if (c == quotec) { 1145ab0c2486Smichele *p = '\0'; 1146ab0c2486Smichele break; 114741eef22fSjsg } else if (c == '\0') { 114841eef22fSjsg yyerror("syntax error"); 114941eef22fSjsg return (findeol()); 1150ab0c2486Smichele } 1151ab0c2486Smichele if (p + 1 >= buf + sizeof(buf) - 1) { 1152ab0c2486Smichele yyerror("string too long"); 1153ab0c2486Smichele return (findeol()); 1154ab0c2486Smichele } 1155015d7b4dSbenno *p++ = c; 1156ab0c2486Smichele } 1157ab0c2486Smichele yylval.v.string = strdup(buf); 1158ab0c2486Smichele if (yylval.v.string == NULL) 1159a062aa9dSkrw err(1, "%s", __func__); 1160ab0c2486Smichele return (STRING); 1161ab0c2486Smichele } 1162ab0c2486Smichele 1163ab0c2486Smichele #define allowed_to_end_number(x) \ 1164ab0c2486Smichele (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 1165ab0c2486Smichele 1166ab0c2486Smichele if (c == '-' || isdigit(c)) { 1167ab0c2486Smichele do { 1168ab0c2486Smichele *p++ = c; 1169915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) { 1170ab0c2486Smichele yyerror("string too long"); 1171ab0c2486Smichele return (findeol()); 1172ab0c2486Smichele } 1173ab0c2486Smichele } while ((c = lgetc(0)) != EOF && isdigit(c)); 1174ab0c2486Smichele lungetc(c); 1175ab0c2486Smichele if (p == buf + 1 && buf[0] == '-') 1176ab0c2486Smichele goto nodigits; 1177ab0c2486Smichele if (c == EOF || allowed_to_end_number(c)) { 1178ab0c2486Smichele const char *errstr = NULL; 1179ab0c2486Smichele 1180ab0c2486Smichele *p = '\0'; 1181ab0c2486Smichele yylval.v.number = strtonum(buf, LLONG_MIN, 1182ab0c2486Smichele LLONG_MAX, &errstr); 1183ab0c2486Smichele if (errstr) { 1184ab0c2486Smichele yyerror("\"%s\" invalid number: %s", 1185ab0c2486Smichele buf, errstr); 1186ab0c2486Smichele return (findeol()); 1187ab0c2486Smichele } 1188ab0c2486Smichele return (NUMBER); 1189ab0c2486Smichele } else { 1190ab0c2486Smichele nodigits: 1191ab0c2486Smichele while (p > buf + 1) 119208f6ba19Snaddy lungetc((unsigned char)*--p); 119308f6ba19Snaddy c = (unsigned char)*--p; 1194ab0c2486Smichele if (c == '-') 1195ab0c2486Smichele return (c); 1196ab0c2486Smichele } 1197ab0c2486Smichele } 1198ab0c2486Smichele 1199ab0c2486Smichele #define allowed_in_string(x) \ 1200ab0c2486Smichele (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 1201ab0c2486Smichele x != '{' && x != '}' && \ 1202ab0c2486Smichele x != '!' && x != '=' && x != '#' && \ 1203ab0c2486Smichele x != ',')) 1204ab0c2486Smichele 1205ab0c2486Smichele if (isalnum(c) || c == ':' || c == '_') { 1206ab0c2486Smichele do { 1207ab0c2486Smichele *p++ = c; 1208915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) { 1209ab0c2486Smichele yyerror("string too long"); 1210ab0c2486Smichele return (findeol()); 1211ab0c2486Smichele } 1212ab0c2486Smichele } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 1213ab0c2486Smichele lungetc(c); 1214ab0c2486Smichele *p = '\0'; 1215ab0c2486Smichele if ((token = lookup(buf)) == STRING) 1216ab0c2486Smichele if ((yylval.v.string = strdup(buf)) == NULL) 1217a062aa9dSkrw err(1, "%s", __func__); 1218ab0c2486Smichele return (token); 1219ab0c2486Smichele } 1220ab0c2486Smichele if (c == '\n') { 1221ab0c2486Smichele yylval.lineno = file->lineno; 1222ab0c2486Smichele file->lineno++; 1223ab0c2486Smichele } 1224ab0c2486Smichele if (c == EOF) 1225ab0c2486Smichele return (0); 1226ab0c2486Smichele return (c); 1227ab0c2486Smichele } 1228ab0c2486Smichele 1229c28a25a1Srenato static int 1230ab0c2486Smichele check_file_secrecy(int fd, const char *fname) 1231ab0c2486Smichele { 1232ab0c2486Smichele struct stat st; 1233ab0c2486Smichele 1234ab0c2486Smichele if (fstat(fd, &st)) { 1235ab0c2486Smichele log_warn("cannot stat %s", fname); 1236ab0c2486Smichele return (-1); 1237ab0c2486Smichele } 1238ab0c2486Smichele if (st.st_uid != 0 && st.st_uid != getuid()) { 1239ab0c2486Smichele log_warnx("%s: owner not root or current user", fname); 1240ab0c2486Smichele return (-1); 1241ab0c2486Smichele } 12427140c133Shenning if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 12437140c133Shenning log_warnx("%s: group writable or world read/writable", fname); 1244ab0c2486Smichele return (-1); 1245ab0c2486Smichele } 1246ab0c2486Smichele return (0); 1247ab0c2486Smichele } 1248ab0c2486Smichele 1249c28a25a1Srenato static struct file * 1250ab0c2486Smichele pushfile(const char *name, int secret) 1251ab0c2486Smichele { 1252ab0c2486Smichele struct file *nfile; 1253ab0c2486Smichele 1254d0812690Smichele if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 12556a3d55f9Skrw log_warn("%s", __func__); 1256ab0c2486Smichele return (NULL); 1257ab0c2486Smichele } 1258d0812690Smichele if ((nfile->name = strdup(name)) == NULL) { 12596a3d55f9Skrw log_warn("%s", __func__); 1260d0812690Smichele free(nfile); 1261d0812690Smichele return (NULL); 1262d0812690Smichele } 1263ab0c2486Smichele if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 12646a3d55f9Skrw log_warn("%s: %s", __func__, nfile->name); 1265ab0c2486Smichele free(nfile->name); 1266ab0c2486Smichele free(nfile); 1267ab0c2486Smichele return (NULL); 1268ab0c2486Smichele } else if (secret && 1269ab0c2486Smichele check_file_secrecy(fileno(nfile->stream), nfile->name)) { 1270ab0c2486Smichele fclose(nfile->stream); 1271ab0c2486Smichele free(nfile->name); 1272ab0c2486Smichele free(nfile); 1273ab0c2486Smichele return (NULL); 1274ab0c2486Smichele } 12756dbe86f5Sdenis nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; 12766dbe86f5Sdenis nfile->ungetsize = 16; 12776dbe86f5Sdenis nfile->ungetbuf = malloc(nfile->ungetsize); 12786dbe86f5Sdenis if (nfile->ungetbuf == NULL) { 12796a3d55f9Skrw log_warn("%s", __func__); 12806dbe86f5Sdenis fclose(nfile->stream); 12816dbe86f5Sdenis free(nfile->name); 12826dbe86f5Sdenis free(nfile); 12836dbe86f5Sdenis return (NULL); 12846dbe86f5Sdenis } 1285ab0c2486Smichele TAILQ_INSERT_TAIL(&files, nfile, entry); 1286ab0c2486Smichele return (nfile); 1287ab0c2486Smichele } 1288ab0c2486Smichele 1289c28a25a1Srenato static int 1290ab0c2486Smichele popfile(void) 1291ab0c2486Smichele { 1292ab0c2486Smichele struct file *prev; 1293ab0c2486Smichele 1294ab0c2486Smichele if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 1295ab0c2486Smichele prev->errors += file->errors; 1296ab0c2486Smichele 1297ab0c2486Smichele TAILQ_REMOVE(&files, file, entry); 1298ab0c2486Smichele fclose(file->stream); 1299ab0c2486Smichele free(file->name); 13006dbe86f5Sdenis free(file->ungetbuf); 1301ab0c2486Smichele free(file); 1302ab0c2486Smichele file = prev; 1303ab0c2486Smichele return (file ? 0 : EOF); 1304ab0c2486Smichele } 1305ab0c2486Smichele 1306ab0c2486Smichele struct ldpd_conf * 13073de94509Srenato parse_config(char *filename) 1308ab0c2486Smichele { 1309ab0c2486Smichele struct sym *sym, *next; 1310ab0c2486Smichele 131116040b47Srenato conf = config_new_empty(); 13128622bd53Srenato conf->rdomain = 0; 1313a8c39dc0Srenato conf->trans_pref = DUAL_STACK_LDPOV6; 1314ab0c2486Smichele 1315ab0c2486Smichele defs = &globaldefs; 1316a8c39dc0Srenato defs->keepalive = DEFAULT_KEEPALIVE; 131783dcf737Sclaudio defs->lhello_holdtime = LINK_DFLT_HOLDTIME; 131883dcf737Sclaudio defs->lhello_interval = DEFAULT_HELLO_INTERVAL; 131983dcf737Sclaudio defs->thello_holdtime = TARGETED_DFLT_HOLDTIME; 132083dcf737Sclaudio defs->thello_interval = DEFAULT_HELLO_INTERVAL; 1321a2da3f43Srenato defs->pwflags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; 132273d80685Smichele 13233de94509Srenato if ((file = pushfile(filename, 13243de94509Srenato !(global.cmd_opts & LDPD_OPT_NOACTION))) == NULL) { 1325ab0c2486Smichele free(conf); 1326ab0c2486Smichele return (NULL); 1327ab0c2486Smichele } 1328ab0c2486Smichele topfile = file; 1329ab0c2486Smichele 1330ab0c2486Smichele yyparse(); 1331ab0c2486Smichele errors = file->errors; 1332ab0c2486Smichele popfile(); 1333ab0c2486Smichele 1334ab0c2486Smichele /* Free macros and check which have not been used. */ 133546bca67bSkrw TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { 13363de94509Srenato if ((global.cmd_opts & LDPD_OPT_VERBOSE2) && !sym->used) 1337ab0c2486Smichele fprintf(stderr, "warning: macro '%s' not " 1338ab0c2486Smichele "used\n", sym->nam); 1339ab0c2486Smichele if (!sym->persist) { 1340ab0c2486Smichele free(sym->nam); 1341ab0c2486Smichele free(sym->val); 1342ab0c2486Smichele TAILQ_REMOVE(&symhead, sym, entry); 1343ab0c2486Smichele free(sym); 1344ab0c2486Smichele } 1345ab0c2486Smichele } 1346ab0c2486Smichele 13478622bd53Srenato /* check that all interfaces belong to the configured rdomain */ 13488622bd53Srenato errors += conf_check_rdomain(conf->rdomain); 13498622bd53Srenato 1350ab0c2486Smichele /* free global config defaults */ 1351ab0c2486Smichele if (errors) { 1352ab0c2486Smichele clear_config(conf); 1353ab0c2486Smichele return (NULL); 1354ab0c2486Smichele } 1355ab0c2486Smichele 135619fce358Srenato if (conf->rtr_id.s_addr == INADDR_ANY) 1357ab0c2486Smichele conf->rtr_id.s_addr = get_rtr_id(); 1358a8c39dc0Srenato 1359a8c39dc0Srenato /* if the ipv4 transport-address is not set, use the router-id */ 1360a8c39dc0Srenato if ((conf->ipv4.flags & F_LDPD_AF_ENABLED) && 1361a8c39dc0Srenato conf->ipv4.trans_addr.v4.s_addr == INADDR_ANY) 1362a8c39dc0Srenato conf->ipv4.trans_addr.v4 = conf->rtr_id; 1363ab0c2486Smichele 1364ab0c2486Smichele return (conf); 1365ab0c2486Smichele } 1366ab0c2486Smichele 1367c28a25a1Srenato static int 1368ab0c2486Smichele symset(const char *nam, const char *val, int persist) 1369ab0c2486Smichele { 1370ab0c2486Smichele struct sym *sym; 1371ab0c2486Smichele 137254c95b7aSkrw TAILQ_FOREACH(sym, &symhead, entry) { 137354c95b7aSkrw if (strcmp(nam, sym->nam) == 0) 137454c95b7aSkrw break; 137554c95b7aSkrw } 1376ab0c2486Smichele 1377ab0c2486Smichele if (sym != NULL) { 1378ab0c2486Smichele if (sym->persist == 1) 1379ab0c2486Smichele return (0); 1380ab0c2486Smichele else { 1381ab0c2486Smichele free(sym->nam); 1382ab0c2486Smichele free(sym->val); 1383ab0c2486Smichele TAILQ_REMOVE(&symhead, sym, entry); 1384ab0c2486Smichele free(sym); 1385ab0c2486Smichele } 1386ab0c2486Smichele } 1387ab0c2486Smichele if ((sym = calloc(1, sizeof(*sym))) == NULL) 1388ab0c2486Smichele return (-1); 1389ab0c2486Smichele 1390ab0c2486Smichele sym->nam = strdup(nam); 1391ab0c2486Smichele if (sym->nam == NULL) { 1392ab0c2486Smichele free(sym); 1393ab0c2486Smichele return (-1); 1394ab0c2486Smichele } 1395ab0c2486Smichele sym->val = strdup(val); 1396ab0c2486Smichele if (sym->val == NULL) { 1397ab0c2486Smichele free(sym->nam); 1398ab0c2486Smichele free(sym); 1399ab0c2486Smichele return (-1); 1400ab0c2486Smichele } 1401ab0c2486Smichele sym->used = 0; 1402ab0c2486Smichele sym->persist = persist; 1403ab0c2486Smichele TAILQ_INSERT_TAIL(&symhead, sym, entry); 1404ab0c2486Smichele return (0); 1405ab0c2486Smichele } 1406ab0c2486Smichele 1407ab0c2486Smichele int 1408ab0c2486Smichele cmdline_symset(char *s) 1409ab0c2486Smichele { 1410ab0c2486Smichele char *sym, *val; 1411ab0c2486Smichele int ret; 1412ab0c2486Smichele 1413ab0c2486Smichele if ((val = strrchr(s, '=')) == NULL) 1414ab0c2486Smichele return (-1); 1415ed1b9eb8Smiko sym = strndup(s, val - s); 1416ed1b9eb8Smiko if (sym == NULL) 1417ed1b9eb8Smiko errx(1, "%s: strndup", __func__); 1418ab0c2486Smichele ret = symset(sym, val + 1, 1); 1419ab0c2486Smichele free(sym); 1420ab0c2486Smichele 1421ab0c2486Smichele return (ret); 1422ab0c2486Smichele } 1423ab0c2486Smichele 1424c28a25a1Srenato static char * 1425ab0c2486Smichele symget(const char *nam) 1426ab0c2486Smichele { 1427ab0c2486Smichele struct sym *sym; 1428ab0c2486Smichele 142954c95b7aSkrw TAILQ_FOREACH(sym, &symhead, entry) { 1430ab0c2486Smichele if (strcmp(nam, sym->nam) == 0) { 1431ab0c2486Smichele sym->used = 1; 1432ab0c2486Smichele return (sym->val); 1433ab0c2486Smichele } 143454c95b7aSkrw } 1435ab0c2486Smichele return (NULL); 1436ab0c2486Smichele } 1437ab0c2486Smichele 1438c28a25a1Srenato static struct iface * 1439814e607dSclaudio conf_get_if(struct kif *kif) 1440ab0c2486Smichele { 1441ab0c2486Smichele struct iface *i; 1442c000763aSrenato struct l2vpn *l; 1443ab0c2486Smichele 144419fce358Srenato if (kif->if_type == IFT_LOOP || 144519fce358Srenato kif->if_type == IFT_CARP || 1446c000763aSrenato kif->if_type == IFT_BRIDGE || 144719fce358Srenato kif->if_type == IFT_MPLSTUNNEL) { 144819fce358Srenato yyerror("unsupported interface type on interface %s", 144919fce358Srenato kif->ifname); 145019fce358Srenato return (NULL); 145119fce358Srenato } 1452ab0c2486Smichele 1453c000763aSrenato LIST_FOREACH(l, &conf->l2vpn_list, entry) 1454c000763aSrenato if (l2vpn_if_find(l, kif->ifindex)) { 1455c000763aSrenato yyerror("interface %s already configured under " 1456c000763aSrenato "l2vpn %s", kif->ifname, l->name); 1457c000763aSrenato return (NULL); 1458c000763aSrenato } 1459c000763aSrenato 1460c000763aSrenato LIST_FOREACH(i, &conf->iface_list, entry) 1461c000763aSrenato if (i->ifindex == kif->ifindex) 1462c000763aSrenato return (i); 1463c000763aSrenato 146419fce358Srenato i = if_new(kif); 146519fce358Srenato LIST_INSERT_HEAD(&conf->iface_list, i, entry); 1466ab0c2486Smichele return (i); 1467ab0c2486Smichele } 1468ab0c2486Smichele 1469c28a25a1Srenato static struct tnbr * 1470a8c39dc0Srenato conf_get_tnbr(union ldpd_addr *addr) 147183dcf737Sclaudio { 147283dcf737Sclaudio struct tnbr *t; 147383dcf737Sclaudio 1474a8c39dc0Srenato t = tnbr_find(conf, af, addr); 1475edf37f74Srenato if (t) { 147683dcf737Sclaudio yyerror("targeted neighbor %s already configured", 1477a8c39dc0Srenato log_addr(af, addr)); 147883dcf737Sclaudio return (NULL); 147983dcf737Sclaudio } 148083dcf737Sclaudio 1481a8c39dc0Srenato t = tnbr_new(conf, af, addr); 148219fce358Srenato t->flags |= F_TNBR_CONFIGURED; 148319fce358Srenato LIST_INSERT_HEAD(&conf->tnbr_list, t, entry); 148483dcf737Sclaudio return (t); 148583dcf737Sclaudio } 148683dcf737Sclaudio 1487c28a25a1Srenato static struct nbr_params * 14881ce5acabSrenato conf_get_nbrp(struct in_addr lsr_id) 1489627846caSrenato { 1490627846caSrenato struct nbr_params *n; 1491627846caSrenato 1492627846caSrenato LIST_FOREACH(n, &conf->nbrp_list, entry) { 14931ce5acabSrenato if (n->lsr_id.s_addr == lsr_id.s_addr) { 1494627846caSrenato yyerror("neighbor %s already configured", 14951ce5acabSrenato inet_ntoa(lsr_id)); 1496627846caSrenato return (NULL); 1497627846caSrenato } 1498627846caSrenato } 1499627846caSrenato 15001ce5acabSrenato n = nbr_params_new(lsr_id); 150119fce358Srenato LIST_INSERT_HEAD(&conf->nbrp_list, n, entry); 1502627846caSrenato return (n); 1503627846caSrenato } 1504627846caSrenato 1505c28a25a1Srenato static struct l2vpn * 15066399cec1Srenato conf_get_l2vpn(char *name) 15076399cec1Srenato { 15086399cec1Srenato struct l2vpn *l; 15096399cec1Srenato 15106399cec1Srenato if (l2vpn_find(conf, name)) { 15116399cec1Srenato yyerror("l2vpn %s already configured", name); 15126399cec1Srenato return (NULL); 15136399cec1Srenato } 15146399cec1Srenato 15156399cec1Srenato l = l2vpn_new(name); 151619fce358Srenato LIST_INSERT_HEAD(&conf->l2vpn_list, l, entry); 15176399cec1Srenato return (l); 15186399cec1Srenato } 15196399cec1Srenato 1520c28a25a1Srenato static struct l2vpn_if * 15216399cec1Srenato conf_get_l2vpn_if(struct l2vpn *l, struct kif *kif) 15226399cec1Srenato { 15236399cec1Srenato struct iface *i; 15246399cec1Srenato struct l2vpn *ltmp; 152519fce358Srenato struct l2vpn_if *f; 15266399cec1Srenato 1527c000763aSrenato if (kif->if_type == IFT_LOOP || 1528c000763aSrenato kif->if_type == IFT_CARP || 1529c000763aSrenato kif->if_type == IFT_BRIDGE || 1530c000763aSrenato kif->if_type == IFT_MPLSTUNNEL) { 1531c000763aSrenato yyerror("unsupported interface type on interface %s", 1532c000763aSrenato kif->ifname); 1533c000763aSrenato return (NULL); 1534c000763aSrenato } 1535c000763aSrenato 1536c000763aSrenato LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) 1537c000763aSrenato if (l2vpn_if_find(ltmp, kif->ifindex)) { 1538c000763aSrenato yyerror("interface %s already configured under " 1539c000763aSrenato "l2vpn %s", kif->ifname, ltmp->name); 1540c000763aSrenato return (NULL); 1541c000763aSrenato } 1542c000763aSrenato 15436399cec1Srenato LIST_FOREACH(i, &conf->iface_list, entry) { 15446399cec1Srenato if (i->ifindex == kif->ifindex) { 15456399cec1Srenato yyerror("interface %s already configured", 15466399cec1Srenato kif->ifname); 15476399cec1Srenato return (NULL); 15486399cec1Srenato } 15496399cec1Srenato } 15506399cec1Srenato 155119fce358Srenato f = l2vpn_if_new(l, kif); 155219fce358Srenato LIST_INSERT_HEAD(&l2vpn->if_list, f, entry); 155319fce358Srenato return (f); 15546399cec1Srenato } 15556399cec1Srenato 1556c28a25a1Srenato static struct l2vpn_pw * 15576399cec1Srenato conf_get_l2vpn_pw(struct l2vpn *l, struct kif *kif) 15586399cec1Srenato { 15596399cec1Srenato struct l2vpn *ltmp; 156019fce358Srenato struct l2vpn_pw *p; 15616399cec1Srenato 15626399cec1Srenato LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) { 15636399cec1Srenato if (l2vpn_pw_find(ltmp, kif->ifindex)) { 15646399cec1Srenato yyerror("pseudowire %s is already being " 15656399cec1Srenato "used by l2vpn %s", kif->ifname, ltmp->name); 15666399cec1Srenato return (NULL); 15676399cec1Srenato } 15686399cec1Srenato } 15696399cec1Srenato 157019fce358Srenato p = l2vpn_pw_new(l, kif); 157119fce358Srenato LIST_INSERT_HEAD(&l2vpn->pw_list, p, entry); 157219fce358Srenato return (p); 15736399cec1Srenato } 15746399cec1Srenato 15758622bd53Srenato int 15768622bd53Srenato conf_check_rdomain(unsigned int rdomain) 15778622bd53Srenato { 15788622bd53Srenato struct iface *i; 15798622bd53Srenato int errs = 0; 15808622bd53Srenato 15818622bd53Srenato LIST_FOREACH(i, &conf->iface_list, entry) { 15828622bd53Srenato if (i->rdomain != rdomain) { 15838622bd53Srenato logit(LOG_CRIT, "interface %s not in rdomain %u", 15848622bd53Srenato i->name, rdomain); 15858622bd53Srenato errs++; 15868622bd53Srenato } 15878622bd53Srenato } 15888622bd53Srenato 15898622bd53Srenato return (errs); 15908622bd53Srenato } 15918622bd53Srenato 1592c28a25a1Srenato static void 1593ab0c2486Smichele clear_config(struct ldpd_conf *xconf) 1594ab0c2486Smichele { 1595ab0c2486Smichele struct iface *i; 159617cc0810Srenato struct tnbr *t; 159717cc0810Srenato struct nbr_params *n; 15986399cec1Srenato struct l2vpn *l; 15996399cec1Srenato struct l2vpn_if *f; 16006399cec1Srenato struct l2vpn_pw *p; 1601ab0c2486Smichele 160217cc0810Srenato while ((i = LIST_FIRST(&xconf->iface_list)) != NULL) { 1603ab0c2486Smichele LIST_REMOVE(i, entry); 1604eee72fddSrenato free(i); 1605ab0c2486Smichele } 1606ab0c2486Smichele 160717cc0810Srenato while ((t = LIST_FIRST(&xconf->tnbr_list)) != NULL) { 160817cc0810Srenato LIST_REMOVE(t, entry); 1609eee72fddSrenato free(t); 161017cc0810Srenato } 161117cc0810Srenato 161217cc0810Srenato while ((n = LIST_FIRST(&xconf->nbrp_list)) != NULL) { 161317cc0810Srenato LIST_REMOVE(n, entry); 161417cc0810Srenato free(n); 161517cc0810Srenato } 161617cc0810Srenato 16176399cec1Srenato while ((l = LIST_FIRST(&xconf->l2vpn_list)) != NULL) { 16186399cec1Srenato while ((f = LIST_FIRST(&l->if_list)) != NULL) { 16196399cec1Srenato LIST_REMOVE(f, entry); 16206399cec1Srenato free(f); 16216399cec1Srenato } 16226399cec1Srenato while ((p = LIST_FIRST(&l->pw_list)) != NULL) { 16236399cec1Srenato LIST_REMOVE(p, entry); 16246399cec1Srenato free(p); 16256399cec1Srenato } 16266399cec1Srenato LIST_REMOVE(l, entry); 16276399cec1Srenato free(l); 16286399cec1Srenato } 16296399cec1Srenato 1630ab0c2486Smichele free(xconf); 1631ab0c2486Smichele } 1632ab0c2486Smichele 1633c28a25a1Srenato static uint32_t 1634ab0c2486Smichele get_rtr_id(void) 1635ab0c2486Smichele { 1636ab0c2486Smichele struct ifaddrs *ifap, *ifa; 16373de94509Srenato uint32_t ip = 0, cur, localnet; 1638ab0c2486Smichele 1639ab0c2486Smichele localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); 1640ab0c2486Smichele 164108964f31Srenato if (getifaddrs(&ifap) == -1) { 164208964f31Srenato log_warn("getifaddrs"); 164308964f31Srenato return (0); 164408964f31Srenato } 1645ab0c2486Smichele 1646ab0c2486Smichele for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1647f2af7f71Sclaudio if (strncmp(ifa->ifa_name, "carp", 4) == 0) 1648f2af7f71Sclaudio continue; 1649ab0c2486Smichele if (ifa->ifa_addr->sa_family != AF_INET) 1650ab0c2486Smichele continue; 1651ab0c2486Smichele cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 1652ab0c2486Smichele if ((cur & localnet) == localnet) /* skip 127/8 */ 1653ab0c2486Smichele continue; 165436dfdbcaSrenato if (ntohl(cur) < ntohl(ip) || ip == 0) 1655ab0c2486Smichele ip = cur; 1656ab0c2486Smichele } 1657ab0c2486Smichele freeifaddrs(ifap); 1658ab0c2486Smichele 1659ab0c2486Smichele return (ip); 1660ab0c2486Smichele } 1661ab0c2486Smichele 1662c28a25a1Srenato static int 1663a8c39dc0Srenato get_address(const char *s, union ldpd_addr *addr) 1664ab0c2486Smichele { 1665a8c39dc0Srenato switch (af) { 1666a8c39dc0Srenato case AF_INET: 1667a8c39dc0Srenato if (inet_pton(AF_INET, s, &addr->v4) != 1) 1668a8c39dc0Srenato return (-1); 1669a8c39dc0Srenato break; 1670a8c39dc0Srenato case AF_INET6: 1671a8c39dc0Srenato if (inet_pton(AF_INET6, s, &addr->v6) != 1) 1672a8c39dc0Srenato return (-1); 1673a8c39dc0Srenato break; 1674a8c39dc0Srenato default: 1675a8c39dc0Srenato return (-1); 1676a8c39dc0Srenato } 1677ab0c2486Smichele 1678ab0c2486Smichele return (0); 1679ab0c2486Smichele } 1680ab0c2486Smichele 1681c28a25a1Srenato static int 1682a8c39dc0Srenato get_af_address(const char *s, int *family, union ldpd_addr *addr) 1683a8c39dc0Srenato { 1684a8c39dc0Srenato if (inet_pton(AF_INET, s, &addr->v4) == 1) { 1685a8c39dc0Srenato *family = AF_INET; 1686a8c39dc0Srenato return (0); 1687a8c39dc0Srenato } 1688ab0c2486Smichele 1689a8c39dc0Srenato if (inet_pton(AF_INET6, s, &addr->v6) == 1) { 1690a8c39dc0Srenato *family = AF_INET6; 1691a8c39dc0Srenato return (0); 1692a8c39dc0Srenato } 1693a8c39dc0Srenato 1694a8c39dc0Srenato return (-1); 1695ab0c2486Smichele } 16967ee91690Sdlg 16977ee91690Sdlg static int 16987ee91690Sdlg hexchar(int ch) 16997ee91690Sdlg { 17007ee91690Sdlg if (ch >= '0' && ch <= '9') 17017ee91690Sdlg return (ch - '0'); 17027ee91690Sdlg if (ch >= 'a' && ch <= 'f') 17037ee91690Sdlg return (ch - 'a'); 17047ee91690Sdlg if (ch >= 'A' && ch <= 'F') 17057ee91690Sdlg return (ch - 'A'); 17067ee91690Sdlg 17077ee91690Sdlg return (-1); 17087ee91690Sdlg } 17097ee91690Sdlg 17107ee91690Sdlg static int 17117ee91690Sdlg str2key(char *dst, const char *src, int dstlen) 17127ee91690Sdlg { 17137ee91690Sdlg int i = 0; 17147ee91690Sdlg int digit; 17157ee91690Sdlg 17167ee91690Sdlg while (*src != '\0') { 17177ee91690Sdlg digit = hexchar(*src); 17187ee91690Sdlg if (digit == -1) 17197ee91690Sdlg return (-1); 17207ee91690Sdlg 17217ee91690Sdlg if (i < dstlen) 17227ee91690Sdlg *dst = digit << 4; 17237ee91690Sdlg 17247ee91690Sdlg src++; 17257ee91690Sdlg if (*src == '\0') 17267ee91690Sdlg return (-1); 17277ee91690Sdlg digit = hexchar(*src); 17287ee91690Sdlg if (digit == -1) 17297ee91690Sdlg return (-1); 17307ee91690Sdlg 17317ee91690Sdlg if (i < dstlen) 17327ee91690Sdlg *dst |= digit; 17337ee91690Sdlg 17347ee91690Sdlg src++; 17357ee91690Sdlg i++; 17367ee91690Sdlg } 17377ee91690Sdlg 17387ee91690Sdlg return (i); 17397ee91690Sdlg } 1740