summaryrefslogtreecommitdiffstats
path: root/tools/ipnat_y.y
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ipnat_y.y')
-rw-r--r--tools/ipnat_y.y871
1 files changed, 871 insertions, 0 deletions
diff --git a/tools/ipnat_y.y b/tools/ipnat_y.y
new file mode 100644
index 0000000..6208c98
--- /dev/null
+++ b/tools/ipnat_y.y
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2001-2006 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#ifdef __FreeBSD__
+# ifndef __FreeBSD_cc_version
+# include <osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <osreldate.h>
+# endif
+# endif
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <net/if.h>
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+#endif
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "ipnat_l.h"
+
+#define YYDEBUG 1
+
+extern void yyerror __P((char *));
+extern int yyparse __P((void));
+extern int yylex __P((void));
+extern int yydebug;
+extern FILE *yyin;
+extern int yylineNum;
+
+static ipnat_t *nattop = NULL;
+static ipnat_t *nat = NULL;
+static int natfd = -1;
+static ioctlfunc_t natioctlfunc = NULL;
+static addfunc_t nataddfunc = NULL;
+static int suggest_port = 0;
+
+static void newnatrule __P((void));
+static void setnatproto __P((int));
+
+%}
+%union {
+ char *str;
+ u_32_t num;
+ struct in_addr ipa;
+ frentry_t fr;
+ frtuc_t *frt;
+ u_short port;
+ struct {
+ u_short p1;
+ u_short p2;
+ int pc;
+ } pc;
+ struct {
+ struct in_addr a;
+ struct in_addr m;
+ } ipp;
+ union i6addr ip6;
+};
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+%token <ip6> YY_IPV6
+
+%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
+%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
+%token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
+%token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
+%token IPNY_TLATE
+%type <port> portspec
+%type <num> hexnumber compare range proto
+%type <ipa> hostname ipv4
+%type <ipp> addr nummask rhaddr
+%type <pc> portstuff
+%%
+file: line
+ | assign
+ | file line
+ | file assign
+ ;
+
+line: xx rule { while ((nat = nattop) != NULL) {
+ nattop = nat->in_next;
+ (*nataddfunc)(natfd, natioctlfunc, nat);
+ free(nat);
+ }
+ resetlexer();
+ }
+ | YY_COMMENT
+ ;
+
+assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+xx: { newnatrule(); }
+ ;
+
+rule: map eol
+ | mapblock eol
+ | redir eol
+ ;
+
+eol: | ';'
+ ;
+
+map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
+ { nat->in_v = 4;
+ nat->in_inip = $3.a.s_addr;
+ nat->in_inmsk = $3.m.s_addr;
+ nat->in_outip = $5.a.s_addr;
+ nat->in_outmsk = $5.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ if ((nat->in_flags & IPN_TCPUDP) == 0)
+ setnatproto(nat->in_p);
+ if (((nat->in_redir & NAT_MAPBLK) != 0) ||
+ ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
+ nat_setgroupmap(nat);
+ }
+ | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
+ { nat->in_v = 4;
+ nat->in_inip = $3.a.s_addr;
+ nat->in_inmsk = $3.m.s_addr;
+ nat->in_outip = $5.a.s_addr;
+ nat->in_outmsk = $5.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ if (((nat->in_redir & NAT_MAPBLK) != 0) ||
+ ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
+ nat_setgroupmap(nat);
+ }
+ | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
+ { nat->in_v = 4;
+ nat->in_outip = $5.a.s_addr;
+ nat->in_outmsk = $5.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ if ((suggest_port == 1) &&
+ (nat->in_flags & IPN_TCPUDP) == 0)
+ nat->in_flags |= IPN_TCPUDP;
+ if ((nat->in_flags & IPN_TCPUDP) == 0)
+ setnatproto(nat->in_p);
+ if (((nat->in_redir & NAT_MAPBLK) != 0) ||
+ ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
+ nat_setgroupmap(nat);
+ }
+ | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
+ { nat->in_v = 4;
+ nat->in_outip = $5.a.s_addr;
+ nat->in_outmsk = $5.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ if ((suggest_port == 1) &&
+ (nat->in_flags & IPN_TCPUDP) == 0)
+ nat->in_flags |= IPN_TCPUDP;
+ if (((nat->in_redir & NAT_MAPBLK) != 0) ||
+ ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
+ nat_setgroupmap(nat);
+ }
+ ;
+
+mapblock:
+ mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
+ { nat->in_v = 4;
+ nat->in_inip = $3.a.s_addr;
+ nat->in_inmsk = $3.m.s_addr;
+ nat->in_outip = $5.a.s_addr;
+ nat->in_outmsk = $5.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ if ((nat->in_flags & IPN_TCPUDP) == 0)
+ setnatproto(nat->in_p);
+ if (((nat->in_redir & NAT_MAPBLK) != 0) ||
+ ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
+ nat_setgroupmap(nat);
+ }
+ ;
+
+redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
+ { nat->in_v = 4;
+ nat->in_outip = $3.a.s_addr;
+ nat->in_outmsk = $3.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ if ((nat->in_p == 0) &&
+ ((nat->in_flags & IPN_TCPUDP) == 0) &&
+ (nat->in_pmin != 0 ||
+ nat->in_pmax != 0 ||
+ nat->in_pnext != 0))
+ setnatproto(IPPROTO_TCP);
+ }
+ | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
+ { nat->in_v = 4;
+ if ((nat->in_p == 0) &&
+ ((nat->in_flags & IPN_TCPUDP) == 0) &&
+ (nat->in_pmin != 0 ||
+ nat->in_pmax != 0 ||
+ nat->in_pnext != 0))
+ setnatproto(IPPROTO_TCP);
+ if ((suggest_port == 1) &&
+ (nat->in_flags & IPN_TCPUDP) == 0)
+ nat->in_flags |= IPN_TCPUDP;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ }
+ | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
+ { nat->in_v = 4;
+ nat->in_outip = $3.a.s_addr;
+ nat->in_outmsk = $3.m.s_addr;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ }
+ | rdrit ifnames rdrfrom IPNY_TLATE dip setproto rdroptions
+ { nat->in_v = 4;
+ if ((suggest_port == 1) &&
+ (nat->in_flags & IPN_TCPUDP) == 0)
+ nat->in_flags |= IPN_TCPUDP;
+ if (nat->in_ifnames[1][0] == '\0')
+ strncpy(nat->in_ifnames[1],
+ nat->in_ifnames[0],
+ sizeof(nat->in_ifnames[0]));
+ }
+ ;
+
+proxy: | IPNY_PROXY port portspec YY_STR '/' proto
+ { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
+ if (nat->in_dcmp == 0) {
+ nat->in_dport = htons($3);
+ } else if ($3 != nat->in_dport) {
+ yyerror("proxy port numbers not consistant");
+ }
+ setnatproto($6);
+ free($4);
+ }
+ | IPNY_PROXY port YY_STR YY_STR '/' proto
+ { int pnum;
+ strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
+ pnum = getportproto($3, $6);
+ if (pnum == -1)
+ yyerror("invalid port number");
+ nat->in_dport = pnum;
+ setnatproto($6);
+ free($3);
+ free($4);
+ }
+ ;
+
+setproto:
+ | proto { if (nat->in_p != 0 ||
+ nat->in_flags & IPN_TCPUDP)
+ yyerror("protocol set twice");
+ setnatproto($1);
+ }
+ | IPNY_TCPUDP { if (nat->in_p != 0 ||
+ nat->in_flags & IPN_TCPUDP)
+ yyerror("protocol set twice");
+ nat->in_flags |= IPN_TCPUDP;
+ nat->in_p = 0;
+ }
+ | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 ||
+ nat->in_flags & IPN_TCPUDP)
+ yyerror("protocol set twice");
+ nat->in_flags |= IPN_TCPUDP;
+ nat->in_p = 0;
+ }
+ ;
+
+rhaddr: addr { $$.a = $1.a; $$.m = $1.m; }
+ | IPNY_RANGE ipv4 '-' ipv4
+ { $$.a = $2; $$.m = $4;
+ nat->in_flags |= IPN_IPRANGE; }
+ ;
+
+dip:
+ hostname { nat->in_inip = $1.s_addr;
+ nat->in_inmsk = 0xffffffff; }
+ | hostname '/' YY_NUMBER { if ($3 != 0 || $1.s_addr != 0)
+ yyerror("Only 0/0 supported");
+ nat->in_inip = 0;
+ nat->in_inmsk = 0;
+ }
+ | hostname ',' hostname { nat->in_flags |= IPN_SPLIT;
+ nat->in_inip = $1.s_addr;
+ nat->in_inmsk = $3.s_addr; }
+ ;
+
+port: IPNY_PORT { suggest_port = 1; }
+ ;
+
+portspec:
+ YY_NUMBER { if ($1 > 65535) /* Unsigned */
+ yyerror("invalid port number");
+ else
+ $$ = $1;
+ }
+ | YY_STR { if (getport(NULL, $1, &($$)) == -1)
+ yyerror("invalid port number");
+ $$ = ntohs($$);
+ }
+ ;
+
+dport: | port portspec { nat->in_pmin = htons($2);
+ nat->in_pmax = htons($2); }
+ | port portspec '-' portspec { nat->in_pmin = htons($2);
+ nat->in_pmax = htons($4); }
+ | port portspec ':' portspec { nat->in_pmin = htons($2);
+ nat->in_pmax = htons($4); }
+ ;
+
+nport: port portspec { nat->in_pnext = htons($2); }
+ | port '=' portspec { nat->in_pnext = htons($3);
+ nat->in_flags |= IPN_FIXEDDPORT;
+ }
+ ;
+
+ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $2; }
+ | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; }
+ ;
+
+mapit: IPNY_MAP { nat->in_redir = NAT_MAP; }
+ | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; }
+ ;
+
+rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; }
+ ;
+
+mapblockit:
+ IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; }
+ ;
+
+mapfrom:
+ from sobject IPNY_TO dobject
+ | from sobject '!' IPNY_TO dobject
+ { nat->in_flags |= IPN_NOTDST; }
+ | from sobject IPNY_TO '!' dobject
+ { nat->in_flags |= IPN_NOTDST; }
+ ;
+
+rdrfrom:
+ from sobject IPNY_TO dobject
+ | '!' from sobject IPNY_TO dobject
+ { nat->in_flags |= IPN_NOTSRC; }
+ | from '!' sobject IPNY_TO dobject
+ { nat->in_flags |= IPN_NOTSRC; }
+ ;
+
+from: IPNY_FROM { nat->in_flags |= IPN_FILTER; }
+ ;
+
+ifnames:
+ ifname
+ | ifname ',' otherifname
+ ;
+
+ifname: YY_STR { strncpy(nat->in_ifnames[0], $1,
+ sizeof(nat->in_ifnames[0]));
+ nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ free($1);
+ }
+ ;
+
+otherifname:
+ YY_STR { strncpy(nat->in_ifnames[1], $1,
+ sizeof(nat->in_ifnames[1]));
+ nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ free($1);
+ }
+ ;
+
+mapport:
+ IPNY_PORTMAP tcpudp portspec ':' portspec
+ { nat->in_pmin = htons($3);
+ nat->in_pmax = htons($5);
+ }
+ | IPNY_PORTMAP tcpudp IPNY_AUTO
+ { nat->in_flags |= IPN_AUTOPORTMAP;
+ nat->in_pmin = htons(1024);
+ nat->in_pmax = htons(65535);
+ }
+ | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
+ { if (strcmp($2, "icmp") != 0) {
+ yyerror("icmpidmap not followed by icmp");
+ }
+ free($2);
+ if ($3 < 0 || $3 > 65535)
+ yyerror("invalid ICMP Id number");
+ if ($5 < 0 || $5 > 65535)
+ yyerror("invalid ICMP Id number");
+ nat->in_flags = IPN_ICMPQUERY;
+ nat->in_pmin = htons($3);
+ nat->in_pmax = htons($5);
+ }
+ ;
+
+sobject:
+ saddr
+ | saddr port portstuff { nat->in_sport = $3.p1;
+ nat->in_stop = $3.p2;
+ nat->in_scmp = $3.pc; }
+ ;
+
+saddr: addr { if (nat->in_redir == NAT_REDIRECT) {
+ nat->in_srcip = $1.a.s_addr;
+ nat->in_srcmsk = $1.m.s_addr;
+ } else {
+ nat->in_inip = $1.a.s_addr;
+ nat->in_inmsk = $1.m.s_addr;
+ }
+ }
+ ;
+
+dobject:
+ daddr
+ | daddr port portstuff { nat->in_dport = $3.p1;
+ nat->in_dtop = $3.p2;
+ nat->in_dcmp = $3.pc;
+ if (nat->in_redir == NAT_REDIRECT)
+ nat->in_pmin = htons($3.p1);
+ }
+ ;
+
+daddr: addr { if (nat->in_redir == NAT_REDIRECT) {
+ nat->in_outip = $1.a.s_addr;
+ nat->in_outmsk = $1.m.s_addr;
+ } else {
+ nat->in_srcip = $1.a.s_addr;
+ nat->in_srcmsk = $1.m.s_addr;
+ }
+ }
+ ;
+
+addr: IPNY_ANY { $$.a.s_addr = 0; $$.m.s_addr = 0; }
+ | nummask { $$.a = $1.a; $$.m = $1.m;
+ $$.a.s_addr &= $$.m.s_addr; }
+ | hostname '/' ipv4 { $$.a = $1; $$.m = $3;
+ $$.a.s_addr &= $$.m.s_addr; }
+ | hostname '/' hexnumber { $$.a = $1; $$.m.s_addr = htonl($3);
+ $$.a.s_addr &= $$.m.s_addr; }
+ | hostname IPNY_MASK ipv4 { $$.a = $1; $$.m = $3;
+ $$.a.s_addr &= $$.m.s_addr; }
+ | hostname IPNY_MASK hexnumber { $$.a = $1; $$.m.s_addr = htonl($3);
+ $$.a.s_addr &= $$.m.s_addr; }
+ ;
+
+nummask:
+ hostname { $$.a = $1;
+ $$.m.s_addr = 0xffffffff; }
+ | hostname '/' YY_NUMBER { $$.a = $1;
+ ntomask(4, $3, &$$.m.s_addr); }
+ ;
+
+portstuff:
+ compare portspec { $$.pc = $1; $$.p1 = $2; }
+ | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
+ ;
+
+mapoptions:
+ rr frag age mssclamp nattag setproto
+ ;
+
+rdroptions:
+ rr frag age sticky mssclamp rdrproxy nattag
+ ;
+
+nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2,
+ sizeof(nat->in_tag.ipt_tag));
+ }
+rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; }
+ ;
+
+frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; }
+ ;
+
+age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2;
+ nat->in_age[1] = $2; }
+ | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2;
+ nat->in_age[1] = $4; }
+ ;
+
+sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) &&
+ !(nat->in_flags & IPN_SPLIT)) {
+ fprintf(stderr,
+ "'sticky' for use with round-robin/IP splitting only\n");
+ } else
+ nat->in_flags |= IPN_STICKY;
+ }
+ ;
+
+mssclamp:
+ | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; }
+ ;
+
+tcpudp: | IPNY_TCP { setnatproto(IPPROTO_TCP); }
+ | IPNY_UDP { setnatproto(IPPROTO_UDP); }
+ | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP;
+ nat->in_p = 0;
+ }
+ | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
+ nat->in_p = 0;
+ }
+ ;
+
+rdrproxy:
+ IPNY_PROXY YY_STR
+ { strncpy(nat->in_plabel, $2,
+ sizeof(nat->in_plabel));
+ nat->in_dport = nat->in_pnext;
+ nat->in_dport = htons(nat->in_dport);
+ free($2);
+ }
+ | proxy { if (nat->in_plabel[0] != '\0') {
+ nat->in_pmin = nat->in_dport;
+ nat->in_pmax = nat->in_pmin;
+ nat->in_pnext = nat->in_pmin;
+ }
+ }
+ ;
+
+proto: YY_NUMBER { $$ = $1;
+ if ($$ != IPPROTO_TCP &&
+ $$ != IPPROTO_UDP)
+ suggest_port = 0;
+ }
+ | IPNY_TCP { $$ = IPPROTO_TCP; }
+ | IPNY_UDP { $$ = IPPROTO_UDP; }
+ | YY_STR { $$ = getproto($1); free($1);
+ if ($$ != IPPROTO_TCP &&
+ $$ != IPPROTO_UDP)
+ suggest_port = 0;
+ }
+ ;
+
+hexnumber:
+ YY_HEX { $$ = $1; }
+ ;
+
+hostname:
+ YY_STR { if (gethost($1, &$$.s_addr) == -1)
+ fprintf(stderr,
+ "Unknown host '%s'\n",
+ $1);
+ free($1);
+ }
+ | YY_NUMBER { $$.s_addr = htonl($1); }
+ | ipv4 { $$.s_addr = $1.s_addr; }
+ ;
+
+compare:
+ '=' { $$ = FR_EQUAL; }
+ | YY_CMP_EQ { $$ = FR_EQUAL; }
+ | YY_CMP_NE { $$ = FR_NEQUAL; }
+ | YY_CMP_LT { $$ = FR_LESST; }
+ | YY_CMP_LE { $$ = FR_LESSTE; }
+ | YY_CMP_GT { $$ = FR_GREATERT; }
+ | YY_CMP_GE { $$ = FR_GREATERTE; }
+
+range:
+ YY_RANGE_OUT { $$ = FR_OUTRANGE; }
+ | YY_RANGE_IN { $$ = FR_INRANGE; }
+ | ':' { $$ = FR_INCRANGE; }
+ ;
+
+ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
+ { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
+ $$.s_addr = htonl($$.s_addr);
+ }
+ ;
+
+%%
+
+
+static wordtab_t yywords[] = {
+ { "age", IPNY_AGE },
+ { "any", IPNY_ANY },
+ { "auto", IPNY_AUTO },
+ { "bimap", IPNY_BIMAP },
+ { "frag", IPNY_FRAG },
+ { "from", IPNY_FROM },
+ { "icmpidmap", IPNY_ICMPIDMAP },
+ { "mask", IPNY_MASK },
+ { "map", IPNY_MAP },
+ { "map-block", IPNY_MAPBLOCK },
+ { "mssclamp", IPNY_MSSCLAMP },
+ { "netmask", IPNY_MASK },
+ { "port", IPNY_PORT },
+ { "portmap", IPNY_PORTMAP },
+ { "ports", IPNY_PORTS },
+ { "proxy", IPNY_PROXY },
+ { "range", IPNY_RANGE },
+ { "rdr", IPNY_RDR },
+ { "round-robin",IPNY_ROUNDROBIN },
+ { "sticky", IPNY_STICKY },
+ { "tag", IPNY_TAG },
+ { "tcp", IPNY_TCP },
+ { "tcpudp", IPNY_TCPUDP },
+ { "to", IPNY_TO },
+ { "udp", IPNY_UDP },
+ { "-", '-' },
+ { "->", IPNY_TLATE },
+ { "eq", YY_CMP_EQ },
+ { "ne", YY_CMP_NE },
+ { "lt", YY_CMP_LT },
+ { "gt", YY_CMP_GT },
+ { "le", YY_CMP_LE },
+ { "ge", YY_CMP_GE },
+ { NULL, 0 }
+};
+
+
+int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
+int fd;
+addfunc_t addfunc;
+ioctlfunc_t ioctlfunc;
+char *filename;
+{
+ FILE *fp = NULL;
+ char *s;
+
+ (void) yysettab(yywords);
+
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ if (strcmp(filename, "-")) {
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "fopen(%s) failed: %s\n", filename,
+ STRERROR(errno));
+ return -1;
+ }
+ } else
+ fp = stdin;
+
+ while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
+ ;
+ if (fp != NULL)
+ fclose(fp);
+ return 0;
+}
+
+
+int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
+int fd;
+addfunc_t addfunc;
+ioctlfunc_t ioctlfunc;
+FILE *fp;
+{
+ char *s;
+ int i;
+
+ yylineNum = 1;
+
+ natfd = fd;
+ nataddfunc = addfunc;
+ natioctlfunc = ioctlfunc;
+
+ if (feof(fp))
+ return 0;
+ i = fgetc(fp);
+ if (i == EOF)
+ return 0;
+ if (ungetc(i, fp) == EOF)
+ return 0;
+ if (feof(fp))
+ return 0;
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ yyin = fp;
+ yyparse();
+ return 1;
+}
+
+
+static void newnatrule()
+{
+ ipnat_t *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL)
+ return;
+
+ if (nat == NULL)
+ nattop = nat = n;
+ else {
+ nat->in_next = n;
+ nat = n;
+ }
+
+ suggest_port = 0;
+}
+
+
+static void setnatproto(p)
+int p;
+{
+ nat->in_p = p;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ nat->in_flags |= IPN_TCP;
+ nat->in_flags &= ~IPN_UDP;
+ break;
+ case IPPROTO_UDP :
+ nat->in_flags |= IPN_UDP;
+ nat->in_flags &= ~IPN_TCP;
+ break;
+ case IPPROTO_ICMP :
+ nat->in_flags &= ~IPN_TCPUDP;
+ if (!(nat->in_flags & IPN_ICMPQUERY)) {
+ nat->in_dcmp = 0;
+ nat->in_scmp = 0;
+ nat->in_pmin = 0;
+ nat->in_pmax = 0;
+ nat->in_pnext = 0;
+ }
+ break;
+ default :
+ if ((nat->in_redir & NAT_MAPBLK) == 0) {
+ nat->in_flags &= ~IPN_TCPUDP;
+ nat->in_dcmp = 0;
+ nat->in_scmp = 0;
+ nat->in_pmin = 0;
+ nat->in_pmax = 0;
+ nat->in_pnext = 0;
+ }
+ break;
+ }
+
+ if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
+ nat->in_flags &= ~IPN_FIXEDDPORT;
+}
+
+
+void ipnat_addrule(fd, ioctlfunc, ptr)
+int fd;
+ioctlfunc_t ioctlfunc;
+void *ptr;
+{
+ ioctlcmd_t add, del;
+ ipfobj_t obj;
+ ipnat_t *ipn;
+
+ ipn = ptr;
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(ipnat_t);
+ obj.ipfo_type = IPFOBJ_IPNAT;
+ obj.ipfo_ptr = ptr;
+ add = 0;
+ del = 0;
+
+ if ((opts & OPT_DONOTHING) != 0)
+ fd = -1;
+
+ if (opts & OPT_ZERORULEST) {
+ add = SIOCZRLST;
+ } else if (opts & OPT_INACTIVE) {
+ add = SIOCADNAT;
+ del = SIOCRMNAT;
+ } else {
+ add = SIOCADNAT;
+ del = SIOCRMNAT;
+ }
+
+ if ((opts & OPT_VERBOSE) != 0)
+ printnat(ipn, opts);
+
+ if (opts & OPT_DEBUG)
+ binprint(ipn, sizeof(*ipn));
+
+ if ((opts & OPT_ZERORULEST) != 0) {
+ if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ fprintf(stderr, "%d:", yylineNum);
+ perror("ioctl(SIOCZRLST)");
+ }
+ } else {
+#ifdef USE_QUAD_T
+/*
+ printf("hits %qd bytes %qd ",
+ (long long)fr->fr_hits,
+ (long long)fr->fr_bytes);
+*/
+#else
+/*
+ printf("hits %ld bytes %ld ",
+ fr->fr_hits, fr->fr_bytes);
+*/
+#endif
+ printnat(ipn, opts);
+ }
+ } else if ((opts & OPT_REMOVE) != 0) {
+ if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ fprintf(stderr, "%d:", yylineNum);
+ perror("ioctl(delete nat rule)");
+ }
+ }
+ } else {
+ if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ fprintf(stderr, "%d:", yylineNum);
+ perror("ioctl(add/insert nat rule)");
+ }
+ }
+ }
+}
OpenPOWER on IntegriCloud