4 * Copyright (C) 2012 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
10 # ifndef __FreeBSD_cc_version
11 # include <osreldate.h>
13 # if __FreeBSD_cc_version < 430000
14 # include <osreldate.h>
23 #if !defined(__SVR4) && !defined(__GNUC__)
26 #include <sys/types.h>
27 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
39 #include <arpa/nameser.h>
42 #include "netinet/ipl.h"
47 extern void yyerror __P((char *));
48 extern int yyparse __P((void));
49 extern int yylex __P((void));
54 static ipnat_t *nattop = NULL;
55 static ipnat_t *nat = NULL;
56 static int natfd = -1;
57 static ioctlfunc_t natioctlfunc = NULL;
58 static addfunc_t nataddfunc = NULL;
59 static int suggest_port = 0;
60 static proxyrule_t *prules = NULL;
61 static int parser_error = 0;
63 static void newnatrule __P((void));
64 static void setnatproto __P((int));
65 static void setmapifnames __P((void));
66 static void setrdrifnames __P((void));
67 static void proxy_setconfig __P((int));
68 static void proxy_unsetconfig __P((void));
69 static namelist_t *proxy_dns_add_pass __P((char *, char *));
70 static namelist_t *proxy_dns_add_block __P((char *, char *));
71 static void proxy_addconfig __P((char *, int, char *, namelist_t *));
72 static void proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
73 char *, namelist_t *));
74 static void proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
75 static void setmapifnames __P((void));
76 static void setrdrifnames __P((void));
77 static void setifname __P((ipnat_t **, int, char *));
78 static int addname __P((ipnat_t **, char *));
98 int t; /* Address type */
101 int v; /* IP version */
102 int s; /* 0 = number, 1 = text */
109 %token <num> YY_NUMBER YY_HEX
112 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
113 %token YY_RANGE_OUT YY_RANGE_IN
116 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
117 %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
118 %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
119 %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
120 %token IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
121 %token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
122 %token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
123 %token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
124 %type <port> portspec
125 %type <num> hexnumber compare range proto
126 %type <num> saddr daddr sobject dobject mapfrom rdrfrom dip
127 %type <ipa> hostname ipv4 ipaddr
128 %type <ipp> addr rhsaddr rhdaddr erhdaddr
129 %type <pc> portstuff portpair comaports srcports dstports
130 %type <names> dnslines dnsline
139 line: xx rule { int err;
140 while ((nat = nattop) != NULL) {
141 if (nat->in_v[0] == 0)
143 if (nat->in_v[1] == 0)
144 nat->in_v[1] = nat->in_v[0];
145 nattop = nat->in_next;
146 err = (*nataddfunc)(natfd, natioctlfunc, nat);
153 if (parser_error == 0 && prules != NULL) {
154 proxy_loadrules(natfd, natioctlfunc, prules);
162 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
171 '=' { yyvarnext = 1; }
174 xx: { newnatrule(); }
184 no: IPNY_NO { nat->in_flags |= IPN_NO; }
190 map: mapit ifnames addr tlate rhsaddr proxy mapoptions
191 { if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
192 yyerror("3.address family mismatch");
193 if (nat->in_v[0] == 0 && $5.v != 0)
195 else if (nat->in_v[0] == 0 && $3.v != 0)
197 if (nat->in_v[1] == 0 && $5.v != 0)
199 else if (nat->in_v[1] == 0 && $3.v != 0)
201 nat->in_osrcatype = $3.t;
202 bcopy(&$3.a, &nat->in_osrc.na_addr[0],
204 bcopy(&$3.m, &nat->in_osrc.na_addr[1],
206 nat->in_nsrcatype = $5.t;
207 nat->in_nsrcafunc = $5.u;
208 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
210 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
215 | mapit ifnames addr tlate rhsaddr mapport mapoptions
216 { if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
217 yyerror("4.address family mismatch");
218 if (nat->in_v[1] == 0 && $5.v != 0)
220 else if (nat->in_v[0] == 0 && $3.v != 0)
222 if (nat->in_v[0] == 0 && $5.v != 0)
224 else if (nat->in_v[1] == 0 && $3.v != 0)
226 nat->in_osrcatype = $3.t;
227 bcopy(&$3.a, &nat->in_osrc.na_addr[0],
229 bcopy(&$3.m, &nat->in_osrc.na_addr[1],
231 nat->in_nsrcatype = $5.t;
232 nat->in_nsrcafunc = $5.u;
233 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
235 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
240 | no mapit ifnames addr setproto ';'
241 { if (nat->in_v[0] == 0)
243 nat->in_osrcatype = $4.t;
244 bcopy(&$4.a, &nat->in_osrc.na_addr[0],
246 bcopy(&$4.m, &nat->in_osrc.na_addr[1],
251 | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
252 { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
253 yyerror("5.address family mismatch");
254 if (nat->in_v[0] == 0 && $5.v != 0)
256 else if (nat->in_v[0] == 0 && $3 != 0)
257 nat->in_v[0] = ftov($3);
258 if (nat->in_v[1] == 0 && $5.v != 0)
260 else if (nat->in_v[1] == 0 && $3 != 0)
261 nat->in_v[1] = ftov($3);
262 nat->in_nsrcatype = $5.t;
263 nat->in_nsrcafunc = $5.u;
264 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
266 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
271 | no mapit ifnames mapfrom setproto ';'
272 { nat->in_v[0] = ftov($4);
275 | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
276 { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
277 yyerror("6.address family mismatch");
278 if (nat->in_v[0] == 0 && $5.v != 0)
280 else if (nat->in_v[0] == 0 && $3 != 0)
281 nat->in_v[0] = ftov($3);
282 if (nat->in_v[1] == 0 && $5.v != 0)
284 else if (nat->in_v[1] == 0 && $3 != 0)
285 nat->in_v[1] = ftov($3);
286 nat->in_nsrcatype = $5.t;
287 nat->in_nsrcafunc = $5.u;
288 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
290 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
298 mapblockit ifnames addr tlate addr ports mapoptions
299 { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
300 yyerror("7.address family mismatch");
301 if (nat->in_v[0] == 0 && $5.v != 0)
303 else if (nat->in_v[0] == 0 && $3.v != 0)
305 if (nat->in_v[1] == 0 && $5.v != 0)
307 else if (nat->in_v[1] == 0 && $3.v != 0)
309 nat->in_osrcatype = $3.t;
310 bcopy(&$3.a, &nat->in_osrc.na_addr[0],
312 bcopy(&$3.m, &nat->in_osrc.na_addr[1],
314 nat->in_nsrcatype = $5.t;
315 nat->in_nsrcafunc = $5.u;
316 bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
318 bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
323 | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
324 { if (nat->in_v[0] == 0)
326 if (nat->in_v[1] == 0)
328 nat->in_osrcatype = $5.t;
329 bcopy(&$5.a, &nat->in_osrc.na_addr[0],
331 bcopy(&$5.m, &nat->in_osrc.na_addr[1],
338 redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions
339 { if ($6 != 0 && $3.f != 0 && $6 != $3.f)
340 yyerror("21.address family mismatch");
341 if (nat->in_v[0] == 0) {
342 if ($3.v != AF_UNSPEC)
343 nat->in_v[0] = ftov($3.f);
345 nat->in_v[0] = ftov($6);
347 nat->in_odstatype = $3.t;
348 bcopy(&$3.a, &nat->in_odst.na_addr[0],
350 bcopy(&$3.m, &nat->in_odst.na_addr[1],
355 | no rdrit ifnames addr dport setproto ';'
356 { if (nat->in_v[0] == 0)
357 nat->in_v[0] = ftov($4.f);
358 nat->in_odstatype = $4.t;
359 bcopy(&$4.a, &nat->in_odst.na_addr[0],
361 bcopy(&$4.m, &nat->in_odst.na_addr[1],
366 | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
367 { if ($5 != 0 && $3 != 0 && $5 != $3)
368 yyerror("20.address family mismatch");
369 if (nat->in_v[0] == 0) {
371 nat->in_v[0] = ftov($3);
373 nat->in_v[0] = ftov($5);
377 | no rdrit ifnames rdrfrom setproto ';'
378 { nat->in_v[0] = ftov($4);
385 IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
386 { if (nat->in_v[0] == 0)
387 nat->in_v[0] = ftov($4);
388 if (nat->in_redir & NAT_MAP)
392 nat->in_redir |= NAT_REWRITE;
396 divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
397 { if (nat->in_v[0] == 0)
398 nat->in_v[0] = ftov($4);
399 if (nat->in_redir & NAT_MAP) {
401 nat->in_pr[0] = IPPROTO_UDP;
404 nat->in_pr[1] = IPPROTO_UDP;
406 nat->in_flags &= ~IPN_TCP;
410 tlate: IPNY_TLATE { yyexpectaddr = 1; }
413 pconf: IPNY_PROXY { yysetdict(proxies); }
414 IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
415 { proxy_setconfig(IPNY_DNS); }
417 { proxy_addconfig("dns", $5, $7, $10);
424 | dnslines ';' dnsline { $$ = $1; $1->na_next = $3; }
428 IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); }
429 | IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); }
430 | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); }
431 | IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); }
435 inout IPNY_ON ifnames { ; }
438 inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; }
439 | IPNY_OUT { nat->in_redir = NAT_MAP; }
443 | IPNY_PROTO setproto
446 newdst: src rhsaddr srcports dst erhdaddr dstports
447 { nat->in_nsrc.na_addr[0] = $2.a;
448 nat->in_nsrc.na_addr[1] = $2.m;
449 nat->in_nsrc.na_atype = $2.t;
450 if ($2.t == FRI_LOOKUP) {
451 nat->in_nsrc.na_type = $2.u;
452 nat->in_nsrc.na_subtype = $2.s;
453 nat->in_nsrc.na_num = $2.n;
455 nat->in_nsports[0] = $3.p1;
456 nat->in_nsports[1] = $3.p2;
457 nat->in_ndst.na_addr[0] = $5.a;
458 nat->in_ndst.na_addr[1] = $5.m;
459 nat->in_ndst.na_atype = $5.t;
460 if ($5.t == FRI_LOOKUP) {
461 nat->in_ndst.na_type = $5.u;
462 nat->in_ndst.na_subtype = $5.s;
463 nat->in_ndst.na_num = $5.n;
465 nat->in_ndports[0] = $6.p1;
466 nat->in_ndports[1] = $6.p2;
470 divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP
471 { nat->in_nsrc.na_addr[0] = $2.a;
472 if ($2.m.in4.s_addr != 0xffffffff)
473 yyerror("divert must have /32 dest");
474 nat->in_nsrc.na_addr[1] = $2.m;
475 nat->in_nsports[0] = $4;
476 nat->in_nsports[1] = $4;
478 nat->in_ndst.na_addr[0] = $6.a;
479 nat->in_ndst.na_addr[1] = $6.m;
480 if ($6.m.in4.s_addr != 0xffffffff)
481 yyerror("divert must have /32 dest");
482 nat->in_ndports[0] = $8;
483 nat->in_ndports[1] = $8;
485 nat->in_redir |= NAT_DIVERTUDP;
489 src: IPNY_SRC { yyexpectaddr = 1; }
492 dst: IPNY_DST { yyexpectaddr = 1; }
496 comaports { $$.p1 = $1.p1;
499 | IPNY_PORT '=' portspec
502 nat->in_flags |= IPN_FIXEDSPORT;
507 comaports { $$.p1 = $1.p1;
510 | IPNY_PORT '=' portspec
513 nat->in_flags |= IPN_FIXEDDPORT;
521 | ',' { if (!(nat->in_flags & IPN_TCPUDP))
522 yyerror("must be TCP/UDP for ports");
524 portpair { $$.p1 = $3.p1;
529 proxy: | IPNY_PROXY port portspec YY_STR '/' proto
531 pos = addname(&nat, $4);
532 nat->in_plabel = pos;
533 if (nat->in_dcmp == 0) {
535 } else if ($3 != nat->in_odport) {
536 yyerror("proxy port numbers not consistant");
542 | IPNY_PROXY port YY_STR YY_STR '/' proto
544 pos = addname(&nat, $4);
545 nat->in_plabel = pos;
546 pnum = getportproto($3, $6);
548 yyerror("invalid port number");
549 nat->in_odport = ntohs(pnum);
550 nat->in_ndport = ntohs(pnum);
555 | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
557 pos = addname(&nat, $4);
558 nat->in_plabel = pos;
559 if (nat->in_dcmp == 0) {
561 } else if ($3 != nat->in_odport) {
562 yyerror("proxy port numbers not consistant");
566 nat->in_pconfig = addname(&nat, $8);
570 | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
572 pos = addname(&nat, $4);
573 nat->in_plabel = pos;
574 pnum = getportproto($3, $6);
576 yyerror("invalid port number");
577 nat->in_odport = ntohs(pnum);
578 nat->in_ndport = ntohs(pnum);
580 pos = addname(&nat, $8);
581 nat->in_pconfig = pos;
588 | proto { if (nat->in_pr[0] != 0 ||
589 nat->in_pr[1] != 0 ||
590 nat->in_flags & IPN_TCPUDP)
591 yyerror("protocol set twice");
594 | IPNY_TCPUDP { if (nat->in_pr[0] != 0 ||
595 nat->in_pr[1] != 0 ||
596 nat->in_flags & IPN_TCPUDP)
597 yyerror("protocol set twice");
598 nat->in_flags |= IPN_TCPUDP;
602 | IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 ||
603 nat->in_pr[1] != 0 ||
604 nat->in_flags & IPN_TCPUDP)
605 yyerror("protocol set twice");
606 nat->in_flags |= IPN_TCPUDP;
616 | hostname '-' { yyexpectaddr = 1; } hostname
619 yyerror("8.address family "
625 nat->in_flags |= IPN_SIPRANGE;
628 | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
631 yyerror("9.address family "
637 nat->in_flags |= IPN_SIPRANGE;
643 hostname ',' { yyexpectaddr = 1; } hostname
644 { nat->in_flags |= IPN_SPLIT;
646 yyerror("10.address family "
649 nat->in_ndstip6 = $1.a;
650 nat->in_ndstmsk6 = $4.a;
651 nat->in_ndstatype = FRI_SPLIT;
654 | rhdaddr { int bits;
655 nat->in_ndstip6 = $1.a;
656 nat->in_ndstmsk6 = $1.m;
657 nat->in_ndst.na_atype = $1.t;
660 bits = count4bits($1.m.in4.s_addr);
662 bits = count6bits($1.m.i6);
663 if (($1.f == AF_INET) && (bits != 0) &&
665 yyerror("dest ip bitmask not /32");
666 } else if (($1.f == AF_INET6) &&
667 (bits != 0) && (bits != 128)) {
668 yyerror("dest ip bitmask not /128");
678 | hostname '-' hostname { bzero(&$$, sizeof($$));
680 if ($1.f != 0 && $3.f != 0 &&
682 yyerror("11.address family "
686 nat->in_flags |= IPN_DIPRANGE;
689 | IPNY_RANGE hostname '-' hostname
690 { bzero(&$$, sizeof($$));
692 if ($2.f != 0 && $4.f != 0 &&
694 yyerror("12.address family "
698 nat->in_flags |= IPN_DIPRANGE;
705 | IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP;
710 | IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP;
713 $$.n = addname(&nat, $3);
717 port: IPNY_PORT { suggest_port = 1; }
721 YY_NUMBER { if ($1 > 65535) /* Unsigned */
722 yyerror("invalid port number");
726 | YY_STR { if (getport(NULL, $1,
728 yyerror("invalid port number");
734 portspec { $$.p1 = $1; $$.p2 = $1; }
735 | portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; }
736 | portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; }
739 dport: | port portpair { nat->in_odport = $2.p1;
741 nat->in_dtop = $2.p1;
743 nat->in_dtop = $2.p2;
747 nport: | port portpair { nat->in_dpmin = $2.p1;
748 nat->in_dpnext = $2.p1;
749 nat->in_dpmax = $2.p2;
750 nat->in_ndport = $2.p1;
751 if (nat->in_dtop == 0)
752 nat->in_dtop = $2.p2;
754 | port '=' portspec { nat->in_dpmin = $3;
757 if (nat->in_dtop == 0)
758 nat->in_dtop = nat->in_odport;
759 nat->in_flags |= IPN_FIXEDDPORT;
763 ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $2; }
764 | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; }
767 mapit: IPNY_MAP { nat->in_redir = NAT_MAP; }
768 | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; }
771 rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; }
775 IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; }
779 from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
780 yyerror("13.address family "
784 | from sobject '!' to dobject
785 { if ($2 != 0 && $5 != 0 && $2 != $5)
786 yyerror("14.address family "
788 nat->in_flags |= IPN_NOTDST;
791 | from sobject to '!' dobject
792 { if ($2 != 0 && $5 != 0 && $2 != $5)
793 yyerror("15.address family "
795 nat->in_flags |= IPN_NOTDST;
801 from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
802 yyerror("16.address family "
806 | '!' from sobject to dobject
807 { if ($3 != 0 && $5 != 0 && $3 != $5)
808 yyerror("17.address family "
810 nat->in_flags |= IPN_NOTSRC;
813 | from '!' sobject to dobject
814 { if ($3 != 0 && $5 != 0 && $3 != $5)
815 yyerror("18.address family "
817 nat->in_flags |= IPN_NOTSRC;
822 from: IPNY_FROM { nat->in_flags |= IPN_FILTER;
827 to: IPNY_TO { yyexpectaddr = 1; }
831 ifname family { yyexpectaddr = 1; }
832 | ifname ',' otherifname family { yyexpectaddr = 1; }
835 ifname: YY_STR { setifname(&nat, 0, $1);
840 family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; }
841 | IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; }
845 YY_STR { setifname(&nat, 1, $1);
851 IPNY_PORTMAP tcpudp portpair sequential
852 { nat->in_spmin = $3.p1;
853 nat->in_spmax = $3.p2;
855 | IPNY_PORTMAP portpair tcpudp sequential
856 { nat->in_spmin = $2.p1;
857 nat->in_spmax = $2.p2;
859 | IPNY_PORTMAP tcpudp IPNY_AUTO sequential
860 { nat->in_flags |= IPN_AUTOPORTMAP;
861 nat->in_spmin = 1024;
862 nat->in_spmax = 65535;
864 | IPNY_ICMPIDMAP YY_STR portpair sequential
865 { if (strcmp($2, "icmp") != 0 &&
866 strcmp($2, "ipv6-icmp") != 0) {
867 yyerror("icmpidmap not followed by icmp");
870 if ($3.p1 < 0 || $3.p1 > 65535)
871 yyerror("invalid 1st ICMP Id number");
872 if ($3.p2 < 0 || $3.p2 > 65535)
873 yyerror("invalid 2nd ICMP Id number");
874 if (strcmp($2, "ipv6-icmp") == 0) {
875 nat->in_pr[0] = IPPROTO_ICMPV6;
876 nat->in_pr[1] = IPPROTO_ICMPV6;
878 nat->in_pr[0] = IPPROTO_ICMP;
879 nat->in_pr[1] = IPPROTO_ICMP;
881 nat->in_flags = IPN_ICMPQUERY;
882 nat->in_spmin = $3.p1;
883 nat->in_spmax = $3.p2;
889 | saddr port portstuff { nat->in_osport = $3.p1;
890 nat->in_stop = $3.p2;
891 nat->in_scmp = $3.pc;
896 saddr: addr { nat->in_osrcatype = $1.t;
898 &nat->in_osrc.na_addr[0],
901 &nat->in_osrc.na_addr[1],
909 | daddr port portstuff { nat->in_odport = $3.p1;
910 nat->in_dtop = $3.p2;
911 nat->in_dcmp = $3.pc;
916 daddr: addr { nat->in_odstatype = $1.t;
918 &nat->in_odst.na_addr[0],
921 &nat->in_odst.na_addr[1],
927 addr: IPNY_ANY { yyexpectaddr = 0;
928 bzero(&$$, sizeof($$));
931 | hostname { bzero(&$$, sizeof($$));
936 if ($$.f == AF_INET) {
937 $$.m.in4.s_addr = 0xffffffff;
938 } else if ($$.f == AF_INET6) {
939 $$.m.i6[0] = 0xffffffff;
940 $$.m.i6[1] = 0xffffffff;
941 $$.m.i6[2] = 0xffffffff;
942 $$.m.i6[3] = 0xffffffff;
946 | hostname slash YY_NUMBER
947 { bzero(&$$, sizeof($$));
952 ntomask($$.f, $3, (u_32_t *)&$$.m);
953 $$.a.i6[0] &= $$.m.i6[0];
954 $$.a.i6[1] &= $$.m.i6[1];
955 $$.a.i6[2] &= $$.m.i6[2];
956 $$.a.i6[3] &= $$.m.i6[3];
959 | hostname slash ipaddr { bzero(&$$, sizeof($$));
961 yyerror("1.address family "
967 $$.a.i6[0] &= $$.m.i6[0];
968 $$.a.i6[1] &= $$.m.i6[1];
969 $$.a.i6[2] &= $$.m.i6[2];
970 $$.a.i6[3] &= $$.m.i6[3];
975 | hostname slash hexnumber { bzero(&$$, sizeof($$));
977 $$.m.in4.s_addr = htonl($3);
979 $$.a.in4.s_addr &= $$.m.in4.s_addr;
982 if ($$.f == AF_INET6)
983 yyerror("incorrect inet6 mask");
985 | hostname mask ipaddr { bzero(&$$, sizeof($$));
987 yyerror("2.address family "
993 $$.a.i6[0] &= $$.m.i6[0];
994 $$.a.i6[1] &= $$.m.i6[1];
995 $$.a.i6[2] &= $$.m.i6[2];
996 $$.a.i6[3] &= $$.m.i6[3];
1001 | hostname mask hexnumber { bzero(&$$, sizeof($$));
1003 $$.m.in4.s_addr = htonl($3);
1005 $$.a.in4.s_addr &= $$.m.in4.s_addr;
1009 | pool slash YY_NUMBER { bzero(&$$, sizeof($$));
1010 $$.a.iplookupnum = $3;
1011 $$.a.iplookuptype = IPLT_POOL;
1012 $$.a.iplookupsubtype = 0;
1015 | pool slash YY_STR { bzero(&$$, sizeof($$));
1016 $$.a.iplookupname = addname(&nat,$3);
1017 $$.a.iplookuptype = IPLT_POOL;
1018 $$.a.iplookupsubtype = 1;
1021 | hash slash YY_NUMBER { bzero(&$$, sizeof($$));
1022 $$.a.iplookupnum = $3;
1023 $$.a.iplookuptype = IPLT_HASH;
1024 $$.a.iplookupsubtype = 0;
1027 | hash slash YY_STR { bzero(&$$, sizeof($$));
1028 $$.a.iplookupname = addname(&nat,$3);
1029 $$.a.iplookuptype = IPLT_HASH;
1030 $$.a.iplookupsubtype = 1;
1035 slash: '/' { yyexpectaddr = 0; }
1038 mask: IPNY_MASK { yyexpectaddr = 0; }
1041 pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) {
1042 yyerror("Can only use pool with from/to rules\n");
1049 hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) {
1050 yyerror("Can only use hash with from/to rules\n");
1058 compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
1059 | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1063 rr frag age mssclamp nattag setproto purge
1067 rr frag age sticky mssclamp rdrproxy nattag purge
1070 nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2,
1071 sizeof(nat->in_tag.ipt_tag));
1073 rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; }
1076 frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; }
1079 age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2;
1080 nat->in_age[1] = $2; }
1081 | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2;
1082 nat->in_age[1] = $4; }
1085 sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) &&
1086 !(nat->in_flags & IPN_SPLIT)) {
1088 "'sticky' for use with round-robin/IP splitting only\n");
1090 nat->in_flags |= IPN_STICKY;
1095 | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; }
1098 tcpudp: IPNY_TCP { setnatproto(IPPROTO_TCP); }
1099 | IPNY_UDP { setnatproto(IPPROTO_UDP); }
1100 | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP;
1104 | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
1111 | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; }
1115 | IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
1121 pos = addname(&nat, $2);
1122 nat->in_plabel = pos;
1123 nat->in_odport = nat->in_dpnext;
1124 nat->in_dtop = nat->in_odport;
1127 | proxy { if (nat->in_plabel != -1) {
1128 nat->in_ndport = nat->in_odport;
1129 nat->in_dpmin = nat->in_odport;
1130 nat->in_dpmax = nat->in_dpmin;
1131 nat->in_dtop = nat->in_dpmin;
1132 nat->in_dpnext = nat->in_dpmin;
1138 | IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
1141 proto: YY_NUMBER { $$ = $1;
1142 if ($$ != IPPROTO_TCP &&
1146 | IPNY_TCP { $$ = IPPROTO_TCP; }
1147 | IPNY_UDP { $$ = IPPROTO_UDP; }
1148 | YY_STR { $$ = getproto($1);
1151 yyerror("unknown protocol");
1152 if ($$ != IPPROTO_TCP &&
1163 YY_STR { i6addr_t addr;
1167 if (nat->in_v[0] == 6)
1172 memset(&($$), 0, sizeof($$));
1173 memset(&addr, 0, sizeof(addr));
1175 if (gethost(family, $1,
1180 "Unknown host '%s'\n",
1185 | YY_NUMBER { memset(&($$), 0, sizeof($$));
1186 $$.a.in4.s_addr = htonl($1);
1187 if ($$.a.in4.s_addr != 0)
1191 | YY_IPV6 { memset(&($$), 0, sizeof($$));
1195 | YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$));
1202 '=' { $$ = FR_EQUAL; }
1203 | YY_CMP_EQ { $$ = FR_EQUAL; }
1204 | YY_CMP_NE { $$ = FR_NEQUAL; }
1205 | YY_CMP_LT { $$ = FR_LESST; }
1206 | YY_CMP_LE { $$ = FR_LESSTE; }
1207 | YY_CMP_GT { $$ = FR_GREATERT; }
1208 | YY_CMP_GE { $$ = FR_GREATERTE; }
1211 YY_RANGE_OUT { $$ = FR_OUTRANGE; }
1212 | YY_RANGE_IN { $$ = FR_INRANGE; }
1213 | ':' { $$ = FR_INCRANGE; }
1216 ipaddr: ipv4 { $$ = $1; }
1217 | YY_IPV6 { $$.a = $1;
1222 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1223 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1224 yyerror("Invalid octet string for IP address");
1227 bzero((char *)&$$, sizeof($$));
1228 $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1229 $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1237 static wordtab_t proxies[] = {
1241 static wordtab_t dnswords[] = {
1242 { "allow", IPNY_ALLOW },
1243 { "block", IPNY_DENY },
1244 { "deny", IPNY_DENY },
1245 { "drop", IPNY_DENY },
1246 { "pass", IPNY_ALLOW },
1250 static wordtab_t yywords[] = {
1251 { "age", IPNY_AGE },
1252 { "any", IPNY_ANY },
1253 { "auto", IPNY_AUTO },
1254 { "bimap", IPNY_BIMAP },
1255 { "config", IPNY_CONFIG },
1256 { "divert", IPNY_DIVERT },
1257 { "dst", IPNY_DST },
1258 { "dstlist", IPNY_DSTLIST },
1259 { "frag", IPNY_FRAG },
1260 { "from", IPNY_FROM },
1261 { "hash", IPNY_HASH },
1262 { "icmpidmap", IPNY_ICMPIDMAP },
1264 { "inet", IPNY_INET },
1265 { "inet6", IPNY_INET6 },
1266 { "mask", IPNY_MASK },
1267 { "map", IPNY_MAP },
1268 { "map-block", IPNY_MAPBLOCK },
1269 { "mssclamp", IPNY_MSSCLAMP },
1270 { "netmask", IPNY_MASK },
1273 { "out", IPNY_OUT },
1274 { "pool", IPNY_POOL },
1275 { "port", IPNY_PORT },
1276 { "portmap", IPNY_PORTMAP },
1277 { "ports", IPNY_PORTS },
1278 { "proto", IPNY_PROTO },
1279 { "proxy", IPNY_PROXY },
1280 { "purge", IPNY_PURGE },
1281 { "range", IPNY_RANGE },
1282 { "rewrite", IPNY_REWRITE },
1283 { "rdr", IPNY_RDR },
1284 { "round-robin",IPNY_ROUNDROBIN },
1285 { "sequential", IPNY_SEQUENTIAL },
1286 { "src", IPNY_SRC },
1287 { "sticky", IPNY_STICKY },
1288 { "tag", IPNY_TAG },
1289 { "tcp", IPNY_TCP },
1290 { "tcpudp", IPNY_TCPUDP },
1292 { "udp", IPNY_UDP },
1294 { "->", IPNY_TLATE },
1295 { "eq", YY_CMP_EQ },
1296 { "ne", YY_CMP_NE },
1297 { "lt", YY_CMP_LT },
1298 { "gt", YY_CMP_GT },
1299 { "le", YY_CMP_LE },
1300 { "ge", YY_CMP_GE },
1306 ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1309 ioctlfunc_t ioctlfunc;
1318 (void) yysettab(yywords);
1320 s = getenv("YYDEBUG");
1326 if (strcmp(filename, "-")) {
1327 fp = fopen(filename, "r");
1329 FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1336 while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1349 ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1352 ioctlfunc_t ioctlfunc;
1360 nataddfunc = addfunc;
1361 natioctlfunc = ioctlfunc;
1368 if (ungetc(i, fp) == EOF)
1372 s = getenv("YYDEBUG");
1380 return parser_error;
1389 n = calloc(1, sizeof(*n));
1395 n->in_pnext = &nattop;
1398 n->in_pnext = &nat->in_next;
1402 n->in_flineno = yylineNum;
1403 n->in_ifnames[0] = -1;
1404 n->in_ifnames[1] = -1;
1407 n->in_size = sizeof(*n);
1423 nat->in_flags |= IPN_TCP;
1424 nat->in_flags &= ~IPN_UDP;
1427 nat->in_flags |= IPN_UDP;
1428 nat->in_flags &= ~IPN_TCP;
1431 case IPPROTO_ICMPV6 :
1434 nat->in_flags &= ~IPN_TCPUDP;
1435 if (!(nat->in_flags & IPN_ICMPQUERY) &&
1436 !(nat->in_redir & NAT_DIVERTUDP)) {
1448 if ((nat->in_redir & NAT_MAPBLK) == 0) {
1449 nat->in_flags &= ~IPN_TCPUDP;
1462 if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1472 if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1473 nat->in_flags &= ~IPN_FIXEDDPORT;
1478 ipnat_addrule(fd, ioctlfunc, ptr)
1480 ioctlfunc_t ioctlfunc;
1483 ioctlcmd_t add, del;
1488 bzero((char *)&obj, sizeof(obj));
1489 obj.ipfo_rev = IPFILTER_VERSION;
1490 obj.ipfo_size = ipn->in_size;
1491 obj.ipfo_type = IPFOBJ_IPNAT;
1494 if ((opts & OPT_DONOTHING) != 0)
1497 if (opts & OPT_ZERORULEST) {
1500 } else if (opts & OPT_PURGE) {
1508 if ((opts & OPT_VERBOSE) != 0)
1509 printnat(ipn, opts);
1511 if (opts & OPT_DEBUG)
1512 binprint(ipn, ipn->in_size);
1514 if ((opts & OPT_ZERORULEST) != 0) {
1515 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1516 if ((opts & OPT_DONOTHING) == 0) {
1519 sprintf(msg, "%d:ioctl(zero nat rule)",
1521 return ipf_perror_fd(fd, ioctlfunc, msg);
1524 PRINTF("hits %lu ", ipn->in_hits);
1526 PRINTF("bytes %"PRIu64" ",
1527 ipn->in_bytes[0] + ipn->in_bytes[1]);
1529 PRINTF("bytes %lu ",
1530 ipn->in_bytes[0] + ipn->in_bytes[1]);
1532 printnat(ipn, opts);
1534 } else if ((opts & OPT_REMOVE) != 0) {
1535 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1536 if ((opts & OPT_DONOTHING) == 0) {
1539 sprintf(msg, "%d:ioctl(delete nat rule)",
1541 return ipf_perror_fd(fd, ioctlfunc, msg);
1545 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1546 if ((opts & OPT_DONOTHING) == 0) {
1549 sprintf(msg, "%d:ioctl(add/insert nat rule)",
1551 if (errno == EEXIST) {
1552 sprintf(msg + strlen(msg), "(line %d)",
1555 return ipf_perror_fd(fd, ioctlfunc, msg);
1566 if (nat->in_ifnames[1] == -1)
1567 nat->in_ifnames[1] = nat->in_ifnames[0];
1569 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1570 nat->in_flags |= IPN_TCPUDP;
1572 if ((nat->in_flags & IPN_TCPUDP) == 0)
1573 setnatproto(nat->in_pr[1]);
1575 if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1576 ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1577 nat_setgroupmap(nat);
1584 if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1585 nat->in_flags |= IPN_TCPUDP;
1587 if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1588 (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1589 setnatproto(IPPROTO_TCP);
1591 if (nat->in_ifnames[1] == -1)
1592 nat->in_ifnames[1] = nat->in_ifnames[0];
1597 proxy_setconfig(proxy)
1600 if (proxy == IPNY_DNS) {
1601 yysetfixeddict(dnswords);
1614 proxy_dns_add_pass(prefix, name)
1615 char *prefix, *name;
1619 n = calloc(1, sizeof(*n));
1621 if (prefix == NULL || *prefix == '\0') {
1622 n->na_name = strdup(name);
1624 n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1625 strcpy(n->na_name, prefix);
1626 strcat(n->na_name, name);
1634 proxy_dns_add_block(prefix, name)
1635 char *prefix, *name;
1639 n = calloc(1, sizeof(*n));
1641 if (prefix == NULL || *prefix == '\0') {
1642 n->na_name = strdup(name);
1644 n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1645 strcpy(n->na_name, prefix);
1646 strcat(n->na_name, name);
1655 proxy_addconfig(proxy, proto, conf, list)
1662 pr = calloc(1, sizeof(*pr));
1664 pr->pr_proto = proto;
1665 pr->pr_proxy = proxy;
1667 pr->pr_names = list;
1668 pr->pr_next = prules;
1675 proxy_loadrules(fd, ioctlfunc, rules)
1677 ioctlfunc_t ioctlfunc;
1682 while ((pr = rules) != NULL) {
1683 proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1684 pr->pr_conf, pr->pr_names);
1685 rules = pr->pr_next;
1693 proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1695 ioctlfunc_t ioctlfunc;
1704 obj.ipfo_rev = IPFILTER_VERSION;
1705 obj.ipfo_type = IPFOBJ_PROXYCTL;
1706 obj.ipfo_size = sizeof(pcmd);
1707 obj.ipfo_ptr = &pcmd;
1709 while ((na = list) != NULL) {
1710 if ((opts & OPT_REMOVE) != 0)
1711 pcmd.apc_cmd = APC_CMD_DEL;
1713 pcmd.apc_cmd = APC_CMD_ADD;
1714 pcmd.apc_dsize = strlen(na->na_name) + 1;
1715 pcmd.apc_data = na->na_name;
1716 pcmd.apc_arg = na->na_value;
1719 strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1720 pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1722 strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1723 pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1725 if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1726 if ((opts & OPT_DONOTHING) == 0) {
1729 sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1731 ipf_perror_fd(fd, ioctlfunc, msg);
1744 setifname(np, idx, name)
1751 pos = addname(np, name);
1754 (*np)->in_ifnames[idx] = pos;
1767 nlen = strlen(name) + 1;
1768 n = realloc(*np, (*np)->in_size + nlen);
1774 if (n->in_pnext != NULL)
1777 pos = n->in_namelen;
1778 n->in_namelen += nlen;
1779 strcpy(n->in_names + pos, name);
1780 n->in_names[n->in_namelen] = '\0';