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