1 %{
2 /*
3 * Copyright (C) 2003 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 *
7 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
8 * Use is subject to license terms.
9 * Copyright 2019 Joyent, Inc.
10 */
11
12 #pragma ident "%Z%%M% %I% %E% SMI"
13
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/param.h>
17 #include <sys/socket.h>
18 #if defined(BSD) && (BSD >= 199306)
19 # include <sys/cdefs.h>
20 #endif
21 #include <sys/ioctl.h>
22
23 #include <net/if.h>
24 #if __FreeBSD_version >= 300000
25 # include <net/if_var.h>
26 #endif
27 #include <netinet/in.h>
28
29 #include <arpa/inet.h>
30
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <netdb.h>
36 #include <ctype.h>
37 #include <unistd.h>
38 #include <uuid/uuid.h>
39
40 #include "ipf.h"
41 #include "netinet/ip_lookup.h"
42 #include "netinet/ip_pool.h"
43 #include "netinet/ip_htable.h"
44 #include "ippool_l.h"
45 #include "kmem.h"
46
47 #define YYDEBUG 1
48
49 extern int yyparse __P((void));
50 extern int yydebug;
51 extern FILE *yyin;
52
53 static iphtable_t ipht;
54 static iphtent_t iphte;
55 static ip_pool_t iplo;
56 static ioctlfunc_t poolioctl = NULL;
57 static char poolname[FR_GROUPLEN];
58 static int set_ipv6_addr = 0;
59
60 %}
61
62 %union {
63 char *str;
64 u_32_t num;
65 struct in_addr addr;
66 struct alist_s *alist;
67 union i6addr adrmsk[2];
68 iphtent_t *ipe;
69 ip_pool_node_t *ipp;
70 union i6addr ip6;
71 uuid_t uuid;
72 }
73
74 %token <num> YY_NUMBER YY_HEX
75 %token <str> YY_STR
76 %token YY_COMMENT
77 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
78 %token YY_RANGE_OUT YY_RANGE_IN
79 %token <ip6> YY_IPV6
80 %token <uuid> YY_UUID
81
82 %token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT
83 %token IPT_TABLE IPT_GROUPMAP IPT_HASH
84 %token IPT_ROLE IPT_TYPE IPT_TREE
85 %token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME
86 %type <num> role table inout
87 %type <ipp> ipftree range addrlist
88 %type <adrmsk> addrmask
89 %type <ipe> ipfgroup ipfhash hashlist hashentry
90 %type <ipe> groupentry setgrouplist grouplist
91 %type <ip6> ipaddr mask ipv4
92 %type <str> number setgroup
93
94 %%
95 file: line
96 | assign
97 | file line
98 | file assign
99 ;
100
101 line: table role ipftree eol { iplo.ipo_unit = $2;
102 iplo.ipo_list = $3;
103 load_pool(&iplo, poolioctl);
104 resetlexer();
105 }
106 | table role ipfhash eol { ipht.iph_unit = $2;
107 ipht.iph_type = IPHASH_LOOKUP;
108 load_hash(&ipht, $3, poolioctl);
109 resetlexer();
110 }
111 | groupmap role number ipfgroup eol
112 { ipht.iph_unit = $2;
113 strncpy(ipht.iph_name, $3,
114 sizeof(ipht.iph_name));
115 ipht.iph_type = IPHASH_GROUPMAP;
116 load_hash(&ipht, $4, poolioctl);
117 resetlexer();
118 }
119 | YY_COMMENT
120 ;
121
122 eol: ';'
123 ;
124
125 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
126 resetlexer();
127 free($1);
128 free($3);
129 }
130 ;
131
132 assigning:
133 '=' { yyvarnext = 1; }
134 ;
135
136 table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht));
137 bzero((char *)&iphte, sizeof(iphte));
138 bzero((char *)&iplo, sizeof(iplo));
139 *ipht.iph_name = '\0';
140 iplo.ipo_flags = IPHASH_ANON;
141 iplo.ipo_name[0] = '\0';
142 }
143 ;
144
145 groupmap:
146 IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht));
147 bzero((char *)&iphte, sizeof(iphte));
148 *ipht.iph_name = '\0';
149 ipht.iph_unit = IPHASH_GROUPMAP;
150 ipht.iph_flags = $2;
151 }
152 ;
153
154 inout: IPT_IN { $$ = FR_INQUE; }
155 | IPT_OUT { $$ = FR_OUTQUE; }
156 ;
157 role:
158 IPT_ROLE '=' IPT_IPF { $$ = IPL_LOGIPF; }
159 | IPT_ROLE '=' IPT_NAT { $$ = IPL_LOGNAT; }
160 | IPT_ROLE '=' IPT_AUTH { $$ = IPL_LOGAUTH; }
161 | IPT_ROLE '=' IPT_COUNT { $$ = IPL_LOGCOUNT; }
162 ;
163
164 ipftree:
165 IPT_TYPE '=' IPT_TREE number start addrlist end
166 { strncpy(iplo.ipo_name, $4,
167 sizeof(iplo.ipo_name));
168 $$ = $6;
169 }
170 ;
171
172 ipfhash:
173 IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
174 { strncpy(ipht.iph_name, $4,
175 sizeof(ipht.iph_name));
176 $$ = $7;
177 }
178 ;
179
180 ipfgroup:
181 setgroup hashopts start grouplist end
182 { iphtent_t *e;
183 for (e = $4; e != NULL;
184 e = e->ipe_next)
185 if (e->ipe_group[0] == '\0')
186 strncpy(e->ipe_group,
187 $1,
188 FR_GROUPLEN);
189 $$ = $4;
190 }
191 | hashopts start setgrouplist end { $$ = $3; }
192 ;
193
194 number: IPT_NUM '=' YY_NUMBER { snprintf(poolname, FR_GROUPLEN, "%u", $3);
195 $$ = poolname;
196 }
197 | IPT_NAME '=' YY_STR { $$ = $3; }
198 | { $$ = ""; }
199 ;
200
201 setgroup:
202 IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1];
203 strncpy(tmp, $3, FR_GROUPLEN);
204 $$ = strdup(tmp);
205 }
206 | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1];
207 snprintf(tmp, FR_GROUPLEN, "%u", $3);
208 $$ = strdup(tmp);
209 }
210 ;
211
212 hashopts:
213 | size
214 | seed
215 | size seed
216 ;
217
218 addrlist:
219 ';' { $$ = NULL; }
220 | range next addrlist { $1->ipn_next = $3; $$ = $1; }
221 | range next { $$ = $1; }
222 | range
223 ;
224
225 grouplist:
226 ';' { $$ = NULL; }
227 | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; }
228 | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t));
229 if ($$ == NULL)
230 yyerror("sorry, out of memory");
231 if (set_ipv6_addr)
232 $$->ipe_family = AF_INET6;
233 else
234 $$->ipe_family = AF_INET;
235 bcopy((char *)&($1[0]),
236 (char *)&($$->ipe_addr),
237 sizeof($$->ipe_addr));
238 bcopy((char *)&($1[1]),
239 (char *)&($$->ipe_mask),
240 sizeof($$->ipe_mask));
241 set_ipv6_addr = 0;
242 $$->ipe_next = $3;
243 }
244 | groupentry next { $$ = $1; }
245 | addrmask next { $$ = calloc(1, sizeof(iphtent_t));
246 if ($$ == NULL)
247 yyerror("sorry, out of memory");
248 if (set_ipv6_addr)
249 $$->ipe_family = AF_INET6;
250 else
251 $$->ipe_family = AF_INET;
252 bcopy((char *)&($1[0]),
253 (char *)&($$->ipe_addr),
254 sizeof($$->ipe_addr));
255 bcopy((char *)&($1[1]),
256 (char *)&($$->ipe_mask),
257 sizeof($$->ipe_mask));
258 set_ipv6_addr = 0;
259 }
260 ;
261
262 setgrouplist:
263 ';' { $$ = NULL; }
264 | groupentry next { $$ = $1; }
265 | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; }
266 ;
267
268 groupentry:
269 addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t));
270 if ($$ == NULL)
271 yyerror("sorry, out of memory");
272 if (set_ipv6_addr)
273 $$->ipe_family = AF_INET6;
274 else
275 $$->ipe_family = AF_INET;
276 bcopy((char *)&($1[0]),
277 (char *)&($$->ipe_addr),
278 sizeof($$->ipe_addr));
279 bcopy((char *)&($1[1]),
280 (char *)&($$->ipe_mask),
281 sizeof($$->ipe_mask));
282 set_ipv6_addr = 0;
283 strncpy($$->ipe_group, $3,
284 FR_GROUPLEN);
285 free($3);
286 }
287 ;
288
289 range: addrmask { $$ = calloc(1, sizeof(*$$));
290 if ($$ == NULL)
291 yyerror("sorry, out of memory");
292 $$->ipn_info = 0;
293 $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
294 $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
295 if (set_ipv6_addr) {
296 $$->ipn_addr.adf_family = AF_INET6;
297 $$->ipn_addr.adf_addr = $1[0];
298 $$->ipn_mask.adf_addr = $1[1];
299
300 } else {
301 $$->ipn_addr.adf_family = AF_INET;
302 $$->ipn_addr.adf_addr.in4.s_addr = $1[0].in4.s_addr;
303 $$->ipn_mask.adf_addr.in4.s_addr = $1[1].in4.s_addr;
304 }
305 set_ipv6_addr = 0;
306 }
307 | '!' addrmask { $$ = calloc(1, sizeof(*$$));
308 if ($$ == NULL)
309 yyerror("sorry, out of memory");
310 $$->ipn_info = 1;
311 $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
312 $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
313 if (set_ipv6_addr) {
314 $$->ipn_addr.adf_family = AF_INET6;
315 $$->ipn_addr.adf_addr = $2[0];
316 $$->ipn_mask.adf_addr = $2[1];
317 } else {
318 $$->ipn_addr.adf_family = AF_INET;
319 $$->ipn_addr.adf_addr.in4.s_addr = $2[0].in4.s_addr;
320 $$->ipn_mask.adf_addr.in4.s_addr = $2[1].in4.s_addr;
321 }
322 set_ipv6_addr = 0;
323 }
324
325 hashlist:
326 ';' { $$ = NULL; }
327 | hashentry next { $$ = $1; }
328 | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; }
329 ;
330
331 hashentry:
332 addrmask { $$ = calloc(1, sizeof(iphtent_t));
333 if ($$ == NULL)
334 yyerror("sorry, out of memory");
335 if (set_ipv6_addr)
336 $$->ipe_family = AF_INET6;
337 else
338 $$->ipe_family = AF_INET;
339 bcopy((char *)&($1[0]),
340 (char *)&($$->ipe_addr),
341 sizeof($$->ipe_addr));
342 bcopy((char *)&($1[1]),
343 (char *)&($$->ipe_mask),
344 sizeof($$->ipe_mask));
345 }
346 ;
347
348 addrmask:
349 ipaddr '/' mask { $$[0] = $1; $$[1] = $3;
350 yyexpectaddr = 0;
351 }
352 | ipaddr { $$[0] = $1;
353 yyexpectaddr = 0;
354 if (set_ipv6_addr)
355 fill6bits(128, (u_32_t *)$$[1].in6.s6_addr);
356 else
357 $$[1].in4.s_addr = 0xffffffff;
358 }
359 ;
360
361 ipaddr: ipv4 { $$ = $1; }
362 | YY_NUMBER { $$.in4.s_addr = htonl($1); }
363 | YY_IPV6 { set_ipv6_addr = 1;
364 bcopy(&$1, &$$, sizeof($$));
365 yyexpectaddr = 0; }
366 | YY_STR { if (gethost($1, &$$, 0) == -1)
367 yyerror("Unknown hostname");
368 }
369 ;
370
371 mask: YY_NUMBER { if (set_ipv6_addr)
372 ntomask(6, $1, (u_32_t *)$$.in6.s6_addr);
373 else
374 ntomask(4, $1, (u_32_t *)&$$.in4.s_addr); }
375 | ipv4 { $$ = $1; }
376 ;
377
378 start: '{' { yyexpectaddr = 1; }
379 ;
380
381 end: '}' { yyexpectaddr = 0; }
382 ;
383
384 next: ',' { yyexpectaddr = 1; }
385 | ';' { yyexpectaddr = 1; }
386 ;
387
388 size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; }
389 ;
390
391 seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; }
392 ;
393
394 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
395 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
396 yyerror("Invalid octet string for IP address");
397 return 0;
398 }
399 $$.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
400 $$.in4.s_addr = htonl($$.in4.s_addr);
401 }
402 ;
403 %%
404 static wordtab_t yywords[] = {
405 { "auth", IPT_AUTH },
406 { "count", IPT_COUNT },
407 { "group", IPT_GROUP },
408 { "group-map", IPT_GROUPMAP },
409 { "hash", IPT_HASH },
410 { "in", IPT_IN },
411 { "ipf", IPT_IPF },
412 { "name", IPT_NAME },
413 { "nat", IPT_NAT },
414 { "number", IPT_NUM },
415 { "out", IPT_OUT },
416 { "role", IPT_ROLE },
417 { "seed", IPT_SEED },
418 { "size", IPT_SIZE },
419 { "table", IPT_TABLE },
420 { "tree", IPT_TREE },
421 { "type", IPT_TYPE },
422 { NULL, 0 }
423 };
424
425
426 int ippool_parsefile(fd, filename, iocfunc)
427 int fd;
428 char *filename;
429 ioctlfunc_t iocfunc;
430 {
431 FILE *fp = NULL;
432 char *s;
433
434 yylineNum = 1;
435 (void) yysettab(yywords);
436
437 s = getenv("YYDEBUG");
438 if (s)
439 yydebug = atoi(s);
440 else
441 yydebug = 0;
442
443 if (strcmp(filename, "-")) {
444 fp = fopen(filename, "r");
445 if (!fp) {
446 fprintf(stderr, "fopen(%s) failed: %s\n", filename,
447 STRERROR(errno));
448 return -1;
449 }
450 } else
451 fp = stdin;
452
453 while (ippool_parsesome(fd, fp, iocfunc) == 1)
454 ;
455 if (fp != NULL)
456 fclose(fp);
457 return 0;
458 }
459
460
461 int ippool_parsesome(fd, fp, iocfunc)
462 int fd;
463 FILE *fp;
464 ioctlfunc_t iocfunc;
465 {
466 char *s;
467 int i;
468
469 poolioctl = iocfunc;
470
471 if (feof(fp))
472 return 0;
473 i = fgetc(fp);
474 if (i == EOF)
475 return 0;
476 if (ungetc(i, fp) == EOF)
477 return 0;
478 if (feof(fp))
479 return 0;
480 s = getenv("YYDEBUG");
481 if (s)
482 yydebug = atoi(s);
483 else
484 yydebug = 0;
485
486 yyin = fp;
487 yyparse();
488 return 1;
489 }