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