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