5 # ifndef __FreeBSD_cc_version
6 # include <osreldate.h>
8 # if __FreeBSD_cc_version < 430000
9 # include <osreldate.h>
18 #if !defined(__SVR4) && !defined(__GNUC__)
21 #include <sys/types.h>
22 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <netinet/in.h>
29 #include <netinet/in_systm.h>
33 #if __FreeBSD_version >= 300000
34 # include <net/if_var.h>
37 #include <arpa/nameser.h>
40 #include "netinet/ipl.h"
45 extern void yyerror __P((char *));
46 extern int yyparse __P((void));
47 extern int yylex __P((void));
52 static ipnat_t *nattop = NULL;
53 static ipnat_t *nat = NULL;
54 static int natfd = -1;
55 static ioctlfunc_t natioctlfunc = NULL;
56 static addfunc_t nataddfunc = NULL;
57 static int suggest_port = 0;
59 static void newnatrule __P((void));
60 static void setnatproto __P((int));
82 %token <num> YY_NUMBER YY_HEX
85 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
86 %token YY_RANGE_OUT YY_RANGE_IN
89 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
90 %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
91 %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
92 %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
95 %type <num> hexnumber compare range proto
96 %type <ipa> hostname ipv4
97 %type <ipp> addr nummask rhaddr
106 line: xx rule { while ((nat = nattop) != NULL) {
107 nattop = nat->in_next;
108 (*nataddfunc)(natfd, natioctlfunc, nat);
116 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
124 '=' { yyvarnext = 1; }
127 xx: { newnatrule(); }
138 map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
140 nat->in_inip = $3.a.s_addr;
141 nat->in_inmsk = $3.m.s_addr;
142 nat->in_outip = $5.a.s_addr;
143 nat->in_outmsk = $5.m.s_addr;
144 if (nat->in_ifnames[1][0] == '\0')
145 strncpy(nat->in_ifnames[1],
147 sizeof(nat->in_ifnames[0]));
148 if ((nat->in_flags & IPN_TCPUDP) == 0)
149 setnatproto(nat->in_p);
150 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
151 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
152 nat_setgroupmap(nat);
154 | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
156 nat->in_inip = $3.a.s_addr;
157 nat->in_inmsk = $3.m.s_addr;
158 nat->in_outip = $5.a.s_addr;
159 nat->in_outmsk = $5.m.s_addr;
160 if (nat->in_ifnames[1][0] == '\0')
161 strncpy(nat->in_ifnames[1],
163 sizeof(nat->in_ifnames[0]));
164 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
165 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
166 nat_setgroupmap(nat);
168 | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
170 nat->in_outip = $5.a.s_addr;
171 nat->in_outmsk = $5.m.s_addr;
172 if (nat->in_ifnames[1][0] == '\0')
173 strncpy(nat->in_ifnames[1],
175 sizeof(nat->in_ifnames[0]));
176 if ((suggest_port == 1) &&
177 (nat->in_flags & IPN_TCPUDP) == 0)
178 nat->in_flags |= IPN_TCPUDP;
179 if ((nat->in_flags & IPN_TCPUDP) == 0)
180 setnatproto(nat->in_p);
181 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
182 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
183 nat_setgroupmap(nat);
185 | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
187 nat->in_outip = $5.a.s_addr;
188 nat->in_outmsk = $5.m.s_addr;
189 if (nat->in_ifnames[1][0] == '\0')
190 strncpy(nat->in_ifnames[1],
192 sizeof(nat->in_ifnames[0]));
193 if ((suggest_port == 1) &&
194 (nat->in_flags & IPN_TCPUDP) == 0)
195 nat->in_flags |= IPN_TCPUDP;
196 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
197 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
198 nat_setgroupmap(nat);
203 mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
205 nat->in_inip = $3.a.s_addr;
206 nat->in_inmsk = $3.m.s_addr;
207 nat->in_outip = $5.a.s_addr;
208 nat->in_outmsk = $5.m.s_addr;
209 if (nat->in_ifnames[1][0] == '\0')
210 strncpy(nat->in_ifnames[1],
212 sizeof(nat->in_ifnames[0]));
213 if ((nat->in_flags & IPN_TCPUDP) == 0)
214 setnatproto(nat->in_p);
215 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
216 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
217 nat_setgroupmap(nat);
221 redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
223 nat->in_outip = $3.a.s_addr;
224 nat->in_outmsk = $3.m.s_addr;
225 if (nat->in_ifnames[1][0] == '\0')
226 strncpy(nat->in_ifnames[1],
228 sizeof(nat->in_ifnames[0]));
229 if ((nat->in_p == 0) &&
230 ((nat->in_flags & IPN_TCPUDP) == 0) &&
231 (nat->in_pmin != 0 ||
234 setnatproto(IPPROTO_TCP);
236 | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
238 if ((nat->in_p == 0) &&
239 ((nat->in_flags & IPN_TCPUDP) == 0) &&
240 (nat->in_pmin != 0 ||
243 setnatproto(IPPROTO_TCP);
244 if ((suggest_port == 1) &&
245 (nat->in_flags & IPN_TCPUDP) == 0)
246 nat->in_flags |= IPN_TCPUDP;
247 if (nat->in_ifnames[1][0] == '\0')
248 strncpy(nat->in_ifnames[1],
250 sizeof(nat->in_ifnames[0]));
252 | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
254 nat->in_outip = $3.a.s_addr;
255 nat->in_outmsk = $3.m.s_addr;
256 if (nat->in_ifnames[1][0] == '\0')
257 strncpy(nat->in_ifnames[1],
259 sizeof(nat->in_ifnames[0]));
261 | rdrit ifnames rdrfrom IPNY_TLATE dip setproto rdroptions
263 if ((suggest_port == 1) &&
264 (nat->in_flags & IPN_TCPUDP) == 0)
265 nat->in_flags |= IPN_TCPUDP;
266 if (nat->in_ifnames[1][0] == '\0')
267 strncpy(nat->in_ifnames[1],
269 sizeof(nat->in_ifnames[0]));
273 proxy: | IPNY_PROXY port portspec YY_STR '/' proto
274 { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
275 if (nat->in_dcmp == 0) {
276 nat->in_dport = htons($3);
277 } else if ($3 != nat->in_dport) {
278 yyerror("proxy port numbers not consistant");
283 | IPNY_PROXY port YY_STR YY_STR '/' proto
285 strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
286 pnum = getportproto($3, $6);
288 yyerror("invalid port number");
289 nat->in_dport = pnum;
297 | proto { if (nat->in_p != 0 ||
298 nat->in_flags & IPN_TCPUDP)
299 yyerror("protocol set twice");
302 | IPNY_TCPUDP { if (nat->in_p != 0 ||
303 nat->in_flags & IPN_TCPUDP)
304 yyerror("protocol set twice");
305 nat->in_flags |= IPN_TCPUDP;
308 | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 ||
309 nat->in_flags & IPN_TCPUDP)
310 yyerror("protocol set twice");
311 nat->in_flags |= IPN_TCPUDP;
316 rhaddr: addr { $$.a = $1.a; $$.m = $1.m; }
317 | IPNY_RANGE ipv4 '-' ipv4
318 { $$.a = $2; $$.m = $4;
319 nat->in_flags |= IPN_IPRANGE; }
323 hostname { nat->in_inip = $1.s_addr;
324 nat->in_inmsk = 0xffffffff; }
325 | hostname '/' YY_NUMBER { if ($3 != 0 || $1.s_addr != 0)
326 yyerror("Only 0/0 supported");
330 | hostname ',' hostname { nat->in_flags |= IPN_SPLIT;
331 nat->in_inip = $1.s_addr;
332 nat->in_inmsk = $3.s_addr; }
335 port: IPNY_PORT { suggest_port = 1; }
339 YY_NUMBER { if ($1 > 65535) /* Unsigned */
340 yyerror("invalid port number");
344 | YY_STR { if (getport(NULL, $1, &($$)) == -1)
345 yyerror("invalid port number");
350 dport: | port portspec { nat->in_pmin = htons($2);
351 nat->in_pmax = htons($2); }
352 | port portspec '-' portspec { nat->in_pmin = htons($2);
353 nat->in_pmax = htons($4); }
354 | port portspec ':' portspec { nat->in_pmin = htons($2);
355 nat->in_pmax = htons($4); }
358 nport: port portspec { nat->in_pnext = htons($2); }
359 | port '=' portspec { nat->in_pnext = htons($3);
360 nat->in_flags |= IPN_FIXEDDPORT;
364 ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $2; }
365 | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; }
368 mapit: IPNY_MAP { nat->in_redir = NAT_MAP; }
369 | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; }
372 rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; }
376 IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; }
380 from sobject IPNY_TO dobject
381 | from sobject '!' IPNY_TO dobject
382 { nat->in_flags |= IPN_NOTDST; }
383 | from sobject IPNY_TO '!' dobject
384 { nat->in_flags |= IPN_NOTDST; }
388 from sobject IPNY_TO dobject
389 | '!' from sobject IPNY_TO dobject
390 { nat->in_flags |= IPN_NOTSRC; }
391 | from '!' sobject IPNY_TO dobject
392 { nat->in_flags |= IPN_NOTSRC; }
395 from: IPNY_FROM { nat->in_flags |= IPN_FILTER; }
400 | ifname ',' otherifname
403 ifname: YY_STR { strncpy(nat->in_ifnames[0], $1,
404 sizeof(nat->in_ifnames[0]));
405 nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
411 YY_STR { strncpy(nat->in_ifnames[1], $1,
412 sizeof(nat->in_ifnames[1]));
413 nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
419 IPNY_PORTMAP tcpudp portspec ':' portspec
420 { nat->in_pmin = htons($3);
421 nat->in_pmax = htons($5);
423 | IPNY_PORTMAP tcpudp IPNY_AUTO
424 { nat->in_flags |= IPN_AUTOPORTMAP;
425 nat->in_pmin = htons(1024);
426 nat->in_pmax = htons(65535);
428 | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
429 { if (strcmp($2, "icmp") != 0) {
430 yyerror("icmpidmap not followed by icmp");
433 if ($3 < 0 || $3 > 65535)
434 yyerror("invalid ICMP Id number");
435 if ($5 < 0 || $5 > 65535)
436 yyerror("invalid ICMP Id number");
437 nat->in_flags = IPN_ICMPQUERY;
438 nat->in_pmin = htons($3);
439 nat->in_pmax = htons($5);
445 | saddr port portstuff { nat->in_sport = $3.p1;
446 nat->in_stop = $3.p2;
447 nat->in_scmp = $3.pc; }
450 saddr: addr { if (nat->in_redir == NAT_REDIRECT) {
451 nat->in_srcip = $1.a.s_addr;
452 nat->in_srcmsk = $1.m.s_addr;
454 nat->in_inip = $1.a.s_addr;
455 nat->in_inmsk = $1.m.s_addr;
462 | daddr port portstuff { nat->in_dport = $3.p1;
463 nat->in_dtop = $3.p2;
464 nat->in_dcmp = $3.pc;
465 if (nat->in_redir == NAT_REDIRECT)
466 nat->in_pmin = htons($3.p1);
470 daddr: addr { if (nat->in_redir == NAT_REDIRECT) {
471 nat->in_outip = $1.a.s_addr;
472 nat->in_outmsk = $1.m.s_addr;
474 nat->in_srcip = $1.a.s_addr;
475 nat->in_srcmsk = $1.m.s_addr;
480 addr: IPNY_ANY { $$.a.s_addr = 0; $$.m.s_addr = 0; }
481 | nummask { $$.a = $1.a; $$.m = $1.m;
482 $$.a.s_addr &= $$.m.s_addr; }
483 | hostname '/' ipv4 { $$.a = $1; $$.m = $3;
484 $$.a.s_addr &= $$.m.s_addr; }
485 | hostname '/' hexnumber { $$.a = $1; $$.m.s_addr = htonl($3);
486 $$.a.s_addr &= $$.m.s_addr; }
487 | hostname IPNY_MASK ipv4 { $$.a = $1; $$.m = $3;
488 $$.a.s_addr &= $$.m.s_addr; }
489 | hostname IPNY_MASK hexnumber { $$.a = $1; $$.m.s_addr = htonl($3);
490 $$.a.s_addr &= $$.m.s_addr; }
494 hostname { $$.a = $1;
495 $$.m.s_addr = 0xffffffff; }
496 | hostname '/' YY_NUMBER { $$.a = $1;
497 ntomask(4, $3, &$$.m.s_addr); }
501 compare portspec { $$.pc = $1; $$.p1 = $2; }
502 | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
506 rr frag age mssclamp nattag setproto
510 rr frag age sticky mssclamp rdrproxy nattag
513 nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2,
514 sizeof(nat->in_tag.ipt_tag));
516 rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; }
519 frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; }
522 age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2;
523 nat->in_age[1] = $2; }
524 | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2;
525 nat->in_age[1] = $4; }
528 sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) &&
529 !(nat->in_flags & IPN_SPLIT)) {
531 "'sticky' for use with round-robin/IP splitting only\n");
533 nat->in_flags |= IPN_STICKY;
538 | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; }
541 tcpudp: | IPNY_TCP { setnatproto(IPPROTO_TCP); }
542 | IPNY_UDP { setnatproto(IPPROTO_UDP); }
543 | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP;
546 | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
553 { strncpy(nat->in_plabel, $2,
554 sizeof(nat->in_plabel));
555 nat->in_dport = nat->in_pnext;
556 nat->in_dport = htons(nat->in_dport);
559 | proxy { if (nat->in_plabel[0] != '\0') {
560 nat->in_pmin = nat->in_dport;
561 nat->in_pmax = nat->in_pmin;
562 nat->in_pnext = nat->in_pmin;
567 proto: YY_NUMBER { $$ = $1;
568 if ($$ != IPPROTO_TCP &&
572 | IPNY_TCP { $$ = IPPROTO_TCP; }
573 | IPNY_UDP { $$ = IPPROTO_UDP; }
574 | YY_STR { $$ = getproto($1); free($1);
575 if ($$ != IPPROTO_TCP &&
586 YY_STR { if (gethost($1, &$$.s_addr) == -1)
588 "Unknown host '%s'\n",
592 | YY_NUMBER { $$.s_addr = htonl($1); }
593 | ipv4 { $$.s_addr = $1.s_addr; }
597 '=' { $$ = FR_EQUAL; }
598 | YY_CMP_EQ { $$ = FR_EQUAL; }
599 | YY_CMP_NE { $$ = FR_NEQUAL; }
600 | YY_CMP_LT { $$ = FR_LESST; }
601 | YY_CMP_LE { $$ = FR_LESSTE; }
602 | YY_CMP_GT { $$ = FR_GREATERT; }
603 | YY_CMP_GE { $$ = FR_GREATERTE; }
606 YY_RANGE_OUT { $$ = FR_OUTRANGE; }
607 | YY_RANGE_IN { $$ = FR_INRANGE; }
610 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
611 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
612 yyerror("Invalid octet string for IP address");
615 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
616 $$.s_addr = htonl($$.s_addr);
623 static wordtab_t yywords[] = {
626 { "auto", IPNY_AUTO },
627 { "bimap", IPNY_BIMAP },
628 { "frag", IPNY_FRAG },
629 { "from", IPNY_FROM },
630 { "icmpidmap", IPNY_ICMPIDMAP },
631 { "mask", IPNY_MASK },
633 { "map-block", IPNY_MAPBLOCK },
634 { "mssclamp", IPNY_MSSCLAMP },
635 { "netmask", IPNY_MASK },
636 { "port", IPNY_PORT },
637 { "portmap", IPNY_PORTMAP },
638 { "ports", IPNY_PORTS },
639 { "proxy", IPNY_PROXY },
640 { "range", IPNY_RANGE },
642 { "round-robin",IPNY_ROUNDROBIN },
643 { "sticky", IPNY_STICKY },
646 { "tcpudp", IPNY_TCPUDP },
650 { "->", IPNY_TLATE },
661 int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
664 ioctlfunc_t ioctlfunc;
670 (void) yysettab(yywords);
672 s = getenv("YYDEBUG");
678 if (strcmp(filename, "-")) {
679 fp = fopen(filename, "r");
681 fprintf(stderr, "fopen(%s) failed: %s\n", filename,
688 while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
696 int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
699 ioctlfunc_t ioctlfunc;
708 nataddfunc = addfunc;
709 natioctlfunc = ioctlfunc;
716 if (ungetc(i, fp) == EOF)
720 s = getenv("YYDEBUG");
732 static void newnatrule()
736 n = calloc(1, sizeof(*n));
751 static void setnatproto(p)
759 nat->in_flags |= IPN_TCP;
760 nat->in_flags &= ~IPN_UDP;
763 nat->in_flags |= IPN_UDP;
764 nat->in_flags &= ~IPN_TCP;
767 nat->in_flags &= ~IPN_TCPUDP;
768 if (!(nat->in_flags & IPN_ICMPQUERY)) {
777 if ((nat->in_redir & NAT_MAPBLK) == 0) {
778 nat->in_flags &= ~IPN_TCPUDP;
788 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
789 nat->in_flags &= ~IPN_FIXEDDPORT;
793 void ipnat_addrule(fd, ioctlfunc, ptr)
795 ioctlfunc_t ioctlfunc;
803 bzero((char *)&obj, sizeof(obj));
804 obj.ipfo_rev = IPFILTER_VERSION;
805 obj.ipfo_size = sizeof(ipnat_t);
806 obj.ipfo_type = IPFOBJ_IPNAT;
811 if ((opts & OPT_DONOTHING) != 0)
814 if (opts & OPT_ZERORULEST) {
816 } else if (opts & OPT_INACTIVE) {
824 if ((opts & OPT_VERBOSE) != 0)
827 if (opts & OPT_DEBUG)
828 binprint(ipn, sizeof(*ipn));
830 if ((opts & OPT_ZERORULEST) != 0) {
831 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
832 if ((opts & OPT_DONOTHING) == 0) {
833 fprintf(stderr, "%d:", yylineNum);
834 perror("ioctl(SIOCZRLST)");
839 printf("hits %qd bytes %qd ",
840 (long long)fr->fr_hits,
841 (long long)fr->fr_bytes);
845 printf("hits %ld bytes %ld ",
846 fr->fr_hits, fr->fr_bytes);
851 } else if ((opts & OPT_REMOVE) != 0) {
852 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
853 if ((opts & OPT_DONOTHING) == 0) {
854 fprintf(stderr, "%d:", yylineNum);
855 perror("ioctl(delete nat rule)");
859 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
860 if ((opts & OPT_DONOTHING) == 0) {
861 fprintf(stderr, "%d:", yylineNum);
862 perror("ioctl(add/insert nat rule)");