]>
Commit | Line | Data |
---|---|---|
77234bbb OZ |
1 | /* |
2 | * BIRD -- Flow specification (RFC 5575) grammar | |
3 | * | |
4 | * (c) 2016 CZ.NIC z.s.p.o. | |
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 "sysdep/unix/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/cli.h" | |
23 | #include "filter/filter.h" | |
24 | #include "lib/flowspec.h" | |
25 | ||
26 | ||
27 | CF_DEFINES | |
28 | ||
29 | struct flow_builder *this_flow; | |
30 | ||
31 | ||
32 | CF_DECLS | |
33 | ||
34 | %type <i32> flow_num_op flow_srcdst flow_logic_op flow_num_type_ flow_frag_val flow_neg | |
35 | %type <net_ptr> net_flow4_ net_flow6_ net_flow_ | |
36 | ||
37 | CF_KEYWORDS(FLOW4, FLOW6, DST, SRC, PROTO, NEXT, HEADER, DPORT, SPORT, ICMP, | |
38 | TYPE, CODE, TCP, FLAGS, LENGTH, DSCP, DONT_FRAGMENT, IS_FRAGMENT, | |
39 | FIRST_FRAGMENT, LAST_FRAGMENT, FRAGMENT, LABEL, OFFSET) | |
40 | ||
41 | ||
42 | CF_GRAMMAR | |
43 | ||
44 | /* Network Flow Specification */ | |
45 | ||
46 | flow_num_op: | |
734e9fb8 OZ |
47 | TRUE { $$ = FLOW_OP_TRUE; } |
48 | | '=' { $$ = FLOW_OP_EQ; } | |
49 | | NEQ { $$ = FLOW_OP_NEQ; } | |
50 | | '<' { $$ = FLOW_OP_LT; } | |
51 | | LEQ { $$ = FLOW_OP_LEQ; } | |
52 | | '>' { $$ = FLOW_OP_GT; } | |
53 | | GEQ { $$ = FLOW_OP_GEQ; } | |
54 | | FALSE { $$ = FLOW_OP_FALSE; } | |
77234bbb OZ |
55 | ; |
56 | ||
57 | flow_logic_op: | |
734e9fb8 OZ |
58 | OR { $$ = FLOW_OP_OR; } |
59 | | AND { $$ = FLOW_OP_AND; } | |
77234bbb OZ |
60 | ; |
61 | ||
62 | flow_num_type_: | |
63 | PROTO { $$ = FLOW_TYPE_IP_PROTOCOL; } | |
64 | | NEXT HEADER { $$ = FLOW_TYPE_NEXT_HEADER; } | |
65 | | PORT { $$ = FLOW_TYPE_PORT; } | |
66 | | DPORT { $$ = FLOW_TYPE_DST_PORT; } | |
67 | | SPORT { $$ = FLOW_TYPE_SRC_PORT; } | |
68 | | ICMP TYPE { $$ = FLOW_TYPE_ICMP_TYPE; } | |
69 | | ICMP CODE { $$ = FLOW_TYPE_ICMP_CODE; } | |
70 | | LENGTH { $$ = FLOW_TYPE_PACKET_LENGTH; } | |
71 | | DSCP { $$ = FLOW_TYPE_DSCP; } | |
72 | ; | |
73 | ||
74 | flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); }; | |
75 | flow_flag_type: TCP FLAGS { flow_builder_set_type(this_flow, FLOW_TYPE_TCP_FLAGS); }; | |
76 | flow_frag_type: FRAGMENT { flow_builder_set_type(this_flow, FLOW_TYPE_FRAGMENT); }; | |
77 | flow_label_type: LABEL { flow_builder_set_type(this_flow, FLOW_TYPE_LABEL); }; | |
78 | ||
79 | flow_srcdst: | |
80 | DST { $$ = FLOW_TYPE_DST_PREFIX; } | |
81 | | SRC { $$ = FLOW_TYPE_SRC_PREFIX; } | |
82 | ; | |
83 | ||
84 | flow_num_opts: | |
85 | flow_num_op expr { | |
86 | flow_check_cf_value_length(this_flow, $2); | |
87 | flow_builder_add_op_val(this_flow, $1, $2); | |
88 | } | |
89 | | flow_num_opts flow_logic_op flow_num_op expr { | |
90 | flow_check_cf_value_length(this_flow, $4); | |
91 | flow_builder_add_op_val(this_flow, $2 | $3, $4); | |
92 | } | |
93 | | flow_num_opt_ext | |
94 | | flow_num_opts OR flow_num_opt_ext | |
95 | ; | |
96 | ||
97 | flow_num_opt_ext_expr: | |
98 | expr { | |
99 | flow_check_cf_value_length(this_flow, $1); | |
734e9fb8 | 100 | flow_builder_add_op_val(this_flow, FLOW_OP_EQ, $1); |
77234bbb OZ |
101 | } |
102 | | expr DDOT expr { | |
103 | flow_check_cf_value_length(this_flow, $1); | |
104 | flow_check_cf_value_length(this_flow, $3); | |
734e9fb8 OZ |
105 | flow_builder_add_op_val(this_flow, FLOW_OP_GEQ, $1); |
106 | flow_builder_add_op_val(this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3); | |
77234bbb OZ |
107 | } |
108 | ; | |
109 | ||
110 | flow_num_opt_ext: | |
111 | flow_num_opt_ext_expr | |
112 | | flow_num_opt_ext ',' flow_num_opt_ext_expr | |
113 | ; | |
114 | ||
115 | flow_bmk_opts: | |
116 | flow_neg expr '/' expr { | |
117 | flow_check_cf_bmk_values(this_flow, $1, $2, $4); | |
118 | flow_builder_add_val_mask(this_flow, $1, $2, $4); | |
119 | } | |
120 | | flow_bmk_opts flow_logic_op flow_neg expr '/' expr { | |
121 | flow_check_cf_bmk_values(this_flow, $3, $4, $6); | |
122 | flow_builder_add_val_mask(this_flow, $2 | $3, $4, $6); | |
123 | } | |
124 | | flow_bmk_opts ',' flow_neg expr '/' expr { | |
125 | flow_check_cf_bmk_values(this_flow, $3, $4, $6); | |
126 | flow_builder_add_val_mask(this_flow, 0x40 | $3, $4, $6); /* AND */ | |
127 | } | |
128 | ; | |
129 | ||
130 | flow_neg: | |
131 | /* empty */ { $$ = 0x00; } | |
132 | | '!' { $$ = 0x02; } | |
133 | ; | |
134 | ||
135 | flow_frag_val: | |
136 | DONT_FRAGMENT { $$ = 1; } | |
137 | | IS_FRAGMENT { $$ = 2; } | |
138 | | FIRST_FRAGMENT { $$ = 4; } | |
139 | | LAST_FRAGMENT { $$ = 8; } | |
140 | ; | |
141 | ||
142 | flow_frag_opts: | |
143 | flow_neg flow_frag_val { | |
144 | flow_builder_add_val_mask(this_flow, 0, ($1 ? 0 : $2), $2); | |
145 | } | |
146 | | flow_frag_opts flow_logic_op flow_neg flow_frag_val { | |
147 | flow_builder_add_val_mask(this_flow, $2, ($3 ? 0 : $4), $4); | |
148 | } | |
149 | | flow_frag_opts ',' flow_neg flow_frag_val { | |
150 | flow_builder_add_val_mask(this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */ | |
151 | } | |
152 | ; | |
153 | ||
154 | flow4_item: | |
155 | flow_srcdst net_ip { | |
156 | flow_builder_set_type(this_flow, $1); | |
157 | flow_builder4_add_pfx(this_flow, (net_addr_ip4 *) &($2)); | |
158 | } | |
159 | | flow_num_type flow_num_opts | |
160 | | flow_flag_type flow_bmk_opts | |
161 | | flow_frag_type flow_frag_opts | |
162 | ; | |
163 | ||
164 | flow6_item: | |
165 | flow_srcdst net_ip6 { | |
166 | flow_builder_set_type(this_flow, $1); | |
167 | flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), 0); | |
168 | } | |
169 | | flow_srcdst net_ip6 OFFSET NUM { | |
170 | if ($4 > $2.pxlen) | |
171 | cf_error("Prefix offset is higher than prefix length"); | |
172 | flow_builder_set_type(this_flow, $1); | |
173 | flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), $4); | |
174 | } | |
175 | | flow_num_type flow_num_opts | |
176 | | flow_flag_type flow_bmk_opts | |
177 | | flow_frag_type flow_frag_opts | |
178 | | flow_label_type flow_bmk_opts | |
179 | ; | |
180 | ||
181 | flow4_opts: | |
182 | /* empty */ | |
183 | | flow4_opts flow4_item ';' | |
184 | ; | |
185 | ||
186 | flow6_opts: | |
187 | /* empty */ | |
188 | | flow6_opts flow6_item ';' | |
189 | ; | |
190 | ||
191 | flow_builder_init: | |
192 | { | |
193 | if (this_flow == NULL) | |
194 | this_flow = flow_builder_init(&root_pool); | |
195 | else | |
196 | flow_builder_clear(this_flow); | |
197 | }; | |
198 | ||
199 | flow_builder_set_ipv4: { this_flow->ipv6 = 0; }; | |
200 | flow_builder_set_ipv6: { this_flow->ipv6 = 1; }; | |
201 | ||
202 | net_flow4_: FLOW4 '{' flow_builder_init flow_builder_set_ipv4 flow4_opts '}' | |
203 | { | |
204 | $$ = (net_addr *) flow_builder4_finalize(this_flow, cfg_mem); | |
205 | flow4_validate_cf((net_addr_flow4 *) $$); | |
206 | }; | |
207 | ||
208 | net_flow6_: FLOW6 '{' flow_builder_init flow_builder_set_ipv6 flow6_opts '}' | |
209 | { | |
210 | $$ = (net_addr *) flow_builder6_finalize(this_flow, cfg_mem); | |
211 | flow6_validate_cf((net_addr_flow6 *) $$); | |
212 | }; | |
213 | ||
214 | net_flow_: net_flow4_ | net_flow6_ ; | |
215 | ||
216 | ||
217 | CF_CODE | |
218 | ||
219 | CF_END |