4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
11 #include <sys/param.h>
12 #include <sys/socket.h>
13 #if defined(BSD) && (BSD >= 199306)
14 # include <sys/cdefs.h>
16 #include <sys/ioctl.h>
19 #include <netinet/in.h>
21 #include <arpa/inet.h>
32 #include "netinet/ip_lookup.h"
33 #include "netinet/ip_pool.h"
34 #include "netinet/ip_htable.h"
35 #include "netinet/ip_dstlist.h"
40 #define YYSTACKSIZE 0x00ffffff
42 extern int yyparse __P((void));
46 static iphtable_t ipht;
47 static iphtent_t iphte;
48 static ip_pool_t iplo;
49 static ippool_dst_t ipld;
50 static ioctlfunc_t poolioctl = NULL;
51 static char poolname[FR_GROUPLEN];
53 static iphtent_t *add_htablehosts __P((char *));
54 static ip_pool_node_t *add_poolhosts __P((char *));
55 static ip_pool_node_t *read_whoisfile __P((char *));
56 static void setadflen __P((addrfamily_t *));
64 struct alist_s *alist;
65 addrfamily_t adrmsk[2];
73 %token <num> YY_NUMBER YY_HEX
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 IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT IPT_ALL
80 %token IPT_TABLE IPT_GROUPMAP IPT_HASH IPT_SRCHASH IPT_DSTHASH
81 %token IPT_ROLE IPT_TYPE IPT_TREE
82 %token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME IPT_POLICY
83 %token IPT_POOL IPT_DSTLIST IPT_ROUNDROBIN
84 %token IPT_WEIGHTED IPT_RANDOM IPT_CONNECTION
85 %token IPT_WHOIS IPT_FILE
86 %type <num> role table inout unit dstopts weighting
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 <ipa> ipaddr mask
93 %type <str> number setgroup name
94 %type <ipd> dstentry dstentries dstlist
103 line: table role ipftree eol { ip_pool_node_t *n;
106 load_pool(&iplo, poolioctl);
107 while ((n = $3) != NULL) {
114 | table role ipfhash eol { iphtent_t *h;
116 ipht.iph_type = IPHASH_LOOKUP;
117 load_hash(&ipht, $3, poolioctl);
118 while ((h = $3) != NULL) {
125 | groupmap role number ipfgroup eol
128 strncpy(ipht.iph_name, $3,
129 sizeof(ipht.iph_name));
130 ipht.iph_type = IPHASH_GROUPMAP;
131 load_hash(&ipht, $4, poolioctl);
132 while ((h = $4) != NULL) {
146 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
155 '=' { yyvarnext = 1; }
158 table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht));
159 bzero((char *)&iphte, sizeof(iphte));
160 bzero((char *)&iplo, sizeof(iplo));
161 bzero((char *)&ipld, sizeof(ipld));
162 *ipht.iph_name = '\0';
163 iplo.ipo_flags = IPHASH_ANON;
164 iplo.ipo_name[0] = '\0';
169 IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht));
170 bzero((char *)&iphte, sizeof(iphte));
171 *ipht.iph_name = '\0';
172 ipht.iph_unit = IPHASH_GROUPMAP;
177 inout: IPT_IN { $$ = FR_INQUE; }
178 | IPT_OUT { $$ = FR_OUTQUE; }
181 role: IPT_ROLE '=' unit { $$ = $3; }
184 unit: IPT_IPF { $$ = IPL_LOGIPF; }
185 | IPT_NAT { $$ = IPL_LOGNAT; }
186 | IPT_AUTH { $$ = IPL_LOGAUTH; }
187 | IPT_COUNT { $$ = IPL_LOGCOUNT; }
188 | IPT_ALL { $$ = IPL_LOGALL; }
192 IPT_TYPE '=' IPT_TREE number start addrlist end
193 { strncpy(iplo.ipo_name, $4,
194 sizeof(iplo.ipo_name));
200 IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
201 { strncpy(ipht.iph_name, $4,
202 sizeof(ipht.iph_name));
208 setgroup hashopts start grouplist end
210 for (e = $4; e != NULL;
212 if (e->ipe_group[0] == '\0')
213 strncpy(e->ipe_group,
219 | hashopts start setgrouplist end
223 number: IPT_NUM '=' YY_NUMBER { sprintf(poolname, "%u", $3);
226 | IPT_NAME '=' YY_STR { strncpy(poolname, $3,
228 poolname[FR_GROUPLEN-1]='\0';
236 IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1];
237 strncpy(tmp, $3, FR_GROUPLEN);
241 | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1];
242 sprintf(tmp, "%u", $3);
255 | range next addrlist { $$ = $1;
256 while ($1->ipn_next != NULL)
260 | range next { $$ = $1; }
265 | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; }
266 | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t));
267 $$->ipe_addr = $1[0].adf_addr;
268 $$->ipe_mask = $1[1].adf_addr;
269 $$->ipe_family = $1[0].adf_family;
272 | groupentry next { $$ = $1; }
273 | addrmask next { $$ = calloc(1, sizeof(iphtent_t));
274 $$->ipe_addr = $1[0].adf_addr;
275 $$->ipe_mask = $1[1].adf_addr;
278 $$->ipe_family = AF_INET6;
281 $$->ipe_family = AF_INET;
283 | YY_STR { $$ = add_htablehosts($1);
290 | groupentry next { $$ = $1; }
291 | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; }
295 addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t));
296 $$->ipe_addr = $1[0].adf_addr;
297 $$->ipe_mask = $1[1].adf_addr;
298 strncpy($$->ipe_group, $3,
302 $$->ipe_family = AF_INET6;
305 $$->ipe_family = AF_INET;
310 range: addrmask { $$ = calloc(1, sizeof(*$$));
312 $$->ipn_addr = $1[0];
313 $$->ipn_mask = $1[1];
315 | '!' addrmask { $$ = calloc(1, sizeof(*$$));
317 $$->ipn_addr = $2[0];
318 $$->ipn_mask = $2[1];
320 | YY_STR { $$ = add_poolhosts($1);
323 | IPT_WHOIS IPT_FILE YY_STR { $$ = read_whoisfile($3);
330 | hashentry next { $$ = $1; }
331 | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; }
335 addrmask { $$ = calloc(1, sizeof(iphtent_t));
336 $$->ipe_addr = $1[0].adf_addr;
337 $$->ipe_mask = $1[1].adf_addr;
340 $$->ipe_family = AF_INET6;
343 $$->ipe_family = AF_INET;
345 | YY_STR { $$ = add_htablehosts($1);
351 ipaddr '/' mask { $$[0] = $1;
354 $$[1].adf_len = $$[0].adf_len;
356 | ipaddr { $$[0] = $1;
358 $$[1].adf_len = $$[0].adf_len;
361 memset(&$$[1].adf_addr, 0xff,
362 sizeof($$[1].adf_addr.in6));
365 memset(&$$[1].adf_addr, 0xff,
366 sizeof($$[1].adf_addr.in4));
370 ipaddr: ipv4 { $$.adf_addr.in4 = $1;
371 $$.adf_family = AF_INET;
375 | YY_NUMBER { $$.adf_addr.in4.s_addr = htonl($1);
376 $$.adf_family = AF_INET;
380 | YY_IPV6 { $$.adf_addr = $1;
381 $$.adf_family = AF_INET6;
387 mask: YY_NUMBER { bzero(&$$, sizeof($$));
389 if (ntomask(AF_INET6, $1,
390 (u_32_t *)&$$.adf_addr) == -1)
391 yyerror("bad bitmask");
393 if (ntomask(AF_INET, $1,
394 (u_32_t *)&$$.adf_addr.in4) == -1)
395 yyerror("bad bitmask");
398 | ipv4 { bzero(&$$, sizeof($$));
399 $$.adf_addr.in4 = $1;
401 | YY_IPV6 { bzero(&$$, sizeof($$));
406 size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; }
409 seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; }
412 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
413 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
414 yyerror("Invalid octet string for IP address");
417 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
418 $$.s_addr = htonl($$.s_addr);
422 next: ';' { yyexpectaddr = 1; }
425 start: '{' { yyexpectaddr = 1; }
428 end: '}' { yyexpectaddr = 0; }
432 IPT_POOL unit '/' IPT_DSTLIST '(' name ';' dstopts ')'
434 { bzero((char *)&ipld, sizeof(ipld));
435 strncpy(ipld.ipld_name, $6,
436 sizeof(ipld.ipld_name));
438 ipld.ipld_policy = $8;
439 load_dstlist(&ipld, poolioctl, $11);
444 | IPT_POOL unit '/' IPT_TREE '(' name ';' ')'
446 { bzero((char *)&iplo, sizeof(iplo));
447 strncpy(iplo.ipo_name, $6,
448 sizeof(iplo.ipo_name));
451 load_pool(&iplo, poolioctl);
456 | IPT_POOL '(' name ';' ')' start addrlist end
457 { bzero((char *)&iplo, sizeof(iplo));
458 strncpy(iplo.ipo_name, $3,
459 sizeof(iplo.ipo_name));
461 iplo.ipo_unit = IPL_LOGALL;
462 load_pool(&iplo, poolioctl);
467 | IPT_POOL unit '/' IPT_HASH '(' name ';' hashoptlist ')'
470 bzero((char *)&ipht, sizeof(ipht));
471 strncpy(ipht.iph_name, $6,
472 sizeof(ipht.iph_name));
474 load_hash(&ipht, $11, poolioctl);
475 while ((h = ipht.iph_list) != NULL) {
476 ipht.iph_list = h->ipe_next;
483 | IPT_GROUPMAP '(' name ';' inout ';' ')'
484 start setgrouplist end
486 bzero((char *)&ipht, sizeof(ipht));
487 strncpy(ipht.iph_name, $3,
488 sizeof(ipht.iph_name));
489 ipht.iph_type = IPHASH_GROUPMAP;
490 ipht.iph_unit = IPL_LOGIPF;
492 load_hash(&ipht, $9, poolioctl);
493 while ((h = ipht.iph_list) != NULL) {
494 ipht.iph_list = h->ipe_next;
503 name: IPT_NAME YY_STR { $$ = $2; }
504 | IPT_NUM YY_NUMBER { char name[80];
505 sprintf(name, "%d", $2);
512 | hashoptlist ';' hashopt ';'
520 dstentries { $$ = $1; }
525 dstentry next { $$ = $1; }
526 | dstentry next dstentries { $1->ipfd_next = $3; $$ = $1; }
530 YY_STR ':' ipaddr { int size = sizeof(*$$) + strlen($1) + 1;
531 $$ = calloc(1, size);
533 $$->ipfd_dest.fd_name = strlen($1) + 1;
534 bcopy($1, $$->ipfd_names,
535 $$->ipfd_dest.fd_name);
536 $$->ipfd_dest.fd_addr = $3;
537 $$->ipfd_size = size;
541 | ipaddr { $$ = calloc(1, sizeof(*$$));
543 $$->ipfd_dest.fd_name = -1;
544 $$->ipfd_dest.fd_addr = $1;
545 $$->ipfd_size = sizeof(*$$);
552 | IPT_POLICY IPT_ROUNDROBIN ';' { $$ = IPLDP_ROUNDROBIN; }
553 | IPT_POLICY IPT_WEIGHTED weighting ';' { $$ = $3; }
554 | IPT_POLICY IPT_RANDOM ';' { $$ = IPLDP_RANDOM; }
555 | IPT_POLICY IPT_HASH ';' { $$ = IPLDP_HASHED; }
556 | IPT_POLICY IPT_SRCHASH ';' { $$ = IPLDP_SRCHASH; }
557 | IPT_POLICY IPT_DSTHASH ';' { $$ = IPLDP_DSTHASH; }
561 IPT_CONNECTION { $$ = IPLDP_CONNECTION; }
564 static wordtab_t yywords[] = {
566 { "auth", IPT_AUTH },
567 { "connection", IPT_CONNECTION },
568 { "count", IPT_COUNT },
569 { "dst-hash", IPT_DSTHASH },
570 { "dstlist", IPT_DSTLIST },
571 { "file", IPT_FILE },
572 { "group", IPT_GROUP },
573 { "group-map", IPT_GROUPMAP },
574 { "hash", IPT_HASH },
577 { "name", IPT_NAME },
579 { "number", IPT_NUM },
581 { "policy", IPT_POLICY },
582 { "pool", IPT_POOL },
583 { "random", IPT_RANDOM },
584 { "round-robin", IPT_ROUNDROBIN },
585 { "role", IPT_ROLE },
586 { "seed", IPT_SEED },
587 { "size", IPT_SIZE },
588 { "src-hash", IPT_SRCHASH },
589 { "table", IPT_TABLE },
590 { "tree", IPT_TREE },
591 { "type", IPT_TYPE },
592 { "weighted", IPT_WEIGHTED },
593 { "whois", IPT_WHOIS },
598 int ippool_parsefile(fd, filename, iocfunc)
607 (void) yysettab(yywords);
609 s = getenv("YYDEBUG");
615 if (strcmp(filename, "-")) {
616 fp = fopen(filename, "r");
618 fprintf(stderr, "fopen(%s) failed: %s\n", filename,
625 while (ippool_parsesome(fd, fp, iocfunc) == 1)
633 int ippool_parsesome(fd, fp, iocfunc)
648 if (ungetc(i, fp) == EOF)
652 s = getenv("YYDEBUG");
668 iphtent_t *htop, *hbot, *h;
671 if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
672 hlist = load_url(url);
676 hlist = calloc(1, sizeof(*hlist));
680 if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) {
681 yyerror("Unknown hostname");
688 for (a = hlist; a != NULL; a = a->al_next) {
689 h = calloc(1, sizeof(*h));
693 h->ipe_family = a->al_family;
694 h->ipe_addr = a->al_i6addr;
695 h->ipe_mask = a->al_i6mask;
710 static ip_pool_node_t *
714 ip_pool_node_t *ptop, *pbot, *p;
717 if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
718 hlist = load_url(url);
722 hlist = calloc(1, sizeof(*hlist));
726 if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) {
727 yyerror("Unknown hostname");
734 for (a = hlist; a != NULL; a = a->al_next) {
735 p = calloc(1, sizeof(*p));
738 p->ipn_mask.adf_addr = a->al_i6mask;
740 if (a->al_family == AF_INET) {
741 p->ipn_addr.adf_family = AF_INET;
743 } else if (a->al_family == AF_INET6) {
744 p->ipn_addr.adf_family = AF_INET6;
747 setadflen(&p->ipn_addr);
748 p->ipn_addr.adf_addr = a->al_i6addr;
749 p->ipn_info = a->al_not;
750 p->ipn_mask.adf_len = p->ipn_addr.adf_len;
769 ip_pool_node_t *ntop, *ipn, node, *last;
773 fp = fopen(file, "r");
779 while (fgets(line, sizeof(line) - 1, fp) != NULL) {
780 line[sizeof(line) - 1] = '\0';
782 if (parsewhoisline(line, &node.ipn_addr, &node.ipn_mask))
784 ipn = calloc(1, sizeof(*ipn));
787 ipn->ipn_addr = node.ipn_addr;
788 ipn->ipn_mask = node.ipn_mask;
792 last->ipn_next = ipn;
804 afp->adf_len = offsetof(addrfamily_t, adf_addr);
805 switch (afp->adf_family)
808 afp->adf_len += sizeof(struct in_addr);
812 afp->adf_len += sizeof(struct in6_addr);