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