ipnat_y.y revision 272461
1/* $FreeBSD: releng/10.1/contrib/ipfilter/tools/ipnat_y.y 255332 2013-09-06 23:11:19Z 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 ICMP Id number"); 875 if ($3.p2 < 0 || $3.p2 > 65535) 876 yyerror("invalid 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; } 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("unknwon 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 1168 bzero(&$$, sizeof($$)); 1169 if (gethost(AF_INET, $1, 1170 &addr) == 0) { 1171 $$.a = addr; 1172 $$.f = AF_INET; 1173 } else 1174 if (gethost(AF_INET6, $1, 1175 &addr) == 0) { 1176 $$.a = addr; 1177 $$.f = AF_INET6; 1178 } else { 1179 FPRINTF(stderr, 1180 "Unknown host '%s'\n", 1181 $1); 1182 } 1183 free($1); 1184 } 1185 | YY_NUMBER { bzero(&$$, sizeof($$)); 1186 $$.a.in4.s_addr = htonl($1); 1187 if ($$.a.in4.s_addr != 0) 1188 $$.f = AF_INET; 1189 } 1190 | ipv4 { $$ = $1; } 1191 | YY_IPV6 { bzero(&$$, sizeof($$)); 1192 $$.a = $1; 1193 $$.f = AF_INET6; 1194 } 1195 | YY_NUMBER YY_IPV6 { bzero(&$$, sizeof($$)); 1196 $$.a = $2; 1197 $$.f = AF_INET6; 1198 } 1199 ; 1200 1201compare: 1202 '=' { $$ = FR_EQUAL; } 1203 | YY_CMP_EQ { $$ = FR_EQUAL; } 1204 | YY_CMP_NE { $$ = FR_NEQUAL; } 1205 | YY_CMP_LT { $$ = FR_LESST; } 1206 | YY_CMP_LE { $$ = FR_LESSTE; } 1207 | YY_CMP_GT { $$ = FR_GREATERT; } 1208 | YY_CMP_GE { $$ = FR_GREATERTE; } 1209 1210range: 1211 YY_RANGE_OUT { $$ = FR_OUTRANGE; } 1212 | YY_RANGE_IN { $$ = FR_INRANGE; } 1213 | ':' { $$ = FR_INCRANGE; } 1214 ; 1215 1216ipaddr: ipv4 { $$ = $1; } 1217 | YY_IPV6 { $$.a = $1; 1218 $$.f = AF_INET6; 1219 } 1220 ; 1221 1222ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER 1223 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 1224 yyerror("Invalid octet string for IP address"); 1225 return 0; 1226 } 1227 bzero((char *)&$$, sizeof($$)); 1228 $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; 1229 $$.a.in4.s_addr = htonl($$.a.in4.s_addr); 1230 $$.f = AF_INET; 1231 } 1232 ; 1233 1234%% 1235 1236 1237static wordtab_t proxies[] = { 1238 { "dns", IPNY_DNS } 1239}; 1240 1241static wordtab_t dnswords[] = { 1242 { "allow", IPNY_ALLOW }, 1243 { "block", IPNY_DENY }, 1244 { "deny", IPNY_DENY }, 1245 { "drop", IPNY_DENY }, 1246 { "pass", IPNY_ALLOW }, 1247 1248}; 1249 1250static wordtab_t yywords[] = { 1251 { "age", IPNY_AGE }, 1252 { "any", IPNY_ANY }, 1253 { "auto", IPNY_AUTO }, 1254 { "bimap", IPNY_BIMAP }, 1255 { "config", IPNY_CONFIG }, 1256 { "divert", IPNY_DIVERT }, 1257 { "dst", IPNY_DST }, 1258 { "dstlist", IPNY_DSTLIST }, 1259 { "frag", IPNY_FRAG }, 1260 { "from", IPNY_FROM }, 1261 { "hash", IPNY_HASH }, 1262 { "icmpidmap", IPNY_ICMPIDMAP }, 1263 { "in", IPNY_IN }, 1264 { "inet", IPNY_INET }, 1265 { "inet6", IPNY_INET6 }, 1266 { "mask", IPNY_MASK }, 1267 { "map", IPNY_MAP }, 1268 { "map-block", IPNY_MAPBLOCK }, 1269 { "mssclamp", IPNY_MSSCLAMP }, 1270 { "netmask", IPNY_MASK }, 1271 { "no", IPNY_NO }, 1272 { "on", IPNY_ON }, 1273 { "out", IPNY_OUT }, 1274 { "pool", IPNY_POOL }, 1275 { "port", IPNY_PORT }, 1276 { "portmap", IPNY_PORTMAP }, 1277 { "ports", IPNY_PORTS }, 1278 { "proto", IPNY_PROTO }, 1279 { "proxy", IPNY_PROXY }, 1280 { "purge", IPNY_PURGE }, 1281 { "range", IPNY_RANGE }, 1282 { "rewrite", IPNY_REWRITE }, 1283 { "rdr", IPNY_RDR }, 1284 { "round-robin",IPNY_ROUNDROBIN }, 1285 { "sequential", IPNY_SEQUENTIAL }, 1286 { "src", IPNY_SRC }, 1287 { "sticky", IPNY_STICKY }, 1288 { "tag", IPNY_TAG }, 1289 { "tcp", IPNY_TCP }, 1290 { "tcpudp", IPNY_TCPUDP }, 1291 { "to", IPNY_TO }, 1292 { "udp", IPNY_UDP }, 1293 { "-", '-' }, 1294 { "->", IPNY_TLATE }, 1295 { "eq", YY_CMP_EQ }, 1296 { "ne", YY_CMP_NE }, 1297 { "lt", YY_CMP_LT }, 1298 { "gt", YY_CMP_GT }, 1299 { "le", YY_CMP_LE }, 1300 { "ge", YY_CMP_GE }, 1301 { NULL, 0 } 1302}; 1303 1304 1305int 1306ipnat_parsefile(fd, addfunc, ioctlfunc, filename) 1307 int fd; 1308 addfunc_t addfunc; 1309 ioctlfunc_t ioctlfunc; 1310 char *filename; 1311{ 1312 FILE *fp = NULL; 1313 int rval; 1314 char *s; 1315 1316 yylineNum = 1; 1317 1318 (void) yysettab(yywords); 1319 1320 s = getenv("YYDEBUG"); 1321 if (s) 1322 yydebug = atoi(s); 1323 else 1324 yydebug = 0; 1325 1326 if (strcmp(filename, "-")) { 1327 fp = fopen(filename, "r"); 1328 if (!fp) { 1329 FPRINTF(stderr, "fopen(%s) failed: %s\n", filename, 1330 STRERROR(errno)); 1331 return -1; 1332 } 1333 } else 1334 fp = stdin; 1335 1336 while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0) 1337 ; 1338 if (fp != NULL) 1339 fclose(fp); 1340 if (rval == -1) 1341 rval = 0; 1342 else if (rval != 0) 1343 rval = 1; 1344 return rval; 1345} 1346 1347 1348int 1349ipnat_parsesome(fd, addfunc, ioctlfunc, fp) 1350 int fd; 1351 addfunc_t addfunc; 1352 ioctlfunc_t ioctlfunc; 1353 FILE *fp; 1354{ 1355 char *s; 1356 int i; 1357 1358 natfd = fd; 1359 parser_error = 0; 1360 nataddfunc = addfunc; 1361 natioctlfunc = ioctlfunc; 1362 1363 if (feof(fp)) 1364 return -1; 1365 i = fgetc(fp); 1366 if (i == EOF) 1367 return -1; 1368 if (ungetc(i, fp) == EOF) 1369 return -1; 1370 if (feof(fp)) 1371 return -1; 1372 s = getenv("YYDEBUG"); 1373 if (s) 1374 yydebug = atoi(s); 1375 else 1376 yydebug = 0; 1377 1378 yyin = fp; 1379 yyparse(); 1380 return parser_error; 1381} 1382 1383 1384static void 1385newnatrule() 1386{ 1387 ipnat_t *n; 1388 1389 n = calloc(1, sizeof(*n)); 1390 if (n == NULL) 1391 return; 1392 1393 if (nat == NULL) { 1394 nattop = nat = n; 1395 n->in_pnext = &nattop; 1396 } else { 1397 nat->in_next = n; 1398 n->in_pnext = &nat->in_next; 1399 nat = n; 1400 } 1401 1402 n->in_flineno = yylineNum; 1403 n->in_ifnames[0] = -1; 1404 n->in_ifnames[1] = -1; 1405 n->in_plabel = -1; 1406 n->in_pconfig = -1; 1407 n->in_size = sizeof(*n); 1408 1409 suggest_port = 0; 1410} 1411 1412 1413static void 1414setnatproto(p) 1415 int p; 1416{ 1417 nat->in_pr[0] = p; 1418 nat->in_pr[1] = p; 1419 1420 switch (p) 1421 { 1422 case IPPROTO_TCP : 1423 nat->in_flags |= IPN_TCP; 1424 nat->in_flags &= ~IPN_UDP; 1425 break; 1426 case IPPROTO_UDP : 1427 nat->in_flags |= IPN_UDP; 1428 nat->in_flags &= ~IPN_TCP; 1429 break; 1430 case IPPROTO_ICMP : 1431 nat->in_flags &= ~IPN_TCPUDP; 1432 if (!(nat->in_flags & IPN_ICMPQUERY) && 1433 !(nat->in_redir & NAT_DIVERTUDP)) { 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 default : 1445 if ((nat->in_redir & NAT_MAPBLK) == 0) { 1446 nat->in_flags &= ~IPN_TCPUDP; 1447 nat->in_dcmp = 0; 1448 nat->in_scmp = 0; 1449 nat->in_dpmin = 0; 1450 nat->in_dpmax = 0; 1451 nat->in_dpnext = 0; 1452 nat->in_spmin = 0; 1453 nat->in_spmax = 0; 1454 nat->in_spnext = 0; 1455 } 1456 break; 1457 } 1458 1459 if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) { 1460 nat->in_stop = 0; 1461 nat->in_dtop = 0; 1462 nat->in_osport = 0; 1463 nat->in_odport = 0; 1464 nat->in_stop = 0; 1465 nat->in_osport = 0; 1466 nat->in_dtop = 0; 1467 nat->in_odport = 0; 1468 } 1469 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) 1470 nat->in_flags &= ~IPN_FIXEDDPORT; 1471} 1472 1473 1474int 1475ipnat_addrule(fd, ioctlfunc, ptr) 1476 int fd; 1477 ioctlfunc_t ioctlfunc; 1478 void *ptr; 1479{ 1480 ioctlcmd_t add, del; 1481 ipfobj_t obj; 1482 ipnat_t *ipn; 1483 1484 ipn = ptr; 1485 bzero((char *)&obj, sizeof(obj)); 1486 obj.ipfo_rev = IPFILTER_VERSION; 1487 obj.ipfo_size = ipn->in_size; 1488 obj.ipfo_type = IPFOBJ_IPNAT; 1489 obj.ipfo_ptr = ptr; 1490 1491 if ((opts & OPT_DONOTHING) != 0) 1492 fd = -1; 1493 1494 if (opts & OPT_ZERORULEST) { 1495 add = SIOCZRLST; 1496 del = 0; 1497 } else if (opts & OPT_PURGE) { 1498 add = 0; 1499 del = SIOCPURGENAT; 1500 } else { 1501 add = SIOCADNAT; 1502 del = SIOCRMNAT; 1503 } 1504 1505 if ((opts & OPT_VERBOSE) != 0) 1506 printnat(ipn, opts); 1507 1508 if (opts & OPT_DEBUG) 1509 binprint(ipn, sizeof(*ipn)); 1510 1511 if ((opts & OPT_ZERORULEST) != 0) { 1512 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { 1513 if ((opts & OPT_DONOTHING) == 0) { 1514 char msg[80]; 1515 1516 sprintf(msg, "%d:ioctl(zero nat rule)", 1517 ipn->in_flineno); 1518 return ipf_perror_fd(fd, ioctlfunc, msg); 1519 } 1520 } else { 1521 PRINTF("hits %lu ", ipn->in_hits); 1522#ifdef USE_QUAD_T 1523 PRINTF("bytes %"PRIu64" ", 1524 ipn->in_bytes[0] + ipn->in_bytes[1]); 1525#else 1526 PRINTF("bytes %lu ", 1527 ipn->in_bytes[0] + ipn->in_bytes[1]); 1528#endif 1529 printnat(ipn, opts); 1530 } 1531 } else if ((opts & OPT_REMOVE) != 0) { 1532 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { 1533 if ((opts & OPT_DONOTHING) == 0) { 1534 char msg[80]; 1535 1536 sprintf(msg, "%d:ioctl(delete nat rule)", 1537 ipn->in_flineno); 1538 return ipf_perror_fd(fd, ioctlfunc, msg); 1539 } 1540 } 1541 } else { 1542 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { 1543 if ((opts & OPT_DONOTHING) == 0) { 1544 char msg[80]; 1545 1546 sprintf(msg, "%d:ioctl(add/insert nat rule)", 1547 ipn->in_flineno); 1548 if (errno == EEXIST) { 1549 sprintf(msg + strlen(msg), "(line %d)", 1550 ipn->in_flineno); 1551 } 1552 return ipf_perror_fd(fd, ioctlfunc, msg); 1553 } 1554 } 1555 } 1556 return 0; 1557} 1558 1559 1560static void 1561setmapifnames() 1562{ 1563 if (nat->in_ifnames[1] == -1) 1564 nat->in_ifnames[1] = nat->in_ifnames[0]; 1565 1566 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) 1567 nat->in_flags |= IPN_TCPUDP; 1568 1569 if ((nat->in_flags & IPN_TCPUDP) == 0) 1570 setnatproto(nat->in_pr[1]); 1571 1572 if (((nat->in_redir & NAT_MAPBLK) != 0) || 1573 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 1574 nat_setgroupmap(nat); 1575} 1576 1577 1578static void 1579setrdrifnames() 1580{ 1581 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) 1582 nat->in_flags |= IPN_TCPUDP; 1583 1584 if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && 1585 (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0)) 1586 setnatproto(IPPROTO_TCP); 1587 1588 if (nat->in_ifnames[1] == -1) 1589 nat->in_ifnames[1] = nat->in_ifnames[0]; 1590} 1591 1592 1593static void 1594proxy_setconfig(proxy) 1595 int proxy; 1596{ 1597 if (proxy == IPNY_DNS) { 1598 yysetfixeddict(dnswords); 1599 } 1600} 1601 1602 1603static void 1604proxy_unsetconfig() 1605{ 1606 yyresetdict(); 1607} 1608 1609 1610static namelist_t * 1611proxy_dns_add_pass(prefix, name) 1612 char *prefix, *name; 1613{ 1614 namelist_t *n; 1615 1616 n = calloc(1, sizeof(*n)); 1617 if (n != NULL) { 1618 if (prefix == NULL || *prefix == '\0') { 1619 n->na_name = strdup(name); 1620 } else { 1621 n->na_name = malloc(strlen(name) + strlen(prefix) + 1); 1622 strcpy(n->na_name, prefix); 1623 strcat(n->na_name, name); 1624 } 1625 } 1626 return n; 1627} 1628 1629 1630static namelist_t * 1631proxy_dns_add_block(prefix, name) 1632 char *prefix, *name; 1633{ 1634 namelist_t *n; 1635 1636 n = calloc(1, sizeof(*n)); 1637 if (n != NULL) { 1638 if (prefix == NULL || *prefix == '\0') { 1639 n->na_name = strdup(name); 1640 } else { 1641 n->na_name = malloc(strlen(name) + strlen(prefix) + 1); 1642 strcpy(n->na_name, prefix); 1643 strcat(n->na_name, name); 1644 } 1645 n->na_value = 1; 1646 } 1647 return n; 1648} 1649 1650 1651static void 1652proxy_addconfig(proxy, proto, conf, list) 1653 char *proxy, *conf; 1654 int proto; 1655 namelist_t *list; 1656{ 1657 proxyrule_t *pr; 1658 1659 pr = calloc(1, sizeof(*pr)); 1660 if (pr != NULL) { 1661 pr->pr_proto = proto; 1662 pr->pr_proxy = proxy; 1663 pr->pr_conf = conf; 1664 pr->pr_names = list; 1665 pr->pr_next = prules; 1666 prules = pr; 1667 } 1668} 1669 1670 1671static void 1672proxy_loadrules(fd, ioctlfunc, rules) 1673 int fd; 1674 ioctlfunc_t ioctlfunc; 1675 proxyrule_t *rules; 1676{ 1677 proxyrule_t *pr; 1678 1679 while ((pr = rules) != NULL) { 1680 proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto, 1681 pr->pr_conf, pr->pr_names); 1682 rules = pr->pr_next; 1683 free(pr->pr_conf); 1684 free(pr); 1685 } 1686} 1687 1688 1689static void 1690proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list) 1691 int fd; 1692 ioctlfunc_t ioctlfunc; 1693 char *proxy, *conf; 1694 int proto; 1695 namelist_t *list; 1696{ 1697 namelist_t *na; 1698 ipfobj_t obj; 1699 ap_ctl_t pcmd; 1700 1701 obj.ipfo_rev = IPFILTER_VERSION; 1702 obj.ipfo_type = IPFOBJ_PROXYCTL; 1703 obj.ipfo_size = sizeof(pcmd); 1704 obj.ipfo_ptr = &pcmd; 1705 1706 while ((na = list) != NULL) { 1707 if ((opts & OPT_REMOVE) != 0) 1708 pcmd.apc_cmd = APC_CMD_DEL; 1709 else 1710 pcmd.apc_cmd = APC_CMD_ADD; 1711 pcmd.apc_dsize = strlen(na->na_name) + 1; 1712 pcmd.apc_data = na->na_name; 1713 pcmd.apc_arg = na->na_value; 1714 pcmd.apc_p = proto; 1715 1716 strncpy(pcmd.apc_label, proxy, APR_LABELLEN); 1717 pcmd.apc_label[APR_LABELLEN - 1] = '\0'; 1718 1719 strncpy(pcmd.apc_config, conf, APR_LABELLEN); 1720 pcmd.apc_config[APR_LABELLEN - 1] = '\0'; 1721 1722 if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) { 1723 if ((opts & OPT_DONOTHING) == 0) { 1724 char msg[80]; 1725 1726 sprintf(msg, "%d:ioctl(add/remove proxy rule)", 1727 yylineNum); 1728 ipf_perror_fd(fd, ioctlfunc, msg); 1729 return; 1730 } 1731 } 1732 1733 list = na->na_next; 1734 free(na->na_name); 1735 free(na); 1736 } 1737} 1738 1739 1740static void 1741setifname(np, idx, name) 1742 ipnat_t **np; 1743 int idx; 1744 char *name; 1745{ 1746 int pos; 1747 1748 pos = addname(np, name); 1749 if (pos == -1) 1750 return; 1751 (*np)->in_ifnames[idx] = pos; 1752} 1753 1754 1755static int 1756addname(np, name) 1757 ipnat_t **np; 1758 char *name; 1759{ 1760 ipnat_t *n; 1761 int nlen; 1762 int pos; 1763 1764 nlen = strlen(name) + 1; 1765 n = realloc(*np, (*np)->in_size + nlen); 1766 if (*np == nattop) 1767 nattop = n; 1768 *np = n; 1769 if (n == NULL) 1770 return -1; 1771 if (n->in_pnext != NULL) 1772 *n->in_pnext = n; 1773 n->in_size += nlen; 1774 pos = n->in_namelen; 1775 n->in_namelen += nlen; 1776 strcpy(n->in_names + pos, name); 1777 n->in_names[n->in_namelen] = '\0'; 1778 return pos; 1779} 1780