1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 %{ 9 #include <stdio.h> 10 #include <unistd.h> 11 #include <string.h> 12 #include <fcntl.h> 13 #include <errno.h> 14 #if !defined(__SVR4) && !defined(__GNUC__) 15 #include <strings.h> 16 #endif 17 #include <sys/types.h> 18 #include <sys/param.h> 19 #include <sys/file.h> 20 #include <stdlib.h> 21 #include <stddef.h> 22 #include <sys/socket.h> 23 #include <sys/ioctl.h> 24 #include <netinet/in.h> 25 #include <netinet/in_systm.h> 26 #include <sys/time.h> 27 #include <syslog.h> 28 #include <net/if.h> 29 #include <netdb.h> 30 #include <arpa/nameser.h> 31 #include <resolv.h> 32 #include "ipf.h" 33 #include "netinet/ipl.h" 34 #include "ipnat_l.h" 35 36 #define YYDEBUG 1 37 38 extern void yyerror(char *); 39 extern int yyparse(void); 40 extern int yylex(void); 41 extern int yydebug; 42 extern FILE *yyin; 43 extern int yylineNum; 44 45 static ipnat_t *nattop = NULL; 46 static ipnat_t *nat = NULL; 47 static int natfd = -1; 48 static ioctlfunc_t natioctlfunc = NULL; 49 static addfunc_t nataddfunc = NULL; 50 static int suggest_port = 0; 51 static proxyrule_t *prules = NULL; 52 static int parser_error = 0; 53 54 static void newnatrule(void); 55 static void setnatproto(int); 56 static void setmapifnames(void); 57 static void setrdrifnames(void); 58 static void proxy_setconfig(int); 59 static void proxy_unsetconfig(void); 60 static namelist_t *proxy_dns_add_pass(char *, char *); 61 static namelist_t *proxy_dns_add_block(char *, char *); 62 static void proxy_addconfig(char *, int, char *, namelist_t *); 63 static void proxy_loadconfig(int, ioctlfunc_t, char *, int, 64 char *, namelist_t *); 65 static void proxy_loadrules(int, ioctlfunc_t, proxyrule_t *); 66 static void setmapifnames(void); 67 static void setrdrifnames(void); 68 static void setifname(ipnat_t **, int, char *); 69 static int addname(ipnat_t **, char *); 70 %} 71 %union { 72 char *str; 73 u_32_t num; 74 struct { 75 i6addr_t a; 76 int f; 77 } ipa; 78 frentry_t fr; 79 frtuc_t *frt; 80 u_short port; 81 struct { 82 int p1; 83 int p2; 84 int pc; 85 } pc; 86 struct { 87 i6addr_t a; 88 i6addr_t m; 89 int t; /* Address type */ 90 int u; 91 int f; /* Family */ 92 int v; /* IP version */ 93 int s; /* 0 = number, 1 = text */ 94 int n; /* number */ 95 } ipp; 96 union i6addr ip6; 97 namelist_t *names; 98 }; 99 100 %token <num> YY_NUMBER YY_HEX 101 %token <str> YY_STR 102 %token YY_COMMENT 103 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT 104 %token YY_RANGE_OUT YY_RANGE_IN 105 %token <ip6> YY_IPV6 106 107 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE 108 %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY 109 %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY 110 %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG 111 %token IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO 112 %token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT 113 %token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6 114 %token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE 115 %type <port> portspec 116 %type <num> hexnumber compare range proto 117 %type <num> saddr daddr sobject dobject mapfrom rdrfrom dip 118 %type <ipa> hostname ipv4 ipaddr 119 %type <ipp> addr rhsaddr rhdaddr erhdaddr 120 %type <pc> portstuff portpair comaports srcports dstports 121 %type <names> dnslines dnsline 122 %% 123 file: line 124 | assign 125 | file line 126 | file assign 127 | file pconf ';' 128 ; 129 130 line: xx rule { int err; 131 while ((nat = nattop) != NULL) { 132 if (nat->in_v[0] == 0) 133 nat->in_v[0] = 4; 134 if (nat->in_v[1] == 0) 135 nat->in_v[1] = nat->in_v[0]; 136 nattop = nat->in_next; 137 err = (*nataddfunc)(natfd, natioctlfunc, nat); 138 free(nat); 139 if (err != 0) { 140 parser_error = err; 141 break; 142 } 143 } 144 if (parser_error == 0 && prules != NULL) { 145 proxy_loadrules(natfd, natioctlfunc, prules); 146 prules = NULL; 147 } 148 resetlexer(); 149 } 150 | YY_COMMENT 151 ; 152 153 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); 154 resetlexer(); 155 free($1); 156 free($3); 157 yyvarnext = 0; 158 } 159 ; 160 161 assigning: 162 '=' { yyvarnext = 1; } 163 ; 164 165 xx: { newnatrule(); } 166 ; 167 168 rule: map eol 169 | mapblock eol 170 | redir eol 171 | rewrite ';' 172 | divert ';' 173 ; 174 175 no: IPNY_NO { nat->in_flags |= IPN_NO; } 176 ; 177 178 eol: | ';' 179 ; 180 181 map: mapit ifnames addr tlate rhsaddr proxy mapoptions 182 { if ($3.f != 0 && $3.f != $5.f && $5.f != 0) 183 yyerror("3.address family mismatch"); 184 if (nat->in_v[0] == 0 && $5.v != 0) 185 nat->in_v[0] = $5.v; 186 else if (nat->in_v[0] == 0 && $3.v != 0) 187 nat->in_v[0] = $3.v; 188 if (nat->in_v[1] == 0 && $5.v != 0) 189 nat->in_v[1] = $5.v; 190 else if (nat->in_v[1] == 0 && $3.v != 0) 191 nat->in_v[1] = $3.v; 192 nat->in_osrcatype = $3.t; 193 bcopy(&$3.a, &nat->in_osrc.na_addr[0], 194 sizeof($3.a)); 195 bcopy(&$3.m, &nat->in_osrc.na_addr[1], 196 sizeof($3.a)); 197 nat->in_nsrcatype = $5.t; 198 nat->in_nsrcafunc = $5.u; 199 bcopy(&$5.a, &nat->in_nsrc.na_addr[0], 200 sizeof($5.a)); 201 bcopy(&$5.m, &nat->in_nsrc.na_addr[1], 202 sizeof($5.a)); 203 204 setmapifnames(); 205 } 206 | mapit ifnames addr tlate rhsaddr mapport mapoptions 207 { if ($3.f != $5.f && $3.f != 0 && $5.f != 0) 208 yyerror("4.address family mismatch"); 209 if (nat->in_v[1] == 0 && $5.v != 0) 210 nat->in_v[1] = $5.v; 211 else if (nat->in_v[0] == 0 && $3.v != 0) 212 nat->in_v[0] = $3.v; 213 if (nat->in_v[0] == 0 && $5.v != 0) 214 nat->in_v[0] = $5.v; 215 else if (nat->in_v[1] == 0 && $3.v != 0) 216 nat->in_v[1] = $3.v; 217 nat->in_osrcatype = $3.t; 218 bcopy(&$3.a, &nat->in_osrc.na_addr[0], 219 sizeof($3.a)); 220 bcopy(&$3.m, &nat->in_osrc.na_addr[1], 221 sizeof($3.a)); 222 nat->in_nsrcatype = $5.t; 223 nat->in_nsrcafunc = $5.u; 224 bcopy(&$5.a, &nat->in_nsrc.na_addr[0], 225 sizeof($5.a)); 226 bcopy(&$5.m, &nat->in_nsrc.na_addr[1], 227 sizeof($5.a)); 228 229 setmapifnames(); 230 } 231 | no mapit ifnames addr setproto ';' 232 { if (nat->in_v[0] == 0) 233 nat->in_v[0] = $4.v; 234 nat->in_osrcatype = $4.t; 235 bcopy(&$4.a, &nat->in_osrc.na_addr[0], 236 sizeof($4.a)); 237 bcopy(&$4.m, &nat->in_osrc.na_addr[1], 238 sizeof($4.a)); 239 240 setmapifnames(); 241 } 242 | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions 243 { if ($3 != 0 && $5.f != 0 && $3 != $5.f) 244 yyerror("5.address family mismatch"); 245 if (nat->in_v[0] == 0 && $5.v != 0) 246 nat->in_v[0] = $5.v; 247 else if (nat->in_v[0] == 0 && $3 != 0) 248 nat->in_v[0] = ftov($3); 249 if (nat->in_v[1] == 0 && $5.v != 0) 250 nat->in_v[1] = $5.v; 251 else if (nat->in_v[1] == 0 && $3 != 0) 252 nat->in_v[1] = ftov($3); 253 nat->in_nsrcatype = $5.t; 254 nat->in_nsrcafunc = $5.u; 255 bcopy(&$5.a, &nat->in_nsrc.na_addr[0], 256 sizeof($5.a)); 257 bcopy(&$5.m, &nat->in_nsrc.na_addr[1], 258 sizeof($5.a)); 259 260 setmapifnames(); 261 } 262 | no mapit ifnames mapfrom setproto ';' 263 { nat->in_v[0] = ftov($4); 264 setmapifnames(); 265 } 266 | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions 267 { if ($3 != 0 && $5.f != 0 && $3 != $5.f) 268 yyerror("6.address family mismatch"); 269 if (nat->in_v[0] == 0 && $5.v != 0) 270 nat->in_v[0] = $5.v; 271 else if (nat->in_v[0] == 0 && $3 != 0) 272 nat->in_v[0] = ftov($3); 273 if (nat->in_v[1] == 0 && $5.v != 0) 274 nat->in_v[1] = $5.v; 275 else if (nat->in_v[1] == 0 && $3 != 0) 276 nat->in_v[1] = ftov($3); 277 nat->in_nsrcatype = $5.t; 278 nat->in_nsrcafunc = $5.u; 279 bcopy(&$5.a, &nat->in_nsrc.na_addr[0], 280 sizeof($5.a)); 281 bcopy(&$5.m, &nat->in_nsrc.na_addr[1], 282 sizeof($5.a)); 283 284 setmapifnames(); 285 } 286 ; 287 288 mapblock: 289 mapblockit ifnames addr tlate addr ports mapoptions 290 { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f) 291 yyerror("7.address family mismatch"); 292 if (nat->in_v[0] == 0 && $5.v != 0) 293 nat->in_v[0] = $5.v; 294 else if (nat->in_v[0] == 0 && $3.v != 0) 295 nat->in_v[0] = $3.v; 296 if (nat->in_v[1] == 0 && $5.v != 0) 297 nat->in_v[1] = $5.v; 298 else if (nat->in_v[1] == 0 && $3.v != 0) 299 nat->in_v[1] = $3.v; 300 nat->in_osrcatype = $3.t; 301 bcopy(&$3.a, &nat->in_osrc.na_addr[0], 302 sizeof($3.a)); 303 bcopy(&$3.m, &nat->in_osrc.na_addr[1], 304 sizeof($3.a)); 305 nat->in_nsrcatype = $5.t; 306 nat->in_nsrcafunc = $5.u; 307 bcopy(&$5.a, &nat->in_nsrc.na_addr[0], 308 sizeof($5.a)); 309 bcopy(&$5.m, &nat->in_nsrc.na_addr[1], 310 sizeof($5.a)); 311 312 setmapifnames(); 313 } 314 | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';' 315 { if (nat->in_v[0] == 0) 316 nat->in_v[0] = $5.v; 317 if (nat->in_v[1] == 0) 318 nat->in_v[1] = $5.v; 319 nat->in_osrcatype = $5.t; 320 bcopy(&$5.a, &nat->in_osrc.na_addr[0], 321 sizeof($5.a)); 322 bcopy(&$5.m, &nat->in_osrc.na_addr[1], 323 sizeof($5.a)); 324 325 setmapifnames(); 326 } 327 ; 328 329 redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions 330 { if ($6 != 0 && $3.f != 0 && $6 != $3.f) 331 yyerror("21.address family mismatch"); 332 if (nat->in_v[0] == 0) { 333 if ($3.v != AF_UNSPEC) 334 nat->in_v[0] = ftov($3.f); 335 else 336 nat->in_v[0] = ftov($6); 337 } 338 nat->in_odstatype = $3.t; 339 bcopy(&$3.a, &nat->in_odst.na_addr[0], 340 sizeof($3.a)); 341 bcopy(&$3.m, &nat->in_odst.na_addr[1], 342 sizeof($3.a)); 343 344 setrdrifnames(); 345 } 346 | no rdrit ifnames addr dport setproto ';' 347 { if (nat->in_v[0] == 0) 348 nat->in_v[0] = ftov($4.f); 349 nat->in_odstatype = $4.t; 350 bcopy(&$4.a, &nat->in_odst.na_addr[0], 351 sizeof($4.a)); 352 bcopy(&$4.m, &nat->in_odst.na_addr[1], 353 sizeof($4.a)); 354 355 setrdrifnames(); 356 } 357 | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions 358 { if ($5 != 0 && $3 != 0 && $5 != $3) 359 yyerror("20.address family mismatch"); 360 if (nat->in_v[0] == 0) { 361 if ($3 != AF_UNSPEC) 362 nat->in_v[0] = ftov($3); 363 else 364 nat->in_v[0] = ftov($5); 365 } 366 setrdrifnames(); 367 } 368 | no rdrit ifnames rdrfrom setproto ';' 369 { nat->in_v[0] = ftov($4); 370 371 setrdrifnames(); 372 } 373 ; 374 375 rewrite: 376 IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts 377 { if (nat->in_v[0] == 0) 378 nat->in_v[0] = ftov($4); 379 if (nat->in_redir & NAT_MAP) 380 setmapifnames(); 381 else 382 setrdrifnames(); 383 nat->in_redir |= NAT_REWRITE; 384 } 385 ; 386 387 divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts 388 { if (nat->in_v[0] == 0) 389 nat->in_v[0] = ftov($4); 390 if (nat->in_redir & NAT_MAP) { 391 setmapifnames(); 392 nat->in_pr[0] = IPPROTO_UDP; 393 } else { 394 setrdrifnames(); 395 nat->in_pr[1] = IPPROTO_UDP; 396 } 397 nat->in_flags &= ~IPN_TCP; 398 } 399 ; 400 401 tlate: IPNY_TLATE { yyexpectaddr = 1; } 402 ; 403 404 pconf: IPNY_PROXY { yysetdict(proxies); } 405 IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{' 406 { proxy_setconfig(IPNY_DNS); } 407 dnslines ';' '}' 408 { proxy_addconfig("dns", $5, $7, $10); 409 proxy_unsetconfig(); 410 } 411 ; 412 413 dnslines: 414 dnsline { $$ = $1; } 415 | dnslines ';' dnsline { $$ = $1; $1->na_next = $3; } 416 ; 417 418 dnsline: 419 IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); } 420 | IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); } 421 | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); } 422 | IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); } 423 ; 424 425 oninout: 426 inout IPNY_ON ifnames { ; } 427 ; 428 429 inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; } 430 | IPNY_OUT { nat->in_redir = NAT_MAP; } 431 ; 432 433 rwrproto: 434 | IPNY_PROTO setproto 435 ; 436 437 newdst: src rhsaddr srcports dst erhdaddr dstports 438 { nat->in_nsrc.na_addr[0] = $2.a; 439 nat->in_nsrc.na_addr[1] = $2.m; 440 nat->in_nsrc.na_atype = $2.t; 441 if ($2.t == FRI_LOOKUP) { 442 nat->in_nsrc.na_type = $2.u; 443 nat->in_nsrc.na_subtype = $2.s; 444 nat->in_nsrc.na_num = $2.n; 445 } 446 nat->in_nsports[0] = $3.p1; 447 nat->in_nsports[1] = $3.p2; 448 nat->in_ndst.na_addr[0] = $5.a; 449 nat->in_ndst.na_addr[1] = $5.m; 450 nat->in_ndst.na_atype = $5.t; 451 if ($5.t == FRI_LOOKUP) { 452 nat->in_ndst.na_type = $5.u; 453 nat->in_ndst.na_subtype = $5.s; 454 nat->in_ndst.na_num = $5.n; 455 } 456 nat->in_ndports[0] = $6.p1; 457 nat->in_ndports[1] = $6.p2; 458 } 459 ; 460 461 divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP 462 { nat->in_nsrc.na_addr[0] = $2.a; 463 if ($2.m.in4.s_addr != 0xffffffff) 464 yyerror("divert must have /32 dest"); 465 nat->in_nsrc.na_addr[1] = $2.m; 466 nat->in_nsports[0] = $4; 467 nat->in_nsports[1] = $4; 468 469 nat->in_ndst.na_addr[0] = $6.a; 470 nat->in_ndst.na_addr[1] = $6.m; 471 if ($6.m.in4.s_addr != 0xffffffff) 472 yyerror("divert must have /32 dest"); 473 nat->in_ndports[0] = $8; 474 nat->in_ndports[1] = $8; 475 476 nat->in_redir |= NAT_DIVERTUDP; 477 } 478 ; 479 480 src: IPNY_SRC { yyexpectaddr = 1; } 481 ; 482 483 dst: IPNY_DST { yyexpectaddr = 1; } 484 ; 485 486 srcports: 487 comaports { $$.p1 = $1.p1; 488 $$.p2 = $1.p2; 489 } 490 | IPNY_PORT '=' portspec 491 { $$.p1 = $3; 492 $$.p2 = $3; 493 nat->in_flags |= IPN_FIXEDSPORT; 494 } 495 ; 496 497 dstports: 498 comaports { $$.p1 = $1.p1; 499 $$.p2 = $1.p2; 500 } 501 | IPNY_PORT '=' portspec 502 { $$.p1 = $3; 503 $$.p2 = $3; 504 nat->in_flags |= IPN_FIXEDDPORT; 505 } 506 ; 507 508 comaports: 509 { $$.p1 = 0; 510 $$.p2 = 0; 511 } 512 | ',' { if (!(nat->in_flags & IPN_TCPUDP)) 513 yyerror("must be TCP/UDP for ports"); 514 } 515 portpair { $$.p1 = $3.p1; 516 $$.p2 = $3.p2; 517 } 518 ; 519 520 proxy: | IPNY_PROXY port portspec YY_STR '/' proto 521 { int pos; 522 pos = addname(&nat, $4); 523 nat->in_plabel = pos; 524 if (nat->in_dcmp == 0) { 525 nat->in_odport = $3; 526 } else if ($3 != nat->in_odport) { 527 yyerror("proxy port numbers not consistant"); 528 } 529 nat->in_ndport = $3; 530 setnatproto($6); 531 free($4); 532 } 533 | IPNY_PROXY port YY_STR YY_STR '/' proto 534 { int pnum, pos; 535 pos = addname(&nat, $4); 536 nat->in_plabel = pos; 537 pnum = getportproto($3, $6); 538 if (pnum == -1) 539 yyerror("invalid port number"); 540 nat->in_odport = ntohs(pnum); 541 nat->in_ndport = ntohs(pnum); 542 setnatproto($6); 543 free($3); 544 free($4); 545 } 546 | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR 547 { int pos; 548 pos = addname(&nat, $4); 549 nat->in_plabel = pos; 550 if (nat->in_dcmp == 0) { 551 nat->in_odport = $3; 552 } else if ($3 != nat->in_odport) { 553 yyerror("proxy port numbers not consistant"); 554 } 555 nat->in_ndport = $3; 556 setnatproto($6); 557 nat->in_pconfig = addname(&nat, $8); 558 free($4); 559 free($8); 560 } 561 | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR 562 { int pnum, pos; 563 pos = addname(&nat, $4); 564 nat->in_plabel = pos; 565 pnum = getportproto($3, $6); 566 if (pnum == -1) 567 yyerror("invalid port number"); 568 nat->in_odport = ntohs(pnum); 569 nat->in_ndport = ntohs(pnum); 570 setnatproto($6); 571 pos = addname(&nat, $8); 572 nat->in_pconfig = pos; 573 free($3); 574 free($4); 575 free($8); 576 } 577 ; 578 setproto: 579 | proto { if (nat->in_pr[0] != 0 || 580 nat->in_pr[1] != 0 || 581 nat->in_flags & IPN_TCPUDP) 582 yyerror("protocol set twice"); 583 setnatproto($1); 584 } 585 | IPNY_TCPUDP { if (nat->in_pr[0] != 0 || 586 nat->in_pr[1] != 0 || 587 nat->in_flags & IPN_TCPUDP) 588 yyerror("protocol set twice"); 589 nat->in_flags |= IPN_TCPUDP; 590 nat->in_pr[0] = 0; 591 nat->in_pr[1] = 0; 592 } 593 | IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 || 594 nat->in_pr[1] != 0 || 595 nat->in_flags & IPN_TCPUDP) 596 yyerror("protocol set twice"); 597 nat->in_flags |= IPN_TCPUDP; 598 nat->in_pr[0] = 0; 599 nat->in_pr[1] = 0; 600 } 601 ; 602 603 rhsaddr: 604 addr { $$ = $1; 605 yyexpectaddr = 0; 606 } 607 | hostname '-' { yyexpectaddr = 1; } hostname 608 { $$.t = FRI_RANGE; 609 if ($1.f != $4.f) 610 yyerror("8.address family " 611 "mismatch"); 612 $$.f = $1.f; 613 $$.v = ftov($1.f); 614 $$.a = $1.a; 615 $$.m = $4.a; 616 nat->in_flags |= IPN_SIPRANGE; 617 yyexpectaddr = 0; 618 } 619 | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname 620 { $$.t = FRI_RANGE; 621 if ($2.f != $5.f) 622 yyerror("9.address family " 623 "mismatch"); 624 $$.f = $2.f; 625 $$.v = ftov($2.f); 626 $$.a = $2.a; 627 $$.m = $5.a; 628 nat->in_flags |= IPN_SIPRANGE; 629 yyexpectaddr = 0; 630 } 631 ; 632 633 dip: 634 hostname ',' { yyexpectaddr = 1; } hostname 635 { nat->in_flags |= IPN_SPLIT; 636 if ($1.f != $4.f) 637 yyerror("10.address family " 638 "mismatch"); 639 $$ = $1.f; 640 nat->in_ndstip6 = $1.a; 641 nat->in_ndstmsk6 = $4.a; 642 nat->in_ndstatype = FRI_SPLIT; 643 yyexpectaddr = 0; 644 } 645 | rhdaddr { int bits; 646 nat->in_ndstip6 = $1.a; 647 nat->in_ndstmsk6 = $1.m; 648 nat->in_ndst.na_atype = $1.t; 649 yyexpectaddr = 0; 650 if ($1.f == AF_INET) 651 bits = count4bits($1.m.in4.s_addr); 652 else 653 bits = count6bits($1.m.i6); 654 if (($1.f == AF_INET) && (bits != 0) && 655 (bits != 32)) { 656 yyerror("dest ip bitmask not /32"); 657 } else if (($1.f == AF_INET6) && 658 (bits != 0) && (bits != 128)) { 659 yyerror("dest ip bitmask not /128"); 660 } 661 $$ = $1.f; 662 } 663 ; 664 665 rhdaddr: 666 addr { $$ = $1; 667 yyexpectaddr = 0; 668 } 669 | hostname '-' hostname { bzero(&$$, sizeof($$)); 670 $$.t = FRI_RANGE; 671 if ($1.f != 0 && $3.f != 0 && 672 $1.f != $3.f) 673 yyerror("11.address family " 674 "mismatch"); 675 $$.a = $1.a; 676 $$.m = $3.a; 677 nat->in_flags |= IPN_DIPRANGE; 678 yyexpectaddr = 0; 679 } 680 | IPNY_RANGE hostname '-' hostname 681 { bzero(&$$, sizeof($$)); 682 $$.t = FRI_RANGE; 683 if ($2.f != 0 && $4.f != 0 && 684 $2.f != $4.f) 685 yyerror("12.address family " 686 "mismatch"); 687 $$.a = $2.a; 688 $$.m = $4.a; 689 nat->in_flags |= IPN_DIPRANGE; 690 yyexpectaddr = 0; 691 } 692 ; 693 694 erhdaddr: 695 rhdaddr { $$ = $1; } 696 | IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP; 697 $$.u = IPLT_DSTLIST; 698 $$.s = 0; 699 $$.n = $3; 700 } 701 | IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP; 702 $$.u = IPLT_DSTLIST; 703 $$.s = 1; 704 $$.n = addname(&nat, $3); 705 } 706 ; 707 708 port: IPNY_PORT { suggest_port = 1; } 709 ; 710 711 portspec: 712 YY_NUMBER { if ($1 > 65535) /* Unsigned */ 713 yyerror("invalid port number"); 714 else 715 $$ = $1; 716 } 717 | YY_STR { if (getport(NULL, $1, 718 &($$), NULL) == -1) 719 yyerror("invalid port number"); 720 $$ = ntohs($$); 721 } 722 ; 723 724 portpair: 725 portspec { $$.p1 = $1; $$.p2 = $1; } 726 | portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; } 727 | portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; } 728 ; 729 730 dport: | port portpair { nat->in_odport = $2.p1; 731 if ($2.p2 == 0) 732 nat->in_dtop = $2.p1; 733 else 734 nat->in_dtop = $2.p2; 735 } 736 ; 737 738 nport: | port portpair { nat->in_dpmin = $2.p1; 739 nat->in_dpnext = $2.p1; 740 nat->in_dpmax = $2.p2; 741 nat->in_ndport = $2.p1; 742 if (nat->in_dtop == 0) 743 nat->in_dtop = $2.p2; 744 } 745 | port '=' portspec { nat->in_dpmin = $3; 746 nat->in_dpnext = $3; 747 nat->in_ndport = $3; 748 if (nat->in_dtop == 0) 749 nat->in_dtop = nat->in_odport; 750 nat->in_flags |= IPN_FIXEDDPORT; 751 } 752 ; 753 754 ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $2; } 755 | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; } 756 ; 757 758 mapit: IPNY_MAP { nat->in_redir = NAT_MAP; } 759 | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; } 760 ; 761 762 rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; } 763 ; 764 765 mapblockit: 766 IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; } 767 ; 768 769 mapfrom: 770 from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4) 771 yyerror("13.address family " 772 "mismatch"); 773 $$ = $2; 774 } 775 | from sobject '!' to dobject 776 { if ($2 != 0 && $5 != 0 && $2 != $5) 777 yyerror("14.address family " 778 "mismatch"); 779 nat->in_flags |= IPN_NOTDST; 780 $$ = $2; 781 } 782 | from sobject to '!' dobject 783 { if ($2 != 0 && $5 != 0 && $2 != $5) 784 yyerror("15.address family " 785 "mismatch"); 786 nat->in_flags |= IPN_NOTDST; 787 $$ = $2; 788 } 789 ; 790 791 rdrfrom: 792 from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4) 793 yyerror("16.address family " 794 "mismatch"); 795 $$ = $2; 796 } 797 | '!' from sobject to dobject 798 { if ($3 != 0 && $5 != 0 && $3 != $5) 799 yyerror("17.address family " 800 "mismatch"); 801 nat->in_flags |= IPN_NOTSRC; 802 $$ = $3; 803 } 804 | from '!' sobject to dobject 805 { if ($3 != 0 && $5 != 0 && $3 != $5) 806 yyerror("18.address family " 807 "mismatch"); 808 nat->in_flags |= IPN_NOTSRC; 809 $$ = $3; 810 } 811 ; 812 813 from: IPNY_FROM { nat->in_flags |= IPN_FILTER; 814 yyexpectaddr = 1; 815 } 816 ; 817 818 to: IPNY_TO { yyexpectaddr = 1; } 819 ; 820 821 ifnames: 822 ifname family { yyexpectaddr = 1; } 823 | ifname ',' otherifname family { yyexpectaddr = 1; } 824 ; 825 826 ifname: YY_STR { setifname(&nat, 0, $1); 827 free($1); 828 } 829 ; 830 831 family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; } 832 | IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; } 833 ; 834 835 otherifname: 836 YY_STR { setifname(&nat, 1, $1); 837 free($1); 838 } 839 ; 840 841 mapport: 842 IPNY_PORTMAP tcpudp portpair sequential 843 { nat->in_spmin = $3.p1; 844 nat->in_spmax = $3.p2; 845 } 846 | IPNY_PORTMAP portpair tcpudp sequential 847 { nat->in_spmin = $2.p1; 848 nat->in_spmax = $2.p2; 849 } 850 | IPNY_PORTMAP tcpudp IPNY_AUTO sequential 851 { nat->in_flags |= IPN_AUTOPORTMAP; 852 nat->in_spmin = 1024; 853 nat->in_spmax = 65535; 854 } 855 | IPNY_ICMPIDMAP YY_STR portpair sequential 856 { if (strcmp($2, "icmp") != 0 && 857 strcmp($2, "ipv6-icmp") != 0) { 858 yyerror("icmpidmap not followed by icmp"); 859 } 860 free($2); 861 if ($3.p1 < 0 || $3.p1 > 65535) 862 yyerror("invalid 1st ICMP Id number"); 863 if ($3.p2 < 0 || $3.p2 > 65535) 864 yyerror("invalid 2nd ICMP Id number"); 865 if (strcmp($2, "ipv6-icmp") == 0) { 866 nat->in_pr[0] = IPPROTO_ICMPV6; 867 nat->in_pr[1] = IPPROTO_ICMPV6; 868 } else { 869 nat->in_pr[0] = IPPROTO_ICMP; 870 nat->in_pr[1] = IPPROTO_ICMP; 871 } 872 nat->in_flags = IPN_ICMPQUERY; 873 nat->in_spmin = $3.p1; 874 nat->in_spmax = $3.p2; 875 } 876 ; 877 878 sobject: 879 saddr { $$ = $1; } 880 | saddr port portstuff { nat->in_osport = $3.p1; 881 nat->in_stop = $3.p2; 882 nat->in_scmp = $3.pc; 883 $$ = $1; 884 } 885 ; 886 887 saddr: addr { nat->in_osrcatype = $1.t; 888 bcopy(&$1.a, 889 &nat->in_osrc.na_addr[0], 890 sizeof($1.a)); 891 bcopy(&$1.m, 892 &nat->in_osrc.na_addr[1], 893 sizeof($1.m)); 894 $$ = $1.f; 895 } 896 ; 897 898 dobject: 899 daddr { $$ = $1; } 900 | daddr port portstuff { nat->in_odport = $3.p1; 901 nat->in_dtop = $3.p2; 902 nat->in_dcmp = $3.pc; 903 $$ = $1; 904 } 905 ; 906 907 daddr: addr { nat->in_odstatype = $1.t; 908 bcopy(&$1.a, 909 &nat->in_odst.na_addr[0], 910 sizeof($1.a)); 911 bcopy(&$1.m, 912 &nat->in_odst.na_addr[1], 913 sizeof($1.m)); 914 $$ = $1.f; 915 } 916 ; 917 918 addr: IPNY_ANY { yyexpectaddr = 0; 919 bzero(&$$, sizeof($$)); 920 $$.t = FRI_NORMAL; 921 } 922 | hostname { bzero(&$$, sizeof($$)); 923 $$.a = $1.a; 924 $$.t = FRI_NORMAL; 925 $$.v = ftov($1.f); 926 $$.f = $1.f; 927 if ($$.f == AF_INET) { 928 $$.m.in4.s_addr = 0xffffffff; 929 } else if ($$.f == AF_INET6) { 930 $$.m.i6[0] = 0xffffffff; 931 $$.m.i6[1] = 0xffffffff; 932 $$.m.i6[2] = 0xffffffff; 933 $$.m.i6[3] = 0xffffffff; 934 } 935 yyexpectaddr = 0; 936 } 937 | hostname slash YY_NUMBER 938 { bzero(&$$, sizeof($$)); 939 $$.a = $1.a; 940 $$.f = $1.f; 941 $$.v = ftov($1.f); 942 $$.t = FRI_NORMAL; 943 ntomask($$.f, $3, (u_32_t *)&$$.m); 944 $$.a.i6[0] &= $$.m.i6[0]; 945 $$.a.i6[1] &= $$.m.i6[1]; 946 $$.a.i6[2] &= $$.m.i6[2]; 947 $$.a.i6[3] &= $$.m.i6[3]; 948 yyexpectaddr = 0; 949 } 950 | hostname slash ipaddr { bzero(&$$, sizeof($$)); 951 if ($1.f != $3.f) { 952 yyerror("1.address family " 953 "mismatch"); 954 } 955 $$.a = $1.a; 956 $$.m = $3.a; 957 $$.t = FRI_NORMAL; 958 $$.a.i6[0] &= $$.m.i6[0]; 959 $$.a.i6[1] &= $$.m.i6[1]; 960 $$.a.i6[2] &= $$.m.i6[2]; 961 $$.a.i6[3] &= $$.m.i6[3]; 962 $$.f = $1.f; 963 $$.v = ftov($1.f); 964 yyexpectaddr = 0; 965 } 966 | hostname slash hexnumber { bzero(&$$, sizeof($$)); 967 $$.a = $1.a; 968 $$.m.in4.s_addr = htonl($3); 969 $$.t = FRI_NORMAL; 970 $$.a.in4.s_addr &= $$.m.in4.s_addr; 971 $$.f = $1.f; 972 $$.v = ftov($1.f); 973 if ($$.f == AF_INET6) 974 yyerror("incorrect inet6 mask"); 975 } 976 | hostname mask ipaddr { bzero(&$$, sizeof($$)); 977 if ($1.f != $3.f) { 978 yyerror("2.address family " 979 "mismatch"); 980 } 981 $$.a = $1.a; 982 $$.m = $3.a; 983 $$.t = FRI_NORMAL; 984 $$.a.i6[0] &= $$.m.i6[0]; 985 $$.a.i6[1] &= $$.m.i6[1]; 986 $$.a.i6[2] &= $$.m.i6[2]; 987 $$.a.i6[3] &= $$.m.i6[3]; 988 $$.f = $1.f; 989 $$.v = ftov($1.f); 990 yyexpectaddr = 0; 991 } 992 | hostname mask hexnumber { bzero(&$$, sizeof($$)); 993 $$.a = $1.a; 994 $$.m.in4.s_addr = htonl($3); 995 $$.t = FRI_NORMAL; 996 $$.a.in4.s_addr &= $$.m.in4.s_addr; 997 $$.f = AF_INET; 998 $$.v = 4; 999 } 1000 | pool slash YY_NUMBER { bzero(&$$, sizeof($$)); 1001 $$.a.iplookupnum = $3; 1002 $$.a.iplookuptype = IPLT_POOL; 1003 $$.a.iplookupsubtype = 0; 1004 $$.t = FRI_LOOKUP; 1005 } 1006 | pool slash YY_STR { bzero(&$$, sizeof($$)); 1007 $$.a.iplookupname = addname(&nat,$3); 1008 $$.a.iplookuptype = IPLT_POOL; 1009 $$.a.iplookupsubtype = 1; 1010 $$.t = FRI_LOOKUP; 1011 } 1012 | hash slash YY_NUMBER { bzero(&$$, sizeof($$)); 1013 $$.a.iplookupnum = $3; 1014 $$.a.iplookuptype = IPLT_HASH; 1015 $$.a.iplookupsubtype = 0; 1016 $$.t = FRI_LOOKUP; 1017 } 1018 | hash slash YY_STR { bzero(&$$, sizeof($$)); 1019 $$.a.iplookupname = addname(&nat,$3); 1020 $$.a.iplookuptype = IPLT_HASH; 1021 $$.a.iplookupsubtype = 1; 1022 $$.t = FRI_LOOKUP; 1023 } 1024 ; 1025 1026 slash: '/' { yyexpectaddr = 0; } 1027 ; 1028 1029 mask: IPNY_MASK { yyexpectaddr = 0; } 1030 ; 1031 1032 pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) { 1033 yyerror("Can only use pool with from/to rules\n"); 1034 } 1035 yyexpectaddr = 0; 1036 yyresetdict(); 1037 } 1038 ; 1039 1040 hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) { 1041 yyerror("Can only use hash with from/to rules\n"); 1042 } 1043 yyexpectaddr = 0; 1044 yyresetdict(); 1045 } 1046 ; 1047 1048 portstuff: 1049 compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; } 1050 | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; } 1051 ; 1052 1053 mapoptions: 1054 rr frag age mssclamp nattag setproto purge 1055 ; 1056 1057 rdroptions: 1058 rr frag age sticky mssclamp rdrproxy nattag purge 1059 ; 1060 1061 nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2, 1062 sizeof(nat->in_tag.ipt_tag)); 1063 } 1064 rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; } 1065 ; 1066 1067 frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; } 1068 ; 1069 1070 age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2; 1071 nat->in_age[1] = $2; } 1072 | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2; 1073 nat->in_age[1] = $4; } 1074 ; 1075 1076 sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) && 1077 !(nat->in_flags & IPN_SPLIT)) { 1078 FPRINTF(stderr, 1079 "'sticky' for use with round-robin/IP splitting only\n"); 1080 } else 1081 nat->in_flags |= IPN_STICKY; 1082 } 1083 ; 1084 1085 mssclamp: 1086 | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; } 1087 ; 1088 1089 tcpudp: IPNY_TCP { setnatproto(IPPROTO_TCP); } 1090 | IPNY_UDP { setnatproto(IPPROTO_UDP); } 1091 | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP; 1092 nat->in_pr[0] = 0; 1093 nat->in_pr[1] = 0; 1094 } 1095 | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; 1096 nat->in_pr[0] = 0; 1097 nat->in_pr[1] = 0; 1098 } 1099 ; 1100 1101 sequential: 1102 | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; } 1103 ; 1104 1105 purge: 1106 | IPNY_PURGE { nat->in_flags |= IPN_PURGE; } 1107 ; 1108 1109 rdrproxy: 1110 IPNY_PROXY YY_STR 1111 { int pos; 1112 pos = addname(&nat, $2); 1113 nat->in_plabel = pos; 1114 nat->in_odport = nat->in_dpnext; 1115 nat->in_dtop = nat->in_odport; 1116 free($2); 1117 } 1118 | proxy { if (nat->in_plabel != -1) { 1119 nat->in_ndport = nat->in_odport; 1120 nat->in_dpmin = nat->in_odport; 1121 nat->in_dpmax = nat->in_dpmin; 1122 nat->in_dtop = nat->in_dpmin; 1123 nat->in_dpnext = nat->in_dpmin; 1124 } 1125 } 1126 ; 1127 1128 newopts: 1129 | IPNY_PURGE { nat->in_flags |= IPN_PURGE; } 1130 ; 1131 1132 proto: YY_NUMBER { $$ = $1; 1133 if ($$ != IPPROTO_TCP && 1134 $$ != IPPROTO_UDP) 1135 suggest_port = 0; 1136 } 1137 | IPNY_TCP { $$ = IPPROTO_TCP; } 1138 | IPNY_UDP { $$ = IPPROTO_UDP; } 1139 | YY_STR { $$ = getproto($1); 1140 free($1); 1141 if ($$ == -1) 1142 yyerror("unknown protocol"); 1143 if ($$ != IPPROTO_TCP && 1144 $$ != IPPROTO_UDP) 1145 suggest_port = 0; 1146 } 1147 ; 1148 1149 hexnumber: 1150 YY_HEX { $$ = $1; } 1151 ; 1152 1153 hostname: 1154 YY_STR { i6addr_t addr; 1155 int family; 1156 1157 #ifdef USE_INET6 1158 if (nat->in_v[0] == 6) 1159 family = AF_INET6; 1160 else 1161 #endif 1162 family = AF_INET; 1163 memset(&($$), 0, sizeof($$)); 1164 memset(&addr, 0, sizeof(addr)); 1165 $$.f = family; 1166 if (gethost(family, $1, 1167 &addr) == 0) { 1168 $$.a = addr; 1169 } else { 1170 FPRINTF(stderr, 1171 "Unknown host '%s'\n", 1172 $1); 1173 } 1174 free($1); 1175 } 1176 | YY_NUMBER { memset(&($$), 0, sizeof($$)); 1177 $$.a.in4.s_addr = htonl($1); 1178 if ($$.a.in4.s_addr != 0) 1179 $$.f = AF_INET; 1180 } 1181 | ipv4 { $$ = $1; } 1182 | YY_IPV6 { memset(&($$), 0, sizeof($$)); 1183 $$.a = $1; 1184 $$.f = AF_INET6; 1185 } 1186 | YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$)); 1187 $$.a = $2; 1188 $$.f = AF_INET6; 1189 } 1190 ; 1191 1192 compare: 1193 '=' { $$ = FR_EQUAL; } 1194 | YY_CMP_EQ { $$ = FR_EQUAL; } 1195 | YY_CMP_NE { $$ = FR_NEQUAL; } 1196 | YY_CMP_LT { $$ = FR_LESST; } 1197 | YY_CMP_LE { $$ = FR_LESSTE; } 1198 | YY_CMP_GT { $$ = FR_GREATERT; } 1199 | YY_CMP_GE { $$ = FR_GREATERTE; } 1200 1201 range: 1202 YY_RANGE_OUT { $$ = FR_OUTRANGE; } 1203 | YY_RANGE_IN { $$ = FR_INRANGE; } 1204 | ':' { $$ = FR_INCRANGE; } 1205 ; 1206 1207 ipaddr: ipv4 { $$ = $1; } 1208 | YY_IPV6 { $$.a = $1; 1209 $$.f = AF_INET6; 1210 } 1211 ; 1212 1213 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER 1214 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 1215 yyerror("Invalid octet string for IP address"); 1216 return(0); 1217 } 1218 bzero((char *)&$$, sizeof($$)); 1219 $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; 1220 $$.a.in4.s_addr = htonl($$.a.in4.s_addr); 1221 $$.f = AF_INET; 1222 } 1223 ; 1224 1225 %% 1226 1227 1228 static wordtab_t proxies[] = { 1229 { "dns", IPNY_DNS } 1230 }; 1231 1232 static wordtab_t dnswords[] = { 1233 { "allow", IPNY_ALLOW }, 1234 { "block", IPNY_DENY }, 1235 { "deny", IPNY_DENY }, 1236 { "drop", IPNY_DENY }, 1237 { "pass", IPNY_ALLOW }, 1238 1239 }; 1240 1241 static wordtab_t yywords[] = { 1242 { "age", IPNY_AGE }, 1243 { "any", IPNY_ANY }, 1244 { "auto", IPNY_AUTO }, 1245 { "bimap", IPNY_BIMAP }, 1246 { "config", IPNY_CONFIG }, 1247 { "divert", IPNY_DIVERT }, 1248 { "dst", IPNY_DST }, 1249 { "dstlist", IPNY_DSTLIST }, 1250 { "frag", IPNY_FRAG }, 1251 { "from", IPNY_FROM }, 1252 { "hash", IPNY_HASH }, 1253 { "icmpidmap", IPNY_ICMPIDMAP }, 1254 { "in", IPNY_IN }, 1255 { "inet", IPNY_INET }, 1256 { "inet6", IPNY_INET6 }, 1257 { "mask", IPNY_MASK }, 1258 { "map", IPNY_MAP }, 1259 { "map-block", IPNY_MAPBLOCK }, 1260 { "mssclamp", IPNY_MSSCLAMP }, 1261 { "netmask", IPNY_MASK }, 1262 { "no", IPNY_NO }, 1263 { "on", IPNY_ON }, 1264 { "out", IPNY_OUT }, 1265 { "pool", IPNY_POOL }, 1266 { "port", IPNY_PORT }, 1267 { "portmap", IPNY_PORTMAP }, 1268 { "ports", IPNY_PORTS }, 1269 { "proto", IPNY_PROTO }, 1270 { "proxy", IPNY_PROXY }, 1271 { "purge", IPNY_PURGE }, 1272 { "range", IPNY_RANGE }, 1273 { "rewrite", IPNY_REWRITE }, 1274 { "rdr", IPNY_RDR }, 1275 { "round-robin",IPNY_ROUNDROBIN }, 1276 { "sequential", IPNY_SEQUENTIAL }, 1277 { "src", IPNY_SRC }, 1278 { "sticky", IPNY_STICKY }, 1279 { "tag", IPNY_TAG }, 1280 { "tcp", IPNY_TCP }, 1281 { "tcpudp", IPNY_TCPUDP }, 1282 { "to", IPNY_TO }, 1283 { "udp", IPNY_UDP }, 1284 { "-", '-' }, 1285 { "->", IPNY_TLATE }, 1286 { "eq", YY_CMP_EQ }, 1287 { "ne", YY_CMP_NE }, 1288 { "lt", YY_CMP_LT }, 1289 { "gt", YY_CMP_GT }, 1290 { "le", YY_CMP_LE }, 1291 { "ge", YY_CMP_GE }, 1292 { NULL, 0 } 1293 }; 1294 1295 1296 int 1297 ipnat_parsefile(int fd, addfunc_t addfunc, ioctlfunc_t ioctlfunc, 1298 char *filename) 1299 { 1300 FILE *fp = NULL; 1301 int rval; 1302 char *s; 1303 1304 yylineNum = 1; 1305 1306 (void) yysettab(yywords); 1307 1308 s = getenv("YYDEBUG"); 1309 if (s) 1310 yydebug = atoi(s); 1311 else 1312 yydebug = 0; 1313 1314 if (strcmp(filename, "-")) { 1315 fp = fopen(filename, "r"); 1316 if (!fp) { 1317 FPRINTF(stderr, "fopen(%s) failed: %s\n", filename, 1318 STRERROR(errno)); 1319 return(-1); 1320 } 1321 } else 1322 fp = stdin; 1323 1324 while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0) 1325 ; 1326 if (fp != NULL) 1327 fclose(fp); 1328 if (rval == -1) 1329 rval = 0; 1330 else if (rval != 0) 1331 rval = 1; 1332 return(rval); 1333 } 1334 1335 1336 int 1337 ipnat_parsesome(int fd, addfunc_t addfunc, ioctlfunc_t ioctlfunc, 1338 FILE *fp) 1339 { 1340 char *s; 1341 int i; 1342 1343 natfd = fd; 1344 parser_error = 0; 1345 nataddfunc = addfunc; 1346 natioctlfunc = ioctlfunc; 1347 1348 if (feof(fp)) 1349 return(-1); 1350 i = fgetc(fp); 1351 if (i == EOF) 1352 return(-1); 1353 if (ungetc(i, fp) == EOF) 1354 return(-1); 1355 if (feof(fp)) 1356 return(-1); 1357 s = getenv("YYDEBUG"); 1358 if (s) 1359 yydebug = atoi(s); 1360 else 1361 yydebug = 0; 1362 1363 yyin = fp; 1364 yyparse(); 1365 return(parser_error); 1366 } 1367 1368 1369 static void 1370 newnatrule(void) 1371 { 1372 ipnat_t *n; 1373 1374 n = calloc(1, sizeof(*n)); 1375 if (n == NULL) 1376 return; 1377 1378 if (nat == NULL) { 1379 nattop = nat = n; 1380 n->in_pnext = &nattop; 1381 } else { 1382 nat->in_next = n; 1383 n->in_pnext = &nat->in_next; 1384 nat = n; 1385 } 1386 1387 n->in_flineno = yylineNum; 1388 n->in_ifnames[0] = -1; 1389 n->in_ifnames[1] = -1; 1390 n->in_plabel = -1; 1391 n->in_pconfig = -1; 1392 n->in_size = sizeof(*n); 1393 1394 suggest_port = 0; 1395 } 1396 1397 1398 static void 1399 setnatproto(int p) 1400 { 1401 nat->in_pr[0] = p; 1402 nat->in_pr[1] = p; 1403 1404 switch (p) 1405 { 1406 case IPPROTO_TCP : 1407 nat->in_flags |= IPN_TCP; 1408 nat->in_flags &= ~IPN_UDP; 1409 break; 1410 case IPPROTO_UDP : 1411 nat->in_flags |= IPN_UDP; 1412 nat->in_flags &= ~IPN_TCP; 1413 break; 1414 #ifdef USE_INET6 1415 case IPPROTO_ICMPV6 : 1416 #endif 1417 case IPPROTO_ICMP : 1418 nat->in_flags &= ~IPN_TCPUDP; 1419 if (!(nat->in_flags & IPN_ICMPQUERY) && 1420 !(nat->in_redir & NAT_DIVERTUDP)) { 1421 nat->in_dcmp = 0; 1422 nat->in_scmp = 0; 1423 nat->in_dpmin = 0; 1424 nat->in_dpmax = 0; 1425 nat->in_dpnext = 0; 1426 nat->in_spmin = 0; 1427 nat->in_spmax = 0; 1428 nat->in_spnext = 0; 1429 } 1430 break; 1431 default : 1432 if ((nat->in_redir & NAT_MAPBLK) == 0) { 1433 nat->in_flags &= ~IPN_TCPUDP; 1434 nat->in_dcmp = 0; 1435 nat->in_scmp = 0; 1436 nat->in_dpmin = 0; 1437 nat->in_dpmax = 0; 1438 nat->in_dpnext = 0; 1439 nat->in_spmin = 0; 1440 nat->in_spmax = 0; 1441 nat->in_spnext = 0; 1442 } 1443 break; 1444 } 1445 1446 if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) { 1447 nat->in_stop = 0; 1448 nat->in_dtop = 0; 1449 nat->in_osport = 0; 1450 nat->in_odport = 0; 1451 nat->in_stop = 0; 1452 nat->in_osport = 0; 1453 nat->in_dtop = 0; 1454 nat->in_odport = 0; 1455 } 1456 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) 1457 nat->in_flags &= ~IPN_FIXEDDPORT; 1458 } 1459 1460 1461 int 1462 ipnat_addrule(int fd, ioctlfunc_t ioctlfunc, void *ptr) 1463 { 1464 ioctlcmd_t add, del; 1465 ipfobj_t obj; 1466 ipnat_t *ipn; 1467 1468 ipn = ptr; 1469 bzero((char *)&obj, sizeof(obj)); 1470 obj.ipfo_rev = IPFILTER_VERSION; 1471 obj.ipfo_size = ipn->in_size; 1472 obj.ipfo_type = IPFOBJ_IPNAT; 1473 obj.ipfo_ptr = ptr; 1474 1475 if ((opts & OPT_DONOTHING) != 0) 1476 fd = -1; 1477 1478 if (opts & OPT_ZERORULEST) { 1479 add = SIOCZRLST; 1480 del = 0; 1481 } else if (opts & OPT_PURGE) { 1482 add = 0; 1483 del = SIOCPURGENAT; 1484 } else { 1485 add = SIOCADNAT; 1486 del = SIOCRMNAT; 1487 } 1488 1489 if ((opts & OPT_VERBOSE) != 0) 1490 printnat(ipn, opts); 1491 1492 if (opts & OPT_DEBUG) 1493 binprint(ipn, ipn->in_size); 1494 1495 if ((opts & OPT_ZERORULEST) != 0) { 1496 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { 1497 if ((opts & OPT_DONOTHING) == 0) { 1498 char msg[80]; 1499 1500 snprintf(msg, sizeof(msg), "%d:ioctl(zero nat rule)", 1501 ipn->in_flineno); 1502 return(ipf_perror_fd(fd, ioctlfunc, msg)); 1503 } 1504 } else { 1505 PRINTF("hits %lu ", ipn->in_hits); 1506 #ifdef USE_QUAD_T 1507 PRINTF("bytes %"PRIu64" ", 1508 ipn->in_bytes[0] + ipn->in_bytes[1]); 1509 #else 1510 PRINTF("bytes %lu ", 1511 ipn->in_bytes[0] + ipn->in_bytes[1]); 1512 #endif 1513 printnat(ipn, opts); 1514 } 1515 } else if ((opts & OPT_REMOVE) != 0) { 1516 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { 1517 if ((opts & OPT_DONOTHING) == 0) { 1518 char msg[80]; 1519 1520 snprintf(msg, sizeof(msg), "%d:ioctl(delete nat rule)", 1521 ipn->in_flineno); 1522 return(ipf_perror_fd(fd, ioctlfunc, msg)); 1523 } 1524 } 1525 } else { 1526 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { 1527 if ((opts & OPT_DONOTHING) == 0) { 1528 char msg[80]; 1529 1530 snprintf(msg, sizeof(msg), "%d:ioctl(add/insert nat rule)", 1531 ipn->in_flineno); 1532 if (errno == EEXIST) { 1533 int strlen_msg = strlen(msg); 1534 snprintf(msg + strlen_msg, sizeof(msg) -strlen_msg, "(line %d)", 1535 ipn->in_flineno); 1536 } 1537 return(ipf_perror_fd(fd, ioctlfunc, msg)); 1538 } 1539 } 1540 } 1541 return(0); 1542 } 1543 1544 1545 static void 1546 setmapifnames() 1547 { 1548 if (nat->in_ifnames[1] == -1) 1549 nat->in_ifnames[1] = nat->in_ifnames[0]; 1550 1551 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) 1552 nat->in_flags |= IPN_TCPUDP; 1553 1554 if ((nat->in_flags & IPN_TCPUDP) == 0) 1555 setnatproto(nat->in_pr[1]); 1556 1557 if (((nat->in_redir & NAT_MAPBLK) != 0) || 1558 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 1559 nat_setgroupmap(nat); 1560 } 1561 1562 1563 static void 1564 setrdrifnames(void) 1565 { 1566 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) 1567 nat->in_flags |= IPN_TCPUDP; 1568 1569 if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && 1570 (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0)) 1571 setnatproto(IPPROTO_TCP); 1572 1573 if (nat->in_ifnames[1] == -1) 1574 nat->in_ifnames[1] = nat->in_ifnames[0]; 1575 } 1576 1577 1578 static void 1579 proxy_setconfig(int proxy) 1580 { 1581 if (proxy == IPNY_DNS) { 1582 yysetfixeddict(dnswords); 1583 } 1584 } 1585 1586 1587 static void 1588 proxy_unsetconfig(void) 1589 { 1590 yyresetdict(); 1591 } 1592 1593 1594 static namelist_t * 1595 proxy_dns_add_pass(char *prefix, char *name) 1596 { 1597 namelist_t *n; 1598 1599 n = calloc(1, sizeof(*n)); 1600 if (n != NULL) { 1601 if (prefix == NULL || *prefix == '\0') { 1602 n->na_name = strdup(name); 1603 } else { 1604 n->na_name = malloc(strlen(name) + strlen(prefix) + 1); 1605 strcpy(n->na_name, prefix); 1606 strcat(n->na_name, name); 1607 } 1608 } 1609 return(n); 1610 } 1611 1612 1613 static namelist_t * 1614 proxy_dns_add_block(char *prefix, char *name) 1615 { 1616 namelist_t *n; 1617 1618 n = calloc(1, sizeof(*n)); 1619 if (n != NULL) { 1620 if (prefix == NULL || *prefix == '\0') { 1621 n->na_name = strdup(name); 1622 } else { 1623 n->na_name = malloc(strlen(name) + strlen(prefix) + 1); 1624 strcpy(n->na_name, prefix); 1625 strcat(n->na_name, name); 1626 } 1627 n->na_value = 1; 1628 } 1629 return(n); 1630 } 1631 1632 1633 static void 1634 proxy_addconfig(char *proxy, int proto, char *conf, namelist_t *list) 1635 { 1636 proxyrule_t *pr; 1637 1638 pr = calloc(1, sizeof(*pr)); 1639 if (pr != NULL) { 1640 pr->pr_proto = proto; 1641 pr->pr_proxy = proxy; 1642 pr->pr_conf = conf; 1643 pr->pr_names = list; 1644 pr->pr_next = prules; 1645 prules = pr; 1646 } 1647 } 1648 1649 1650 static void 1651 proxy_loadrules(int fd, ioctlfunc_t ioctlfunc, proxyrule_t *rules) 1652 { 1653 proxyrule_t *pr; 1654 1655 while ((pr = rules) != NULL) { 1656 proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto, 1657 pr->pr_conf, pr->pr_names); 1658 rules = pr->pr_next; 1659 free(pr->pr_conf); 1660 free(pr); 1661 } 1662 } 1663 1664 1665 static void 1666 proxy_loadconfig(int fd, ioctlfunc_t ioctlfunc, char *proxy, int proto, 1667 char *conf, namelist_t *list) 1668 { 1669 namelist_t *na; 1670 ipfobj_t obj; 1671 ap_ctl_t pcmd; 1672 1673 obj.ipfo_rev = IPFILTER_VERSION; 1674 obj.ipfo_type = IPFOBJ_PROXYCTL; 1675 obj.ipfo_size = sizeof(pcmd); 1676 obj.ipfo_ptr = &pcmd; 1677 1678 while ((na = list) != NULL) { 1679 if ((opts & OPT_REMOVE) != 0) 1680 pcmd.apc_cmd = APC_CMD_DEL; 1681 else 1682 pcmd.apc_cmd = APC_CMD_ADD; 1683 pcmd.apc_dsize = strlen(na->na_name) + 1; 1684 pcmd.apc_data = na->na_name; 1685 pcmd.apc_arg = na->na_value; 1686 pcmd.apc_p = proto; 1687 1688 strncpy(pcmd.apc_label, proxy, APR_LABELLEN); 1689 pcmd.apc_label[APR_LABELLEN - 1] = '\0'; 1690 1691 strncpy(pcmd.apc_config, conf, APR_LABELLEN); 1692 pcmd.apc_config[APR_LABELLEN - 1] = '\0'; 1693 1694 if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) { 1695 if ((opts & OPT_DONOTHING) == 0) { 1696 char msg[80]; 1697 1698 snprintf(msg, sizeof(msg), "%d:ioctl(add/remove proxy rule)", 1699 yylineNum); 1700 ipf_perror_fd(fd, ioctlfunc, msg); 1701 return; 1702 } 1703 } 1704 1705 list = na->na_next; 1706 free(na->na_name); 1707 free(na); 1708 } 1709 } 1710 1711 1712 static void 1713 setifname(ipnat_t **np, int idx, char *name) 1714 { 1715 int pos; 1716 1717 pos = addname(np, name); 1718 if (pos == -1) 1719 return; 1720 (*np)->in_ifnames[idx] = pos; 1721 } 1722 1723 1724 static int 1725 addname(ipnat_t **np, char *name) 1726 { 1727 ipnat_t *n; 1728 int nlen; 1729 int pos; 1730 1731 nlen = strlen(name) + 1; 1732 n = realloc(*np, (*np)->in_size + nlen); 1733 if (*np == nattop) 1734 nattop = n; 1735 *np = n; 1736 if (n == NULL) 1737 return(-1); 1738 if (n->in_pnext != NULL) 1739 *n->in_pnext = n; 1740 n->in_size += nlen; 1741 pos = n->in_namelen; 1742 n->in_namelen += nlen; 1743 strcpy(n->in_names + pos, name); 1744 n->in_names[n->in_namelen] = '\0'; 1745 return(pos); 1746 } 1747