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