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