1 /*
2  *	BIRD -- Configuration Parser Top
3  *
4  *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
5  *
6  *	Can be freely distributed and used under the terms of the GNU GPL.
7  */
8 
9 CF_HDR
10 
11 #define PARSER 1
12 
13 #include "nest/bird.h"
14 #include "conf/conf.h"
15 #include "lib/resource.h"
16 #include "lib/socket.h"
17 #include "lib/timer.h"
18 #include "lib/string.h"
19 #include "nest/protocol.h"
20 #include "nest/iface.h"
21 #include "nest/route.h"
22 #include "nest/bfd.h"
23 #include "nest/cli.h"
24 #include "filter/filter.h"
25 
26 /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
27 
28 CF_DEFINES
29 
30 static void
check_u16(uint val)31 check_u16(uint val)
32 {
33   if (val > 0xFFFF)
34     cf_error("Value %u out of range (0-65535)", val);
35 }
36 
37 #define cf_assert(cond, ...) do { if (!(cond)) cf_error(__VA_ARGS__); } while (0)
cf_assert_symbol(const struct symbol * sym,uint class)38 static inline void cf_assert_symbol(const struct symbol *sym, uint class) {
39   switch (class) {
40     case SYM_PROTO: cf_assert(sym->class == SYM_PROTO, "Protocol name required"); break;
41     case SYM_TEMPLATE: cf_assert(sym->class == SYM_TEMPLATE, "Protocol template name required"); break;
42     case SYM_FUNCTION: cf_assert(sym->class == SYM_FUNCTION, "Function name required"); break;
43     case SYM_FILTER: cf_assert(sym->class == SYM_FILTER, "Filter name required"); break;
44     case SYM_TABLE: cf_assert(sym->class == SYM_TABLE, "Table name required"); break;
45     case SYM_ATTRIBUTE: cf_assert(sym->class == SYM_ATTRIBUTE, "Custom attribute name required"); break;
46     case SYM_VARIABLE: cf_assert((sym->class & ~0xff) == SYM_VARIABLE, "Variable name required"); break;
47     case SYM_CONSTANT: cf_assert((sym->class & ~0xff) == SYM_CONSTANT, "Constant name required"); break;
48     default: bug("This shall not happen");
49   }
50 }
51 
52 CF_DECLS
53 
54 %union {
55   uint i;
56   u32 i32;
57   u64 i64;
58   ip_addr a;
59   ip4_addr ip4;
60   ip6_addr ip6;
61   net_addr net;
62   net_addr *net_ptr;
63   struct symbol *s;
64   const char *t;
65   struct rtable_config *r;
66   struct channel_config *cc;
67   struct channel *c;
68   struct f_inst *x;
69   struct {
70     struct f_inst *begin, *end;
71   } xp;
72   enum filter_return fret;
73   enum ec_subtype ecs;
74   struct f_dynamic_attr fda;
75   struct f_static_attr fsa;
76   struct f_lval flv;
77   struct f_line *fl;
78   const struct filter *f;
79   struct f_tree *e;
80   struct f_trie *trie;
81   struct f_val v;
82   struct password_item *p;
83   struct rt_show_data *ra;
84   struct sym_show_data *sd;
85   struct lsadb_show_data *ld;
86   struct mrt_dump_data *md;
87   struct iface *iface;
88   void *g;
89   btime time;
90   struct f_prefix px;
91   struct proto_spec ps;
92   struct channel_limit cl;
93   struct timeformat *tf;
94   mpls_label_stack *mls;
95 }
96 
97 %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
98 %token GEQ LEQ NEQ AND OR
99 %token PO PC
100 %token <i> NUM ENUM
101 %token <ip4> IP4
102 %token <ip6> IP6
103 %token <i64> VPN_RD
104 %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
105 %token <t> TEXT
106 %type <iface> ipa_scope
107 
108 %type <i> expr bool pxlen4
109 %type <time> expr_us time
110 %type <a> ipa
111 %type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
112 %type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
113 %type <mls> label_stack_start label_stack
114 
115 %type <t> text opttext
116 %type <s> symbol
117 
118 %nonassoc PREFIX_DUMMY
119 %left AND OR
120 %nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
121 %left '+' '-'
122 %left '*' '/' '%'
123 %left '!'
124 %nonassoc '.'
125 
126 %start config
127 
128 CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
129 
130 CF_GRAMMAR
131 
132 /* Basic config file structure */
133 
134 config: conf_entries END { return 0; }
135  | CLI_MARKER cli_cmd { return 0; }
136  ;
137 
138 conf_entries:
139    /* EMPTY */
140  | conf_entries conf
141  ;
142 
143 conf: ';' ;
144 
145 
146 /* Constant expressions */
147 
148 conf: definition ;
149 
150 definition:
151    DEFINE symbol '=' term ';' {
152      struct f_val *val = cfg_allocz(sizeof(struct f_val));
153      if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
154      cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
155    }
156  ;
157 
158 expr:
159    NUM
160  | '(' term ')' { $$ = f_eval_int(f_linearize($2)); }
161  | CF_SYM_KNOWN {
162      if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number constant expected");
163      $$ = SYM_VAL($1).i; }
164  ;
165 
166 expr_us:
167    expr S  { $$ = $1 S_; }
168  | expr MS { $$ = $1 MS_; }
169  | expr US { $$ = $1 US_; }
170  ;
171 
172 symbol: CF_SYM_UNDEFINED | CF_SYM_KNOWN ;
173 
174 /* Switches */
175 
176 bool:
177    expr { $$ = !!$1; }
178  | ON { $$ = 1; }
179  | YES { $$ = 1; }
180  | OFF { $$ = 0; }
181  | NO { $$ = 0; }
182  | /* Silence means agreement */ { $$ = 1; }
183  ;
184 
185 
186 /* Addresses */
187 
188 ipa:
189    IP4 { $$ = ipa_from_ip4($1); }
190  | IP6 { $$ = ipa_from_ip6($1); }
191  | CF_SYM_KNOWN {
192      if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address constant expected");
193      $$ = SYM_VAL($1).ip;
194    }
195  ;
196 
197 ipa_scope:
198    /* empty */ { $$ = NULL; }
199  | '%' symbol { $$ = if_get_by_name($2->name); }
200  ;
201 
202 
203 /* Networks - internal */
204 
205 pxlen4:
206    '/' NUM {
207      if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
208      $$ = $2;
209    }
210  ;
211 
212 net_ip4_: IP4 pxlen4
213 {
214   net_fill_ip4(&($$), $1, $2);
215 
216   net_addr_ip4 *n = (void *) &($$);
217   if (!net_validate_ip4(n))
218     cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
219 	     n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen);
220 };
221 
222 net_ip6_: IP6 '/' NUM
223 {
224   if ($3 > IP6_MAX_PREFIX_LENGTH)
225     cf_error("Invalid prefix length %u", $3);
226 
227   net_fill_ip6(&($$), $1, $3);
228 
229   net_addr_ip6 *n = (void *) &($$);
230   if (!net_validate_ip6(n))
231     cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
232 	     n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
233 };
234 
235 net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
236 {
237   if ($3 > IP6_MAX_PREFIX_LENGTH)
238     cf_error("Invalid prefix length %u", $3);
239 
240   if ($7 > IP6_MAX_PREFIX_LENGTH)
241     cf_error("Invalid prefix length %u", $7);
242 
243   $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
244   net_fill_ip6_sadr($$, $1, $3, $5, $7);
245 
246   net_addr_ip6_sadr *n = (void *) $$;
247   if (!net_validate_ip6_sadr(n))
248     cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
249 	     n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
250 	     ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
251 	     ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
252 };
253 
254 net_vpn4_: VPN_RD net_ip4_
255 {
256   $$ = cfg_alloc(sizeof(net_addr_vpn4));
257   net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
258 }
259 
260 net_vpn6_: VPN_RD net_ip6_
261 {
262   $$ = cfg_alloc(sizeof(net_addr_vpn6));
263   net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
264 }
265 
266 net_roa4_: net_ip4_ MAX NUM AS NUM
267 {
268   $$ = cfg_alloc(sizeof(net_addr_roa4));
269   net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5);
270   if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH)
271     cf_error("Invalid max prefix length %u", $3);
272 };
273 
274 net_roa6_: net_ip6_ MAX NUM AS NUM
275 {
276   $$ = cfg_alloc(sizeof(net_addr_roa6));
277   net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5);
278   if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH)
279     cf_error("Invalid max prefix length %u", $3);
280 };
281 
282 net_mpls_: MPLS NUM
283 {
284   $$ = cfg_alloc(sizeof(net_addr_roa6));
285   net_fill_mpls($$, $2);
286 }
287 
288 net_ip_: net_ip4_ | net_ip6_ ;
289 net_vpn_: net_vpn4_ | net_vpn6_ ;
290 net_roa_: net_roa4_ | net_roa6_ ;
291 
292 net_:
293    net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
294  | net_vpn_
295  | net_roa_
296  | net_flow_
297  | net_ip6_sadr_
298  | net_mpls_
299  ;
300 
301 
302 /* Networks - regular */
303 
304 net_ip6:
305    net_ip6_
306  | CF_SYM_KNOWN {
307      if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
308        cf_error("IPv6 network constant expected");
309      $$ = * SYM_VAL($1).net;
310    }
311  ;
312 
313 net_ip:
314    net_ip_
315  | CF_SYM_KNOWN {
316      if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
317        cf_error("IP network constant expected");
318      $$ = * SYM_VAL($1).net;
319    }
320  ;
321 
322 net_any:
323    net_
324  | CF_SYM_KNOWN {
325      if ($1->class != (SYM_CONSTANT | T_NET))
326        cf_error("Network constant expected");
327      $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
328    }
329  ;
330 
331 net_or_ipa:
332    net_ip4_
333  | net_ip6_
334  | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
335  | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
336  | CF_SYM_KNOWN {
337      if ($1->class == (SYM_CONSTANT | T_IP))
338        net_fill_ip_host(&($$), SYM_VAL($1).ip);
339      else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
340        $$ = * SYM_VAL($1).net;
341      else
342        cf_error("IP address or network constant expected");
343    }
344  ;
345 
346 label_stack_start: NUM
347 {
348   $$ = cfg_allocz(sizeof(mpls_label_stack));
349   $$->len = 1;
350   $$->stack[0] = $1;
351 };
352 
353 label_stack:
354     label_stack_start
355   | label_stack '/' NUM {
356     if ($1->len >= MPLS_MAX_LABEL_STACK)
357       cf_error("Too many labels in stack");
358     $1->stack[$1->len++] = $3;
359     $$ = $1;
360   }
361 ;
362 
363 time:
364    TEXT {
365      $$ = tm_parse_time($1);
366      if (!$$)
367        cf_error("Invalid date/time");
368    }
369  ;
370 
371 text:
372    TEXT
373  | CF_SYM_KNOWN {
374      if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String constant expected");
375      $$ = SYM_VAL($1).s;
376    }
377  ;
378 
379 opttext:
380     TEXT
381  | /* empty */ { $$ = NULL; }
382  ;
383 
384 
385 CF_CODE
386 
387 CF_END
388