ipnat_y.y revision 172776
1/* $FreeBSD: head/contrib/ipfilter/tools/ipnat_y.y 172776 2007-10-18 21:52:14Z darrenr $ */ 2 3/* 4 * Copyright (C) 2001-2006 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; 63 64static void newnatrule __P((void)); 65static void setnatproto __P((int)); 66 67%} 68%union { 69 char *str; 70 u_32_t num; 71 struct in_addr ipa; 72 frentry_t fr; 73 frtuc_t *frt; 74 u_short port; 75 struct { 76 u_short p1; 77 u_short p2; 78 int pc; 79 } pc; 80 struct { 81 struct in_addr a; 82 struct in_addr m; 83 } ipp; 84 union i6addr ip6; 85}; 86 87%token <num> YY_NUMBER YY_HEX 88%token <str> YY_STR 89%token YY_COMMENT 90%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT 91%token YY_RANGE_OUT YY_RANGE_IN 92%token <ip6> YY_IPV6 93 94%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE 95%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY 96%token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY 97%token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG 98%token IPNY_TLATE 99%type <port> portspec 100%type <num> hexnumber compare range proto 101%type <ipa> hostname ipv4 102%type <ipp> addr nummask rhaddr 103%type <pc> portstuff 104%% 105file: line 106 | assign 107 | file line 108 | file assign 109 ; 110 111line: xx rule { while ((nat = nattop) != NULL) { 112 nattop = nat->in_next; 113 (*nataddfunc)(natfd, natioctlfunc, nat); 114 free(nat); 115 } 116 resetlexer(); 117 } 118 | YY_COMMENT 119 ; 120 121assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); 122 resetlexer(); 123 free($1); 124 free($3); 125 yyvarnext = 0; 126 } 127 ; 128 129assigning: 130 '=' { yyvarnext = 1; } 131 ; 132 133xx: { newnatrule(); } 134 ; 135 136rule: map eol 137 | mapblock eol 138 | redir eol 139 ; 140 141eol: | ';' 142 ; 143 144map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions 145 { nat->in_v = 4; 146 nat->in_inip = $3.a.s_addr; 147 nat->in_inmsk = $3.m.s_addr; 148 nat->in_outip = $5.a.s_addr; 149 nat->in_outmsk = $5.m.s_addr; 150 if (nat->in_ifnames[1][0] == '\0') 151 strncpy(nat->in_ifnames[1], 152 nat->in_ifnames[0], 153 sizeof(nat->in_ifnames[0])); 154 if ((nat->in_flags & IPN_TCPUDP) == 0) 155 setnatproto(nat->in_p); 156 if (((nat->in_redir & NAT_MAPBLK) != 0) || 157 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 158 nat_setgroupmap(nat); 159 } 160 | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions 161 { nat->in_v = 4; 162 nat->in_inip = $3.a.s_addr; 163 nat->in_inmsk = $3.m.s_addr; 164 nat->in_outip = $5.a.s_addr; 165 nat->in_outmsk = $5.m.s_addr; 166 if (nat->in_ifnames[1][0] == '\0') 167 strncpy(nat->in_ifnames[1], 168 nat->in_ifnames[0], 169 sizeof(nat->in_ifnames[0])); 170 if (((nat->in_redir & NAT_MAPBLK) != 0) || 171 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 172 nat_setgroupmap(nat); 173 } 174 | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions 175 { nat->in_v = 4; 176 nat->in_outip = $5.a.s_addr; 177 nat->in_outmsk = $5.m.s_addr; 178 if (nat->in_ifnames[1][0] == '\0') 179 strncpy(nat->in_ifnames[1], 180 nat->in_ifnames[0], 181 sizeof(nat->in_ifnames[0])); 182 if ((suggest_port == 1) && 183 (nat->in_flags & IPN_TCPUDP) == 0) 184 nat->in_flags |= IPN_TCPUDP; 185 if ((nat->in_flags & IPN_TCPUDP) == 0) 186 setnatproto(nat->in_p); 187 if (((nat->in_redir & NAT_MAPBLK) != 0) || 188 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 189 nat_setgroupmap(nat); 190 } 191 | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions 192 { nat->in_v = 4; 193 nat->in_outip = $5.a.s_addr; 194 nat->in_outmsk = $5.m.s_addr; 195 if (nat->in_ifnames[1][0] == '\0') 196 strncpy(nat->in_ifnames[1], 197 nat->in_ifnames[0], 198 sizeof(nat->in_ifnames[0])); 199 if ((suggest_port == 1) && 200 (nat->in_flags & IPN_TCPUDP) == 0) 201 nat->in_flags |= IPN_TCPUDP; 202 if (((nat->in_redir & NAT_MAPBLK) != 0) || 203 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 204 nat_setgroupmap(nat); 205 } 206 ; 207 208mapblock: 209 mapblockit ifnames addr IPNY_TLATE addr ports mapoptions 210 { nat->in_v = 4; 211 nat->in_inip = $3.a.s_addr; 212 nat->in_inmsk = $3.m.s_addr; 213 nat->in_outip = $5.a.s_addr; 214 nat->in_outmsk = $5.m.s_addr; 215 if (nat->in_ifnames[1][0] == '\0') 216 strncpy(nat->in_ifnames[1], 217 nat->in_ifnames[0], 218 sizeof(nat->in_ifnames[0])); 219 if ((nat->in_flags & IPN_TCPUDP) == 0) 220 setnatproto(nat->in_p); 221 if (((nat->in_redir & NAT_MAPBLK) != 0) || 222 ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) 223 nat_setgroupmap(nat); 224 } 225 ; 226 227redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions 228 { nat->in_v = 4; 229 nat->in_outip = $3.a.s_addr; 230 nat->in_outmsk = $3.m.s_addr; 231 if (nat->in_ifnames[1][0] == '\0') 232 strncpy(nat->in_ifnames[1], 233 nat->in_ifnames[0], 234 sizeof(nat->in_ifnames[0])); 235 if ((nat->in_p == 0) && 236 ((nat->in_flags & IPN_TCPUDP) == 0) && 237 (nat->in_pmin != 0 || 238 nat->in_pmax != 0 || 239 nat->in_pnext != 0)) 240 setnatproto(IPPROTO_TCP); 241 } 242 | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions 243 { nat->in_v = 4; 244 if ((nat->in_p == 0) && 245 ((nat->in_flags & IPN_TCPUDP) == 0) && 246 (nat->in_pmin != 0 || 247 nat->in_pmax != 0 || 248 nat->in_pnext != 0)) 249 setnatproto(IPPROTO_TCP); 250 if ((suggest_port == 1) && 251 (nat->in_flags & IPN_TCPUDP) == 0) 252 nat->in_flags |= IPN_TCPUDP; 253 if (nat->in_ifnames[1][0] == '\0') 254 strncpy(nat->in_ifnames[1], 255 nat->in_ifnames[0], 256 sizeof(nat->in_ifnames[0])); 257 } 258 | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions 259 { nat->in_v = 4; 260 nat->in_outip = $3.a.s_addr; 261 nat->in_outmsk = $3.m.s_addr; 262 if (nat->in_ifnames[1][0] == '\0') 263 strncpy(nat->in_ifnames[1], 264 nat->in_ifnames[0], 265 sizeof(nat->in_ifnames[0])); 266 } 267 | rdrit ifnames rdrfrom IPNY_TLATE dip setproto rdroptions 268 { nat->in_v = 4; 269 if ((suggest_port == 1) && 270 (nat->in_flags & IPN_TCPUDP) == 0) 271 nat->in_flags |= IPN_TCPUDP; 272 if (nat->in_ifnames[1][0] == '\0') 273 strncpy(nat->in_ifnames[1], 274 nat->in_ifnames[0], 275 sizeof(nat->in_ifnames[0])); 276 } 277 ; 278 279proxy: | IPNY_PROXY port portspec YY_STR '/' proto 280 { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); 281 if (nat->in_dcmp == 0) { 282 nat->in_dport = htons($3); 283 } else if ($3 != nat->in_dport) { 284 yyerror("proxy port numbers not consistant"); 285 } 286 setnatproto($6); 287 free($4); 288 } 289 | IPNY_PROXY port YY_STR YY_STR '/' proto 290 { int pnum; 291 strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); 292 pnum = getportproto($3, $6); 293 if (pnum == -1) 294 yyerror("invalid port number"); 295 nat->in_dport = pnum; 296 setnatproto($6); 297 free($3); 298 free($4); 299 } 300 ; 301 302setproto: 303 | proto { if (nat->in_p != 0 || 304 nat->in_flags & IPN_TCPUDP) 305 yyerror("protocol set twice"); 306 setnatproto($1); 307 } 308 | IPNY_TCPUDP { if (nat->in_p != 0 || 309 nat->in_flags & IPN_TCPUDP) 310 yyerror("protocol set twice"); 311 nat->in_flags |= IPN_TCPUDP; 312 nat->in_p = 0; 313 } 314 | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 || 315 nat->in_flags & IPN_TCPUDP) 316 yyerror("protocol set twice"); 317 nat->in_flags |= IPN_TCPUDP; 318 nat->in_p = 0; 319 } 320 ; 321 322rhaddr: addr { $$.a = $1.a; $$.m = $1.m; } 323 | IPNY_RANGE ipv4 '-' ipv4 324 { $$.a = $2; $$.m = $4; 325 nat->in_flags |= IPN_IPRANGE; } 326 ; 327 328dip: 329 hostname { nat->in_inip = $1.s_addr; 330 nat->in_inmsk = 0xffffffff; } 331 | hostname '/' YY_NUMBER { if ($3 != 0 || $1.s_addr != 0) 332 yyerror("Only 0/0 supported"); 333 nat->in_inip = 0; 334 nat->in_inmsk = 0; 335 } 336 | hostname ',' hostname { nat->in_flags |= IPN_SPLIT; 337 nat->in_inip = $1.s_addr; 338 nat->in_inmsk = $3.s_addr; } 339 ; 340 341port: IPNY_PORT { suggest_port = 1; } 342 ; 343 344portspec: 345 YY_NUMBER { if ($1 > 65535) /* Unsigned */ 346 yyerror("invalid port number"); 347 else 348 $$ = $1; 349 } 350 | YY_STR { if (getport(NULL, $1, &($$)) == -1) 351 yyerror("invalid port number"); 352 $$ = ntohs($$); 353 } 354 ; 355 356dport: | port portspec { nat->in_pmin = htons($2); 357 nat->in_pmax = htons($2); } 358 | port portspec '-' portspec { nat->in_pmin = htons($2); 359 nat->in_pmax = htons($4); } 360 | port portspec ':' portspec { nat->in_pmin = htons($2); 361 nat->in_pmax = htons($4); } 362 ; 363 364nport: port portspec { nat->in_pnext = htons($2); } 365 | port '=' portspec { nat->in_pnext = htons($3); 366 nat->in_flags |= IPN_FIXEDDPORT; 367 } 368 ; 369 370ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $2; } 371 | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; } 372 ; 373 374mapit: IPNY_MAP { nat->in_redir = NAT_MAP; } 375 | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; } 376 ; 377 378rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; } 379 ; 380 381mapblockit: 382 IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; } 383 ; 384 385mapfrom: 386 from sobject IPNY_TO dobject 387 | from sobject '!' IPNY_TO dobject 388 { nat->in_flags |= IPN_NOTDST; } 389 | from sobject IPNY_TO '!' dobject 390 { nat->in_flags |= IPN_NOTDST; } 391 ; 392 393rdrfrom: 394 from sobject IPNY_TO dobject 395 | '!' from sobject IPNY_TO dobject 396 { nat->in_flags |= IPN_NOTSRC; } 397 | from '!' sobject IPNY_TO dobject 398 { nat->in_flags |= IPN_NOTSRC; } 399 ; 400 401from: IPNY_FROM { nat->in_flags |= IPN_FILTER; } 402 ; 403 404ifnames: 405 ifname 406 | ifname ',' otherifname 407 ; 408 409ifname: YY_STR { strncpy(nat->in_ifnames[0], $1, 410 sizeof(nat->in_ifnames[0])); 411 nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; 412 free($1); 413 } 414 ; 415 416otherifname: 417 YY_STR { strncpy(nat->in_ifnames[1], $1, 418 sizeof(nat->in_ifnames[1])); 419 nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; 420 free($1); 421 } 422 ; 423 424mapport: 425 IPNY_PORTMAP tcpudp portspec ':' portspec 426 { nat->in_pmin = htons($3); 427 nat->in_pmax = htons($5); 428 } 429 | IPNY_PORTMAP tcpudp IPNY_AUTO 430 { nat->in_flags |= IPN_AUTOPORTMAP; 431 nat->in_pmin = htons(1024); 432 nat->in_pmax = htons(65535); 433 } 434 | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER 435 { if (strcmp($2, "icmp") != 0) { 436 yyerror("icmpidmap not followed by icmp"); 437 } 438 free($2); 439 if ($3 < 0 || $3 > 65535) 440 yyerror("invalid ICMP Id number"); 441 if ($5 < 0 || $5 > 65535) 442 yyerror("invalid ICMP Id number"); 443 nat->in_flags = IPN_ICMPQUERY; 444 nat->in_pmin = htons($3); 445 nat->in_pmax = htons($5); 446 } 447 ; 448 449sobject: 450 saddr 451 | saddr port portstuff { nat->in_sport = $3.p1; 452 nat->in_stop = $3.p2; 453 nat->in_scmp = $3.pc; } 454 ; 455 456saddr: addr { if (nat->in_redir == NAT_REDIRECT) { 457 nat->in_srcip = $1.a.s_addr; 458 nat->in_srcmsk = $1.m.s_addr; 459 } else { 460 nat->in_inip = $1.a.s_addr; 461 nat->in_inmsk = $1.m.s_addr; 462 } 463 } 464 ; 465 466dobject: 467 daddr 468 | daddr port portstuff { nat->in_dport = $3.p1; 469 nat->in_dtop = $3.p2; 470 nat->in_dcmp = $3.pc; 471 if (nat->in_redir == NAT_REDIRECT) 472 nat->in_pmin = htons($3.p1); 473 } 474 ; 475 476daddr: addr { if (nat->in_redir == NAT_REDIRECT) { 477 nat->in_outip = $1.a.s_addr; 478 nat->in_outmsk = $1.m.s_addr; 479 } else { 480 nat->in_srcip = $1.a.s_addr; 481 nat->in_srcmsk = $1.m.s_addr; 482 } 483 } 484 ; 485 486addr: IPNY_ANY { $$.a.s_addr = 0; $$.m.s_addr = 0; } 487 | nummask { $$.a = $1.a; $$.m = $1.m; 488 $$.a.s_addr &= $$.m.s_addr; } 489 | hostname '/' ipv4 { $$.a = $1; $$.m = $3; 490 $$.a.s_addr &= $$.m.s_addr; } 491 | hostname '/' hexnumber { $$.a = $1; $$.m.s_addr = htonl($3); 492 $$.a.s_addr &= $$.m.s_addr; } 493 | hostname IPNY_MASK ipv4 { $$.a = $1; $$.m = $3; 494 $$.a.s_addr &= $$.m.s_addr; } 495 | hostname IPNY_MASK hexnumber { $$.a = $1; $$.m.s_addr = htonl($3); 496 $$.a.s_addr &= $$.m.s_addr; } 497 ; 498 499nummask: 500 hostname { $$.a = $1; 501 $$.m.s_addr = 0xffffffff; } 502 | hostname '/' YY_NUMBER { $$.a = $1; 503 ntomask(4, $3, &$$.m.s_addr); } 504 ; 505 506portstuff: 507 compare portspec { $$.pc = $1; $$.p1 = $2; } 508 | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; } 509 ; 510 511mapoptions: 512 rr frag age mssclamp nattag setproto 513 ; 514 515rdroptions: 516 rr frag age sticky mssclamp rdrproxy nattag 517 ; 518 519nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2, 520 sizeof(nat->in_tag.ipt_tag)); 521 } 522rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; } 523 ; 524 525frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; } 526 ; 527 528age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2; 529 nat->in_age[1] = $2; } 530 | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2; 531 nat->in_age[1] = $4; } 532 ; 533 534sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) && 535 !(nat->in_flags & IPN_SPLIT)) { 536 fprintf(stderr, 537 "'sticky' for use with round-robin/IP splitting only\n"); 538 } else 539 nat->in_flags |= IPN_STICKY; 540 } 541 ; 542 543mssclamp: 544 | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; } 545 ; 546 547tcpudp: | IPNY_TCP { setnatproto(IPPROTO_TCP); } 548 | IPNY_UDP { setnatproto(IPPROTO_UDP); } 549 | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP; 550 nat->in_p = 0; 551 } 552 | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; 553 nat->in_p = 0; 554 } 555 ; 556 557rdrproxy: 558 IPNY_PROXY YY_STR 559 { strncpy(nat->in_plabel, $2, 560 sizeof(nat->in_plabel)); 561 nat->in_dport = nat->in_pnext; 562 nat->in_dport = htons(nat->in_dport); 563 free($2); 564 } 565 | proxy { if (nat->in_plabel[0] != '\0') { 566 nat->in_pmin = nat->in_dport; 567 nat->in_pmax = nat->in_pmin; 568 nat->in_pnext = nat->in_pmin; 569 } 570 } 571 ; 572 573proto: YY_NUMBER { $$ = $1; 574 if ($$ != IPPROTO_TCP && 575 $$ != IPPROTO_UDP) 576 suggest_port = 0; 577 } 578 | IPNY_TCP { $$ = IPPROTO_TCP; } 579 | IPNY_UDP { $$ = IPPROTO_UDP; } 580 | YY_STR { $$ = getproto($1); free($1); 581 if ($$ != IPPROTO_TCP && 582 $$ != IPPROTO_UDP) 583 suggest_port = 0; 584 } 585 ; 586 587hexnumber: 588 YY_HEX { $$ = $1; } 589 ; 590 591hostname: 592 YY_STR { if (gethost($1, &$$.s_addr) == -1) 593 fprintf(stderr, 594 "Unknown host '%s'\n", 595 $1); 596 free($1); 597 } 598 | YY_NUMBER { $$.s_addr = htonl($1); } 599 | ipv4 { $$.s_addr = $1.s_addr; } 600 ; 601 602compare: 603 '=' { $$ = FR_EQUAL; } 604 | YY_CMP_EQ { $$ = FR_EQUAL; } 605 | YY_CMP_NE { $$ = FR_NEQUAL; } 606 | YY_CMP_LT { $$ = FR_LESST; } 607 | YY_CMP_LE { $$ = FR_LESSTE; } 608 | YY_CMP_GT { $$ = FR_GREATERT; } 609 | YY_CMP_GE { $$ = FR_GREATERTE; } 610 611range: 612 YY_RANGE_OUT { $$ = FR_OUTRANGE; } 613 | YY_RANGE_IN { $$ = FR_INRANGE; } 614 | ':' { $$ = FR_INCRANGE; } 615 ; 616 617ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER 618 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 619 yyerror("Invalid octet string for IP address"); 620 return 0; 621 } 622 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; 623 $$.s_addr = htonl($$.s_addr); 624 } 625 ; 626 627%% 628 629 630static wordtab_t yywords[] = { 631 { "age", IPNY_AGE }, 632 { "any", IPNY_ANY }, 633 { "auto", IPNY_AUTO }, 634 { "bimap", IPNY_BIMAP }, 635 { "frag", IPNY_FRAG }, 636 { "from", IPNY_FROM }, 637 { "icmpidmap", IPNY_ICMPIDMAP }, 638 { "mask", IPNY_MASK }, 639 { "map", IPNY_MAP }, 640 { "map-block", IPNY_MAPBLOCK }, 641 { "mssclamp", IPNY_MSSCLAMP }, 642 { "netmask", IPNY_MASK }, 643 { "port", IPNY_PORT }, 644 { "portmap", IPNY_PORTMAP }, 645 { "ports", IPNY_PORTS }, 646 { "proxy", IPNY_PROXY }, 647 { "range", IPNY_RANGE }, 648 { "rdr", IPNY_RDR }, 649 { "round-robin",IPNY_ROUNDROBIN }, 650 { "sticky", IPNY_STICKY }, 651 { "tag", IPNY_TAG }, 652 { "tcp", IPNY_TCP }, 653 { "tcpudp", IPNY_TCPUDP }, 654 { "to", IPNY_TO }, 655 { "udp", IPNY_UDP }, 656 { "-", '-' }, 657 { "->", IPNY_TLATE }, 658 { "eq", YY_CMP_EQ }, 659 { "ne", YY_CMP_NE }, 660 { "lt", YY_CMP_LT }, 661 { "gt", YY_CMP_GT }, 662 { "le", YY_CMP_LE }, 663 { "ge", YY_CMP_GE }, 664 { NULL, 0 } 665}; 666 667 668int ipnat_parsefile(fd, addfunc, ioctlfunc, filename) 669int fd; 670addfunc_t addfunc; 671ioctlfunc_t ioctlfunc; 672char *filename; 673{ 674 FILE *fp = NULL; 675 char *s; 676 677 (void) yysettab(yywords); 678 679 s = getenv("YYDEBUG"); 680 if (s) 681 yydebug = atoi(s); 682 else 683 yydebug = 0; 684 685 if (strcmp(filename, "-")) { 686 fp = fopen(filename, "r"); 687 if (!fp) { 688 fprintf(stderr, "fopen(%s) failed: %s\n", filename, 689 STRERROR(errno)); 690 return -1; 691 } 692 } else 693 fp = stdin; 694 695 while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1) 696 ; 697 if (fp != NULL) 698 fclose(fp); 699 return 0; 700} 701 702 703int ipnat_parsesome(fd, addfunc, ioctlfunc, fp) 704int fd; 705addfunc_t addfunc; 706ioctlfunc_t ioctlfunc; 707FILE *fp; 708{ 709 char *s; 710 int i; 711 712 yylineNum = 1; 713 714 natfd = fd; 715 nataddfunc = addfunc; 716 natioctlfunc = ioctlfunc; 717 718 if (feof(fp)) 719 return 0; 720 i = fgetc(fp); 721 if (i == EOF) 722 return 0; 723 if (ungetc(i, fp) == EOF) 724 return 0; 725 if (feof(fp)) 726 return 0; 727 s = getenv("YYDEBUG"); 728 if (s) 729 yydebug = atoi(s); 730 else 731 yydebug = 0; 732 733 yyin = fp; 734 yyparse(); 735 return 1; 736} 737 738 739static void newnatrule() 740{ 741 ipnat_t *n; 742 743 n = calloc(1, sizeof(*n)); 744 if (n == NULL) 745 return; 746 747 if (nat == NULL) 748 nattop = nat = n; 749 else { 750 nat->in_next = n; 751 nat = n; 752 } 753 754 suggest_port = 0; 755} 756 757 758static void setnatproto(p) 759int p; 760{ 761 nat->in_p = p; 762 763 switch (p) 764 { 765 case IPPROTO_TCP : 766 nat->in_flags |= IPN_TCP; 767 nat->in_flags &= ~IPN_UDP; 768 break; 769 case IPPROTO_UDP : 770 nat->in_flags |= IPN_UDP; 771 nat->in_flags &= ~IPN_TCP; 772 break; 773 case IPPROTO_ICMP : 774 nat->in_flags &= ~IPN_TCPUDP; 775 if (!(nat->in_flags & IPN_ICMPQUERY)) { 776 nat->in_dcmp = 0; 777 nat->in_scmp = 0; 778 nat->in_pmin = 0; 779 nat->in_pmax = 0; 780 nat->in_pnext = 0; 781 } 782 break; 783 default : 784 if ((nat->in_redir & NAT_MAPBLK) == 0) { 785 nat->in_flags &= ~IPN_TCPUDP; 786 nat->in_dcmp = 0; 787 nat->in_scmp = 0; 788 nat->in_pmin = 0; 789 nat->in_pmax = 0; 790 nat->in_pnext = 0; 791 } 792 break; 793 } 794 795 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) 796 nat->in_flags &= ~IPN_FIXEDDPORT; 797} 798 799 800void ipnat_addrule(fd, ioctlfunc, ptr) 801int fd; 802ioctlfunc_t ioctlfunc; 803void *ptr; 804{ 805 ioctlcmd_t add, del; 806 ipfobj_t obj; 807 ipnat_t *ipn; 808 809 ipn = ptr; 810 bzero((char *)&obj, sizeof(obj)); 811 obj.ipfo_rev = IPFILTER_VERSION; 812 obj.ipfo_size = sizeof(ipnat_t); 813 obj.ipfo_type = IPFOBJ_IPNAT; 814 obj.ipfo_ptr = ptr; 815 add = 0; 816 del = 0; 817 818 if ((opts & OPT_DONOTHING) != 0) 819 fd = -1; 820 821 if (opts & OPT_ZERORULEST) { 822 add = SIOCZRLST; 823 } else if (opts & OPT_INACTIVE) { 824 add = SIOCADNAT; 825 del = SIOCRMNAT; 826 } else { 827 add = SIOCADNAT; 828 del = SIOCRMNAT; 829 } 830 831 if ((opts & OPT_VERBOSE) != 0) 832 printnat(ipn, opts); 833 834 if (opts & OPT_DEBUG) 835 binprint(ipn, sizeof(*ipn)); 836 837 if ((opts & OPT_ZERORULEST) != 0) { 838 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { 839 if ((opts & OPT_DONOTHING) == 0) { 840 fprintf(stderr, "%d:", yylineNum); 841 perror("ioctl(SIOCZRLST)"); 842 } 843 } else { 844#ifdef USE_QUAD_T 845/* 846 printf("hits %qd bytes %qd ", 847 (long long)fr->fr_hits, 848 (long long)fr->fr_bytes); 849*/ 850#else 851/* 852 printf("hits %ld bytes %ld ", 853 fr->fr_hits, fr->fr_bytes); 854*/ 855#endif 856 printnat(ipn, opts); 857 } 858 } else if ((opts & OPT_REMOVE) != 0) { 859 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { 860 if ((opts & OPT_DONOTHING) == 0) { 861 fprintf(stderr, "%d:", yylineNum); 862 perror("ioctl(delete nat rule)"); 863 } 864 } 865 } else { 866 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { 867 if ((opts & OPT_DONOTHING) == 0) { 868 fprintf(stderr, "%d:", yylineNum); 869 perror("ioctl(add/insert nat rule)"); 870 } 871 } 872 } 873} 874