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