ipnat_y.y revision 172776
1193326Sed/* $FreeBSD: head/contrib/ipfilter/tools/ipnat_y.y 172776 2007-10-18 21:52:14Z darrenr $ */ 2193326Sed 3193326Sed/* 4193326Sed * Copyright (C) 2001-2006 by Darren Reed. 5193326Sed * 6193326Sed * See the IPFILTER.LICENCE file for details on licencing. 7193326Sed */ 8193326Sed%{ 9193326Sed#ifdef __FreeBSD__ 10193326Sed# ifndef __FreeBSD_cc_version 11193326Sed# include <osreldate.h> 12193326Sed# else 13193326Sed# if __FreeBSD_cc_version < 430000 14193326Sed# include <osreldate.h> 15193326Sed# endif 16193326Sed# endif 17193326Sed#endif 18193326Sed#include <stdio.h> 19193326Sed#include <unistd.h> 20193326Sed#include <string.h> 21193326Sed#include <fcntl.h> 22193326Sed#include <errno.h> 23193326Sed#if !defined(__SVR4) && !defined(__GNUC__) 24193326Sed#include <strings.h> 25193326Sed#endif 26193326Sed#include <sys/types.h> 27193326Sed#include <sys/param.h> 28193326Sed#include <sys/file.h> 29193326Sed#include <stdlib.h> 30193326Sed#include <stddef.h> 31193326Sed#include <sys/socket.h> 32193326Sed#include <sys/ioctl.h> 33193326Sed#include <netinet/in.h> 34193326Sed#include <netinet/in_systm.h> 35193326Sed#include <sys/time.h> 36193326Sed#include <syslog.h> 37193326Sed#include <net/if.h> 38193326Sed#if __FreeBSD_version >= 300000 39193326Sed# include <net/if_var.h> 40193326Sed#endif 41193326Sed#include <netdb.h> 42193326Sed#include <arpa/nameser.h> 43193326Sed#include <resolv.h> 44193326Sed#include "ipf.h" 45193326Sed#include "netinet/ipl.h" 46193326Sed#include "ipnat_l.h" 47193326Sed 48193326Sed#define YYDEBUG 1 49193326Sed 50193326Sedextern void yyerror __P((char *)); 51193326Sedextern int yyparse __P((void)); 52193326Sedextern int yylex __P((void)); 53193326Sedextern int yydebug; 54193326Sedextern FILE *yyin; 55193326Sedextern int yylineNum; 56193326Sed 57193326Sedstatic ipnat_t *nattop = NULL; 58193326Sedstatic ipnat_t *nat = NULL; 59193326Sedstatic int natfd = -1; 60193326Sedstatic ioctlfunc_t natioctlfunc = NULL; 61193326Sedstatic addfunc_t nataddfunc = NULL; 62193326Sedstatic int suggest_port = 0; 63193326Sed 64193326Sedstatic void newnatrule __P((void)); 65193326Sedstatic void setnatproto __P((int)); 66193326Sed 67193326Sed%} 68193326Sed%union { 69193326Sed char *str; 70193326Sed u_32_t num; 71193326Sed struct in_addr ipa; 72193326Sed frentry_t fr; 73193326Sed frtuc_t *frt; 74193326Sed u_short port; 75193326Sed struct { 76193326Sed u_short p1; 77193326Sed u_short p2; 78193326Sed int pc; 79193326Sed } pc; 80193326Sed struct { 81193326Sed struct in_addr a; 82193326Sed struct in_addr m; 83193326Sed } ipp; 84193326Sed union i6addr ip6; 85193326Sed}; 86193326Sed 87193326Sed%token <num> YY_NUMBER YY_HEX 88193326Sed%token <str> YY_STR 89193326Sed%token YY_COMMENT 90193326Sed%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT 91193326Sed%token YY_RANGE_OUT YY_RANGE_IN 92193326Sed%token <ip6> YY_IPV6 93193326Sed 94193326Sed%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE 95193326Sed%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY 96193326Sed%token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY 97193326Sed%token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG 98193326Sed%token IPNY_TLATE 99193326Sed%type <port> portspec 100193326Sed%type <num> hexnumber compare range proto 101193326Sed%type <ipa> hostname ipv4 102193326Sed%type <ipp> addr nummask rhaddr 103193326Sed%type <pc> portstuff 104193326Sed%% 105193326Sedfile: line 106193326Sed | assign 107193326Sed | file line 108193326Sed | file assign 109193326Sed ; 110193326Sed 111193326Sedline: xx rule { while ((nat = nattop) != NULL) { 112193326Sed nattop = nat->in_next; 113193326Sed (*nataddfunc)(natfd, natioctlfunc, nat); 114193326Sed free(nat); 115193326Sed } 116193326Sed resetlexer(); 117193326Sed } 118193326Sed | YY_COMMENT 119193326Sed ; 120193326Sed 121193326Sedassign: YY_STR assigning YY_STR ';' { set_variable($1, $3); 122193326Sed resetlexer(); 123193326Sed free($1); 124193326Sed free($3); 125193326Sed yyvarnext = 0; 126193326Sed } 127193326Sed ; 128193326Sed 129193326Sedassigning: 130193326Sed '=' { yyvarnext = 1; } 131193326Sed ; 132193326Sed 133193326Sedxx: { newnatrule(); } 134193326Sed ; 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