GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: parse.y,v 1.316 2017/10/19 06:52:55 jsg Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> |
||
5 |
* Copyright (c) 2001 Markus Friedl. All rights reserved. |
||
6 |
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved. |
||
7 |
* Copyright (c) 2001 Theo de Raadt. All rights reserved. |
||
8 |
* Copyright (c) 2016 Job Snijders <job@instituut.net> |
||
9 |
* Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> |
||
10 |
* |
||
11 |
* Permission to use, copy, modify, and distribute this software for any |
||
12 |
* purpose with or without fee is hereby granted, provided that the above |
||
13 |
* copyright notice and this permission notice appear in all copies. |
||
14 |
* |
||
15 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||
16 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
17 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||
18 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
19 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||
20 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||
21 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
22 |
*/ |
||
23 |
|||
24 |
%{ |
||
25 |
#include <sys/types.h> |
||
26 |
#include <sys/socket.h> |
||
27 |
#include <sys/stat.h> |
||
28 |
#include <sys/un.h> |
||
29 |
#include <netinet/in.h> |
||
30 |
#include <netinet/ip_ipsp.h> |
||
31 |
#include <arpa/inet.h> |
||
32 |
#include <netmpls/mpls.h> |
||
33 |
|||
34 |
#include <ctype.h> |
||
35 |
#include <err.h> |
||
36 |
#include <unistd.h> |
||
37 |
#include <errno.h> |
||
38 |
#include <limits.h> |
||
39 |
#include <stdarg.h> |
||
40 |
#include <stdio.h> |
||
41 |
#include <string.h> |
||
42 |
#include <syslog.h> |
||
43 |
|||
44 |
#include "bgpd.h" |
||
45 |
#include "mrt.h" |
||
46 |
#include "session.h" |
||
47 |
#include "rde.h" |
||
48 |
#include "log.h" |
||
49 |
|||
50 |
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); |
||
51 |
static struct file { |
||
52 |
TAILQ_ENTRY(file) entry; |
||
53 |
FILE *stream; |
||
54 |
char *name; |
||
55 |
int lineno; |
||
56 |
int errors; |
||
57 |
} *file, *topfile; |
||
58 |
struct file *pushfile(const char *, int); |
||
59 |
int popfile(void); |
||
60 |
int check_file_secrecy(int, const char *); |
||
61 |
int yyparse(void); |
||
62 |
int yylex(void); |
||
63 |
int yyerror(const char *, ...) |
||
64 |
__attribute__((__format__ (printf, 1, 2))) |
||
65 |
__attribute__((__nonnull__ (1))); |
||
66 |
int kw_cmp(const void *, const void *); |
||
67 |
int lookup(char *); |
||
68 |
int lgetc(int); |
||
69 |
int lungetc(int); |
||
70 |
int findeol(void); |
||
71 |
|||
72 |
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); |
||
73 |
struct sym { |
||
74 |
TAILQ_ENTRY(sym) entry; |
||
75 |
int used; |
||
76 |
int persist; |
||
77 |
char *nam; |
||
78 |
char *val; |
||
79 |
}; |
||
80 |
int symset(const char *, const char *, int); |
||
81 |
char *symget(const char *); |
||
82 |
|||
83 |
static struct bgpd_config *conf; |
||
84 |
static struct network_head *netconf; |
||
85 |
static struct peer *peer_l, *peer_l_old; |
||
86 |
static struct peer *curpeer; |
||
87 |
static struct peer *curgroup; |
||
88 |
static struct rdomain *currdom; |
||
89 |
static struct filter_head *filter_l; |
||
90 |
static struct filter_head *peerfilter_l; |
||
91 |
static struct filter_head *groupfilter_l; |
||
92 |
static struct filter_rule *curpeer_filter[2]; |
||
93 |
static struct filter_rule *curgroup_filter[2]; |
||
94 |
static u_int32_t id; |
||
95 |
|||
96 |
struct filter_rib_l { |
||
97 |
struct filter_rib_l *next; |
||
98 |
char name[PEER_DESCR_LEN]; |
||
99 |
}; |
||
100 |
|||
101 |
struct filter_peers_l { |
||
102 |
struct filter_peers_l *next; |
||
103 |
struct filter_peers p; |
||
104 |
}; |
||
105 |
|||
106 |
struct filter_prefix_l { |
||
107 |
struct filter_prefix_l *next; |
||
108 |
struct filter_prefix p; |
||
109 |
}; |
||
110 |
|||
111 |
struct filter_prefixlen { |
||
112 |
enum comp_ops op; |
||
113 |
int len_min; |
||
114 |
int len_max; |
||
115 |
}; |
||
116 |
|||
117 |
struct filter_as_l { |
||
118 |
struct filter_as_l *next; |
||
119 |
struct filter_as a; |
||
120 |
}; |
||
121 |
|||
122 |
struct filter_match_l { |
||
123 |
struct filter_match m; |
||
124 |
struct filter_prefix_l *prefix_l; |
||
125 |
struct filter_as_l *as_l; |
||
126 |
} fmopts; |
||
127 |
|||
128 |
struct peer *alloc_peer(void); |
||
129 |
struct peer *new_peer(void); |
||
130 |
struct peer *new_group(void); |
||
131 |
int add_mrtconfig(enum mrt_type, char *, int, struct peer *, |
||
132 |
char *); |
||
133 |
int add_rib(char *, u_int, u_int16_t); |
||
134 |
struct rde_rib *find_rib(char *); |
||
135 |
int get_id(struct peer *); |
||
136 |
int merge_prefixspec(struct filter_prefix_l *, |
||
137 |
struct filter_prefixlen *); |
||
138 |
int expand_rule(struct filter_rule *, struct filter_rib_l *, |
||
139 |
struct filter_peers_l *, struct filter_match_l *, |
||
140 |
struct filter_set_head *); |
||
141 |
int str2key(char *, char *, size_t); |
||
142 |
int neighbor_consistent(struct peer *); |
||
143 |
int merge_filterset(struct filter_set_head *, struct filter_set *); |
||
144 |
void copy_filterset(struct filter_set_head *, |
||
145 |
struct filter_set_head *); |
||
146 |
void merge_filter_lists(struct filter_head *, struct filter_head *); |
||
147 |
struct filter_rule *get_rule(enum action_types); |
||
148 |
|||
149 |
int getcommunity(char *); |
||
150 |
int parsecommunity(struct filter_community *, char *); |
||
151 |
int64_t getlargecommunity(char *); |
||
152 |
int parselargecommunity(struct filter_largecommunity *, char *); |
||
153 |
int parsesubtype(char *, int *, int *); |
||
154 |
int parseextvalue(char *, u_int32_t *); |
||
155 |
int parseextcommunity(struct filter_extcommunity *, char *, |
||
156 |
char *); |
||
157 |
|||
158 |
typedef struct { |
||
159 |
union { |
||
160 |
int64_t number; |
||
161 |
char *string; |
||
162 |
struct bgpd_addr addr; |
||
163 |
u_int8_t u8; |
||
164 |
struct filter_rib_l *filter_rib; |
||
165 |
struct filter_peers_l *filter_peers; |
||
166 |
struct filter_match_l filter_match; |
||
167 |
struct filter_prefix_l *filter_prefix; |
||
168 |
struct filter_as_l *filter_as; |
||
169 |
struct filter_set *filter_set; |
||
170 |
struct filter_set_head *filter_set_head; |
||
171 |
struct { |
||
172 |
struct bgpd_addr prefix; |
||
173 |
u_int8_t len; |
||
174 |
} prefix; |
||
175 |
struct filter_prefixlen prefixlen; |
||
176 |
struct { |
||
177 |
u_int8_t enc_alg; |
||
178 |
char enc_key[IPSEC_ENC_KEY_LEN]; |
||
179 |
u_int8_t enc_key_len; |
||
180 |
} encspec; |
||
181 |
} v; |
||
182 |
int lineno; |
||
183 |
} YYSTYPE; |
||
184 |
|||
185 |
%} |
||
186 |
|||
187 |
%token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE |
||
188 |
%token RDOMAIN RD EXPORTTRGT IMPORTTRGT |
||
189 |
%token RDE RIB EVALUATE IGNORE COMPARE |
||
190 |
%token GROUP NEIGHBOR NETWORK |
||
191 |
%token EBGP IBGP |
||
192 |
%token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART |
||
193 |
%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY |
||
194 |
%token DEMOTE ENFORCE NEIGHBORAS REFLECTOR DEPEND DOWN |
||
195 |
%token DUMP IN OUT SOCKET RESTRICTED |
||
196 |
%token LOG ROUTECOLL TRANSPARENT |
||
197 |
%token TCP MD5SIG PASSWORD KEY TTLSECURITY |
||
198 |
%token ALLOW DENY MATCH |
||
199 |
%token QUICK |
||
200 |
%token FROM TO ANY |
||
201 |
%token CONNECTED STATIC |
||
202 |
%token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY |
||
203 |
%token PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN MAXASSEQ |
||
204 |
%token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF |
||
205 |
%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN |
||
206 |
%token ERROR INCLUDE |
||
207 |
%token IPSEC ESP AH SPI IKE |
||
208 |
%token IPV4 IPV6 |
||
209 |
%token QUALIFY VIA |
||
210 |
%token NE LE GE XRANGE LONGER |
||
211 |
%token <v.string> STRING |
||
212 |
%token <v.number> NUMBER |
||
213 |
%type <v.number> asnumber as4number as4number_any optnumber |
||
214 |
%type <v.number> espah family restart origincode nettype |
||
215 |
%type <v.number> yesno inout restricted |
||
216 |
%type <v.string> string |
||
217 |
%type <v.addr> address |
||
218 |
%type <v.prefix> prefix addrspec |
||
219 |
%type <v.u8> action quick direction delete |
||
220 |
%type <v.filter_rib> filter_rib_h filter_rib_l filter_rib |
||
221 |
%type <v.filter_peers> filter_peer filter_peer_l filter_peer_h |
||
222 |
%type <v.filter_match> filter_match filter_elm filter_match_h |
||
223 |
%type <v.filter_as> filter_as filter_as_l filter_as_h |
||
224 |
%type <v.filter_as> filter_as_t filter_as_t_l filter_as_l_h |
||
225 |
%type <v.prefixlen> prefixlenop |
||
226 |
%type <v.filter_set> filter_set_opt |
||
227 |
%type <v.filter_set_head> filter_set filter_set_l |
||
228 |
%type <v.filter_prefix> filter_prefix filter_prefix_l filter_prefix_h |
||
229 |
%type <v.filter_prefix> filter_prefix_m |
||
230 |
%type <v.u8> unaryop equalityop binaryop filter_as_type |
||
231 |
%type <v.encspec> encspec |
||
232 |
%% |
||
233 |
|||
234 |
grammar : /* empty */ |
||
235 |
| grammar '\n' |
||
236 |
| grammar include '\n' |
||
237 |
| grammar conf_main '\n' |
||
238 |
| grammar varset '\n' |
||
239 |
| grammar rdomain '\n' |
||
240 |
| grammar neighbor '\n' |
||
241 |
| grammar group '\n' |
||
242 |
| grammar filterrule '\n' |
||
243 |
| grammar error '\n' { file->errors++; } |
||
244 |
; |
||
245 |
|||
246 |
asnumber : NUMBER { |
||
247 |
/* |
||
248 |
* According to iana 65535 and 4294967295 are reserved |
||
249 |
* but enforcing this is not duty of the parser. |
||
250 |
*/ |
||
251 |
if ($1 < 0 || $1 > UINT_MAX) { |
||
252 |
yyerror("AS too big: max %u", UINT_MAX); |
||
253 |
YYERROR; |
||
254 |
} |
||
255 |
} |
||
256 |
|||
257 |
as4number : STRING { |
||
258 |
const char *errstr; |
||
259 |
char *dot; |
||
260 |
u_int32_t uvalh = 0, uval; |
||
261 |
|||
262 |
if ((dot = strchr($1,'.')) != NULL) { |
||
263 |
*dot++ = '\0'; |
||
264 |
uvalh = strtonum($1, 0, USHRT_MAX, &errstr); |
||
265 |
if (errstr) { |
||
266 |
yyerror("number %s is %s", $1, errstr); |
||
267 |
free($1); |
||
268 |
YYERROR; |
||
269 |
} |
||
270 |
uval = strtonum(dot, 0, USHRT_MAX, &errstr); |
||
271 |
if (errstr) { |
||
272 |
yyerror("number %s is %s", dot, errstr); |
||
273 |
free($1); |
||
274 |
YYERROR; |
||
275 |
} |
||
276 |
free($1); |
||
277 |
} else { |
||
278 |
yyerror("AS %s is bad", $1); |
||
279 |
free($1); |
||
280 |
YYERROR; |
||
281 |
} |
||
282 |
if (uvalh == 0 && uval == AS_TRANS) { |
||
283 |
yyerror("AS %u is reserved and may not be used", |
||
284 |
AS_TRANS); |
||
285 |
YYERROR; |
||
286 |
} |
||
287 |
$$ = uval | (uvalh << 16); |
||
288 |
} |
||
289 |
| asnumber { |
||
290 |
if ($1 == AS_TRANS) { |
||
291 |
yyerror("AS %u is reserved and may not be used", |
||
292 |
AS_TRANS); |
||
293 |
YYERROR; |
||
294 |
} |
||
295 |
$$ = $1; |
||
296 |
} |
||
297 |
; |
||
298 |
|||
299 |
as4number_any : STRING { |
||
300 |
const char *errstr; |
||
301 |
char *dot; |
||
302 |
u_int32_t uvalh = 0, uval; |
||
303 |
|||
304 |
if ((dot = strchr($1,'.')) != NULL) { |
||
305 |
*dot++ = '\0'; |
||
306 |
uvalh = strtonum($1, 0, USHRT_MAX, &errstr); |
||
307 |
if (errstr) { |
||
308 |
yyerror("number %s is %s", $1, errstr); |
||
309 |
free($1); |
||
310 |
YYERROR; |
||
311 |
} |
||
312 |
uval = strtonum(dot, 0, USHRT_MAX, &errstr); |
||
313 |
if (errstr) { |
||
314 |
yyerror("number %s is %s", dot, errstr); |
||
315 |
free($1); |
||
316 |
YYERROR; |
||
317 |
} |
||
318 |
free($1); |
||
319 |
} else { |
||
320 |
yyerror("AS %s is bad", $1); |
||
321 |
free($1); |
||
322 |
YYERROR; |
||
323 |
} |
||
324 |
$$ = uval | (uvalh << 16); |
||
325 |
} |
||
326 |
| asnumber { |
||
327 |
$$ = $1; |
||
328 |
} |
||
329 |
; |
||
330 |
|||
331 |
string : string STRING { |
||
332 |
if (asprintf(&$$, "%s %s", $1, $2) == -1) |
||
333 |
fatal("string: asprintf"); |
||
334 |
free($1); |
||
335 |
free($2); |
||
336 |
} |
||
337 |
| STRING |
||
338 |
; |
||
339 |
|||
340 |
yesno : STRING { |
||
341 |
if (!strcmp($1, "yes")) |
||
342 |
$$ = 1; |
||
343 |
else if (!strcmp($1, "no")) |
||
344 |
$$ = 0; |
||
345 |
else { |
||
346 |
yyerror("syntax error, " |
||
347 |
"either yes or no expected"); |
||
348 |
free($1); |
||
349 |
YYERROR; |
||
350 |
} |
||
351 |
free($1); |
||
352 |
} |
||
353 |
; |
||
354 |
|||
355 |
varset : STRING '=' string { |
||
356 |
char *s = $1; |
||
357 |
if (cmd_opts & BGPD_OPT_VERBOSE) |
||
358 |
printf("%s = \"%s\"\n", $1, $3); |
||
359 |
while (*s++) { |
||
360 |
if (isspace((unsigned char)*s)) { |
||
361 |
yyerror("macro name cannot contain " |
||
362 |
"whitespace"); |
||
363 |
YYERROR; |
||
364 |
} |
||
365 |
} |
||
366 |
if (symset($1, $3, 0) == -1) |
||
367 |
fatal("cannot store variable"); |
||
368 |
free($1); |
||
369 |
free($3); |
||
370 |
} |
||
371 |
; |
||
372 |
|||
373 |
include : INCLUDE STRING { |
||
374 |
struct file *nfile; |
||
375 |
|||
376 |
if ((nfile = pushfile($2, 1)) == NULL) { |
||
377 |
yyerror("failed to include file %s", $2); |
||
378 |
free($2); |
||
379 |
YYERROR; |
||
380 |
} |
||
381 |
free($2); |
||
382 |
|||
383 |
file = nfile; |
||
384 |
lungetc('\n'); |
||
385 |
} |
||
386 |
; |
||
387 |
|||
388 |
conf_main : AS as4number { |
||
389 |
conf->as = $2; |
||
390 |
if ($2 > USHRT_MAX) |
||
391 |
conf->short_as = AS_TRANS; |
||
392 |
else |
||
393 |
conf->short_as = $2; |
||
394 |
} |
||
395 |
| AS as4number asnumber { |
||
396 |
conf->as = $2; |
||
397 |
conf->short_as = $3; |
||
398 |
} |
||
399 |
| ROUTERID address { |
||
400 |
if ($2.aid != AID_INET) { |
||
401 |
yyerror("router-id must be an IPv4 address"); |
||
402 |
YYERROR; |
||
403 |
} |
||
404 |
conf->bgpid = $2.v4.s_addr; |
||
405 |
} |
||
406 |
| HOLDTIME NUMBER { |
||
407 |
if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) { |
||
408 |
yyerror("holdtime must be between %u and %u", |
||
409 |
MIN_HOLDTIME, USHRT_MAX); |
||
410 |
YYERROR; |
||
411 |
} |
||
412 |
conf->holdtime = $2; |
||
413 |
} |
||
414 |
| HOLDTIME YMIN NUMBER { |
||
415 |
if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) { |
||
416 |
yyerror("holdtime must be between %u and %u", |
||
417 |
MIN_HOLDTIME, USHRT_MAX); |
||
418 |
YYERROR; |
||
419 |
} |
||
420 |
conf->min_holdtime = $3; |
||
421 |
} |
||
422 |
| LISTEN ON address { |
||
423 |
struct listen_addr *la; |
||
424 |
|||
425 |
if ((la = calloc(1, sizeof(struct listen_addr))) == |
||
426 |
NULL) |
||
427 |
fatal("parse conf_main listen on calloc"); |
||
428 |
|||
429 |
la->fd = -1; |
||
430 |
memcpy(&la->sa, addr2sa(&$3, BGP_PORT), sizeof(la->sa)); |
||
431 |
TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); |
||
432 |
} |
||
433 |
| FIBPRIORITY NUMBER { |
||
434 |
if ($2 <= RTP_NONE || $2 > RTP_MAX) { |
||
435 |
yyerror("invalid fib-priority"); |
||
436 |
YYERROR; |
||
437 |
} |
||
438 |
conf->fib_priority = $2; |
||
439 |
} |
||
440 |
| FIBUPDATE yesno { |
||
441 |
struct rde_rib *rr; |
||
442 |
rr = find_rib("Loc-RIB"); |
||
443 |
if (rr == NULL) |
||
444 |
fatalx("RTABLE can not find the main RIB!"); |
||
445 |
|||
446 |
if ($2 == 0) |
||
447 |
rr->flags |= F_RIB_NOFIBSYNC; |
||
448 |
else |
||
449 |
rr->flags &= ~F_RIB_NOFIBSYNC; |
||
450 |
} |
||
451 |
| ROUTECOLL yesno { |
||
452 |
if ($2 == 1) |
||
453 |
conf->flags |= BGPD_FLAG_NO_EVALUATE; |
||
454 |
else |
||
455 |
conf->flags &= ~BGPD_FLAG_NO_EVALUATE; |
||
456 |
} |
||
457 |
| RDE RIB STRING { |
||
458 |
if (add_rib($3, conf->default_tableid, F_RIB_NOFIB)) { |
||
459 |
free($3); |
||
460 |
YYERROR; |
||
461 |
} |
||
462 |
free($3); |
||
463 |
} |
||
464 |
| RDE RIB STRING yesno EVALUATE { |
||
465 |
if ($4) { |
||
466 |
free($3); |
||
467 |
yyerror("bad rde rib definition"); |
||
468 |
YYERROR; |
||
469 |
} |
||
470 |
if (add_rib($3, conf->default_tableid, |
||
471 |
F_RIB_NOFIB | F_RIB_NOEVALUATE)) { |
||
472 |
free($3); |
||
473 |
YYERROR; |
||
474 |
} |
||
475 |
free($3); |
||
476 |
} |
||
477 |
| RDE RIB STRING RTABLE NUMBER { |
||
478 |
if (add_rib($3, $5, 0)) { |
||
479 |
free($3); |
||
480 |
YYERROR; |
||
481 |
} |
||
482 |
free($3); |
||
483 |
} |
||
484 |
| RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno { |
||
485 |
int flags = 0; |
||
486 |
if ($7 == 0) |
||
487 |
flags = F_RIB_NOFIBSYNC; |
||
488 |
if (add_rib($3, $5, flags)) { |
||
489 |
free($3); |
||
490 |
YYERROR; |
||
491 |
} |
||
492 |
free($3); |
||
493 |
} |
||
494 |
| TRANSPARENT yesno { |
||
495 |
if ($2 == 1) |
||
496 |
conf->flags |= BGPD_FLAG_DECISION_TRANS_AS; |
||
497 |
else |
||
498 |
conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS; |
||
499 |
} |
||
500 |
| LOG STRING { |
||
501 |
if (!strcmp($2, "updates")) |
||
502 |
conf->log |= BGPD_LOG_UPDATES; |
||
503 |
else { |
||
504 |
free($2); |
||
505 |
YYERROR; |
||
506 |
} |
||
507 |
free($2); |
||
508 |
} |
||
509 |
| network |
||
510 |
| DUMP STRING STRING optnumber { |
||
511 |
int action; |
||
512 |
|||
513 |
if ($4 < 0 || $4 > INT_MAX) { |
||
514 |
yyerror("bad timeout"); |
||
515 |
free($2); |
||
516 |
free($3); |
||
517 |
YYERROR; |
||
518 |
} |
||
519 |
if (!strcmp($2, "table")) |
||
520 |
action = MRT_TABLE_DUMP; |
||
521 |
else if (!strcmp($2, "table-mp")) |
||
522 |
action = MRT_TABLE_DUMP_MP; |
||
523 |
else if (!strcmp($2, "table-v2")) |
||
524 |
action = MRT_TABLE_DUMP_V2; |
||
525 |
else { |
||
526 |
yyerror("unknown mrt dump type"); |
||
527 |
free($2); |
||
528 |
free($3); |
||
529 |
YYERROR; |
||
530 |
} |
||
531 |
free($2); |
||
532 |
if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) { |
||
533 |
free($3); |
||
534 |
YYERROR; |
||
535 |
} |
||
536 |
free($3); |
||
537 |
} |
||
538 |
| DUMP RIB STRING STRING STRING optnumber { |
||
539 |
int action; |
||
540 |
|||
541 |
if ($6 < 0 || $6 > INT_MAX) { |
||
542 |
yyerror("bad timeout"); |
||
543 |
free($3); |
||
544 |
free($4); |
||
545 |
free($5); |
||
546 |
YYERROR; |
||
547 |
} |
||
548 |
if (!strcmp($4, "table")) |
||
549 |
action = MRT_TABLE_DUMP; |
||
550 |
else if (!strcmp($4, "table-mp")) |
||
551 |
action = MRT_TABLE_DUMP_MP; |
||
552 |
else if (!strcmp($4, "table-v2")) |
||
553 |
action = MRT_TABLE_DUMP_V2; |
||
554 |
else { |
||
555 |
yyerror("unknown mrt dump type"); |
||
556 |
free($3); |
||
557 |
free($4); |
||
558 |
free($5); |
||
559 |
YYERROR; |
||
560 |
} |
||
561 |
free($4); |
||
562 |
if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) { |
||
563 |
free($3); |
||
564 |
free($5); |
||
565 |
YYERROR; |
||
566 |
} |
||
567 |
free($3); |
||
568 |
free($5); |
||
569 |
} |
||
570 |
| mrtdump |
||
571 |
| RDE STRING EVALUATE { |
||
572 |
if (!strcmp($2, "route-age")) |
||
573 |
conf->flags |= BGPD_FLAG_DECISION_ROUTEAGE; |
||
574 |
else { |
||
575 |
yyerror("unknown route decision type"); |
||
576 |
free($2); |
||
577 |
YYERROR; |
||
578 |
} |
||
579 |
free($2); |
||
580 |
} |
||
581 |
| RDE STRING IGNORE { |
||
582 |
if (!strcmp($2, "route-age")) |
||
583 |
conf->flags &= ~BGPD_FLAG_DECISION_ROUTEAGE; |
||
584 |
else { |
||
585 |
yyerror("unknown route decision type"); |
||
586 |
free($2); |
||
587 |
YYERROR; |
||
588 |
} |
||
589 |
free($2); |
||
590 |
} |
||
591 |
| RDE MED COMPARE STRING { |
||
592 |
if (!strcmp($4, "always")) |
||
593 |
conf->flags |= BGPD_FLAG_DECISION_MED_ALWAYS; |
||
594 |
else if (!strcmp($4, "strict")) |
||
595 |
conf->flags &= ~BGPD_FLAG_DECISION_MED_ALWAYS; |
||
596 |
else { |
||
597 |
yyerror("rde med compare: " |
||
598 |
"unknown setting \"%s\"", $4); |
||
599 |
free($4); |
||
600 |
YYERROR; |
||
601 |
} |
||
602 |
free($4); |
||
603 |
} |
||
604 |
| NEXTHOP QUALIFY VIA STRING { |
||
605 |
if (!strcmp($4, "bgp")) |
||
606 |
conf->flags |= BGPD_FLAG_NEXTHOP_BGP; |
||
607 |
else if (!strcmp($4, "default")) |
||
608 |
conf->flags |= BGPD_FLAG_NEXTHOP_DEFAULT; |
||
609 |
else { |
||
610 |
yyerror("nexthop depend on: " |
||
611 |
"unknown setting \"%s\"", $4); |
||
612 |
free($4); |
||
613 |
YYERROR; |
||
614 |
} |
||
615 |
free($4); |
||
616 |
} |
||
617 |
| RTABLE NUMBER { |
||
618 |
struct rde_rib *rr; |
||
619 |
if (ktable_exists($2, NULL) != 1) { |
||
620 |
yyerror("rtable id %lld does not exist", $2); |
||
621 |
YYERROR; |
||
622 |
} |
||
623 |
rr = find_rib("Loc-RIB"); |
||
624 |
if (rr == NULL) |
||
625 |
fatalx("RTABLE can not find the main RIB!"); |
||
626 |
rr->rtableid = $2; |
||
627 |
} |
||
628 |
| CONNECTRETRY NUMBER { |
||
629 |
if ($2 > USHRT_MAX || $2 < 1) { |
||
630 |
yyerror("invalid connect-retry"); |
||
631 |
YYERROR; |
||
632 |
} |
||
633 |
conf->connectretry = $2; |
||
634 |
} |
||
635 |
| SOCKET STRING restricted { |
||
636 |
if (strlen($2) >= |
||
637 |
sizeof(((struct sockaddr_un *)0)->sun_path)) { |
||
638 |
yyerror("socket path too long"); |
||
639 |
YYERROR; |
||
640 |
} |
||
641 |
if ($3) { |
||
642 |
free(conf->rcsock); |
||
643 |
conf->rcsock = $2; |
||
644 |
} else { |
||
645 |
free(conf->csock); |
||
646 |
conf->csock = $2; |
||
647 |
} |
||
648 |
} |
||
649 |
; |
||
650 |
|||
651 |
mrtdump : DUMP STRING inout STRING optnumber { |
||
652 |
int action; |
||
653 |
|||
654 |
if ($5 < 0 || $5 > INT_MAX) { |
||
655 |
yyerror("bad timeout"); |
||
656 |
free($2); |
||
657 |
free($4); |
||
658 |
YYERROR; |
||
659 |
} |
||
660 |
if (!strcmp($2, "all")) |
||
661 |
action = $3 ? MRT_ALL_IN : MRT_ALL_OUT; |
||
662 |
else if (!strcmp($2, "updates")) |
||
663 |
action = $3 ? MRT_UPDATE_IN : MRT_UPDATE_OUT; |
||
664 |
else { |
||
665 |
yyerror("unknown mrt msg dump type"); |
||
666 |
free($2); |
||
667 |
free($4); |
||
668 |
YYERROR; |
||
669 |
} |
||
670 |
if (add_mrtconfig(action, $4, $5, curpeer, NULL) == |
||
671 |
-1) { |
||
672 |
free($2); |
||
673 |
free($4); |
||
674 |
YYERROR; |
||
675 |
} |
||
676 |
free($2); |
||
677 |
free($4); |
||
678 |
} |
||
679 |
; |
||
680 |
|||
681 |
network : NETWORK prefix filter_set { |
||
682 |
struct network *n, *m; |
||
683 |
|||
684 |
if ((n = calloc(1, sizeof(struct network))) == NULL) |
||
685 |
fatal("new_network"); |
||
686 |
memcpy(&n->net.prefix, &$2.prefix, |
||
687 |
sizeof(n->net.prefix)); |
||
688 |
n->net.prefixlen = $2.len; |
||
689 |
filterset_move($3, &n->net.attrset); |
||
690 |
free($3); |
||
691 |
TAILQ_FOREACH(m, netconf, entry) { |
||
692 |
if (n->net.prefixlen == m->net.prefixlen && |
||
693 |
prefix_compare(&n->net.prefix, |
||
694 |
&m->net.prefix, n->net.prefixlen) == 0) |
||
695 |
yyerror("duplicate prefix " |
||
696 |
"in network statement"); |
||
697 |
} |
||
698 |
|||
699 |
TAILQ_INSERT_TAIL(netconf, n, entry); |
||
700 |
} |
||
701 |
| NETWORK family RTLABEL STRING filter_set { |
||
702 |
struct network *n; |
||
703 |
|||
704 |
if ((n = calloc(1, sizeof(struct network))) == NULL) |
||
705 |
fatal("new_network"); |
||
706 |
if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) == |
||
707 |
-1) { |
||
708 |
yyerror("unknown family"); |
||
709 |
filterset_free($5); |
||
710 |
free($5); |
||
711 |
YYERROR; |
||
712 |
} |
||
713 |
n->net.type = NETWORK_RTLABEL; |
||
714 |
n->net.rtlabel = rtlabel_name2id($4); |
||
715 |
filterset_move($5, &n->net.attrset); |
||
716 |
free($5); |
||
717 |
|||
718 |
TAILQ_INSERT_TAIL(netconf, n, entry); |
||
719 |
} |
||
720 |
| NETWORK family nettype filter_set { |
||
721 |
struct network *n; |
||
722 |
|||
723 |
if ((n = calloc(1, sizeof(struct network))) == NULL) |
||
724 |
fatal("new_network"); |
||
725 |
if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) == |
||
726 |
-1) { |
||
727 |
yyerror("unknown family"); |
||
728 |
filterset_free($4); |
||
729 |
free($4); |
||
730 |
YYERROR; |
||
731 |
} |
||
732 |
n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED; |
||
733 |
filterset_move($4, &n->net.attrset); |
||
734 |
free($4); |
||
735 |
|||
736 |
TAILQ_INSERT_TAIL(netconf, n, entry); |
||
737 |
} |
||
738 |
; |
||
739 |
|||
740 |
inout : IN { $$ = 1; } |
||
741 |
| OUT { $$ = 0; } |
||
742 |
; |
||
743 |
|||
744 |
restricted : RESTRICTED { $$ = 1; } |
||
745 |
| /* nothing */ { $$ = 0; } |
||
746 |
; |
||
747 |
|||
748 |
address : STRING { |
||
749 |
u_int8_t len; |
||
750 |
|||
751 |
if (!host($1, &$$, &len)) { |
||
752 |
yyerror("could not parse address spec \"%s\"", |
||
753 |
$1); |
||
754 |
free($1); |
||
755 |
YYERROR; |
||
756 |
} |
||
757 |
free($1); |
||
758 |
|||
759 |
if (($$.aid == AID_INET && len != 32) || |
||
760 |
($$.aid == AID_INET6 && len != 128)) { |
||
761 |
/* unreachable */ |
||
762 |
yyerror("got prefixlen %u, expected %u", |
||
763 |
len, $$.aid == AID_INET ? 32 : 128); |
||
764 |
YYERROR; |
||
765 |
} |
||
766 |
} |
||
767 |
; |
||
768 |
|||
769 |
prefix : STRING '/' NUMBER { |
||
770 |
char *s; |
||
771 |
|||
772 |
if ($3 < 0 || $3 > 128) { |
||
773 |
yyerror("bad prefixlen %lld", $3); |
||
774 |
free($1); |
||
775 |
YYERROR; |
||
776 |
} |
||
777 |
if (asprintf(&s, "%s/%lld", $1, $3) == -1) |
||
778 |
fatal(NULL); |
||
779 |
free($1); |
||
780 |
|||
781 |
if (!host(s, &$$.prefix, &$$.len)) { |
||
782 |
yyerror("could not parse address \"%s\"", s); |
||
783 |
free(s); |
||
784 |
YYERROR; |
||
785 |
} |
||
786 |
free(s); |
||
787 |
} |
||
788 |
| NUMBER '/' NUMBER { |
||
789 |
char *s; |
||
790 |
|||
791 |
/* does not match IPv6 */ |
||
792 |
if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 32) { |
||
793 |
yyerror("bad prefix %lld/%lld", $1, $3); |
||
794 |
YYERROR; |
||
795 |
} |
||
796 |
if (asprintf(&s, "%lld/%lld", $1, $3) == -1) |
||
797 |
fatal(NULL); |
||
798 |
|||
799 |
if (!host(s, &$$.prefix, &$$.len)) { |
||
800 |
yyerror("could not parse address \"%s\"", s); |
||
801 |
free(s); |
||
802 |
YYERROR; |
||
803 |
} |
||
804 |
free(s); |
||
805 |
} |
||
806 |
; |
||
807 |
|||
808 |
addrspec : address { |
||
809 |
memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr)); |
||
810 |
if ($$.prefix.aid == AID_INET) |
||
811 |
$$.len = 32; |
||
812 |
else |
||
813 |
$$.len = 128; |
||
814 |
} |
||
815 |
| prefix |
||
816 |
; |
||
817 |
|||
818 |
optnl : '\n' optnl |
||
819 |
| |
||
820 |
; |
||
821 |
|||
822 |
nl : '\n' optnl /* one newline or more */ |
||
823 |
; |
||
824 |
|||
825 |
optnumber : /* empty */ { $$ = 0; } |
||
826 |
| NUMBER |
||
827 |
; |
||
828 |
|||
829 |
rdomain : RDOMAIN NUMBER optnl '{' optnl { |
||
830 |
if (ktable_exists($2, NULL) != 1) { |
||
831 |
yyerror("rdomain %lld does not exist", $2); |
||
832 |
YYERROR; |
||
833 |
} |
||
834 |
if (!(currdom = calloc(1, sizeof(struct rdomain)))) |
||
835 |
fatal(NULL); |
||
836 |
currdom->rtableid = $2; |
||
837 |
TAILQ_INIT(&currdom->import); |
||
838 |
TAILQ_INIT(&currdom->export); |
||
839 |
TAILQ_INIT(&currdom->net_l); |
||
840 |
netconf = &currdom->net_l; |
||
841 |
} |
||
842 |
rdomainopts_l '}' { |
||
843 |
/* insert into list */ |
||
844 |
SIMPLEQ_INSERT_TAIL(&conf->rdomains, currdom, entry); |
||
845 |
currdom = NULL; |
||
846 |
netconf = &conf->networks; |
||
847 |
} |
||
848 |
|||
849 |
rdomainopts_l : rdomainopts_l rdomainoptsl |
||
850 |
| rdomainoptsl |
||
851 |
; |
||
852 |
|||
853 |
rdomainoptsl : rdomainopts nl |
||
854 |
; |
||
855 |
|||
856 |
rdomainopts : RD STRING { |
||
857 |
struct filter_extcommunity ext; |
||
858 |
u_int64_t rd; |
||
859 |
|||
860 |
if (parseextcommunity(&ext, "rt", $2) == -1) { |
||
861 |
free($2); |
||
862 |
YYERROR; |
||
863 |
} |
||
864 |
free($2); |
||
865 |
/* |
||
866 |
* RD is almost encode like an ext-community, |
||
867 |
* but only almost so convert here. |
||
868 |
*/ |
||
869 |
if (community_ext_conv(&ext, 0, &rd)) { |
||
870 |
yyerror("bad encoding of rd"); |
||
871 |
YYERROR; |
||
872 |
} |
||
873 |
rd = betoh64(rd) & 0xffffffffffffULL; |
||
874 |
switch (ext.type) { |
||
875 |
case EXT_COMMUNITY_TRANS_TWO_AS: |
||
876 |
rd |= (0ULL << 48); |
||
877 |
break; |
||
878 |
case EXT_COMMUNITY_TRANS_IPV4: |
||
879 |
rd |= (1ULL << 48); |
||
880 |
break; |
||
881 |
case EXT_COMMUNITY_TRANS_FOUR_AS: |
||
882 |
rd |= (2ULL << 48); |
||
883 |
break; |
||
884 |
default: |
||
885 |
yyerror("bad encoding of rd"); |
||
886 |
YYERROR; |
||
887 |
} |
||
888 |
currdom->rd = htobe64(rd); |
||
889 |
} |
||
890 |
| EXPORTTRGT STRING STRING { |
||
891 |
struct filter_set *set; |
||
892 |
|||
893 |
if ((set = calloc(1, sizeof(struct filter_set))) == |
||
894 |
NULL) |
||
895 |
fatal(NULL); |
||
896 |
set->type = ACTION_SET_EXT_COMMUNITY; |
||
897 |
if (parseextcommunity(&set->action.ext_community, |
||
898 |
$2, $3) == -1) { |
||
899 |
free($3); |
||
900 |
free($2); |
||
901 |
free(set); |
||
902 |
YYERROR; |
||
903 |
} |
||
904 |
free($3); |
||
905 |
free($2); |
||
906 |
TAILQ_INSERT_TAIL(&currdom->export, set, entry); |
||
907 |
} |
||
908 |
| IMPORTTRGT STRING STRING { |
||
909 |
struct filter_set *set; |
||
910 |
|||
911 |
if ((set = calloc(1, sizeof(struct filter_set))) == |
||
912 |
NULL) |
||
913 |
fatal(NULL); |
||
914 |
set->type = ACTION_SET_EXT_COMMUNITY; |
||
915 |
if (parseextcommunity(&set->action.ext_community, |
||
916 |
$2, $3) == -1) { |
||
917 |
free($3); |
||
918 |
free($2); |
||
919 |
free(set); |
||
920 |
YYERROR; |
||
921 |
} |
||
922 |
free($3); |
||
923 |
free($2); |
||
924 |
TAILQ_INSERT_TAIL(&currdom->import, set, entry); |
||
925 |
} |
||
926 |
| DESCR string { |
||
927 |
if (strlcpy(currdom->descr, $2, |
||
928 |
sizeof(currdom->descr)) >= |
||
929 |
sizeof(currdom->descr)) { |
||
930 |
yyerror("descr \"%s\" too long: max %zu", |
||
931 |
$2, sizeof(currdom->descr) - 1); |
||
932 |
free($2); |
||
933 |
YYERROR; |
||
934 |
} |
||
935 |
free($2); |
||
936 |
} |
||
937 |
| FIBUPDATE yesno { |
||
938 |
if ($2 == 0) |
||
939 |
currdom->flags |= F_RIB_NOFIBSYNC; |
||
940 |
else |
||
941 |
currdom->flags &= ~F_RIB_NOFIBSYNC; |
||
942 |
} |
||
943 |
| network |
||
944 |
| DEPEND ON STRING { |
||
945 |
/* XXX this is a hack */ |
||
946 |
if (if_nametoindex($3) == 0) { |
||
947 |
yyerror("interface %s does not exist", $3); |
||
948 |
free($3); |
||
949 |
YYERROR; |
||
950 |
} |
||
951 |
strlcpy(currdom->ifmpe, $3, IFNAMSIZ); |
||
952 |
free($3); |
||
953 |
if (get_mpe_label(currdom)) { |
||
954 |
yyerror("failed to get mpls label from %s", |
||
955 |
currdom->ifmpe); |
||
956 |
YYERROR; |
||
957 |
} |
||
958 |
} |
||
959 |
; |
||
960 |
|||
961 |
neighbor : { curpeer = new_peer(); } |
||
962 |
NEIGHBOR addrspec { |
||
963 |
memcpy(&curpeer->conf.remote_addr, &$3.prefix, |
||
964 |
sizeof(curpeer->conf.remote_addr)); |
||
965 |
curpeer->conf.remote_masklen = $3.len; |
||
966 |
if (($3.prefix.aid == AID_INET && $3.len != 32) || |
||
967 |
($3.prefix.aid == AID_INET6 && $3.len != 128)) |
||
968 |
curpeer->conf.template = 1; |
||
969 |
if (curpeer->conf.capabilities.mp[ |
||
970 |
curpeer->conf.remote_addr.aid] == -1) |
||
971 |
curpeer->conf.capabilities.mp[ |
||
972 |
curpeer->conf.remote_addr.aid] = 1; |
||
973 |
if (get_id(curpeer)) { |
||
974 |
yyerror("get_id failed"); |
||
975 |
YYERROR; |
||
976 |
} |
||
977 |
} |
||
978 |
peeropts_h { |
||
979 |
if (curpeer_filter[0] != NULL) |
||
980 |
TAILQ_INSERT_TAIL(peerfilter_l, |
||
981 |
curpeer_filter[0], entry); |
||
982 |
if (curpeer_filter[1] != NULL) |
||
983 |
TAILQ_INSERT_TAIL(peerfilter_l, |
||
984 |
curpeer_filter[1], entry); |
||
985 |
curpeer_filter[0] = NULL; |
||
986 |
curpeer_filter[1] = NULL; |
||
987 |
|||
988 |
if (neighbor_consistent(curpeer) == -1) |
||
989 |
YYERROR; |
||
990 |
curpeer->next = peer_l; |
||
991 |
peer_l = curpeer; |
||
992 |
curpeer = curgroup; |
||
993 |
} |
||
994 |
; |
||
995 |
|||
996 |
group : GROUP string optnl '{' optnl { |
||
997 |
curgroup = curpeer = new_group(); |
||
998 |
if (strlcpy(curgroup->conf.group, $2, |
||
999 |
sizeof(curgroup->conf.group)) >= |
||
1000 |
sizeof(curgroup->conf.group)) { |
||
1001 |
yyerror("group name \"%s\" too long: max %zu", |
||
1002 |
$2, sizeof(curgroup->conf.group) - 1); |
||
1003 |
free($2); |
||
1004 |
YYERROR; |
||
1005 |
} |
||
1006 |
free($2); |
||
1007 |
if (get_id(curgroup)) { |
||
1008 |
yyerror("get_id failed"); |
||
1009 |
YYERROR; |
||
1010 |
} |
||
1011 |
} |
||
1012 |
groupopts_l '}' { |
||
1013 |
if (curgroup_filter[0] != NULL) |
||
1014 |
TAILQ_INSERT_TAIL(groupfilter_l, |
||
1015 |
curgroup_filter[0], entry); |
||
1016 |
if (curgroup_filter[1] != NULL) |
||
1017 |
TAILQ_INSERT_TAIL(groupfilter_l, |
||
1018 |
curgroup_filter[1], entry); |
||
1019 |
curgroup_filter[0] = NULL; |
||
1020 |
curgroup_filter[1] = NULL; |
||
1021 |
|||
1022 |
free(curgroup); |
||
1023 |
curgroup = NULL; |
||
1024 |
} |
||
1025 |
; |
||
1026 |
|||
1027 |
groupopts_l : groupopts_l groupoptsl |
||
1028 |
| groupoptsl |
||
1029 |
; |
||
1030 |
|||
1031 |
groupoptsl : peeropts nl |
||
1032 |
| neighbor nl |
||
1033 |
| error nl |
||
1034 |
; |
||
1035 |
|||
1036 |
peeropts_h : '{' optnl peeropts_l '}' |
||
1037 |
| /* empty */ |
||
1038 |
; |
||
1039 |
|||
1040 |
peeropts_l : peeropts_l peeroptsl |
||
1041 |
| peeroptsl |
||
1042 |
; |
||
1043 |
|||
1044 |
peeroptsl : peeropts nl |
||
1045 |
; |
||
1046 |
|||
1047 |
peeropts : REMOTEAS as4number { |
||
1048 |
curpeer->conf.remote_as = $2; |
||
1049 |
} |
||
1050 |
| LOCALAS as4number { |
||
1051 |
curpeer->conf.local_as = $2; |
||
1052 |
if ($2 > USHRT_MAX) |
||
1053 |
curpeer->conf.local_short_as = AS_TRANS; |
||
1054 |
else |
||
1055 |
curpeer->conf.local_short_as = $2; |
||
1056 |
} |
||
1057 |
| LOCALAS as4number asnumber { |
||
1058 |
curpeer->conf.local_as = $2; |
||
1059 |
curpeer->conf.local_short_as = $3; |
||
1060 |
} |
||
1061 |
| DESCR string { |
||
1062 |
if (strlcpy(curpeer->conf.descr, $2, |
||
1063 |
sizeof(curpeer->conf.descr)) >= |
||
1064 |
sizeof(curpeer->conf.descr)) { |
||
1065 |
yyerror("descr \"%s\" too long: max %zu", |
||
1066 |
$2, sizeof(curpeer->conf.descr) - 1); |
||
1067 |
free($2); |
||
1068 |
YYERROR; |
||
1069 |
} |
||
1070 |
free($2); |
||
1071 |
} |
||
1072 |
| LOCALADDR address { |
||
1073 |
memcpy(&curpeer->conf.local_addr, &$2, |
||
1074 |
sizeof(curpeer->conf.local_addr)); |
||
1075 |
} |
||
1076 |
| MULTIHOP NUMBER { |
||
1077 |
if ($2 < 2 || $2 > 255) { |
||
1078 |
yyerror("invalid multihop distance %lld", $2); |
||
1079 |
YYERROR; |
||
1080 |
} |
||
1081 |
curpeer->conf.distance = $2; |
||
1082 |
} |
||
1083 |
| PASSIVE { |
||
1084 |
curpeer->conf.passive = 1; |
||
1085 |
} |
||
1086 |
| DOWN { |
||
1087 |
curpeer->conf.down = 1; |
||
1088 |
} |
||
1089 |
| DOWN STRING { |
||
1090 |
curpeer->conf.down = 1; |
||
1091 |
if (strlcpy(curpeer->conf.shutcomm, $2, |
||
1092 |
sizeof(curpeer->conf.shutcomm)) >= |
||
1093 |
sizeof(curpeer->conf.shutcomm)) { |
||
1094 |
yyerror("shutdown reason too long"); |
||
1095 |
free($2); |
||
1096 |
YYERROR; |
||
1097 |
} |
||
1098 |
free($2); |
||
1099 |
} |
||
1100 |
| RIB STRING { |
||
1101 |
if (!find_rib($2)) { |
||
1102 |
yyerror("rib \"%s\" does not exist.", $2); |
||
1103 |
free($2); |
||
1104 |
YYERROR; |
||
1105 |
} |
||
1106 |
if (strlcpy(curpeer->conf.rib, $2, |
||
1107 |
sizeof(curpeer->conf.rib)) >= |
||
1108 |
sizeof(curpeer->conf.rib)) { |
||
1109 |
yyerror("rib name \"%s\" too long: max %zu", |
||
1110 |
$2, sizeof(curpeer->conf.rib) - 1); |
||
1111 |
free($2); |
||
1112 |
YYERROR; |
||
1113 |
} |
||
1114 |
free($2); |
||
1115 |
} |
||
1116 |
| HOLDTIME NUMBER { |
||
1117 |
if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) { |
||
1118 |
yyerror("holdtime must be between %u and %u", |
||
1119 |
MIN_HOLDTIME, USHRT_MAX); |
||
1120 |
YYERROR; |
||
1121 |
} |
||
1122 |
curpeer->conf.holdtime = $2; |
||
1123 |
} |
||
1124 |
| HOLDTIME YMIN NUMBER { |
||
1125 |
if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) { |
||
1126 |
yyerror("holdtime must be between %u and %u", |
||
1127 |
MIN_HOLDTIME, USHRT_MAX); |
||
1128 |
YYERROR; |
||
1129 |
} |
||
1130 |
curpeer->conf.min_holdtime = $3; |
||
1131 |
} |
||
1132 |
| ANNOUNCE family STRING { |
||
1133 |
u_int8_t aid, safi; |
||
1134 |
int8_t val = 1; |
||
1135 |
|||
1136 |
if (!strcmp($3, "none")) { |
||
1137 |
safi = SAFI_UNICAST; |
||
1138 |
val = 0; |
||
1139 |
} else if (!strcmp($3, "unicast")) { |
||
1140 |
safi = SAFI_UNICAST; |
||
1141 |
} else if (!strcmp($3, "vpn")) { |
||
1142 |
safi = SAFI_MPLSVPN; |
||
1143 |
} else { |
||
1144 |
yyerror("unknown/unsupported SAFI \"%s\"", |
||
1145 |
$3); |
||
1146 |
free($3); |
||
1147 |
YYERROR; |
||
1148 |
} |
||
1149 |
free($3); |
||
1150 |
|||
1151 |
if (afi2aid($2, safi, &aid) == -1) { |
||
1152 |
yyerror("unknown AFI/SAFI pair"); |
||
1153 |
YYERROR; |
||
1154 |
} |
||
1155 |
curpeer->conf.capabilities.mp[aid] = val; |
||
1156 |
} |
||
1157 |
| ANNOUNCE CAPABILITIES yesno { |
||
1158 |
curpeer->conf.announce_capa = $3; |
||
1159 |
} |
||
1160 |
| ANNOUNCE REFRESH yesno { |
||
1161 |
curpeer->conf.capabilities.refresh = $3; |
||
1162 |
} |
||
1163 |
| ANNOUNCE RESTART yesno { |
||
1164 |
curpeer->conf.capabilities.grestart.restart = $3; |
||
1165 |
} |
||
1166 |
| ANNOUNCE AS4BYTE yesno { |
||
1167 |
curpeer->conf.capabilities.as4byte = $3; |
||
1168 |
} |
||
1169 |
| ANNOUNCE SELF { |
||
1170 |
curpeer->conf.announce_type = ANNOUNCE_SELF; |
||
1171 |
} |
||
1172 |
| ANNOUNCE STRING { |
||
1173 |
if (!strcmp($2, "self")) |
||
1174 |
curpeer->conf.announce_type = ANNOUNCE_SELF; |
||
1175 |
else if (!strcmp($2, "none")) |
||
1176 |
curpeer->conf.announce_type = ANNOUNCE_NONE; |
||
1177 |
else if (!strcmp($2, "all")) |
||
1178 |
curpeer->conf.announce_type = ANNOUNCE_ALL; |
||
1179 |
else if (!strcmp($2, "default-route")) |
||
1180 |
curpeer->conf.announce_type = |
||
1181 |
ANNOUNCE_DEFAULT_ROUTE; |
||
1182 |
else { |
||
1183 |
yyerror("invalid announce type"); |
||
1184 |
free($2); |
||
1185 |
YYERROR; |
||
1186 |
} |
||
1187 |
free($2); |
||
1188 |
} |
||
1189 |
| ENFORCE NEIGHBORAS yesno { |
||
1190 |
if ($3) |
||
1191 |
curpeer->conf.enforce_as = ENFORCE_AS_ON; |
||
1192 |
else |
||
1193 |
curpeer->conf.enforce_as = ENFORCE_AS_OFF; |
||
1194 |
} |
||
1195 |
| ENFORCE LOCALAS yesno { |
||
1196 |
if ($3) |
||
1197 |
curpeer->conf.enforce_local_as = ENFORCE_AS_ON; |
||
1198 |
else |
||
1199 |
curpeer->conf.enforce_local_as = ENFORCE_AS_OFF; |
||
1200 |
} |
||
1201 |
| MAXPREFIX NUMBER restart { |
||
1202 |
if ($2 < 0 || $2 > UINT_MAX) { |
||
1203 |
yyerror("bad maximum number of prefixes"); |
||
1204 |
YYERROR; |
||
1205 |
} |
||
1206 |
curpeer->conf.max_prefix = $2; |
||
1207 |
curpeer->conf.max_prefix_restart = $3; |
||
1208 |
} |
||
1209 |
| TCP MD5SIG PASSWORD string { |
||
1210 |
if (curpeer->conf.auth.method) { |
||
1211 |
yyerror("auth method cannot be redefined"); |
||
1212 |
free($4); |
||
1213 |
YYERROR; |
||
1214 |
} |
||
1215 |
if (strlcpy(curpeer->conf.auth.md5key, $4, |
||
1216 |
sizeof(curpeer->conf.auth.md5key)) >= |
||
1217 |
sizeof(curpeer->conf.auth.md5key)) { |
||
1218 |
yyerror("tcp md5sig password too long: max %zu", |
||
1219 |
sizeof(curpeer->conf.auth.md5key) - 1); |
||
1220 |
free($4); |
||
1221 |
YYERROR; |
||
1222 |
} |
||
1223 |
curpeer->conf.auth.method = AUTH_MD5SIG; |
||
1224 |
curpeer->conf.auth.md5key_len = strlen($4); |
||
1225 |
free($4); |
||
1226 |
} |
||
1227 |
| TCP MD5SIG KEY string { |
||
1228 |
if (curpeer->conf.auth.method) { |
||
1229 |
yyerror("auth method cannot be redefined"); |
||
1230 |
free($4); |
||
1231 |
YYERROR; |
||
1232 |
} |
||
1233 |
|||
1234 |
if (str2key($4, curpeer->conf.auth.md5key, |
||
1235 |
sizeof(curpeer->conf.auth.md5key)) == -1) { |
||
1236 |
free($4); |
||
1237 |
YYERROR; |
||
1238 |
} |
||
1239 |
curpeer->conf.auth.method = AUTH_MD5SIG; |
||
1240 |
curpeer->conf.auth.md5key_len = strlen($4) / 2; |
||
1241 |
free($4); |
||
1242 |
} |
||
1243 |
| IPSEC espah IKE { |
||
1244 |
if (curpeer->conf.auth.method) { |
||
1245 |
yyerror("auth method cannot be redefined"); |
||
1246 |
YYERROR; |
||
1247 |
} |
||
1248 |
if ($2) |
||
1249 |
curpeer->conf.auth.method = AUTH_IPSEC_IKE_ESP; |
||
1250 |
else |
||
1251 |
curpeer->conf.auth.method = AUTH_IPSEC_IKE_AH; |
||
1252 |
} |
||
1253 |
| IPSEC espah inout SPI NUMBER STRING STRING encspec { |
||
1254 |
u_int32_t auth_alg; |
||
1255 |
u_int8_t keylen; |
||
1256 |
|||
1257 |
if (curpeer->conf.auth.method && |
||
1258 |
(((curpeer->conf.auth.spi_in && $3 == 1) || |
||
1259 |
(curpeer->conf.auth.spi_out && $3 == 0)) || |
||
1260 |
($2 == 1 && curpeer->conf.auth.method != |
||
1261 |
AUTH_IPSEC_MANUAL_ESP) || |
||
1262 |
($2 == 0 && curpeer->conf.auth.method != |
||
1263 |
AUTH_IPSEC_MANUAL_AH))) { |
||
1264 |
yyerror("auth method cannot be redefined"); |
||
1265 |
free($6); |
||
1266 |
free($7); |
||
1267 |
YYERROR; |
||
1268 |
} |
||
1269 |
|||
1270 |
if (!strcmp($6, "sha1")) { |
||
1271 |
auth_alg = SADB_AALG_SHA1HMAC; |
||
1272 |
keylen = 20; |
||
1273 |
} else if (!strcmp($6, "md5")) { |
||
1274 |
auth_alg = SADB_AALG_MD5HMAC; |
||
1275 |
keylen = 16; |
||
1276 |
} else { |
||
1277 |
yyerror("unknown auth algorithm \"%s\"", $6); |
||
1278 |
free($6); |
||
1279 |
free($7); |
||
1280 |
YYERROR; |
||
1281 |
} |
||
1282 |
free($6); |
||
1283 |
|||
1284 |
if (strlen($7) / 2 != keylen) { |
||
1285 |
yyerror("auth key len: must be %u bytes, " |
||
1286 |
"is %zu bytes", keylen, strlen($7) / 2); |
||
1287 |
free($7); |
||
1288 |
YYERROR; |
||
1289 |
} |
||
1290 |
|||
1291 |
if ($2) |
||
1292 |
curpeer->conf.auth.method = |
||
1293 |
AUTH_IPSEC_MANUAL_ESP; |
||
1294 |
else { |
||
1295 |
if ($8.enc_alg) { |
||
1296 |
yyerror("\"ipsec ah\" doesn't take " |
||
1297 |
"encryption keys"); |
||
1298 |
free($7); |
||
1299 |
YYERROR; |
||
1300 |
} |
||
1301 |
curpeer->conf.auth.method = |
||
1302 |
AUTH_IPSEC_MANUAL_AH; |
||
1303 |
} |
||
1304 |
|||
1305 |
if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) { |
||
1306 |
yyerror("bad spi number %lld", $5); |
||
1307 |
free($7); |
||
1308 |
YYERROR; |
||
1309 |
} |
||
1310 |
|||
1311 |
if ($3 == 1) { |
||
1312 |
if (str2key($7, curpeer->conf.auth.auth_key_in, |
||
1313 |
sizeof(curpeer->conf.auth.auth_key_in)) == |
||
1314 |
-1) { |
||
1315 |
free($7); |
||
1316 |
YYERROR; |
||
1317 |
} |
||
1318 |
curpeer->conf.auth.spi_in = $5; |
||
1319 |
curpeer->conf.auth.auth_alg_in = auth_alg; |
||
1320 |
curpeer->conf.auth.enc_alg_in = $8.enc_alg; |
||
1321 |
memcpy(&curpeer->conf.auth.enc_key_in, |
||
1322 |
&$8.enc_key, |
||
1323 |
sizeof(curpeer->conf.auth.enc_key_in)); |
||
1324 |
curpeer->conf.auth.enc_keylen_in = |
||
1325 |
$8.enc_key_len; |
||
1326 |
curpeer->conf.auth.auth_keylen_in = keylen; |
||
1327 |
} else { |
||
1328 |
if (str2key($7, curpeer->conf.auth.auth_key_out, |
||
1329 |
sizeof(curpeer->conf.auth.auth_key_out)) == |
||
1330 |
-1) { |
||
1331 |
free($7); |
||
1332 |
YYERROR; |
||
1333 |
} |
||
1334 |
curpeer->conf.auth.spi_out = $5; |
||
1335 |
curpeer->conf.auth.auth_alg_out = auth_alg; |
||
1336 |
curpeer->conf.auth.enc_alg_out = $8.enc_alg; |
||
1337 |
memcpy(&curpeer->conf.auth.enc_key_out, |
||
1338 |
&$8.enc_key, |
||
1339 |
sizeof(curpeer->conf.auth.enc_key_out)); |
||
1340 |
curpeer->conf.auth.enc_keylen_out = |
||
1341 |
$8.enc_key_len; |
||
1342 |
curpeer->conf.auth.auth_keylen_out = keylen; |
||
1343 |
} |
||
1344 |
free($7); |
||
1345 |
} |
||
1346 |
| TTLSECURITY yesno { |
||
1347 |
curpeer->conf.ttlsec = $2; |
||
1348 |
} |
||
1349 |
| SET filter_set_opt { |
||
1350 |
struct filter_rule *r; |
||
1351 |
|||
1352 |
r = get_rule($2->type); |
||
1353 |
if (merge_filterset(&r->set, $2) == -1) |
||
1354 |
YYERROR; |
||
1355 |
} |
||
1356 |
| SET optnl "{" optnl filter_set_l optnl "}" { |
||
1357 |
struct filter_rule *r; |
||
1358 |
struct filter_set *s; |
||
1359 |
|||
1360 |
while ((s = TAILQ_FIRST($5)) != NULL) { |
||
1361 |
TAILQ_REMOVE($5, s, entry); |
||
1362 |
r = get_rule(s->type); |
||
1363 |
if (merge_filterset(&r->set, s) == -1) |
||
1364 |
YYERROR; |
||
1365 |
} |
||
1366 |
free($5); |
||
1367 |
} |
||
1368 |
| mrtdump |
||
1369 |
| REFLECTOR { |
||
1370 |
if ((conf->flags & BGPD_FLAG_REFLECTOR) && |
||
1371 |
conf->clusterid != 0) { |
||
1372 |
yyerror("only one route reflector " |
||
1373 |
"cluster allowed"); |
||
1374 |
YYERROR; |
||
1375 |
} |
||
1376 |
conf->flags |= BGPD_FLAG_REFLECTOR; |
||
1377 |
curpeer->conf.reflector_client = 1; |
||
1378 |
} |
||
1379 |
| REFLECTOR address { |
||
1380 |
if ($2.aid != AID_INET) { |
||
1381 |
yyerror("route reflector cluster-id must be " |
||
1382 |
"an IPv4 address"); |
||
1383 |
YYERROR; |
||
1384 |
} |
||
1385 |
if ((conf->flags & BGPD_FLAG_REFLECTOR) && |
||
1386 |
conf->clusterid != $2.v4.s_addr) { |
||
1387 |
yyerror("only one route reflector " |
||
1388 |
"cluster allowed"); |
||
1389 |
YYERROR; |
||
1390 |
} |
||
1391 |
conf->flags |= BGPD_FLAG_REFLECTOR; |
||
1392 |
curpeer->conf.reflector_client = 1; |
||
1393 |
conf->clusterid = $2.v4.s_addr; |
||
1394 |
} |
||
1395 |
| DEPEND ON STRING { |
||
1396 |
if (strlcpy(curpeer->conf.if_depend, $3, |
||
1397 |
sizeof(curpeer->conf.if_depend)) >= |
||
1398 |
sizeof(curpeer->conf.if_depend)) { |
||
1399 |
yyerror("interface name \"%s\" too long: " |
||
1400 |
"max %zu", $3, |
||
1401 |
sizeof(curpeer->conf.if_depend) - 1); |
||
1402 |
free($3); |
||
1403 |
YYERROR; |
||
1404 |
} |
||
1405 |
free($3); |
||
1406 |
} |
||
1407 |
| DEMOTE STRING { |
||
1408 |
if (strlcpy(curpeer->conf.demote_group, $2, |
||
1409 |
sizeof(curpeer->conf.demote_group)) >= |
||
1410 |
sizeof(curpeer->conf.demote_group)) { |
||
1411 |
yyerror("demote group name \"%s\" too long: " |
||
1412 |
"max %zu", $2, |
||
1413 |
sizeof(curpeer->conf.demote_group) - 1); |
||
1414 |
free($2); |
||
1415 |
YYERROR; |
||
1416 |
} |
||
1417 |
free($2); |
||
1418 |
if (carp_demote_init(curpeer->conf.demote_group, |
||
1419 |
cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) { |
||
1420 |
yyerror("error initializing group \"%s\"", |
||
1421 |
curpeer->conf.demote_group); |
||
1422 |
YYERROR; |
||
1423 |
} |
||
1424 |
} |
||
1425 |
| TRANSPARENT yesno { |
||
1426 |
if ($2 == 1) |
||
1427 |
curpeer->conf.flags |= PEERFLAG_TRANS_AS; |
||
1428 |
else |
||
1429 |
curpeer->conf.flags &= ~PEERFLAG_TRANS_AS; |
||
1430 |
} |
||
1431 |
| LOG STRING { |
||
1432 |
if (!strcmp($2, "updates")) |
||
1433 |
curpeer->conf.flags |= PEERFLAG_LOG_UPDATES; |
||
1434 |
else if (!strcmp($2, "no")) |
||
1435 |
curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES; |
||
1436 |
else { |
||
1437 |
free($2); |
||
1438 |
YYERROR; |
||
1439 |
} |
||
1440 |
free($2); |
||
1441 |
} |
||
1442 |
; |
||
1443 |
|||
1444 |
restart : /* nada */ { $$ = 0; } |
||
1445 |
| RESTART NUMBER { |
||
1446 |
if ($2 < 1 || $2 > USHRT_MAX) { |
||
1447 |
yyerror("restart out of range. 1 to %u minutes", |
||
1448 |
USHRT_MAX); |
||
1449 |
YYERROR; |
||
1450 |
} |
||
1451 |
$$ = $2; |
||
1452 |
} |
||
1453 |
; |
||
1454 |
|||
1455 |
family : IPV4 { $$ = AFI_IPv4; } |
||
1456 |
| IPV6 { $$ = AFI_IPv6; } |
||
1457 |
; |
||
1458 |
|||
1459 |
nettype : STATIC { $$ = 1; }, |
||
1460 |
| CONNECTED { $$ = 0; } |
||
1461 |
; |
||
1462 |
|||
1463 |
espah : ESP { $$ = 1; } |
||
1464 |
| AH { $$ = 0; } |
||
1465 |
; |
||
1466 |
|||
1467 |
encspec : /* nada */ { |
||
1468 |
bzero(&$$, sizeof($$)); |
||
1469 |
} |
||
1470 |
| STRING STRING { |
||
1471 |
bzero(&$$, sizeof($$)); |
||
1472 |
if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) { |
||
1473 |
$$.enc_alg = SADB_EALG_3DESCBC; |
||
1474 |
$$.enc_key_len = 21; /* XXX verify */ |
||
1475 |
} else if (!strcmp($1, "aes") || |
||
1476 |
!strcmp($1, "aes-128-cbc")) { |
||
1477 |
$$.enc_alg = SADB_X_EALG_AES; |
||
1478 |
$$.enc_key_len = 16; |
||
1479 |
} else { |
||
1480 |
yyerror("unknown enc algorithm \"%s\"", $1); |
||
1481 |
free($1); |
||
1482 |
free($2); |
||
1483 |
YYERROR; |
||
1484 |
} |
||
1485 |
free($1); |
||
1486 |
|||
1487 |
if (strlen($2) / 2 != $$.enc_key_len) { |
||
1488 |
yyerror("enc key length wrong: should be %u " |
||
1489 |
"bytes, is %zu bytes", |
||
1490 |
$$.enc_key_len * 2, strlen($2)); |
||
1491 |
free($2); |
||
1492 |
YYERROR; |
||
1493 |
} |
||
1494 |
|||
1495 |
if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) { |
||
1496 |
free($2); |
||
1497 |
YYERROR; |
||
1498 |
} |
||
1499 |
free($2); |
||
1500 |
} |
||
1501 |
; |
||
1502 |
|||
1503 |
filterrule : action quick filter_rib_h direction filter_peer_h filter_match_h filter_set |
||
1504 |
{ |
||
1505 |
struct filter_rule r; |
||
1506 |
struct filter_rib_l *rb, *rbnext; |
||
1507 |
|||
1508 |
bzero(&r, sizeof(r)); |
||
1509 |
r.action = $1; |
||
1510 |
r.quick = $2; |
||
1511 |
r.dir = $4; |
||
1512 |
if ($3) { |
||
1513 |
if (r.dir != DIR_IN) { |
||
1514 |
yyerror("rib only allowed on \"from\" " |
||
1515 |
"rules."); |
||
1516 |
|||
1517 |
for (rb = $3; rb != NULL; rb = rbnext) { |
||
1518 |
rbnext = rb->next; |
||
1519 |
free(rb); |
||
1520 |
} |
||
1521 |
YYERROR; |
||
1522 |
} |
||
1523 |
} |
||
1524 |
if (expand_rule(&r, $3, $5, &$6, $7) == -1) |
||
1525 |
YYERROR; |
||
1526 |
} |
||
1527 |
; |
||
1528 |
|||
1529 |
action : ALLOW { $$ = ACTION_ALLOW; } |
||
1530 |
| DENY { $$ = ACTION_DENY; } |
||
1531 |
| MATCH { $$ = ACTION_NONE; } |
||
1532 |
; |
||
1533 |
|||
1534 |
quick : /* empty */ { $$ = 0; } |
||
1535 |
| QUICK { $$ = 1; } |
||
1536 |
; |
||
1537 |
|||
1538 |
direction : FROM { $$ = DIR_IN; } |
||
1539 |
| TO { $$ = DIR_OUT; } |
||
1540 |
; |
||
1541 |
|||
1542 |
filter_rib_h : /* empty */ { $$ = NULL; } |
||
1543 |
| RIB filter_rib { $$ = $2; } |
||
1544 |
| RIB '{' filter_rib_l '}' { $$ = $3; } |
||
1545 |
|||
1546 |
filter_rib_l : filter_rib { $$ = $1; } |
||
1547 |
| filter_rib_l comma filter_rib { |
||
1548 |
$3->next = $1; |
||
1549 |
$$ = $3; |
||
1550 |
} |
||
1551 |
; |
||
1552 |
|||
1553 |
filter_rib : STRING { |
||
1554 |
if (!find_rib($1)) { |
||
1555 |
yyerror("rib \"%s\" does not exist.", $1); |
||
1556 |
free($1); |
||
1557 |
YYERROR; |
||
1558 |
} |
||
1559 |
if (($$ = calloc(1, sizeof(struct filter_rib_l))) == |
||
1560 |
NULL) |
||
1561 |
fatal(NULL); |
||
1562 |
$$->next = NULL; |
||
1563 |
if (strlcpy($$->name, $1, sizeof($$->name)) >= |
||
1564 |
sizeof($$->name)) { |
||
1565 |
yyerror("rib name \"%s\" too long: " |
||
1566 |
"max %zu", $1, sizeof($$->name) - 1); |
||
1567 |
free($1); |
||
1568 |
free($$); |
||
1569 |
YYERROR; |
||
1570 |
} |
||
1571 |
free($1); |
||
1572 |
} |
||
1573 |
; |
||
1574 |
|||
1575 |
filter_peer_h : filter_peer |
||
1576 |
| '{' filter_peer_l '}' { $$ = $2; } |
||
1577 |
; |
||
1578 |
|||
1579 |
filter_peer_l : filter_peer { $$ = $1; } |
||
1580 |
| filter_peer_l comma filter_peer { |
||
1581 |
$3->next = $1; |
||
1582 |
$$ = $3; |
||
1583 |
} |
||
1584 |
; |
||
1585 |
|||
1586 |
filter_peer : ANY { |
||
1587 |
if (($$ = calloc(1, sizeof(struct filter_peers_l))) == |
||
1588 |
NULL) |
||
1589 |
fatal(NULL); |
||
1590 |
$$->p.peerid = $$->p.groupid = 0; |
||
1591 |
$$->next = NULL; |
||
1592 |
} |
||
1593 |
| address { |
||
1594 |
struct peer *p; |
||
1595 |
|||
1596 |
if (($$ = calloc(1, sizeof(struct filter_peers_l))) == |
||
1597 |
NULL) |
||
1598 |
fatal(NULL); |
||
1599 |
$$->p.remote_as = $$->p.groupid = $$->p.peerid = 0; |
||
1600 |
$$->next = NULL; |
||
1601 |
for (p = peer_l; p != NULL; p = p->next) |
||
1602 |
if (!memcmp(&p->conf.remote_addr, |
||
1603 |
&$1, sizeof(p->conf.remote_addr))) { |
||
1604 |
$$->p.peerid = p->conf.id; |
||
1605 |
break; |
||
1606 |
} |
||
1607 |
if ($$->p.peerid == 0) { |
||
1608 |
yyerror("no such peer: %s", log_addr(&$1)); |
||
1609 |
free($$); |
||
1610 |
YYERROR; |
||
1611 |
} |
||
1612 |
} |
||
1613 |
| AS as4number { |
||
1614 |
if (($$ = calloc(1, sizeof(struct filter_peers_l))) == |
||
1615 |
NULL) |
||
1616 |
fatal(NULL); |
||
1617 |
$$->p.groupid = $$->p.peerid = 0; |
||
1618 |
$$->p.remote_as = $2; |
||
1619 |
} |
||
1620 |
| GROUP STRING { |
||
1621 |
struct peer *p; |
||
1622 |
|||
1623 |
if (($$ = calloc(1, sizeof(struct filter_peers_l))) == |
||
1624 |
NULL) |
||
1625 |
fatal(NULL); |
||
1626 |
$$->p.remote_as = $$->p.peerid = 0; |
||
1627 |
$$->next = NULL; |
||
1628 |
for (p = peer_l; p != NULL; p = p->next) |
||
1629 |
if (!strcmp(p->conf.group, $2)) { |
||
1630 |
$$->p.groupid = p->conf.groupid; |
||
1631 |
break; |
||
1632 |
} |
||
1633 |
if ($$->p.groupid == 0) { |
||
1634 |
yyerror("no such group: \"%s\"", $2); |
||
1635 |
free($2); |
||
1636 |
free($$); |
||
1637 |
YYERROR; |
||
1638 |
} |
||
1639 |
free($2); |
||
1640 |
} |
||
1641 |
| EBGP { |
||
1642 |
if (($$ = calloc(1, sizeof(struct filter_peers_l))) == |
||
1643 |
NULL) |
||
1644 |
fatal(NULL); |
||
1645 |
$$->p.ebgp = 1; |
||
1646 |
} |
||
1647 |
| IBGP { |
||
1648 |
if (($$ = calloc(1, sizeof(struct filter_peers_l))) == |
||
1649 |
NULL) |
||
1650 |
fatal(NULL); |
||
1651 |
$$->p.ibgp = 1; |
||
1652 |
} |
||
1653 |
; |
||
1654 |
|||
1655 |
filter_prefix_h : IPV4 prefixlenop { |
||
1656 |
if ($2.op == OP_NONE) |
||
1657 |
$2.op = OP_GE; |
||
1658 |
if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == |
||
1659 |
NULL) |
||
1660 |
fatal(NULL); |
||
1661 |
$$->p.addr.aid = AID_INET; |
||
1662 |
if (merge_prefixspec($$, &$2) == -1) { |
||
1663 |
free($$); |
||
1664 |
YYERROR; |
||
1665 |
} |
||
1666 |
} |
||
1667 |
| IPV6 prefixlenop { |
||
1668 |
if ($2.op == OP_NONE) |
||
1669 |
$2.op = OP_GE; |
||
1670 |
if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == |
||
1671 |
NULL) |
||
1672 |
fatal(NULL); |
||
1673 |
$$->p.addr.aid = AID_INET6; |
||
1674 |
if (merge_prefixspec($$, &$2) == -1) { |
||
1675 |
free($$); |
||
1676 |
YYERROR; |
||
1677 |
} |
||
1678 |
} |
||
1679 |
| PREFIX filter_prefix { $$ = $2; } |
||
1680 |
| PREFIX '{' filter_prefix_m '}' { $$ = $3; } |
||
1681 |
; |
||
1682 |
|||
1683 |
filter_prefix_m : filter_prefix_l |
||
1684 |
| '{' filter_prefix_l '}' { $$ = $2; } |
||
1685 |
| '{' filter_prefix_l '}' filter_prefix_m |
||
1686 |
{ |
||
1687 |
struct filter_prefix_l *p; |
||
1688 |
|||
1689 |
/* merge, both can be lists */ |
||
1690 |
for (p = $2; p != NULL && p->next != NULL; p = p->next) |
||
1691 |
; /* nothing */ |
||
1692 |
if (p != NULL) |
||
1693 |
p->next = $4; |
||
1694 |
$$ = $2; |
||
1695 |
} |
||
1696 |
|||
1697 |
filter_prefix_l : filter_prefix { $$ = $1; } |
||
1698 |
| filter_prefix_l comma filter_prefix { |
||
1699 |
$3->next = $1; |
||
1700 |
$$ = $3; |
||
1701 |
} |
||
1702 |
; |
||
1703 |
|||
1704 |
filter_prefix : prefix prefixlenop { |
||
1705 |
if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == |
||
1706 |
NULL) |
||
1707 |
fatal(NULL); |
||
1708 |
memcpy(&$$->p.addr, &$1.prefix, |
||
1709 |
sizeof($$->p.addr)); |
||
1710 |
$$->p.len = $1.len; |
||
1711 |
|||
1712 |
if (merge_prefixspec($$, &$2) == -1) { |
||
1713 |
free($$); |
||
1714 |
YYERROR; |
||
1715 |
} |
||
1716 |
} |
||
1717 |
; |
||
1718 |
|||
1719 |
filter_as_h : filter_as_t |
||
1720 |
| '{' filter_as_t_l '}' { $$ = $2; } |
||
1721 |
; |
||
1722 |
|||
1723 |
filter_as_t_l : filter_as_t |
||
1724 |
| filter_as_t_l comma filter_as_t { |
||
1725 |
struct filter_as_l *a; |
||
1726 |
|||
1727 |
/* merge, both can be lists */ |
||
1728 |
for (a = $1; a != NULL && a->next != NULL; a = a->next) |
||
1729 |
; /* nothing */ |
||
1730 |
if (a != NULL) |
||
1731 |
a->next = $3; |
||
1732 |
$$ = $1; |
||
1733 |
} |
||
1734 |
; |
||
1735 |
|||
1736 |
filter_as_t : filter_as_type filter_as { |
||
1737 |
$$ = $2; |
||
1738 |
$$->a.type = $1; |
||
1739 |
} |
||
1740 |
| filter_as_type '{' filter_as_l_h '}' { |
||
1741 |
struct filter_as_l *a; |
||
1742 |
|||
1743 |
$$ = $3; |
||
1744 |
for (a = $$; a != NULL; a = a->next) |
||
1745 |
a->a.type = $1; |
||
1746 |
} |
||
1747 |
; |
||
1748 |
|||
1749 |
filter_as_l_h : filter_as_l |
||
1750 |
| '{' filter_as_l '}' { $$ = $2; } |
||
1751 |
| '{' filter_as_l '}' filter_as_l_h |
||
1752 |
{ |
||
1753 |
struct filter_as_l *a; |
||
1754 |
|||
1755 |
/* merge, both can be lists */ |
||
1756 |
for (a = $2; a != NULL && a->next != NULL; a = a->next) |
||
1757 |
; /* nothing */ |
||
1758 |
if (a != NULL) |
||
1759 |
a->next = $4; |
||
1760 |
$$ = $2; |
||
1761 |
} |
||
1762 |
; |
||
1763 |
|||
1764 |
filter_as_l : filter_as |
||
1765 |
| filter_as_l comma filter_as { |
||
1766 |
$3->next = $1; |
||
1767 |
$$ = $3; |
||
1768 |
} |
||
1769 |
; |
||
1770 |
|||
1771 |
filter_as : as4number_any { |
||
1772 |
if (($$ = calloc(1, sizeof(struct filter_as_l))) == |
||
1773 |
NULL) |
||
1774 |
fatal(NULL); |
||
1775 |
$$->a.as = $1; |
||
1776 |
$$->a.op = OP_EQ; |
||
1777 |
} |
||
1778 |
| NEIGHBORAS { |
||
1779 |
if (($$ = calloc(1, sizeof(struct filter_as_l))) == |
||
1780 |
NULL) |
||
1781 |
fatal(NULL); |
||
1782 |
$$->a.flags = AS_FLAG_NEIGHBORAS; |
||
1783 |
} |
||
1784 |
| equalityop as4number_any { |
||
1785 |
if (($$ = calloc(1, sizeof(struct filter_as_l))) == |
||
1786 |
NULL) |
||
1787 |
fatal(NULL); |
||
1788 |
$$->a.op = $1; |
||
1789 |
$$->a.as = $2; |
||
1790 |
} |
||
1791 |
| as4number_any binaryop as4number_any { |
||
1792 |
if (($$ = calloc(1, sizeof(struct filter_as_l))) == |
||
1793 |
NULL) |
||
1794 |
fatal(NULL); |
||
1795 |
if ($1 >= $3) { |
||
1796 |
yyerror("start AS is bigger than end"); |
||
1797 |
YYERROR; |
||
1798 |
} |
||
1799 |
$$->a.op = $2; |
||
1800 |
$$->a.as_min = $1; |
||
1801 |
$$->a.as_max = $3; |
||
1802 |
} |
||
1803 |
; |
||
1804 |
|||
1805 |
filter_match_h : /* empty */ { |
||
1806 |
bzero(&$$, sizeof($$)); |
||
1807 |
$$.m.community.as = COMMUNITY_UNSET; |
||
1808 |
$$.m.large_community.as = COMMUNITY_UNSET; |
||
1809 |
} |
||
1810 |
| { |
||
1811 |
bzero(&fmopts, sizeof(fmopts)); |
||
1812 |
fmopts.m.community.as = COMMUNITY_UNSET; |
||
1813 |
fmopts.m.large_community.as = COMMUNITY_UNSET; |
||
1814 |
} |
||
1815 |
filter_match { |
||
1816 |
memcpy(&$$, &fmopts, sizeof($$)); |
||
1817 |
} |
||
1818 |
; |
||
1819 |
|||
1820 |
filter_match : filter_elm |
||
1821 |
| filter_match filter_elm |
||
1822 |
; |
||
1823 |
|||
1824 |
filter_elm : filter_prefix_h { |
||
1825 |
if (fmopts.prefix_l != NULL) { |
||
1826 |
yyerror("\"prefix\" already specified"); |
||
1827 |
YYERROR; |
||
1828 |
} |
||
1829 |
fmopts.prefix_l = $1; |
||
1830 |
} |
||
1831 |
| filter_as_h { |
||
1832 |
if (fmopts.as_l != NULL) { |
||
1833 |
yyerror("AS filters already specified"); |
||
1834 |
YYERROR; |
||
1835 |
} |
||
1836 |
fmopts.as_l = $1; |
||
1837 |
} |
||
1838 |
| MAXASLEN NUMBER { |
||
1839 |
if (fmopts.m.aslen.type != ASLEN_NONE) { |
||
1840 |
yyerror("AS length filters already specified"); |
||
1841 |
YYERROR; |
||
1842 |
} |
||
1843 |
if ($2 < 0 || $2 > UINT_MAX) { |
||
1844 |
yyerror("bad max-as-len %lld", $2); |
||
1845 |
YYERROR; |
||
1846 |
} |
||
1847 |
fmopts.m.aslen.type = ASLEN_MAX; |
||
1848 |
fmopts.m.aslen.aslen = $2; |
||
1849 |
} |
||
1850 |
| MAXASSEQ NUMBER { |
||
1851 |
if (fmopts.m.aslen.type != ASLEN_NONE) { |
||
1852 |
yyerror("AS length filters already specified"); |
||
1853 |
YYERROR; |
||
1854 |
} |
||
1855 |
if ($2 < 0 || $2 > UINT_MAX) { |
||
1856 |
yyerror("bad max-as-seq %lld", $2); |
||
1857 |
YYERROR; |
||
1858 |
} |
||
1859 |
fmopts.m.aslen.type = ASLEN_SEQ; |
||
1860 |
fmopts.m.aslen.aslen = $2; |
||
1861 |
} |
||
1862 |
| COMMUNITY STRING { |
||
1863 |
if (fmopts.m.community.as != COMMUNITY_UNSET) { |
||
1864 |
yyerror("\"community\" already specified"); |
||
1865 |
free($2); |
||
1866 |
YYERROR; |
||
1867 |
} |
||
1868 |
if (parsecommunity(&fmopts.m.community, $2) == -1) { |
||
1869 |
free($2); |
||
1870 |
YYERROR; |
||
1871 |
} |
||
1872 |
free($2); |
||
1873 |
} |
||
1874 |
| LARGECOMMUNITY STRING { |
||
1875 |
if (fmopts.m.large_community.as != COMMUNITY_UNSET) { |
||
1876 |
yyerror("\"large-community\" already specified"); |
||
1877 |
free($2); |
||
1878 |
YYERROR; |
||
1879 |
} |
||
1880 |
if (parselargecommunity(&fmopts.m.large_community, $2) == -1) { |
||
1881 |
free($2); |
||
1882 |
YYERROR; |
||
1883 |
} |
||
1884 |
free($2); |
||
1885 |
} |
||
1886 |
| EXTCOMMUNITY STRING STRING { |
||
1887 |
if (fmopts.m.ext_community.flags & |
||
1888 |
EXT_COMMUNITY_FLAG_VALID) { |
||
1889 |
yyerror("\"ext-community\" already specified"); |
||
1890 |
free($2); |
||
1891 |
free($3); |
||
1892 |
YYERROR; |
||
1893 |
} |
||
1894 |
|||
1895 |
if (parseextcommunity(&fmopts.m.ext_community, |
||
1896 |
$2, $3) == -1) { |
||
1897 |
free($2); |
||
1898 |
free($3); |
||
1899 |
YYERROR; |
||
1900 |
} |
||
1901 |
free($2); |
||
1902 |
free($3); |
||
1903 |
} |
||
1904 |
| NEXTHOP address { |
||
1905 |
if (fmopts.m.nexthop.flags) { |
||
1906 |
yyerror("nexthop already specified"); |
||
1907 |
YYERROR; |
||
1908 |
} |
||
1909 |
fmopts.m.nexthop.addr = $2; |
||
1910 |
fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR; |
||
1911 |
} |
||
1912 |
| NEXTHOP NEIGHBOR { |
||
1913 |
if (fmopts.m.nexthop.flags) { |
||
1914 |
yyerror("nexthop already specified"); |
||
1915 |
YYERROR; |
||
1916 |
} |
||
1917 |
fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR; |
||
1918 |
} |
||
1919 |
; |
||
1920 |
|||
1921 |
prefixlenop : /* empty */ { bzero(&$$, sizeof($$)); } |
||
1922 |
| LONGER { |
||
1923 |
bzero(&$$, sizeof($$)); |
||
1924 |
$$.op = OP_GE; |
||
1925 |
$$.len_min = -1; |
||
1926 |
} |
||
1927 |
| PREFIXLEN unaryop NUMBER { |
||
1928 |
bzero(&$$, sizeof($$)); |
||
1929 |
if ($3 < 0 || $3 > 128) { |
||
1930 |
yyerror("prefixlen must be >= 0 and <= 128"); |
||
1931 |
YYERROR; |
||
1932 |
} |
||
1933 |
if ($2 == OP_GT && $3 == 0) { |
||
1934 |
yyerror("prefixlen must be > 0"); |
||
1935 |
YYERROR; |
||
1936 |
} |
||
1937 |
$$.op = $2; |
||
1938 |
$$.len_min = $3; |
||
1939 |
} |
||
1940 |
| PREFIXLEN NUMBER binaryop NUMBER { |
||
1941 |
bzero(&$$, sizeof($$)); |
||
1942 |
if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) { |
||
1943 |
yyerror("prefixlen must be < 128"); |
||
1944 |
YYERROR; |
||
1945 |
} |
||
1946 |
if ($2 >= $4) { |
||
1947 |
yyerror("start prefixlen is bigger than end"); |
||
1948 |
YYERROR; |
||
1949 |
} |
||
1950 |
$$.op = $3; |
||
1951 |
$$.len_min = $2; |
||
1952 |
$$.len_max = $4; |
||
1953 |
} |
||
1954 |
; |
||
1955 |
|||
1956 |
filter_as_type : AS { $$ = AS_ALL; } |
||
1957 |
| SOURCEAS { $$ = AS_SOURCE; } |
||
1958 |
| TRANSITAS { $$ = AS_TRANSIT; } |
||
1959 |
| PEERAS { $$ = AS_PEER; } |
||
1960 |
; |
||
1961 |
|||
1962 |
filter_set : /* empty */ { $$ = NULL; } |
||
1963 |
| SET filter_set_opt { |
||
1964 |
if (($$ = calloc(1, sizeof(struct filter_set_head))) == |
||
1965 |
NULL) |
||
1966 |
fatal(NULL); |
||
1967 |
TAILQ_INIT($$); |
||
1968 |
TAILQ_INSERT_TAIL($$, $2, entry); |
||
1969 |
} |
||
1970 |
| SET optnl "{" optnl filter_set_l optnl "}" { $$ = $5; } |
||
1971 |
; |
||
1972 |
|||
1973 |
filter_set_l : filter_set_l comma filter_set_opt { |
||
1974 |
$$ = $1; |
||
1975 |
if (merge_filterset($$, $3) == 1) |
||
1976 |
YYERROR; |
||
1977 |
} |
||
1978 |
| filter_set_opt { |
||
1979 |
if (($$ = calloc(1, sizeof(struct filter_set_head))) == |
||
1980 |
NULL) |
||
1981 |
fatal(NULL); |
||
1982 |
TAILQ_INIT($$); |
||
1983 |
TAILQ_INSERT_TAIL($$, $1, entry); |
||
1984 |
} |
||
1985 |
; |
||
1986 |
|||
1987 |
delete : /* empty */ { $$ = 0; } |
||
1988 |
| DELETE { $$ = 1; } |
||
1989 |
; |
||
1990 |
|||
1991 |
filter_set_opt : LOCALPREF NUMBER { |
||
1992 |
if ($2 < -INT_MAX || $2 > UINT_MAX) { |
||
1993 |
yyerror("bad localpref %lld", $2); |
||
1994 |
YYERROR; |
||
1995 |
} |
||
1996 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
1997 |
fatal(NULL); |
||
1998 |
if ($2 >= 0) { |
||
1999 |
$$->type = ACTION_SET_LOCALPREF; |
||
2000 |
$$->action.metric = $2; |
||
2001 |
} else { |
||
2002 |
$$->type = ACTION_SET_RELATIVE_LOCALPREF; |
||
2003 |
$$->action.relative = $2; |
||
2004 |
} |
||
2005 |
} |
||
2006 |
| LOCALPREF '+' NUMBER { |
||
2007 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2008 |
yyerror("bad localpref +%lld", $3); |
||
2009 |
YYERROR; |
||
2010 |
} |
||
2011 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2012 |
fatal(NULL); |
||
2013 |
$$->type = ACTION_SET_RELATIVE_LOCALPREF; |
||
2014 |
$$->action.relative = $3; |
||
2015 |
} |
||
2016 |
| LOCALPREF '-' NUMBER { |
||
2017 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2018 |
yyerror("bad localpref -%lld", $3); |
||
2019 |
YYERROR; |
||
2020 |
} |
||
2021 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2022 |
fatal(NULL); |
||
2023 |
$$->type = ACTION_SET_RELATIVE_LOCALPREF; |
||
2024 |
$$->action.relative = -$3; |
||
2025 |
} |
||
2026 |
| MED NUMBER { |
||
2027 |
if ($2 < -INT_MAX || $2 > UINT_MAX) { |
||
2028 |
yyerror("bad metric %lld", $2); |
||
2029 |
YYERROR; |
||
2030 |
} |
||
2031 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2032 |
fatal(NULL); |
||
2033 |
if ($2 >= 0) { |
||
2034 |
$$->type = ACTION_SET_MED; |
||
2035 |
$$->action.metric = $2; |
||
2036 |
} else { |
||
2037 |
$$->type = ACTION_SET_RELATIVE_MED; |
||
2038 |
$$->action.relative = $2; |
||
2039 |
} |
||
2040 |
} |
||
2041 |
| MED '+' NUMBER { |
||
2042 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2043 |
yyerror("bad metric +%lld", $3); |
||
2044 |
YYERROR; |
||
2045 |
} |
||
2046 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2047 |
fatal(NULL); |
||
2048 |
$$->type = ACTION_SET_RELATIVE_MED; |
||
2049 |
$$->action.relative = $3; |
||
2050 |
} |
||
2051 |
| MED '-' NUMBER { |
||
2052 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2053 |
yyerror("bad metric -%lld", $3); |
||
2054 |
YYERROR; |
||
2055 |
} |
||
2056 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2057 |
fatal(NULL); |
||
2058 |
$$->type = ACTION_SET_RELATIVE_MED; |
||
2059 |
$$->action.relative = -$3; |
||
2060 |
} |
||
2061 |
| METRIC NUMBER { /* alias for MED */ |
||
2062 |
if ($2 < -INT_MAX || $2 > UINT_MAX) { |
||
2063 |
yyerror("bad metric %lld", $2); |
||
2064 |
YYERROR; |
||
2065 |
} |
||
2066 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2067 |
fatal(NULL); |
||
2068 |
if ($2 >= 0) { |
||
2069 |
$$->type = ACTION_SET_MED; |
||
2070 |
$$->action.metric = $2; |
||
2071 |
} else { |
||
2072 |
$$->type = ACTION_SET_RELATIVE_MED; |
||
2073 |
$$->action.relative = $2; |
||
2074 |
} |
||
2075 |
} |
||
2076 |
| METRIC '+' NUMBER { |
||
2077 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2078 |
yyerror("bad metric +%lld", $3); |
||
2079 |
YYERROR; |
||
2080 |
} |
||
2081 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2082 |
fatal(NULL); |
||
2083 |
$$->type = ACTION_SET_RELATIVE_MED; |
||
2084 |
$$->action.metric = $3; |
||
2085 |
} |
||
2086 |
| METRIC '-' NUMBER { |
||
2087 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2088 |
yyerror("bad metric -%lld", $3); |
||
2089 |
YYERROR; |
||
2090 |
} |
||
2091 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2092 |
fatal(NULL); |
||
2093 |
$$->type = ACTION_SET_RELATIVE_MED; |
||
2094 |
$$->action.relative = -$3; |
||
2095 |
} |
||
2096 |
| WEIGHT NUMBER { |
||
2097 |
if ($2 < -INT_MAX || $2 > UINT_MAX) { |
||
2098 |
yyerror("bad weight %lld", $2); |
||
2099 |
YYERROR; |
||
2100 |
} |
||
2101 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2102 |
fatal(NULL); |
||
2103 |
if ($2 > 0) { |
||
2104 |
$$->type = ACTION_SET_WEIGHT; |
||
2105 |
$$->action.metric = $2; |
||
2106 |
} else { |
||
2107 |
$$->type = ACTION_SET_RELATIVE_WEIGHT; |
||
2108 |
$$->action.relative = $2; |
||
2109 |
} |
||
2110 |
} |
||
2111 |
| WEIGHT '+' NUMBER { |
||
2112 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2113 |
yyerror("bad weight +%lld", $3); |
||
2114 |
YYERROR; |
||
2115 |
} |
||
2116 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2117 |
fatal(NULL); |
||
2118 |
$$->type = ACTION_SET_RELATIVE_WEIGHT; |
||
2119 |
$$->action.relative = $3; |
||
2120 |
} |
||
2121 |
| WEIGHT '-' NUMBER { |
||
2122 |
if ($3 < 0 || $3 > INT_MAX) { |
||
2123 |
yyerror("bad weight -%lld", $3); |
||
2124 |
YYERROR; |
||
2125 |
} |
||
2126 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2127 |
fatal(NULL); |
||
2128 |
$$->type = ACTION_SET_RELATIVE_WEIGHT; |
||
2129 |
$$->action.relative = -$3; |
||
2130 |
} |
||
2131 |
| NEXTHOP address { |
||
2132 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2133 |
fatal(NULL); |
||
2134 |
$$->type = ACTION_SET_NEXTHOP; |
||
2135 |
memcpy(&$$->action.nexthop, &$2, |
||
2136 |
sizeof($$->action.nexthop)); |
||
2137 |
} |
||
2138 |
| NEXTHOP BLACKHOLE { |
||
2139 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2140 |
fatal(NULL); |
||
2141 |
$$->type = ACTION_SET_NEXTHOP_BLACKHOLE; |
||
2142 |
} |
||
2143 |
| NEXTHOP REJECT { |
||
2144 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2145 |
fatal(NULL); |
||
2146 |
$$->type = ACTION_SET_NEXTHOP_REJECT; |
||
2147 |
} |
||
2148 |
| NEXTHOP NOMODIFY { |
||
2149 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2150 |
fatal(NULL); |
||
2151 |
$$->type = ACTION_SET_NEXTHOP_NOMODIFY; |
||
2152 |
} |
||
2153 |
| NEXTHOP SELF { |
||
2154 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2155 |
fatal(NULL); |
||
2156 |
$$->type = ACTION_SET_NEXTHOP_SELF; |
||
2157 |
} |
||
2158 |
| PREPEND_SELF NUMBER { |
||
2159 |
if ($2 < 0 || $2 > 128) { |
||
2160 |
yyerror("bad number of prepends"); |
||
2161 |
YYERROR; |
||
2162 |
} |
||
2163 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2164 |
fatal(NULL); |
||
2165 |
$$->type = ACTION_SET_PREPEND_SELF; |
||
2166 |
$$->action.prepend = $2; |
||
2167 |
} |
||
2168 |
| PREPEND_PEER NUMBER { |
||
2169 |
if ($2 < 0 || $2 > 128) { |
||
2170 |
yyerror("bad number of prepends"); |
||
2171 |
YYERROR; |
||
2172 |
} |
||
2173 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2174 |
fatal(NULL); |
||
2175 |
$$->type = ACTION_SET_PREPEND_PEER; |
||
2176 |
$$->action.prepend = $2; |
||
2177 |
} |
||
2178 |
| PFTABLE STRING { |
||
2179 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2180 |
fatal(NULL); |
||
2181 |
$$->type = ACTION_PFTABLE; |
||
2182 |
if (!(cmd_opts & BGPD_OPT_NOACTION) && |
||
2183 |
pftable_exists($2) != 0) { |
||
2184 |
yyerror("pftable name does not exist"); |
||
2185 |
free($2); |
||
2186 |
free($$); |
||
2187 |
YYERROR; |
||
2188 |
} |
||
2189 |
if (strlcpy($$->action.pftable, $2, |
||
2190 |
sizeof($$->action.pftable)) >= |
||
2191 |
sizeof($$->action.pftable)) { |
||
2192 |
yyerror("pftable name too long"); |
||
2193 |
free($2); |
||
2194 |
free($$); |
||
2195 |
YYERROR; |
||
2196 |
} |
||
2197 |
if (pftable_add($2) != 0) { |
||
2198 |
yyerror("Couldn't register table"); |
||
2199 |
free($2); |
||
2200 |
free($$); |
||
2201 |
YYERROR; |
||
2202 |
} |
||
2203 |
free($2); |
||
2204 |
} |
||
2205 |
| RTLABEL STRING { |
||
2206 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2207 |
fatal(NULL); |
||
2208 |
$$->type = ACTION_RTLABEL; |
||
2209 |
if (strlcpy($$->action.rtlabel, $2, |
||
2210 |
sizeof($$->action.rtlabel)) >= |
||
2211 |
sizeof($$->action.rtlabel)) { |
||
2212 |
yyerror("rtlabel name too long"); |
||
2213 |
free($2); |
||
2214 |
free($$); |
||
2215 |
YYERROR; |
||
2216 |
} |
||
2217 |
free($2); |
||
2218 |
} |
||
2219 |
| COMMUNITY delete STRING { |
||
2220 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2221 |
fatal(NULL); |
||
2222 |
if ($2) |
||
2223 |
$$->type = ACTION_DEL_COMMUNITY; |
||
2224 |
else |
||
2225 |
$$->type = ACTION_SET_COMMUNITY; |
||
2226 |
|||
2227 |
if (parsecommunity(&$$->action.community, $3) == -1) { |
||
2228 |
free($3); |
||
2229 |
free($$); |
||
2230 |
YYERROR; |
||
2231 |
} |
||
2232 |
free($3); |
||
2233 |
/* Don't allow setting of any match */ |
||
2234 |
if (!$2 && ($$->action.community.as == COMMUNITY_ANY || |
||
2235 |
$$->action.community.type == COMMUNITY_ANY)) { |
||
2236 |
yyerror("'*' is not allowed in set community"); |
||
2237 |
free($$); |
||
2238 |
YYERROR; |
||
2239 |
} |
||
2240 |
} |
||
2241 |
| LARGECOMMUNITY delete STRING { |
||
2242 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2243 |
fatal(NULL); |
||
2244 |
if ($2) |
||
2245 |
$$->type = ACTION_DEL_LARGE_COMMUNITY; |
||
2246 |
else |
||
2247 |
$$->type = ACTION_SET_LARGE_COMMUNITY; |
||
2248 |
|||
2249 |
if (parselargecommunity(&$$->action.large_community, |
||
2250 |
$3) == -1) { |
||
2251 |
free($3); |
||
2252 |
free($$); |
||
2253 |
YYERROR; |
||
2254 |
} |
||
2255 |
free($3); |
||
2256 |
/* Don't allow setting of any match */ |
||
2257 |
if (!$2 && |
||
2258 |
($$->action.large_community.as == COMMUNITY_ANY || |
||
2259 |
$$->action.large_community.ld1 == COMMUNITY_ANY || |
||
2260 |
$$->action.large_community.ld2 == COMMUNITY_ANY)) { |
||
2261 |
yyerror("'*' is not allowed in set community"); |
||
2262 |
free($$); |
||
2263 |
YYERROR; |
||
2264 |
} |
||
2265 |
} |
||
2266 |
| EXTCOMMUNITY delete STRING STRING { |
||
2267 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2268 |
fatal(NULL); |
||
2269 |
if ($2) |
||
2270 |
$$->type = ACTION_DEL_EXT_COMMUNITY; |
||
2271 |
else |
||
2272 |
$$->type = ACTION_SET_EXT_COMMUNITY; |
||
2273 |
|||
2274 |
if (parseextcommunity(&$$->action.ext_community, |
||
2275 |
$3, $4) == -1) { |
||
2276 |
free($3); |
||
2277 |
free($4); |
||
2278 |
free($$); |
||
2279 |
YYERROR; |
||
2280 |
} |
||
2281 |
free($3); |
||
2282 |
free($4); |
||
2283 |
} |
||
2284 |
| ORIGIN origincode { |
||
2285 |
if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) |
||
2286 |
fatal(NULL); |
||
2287 |
$$->type = ACTION_SET_ORIGIN; |
||
2288 |
$$->action.origin = $2; |
||
2289 |
} |
||
2290 |
; |
||
2291 |
|||
2292 |
origincode : string { |
||
2293 |
if (!strcmp($1, "egp")) |
||
2294 |
$$ = ORIGIN_EGP; |
||
2295 |
else if (!strcmp($1, "igp")) |
||
2296 |
$$ = ORIGIN_IGP; |
||
2297 |
else if (!strcmp($1, "incomplete")) |
||
2298 |
$$ = ORIGIN_INCOMPLETE; |
||
2299 |
else { |
||
2300 |
yyerror("unknown origin \"%s\"", $1); |
||
2301 |
free($1); |
||
2302 |
YYERROR; |
||
2303 |
} |
||
2304 |
free($1); |
||
2305 |
}; |
||
2306 |
|||
2307 |
comma : "," |
||
2308 |
| /* empty */ |
||
2309 |
; |
||
2310 |
|||
2311 |
unaryop : '=' { $$ = OP_EQ; } |
||
2312 |
| NE { $$ = OP_NE; } |
||
2313 |
| LE { $$ = OP_LE; } |
||
2314 |
| '<' { $$ = OP_LT; } |
||
2315 |
| GE { $$ = OP_GE; } |
||
2316 |
| '>' { $$ = OP_GT; } |
||
2317 |
; |
||
2318 |
|||
2319 |
equalityop : '=' { $$ = OP_EQ; } |
||
2320 |
| NE { $$ = OP_NE; } |
||
2321 |
; |
||
2322 |
|||
2323 |
binaryop : '-' { $$ = OP_RANGE; } |
||
2324 |
| XRANGE { $$ = OP_XRANGE; } |
||
2325 |
; |
||
2326 |
|||
2327 |
%% |
||
2328 |
|||
2329 |
struct keywords { |
||
2330 |
const char *k_name; |
||
2331 |
int k_val; |
||
2332 |
}; |
||
2333 |
|||
2334 |
int |
||
2335 |
yyerror(const char *fmt, ...) |
||
2336 |
{ |
||
2337 |
va_list ap; |
||
2338 |
char *msg; |
||
2339 |
|||
2340 |
file->errors++; |
||
2341 |
va_start(ap, fmt); |
||
2342 |
if (vasprintf(&msg, fmt, ap) == -1) |
||
2343 |
fatalx("yyerror vasprintf"); |
||
2344 |
va_end(ap); |
||
2345 |
logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); |
||
2346 |
free(msg); |
||
2347 |
return (0); |
||
2348 |
} |
||
2349 |
|||
2350 |
int |
||
2351 |
kw_cmp(const void *k, const void *e) |
||
2352 |
{ |
||
2353 |
15272 |
return (strcmp(k, ((const struct keywords *)e)->k_name)); |
|
2354 |
} |
||
2355 |
|||
2356 |
int |
||
2357 |
lookup(char *s) |
||
2358 |
{ |
||
2359 |
/* this has to be sorted always */ |
||
2360 |
static const struct keywords keywords[] = { |
||
2361 |
{ "AS", AS}, |
||
2362 |
{ "IPv4", IPV4}, |
||
2363 |
{ "IPv6", IPV6}, |
||
2364 |
{ "ah", AH}, |
||
2365 |
{ "allow", ALLOW}, |
||
2366 |
{ "announce", ANNOUNCE}, |
||
2367 |
{ "any", ANY}, |
||
2368 |
{ "as-4byte", AS4BYTE }, |
||
2369 |
{ "blackhole", BLACKHOLE}, |
||
2370 |
{ "capabilities", CAPABILITIES}, |
||
2371 |
{ "community", COMMUNITY}, |
||
2372 |
{ "compare", COMPARE}, |
||
2373 |
{ "connect-retry", CONNECTRETRY}, |
||
2374 |
{ "connected", CONNECTED}, |
||
2375 |
{ "delete", DELETE}, |
||
2376 |
{ "demote", DEMOTE}, |
||
2377 |
{ "deny", DENY}, |
||
2378 |
{ "depend", DEPEND}, |
||
2379 |
{ "descr", DESCR}, |
||
2380 |
{ "down", DOWN}, |
||
2381 |
{ "dump", DUMP}, |
||
2382 |
{ "ebgp", EBGP}, |
||
2383 |
{ "enforce", ENFORCE}, |
||
2384 |
{ "esp", ESP}, |
||
2385 |
{ "evaluate", EVALUATE}, |
||
2386 |
{ "export-target", EXPORTTRGT}, |
||
2387 |
{ "ext-community", EXTCOMMUNITY}, |
||
2388 |
{ "fib-priority", FIBPRIORITY}, |
||
2389 |
{ "fib-update", FIBUPDATE}, |
||
2390 |
{ "from", FROM}, |
||
2391 |
{ "group", GROUP}, |
||
2392 |
{ "holdtime", HOLDTIME}, |
||
2393 |
{ "ibgp", IBGP}, |
||
2394 |
{ "ignore", IGNORE}, |
||
2395 |
{ "ike", IKE}, |
||
2396 |
{ "import-target", IMPORTTRGT}, |
||
2397 |
{ "in", IN}, |
||
2398 |
{ "include", INCLUDE}, |
||
2399 |
{ "inet", IPV4}, |
||
2400 |
{ "inet6", IPV6}, |
||
2401 |
{ "ipsec", IPSEC}, |
||
2402 |
{ "key", KEY}, |
||
2403 |
{ "large-community", LARGECOMMUNITY}, |
||
2404 |
{ "listen", LISTEN}, |
||
2405 |
{ "local-address", LOCALADDR}, |
||
2406 |
{ "local-as", LOCALAS}, |
||
2407 |
{ "localpref", LOCALPREF}, |
||
2408 |
{ "log", LOG}, |
||
2409 |
{ "match", MATCH}, |
||
2410 |
{ "max-as-len", MAXASLEN}, |
||
2411 |
{ "max-as-seq", MAXASSEQ}, |
||
2412 |
{ "max-prefix", MAXPREFIX}, |
||
2413 |
{ "md5sig", MD5SIG}, |
||
2414 |
{ "med", MED}, |
||
2415 |
{ "metric", METRIC}, |
||
2416 |
{ "min", YMIN}, |
||
2417 |
{ "multihop", MULTIHOP}, |
||
2418 |
{ "neighbor", NEIGHBOR}, |
||
2419 |
{ "neighbor-as", NEIGHBORAS}, |
||
2420 |
{ "network", NETWORK}, |
||
2421 |
{ "nexthop", NEXTHOP}, |
||
2422 |
{ "no-modify", NOMODIFY}, |
||
2423 |
{ "on", ON}, |
||
2424 |
{ "or-longer", LONGER}, |
||
2425 |
{ "origin", ORIGIN}, |
||
2426 |
{ "out", OUT}, |
||
2427 |
{ "passive", PASSIVE}, |
||
2428 |
{ "password", PASSWORD}, |
||
2429 |
{ "peer-as", PEERAS}, |
||
2430 |
{ "pftable", PFTABLE}, |
||
2431 |
{ "prefix", PREFIX}, |
||
2432 |
{ "prefixlen", PREFIXLEN}, |
||
2433 |
{ "prepend-neighbor", PREPEND_PEER}, |
||
2434 |
{ "prepend-self", PREPEND_SELF}, |
||
2435 |
{ "qualify", QUALIFY}, |
||
2436 |
{ "quick", QUICK}, |
||
2437 |
{ "rd", RD}, |
||
2438 |
{ "rde", RDE}, |
||
2439 |
{ "rdomain", RDOMAIN}, |
||
2440 |
{ "refresh", REFRESH }, |
||
2441 |
{ "reject", REJECT}, |
||
2442 |
{ "remote-as", REMOTEAS}, |
||
2443 |
{ "restart", RESTART}, |
||
2444 |
{ "restricted", RESTRICTED}, |
||
2445 |
{ "rib", RIB}, |
||
2446 |
{ "route-collector", ROUTECOLL}, |
||
2447 |
{ "route-reflector", REFLECTOR}, |
||
2448 |
{ "router-id", ROUTERID}, |
||
2449 |
{ "rtable", RTABLE}, |
||
2450 |
{ "rtlabel", RTLABEL}, |
||
2451 |
{ "self", SELF}, |
||
2452 |
{ "set", SET}, |
||
2453 |
{ "socket", SOCKET }, |
||
2454 |
{ "source-as", SOURCEAS}, |
||
2455 |
{ "spi", SPI}, |
||
2456 |
{ "static", STATIC}, |
||
2457 |
{ "tcp", TCP}, |
||
2458 |
{ "to", TO}, |
||
2459 |
{ "transit-as", TRANSITAS}, |
||
2460 |
{ "transparent-as", TRANSPARENT}, |
||
2461 |
{ "ttl-security", TTLSECURITY}, |
||
2462 |
{ "via", VIA}, |
||
2463 |
{ "weight", WEIGHT} |
||
2464 |
}; |
||
2465 |
const struct keywords *p; |
||
2466 |
|||
2467 |
2720 |
p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), |
|
2468 |
sizeof(keywords[0]), kw_cmp); |
||
2469 |
|||
2470 |
✓✓ | 1360 |
if (p) |
2471 |
1088 |
return (p->k_val); |
|
2472 |
else |
||
2473 |
272 |
return (STRING); |
|
2474 |
1360 |
} |
|
2475 |
|||
2476 |
#define MAXPUSHBACK 128 |
||
2477 |
|||
2478 |
u_char *parsebuf; |
||
2479 |
int parseindex; |
||
2480 |
u_char pushback_buffer[MAXPUSHBACK]; |
||
2481 |
int pushback_index = 0; |
||
2482 |
|||
2483 |
int |
||
2484 |
lgetc(int quotec) |
||
2485 |
{ |
||
2486 |
int c, next; |
||
2487 |
|||
2488 |
✓✓ | 46840 |
if (parsebuf) { |
2489 |
/* Read character from the parsebuffer instead of input. */ |
||
2490 |
✓✗ | 88 |
if (parseindex >= 0) { |
2491 |
88 |
c = parsebuf[parseindex++]; |
|
2492 |
✓✓ | 88 |
if (c != '\0') |
2493 |
80 |
return (c); |
|
2494 |
8 |
parsebuf = NULL; |
|
2495 |
8 |
} else |
|
2496 |
parseindex++; |
||
2497 |
} |
||
2498 |
|||
2499 |
✓✓ | 23340 |
if (pushback_index) |
2500 |
2072 |
return (pushback_buffer[--pushback_index]); |
|
2501 |
|||
2502 |
✓✓ | 21268 |
if (quotec) { |
2503 |
✓✗✗✓ ✗✓ |
1984 |
if ((c = getc(file->stream)) == EOF) { |
2504 |
yyerror("reached end of file while parsing " |
||
2505 |
"quoted string"); |
||
2506 |
if (file == topfile || popfile() == EOF) |
||
2507 |
return (EOF); |
||
2508 |
return (quotec); |
||
2509 |
} |
||
2510 |
496 |
return (c); |
|
2511 |
} |
||
2512 |
|||
2513 |
✓✗✓✓ ✓✓ |
103900 |
while ((c = getc(file->stream)) == '\\') { |
2514 |
✓✗✗✓ |
32 |
next = getc(file->stream); |
2515 |
✗✓ | 8 |
if (next != '\n') { |
2516 |
c = next; |
||
2517 |
break; |
||
2518 |
} |
||
2519 |
8 |
yylval.lineno = file->lineno; |
|
2520 |
8 |
file->lineno++; |
|
2521 |
} |
||
2522 |
|||
2523 |
✓✓ | 41544 |
while (c == EOF) { |
2524 |
✗✓✗✗ |
12 |
if (file == topfile || popfile() == EOF) |
2525 |
12 |
return (EOF); |
|
2526 |
c = getc(file->stream); |
||
2527 |
} |
||
2528 |
20760 |
return (c); |
|
2529 |
23420 |
} |
|
2530 |
|||
2531 |
int |
||
2532 |
lungetc(int c) |
||
2533 |
{ |
||
2534 |
✗✓ | 4176 |
if (c == EOF) |
2535 |
return (EOF); |
||
2536 |
✓✓ | 2088 |
if (parsebuf) { |
2537 |
16 |
parseindex--; |
|
2538 |
✓✗ | 16 |
if (parseindex >= 0) |
2539 |
16 |
return (c); |
|
2540 |
} |
||
2541 |
✓✗ | 2072 |
if (pushback_index < MAXPUSHBACK-1) |
2542 |
2072 |
return (pushback_buffer[pushback_index++] = c); |
|
2543 |
else |
||
2544 |
return (EOF); |
||
2545 |
2088 |
} |
|
2546 |
|||
2547 |
int |
||
2548 |
findeol(void) |
||
2549 |
{ |
||
2550 |
int c; |
||
2551 |
|||
2552 |
parsebuf = NULL; |
||
2553 |
|||
2554 |
/* skip to either EOF or the first real EOL */ |
||
2555 |
while (1) { |
||
2556 |
if (pushback_index) |
||
2557 |
c = pushback_buffer[--pushback_index]; |
||
2558 |
else |
||
2559 |
c = lgetc(0); |
||
2560 |
if (c == '\n') { |
||
2561 |
file->lineno++; |
||
2562 |
break; |
||
2563 |
} |
||
2564 |
if (c == EOF) |
||
2565 |
break; |
||
2566 |
} |
||
2567 |
return (ERROR); |
||
2568 |
} |
||
2569 |
|||
2570 |
int |
||
2571 |
yylex(void) |
||
2572 |
{ |
||
2573 |
5344 |
u_char buf[8096]; |
|
2574 |
u_char *p, *val; |
||
2575 |
int quotec, next, c; |
||
2576 |
2672 |
int token; |
|
2577 |
|||
2578 |
top: |
||
2579 |
2680 |
p = buf; |
|
2580 |
✓✓ | 9216 |
while ((c = lgetc(0)) == ' ' || c == '\t') |
2581 |
; /* nothing */ |
||
2582 |
|||
2583 |
2680 |
yylval.lineno = file->lineno; |
|
2584 |
✓✓ | 2680 |
if (c == '#') |
2585 |
✓✓ | 17280 |
while ((c = lgetc(0)) != '\n' && c != EOF) |
2586 |
; /* nothing */ |
||
2587 |
✓✓ | 2680 |
if (c == '$' && parsebuf == NULL) { |
2588 |
8 |
while (1) { |
|
2589 |
✗✓ | 48 |
if ((c = lgetc(0)) == EOF) |
2590 |
return (0); |
||
2591 |
|||
2592 |
✗✓ | 48 |
if (p + 1 >= buf + sizeof(buf) - 1) { |
2593 |
yyerror("string too long"); |
||
2594 |
return (findeol()); |
||
2595 |
} |
||
2596 |
✓✓ | 48 |
if (isalnum(c) || c == '_') { |
2597 |
40 |
*p++ = c; |
|
2598 |
40 |
continue; |
|
2599 |
} |
||
2600 |
8 |
*p = '\0'; |
|
2601 |
8 |
lungetc(c); |
|
2602 |
break; |
||
2603 |
} |
||
2604 |
8 |
val = symget(buf); |
|
2605 |
✗✓ | 8 |
if (val == NULL) { |
2606 |
yyerror("macro '%s' not defined", buf); |
||
2607 |
return (findeol()); |
||
2608 |
} |
||
2609 |
8 |
parsebuf = val; |
|
2610 |
8 |
parseindex = 0; |
|
2611 |
8 |
goto top; |
|
2612 |
} |
||
2613 |
|||
2614 |
✗✓✗✗ ✓✓ |
2672 |
switch (c) { |
2615 |
case '\'': |
||
2616 |
case '"': |
||
2617 |
quotec = c; |
||
2618 |
496 |
while (1) { |
|
2619 |
✗✓ | 496 |
if ((c = lgetc(quotec)) == EOF) |
2620 |
return (0); |
||
2621 |
✗✓ | 496 |
if (c == '\n') { |
2622 |
file->lineno++; |
||
2623 |
continue; |
||
2624 |
✗✓ | 496 |
} else if (c == '\\') { |
2625 |
if ((next = lgetc(quotec)) == EOF) |
||
2626 |
return (0); |
||
2627 |
if (next == quotec || c == ' ' || c == '\t') |
||
2628 |
c = next; |
||
2629 |
else if (next == '\n') { |
||
2630 |
file->lineno++; |
||
2631 |
continue; |
||
2632 |
} else |
||
2633 |
lungetc(next); |
||
2634 |
✓✓ | 496 |
} else if (c == quotec) { |
2635 |
32 |
*p = '\0'; |
|
2636 |
break; |
||
2637 |
✗✓ | 464 |
} else if (c == '\0') { |
2638 |
yyerror("syntax error"); |
||
2639 |
return (findeol()); |
||
2640 |
} |
||
2641 |
✗✓ | 464 |
if (p + 1 >= buf + sizeof(buf) - 1) { |
2642 |
yyerror("string too long"); |
||
2643 |
return (findeol()); |
||
2644 |
} |
||
2645 |
464 |
*p++ = c; |
|
2646 |
} |
||
2647 |
32 |
yylval.v.string = strdup(buf); |
|
2648 |
✗✓ | 32 |
if (yylval.v.string == NULL) |
2649 |
fatal("yylex: strdup"); |
||
2650 |
32 |
return (STRING); |
|
2651 |
case '!': |
||
2652 |
next = lgetc(0); |
||
2653 |
if (next == '=') |
||
2654 |
return (NE); |
||
2655 |
lungetc(next); |
||
2656 |
break; |
||
2657 |
case '<': |
||
2658 |
next = lgetc(0); |
||
2659 |
if (next == '=') |
||
2660 |
return (LE); |
||
2661 |
lungetc(next); |
||
2662 |
break; |
||
2663 |
case '>': |
||
2664 |
92 |
next = lgetc(0); |
|
2665 |
✗✓ | 92 |
if (next == '<') |
2666 |
return (XRANGE); |
||
2667 |
✓✗ | 92 |
else if (next == '=') |
2668 |
92 |
return (GE); |
|
2669 |
lungetc(next); |
||
2670 |
break; |
||
2671 |
} |
||
2672 |
|||
2673 |
#define allowed_to_end_number(x) \ |
||
2674 |
(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') |
||
2675 |
|||
2676 |
✓✓✓✓ |
5064 |
if (c == '-' || isdigit(c)) { |
2677 |
512 |
do { |
|
2678 |
1268 |
*p++ = c; |
|
2679 |
✗✓ | 1268 |
if ((unsigned)(p-buf) >= sizeof(buf)) { |
2680 |
yyerror("string too long"); |
||
2681 |
return (findeol()); |
||
2682 |
} |
||
2683 |
✓✗✓✓ |
2536 |
} while ((c = lgetc(0)) != EOF && isdigit(c)); |
2684 |
512 |
lungetc(c); |
|
2685 |
✓✓✓✓ |
660 |
if (p == buf + 1 && buf[0] == '-') |
2686 |
goto nodigits; |
||
2687 |
✓✗✓✓ |
960 |
if (c == EOF || allowed_to_end_number(c)) { |
2688 |
324 |
const char *errstr = NULL; |
|
2689 |
|||
2690 |
324 |
*p = '\0'; |
|
2691 |
324 |
yylval.v.number = strtonum(buf, LLONG_MIN, |
|
2692 |
LLONG_MAX, &errstr); |
||
2693 |
✗✓ | 324 |
if (errstr) { |
2694 |
yyerror("\"%s\" invalid number: %s", |
||
2695 |
buf, errstr); |
||
2696 |
return (findeol()); |
||
2697 |
} |
||
2698 |
324 |
return (NUMBER); |
|
2699 |
324 |
} else { |
|
2700 |
nodigits: |
||
2701 |
✓✓ | 792 |
while (p > buf + 1) |
2702 |
208 |
lungetc(*--p); |
|
2703 |
c = *--p; |
||
2704 |
✓✓ | 188 |
if (c == '-') |
2705 |
32 |
return (c); |
|
2706 |
} |
||
2707 |
} |
||
2708 |
|||
2709 |
#define allowed_in_string(x) \ |
||
2710 |
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ |
||
2711 |
x != '{' && x != '}' && x != '<' && x != '>' && \ |
||
2712 |
x != '!' && x != '=' && x != '/' && x != '#' && \ |
||
2713 |
x != ',')) |
||
2714 |
|||
2715 |
✓✓ | 2192 |
if (isalnum(c) || c == ':' || c == '_' || c == '*') { |
2716 |
1360 |
do { |
|
2717 |
8268 |
*p++ = c; |
|
2718 |
✗✓ | 8268 |
if ((unsigned)(p-buf) >= sizeof(buf)) { |
2719 |
yyerror("string too long"); |
||
2720 |
return (findeol()); |
||
2721 |
} |
||
2722 |
✓✗✓✓ ✓✓ |
18452 |
} while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); |
2723 |
1360 |
lungetc(c); |
|
2724 |
1360 |
*p = '\0'; |
|
2725 |
✓✓ | 1360 |
if ((token = lookup(buf)) == STRING) |
2726 |
✗✓ | 272 |
if ((yylval.v.string = strdup(buf)) == NULL) |
2727 |
fatal("yylex: strdup"); |
||
2728 |
1360 |
return (token); |
|
2729 |
} |
||
2730 |
✓✓ | 832 |
if (c == '\n') { |
2731 |
640 |
yylval.lineno = file->lineno; |
|
2732 |
640 |
file->lineno++; |
|
2733 |
640 |
} |
|
2734 |
✓✓ | 832 |
if (c == EOF) |
2735 |
12 |
return (0); |
|
2736 |
820 |
return (c); |
|
2737 |
2672 |
} |
|
2738 |
|||
2739 |
int |
||
2740 |
check_file_secrecy(int fd, const char *fname) |
||
2741 |
{ |
||
2742 |
24 |
struct stat st; |
|
2743 |
|||
2744 |
✗✓ | 12 |
if (fstat(fd, &st)) { |
2745 |
log_warn("cannot stat %s", fname); |
||
2746 |
return (-1); |
||
2747 |
} |
||
2748 |
12 |
return (0); |
|
2749 |
12 |
} |
|
2750 |
|||
2751 |
struct file * |
||
2752 |
pushfile(const char *name, int secret) |
||
2753 |
{ |
||
2754 |
struct file *nfile; |
||
2755 |
|||
2756 |
✗✓ | 24 |
if ((nfile = calloc(1, sizeof(struct file))) == NULL) { |
2757 |
log_warn("malloc"); |
||
2758 |
return (NULL); |
||
2759 |
} |
||
2760 |
✗✓ | 12 |
if ((nfile->name = strdup(name)) == NULL) { |
2761 |
log_warn("malloc"); |
||
2762 |
free(nfile); |
||
2763 |
return (NULL); |
||
2764 |
} |
||
2765 |
✗✓ | 12 |
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { |
2766 |
log_warn("%s", nfile->name); |
||
2767 |
free(nfile->name); |
||
2768 |
free(nfile); |
||
2769 |
return (NULL); |
||
2770 |
} |
||
2771 |
✓✗✗✓ |
24 |
if (secret && |
2772 |
✓✗ | 36 |
check_file_secrecy(fileno(nfile->stream), nfile->name)) { |
2773 |
fclose(nfile->stream); |
||
2774 |
free(nfile->name); |
||
2775 |
free(nfile); |
||
2776 |
return (NULL); |
||
2777 |
} |
||
2778 |
12 |
nfile->lineno = 1; |
|
2779 |
12 |
TAILQ_INSERT_TAIL(&files, nfile, entry); |
|
2780 |
12 |
return (nfile); |
|
2781 |
12 |
} |
|
2782 |
|||
2783 |
int |
||
2784 |
popfile(void) |
||
2785 |
{ |
||
2786 |
struct file *prev; |
||
2787 |
|||
2788 |
✗✓ | 24 |
if ((prev = TAILQ_PREV(file, files, entry)) != NULL) |
2789 |
prev->errors += file->errors; |
||
2790 |
|||
2791 |
✗✓ | 24 |
TAILQ_REMOVE(&files, file, entry); |
2792 |
12 |
fclose(file->stream); |
|
2793 |
12 |
free(file->name); |
|
2794 |
12 |
free(file); |
|
2795 |
12 |
file = prev; |
|
2796 |
12 |
return (file ? 0 : EOF); |
|
2797 |
} |
||
2798 |
|||
2799 |
int |
||
2800 |
parse_config(char *filename, struct bgpd_config *xconf, struct peer **xpeers) |
||
2801 |
{ |
||
2802 |
struct sym *sym, *next; |
||
2803 |
struct peer *p, *pnext; |
||
2804 |
struct rde_rib *rr; |
||
2805 |
int errors = 0; |
||
2806 |
|||
2807 |
24 |
conf = new_config(); |
|
2808 |
|||
2809 |
✗✓ | 12 |
if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL) |
2810 |
fatal(NULL); |
||
2811 |
✗✓ | 12 |
if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL) |
2812 |
fatal(NULL); |
||
2813 |
✗✓ | 12 |
if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL) |
2814 |
fatal(NULL); |
||
2815 |
12 |
TAILQ_INIT(filter_l); |
|
2816 |
12 |
TAILQ_INIT(peerfilter_l); |
|
2817 |
12 |
TAILQ_INIT(groupfilter_l); |
|
2818 |
|||
2819 |
12 |
peer_l = NULL; |
|
2820 |
12 |
peer_l_old = *xpeers; |
|
2821 |
12 |
curpeer = NULL; |
|
2822 |
12 |
curgroup = NULL; |
|
2823 |
12 |
id = 1; |
|
2824 |
|||
2825 |
12 |
netconf = &conf->networks; |
|
2826 |
|||
2827 |
12 |
add_rib("Adj-RIB-In", conf->default_tableid, |
|
2828 |
F_RIB_NOFIB | F_RIB_NOEVALUATE); |
||
2829 |
12 |
add_rib("Loc-RIB", conf->default_tableid, F_RIB_LOCAL); |
|
2830 |
|||
2831 |
✗✓ | 12 |
if ((file = pushfile(filename, 1)) == NULL) { |
2832 |
free(conf); |
||
2833 |
return (-1); |
||
2834 |
} |
||
2835 |
12 |
topfile = file; |
|
2836 |
|||
2837 |
12 |
yyparse(); |
|
2838 |
12 |
errors = file->errors; |
|
2839 |
12 |
popfile(); |
|
2840 |
|||
2841 |
/* Free macros and check which have not been used. */ |
||
2842 |
✓✓ | 48 |
TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { |
2843 |
✓✗✗✓ |
16 |
if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used) |
2844 |
fprintf(stderr, "warning: macro \"%s\" not " |
||
2845 |
"used\n", sym->nam); |
||
2846 |
✓✗ | 8 |
if (!sym->persist) { |
2847 |
8 |
free(sym->nam); |
|
2848 |
8 |
free(sym->val); |
|
2849 |
✓✓ | 20 |
TAILQ_REMOVE(&symhead, sym, entry); |
2850 |
8 |
free(sym); |
|
2851 |
8 |
} |
|
2852 |
} |
||
2853 |
|||
2854 |
✗✓ | 12 |
if (errors) { |
2855 |
for (p = peer_l; p != NULL; p = pnext) { |
||
2856 |
pnext = p->next; |
||
2857 |
free(p); |
||
2858 |
} |
||
2859 |
|||
2860 |
while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { |
||
2861 |
SIMPLEQ_REMOVE_HEAD(&ribnames, entry); |
||
2862 |
free(rr); |
||
2863 |
} |
||
2864 |
|||
2865 |
filterlist_free(filter_l); |
||
2866 |
filterlist_free(peerfilter_l); |
||
2867 |
filterlist_free(groupfilter_l); |
||
2868 |
|||
2869 |
free_config(conf); |
||
2870 |
} else { |
||
2871 |
/* |
||
2872 |
* Move filter list and static group and peer filtersets |
||
2873 |
* together. Static group sets come first then peer sets |
||
2874 |
* last normal filter rules. |
||
2875 |
*/ |
||
2876 |
12 |
merge_filter_lists(conf->filters, groupfilter_l); |
|
2877 |
12 |
merge_filter_lists(conf->filters, peerfilter_l); |
|
2878 |
12 |
merge_filter_lists(conf->filters, filter_l); |
|
2879 |
|||
2880 |
12 |
errors += mrt_mergeconfig(xconf->mrt, conf->mrt); |
|
2881 |
12 |
errors += merge_config(xconf, conf, peer_l); |
|
2882 |
12 |
*xpeers = peer_l; |
|
2883 |
|||
2884 |
✗✓ | 24 |
for (p = peer_l_old; p != NULL; p = pnext) { |
2885 |
pnext = p->next; |
||
2886 |
free(p); |
||
2887 |
} |
||
2888 |
|||
2889 |
12 |
free(filter_l); |
|
2890 |
12 |
free(peerfilter_l); |
|
2891 |
12 |
free(groupfilter_l); |
|
2892 |
} |
||
2893 |
|||
2894 |
12 |
return (errors ? -1 : 0); |
|
2895 |
12 |
} |
|
2896 |
|||
2897 |
int |
||
2898 |
symset(const char *nam, const char *val, int persist) |
||
2899 |
{ |
||
2900 |
struct sym *sym; |
||
2901 |
|||
2902 |
✓✓ | 32 |
TAILQ_FOREACH(sym, &symhead, entry) { |
2903 |
✓✗ | 4 |
if (strcmp(nam, sym->nam) == 0) |
2904 |
break; |
||
2905 |
} |
||
2906 |
|||
2907 |
✗✓ | 8 |
if (sym != NULL) { |
2908 |
if (sym->persist == 1) |
||
2909 |
return (0); |
||
2910 |
else { |
||
2911 |
free(sym->nam); |
||
2912 |
free(sym->val); |
||
2913 |
TAILQ_REMOVE(&symhead, sym, entry); |
||
2914 |
free(sym); |
||
2915 |
} |
||
2916 |
} |
||
2917 |
✗✓ | 8 |
if ((sym = calloc(1, sizeof(*sym))) == NULL) |
2918 |
return (-1); |
||
2919 |
|||
2920 |
8 |
sym->nam = strdup(nam); |
|
2921 |
✗✓ | 8 |
if (sym->nam == NULL) { |
2922 |
free(sym); |
||
2923 |
return (-1); |
||
2924 |
} |
||
2925 |
8 |
sym->val = strdup(val); |
|
2926 |
✗✓ | 8 |
if (sym->val == NULL) { |
2927 |
free(sym->nam); |
||
2928 |
free(sym); |
||
2929 |
return (-1); |
||
2930 |
} |
||
2931 |
8 |
sym->used = 0; |
|
2932 |
8 |
sym->persist = persist; |
|
2933 |
8 |
TAILQ_INSERT_TAIL(&symhead, sym, entry); |
|
2934 |
8 |
return (0); |
|
2935 |
8 |
} |
|
2936 |
|||
2937 |
int |
||
2938 |
cmdline_symset(char *s) |
||
2939 |
{ |
||
2940 |
char *sym, *val; |
||
2941 |
int ret; |
||
2942 |
size_t len; |
||
2943 |
|||
2944 |
if ((val = strrchr(s, '=')) == NULL) |
||
2945 |
return (-1); |
||
2946 |
|||
2947 |
len = strlen(s) - strlen(val) + 1; |
||
2948 |
if ((sym = malloc(len)) == NULL) |
||
2949 |
fatal("cmdline_symset: malloc"); |
||
2950 |
|||
2951 |
strlcpy(sym, s, len); |
||
2952 |
|||
2953 |
ret = symset(sym, val + 1, 1); |
||
2954 |
free(sym); |
||
2955 |
|||
2956 |
return (ret); |
||
2957 |
} |
||
2958 |
|||
2959 |
char * |
||
2960 |
symget(const char *nam) |
||
2961 |
{ |
||
2962 |
struct sym *sym; |
||
2963 |
|||
2964 |
✓✗ | 32 |
TAILQ_FOREACH(sym, &symhead, entry) { |
2965 |
✓✓ | 12 |
if (strcmp(nam, sym->nam) == 0) { |
2966 |
8 |
sym->used = 1; |
|
2967 |
8 |
return (sym->val); |
|
2968 |
} |
||
2969 |
} |
||
2970 |
return (NULL); |
||
2971 |
8 |
} |
|
2972 |
|||
2973 |
int |
||
2974 |
getcommunity(char *s) |
||
2975 |
{ |
||
2976 |
int val; |
||
2977 |
16 |
const char *errstr; |
|
2978 |
|||
2979 |
✗✓ | 8 |
if (strcmp(s, "*") == 0) |
2980 |
return (COMMUNITY_ANY); |
||
2981 |
✓✓ | 8 |
if (strcmp(s, "neighbor-as") == 0) |
2982 |
4 |
return (COMMUNITY_NEIGHBOR_AS); |
|
2983 |
✓✗ | 4 |
if (strcmp(s, "local-as") == 0) |
2984 |
4 |
return (COMMUNITY_LOCAL_AS); |
|
2985 |
val = strtonum(s, 0, USHRT_MAX, &errstr); |
||
2986 |
if (errstr) { |
||
2987 |
yyerror("Community %s is %s (max: %u)", s, errstr, USHRT_MAX); |
||
2988 |
return (COMMUNITY_ERROR); |
||
2989 |
} |
||
2990 |
return (val); |
||
2991 |
8 |
} |
|
2992 |
|||
2993 |
int |
||
2994 |
parsecommunity(struct filter_community *c, char *s) |
||
2995 |
{ |
||
2996 |
char *p; |
||
2997 |
int i, as; |
||
2998 |
|||
2999 |
/* Well-known communities */ |
||
3000 |
✓✓ | 16 |
if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) { |
3001 |
4 |
c->as = COMMUNITY_WELLKNOWN; |
|
3002 |
4 |
c->type = COMMUNITY_GRACEFUL_SHUTDOWN; |
|
3003 |
4 |
return (0); |
|
3004 |
✗✓ | 4 |
} else if (strcasecmp(s, "NO_EXPORT") == 0) { |
3005 |
c->as = COMMUNITY_WELLKNOWN; |
||
3006 |
c->type = COMMUNITY_NO_EXPORT; |
||
3007 |
return (0); |
||
3008 |
✗✓ | 4 |
} else if (strcasecmp(s, "NO_ADVERTISE") == 0) { |
3009 |
c->as = COMMUNITY_WELLKNOWN; |
||
3010 |
c->type = COMMUNITY_NO_ADVERTISE; |
||
3011 |
return (0); |
||
3012 |
✗✓ | 4 |
} else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { |
3013 |
c->as = COMMUNITY_WELLKNOWN; |
||
3014 |
c->type = COMMUNITY_NO_EXPSUBCONFED; |
||
3015 |
return (0); |
||
3016 |
✗✓ | 4 |
} else if (strcasecmp(s, "NO_PEER") == 0) { |
3017 |
c->as = COMMUNITY_WELLKNOWN; |
||
3018 |
c->type = COMMUNITY_NO_PEER; |
||
3019 |
return (0); |
||
3020 |
✗✓ | 4 |
} else if (strcasecmp(s, "BLACKHOLE") == 0) { |
3021 |
c->as = COMMUNITY_WELLKNOWN; |
||
3022 |
c->type = COMMUNITY_BLACKHOLE; |
||
3023 |
return (0); |
||
3024 |
} |
||
3025 |
|||
3026 |
✗✓ | 4 |
if ((p = strchr(s, ':')) == NULL) { |
3027 |
yyerror("Bad community syntax"); |
||
3028 |
return (-1); |
||
3029 |
} |
||
3030 |
4 |
*p++ = 0; |
|
3031 |
|||
3032 |
✗✓ | 4 |
if ((i = getcommunity(s)) == COMMUNITY_ERROR) |
3033 |
return (-1); |
||
3034 |
as = i; |
||
3035 |
|||
3036 |
✗✓ | 4 |
if ((i = getcommunity(p)) == COMMUNITY_ERROR) |
3037 |
return (-1); |
||
3038 |
4 |
c->as = as; |
|
3039 |
4 |
c->type = i; |
|
3040 |
|||
3041 |
4 |
return (0); |
|
3042 |
8 |
} |
|
3043 |
|||
3044 |
int64_t |
||
3045 |
getlargecommunity(char *s) |
||
3046 |
{ |
||
3047 |
u_int val; |
||
3048 |
24 |
const char *errstr; |
|
3049 |
|||
3050 |
✓✓ | 12 |
if (strcmp(s, "*") == 0) |
3051 |
4 |
return (COMMUNITY_ANY); |
|
3052 |
✓✓ | 8 |
if (strcmp(s, "neighbor-as") == 0) |
3053 |
4 |
return (COMMUNITY_NEIGHBOR_AS); |
|
3054 |
✓✗ | 4 |
if (strcmp(s, "local-as") == 0) |
3055 |
4 |
return (COMMUNITY_LOCAL_AS); |
|
3056 |
val = strtonum(s, 0, UINT_MAX, &errstr); |
||
3057 |
if (errstr) { |
||
3058 |
yyerror("Large Community %s is %s (max: %u)", |
||
3059 |
s, errstr, UINT_MAX); |
||
3060 |
return (COMMUNITY_ERROR); |
||
3061 |
} |
||
3062 |
return (val); |
||
3063 |
12 |
} |
|
3064 |
|||
3065 |
int |
||
3066 |
parselargecommunity(struct filter_largecommunity *c, char *s) |
||
3067 |
{ |
||
3068 |
char *p, *q; |
||
3069 |
int64_t as, ld1, ld2; |
||
3070 |
|||
3071 |
✗✓ | 8 |
if ((p = strchr(s, ':')) == NULL) { |
3072 |
yyerror("Bad community syntax"); |
||
3073 |
return (-1); |
||
3074 |
} |
||
3075 |
4 |
*p++ = 0; |
|
3076 |
|||
3077 |
✗✓ | 4 |
if ((q = strchr(p, ':')) == NULL) { |
3078 |
yyerror("Bad community syntax"); |
||
3079 |
return (-1); |
||
3080 |
} |
||
3081 |
4 |
*q++ = 0; |
|
3082 |
|||
3083 |
✗✓ | 4 |
if ((as = getlargecommunity(s)) == COMMUNITY_ERROR) |
3084 |
return (-1); |
||
3085 |
|||
3086 |
✗✓ | 4 |
if ((ld1 = getlargecommunity(p)) == COMMUNITY_ERROR) |
3087 |
return (-1); |
||
3088 |
|||
3089 |
✗✓ | 4 |
if ((ld2 = getlargecommunity(q)) == COMMUNITY_ERROR) |
3090 |
return (-1); |
||
3091 |
|||
3092 |
4 |
c->as = as; |
|
3093 |
4 |
c->ld1 = ld1; |
|
3094 |
4 |
c->ld2 = ld2; |
|
3095 |
|||
3096 |
4 |
return (0); |
|
3097 |
4 |
} |
|
3098 |
|||
3099 |
int |
||
3100 |
parsesubtype(char *name, int *type, int *subtype) |
||
3101 |
{ |
||
3102 |
const struct ext_comm_pairs *cp; |
||
3103 |
int found = 0; |
||
3104 |
|||
3105 |
✓✓ | 980 |
for (cp = iana_ext_comms; cp->subname != NULL; cp++) { |
3106 |
✓✓ | 460 |
if (strcmp(name, cp->subname) == 0) { |
3107 |
✓✓ | 32 |
if (found == 0) { |
3108 |
20 |
*type = cp->type; |
|
3109 |
20 |
*subtype = cp->subtype; |
|
3110 |
20 |
} |
|
3111 |
32 |
found++; |
|
3112 |
32 |
} |
|
3113 |
} |
||
3114 |
✓✓ | 20 |
if (found > 1) |
3115 |
8 |
*type = -1; |
|
3116 |
20 |
return (found); |
|
3117 |
} |
||
3118 |
|||
3119 |
int |
||
3120 |
parseextvalue(char *s, u_int32_t *v) |
||
3121 |
{ |
||
3122 |
16 |
const char *errstr; |
|
3123 |
char *p; |
||
3124 |
8 |
struct in_addr ip; |
|
3125 |
u_int32_t uvalh = 0, uval; |
||
3126 |
|||
3127 |
✓✓ | 8 |
if ((p = strchr(s, '.')) == NULL) { |
3128 |
/* AS_PLAIN number (4 or 2 byte) */ |
||
3129 |
4 |
uval = strtonum(s, 0, UINT_MAX, &errstr); |
|
3130 |
✗✓ | 4 |
if (errstr) { |
3131 |
yyerror("Bad ext-community %s is %s", s, errstr); |
||
3132 |
return (-1); |
||
3133 |
} |
||
3134 |
4 |
*v = uval; |
|
3135 |
✓✗ | 4 |
if (uval <= USHRT_MAX) |
3136 |
4 |
return (EXT_COMMUNITY_TRANS_TWO_AS); |
|
3137 |
else |
||
3138 |
return (EXT_COMMUNITY_TRANS_FOUR_AS); |
||
3139 |
✗✓ | 4 |
} else if (strchr(p + 1, '.') == NULL) { |
3140 |
/* AS_DOT number (4-byte) */ |
||
3141 |
*p++ = '\0'; |
||
3142 |
uvalh = strtonum(s, 0, USHRT_MAX, &errstr); |
||
3143 |
if (errstr) { |
||
3144 |
yyerror("Bad ext-community %s is %s", s, errstr); |
||
3145 |
return (-1); |
||
3146 |
} |
||
3147 |
uval = strtonum(p, 0, USHRT_MAX, &errstr); |
||
3148 |
if (errstr) { |
||
3149 |
yyerror("Bad ext-community %s is %s", p, errstr); |
||
3150 |
return (-1); |
||
3151 |
} |
||
3152 |
*v = uval | (uvalh << 16); |
||
3153 |
return (EXT_COMMUNITY_TRANS_FOUR_AS); |
||
3154 |
} else { |
||
3155 |
/* more than one dot -> IP address */ |
||
3156 |
✗✓ | 4 |
if (inet_aton(s, &ip) == 0) { |
3157 |
yyerror("Bad ext-community %s not parseable", s); |
||
3158 |
return (-1); |
||
3159 |
} |
||
3160 |
4 |
*v = ip.s_addr; |
|
3161 |
4 |
return (EXT_COMMUNITY_TRANS_IPV4); |
|
3162 |
} |
||
3163 |
return (-1); |
||
3164 |
8 |
} |
|
3165 |
|||
3166 |
int |
||
3167 |
parseextcommunity(struct filter_extcommunity *c, char *t, char *s) |
||
3168 |
{ |
||
3169 |
const struct ext_comm_pairs *cp; |
||
3170 |
40 |
const char *errstr; |
|
3171 |
u_int64_t ullval; |
||
3172 |
20 |
u_int32_t uval; |
|
3173 |
20 |
char *p, *ep; |
|
3174 |
20 |
int type, subtype; |
|
3175 |
|||
3176 |
✗✓ | 20 |
if (parsesubtype(t, &type, &subtype) == 0) { |
3177 |
yyerror("Bad ext-community unknown type"); |
||
3178 |
return (-1); |
||
3179 |
} |
||
3180 |
|||
3181 |
✓✗✗✓ ✓ |
32 |
switch (type) { |
3182 |
case -1: |
||
3183 |
✗✓ | 8 |
if ((p = strchr(s, ':')) == NULL) { |
3184 |
yyerror("Bad ext-community %s", s); |
||
3185 |
return (-1); |
||
3186 |
} |
||
3187 |
8 |
*p++ = '\0'; |
|
3188 |
✗✓ | 8 |
if ((type = parseextvalue(s, &uval)) == -1) |
3189 |
return (-1); |
||
3190 |
✓✗✓✗ |
8 |
switch (type) { |
3191 |
case EXT_COMMUNITY_TRANS_TWO_AS: |
||
3192 |
4 |
ullval = strtonum(p, 0, UINT_MAX, &errstr); |
|
3193 |
4 |
break; |
|
3194 |
case EXT_COMMUNITY_TRANS_IPV4: |
||
3195 |
case EXT_COMMUNITY_TRANS_FOUR_AS: |
||
3196 |
4 |
ullval = strtonum(p, 0, USHRT_MAX, &errstr); |
|
3197 |
4 |
break; |
|
3198 |
default: |
||
3199 |
fatalx("parseextcommunity: unexpected result"); |
||
3200 |
} |
||
3201 |
✗✓ | 8 |
if (errstr) { |
3202 |
yyerror("Bad ext-community %s is %s", p, errstr); |
||
3203 |
return (-1); |
||
3204 |
} |
||
3205 |
✓✓✗✓ |
16 |
switch (type) { |
3206 |
case EXT_COMMUNITY_TRANS_TWO_AS: |
||
3207 |
4 |
c->data.ext_as.as = uval; |
|
3208 |
4 |
c->data.ext_as.val = ullval; |
|
3209 |
4 |
break; |
|
3210 |
case EXT_COMMUNITY_TRANS_IPV4: |
||
3211 |
4 |
c->data.ext_ip.addr.s_addr = uval; |
|
3212 |
4 |
c->data.ext_ip.val = ullval; |
|
3213 |
4 |
break; |
|
3214 |
case EXT_COMMUNITY_TRANS_FOUR_AS: |
||
3215 |
c->data.ext_as4.as4 = uval; |
||
3216 |
c->data.ext_as4.val = ullval; |
||
3217 |
break; |
||
3218 |
} |
||
3219 |
break; |
||
3220 |
case EXT_COMMUNITY_TRANS_OPAQUE: |
||
3221 |
case EXT_COMMUNITY_TRANS_EVPN: |
||
3222 |
errno = 0; |
||
3223 |
ullval = strtoull(s, &ep, 0); |
||
3224 |
if (s[0] == '\0' || *ep != '\0') { |
||
3225 |
yyerror("Bad ext-community bad value"); |
||
3226 |
return (-1); |
||
3227 |
} |
||
3228 |
if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) { |
||
3229 |
yyerror("Bad ext-community value too big"); |
||
3230 |
return (-1); |
||
3231 |
} |
||
3232 |
c->data.ext_opaq = ullval; |
||
3233 |
break; |
||
3234 |
case EXT_COMMUNITY_NON_TRANS_OPAQUE: |
||
3235 |
✓✓ | 12 |
if (strcmp(s, "valid") == 0) |
3236 |
4 |
c->data.ext_opaq = EXT_COMMUNITY_OVS_VALID; |
|
3237 |
✓✓ | 8 |
else if (strcmp(s, "invalid") == 0) |
3238 |
4 |
c->data.ext_opaq = EXT_COMMUNITY_OVS_INVALID; |
|
3239 |
✓✗ | 4 |
else if (strcmp(s, "not-found") == 0) |
3240 |
4 |
c->data.ext_opaq = EXT_COMMUNITY_OVS_NOTFOUND; |
|
3241 |
else { |
||
3242 |
yyerror("Bad ext-community %s", s); |
||
3243 |
return (-1); |
||
3244 |
} |
||
3245 |
break; |
||
3246 |
} |
||
3247 |
20 |
c->type = type; |
|
3248 |
20 |
c->subtype = subtype; |
|
3249 |
|||
3250 |
/* verify type/subtype combo */ |
||
3251 |
✓✗ | 616 |
for (cp = iana_ext_comms; cp->subname != NULL; cp++) { |
3252 |
✓✓✓✓ |
344 |
if (cp->type == type && cp->subtype == subtype) { |
3253 |
20 |
c->flags |= EXT_COMMUNITY_FLAG_VALID; |
|
3254 |
20 |
return (0); |
|
3255 |
} |
||
3256 |
} |
||
3257 |
|||
3258 |
yyerror("Bad ext-community bad format for type"); |
||
3259 |
return (-1); |
||
3260 |
20 |
} |
|
3261 |
|||
3262 |
struct peer * |
||
3263 |
alloc_peer(void) |
||
3264 |
{ |
||
3265 |
struct peer *p; |
||
3266 |
u_int8_t i; |
||
3267 |
|||
3268 |
✗✓ | 80 |
if ((p = calloc(1, sizeof(struct peer))) == NULL) |
3269 |
fatal("new_peer"); |
||
3270 |
|||
3271 |
/* some sane defaults */ |
||
3272 |
40 |
p->state = STATE_NONE; |
|
3273 |
40 |
p->next = NULL; |
|
3274 |
40 |
p->conf.distance = 1; |
|
3275 |
40 |
p->conf.announce_type = ANNOUNCE_UNDEF; |
|
3276 |
40 |
p->conf.announce_capa = 1; |
|
3277 |
✓✓ | 400 |
for (i = 0; i < AID_MAX; i++) |
3278 |
160 |
p->conf.capabilities.mp[i] = -1; |
|
3279 |
40 |
p->conf.capabilities.refresh = 1; |
|
3280 |
40 |
p->conf.capabilities.grestart.restart = 1; |
|
3281 |
40 |
p->conf.capabilities.as4byte = 1; |
|
3282 |
40 |
p->conf.local_as = conf->as; |
|
3283 |
40 |
p->conf.local_short_as = conf->short_as; |
|
3284 |
|||
3285 |
40 |
return (p); |
|
3286 |
} |
||
3287 |
|||
3288 |
struct peer * |
||
3289 |
new_peer(void) |
||
3290 |
{ |
||
3291 |
struct peer *p; |
||
3292 |
|||
3293 |
64 |
p = alloc_peer(); |
|
3294 |
|||
3295 |
✓✓ | 32 |
if (curgroup != NULL) { |
3296 |
16 |
memcpy(p, curgroup, sizeof(struct peer)); |
|
3297 |
✗✓ | 32 |
if (strlcpy(p->conf.group, curgroup->conf.group, |
3298 |
16 |
sizeof(p->conf.group)) >= sizeof(p->conf.group)) |
|
3299 |
fatalx("new_peer group strlcpy"); |
||
3300 |
✗✓ | 32 |
if (strlcpy(p->conf.descr, curgroup->conf.descr, |
3301 |
16 |
sizeof(p->conf.descr)) >= sizeof(p->conf.descr)) |
|
3302 |
fatalx("new_peer descr strlcpy"); |
||
3303 |
16 |
p->conf.groupid = curgroup->conf.id; |
|
3304 |
16 |
p->conf.local_as = curgroup->conf.local_as; |
|
3305 |
16 |
p->conf.local_short_as = curgroup->conf.local_short_as; |
|
3306 |
16 |
} |
|
3307 |
32 |
p->next = NULL; |
|
3308 |
✗✓ | 32 |
if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS) |
3309 |
p->conf.flags |= PEERFLAG_TRANS_AS; |
||
3310 |
32 |
return (p); |
|
3311 |
} |
||
3312 |
|||
3313 |
struct peer * |
||
3314 |
new_group(void) |
||
3315 |
{ |
||
3316 |
16 |
return (alloc_peer()); |
|
3317 |
} |
||
3318 |
|||
3319 |
int |
||
3320 |
add_mrtconfig(enum mrt_type type, char *name, int timeout, struct peer *p, |
||
3321 |
char *rib) |
||
3322 |
{ |
||
3323 |
struct mrt *m, *n; |
||
3324 |
|||
3325 |
LIST_FOREACH(m, conf->mrt, entry) { |
||
3326 |
if ((rib && strcmp(rib, m->rib)) || |
||
3327 |
(!rib && *m->rib)) |
||
3328 |
continue; |
||
3329 |
if (p == NULL) { |
||
3330 |
if (m->peer_id != 0 || m->group_id != 0) |
||
3331 |
continue; |
||
3332 |
} else { |
||
3333 |
if (m->peer_id != p->conf.id || |
||
3334 |
m->group_id != p->conf.groupid) |
||
3335 |
continue; |
||
3336 |
} |
||
3337 |
if (m->type == type) { |
||
3338 |
yyerror("only one mrtdump per type allowed."); |
||
3339 |
return (-1); |
||
3340 |
} |
||
3341 |
} |
||
3342 |
|||
3343 |
if ((n = calloc(1, sizeof(struct mrt_config))) == NULL) |
||
3344 |
fatal("add_mrtconfig"); |
||
3345 |
|||
3346 |
n->type = type; |
||
3347 |
if (strlcpy(MRT2MC(n)->name, name, sizeof(MRT2MC(n)->name)) >= |
||
3348 |
sizeof(MRT2MC(n)->name)) { |
||
3349 |
yyerror("filename \"%s\" too long: max %zu", |
||
3350 |
name, sizeof(MRT2MC(n)->name) - 1); |
||
3351 |
free(n); |
||
3352 |
return (-1); |
||
3353 |
} |
||
3354 |
MRT2MC(n)->ReopenTimerInterval = timeout; |
||
3355 |
if (p != NULL) { |
||
3356 |
if (curgroup == p) { |
||
3357 |
n->peer_id = 0; |
||
3358 |
n->group_id = p->conf.id; |
||
3359 |
} else { |
||
3360 |
n->peer_id = p->conf.id; |
||
3361 |
n->group_id = 0; |
||
3362 |
} |
||
3363 |
} |
||
3364 |
if (rib) { |
||
3365 |
if (!find_rib(rib)) { |
||
3366 |
yyerror("rib \"%s\" does not exist.", rib); |
||
3367 |
free(n); |
||
3368 |
return (-1); |
||
3369 |
} |
||
3370 |
if (strlcpy(n->rib, rib, sizeof(n->rib)) >= |
||
3371 |
sizeof(n->rib)) { |
||
3372 |
yyerror("rib name \"%s\" too long: max %zu", |
||
3373 |
name, sizeof(n->rib) - 1); |
||
3374 |
free(n); |
||
3375 |
return (-1); |
||
3376 |
} |
||
3377 |
} |
||
3378 |
|||
3379 |
LIST_INSERT_HEAD(conf->mrt, n, entry); |
||
3380 |
|||
3381 |
return (0); |
||
3382 |
} |
||
3383 |
|||
3384 |
int |
||
3385 |
add_rib(char *name, u_int rtableid, u_int16_t flags) |
||
3386 |
{ |
||
3387 |
struct rde_rib *rr; |
||
3388 |
48 |
u_int rdom, default_rdom; |
|
3389 |
|||
3390 |
✓✗ | 24 |
if ((rr = find_rib(name)) == NULL) { |
3391 |
✗✓ | 24 |
if ((rr = calloc(1, sizeof(*rr))) == NULL) { |
3392 |
log_warn("add_rib"); |
||
3393 |
return (-1); |
||
3394 |
} |
||
3395 |
} |
||
3396 |
✗✓ | 24 |
if (strlcpy(rr->name, name, sizeof(rr->name)) >= sizeof(rr->name)) { |
3397 |
yyerror("rib name \"%s\" too long: max %zu", |
||
3398 |
name, sizeof(rr->name) - 1); |
||
3399 |
free(rr); |
||
3400 |
return (-1); |
||
3401 |
} |
||
3402 |
24 |
rr->flags |= flags; |
|
3403 |
✓✓ | 24 |
if ((rr->flags & F_RIB_HASNOFIB) == 0) { |
3404 |
✗✓ | 12 |
if (ktable_exists(rtableid, &rdom) != 1) { |
3405 |
yyerror("rtable id %u does not exist", rtableid); |
||
3406 |
free(rr); |
||
3407 |
return (-1); |
||
3408 |
} |
||
3409 |
✗✓ | 12 |
if (ktable_exists(conf->default_tableid, &default_rdom) != 1) |
3410 |
fatal("default rtable %u does not exist", |
||
3411 |
conf->default_tableid); |
||
3412 |
✗✓ | 12 |
if (rdom != default_rdom) { |
3413 |
log_warnx("rtable %u does not belong to rdomain %u", |
||
3414 |
rtableid, default_rdom); |
||
3415 |
free(rr); |
||
3416 |
return (-1); |
||
3417 |
} |
||
3418 |
12 |
rr->rtableid = rtableid; |
|
3419 |
12 |
} |
|
3420 |
24 |
SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry); |
|
3421 |
24 |
return (0); |
|
3422 |
24 |
} |
|
3423 |
|||
3424 |
struct rde_rib * |
||
3425 |
find_rib(char *name) |
||
3426 |
{ |
||
3427 |
struct rde_rib *rr; |
||
3428 |
|||
3429 |
✓✓ | 96 |
SIMPLEQ_FOREACH(rr, &ribnames, entry) { |
3430 |
✗✓ | 12 |
if (!strcmp(rr->name, name)) |
3431 |
return (rr); |
||
3432 |
} |
||
3433 |
24 |
return (NULL); |
|
3434 |
24 |
} |
|
3435 |
|||
3436 |
int |
||
3437 |
get_id(struct peer *newpeer) |
||
3438 |
{ |
||
3439 |
struct peer *p; |
||
3440 |
|||
3441 |
✗✓ | 120 |
for (p = peer_l_old; p != NULL; p = p->next) |
3442 |
if (newpeer->conf.remote_addr.aid) { |
||
3443 |
if (!memcmp(&p->conf.remote_addr, |
||
3444 |
&newpeer->conf.remote_addr, |
||
3445 |
sizeof(p->conf.remote_addr))) { |
||
3446 |
newpeer->conf.id = p->conf.id; |
||
3447 |
return (0); |
||
3448 |
} |
||
3449 |
} else { /* newpeer is a group */ |
||
3450 |
if (strcmp(newpeer->conf.group, p->conf.group) == 0) { |
||
3451 |
newpeer->conf.id = p->conf.groupid; |
||
3452 |
return (0); |
||
3453 |
} |
||
3454 |
} |
||
3455 |
|||
3456 |
/* new one */ |
||
3457 |
✓✗ | 80 |
for (; id < UINT_MAX / 2; id++) { |
3458 |
✗✓✗✗ |
80 |
for (p = peer_l_old; p != NULL && |
3459 |
p->conf.id != id && p->conf.groupid != id; p = p->next) |
||
3460 |
; /* nothing */ |
||
3461 |
✓✗ | 40 |
if (p == NULL) { /* we found a free id */ |
3462 |
40 |
newpeer->conf.id = id++; |
|
3463 |
40 |
return (0); |
|
3464 |
} |
||
3465 |
} |
||
3466 |
|||
3467 |
return (-1); |
||
3468 |
40 |
} |
|
3469 |
|||
3470 |
int |
||
3471 |
merge_prefixspec(struct filter_prefix_l *p, struct filter_prefixlen *pl) |
||
3472 |
{ |
||
3473 |
u_int8_t max_len = 0; |
||
3474 |
|||
3475 |
✗✓✓✓ |
312 |
switch (p->p.addr.aid) { |
3476 |
case AID_INET: |
||
3477 |
case AID_VPN_IPv4: |
||
3478 |
max_len = 32; |
||
3479 |
60 |
break; |
|
3480 |
case AID_INET6: |
||
3481 |
max_len = 128; |
||
3482 |
44 |
break; |
|
3483 |
} |
||
3484 |
|||
3485 |
✗✗✓✓ ✗✗✗✓ ✗✓ |
300 |
switch (pl->op) { |
3486 |
case OP_NONE: |
||
3487 |
return (0); |
||
3488 |
case OP_RANGE: |
||
3489 |
case OP_XRANGE: |
||
3490 |
✓✗✗✓ |
24 |
if (pl->len_min > max_len || pl->len_max > max_len) { |
3491 |
yyerror("prefixlen %d too big for AF, limit %d", |
||
3492 |
pl->len_min > max_len ? pl->len_min : pl->len_max, |
||
3493 |
max_len); |
||
3494 |
return (-1); |
||
3495 |
} |
||
3496 |
✗✓ | 12 |
if (pl->len_min < p->p.len) { |
3497 |
yyerror("prefixlen %d smaller than prefix, limit %d", |
||
3498 |
pl->len_min, p->p.len); |
||
3499 |
return (-1); |
||
3500 |
} |
||
3501 |
12 |
p->p.len_max = pl->len_max; |
|
3502 |
12 |
break; |
|
3503 |
case OP_GE: |
||
3504 |
/* fix up the "or-longer" case */ |
||
3505 |
✗✓ | 92 |
if (pl->len_min == -1) |
3506 |
pl->len_min = p->p.len; |
||
3507 |
/* FALLTHROUGH */ |
||
3508 |
case OP_EQ: |
||
3509 |
case OP_NE: |
||
3510 |
case OP_LE: |
||
3511 |
case OP_GT: |
||
3512 |
✗✓ | 92 |
if (pl->len_min > max_len) { |
3513 |
yyerror("prefixlen %d too big for AF, limit %d", |
||
3514 |
pl->len_min, max_len); |
||
3515 |
return (-1); |
||
3516 |
} |
||
3517 |
✗✓ | 92 |
if (pl->len_min < p->p.len) { |
3518 |
yyerror("prefixlen %d smaller than prefix, limit %d", |
||
3519 |
pl->len_min, p->p.len); |
||
3520 |
return (-1); |
||
3521 |
} |
||
3522 |
break; |
||
3523 |
case OP_LT: |
||
3524 |
if (pl->len_min > max_len - 1) { |
||
3525 |
yyerror("prefixlen %d too big for AF, limit %d", |
||
3526 |
pl->len_min, max_len - 1); |
||
3527 |
return (-1); |
||
3528 |
} |
||
3529 |
if (pl->len_min < p->p.len + 1) { |
||
3530 |
yyerror("prefixlen %d too small for prefix, limit %d", |
||
3531 |
pl->len_min, p->p.len + 1); |
||
3532 |
return (-1); |
||
3533 |
} |
||
3534 |
break; |
||
3535 |
} |
||
3536 |
|||
3537 |
104 |
p->p.op = pl->op; |
|
3538 |
104 |
p->p.len_min = pl->len_min; |
|
3539 |
104 |
return (0); |
|
3540 |
104 |
} |
|
3541 |
|||
3542 |
int |
||
3543 |
expand_rule(struct filter_rule *rule, struct filter_rib_l *rib, |
||
3544 |
struct filter_peers_l *peer, struct filter_match_l *match, |
||
3545 |
struct filter_set_head *set) |
||
3546 |
{ |
||
3547 |
struct filter_rule *r; |
||
3548 |
struct filter_rib_l *rb, *rbnext; |
||
3549 |
struct filter_peers_l *p, *pnext; |
||
3550 |
struct filter_prefix_l *prefix, *prefix_next; |
||
3551 |
struct filter_as_l *a, *anext; |
||
3552 |
struct filter_set *s; |
||
3553 |
|||
3554 |
rb = rib; |
||
3555 |
368 |
do { |
|
3556 |
p = peer; |
||
3557 |
184 |
do { |
|
3558 |
184 |
a = match->as_l; |
|
3559 |
184 |
do { |
|
3560 |
184 |
prefix = match->prefix_l; |
|
3561 |
184 |
do { |
|
3562 |
✗✓ | 368 |
if ((r = calloc(1, |
3563 |
184 |
sizeof(struct filter_rule))) == |
|
3564 |
NULL) { |
||
3565 |
log_warn("expand_rule"); |
||
3566 |
return (-1); |
||
3567 |
} |
||
3568 |
|||
3569 |
184 |
memcpy(r, rule, sizeof(struct filter_rule)); |
|
3570 |
184 |
memcpy(&r->match, match, |
|
3571 |
sizeof(struct filter_match)); |
||
3572 |
184 |
TAILQ_INIT(&r->set); |
|
3573 |
184 |
copy_filterset(set, &r->set); |
|
3574 |
|||
3575 |
✗✓ | 184 |
if (rb != NULL) |
3576 |
strlcpy(r->rib, rb->name, |
||
3577 |
sizeof(r->rib)); |
||
3578 |
|||
3579 |
✓✗ | 184 |
if (p != NULL) |
3580 |
184 |
memcpy(&r->peer, &p->p, |
|
3581 |
sizeof(struct filter_peers)); |
||
3582 |
|||
3583 |
✓✓ | 184 |
if (prefix != NULL) |
3584 |
104 |
memcpy(&r->match.prefix, &prefix->p, |
|
3585 |
sizeof(r->match.prefix)); |
||
3586 |
|||
3587 |
✓✓ | 184 |
if (a != NULL) |
3588 |
32 |
memcpy(&r->match.as, &a->a, |
|
3589 |
sizeof(struct filter_as)); |
||
3590 |
|||
3591 |
184 |
TAILQ_INSERT_TAIL(filter_l, r, entry); |
|
3592 |
|||
3593 |
✓✓ | 184 |
if (prefix != NULL) |
3594 |
104 |
prefix = prefix->next; |
|
3595 |
✗✓ | 184 |
} while (prefix != NULL); |
3596 |
|||
3597 |
✓✓ | 184 |
if (a != NULL) |
3598 |
32 |
a = a->next; |
|
3599 |
✗✓ | 184 |
} while (a != NULL); |
3600 |
|||
3601 |
✓✗ | 184 |
if (p != NULL) |
3602 |
184 |
p = p->next; |
|
3603 |
✗✓ | 184 |
} while (p != NULL); |
3604 |
|||
3605 |
✗✓ | 184 |
if (rb != NULL) |
3606 |
rb = rb->next; |
||
3607 |
✗✓ | 184 |
} while (rb != NULL); |
3608 |
|||
3609 |
✗✓ | 368 |
for (rb = rib; rb != NULL; rb = rbnext) { |
3610 |
rbnext = rb->next; |
||
3611 |
free(rb); |
||
3612 |
} |
||
3613 |
|||
3614 |
✓✓ | 736 |
for (p = peer; p != NULL; p = pnext) { |
3615 |
184 |
pnext = p->next; |
|
3616 |
184 |
free(p); |
|
3617 |
} |
||
3618 |
|||
3619 |
✓✓ | 432 |
for (a = match->as_l; a != NULL; a = anext) { |
3620 |
32 |
anext = a->next; |
|
3621 |
32 |
free(a); |
|
3622 |
} |
||
3623 |
|||
3624 |
✓✓ | 576 |
for (prefix = match->prefix_l; prefix != NULL; prefix = prefix_next) { |
3625 |
104 |
prefix_next = prefix->next; |
|
3626 |
104 |
free(prefix); |
|
3627 |
} |
||
3628 |
|||
3629 |
✓✓ | 184 |
if (set != NULL) { |
3630 |
✓✓ | 16 |
while ((s = TAILQ_FIRST(set)) != NULL) { |
3631 |
✗✓ | 12 |
TAILQ_REMOVE(set, s, entry); |
3632 |
4 |
free(s); |
|
3633 |
} |
||
3634 |
4 |
free(set); |
|
3635 |
4 |
} |
|
3636 |
|||
3637 |
184 |
return (0); |
|
3638 |
184 |
} |
|
3639 |
|||
3640 |
int |
||
3641 |
str2key(char *s, char *dest, size_t max_len) |
||
3642 |
{ |
||
3643 |
unsigned i; |
||
3644 |
40 |
char t[3]; |
|
3645 |
|||
3646 |
✗✓ | 20 |
if (strlen(s) / 2 > max_len) { |
3647 |
yyerror("key too long"); |
||
3648 |
return (-1); |
||
3649 |
} |
||
3650 |
|||
3651 |
✗✓ | 20 |
if (strlen(s) % 2) { |
3652 |
yyerror("key must be of even length"); |
||
3653 |
return (-1); |
||
3654 |
} |
||
3655 |
|||
3656 |
✓✓ | 648 |
for (i = 0; i < strlen(s) / 2; i++) { |
3657 |
304 |
t[0] = s[2*i]; |
|
3658 |
304 |
t[1] = s[2*i + 1]; |
|
3659 |
304 |
t[2] = 0; |
|
3660 |
✓✗✗✓ |
608 |
if (!isxdigit(t[0]) || !isxdigit(t[1])) { |
3661 |
yyerror("key must be specified in hex"); |
||
3662 |
return (-1); |
||
3663 |
} |
||
3664 |
304 |
dest[i] = strtoul(t, NULL, 16); |
|
3665 |
} |
||
3666 |
|||
3667 |
20 |
return (0); |
|
3668 |
20 |
} |
|
3669 |
|||
3670 |
int |
||
3671 |
neighbor_consistent(struct peer *p) |
||
3672 |
{ |
||
3673 |
u_int8_t i; |
||
3674 |
|||
3675 |
/* local-address and peer's address: same address family */ |
||
3676 |
✓✓✗✓ |
88 |
if (p->conf.local_addr.aid && |
3677 |
24 |
p->conf.local_addr.aid != p->conf.remote_addr.aid) { |
|
3678 |
yyerror("local-address and neighbor address " |
||
3679 |
"must be of the same address family"); |
||
3680 |
return (-1); |
||
3681 |
} |
||
3682 |
|||
3683 |
/* with any form of ipsec local-address is required */ |
||
3684 |
✓✓✗✓ |
52 |
if ((p->conf.auth.method == AUTH_IPSEC_IKE_ESP || |
3685 |
✓✓ | 28 |
p->conf.auth.method == AUTH_IPSEC_IKE_AH || |
3686 |
✓✓ | 16 |
p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP || |
3687 |
✗✓ | 12 |
p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) && |
3688 |
20 |
!p->conf.local_addr.aid) { |
|
3689 |
yyerror("neighbors with any form of IPsec configured " |
||
3690 |
"need local-address to be specified"); |
||
3691 |
return (-1); |
||
3692 |
} |
||
3693 |
|||
3694 |
/* with static keying we need both directions */ |
||
3695 |
✓✓✗✓ |
36 |
if ((p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP || |
3696 |
✗✓ | 28 |
p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) && |
3697 |
✓✗ | 8 |
(!p->conf.auth.spi_in || !p->conf.auth.spi_out)) { |
3698 |
yyerror("with manual keyed IPsec, SPIs and keys " |
||
3699 |
"for both directions are required"); |
||
3700 |
return (-1); |
||
3701 |
} |
||
3702 |
|||
3703 |
✗✓ | 32 |
if (!conf->as) { |
3704 |
yyerror("AS needs to be given before neighbor definitions"); |
||
3705 |
return (-1); |
||
3706 |
} |
||
3707 |
|||
3708 |
/* set default values if they where undefined */ |
||
3709 |
32 |
p->conf.ebgp = (p->conf.remote_as != conf->as); |
|
3710 |
✓✓ | 32 |
if (p->conf.announce_type == ANNOUNCE_UNDEF) |
3711 |
20 |
p->conf.announce_type = p->conf.ebgp ? |
|
3712 |
ANNOUNCE_SELF : ANNOUNCE_ALL; |
||
3713 |
✓✓ | 32 |
if (p->conf.enforce_as == ENFORCE_AS_UNDEF) |
3714 |
28 |
p->conf.enforce_as = p->conf.ebgp ? |
|
3715 |
ENFORCE_AS_ON : ENFORCE_AS_OFF; |
||
3716 |
✓✗ | 32 |
if (p->conf.enforce_local_as == ENFORCE_AS_UNDEF) |
3717 |
32 |
p->conf.enforce_local_as = ENFORCE_AS_ON; |
|
3718 |
|||
3719 |
✓✓✗✓ |
36 |
if (p->conf.remote_as == 0 && p->conf.enforce_as != ENFORCE_AS_OFF) { |
3720 |
yyerror("peer AS may not be zero"); |
||
3721 |
return (-1); |
||
3722 |
} |
||
3723 |
|||
3724 |
/* EBGP neighbors are not allowed in route reflector clusters */ |
||
3725 |
✗✓✗✗ |
32 |
if (p->conf.reflector_client && p->conf.ebgp) { |
3726 |
yyerror("EBGP neighbors are not allowed in route " |
||
3727 |
"reflector clusters"); |
||
3728 |
return (-1); |
||
3729 |
} |
||
3730 |
|||
3731 |
/* the default MP capability is NONE */ |
||
3732 |
✓✓ | 320 |
for (i = 0; i < AID_MAX; i++) |
3733 |
✓✓ | 128 |
if (p->conf.capabilities.mp[i] == -1) |
3734 |
96 |
p->conf.capabilities.mp[i] = 0; |
|
3735 |
|||
3736 |
32 |
return (0); |
|
3737 |
32 |
} |
|
3738 |
|||
3739 |
int |
||
3740 |
merge_filterset(struct filter_set_head *sh, struct filter_set *s) |
||
3741 |
{ |
||
3742 |
struct filter_set *t; |
||
3743 |
|||
3744 |
TAILQ_FOREACH(t, sh, entry) { |
||
3745 |
/* |
||
3746 |
* need to cycle across the full list because even |
||
3747 |
* if types are not equal filterset_cmp() may return 0. |
||
3748 |
*/ |
||
3749 |
if (filterset_cmp(s, t) == 0) { |
||
3750 |
if (s->type == ACTION_SET_COMMUNITY) |
||
3751 |
yyerror("community is already set"); |
||
3752 |
else if (s->type == ACTION_DEL_COMMUNITY) |
||
3753 |
yyerror("community will already be deleted"); |
||
3754 |
else if (s->type == ACTION_SET_LARGE_COMMUNITY) |
||
3755 |
yyerror("large-community is already set"); |
||
3756 |
else if (s->type == ACTION_DEL_LARGE_COMMUNITY) |
||
3757 |
yyerror("large-community will already be deleted"); |
||
3758 |
else if (s->type == ACTION_SET_EXT_COMMUNITY) |
||
3759 |
yyerror("ext-community is already set"); |
||
3760 |
else if (s->type == ACTION_DEL_EXT_COMMUNITY) |
||
3761 |
yyerror( |
||
3762 |
"ext-community will already be deleted"); |
||
3763 |
else |
||
3764 |
yyerror("redefining set parameter %s", |
||
3765 |
filterset_name(s->type)); |
||
3766 |
return (-1); |
||
3767 |
} |
||
3768 |
} |
||
3769 |
|||
3770 |
TAILQ_FOREACH(t, sh, entry) { |
||
3771 |
if (s->type < t->type) { |
||
3772 |
TAILQ_INSERT_BEFORE(t, s, entry); |
||
3773 |
return (0); |
||
3774 |
} |
||
3775 |
if (s->type == t->type) |
||
3776 |
switch (s->type) { |
||
3777 |
case ACTION_SET_COMMUNITY: |
||
3778 |
case ACTION_DEL_COMMUNITY: |
||
3779 |
if (s->action.community.as < |
||
3780 |
t->action.community.as || |
||
3781 |
(s->action.community.as == |
||
3782 |
t->action.community.as && |
||
3783 |
s->action.community.type < |
||
3784 |
t->action.community.type)) { |
||
3785 |
TAILQ_INSERT_BEFORE(t, s, entry); |
||
3786 |
return (0); |
||
3787 |
} |
||
3788 |
break; |
||
3789 |
case ACTION_SET_LARGE_COMMUNITY: |
||
3790 |
case ACTION_DEL_LARGE_COMMUNITY: |
||
3791 |
if (s->action.large_community.as < |
||
3792 |
t->action.large_community.as || |
||
3793 |
(s->action.large_community.as == |
||
3794 |
t->action.large_community.as && |
||
3795 |
s->action.large_community.ld1 < |
||
3796 |
t->action.large_community.ld2 )) { |
||
3797 |
TAILQ_INSERT_BEFORE(t, s, entry); |
||
3798 |
return (0); |
||
3799 |
} |
||
3800 |
break; |
||
3801 |
case ACTION_SET_EXT_COMMUNITY: |
||
3802 |
case ACTION_DEL_EXT_COMMUNITY: |
||
3803 |
if (memcmp(&s->action.ext_community, |
||
3804 |
&t->action.ext_community, |
||
3805 |
sizeof(s->action.ext_community)) < 0) { |
||
3806 |
TAILQ_INSERT_BEFORE(t, s, entry); |
||
3807 |
return (0); |
||
3808 |
} |
||
3809 |
break; |
||
3810 |
case ACTION_SET_NEXTHOP: |
||
3811 |
if (s->action.nexthop.aid < |
||
3812 |
t->action.nexthop.aid) { |
||
3813 |
TAILQ_INSERT_BEFORE(t, s, entry); |
||
3814 |
return (0); |
||
3815 |
} |
||
3816 |
break; |
||
3817 |
default: |
||
3818 |
break; |
||
3819 |
} |
||
3820 |
} |
||
3821 |
|||
3822 |
TAILQ_INSERT_TAIL(sh, s, entry); |
||
3823 |
return (0); |
||
3824 |
} |
||
3825 |
|||
3826 |
void |
||
3827 |
copy_filterset(struct filter_set_head *source, struct filter_set_head *dest) |
||
3828 |
{ |
||
3829 |
struct filter_set *s, *t; |
||
3830 |
|||
3831 |
✓✓ | 368 |
if (source == NULL) |
3832 |
180 |
return; |
|
3833 |
|||
3834 |
✓✓ | 16 |
TAILQ_FOREACH(s, source, entry) { |
3835 |
✗✓ | 4 |
if ((t = malloc(sizeof(struct filter_set))) == NULL) |
3836 |
fatal(NULL); |
||
3837 |
4 |
memcpy(t, s, sizeof(struct filter_set)); |
|
3838 |
4 |
TAILQ_INSERT_TAIL(dest, t, entry); |
|
3839 |
} |
||
3840 |
188 |
} |
|
3841 |
|||
3842 |
void |
||
3843 |
merge_filter_lists(struct filter_head *dst, struct filter_head *src) |
||
3844 |
{ |
||
3845 |
struct filter_rule *r; |
||
3846 |
|||
3847 |
✓✓ | 476 |
while ((r = TAILQ_FIRST(src)) != NULL) { |
3848 |
✓✓ | 552 |
TAILQ_REMOVE(src, r, entry); |
3849 |
184 |
TAILQ_INSERT_TAIL(dst, r, entry); |
|
3850 |
} |
||
3851 |
36 |
} |
|
3852 |
|||
3853 |
struct filter_rule * |
||
3854 |
get_rule(enum action_types type) |
||
3855 |
{ |
||
3856 |
struct filter_rule *r; |
||
3857 |
int out; |
||
3858 |
|||
3859 |
switch (type) { |
||
3860 |
case ACTION_SET_PREPEND_SELF: |
||
3861 |
case ACTION_SET_NEXTHOP_NOMODIFY: |
||
3862 |
case ACTION_SET_NEXTHOP_SELF: |
||
3863 |
out = 1; |
||
3864 |
break; |
||
3865 |
default: |
||
3866 |
out = 0; |
||
3867 |
break; |
||
3868 |
} |
||
3869 |
r = (curpeer == curgroup) ? curgroup_filter[out] : curpeer_filter[out]; |
||
3870 |
if (r == NULL) { |
||
3871 |
if ((r = calloc(1, sizeof(struct filter_rule))) == NULL) |
||
3872 |
fatal(NULL); |
||
3873 |
r->quick = 0; |
||
3874 |
r->dir = out ? DIR_OUT : DIR_IN; |
||
3875 |
r->action = ACTION_NONE; |
||
3876 |
r->match.community.as = COMMUNITY_UNSET; |
||
3877 |
r->match.large_community.as = COMMUNITY_UNSET; |
||
3878 |
TAILQ_INIT(&r->set); |
||
3879 |
if (curpeer == curgroup) { |
||
3880 |
/* group */ |
||
3881 |
r->peer.groupid = curgroup->conf.id; |
||
3882 |
curgroup_filter[out] = r; |
||
3883 |
} else { |
||
3884 |
/* peer */ |
||
3885 |
r->peer.peerid = curpeer->conf.id; |
||
3886 |
curpeer_filter[out] = r; |
||
3887 |
} |
||
3888 |
} |
||
3889 |
return (r); |
||
3890 |
} |
Generated by: GCOVR (Version 3.3) |