/* $FreeBSD$ */ /* * Copyright (C) 2001-2006 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ %{ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include #include #include #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "ippool_l.h" #include "kmem.h" #define YYDEBUG 1 #define YYSTACKSIZE 0x00ffffff extern int yyparse __P((void)); extern int yydebug; extern FILE *yyin; static iphtable_t ipht; static iphtent_t iphte; static ip_pool_t iplo; static ioctlfunc_t poolioctl = NULL; static char poolname[FR_GROUPLEN]; static iphtent_t *add_htablehosts __P((char *)); static ip_pool_node_t *add_poolhosts __P((char *)); %} %union { char *str; u_32_t num; struct in_addr addr; struct alist_s *alist; struct in_addr adrmsk[2]; iphtent_t *ipe; ip_pool_node_t *ipp; union i6addr ip6; } %token YY_NUMBER YY_HEX %token YY_STR %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token YY_IPV6 %token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT %token IPT_TABLE IPT_GROUPMAP IPT_HASH %token IPT_ROLE IPT_TYPE IPT_TREE %token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME %type role table inout %type ipftree range addrlist %type addrmask %type ipfgroup ipfhash hashlist hashentry %type groupentry setgrouplist grouplist %type ipaddr mask ipv4 %type number setgroup %% file: line | assign | file line | file assign ; line: table role ipftree eol { iplo.ipo_unit = $2; iplo.ipo_list = $3; load_pool(&iplo, poolioctl); resetlexer(); } | table role ipfhash eol { ipht.iph_unit = $2; ipht.iph_type = IPHASH_LOOKUP; load_hash(&ipht, $3, poolioctl); resetlexer(); } | groupmap role number ipfgroup eol { ipht.iph_unit = $2; strncpy(ipht.iph_name, $3, sizeof(ipht.iph_name)); ipht.iph_type = IPHASH_GROUPMAP; load_hash(&ipht, $4, poolioctl); resetlexer(); } | YY_COMMENT ; eol: ';' ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); yyvarnext = 0; } ; assigning: '=' { yyvarnext = 1; } ; table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); bzero((char *)&iplo, sizeof(iplo)); *ipht.iph_name = '\0'; iplo.ipo_flags = IPHASH_ANON; iplo.ipo_name[0] = '\0'; } ; groupmap: IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); *ipht.iph_name = '\0'; ipht.iph_unit = IPHASH_GROUPMAP; ipht.iph_flags = $2; } ; inout: IPT_IN { $$ = FR_INQUE; } | IPT_OUT { $$ = FR_OUTQUE; } ; role: IPT_ROLE '=' IPT_IPF { $$ = IPL_LOGIPF; } | IPT_ROLE '=' IPT_NAT { $$ = IPL_LOGNAT; } | IPT_ROLE '=' IPT_AUTH { $$ = IPL_LOGAUTH; } | IPT_ROLE '=' IPT_COUNT { $$ = IPL_LOGCOUNT; } ; ipftree: IPT_TYPE '=' IPT_TREE number start addrlist end { strncpy(iplo.ipo_name, $4, sizeof(iplo.ipo_name)); $$ = $6; } ; ipfhash: IPT_TYPE '=' IPT_HASH number hashopts start hashlist end { strncpy(ipht.iph_name, $4, sizeof(ipht.iph_name)); $$ = $7; } ; ipfgroup: setgroup hashopts start grouplist end { iphtent_t *e; for (e = $4; e != NULL; e = e->ipe_next) if (e->ipe_group[0] == '\0') strncpy(e->ipe_group, $1, FR_GROUPLEN); $$ = $4; } | hashopts start setgrouplist end { $$ = $3; } ; number: IPT_NUM '=' YY_NUMBER { sprintf(poolname, "%u", $3); $$ = poolname; } | IPT_NAME '=' YY_STR { $$ = $3; } | { $$ = ""; } ; setgroup: IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1]; strncpy(tmp, $3, FR_GROUPLEN); $$ = strdup(tmp); } | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1]; sprintf(tmp, "%u", $3); $$ = strdup(tmp); } ; hashopts: | size | seed | size seed ; addrlist: next { $$ = NULL; } | range next addrlist { $1->ipn_next = $3; $$ = $1; } | range next { $$ = $1; } ; grouplist: next { $$ = NULL; } | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; } | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t)); bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); $$->ipe_next = $3; } | groupentry next { $$ = $1; } | addrmask next { $$ = calloc(1, sizeof(iphtent_t)); bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); } ; setgrouplist: next { $$ = NULL; } | groupentry next { $$ = $1; } | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; } ; groupentry: addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t)); bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); strncpy($$->ipe_group, $3, FR_GROUPLEN); free($3); } | YY_STR { $$ = add_htablehosts($1); } ; range: addrmask { $$ = calloc(1, sizeof(*$$)); $$->ipn_info = 0; $$->ipn_addr.adf_len = sizeof($$->ipn_addr); $$->ipn_addr.adf_addr.in4.s_addr = $1[0].s_addr; $$->ipn_mask.adf_len = sizeof($$->ipn_mask); $$->ipn_mask.adf_addr.in4.s_addr = $1[1].s_addr; } | '!' addrmask { $$ = calloc(1, sizeof(*$$)); $$->ipn_info = 1; $$->ipn_addr.adf_len = sizeof($$->ipn_addr); $$->ipn_addr.adf_addr.in4.s_addr = $2[0].s_addr; $$->ipn_mask.adf_len = sizeof($$->ipn_mask); $$->ipn_mask.adf_addr.in4.s_addr = $2[1].s_addr; } | YY_STR { $$ = add_poolhosts($1); } hashlist: next { $$ = NULL; } | hashentry next { $$ = $1; } | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; } ; hashentry: addrmask { $$ = calloc(1, sizeof(iphtent_t)); bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); } | YY_STR { $$ = add_htablehosts($1); } ; addrmask: ipaddr '/' mask { $$[0] = $1; $$[1].s_addr = $3.s_addr; yyexpectaddr = 0; } | ipaddr { $$[0] = $1; $$[1].s_addr = 0xffffffff; yyexpectaddr = 0; } ; ipaddr: ipv4 { $$ = $1; } | YY_NUMBER { $$.s_addr = htonl($1); } ; mask: YY_NUMBER { ntomask(4, $1, (u_32_t *)&$$.s_addr); } | ipv4 { $$ = $1; } ; start: '{' { yyexpectaddr = 1; } ; end: '}' { yyexpectaddr = 0; } ; next: ';' { yyexpectaddr = 1; } ; size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; } ; seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.s_addr = htonl($$.s_addr); } ; %% static wordtab_t yywords[] = { { "auth", IPT_AUTH }, { "count", IPT_COUNT }, { "group", IPT_GROUP }, { "group-map", IPT_GROUPMAP }, { "hash", IPT_HASH }, { "in", IPT_IN }, { "ipf", IPT_IPF }, { "name", IPT_NAME }, { "nat", IPT_NAT }, { "number", IPT_NUM }, { "out", IPT_OUT }, { "role", IPT_ROLE }, { "seed", IPT_SEED }, { "size", IPT_SIZE }, { "table", IPT_TABLE }, { "tree", IPT_TREE }, { "type", IPT_TYPE }, { NULL, 0 } }; int ippool_parsefile(fd, filename, iocfunc) int fd; char *filename; ioctlfunc_t iocfunc; { FILE *fp = NULL; char *s; yylineNum = 1; (void) yysettab(yywords); s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; if (strcmp(filename, "-")) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "fopen(%s) failed: %s\n", filename, STRERROR(errno)); return -1; } } else fp = stdin; while (ippool_parsesome(fd, fp, iocfunc) == 1) ; if (fp != NULL) fclose(fp); return 0; } int ippool_parsesome(fd, fp, iocfunc) int fd; FILE *fp; ioctlfunc_t iocfunc; { char *s; int i; poolioctl = iocfunc; if (feof(fp)) return 0; i = fgetc(fp); if (i == EOF) return 0; if (ungetc(i, fp) == EOF) return 0; if (feof(fp)) return 0; s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; yyin = fp; yyparse(); return 1; } static iphtent_t * add_htablehosts(url) char *url; { iphtent_t *htop, *hbot, *h; alist_t *a, *hlist; if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) { hlist = load_url(url); } else { use_inet6 = 0; hlist = calloc(1, sizeof(*hlist)); if (hlist == NULL) return NULL; if (gethost(url, &hlist->al_addr) == -1) yyerror("Unknown hostname"); } hbot = NULL; htop = NULL; for (a = hlist; a != NULL; a = a->al_next) { h = calloc(1, sizeof(*h)); if (h == NULL) break; bcopy((char *)&a->al_addr, (char *)&h->ipe_addr, sizeof(h->ipe_addr)); bcopy((char *)&a->al_mask, (char *)&h->ipe_mask, sizeof(h->ipe_mask)); if (hbot != NULL) hbot->ipe_next = h; else htop = h; hbot = h; } alist_free(hlist); return htop; } static ip_pool_node_t * add_poolhosts(url) char *url; { ip_pool_node_t *ptop, *pbot, *p; alist_t *a, *hlist; if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) { hlist = load_url(url); } else { use_inet6 = 0; hlist = calloc(1, sizeof(*hlist)); if (hlist == NULL) return NULL; if (gethost(url, &hlist->al_addr) == -1) yyerror("Unknown hostname"); } pbot = NULL; ptop = NULL; for (a = hlist; a != NULL; a = a->al_next) { p = calloc(1, sizeof(*p)); if (p == NULL) break; p->ipn_addr.adf_len = 8; p->ipn_mask.adf_len = 8; p->ipn_info = a->al_not; bcopy((char *)&a->al_addr, (char *)&p->ipn_addr.adf_addr, sizeof(p->ipn_addr.adf_addr)); bcopy((char *)&a->al_mask, (char *)&p->ipn_mask.adf_addr, sizeof(p->ipn_mask.adf_addr)); if (pbot != NULL) pbot->ipn_next = p; else ptop = p; pbot = p; } alist_free(hlist); return ptop; }