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