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