1747 lines
39 KiB
Plaintext
1747 lines
39 KiB
Plaintext
/* $FreeBSD$ */
|
|
|
|
/*
|
|
* Copyright (C) 2012 by Darren Reed.
|
|
*
|
|
* See the IPFILTER.LICENCE file for details on licencing.
|
|
*/
|
|
%{
|
|
#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>
|
|
#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(char *);
|
|
extern int yyparse(void);
|
|
extern int yylex(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 proxyrule_t *prules = NULL;
|
|
static int parser_error = 0;
|
|
|
|
static void newnatrule(void);
|
|
static void setnatproto(int);
|
|
static void setmapifnames(void);
|
|
static void setrdrifnames(void);
|
|
static void proxy_setconfig(int);
|
|
static void proxy_unsetconfig(void);
|
|
static namelist_t *proxy_dns_add_pass(char *, char *);
|
|
static namelist_t *proxy_dns_add_block(char *, char *);
|
|
static void proxy_addconfig(char *, int, char *, namelist_t *);
|
|
static void proxy_loadconfig(int, ioctlfunc_t, char *, int,
|
|
char *, namelist_t *);
|
|
static void proxy_loadrules(int, ioctlfunc_t, proxyrule_t *);
|
|
static void setmapifnames(void);
|
|
static void setrdrifnames(void);
|
|
static void setifname(ipnat_t **, int, char *);
|
|
static int addname(ipnat_t **, char *);
|
|
%}
|
|
%union {
|
|
char *str;
|
|
u_32_t num;
|
|
struct {
|
|
i6addr_t a;
|
|
int f;
|
|
} ipa;
|
|
frentry_t fr;
|
|
frtuc_t *frt;
|
|
u_short port;
|
|
struct {
|
|
int p1;
|
|
int p2;
|
|
int pc;
|
|
} pc;
|
|
struct {
|
|
i6addr_t a;
|
|
i6addr_t m;
|
|
int t; /* Address type */
|
|
int u;
|
|
int f; /* Family */
|
|
int v; /* IP version */
|
|
int s; /* 0 = number, 1 = text */
|
|
int n; /* number */
|
|
} ipp;
|
|
union i6addr ip6;
|
|
namelist_t *names;
|
|
};
|
|
|
|
%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 IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
|
|
%token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
|
|
%token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
|
|
%token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
|
|
%type <port> portspec
|
|
%type <num> hexnumber compare range proto
|
|
%type <num> saddr daddr sobject dobject mapfrom rdrfrom dip
|
|
%type <ipa> hostname ipv4 ipaddr
|
|
%type <ipp> addr rhsaddr rhdaddr erhdaddr
|
|
%type <pc> portstuff portpair comaports srcports dstports
|
|
%type <names> dnslines dnsline
|
|
%%
|
|
file: line
|
|
| assign
|
|
| file line
|
|
| file assign
|
|
| file pconf ';'
|
|
;
|
|
|
|
line: xx rule { int err;
|
|
while ((nat = nattop) != NULL) {
|
|
if (nat->in_v[0] == 0)
|
|
nat->in_v[0] = 4;
|
|
if (nat->in_v[1] == 0)
|
|
nat->in_v[1] = nat->in_v[0];
|
|
nattop = nat->in_next;
|
|
err = (*nataddfunc)(natfd, natioctlfunc, nat);
|
|
free(nat);
|
|
if (err != 0) {
|
|
parser_error = err;
|
|
break;
|
|
}
|
|
}
|
|
if (parser_error == 0 && prules != NULL) {
|
|
proxy_loadrules(natfd, natioctlfunc, prules);
|
|
prules = NULL;
|
|
}
|
|
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
|
|
| rewrite ';'
|
|
| divert ';'
|
|
;
|
|
|
|
no: IPNY_NO { nat->in_flags |= IPN_NO; }
|
|
;
|
|
|
|
eol: | ';'
|
|
;
|
|
|
|
map: mapit ifnames addr tlate rhsaddr proxy mapoptions
|
|
{ if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
|
|
yyerror("3.address family mismatch");
|
|
if (nat->in_v[0] == 0 && $5.v != 0)
|
|
nat->in_v[0] = $5.v;
|
|
else if (nat->in_v[0] == 0 && $3.v != 0)
|
|
nat->in_v[0] = $3.v;
|
|
if (nat->in_v[1] == 0 && $5.v != 0)
|
|
nat->in_v[1] = $5.v;
|
|
else if (nat->in_v[1] == 0 && $3.v != 0)
|
|
nat->in_v[1] = $3.v;
|
|
nat->in_osrcatype = $3.t;
|
|
bcopy(&$3.a, &nat->in_osrc.na_addr[0],
|
|
sizeof($3.a));
|
|
bcopy(&$3.m, &nat->in_osrc.na_addr[1],
|
|
sizeof($3.a));
|
|
nat->in_nsrcatype = $5.t;
|
|
nat->in_nsrcafunc = $5.u;
|
|
bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
|
|
sizeof($5.a));
|
|
bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
|
|
sizeof($5.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
| mapit ifnames addr tlate rhsaddr mapport mapoptions
|
|
{ if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
|
|
yyerror("4.address family mismatch");
|
|
if (nat->in_v[1] == 0 && $5.v != 0)
|
|
nat->in_v[1] = $5.v;
|
|
else if (nat->in_v[0] == 0 && $3.v != 0)
|
|
nat->in_v[0] = $3.v;
|
|
if (nat->in_v[0] == 0 && $5.v != 0)
|
|
nat->in_v[0] = $5.v;
|
|
else if (nat->in_v[1] == 0 && $3.v != 0)
|
|
nat->in_v[1] = $3.v;
|
|
nat->in_osrcatype = $3.t;
|
|
bcopy(&$3.a, &nat->in_osrc.na_addr[0],
|
|
sizeof($3.a));
|
|
bcopy(&$3.m, &nat->in_osrc.na_addr[1],
|
|
sizeof($3.a));
|
|
nat->in_nsrcatype = $5.t;
|
|
nat->in_nsrcafunc = $5.u;
|
|
bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
|
|
sizeof($5.a));
|
|
bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
|
|
sizeof($5.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
| no mapit ifnames addr setproto ';'
|
|
{ if (nat->in_v[0] == 0)
|
|
nat->in_v[0] = $4.v;
|
|
nat->in_osrcatype = $4.t;
|
|
bcopy(&$4.a, &nat->in_osrc.na_addr[0],
|
|
sizeof($4.a));
|
|
bcopy(&$4.m, &nat->in_osrc.na_addr[1],
|
|
sizeof($4.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
| mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
|
|
{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
|
|
yyerror("5.address family mismatch");
|
|
if (nat->in_v[0] == 0 && $5.v != 0)
|
|
nat->in_v[0] = $5.v;
|
|
else if (nat->in_v[0] == 0 && $3 != 0)
|
|
nat->in_v[0] = ftov($3);
|
|
if (nat->in_v[1] == 0 && $5.v != 0)
|
|
nat->in_v[1] = $5.v;
|
|
else if (nat->in_v[1] == 0 && $3 != 0)
|
|
nat->in_v[1] = ftov($3);
|
|
nat->in_nsrcatype = $5.t;
|
|
nat->in_nsrcafunc = $5.u;
|
|
bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
|
|
sizeof($5.a));
|
|
bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
|
|
sizeof($5.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
| no mapit ifnames mapfrom setproto ';'
|
|
{ nat->in_v[0] = ftov($4);
|
|
setmapifnames();
|
|
}
|
|
| mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
|
|
{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
|
|
yyerror("6.address family mismatch");
|
|
if (nat->in_v[0] == 0 && $5.v != 0)
|
|
nat->in_v[0] = $5.v;
|
|
else if (nat->in_v[0] == 0 && $3 != 0)
|
|
nat->in_v[0] = ftov($3);
|
|
if (nat->in_v[1] == 0 && $5.v != 0)
|
|
nat->in_v[1] = $5.v;
|
|
else if (nat->in_v[1] == 0 && $3 != 0)
|
|
nat->in_v[1] = ftov($3);
|
|
nat->in_nsrcatype = $5.t;
|
|
nat->in_nsrcafunc = $5.u;
|
|
bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
|
|
sizeof($5.a));
|
|
bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
|
|
sizeof($5.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
;
|
|
|
|
mapblock:
|
|
mapblockit ifnames addr tlate addr ports mapoptions
|
|
{ if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
|
|
yyerror("7.address family mismatch");
|
|
if (nat->in_v[0] == 0 && $5.v != 0)
|
|
nat->in_v[0] = $5.v;
|
|
else if (nat->in_v[0] == 0 && $3.v != 0)
|
|
nat->in_v[0] = $3.v;
|
|
if (nat->in_v[1] == 0 && $5.v != 0)
|
|
nat->in_v[1] = $5.v;
|
|
else if (nat->in_v[1] == 0 && $3.v != 0)
|
|
nat->in_v[1] = $3.v;
|
|
nat->in_osrcatype = $3.t;
|
|
bcopy(&$3.a, &nat->in_osrc.na_addr[0],
|
|
sizeof($3.a));
|
|
bcopy(&$3.m, &nat->in_osrc.na_addr[1],
|
|
sizeof($3.a));
|
|
nat->in_nsrcatype = $5.t;
|
|
nat->in_nsrcafunc = $5.u;
|
|
bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
|
|
sizeof($5.a));
|
|
bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
|
|
sizeof($5.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
| no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
|
|
{ if (nat->in_v[0] == 0)
|
|
nat->in_v[0] = $5.v;
|
|
if (nat->in_v[1] == 0)
|
|
nat->in_v[1] = $5.v;
|
|
nat->in_osrcatype = $5.t;
|
|
bcopy(&$5.a, &nat->in_osrc.na_addr[0],
|
|
sizeof($5.a));
|
|
bcopy(&$5.m, &nat->in_osrc.na_addr[1],
|
|
sizeof($5.a));
|
|
|
|
setmapifnames();
|
|
}
|
|
;
|
|
|
|
redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions
|
|
{ if ($6 != 0 && $3.f != 0 && $6 != $3.f)
|
|
yyerror("21.address family mismatch");
|
|
if (nat->in_v[0] == 0) {
|
|
if ($3.v != AF_UNSPEC)
|
|
nat->in_v[0] = ftov($3.f);
|
|
else
|
|
nat->in_v[0] = ftov($6);
|
|
}
|
|
nat->in_odstatype = $3.t;
|
|
bcopy(&$3.a, &nat->in_odst.na_addr[0],
|
|
sizeof($3.a));
|
|
bcopy(&$3.m, &nat->in_odst.na_addr[1],
|
|
sizeof($3.a));
|
|
|
|
setrdrifnames();
|
|
}
|
|
| no rdrit ifnames addr dport setproto ';'
|
|
{ if (nat->in_v[0] == 0)
|
|
nat->in_v[0] = ftov($4.f);
|
|
nat->in_odstatype = $4.t;
|
|
bcopy(&$4.a, &nat->in_odst.na_addr[0],
|
|
sizeof($4.a));
|
|
bcopy(&$4.m, &nat->in_odst.na_addr[1],
|
|
sizeof($4.a));
|
|
|
|
setrdrifnames();
|
|
}
|
|
| rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
|
|
{ if ($5 != 0 && $3 != 0 && $5 != $3)
|
|
yyerror("20.address family mismatch");
|
|
if (nat->in_v[0] == 0) {
|
|
if ($3 != AF_UNSPEC)
|
|
nat->in_v[0] = ftov($3);
|
|
else
|
|
nat->in_v[0] = ftov($5);
|
|
}
|
|
setrdrifnames();
|
|
}
|
|
| no rdrit ifnames rdrfrom setproto ';'
|
|
{ nat->in_v[0] = ftov($4);
|
|
|
|
setrdrifnames();
|
|
}
|
|
;
|
|
|
|
rewrite:
|
|
IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
|
|
{ if (nat->in_v[0] == 0)
|
|
nat->in_v[0] = ftov($4);
|
|
if (nat->in_redir & NAT_MAP)
|
|
setmapifnames();
|
|
else
|
|
setrdrifnames();
|
|
nat->in_redir |= NAT_REWRITE;
|
|
}
|
|
;
|
|
|
|
divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
|
|
{ if (nat->in_v[0] == 0)
|
|
nat->in_v[0] = ftov($4);
|
|
if (nat->in_redir & NAT_MAP) {
|
|
setmapifnames();
|
|
nat->in_pr[0] = IPPROTO_UDP;
|
|
} else {
|
|
setrdrifnames();
|
|
nat->in_pr[1] = IPPROTO_UDP;
|
|
}
|
|
nat->in_flags &= ~IPN_TCP;
|
|
}
|
|
;
|
|
|
|
tlate: IPNY_TLATE { yyexpectaddr = 1; }
|
|
;
|
|
|
|
pconf: IPNY_PROXY { yysetdict(proxies); }
|
|
IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
|
|
{ proxy_setconfig(IPNY_DNS); }
|
|
dnslines ';' '}'
|
|
{ proxy_addconfig("dns", $5, $7, $10);
|
|
proxy_unsetconfig();
|
|
}
|
|
;
|
|
|
|
dnslines:
|
|
dnsline { $$ = $1; }
|
|
| dnslines ';' dnsline { $$ = $1; $1->na_next = $3; }
|
|
;
|
|
|
|
dnsline:
|
|
IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); }
|
|
| IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); }
|
|
| IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); }
|
|
| IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); }
|
|
;
|
|
|
|
oninout:
|
|
inout IPNY_ON ifnames { ; }
|
|
;
|
|
|
|
inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; }
|
|
| IPNY_OUT { nat->in_redir = NAT_MAP; }
|
|
;
|
|
|
|
rwrproto:
|
|
| IPNY_PROTO setproto
|
|
;
|
|
|
|
newdst: src rhsaddr srcports dst erhdaddr dstports
|
|
{ nat->in_nsrc.na_addr[0] = $2.a;
|
|
nat->in_nsrc.na_addr[1] = $2.m;
|
|
nat->in_nsrc.na_atype = $2.t;
|
|
if ($2.t == FRI_LOOKUP) {
|
|
nat->in_nsrc.na_type = $2.u;
|
|
nat->in_nsrc.na_subtype = $2.s;
|
|
nat->in_nsrc.na_num = $2.n;
|
|
}
|
|
nat->in_nsports[0] = $3.p1;
|
|
nat->in_nsports[1] = $3.p2;
|
|
nat->in_ndst.na_addr[0] = $5.a;
|
|
nat->in_ndst.na_addr[1] = $5.m;
|
|
nat->in_ndst.na_atype = $5.t;
|
|
if ($5.t == FRI_LOOKUP) {
|
|
nat->in_ndst.na_type = $5.u;
|
|
nat->in_ndst.na_subtype = $5.s;
|
|
nat->in_ndst.na_num = $5.n;
|
|
}
|
|
nat->in_ndports[0] = $6.p1;
|
|
nat->in_ndports[1] = $6.p2;
|
|
}
|
|
;
|
|
|
|
divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP
|
|
{ nat->in_nsrc.na_addr[0] = $2.a;
|
|
if ($2.m.in4.s_addr != 0xffffffff)
|
|
yyerror("divert must have /32 dest");
|
|
nat->in_nsrc.na_addr[1] = $2.m;
|
|
nat->in_nsports[0] = $4;
|
|
nat->in_nsports[1] = $4;
|
|
|
|
nat->in_ndst.na_addr[0] = $6.a;
|
|
nat->in_ndst.na_addr[1] = $6.m;
|
|
if ($6.m.in4.s_addr != 0xffffffff)
|
|
yyerror("divert must have /32 dest");
|
|
nat->in_ndports[0] = $8;
|
|
nat->in_ndports[1] = $8;
|
|
|
|
nat->in_redir |= NAT_DIVERTUDP;
|
|
}
|
|
;
|
|
|
|
src: IPNY_SRC { yyexpectaddr = 1; }
|
|
;
|
|
|
|
dst: IPNY_DST { yyexpectaddr = 1; }
|
|
;
|
|
|
|
srcports:
|
|
comaports { $$.p1 = $1.p1;
|
|
$$.p2 = $1.p2;
|
|
}
|
|
| IPNY_PORT '=' portspec
|
|
{ $$.p1 = $3;
|
|
$$.p2 = $3;
|
|
nat->in_flags |= IPN_FIXEDSPORT;
|
|
}
|
|
;
|
|
|
|
dstports:
|
|
comaports { $$.p1 = $1.p1;
|
|
$$.p2 = $1.p2;
|
|
}
|
|
| IPNY_PORT '=' portspec
|
|
{ $$.p1 = $3;
|
|
$$.p2 = $3;
|
|
nat->in_flags |= IPN_FIXEDDPORT;
|
|
}
|
|
;
|
|
|
|
comaports:
|
|
{ $$.p1 = 0;
|
|
$$.p2 = 0;
|
|
}
|
|
| ',' { if (!(nat->in_flags & IPN_TCPUDP))
|
|
yyerror("must be TCP/UDP for ports");
|
|
}
|
|
portpair { $$.p1 = $3.p1;
|
|
$$.p2 = $3.p2;
|
|
}
|
|
;
|
|
|
|
proxy: | IPNY_PROXY port portspec YY_STR '/' proto
|
|
{ int pos;
|
|
pos = addname(&nat, $4);
|
|
nat->in_plabel = pos;
|
|
if (nat->in_dcmp == 0) {
|
|
nat->in_odport = $3;
|
|
} else if ($3 != nat->in_odport) {
|
|
yyerror("proxy port numbers not consistant");
|
|
}
|
|
nat->in_ndport = $3;
|
|
setnatproto($6);
|
|
free($4);
|
|
}
|
|
| IPNY_PROXY port YY_STR YY_STR '/' proto
|
|
{ int pnum, pos;
|
|
pos = addname(&nat, $4);
|
|
nat->in_plabel = pos;
|
|
pnum = getportproto($3, $6);
|
|
if (pnum == -1)
|
|
yyerror("invalid port number");
|
|
nat->in_odport = ntohs(pnum);
|
|
nat->in_ndport = ntohs(pnum);
|
|
setnatproto($6);
|
|
free($3);
|
|
free($4);
|
|
}
|
|
| IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
|
|
{ int pos;
|
|
pos = addname(&nat, $4);
|
|
nat->in_plabel = pos;
|
|
if (nat->in_dcmp == 0) {
|
|
nat->in_odport = $3;
|
|
} else if ($3 != nat->in_odport) {
|
|
yyerror("proxy port numbers not consistant");
|
|
}
|
|
nat->in_ndport = $3;
|
|
setnatproto($6);
|
|
nat->in_pconfig = addname(&nat, $8);
|
|
free($4);
|
|
free($8);
|
|
}
|
|
| IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
|
|
{ int pnum, pos;
|
|
pos = addname(&nat, $4);
|
|
nat->in_plabel = pos;
|
|
pnum = getportproto($3, $6);
|
|
if (pnum == -1)
|
|
yyerror("invalid port number");
|
|
nat->in_odport = ntohs(pnum);
|
|
nat->in_ndport = ntohs(pnum);
|
|
setnatproto($6);
|
|
pos = addname(&nat, $8);
|
|
nat->in_pconfig = pos;
|
|
free($3);
|
|
free($4);
|
|
free($8);
|
|
}
|
|
;
|
|
setproto:
|
|
| proto { if (nat->in_pr[0] != 0 ||
|
|
nat->in_pr[1] != 0 ||
|
|
nat->in_flags & IPN_TCPUDP)
|
|
yyerror("protocol set twice");
|
|
setnatproto($1);
|
|
}
|
|
| IPNY_TCPUDP { if (nat->in_pr[0] != 0 ||
|
|
nat->in_pr[1] != 0 ||
|
|
nat->in_flags & IPN_TCPUDP)
|
|
yyerror("protocol set twice");
|
|
nat->in_flags |= IPN_TCPUDP;
|
|
nat->in_pr[0] = 0;
|
|
nat->in_pr[1] = 0;
|
|
}
|
|
| IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 ||
|
|
nat->in_pr[1] != 0 ||
|
|
nat->in_flags & IPN_TCPUDP)
|
|
yyerror("protocol set twice");
|
|
nat->in_flags |= IPN_TCPUDP;
|
|
nat->in_pr[0] = 0;
|
|
nat->in_pr[1] = 0;
|
|
}
|
|
;
|
|
|
|
rhsaddr:
|
|
addr { $$ = $1;
|
|
yyexpectaddr = 0;
|
|
}
|
|
| hostname '-' { yyexpectaddr = 1; } hostname
|
|
{ $$.t = FRI_RANGE;
|
|
if ($1.f != $4.f)
|
|
yyerror("8.address family "
|
|
"mismatch");
|
|
$$.f = $1.f;
|
|
$$.v = ftov($1.f);
|
|
$$.a = $1.a;
|
|
$$.m = $4.a;
|
|
nat->in_flags |= IPN_SIPRANGE;
|
|
yyexpectaddr = 0;
|
|
}
|
|
| IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
|
|
{ $$.t = FRI_RANGE;
|
|
if ($2.f != $5.f)
|
|
yyerror("9.address family "
|
|
"mismatch");
|
|
$$.f = $2.f;
|
|
$$.v = ftov($2.f);
|
|
$$.a = $2.a;
|
|
$$.m = $5.a;
|
|
nat->in_flags |= IPN_SIPRANGE;
|
|
yyexpectaddr = 0;
|
|
}
|
|
;
|
|
|
|
dip:
|
|
hostname ',' { yyexpectaddr = 1; } hostname
|
|
{ nat->in_flags |= IPN_SPLIT;
|
|
if ($1.f != $4.f)
|
|
yyerror("10.address family "
|
|
"mismatch");
|
|
$$ = $1.f;
|
|
nat->in_ndstip6 = $1.a;
|
|
nat->in_ndstmsk6 = $4.a;
|
|
nat->in_ndstatype = FRI_SPLIT;
|
|
yyexpectaddr = 0;
|
|
}
|
|
| rhdaddr { int bits;
|
|
nat->in_ndstip6 = $1.a;
|
|
nat->in_ndstmsk6 = $1.m;
|
|
nat->in_ndst.na_atype = $1.t;
|
|
yyexpectaddr = 0;
|
|
if ($1.f == AF_INET)
|
|
bits = count4bits($1.m.in4.s_addr);
|
|
else
|
|
bits = count6bits($1.m.i6);
|
|
if (($1.f == AF_INET) && (bits != 0) &&
|
|
(bits != 32)) {
|
|
yyerror("dest ip bitmask not /32");
|
|
} else if (($1.f == AF_INET6) &&
|
|
(bits != 0) && (bits != 128)) {
|
|
yyerror("dest ip bitmask not /128");
|
|
}
|
|
$$ = $1.f;
|
|
}
|
|
;
|
|
|
|
rhdaddr:
|
|
addr { $$ = $1;
|
|
yyexpectaddr = 0;
|
|
}
|
|
| hostname '-' hostname { bzero(&$$, sizeof($$));
|
|
$$.t = FRI_RANGE;
|
|
if ($1.f != 0 && $3.f != 0 &&
|
|
$1.f != $3.f)
|
|
yyerror("11.address family "
|
|
"mismatch");
|
|
$$.a = $1.a;
|
|
$$.m = $3.a;
|
|
nat->in_flags |= IPN_DIPRANGE;
|
|
yyexpectaddr = 0;
|
|
}
|
|
| IPNY_RANGE hostname '-' hostname
|
|
{ bzero(&$$, sizeof($$));
|
|
$$.t = FRI_RANGE;
|
|
if ($2.f != 0 && $4.f != 0 &&
|
|
$2.f != $4.f)
|
|
yyerror("12.address family "
|
|
"mismatch");
|
|
$$.a = $2.a;
|
|
$$.m = $4.a;
|
|
nat->in_flags |= IPN_DIPRANGE;
|
|
yyexpectaddr = 0;
|
|
}
|
|
;
|
|
|
|
erhdaddr:
|
|
rhdaddr { $$ = $1; }
|
|
| IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP;
|
|
$$.u = IPLT_DSTLIST;
|
|
$$.s = 0;
|
|
$$.n = $3;
|
|
}
|
|
| IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP;
|
|
$$.u = IPLT_DSTLIST;
|
|
$$.s = 1;
|
|
$$.n = addname(&nat, $3);
|
|
}
|
|
;
|
|
|
|
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,
|
|
&($$), NULL) == -1)
|
|
yyerror("invalid port number");
|
|
$$ = ntohs($$);
|
|
}
|
|
;
|
|
|
|
portpair:
|
|
portspec { $$.p1 = $1; $$.p2 = $1; }
|
|
| portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; }
|
|
| portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; }
|
|
;
|
|
|
|
dport: | port portpair { nat->in_odport = $2.p1;
|
|
if ($2.p2 == 0)
|
|
nat->in_dtop = $2.p1;
|
|
else
|
|
nat->in_dtop = $2.p2;
|
|
}
|
|
;
|
|
|
|
nport: | port portpair { nat->in_dpmin = $2.p1;
|
|
nat->in_dpnext = $2.p1;
|
|
nat->in_dpmax = $2.p2;
|
|
nat->in_ndport = $2.p1;
|
|
if (nat->in_dtop == 0)
|
|
nat->in_dtop = $2.p2;
|
|
}
|
|
| port '=' portspec { nat->in_dpmin = $3;
|
|
nat->in_dpnext = $3;
|
|
nat->in_ndport = $3;
|
|
if (nat->in_dtop == 0)
|
|
nat->in_dtop = nat->in_odport;
|
|
nat->in_flags |= IPN_FIXEDDPORT;
|
|
}
|
|
;
|
|
|
|
ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $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 to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
|
|
yyerror("13.address family "
|
|
"mismatch");
|
|
$$ = $2;
|
|
}
|
|
| from sobject '!' to dobject
|
|
{ if ($2 != 0 && $5 != 0 && $2 != $5)
|
|
yyerror("14.address family "
|
|
"mismatch");
|
|
nat->in_flags |= IPN_NOTDST;
|
|
$$ = $2;
|
|
}
|
|
| from sobject to '!' dobject
|
|
{ if ($2 != 0 && $5 != 0 && $2 != $5)
|
|
yyerror("15.address family "
|
|
"mismatch");
|
|
nat->in_flags |= IPN_NOTDST;
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
rdrfrom:
|
|
from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
|
|
yyerror("16.address family "
|
|
"mismatch");
|
|
$$ = $2;
|
|
}
|
|
| '!' from sobject to dobject
|
|
{ if ($3 != 0 && $5 != 0 && $3 != $5)
|
|
yyerror("17.address family "
|
|
"mismatch");
|
|
nat->in_flags |= IPN_NOTSRC;
|
|
$$ = $3;
|
|
}
|
|
| from '!' sobject to dobject
|
|
{ if ($3 != 0 && $5 != 0 && $3 != $5)
|
|
yyerror("18.address family "
|
|
"mismatch");
|
|
nat->in_flags |= IPN_NOTSRC;
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
from: IPNY_FROM { nat->in_flags |= IPN_FILTER;
|
|
yyexpectaddr = 1;
|
|
}
|
|
;
|
|
|
|
to: IPNY_TO { yyexpectaddr = 1; }
|
|
;
|
|
|
|
ifnames:
|
|
ifname family { yyexpectaddr = 1; }
|
|
| ifname ',' otherifname family { yyexpectaddr = 1; }
|
|
;
|
|
|
|
ifname: YY_STR { setifname(&nat, 0, $1);
|
|
free($1);
|
|
}
|
|
;
|
|
|
|
family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; }
|
|
| IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; }
|
|
;
|
|
|
|
otherifname:
|
|
YY_STR { setifname(&nat, 1, $1);
|
|
free($1);
|
|
}
|
|
;
|
|
|
|
mapport:
|
|
IPNY_PORTMAP tcpudp portpair sequential
|
|
{ nat->in_spmin = $3.p1;
|
|
nat->in_spmax = $3.p2;
|
|
}
|
|
| IPNY_PORTMAP portpair tcpudp sequential
|
|
{ nat->in_spmin = $2.p1;
|
|
nat->in_spmax = $2.p2;
|
|
}
|
|
| IPNY_PORTMAP tcpudp IPNY_AUTO sequential
|
|
{ nat->in_flags |= IPN_AUTOPORTMAP;
|
|
nat->in_spmin = 1024;
|
|
nat->in_spmax = 65535;
|
|
}
|
|
| IPNY_ICMPIDMAP YY_STR portpair sequential
|
|
{ if (strcmp($2, "icmp") != 0 &&
|
|
strcmp($2, "ipv6-icmp") != 0) {
|
|
yyerror("icmpidmap not followed by icmp");
|
|
}
|
|
free($2);
|
|
if ($3.p1 < 0 || $3.p1 > 65535)
|
|
yyerror("invalid 1st ICMP Id number");
|
|
if ($3.p2 < 0 || $3.p2 > 65535)
|
|
yyerror("invalid 2nd ICMP Id number");
|
|
if (strcmp($2, "ipv6-icmp") == 0) {
|
|
nat->in_pr[0] = IPPROTO_ICMPV6;
|
|
nat->in_pr[1] = IPPROTO_ICMPV6;
|
|
} else {
|
|
nat->in_pr[0] = IPPROTO_ICMP;
|
|
nat->in_pr[1] = IPPROTO_ICMP;
|
|
}
|
|
nat->in_flags = IPN_ICMPQUERY;
|
|
nat->in_spmin = $3.p1;
|
|
nat->in_spmax = $3.p2;
|
|
}
|
|
;
|
|
|
|
sobject:
|
|
saddr { $$ = $1; }
|
|
| saddr port portstuff { nat->in_osport = $3.p1;
|
|
nat->in_stop = $3.p2;
|
|
nat->in_scmp = $3.pc;
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
saddr: addr { nat->in_osrcatype = $1.t;
|
|
bcopy(&$1.a,
|
|
&nat->in_osrc.na_addr[0],
|
|
sizeof($1.a));
|
|
bcopy(&$1.m,
|
|
&nat->in_osrc.na_addr[1],
|
|
sizeof($1.m));
|
|
$$ = $1.f;
|
|
}
|
|
;
|
|
|
|
dobject:
|
|
daddr { $$ = $1; }
|
|
| daddr port portstuff { nat->in_odport = $3.p1;
|
|
nat->in_dtop = $3.p2;
|
|
nat->in_dcmp = $3.pc;
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
daddr: addr { nat->in_odstatype = $1.t;
|
|
bcopy(&$1.a,
|
|
&nat->in_odst.na_addr[0],
|
|
sizeof($1.a));
|
|
bcopy(&$1.m,
|
|
&nat->in_odst.na_addr[1],
|
|
sizeof($1.m));
|
|
$$ = $1.f;
|
|
}
|
|
;
|
|
|
|
addr: IPNY_ANY { yyexpectaddr = 0;
|
|
bzero(&$$, sizeof($$));
|
|
$$.t = FRI_NORMAL;
|
|
}
|
|
| hostname { bzero(&$$, sizeof($$));
|
|
$$.a = $1.a;
|
|
$$.t = FRI_NORMAL;
|
|
$$.v = ftov($1.f);
|
|
$$.f = $1.f;
|
|
if ($$.f == AF_INET) {
|
|
$$.m.in4.s_addr = 0xffffffff;
|
|
} else if ($$.f == AF_INET6) {
|
|
$$.m.i6[0] = 0xffffffff;
|
|
$$.m.i6[1] = 0xffffffff;
|
|
$$.m.i6[2] = 0xffffffff;
|
|
$$.m.i6[3] = 0xffffffff;
|
|
}
|
|
yyexpectaddr = 0;
|
|
}
|
|
| hostname slash YY_NUMBER
|
|
{ bzero(&$$, sizeof($$));
|
|
$$.a = $1.a;
|
|
$$.f = $1.f;
|
|
$$.v = ftov($1.f);
|
|
$$.t = FRI_NORMAL;
|
|
ntomask($$.f, $3, (u_32_t *)&$$.m);
|
|
$$.a.i6[0] &= $$.m.i6[0];
|
|
$$.a.i6[1] &= $$.m.i6[1];
|
|
$$.a.i6[2] &= $$.m.i6[2];
|
|
$$.a.i6[3] &= $$.m.i6[3];
|
|
yyexpectaddr = 0;
|
|
}
|
|
| hostname slash ipaddr { bzero(&$$, sizeof($$));
|
|
if ($1.f != $3.f) {
|
|
yyerror("1.address family "
|
|
"mismatch");
|
|
}
|
|
$$.a = $1.a;
|
|
$$.m = $3.a;
|
|
$$.t = FRI_NORMAL;
|
|
$$.a.i6[0] &= $$.m.i6[0];
|
|
$$.a.i6[1] &= $$.m.i6[1];
|
|
$$.a.i6[2] &= $$.m.i6[2];
|
|
$$.a.i6[3] &= $$.m.i6[3];
|
|
$$.f = $1.f;
|
|
$$.v = ftov($1.f);
|
|
yyexpectaddr = 0;
|
|
}
|
|
| hostname slash hexnumber { bzero(&$$, sizeof($$));
|
|
$$.a = $1.a;
|
|
$$.m.in4.s_addr = htonl($3);
|
|
$$.t = FRI_NORMAL;
|
|
$$.a.in4.s_addr &= $$.m.in4.s_addr;
|
|
$$.f = $1.f;
|
|
$$.v = ftov($1.f);
|
|
if ($$.f == AF_INET6)
|
|
yyerror("incorrect inet6 mask");
|
|
}
|
|
| hostname mask ipaddr { bzero(&$$, sizeof($$));
|
|
if ($1.f != $3.f) {
|
|
yyerror("2.address family "
|
|
"mismatch");
|
|
}
|
|
$$.a = $1.a;
|
|
$$.m = $3.a;
|
|
$$.t = FRI_NORMAL;
|
|
$$.a.i6[0] &= $$.m.i6[0];
|
|
$$.a.i6[1] &= $$.m.i6[1];
|
|
$$.a.i6[2] &= $$.m.i6[2];
|
|
$$.a.i6[3] &= $$.m.i6[3];
|
|
$$.f = $1.f;
|
|
$$.v = ftov($1.f);
|
|
yyexpectaddr = 0;
|
|
}
|
|
| hostname mask hexnumber { bzero(&$$, sizeof($$));
|
|
$$.a = $1.a;
|
|
$$.m.in4.s_addr = htonl($3);
|
|
$$.t = FRI_NORMAL;
|
|
$$.a.in4.s_addr &= $$.m.in4.s_addr;
|
|
$$.f = AF_INET;
|
|
$$.v = 4;
|
|
}
|
|
| pool slash YY_NUMBER { bzero(&$$, sizeof($$));
|
|
$$.a.iplookupnum = $3;
|
|
$$.a.iplookuptype = IPLT_POOL;
|
|
$$.a.iplookupsubtype = 0;
|
|
$$.t = FRI_LOOKUP;
|
|
}
|
|
| pool slash YY_STR { bzero(&$$, sizeof($$));
|
|
$$.a.iplookupname = addname(&nat,$3);
|
|
$$.a.iplookuptype = IPLT_POOL;
|
|
$$.a.iplookupsubtype = 1;
|
|
$$.t = FRI_LOOKUP;
|
|
}
|
|
| hash slash YY_NUMBER { bzero(&$$, sizeof($$));
|
|
$$.a.iplookupnum = $3;
|
|
$$.a.iplookuptype = IPLT_HASH;
|
|
$$.a.iplookupsubtype = 0;
|
|
$$.t = FRI_LOOKUP;
|
|
}
|
|
| hash slash YY_STR { bzero(&$$, sizeof($$));
|
|
$$.a.iplookupname = addname(&nat,$3);
|
|
$$.a.iplookuptype = IPLT_HASH;
|
|
$$.a.iplookupsubtype = 1;
|
|
$$.t = FRI_LOOKUP;
|
|
}
|
|
;
|
|
|
|
slash: '/' { yyexpectaddr = 0; }
|
|
;
|
|
|
|
mask: IPNY_MASK { yyexpectaddr = 0; }
|
|
;
|
|
|
|
pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) {
|
|
yyerror("Can only use pool with from/to rules\n");
|
|
}
|
|
yyexpectaddr = 0;
|
|
yyresetdict();
|
|
}
|
|
;
|
|
|
|
hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) {
|
|
yyerror("Can only use hash with from/to rules\n");
|
|
}
|
|
yyexpectaddr = 0;
|
|
yyresetdict();
|
|
}
|
|
;
|
|
|
|
portstuff:
|
|
compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
|
|
| portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
|
|
;
|
|
|
|
mapoptions:
|
|
rr frag age mssclamp nattag setproto purge
|
|
;
|
|
|
|
rdroptions:
|
|
rr frag age sticky mssclamp rdrproxy nattag purge
|
|
;
|
|
|
|
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_pr[0] = 0;
|
|
nat->in_pr[1] = 0;
|
|
}
|
|
| IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
|
|
nat->in_pr[0] = 0;
|
|
nat->in_pr[1] = 0;
|
|
}
|
|
;
|
|
|
|
sequential:
|
|
| IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; }
|
|
;
|
|
|
|
purge:
|
|
| IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
|
|
;
|
|
|
|
rdrproxy:
|
|
IPNY_PROXY YY_STR
|
|
{ int pos;
|
|
pos = addname(&nat, $2);
|
|
nat->in_plabel = pos;
|
|
nat->in_odport = nat->in_dpnext;
|
|
nat->in_dtop = nat->in_odport;
|
|
free($2);
|
|
}
|
|
| proxy { if (nat->in_plabel != -1) {
|
|
nat->in_ndport = nat->in_odport;
|
|
nat->in_dpmin = nat->in_odport;
|
|
nat->in_dpmax = nat->in_dpmin;
|
|
nat->in_dtop = nat->in_dpmin;
|
|
nat->in_dpnext = nat->in_dpmin;
|
|
}
|
|
}
|
|
;
|
|
|
|
newopts:
|
|
| IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
|
|
;
|
|
|
|
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 ($$ == -1)
|
|
yyerror("unknown protocol");
|
|
if ($$ != IPPROTO_TCP &&
|
|
$$ != IPPROTO_UDP)
|
|
suggest_port = 0;
|
|
}
|
|
;
|
|
|
|
hexnumber:
|
|
YY_HEX { $$ = $1; }
|
|
;
|
|
|
|
hostname:
|
|
YY_STR { i6addr_t addr;
|
|
int family;
|
|
|
|
#ifdef USE_INET6
|
|
if (nat->in_v[0] == 6)
|
|
family = AF_INET6;
|
|
else
|
|
#endif
|
|
family = AF_INET;
|
|
memset(&($$), 0, sizeof($$));
|
|
memset(&addr, 0, sizeof(addr));
|
|
$$.f = family;
|
|
if (gethost(family, $1,
|
|
&addr) == 0) {
|
|
$$.a = addr;
|
|
} else {
|
|
FPRINTF(stderr,
|
|
"Unknown host '%s'\n",
|
|
$1);
|
|
}
|
|
free($1);
|
|
}
|
|
| YY_NUMBER { memset(&($$), 0, sizeof($$));
|
|
$$.a.in4.s_addr = htonl($1);
|
|
if ($$.a.in4.s_addr != 0)
|
|
$$.f = AF_INET;
|
|
}
|
|
| ipv4 { $$ = $1; }
|
|
| YY_IPV6 { memset(&($$), 0, sizeof($$));
|
|
$$.a = $1;
|
|
$$.f = AF_INET6;
|
|
}
|
|
| YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$));
|
|
$$.a = $2;
|
|
$$.f = AF_INET6;
|
|
}
|
|
;
|
|
|
|
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; }
|
|
;
|
|
|
|
ipaddr: ipv4 { $$ = $1; }
|
|
| YY_IPV6 { $$.a = $1;
|
|
$$.f = AF_INET6;
|
|
}
|
|
;
|
|
|
|
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);
|
|
}
|
|
bzero((char *)&$$, sizeof($$));
|
|
$$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
|
|
$$.a.in4.s_addr = htonl($$.a.in4.s_addr);
|
|
$$.f = AF_INET;
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
|
|
static wordtab_t proxies[] = {
|
|
{ "dns", IPNY_DNS }
|
|
};
|
|
|
|
static wordtab_t dnswords[] = {
|
|
{ "allow", IPNY_ALLOW },
|
|
{ "block", IPNY_DENY },
|
|
{ "deny", IPNY_DENY },
|
|
{ "drop", IPNY_DENY },
|
|
{ "pass", IPNY_ALLOW },
|
|
|
|
};
|
|
|
|
static wordtab_t yywords[] = {
|
|
{ "age", IPNY_AGE },
|
|
{ "any", IPNY_ANY },
|
|
{ "auto", IPNY_AUTO },
|
|
{ "bimap", IPNY_BIMAP },
|
|
{ "config", IPNY_CONFIG },
|
|
{ "divert", IPNY_DIVERT },
|
|
{ "dst", IPNY_DST },
|
|
{ "dstlist", IPNY_DSTLIST },
|
|
{ "frag", IPNY_FRAG },
|
|
{ "from", IPNY_FROM },
|
|
{ "hash", IPNY_HASH },
|
|
{ "icmpidmap", IPNY_ICMPIDMAP },
|
|
{ "in", IPNY_IN },
|
|
{ "inet", IPNY_INET },
|
|
{ "inet6", IPNY_INET6 },
|
|
{ "mask", IPNY_MASK },
|
|
{ "map", IPNY_MAP },
|
|
{ "map-block", IPNY_MAPBLOCK },
|
|
{ "mssclamp", IPNY_MSSCLAMP },
|
|
{ "netmask", IPNY_MASK },
|
|
{ "no", IPNY_NO },
|
|
{ "on", IPNY_ON },
|
|
{ "out", IPNY_OUT },
|
|
{ "pool", IPNY_POOL },
|
|
{ "port", IPNY_PORT },
|
|
{ "portmap", IPNY_PORTMAP },
|
|
{ "ports", IPNY_PORTS },
|
|
{ "proto", IPNY_PROTO },
|
|
{ "proxy", IPNY_PROXY },
|
|
{ "purge", IPNY_PURGE },
|
|
{ "range", IPNY_RANGE },
|
|
{ "rewrite", IPNY_REWRITE },
|
|
{ "rdr", IPNY_RDR },
|
|
{ "round-robin",IPNY_ROUNDROBIN },
|
|
{ "sequential", IPNY_SEQUENTIAL },
|
|
{ "src", IPNY_SRC },
|
|
{ "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(int fd, addfunc_t addfunc, ioctlfunc_t ioctlfunc,
|
|
char *filename)
|
|
{
|
|
FILE *fp = NULL;
|
|
int rval;
|
|
char *s;
|
|
|
|
yylineNum = 1;
|
|
|
|
(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 ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
|
|
;
|
|
if (fp != NULL)
|
|
fclose(fp);
|
|
if (rval == -1)
|
|
rval = 0;
|
|
else if (rval != 0)
|
|
rval = 1;
|
|
return(rval);
|
|
}
|
|
|
|
|
|
int
|
|
ipnat_parsesome(int fd, addfunc_t addfunc, ioctlfunc_t ioctlfunc,
|
|
FILE *fp)
|
|
{
|
|
char *s;
|
|
int i;
|
|
|
|
natfd = fd;
|
|
parser_error = 0;
|
|
nataddfunc = addfunc;
|
|
natioctlfunc = ioctlfunc;
|
|
|
|
if (feof(fp))
|
|
return(-1);
|
|
i = fgetc(fp);
|
|
if (i == EOF)
|
|
return(-1);
|
|
if (ungetc(i, fp) == EOF)
|
|
return(-1);
|
|
if (feof(fp))
|
|
return(-1);
|
|
s = getenv("YYDEBUG");
|
|
if (s)
|
|
yydebug = atoi(s);
|
|
else
|
|
yydebug = 0;
|
|
|
|
yyin = fp;
|
|
yyparse();
|
|
return(parser_error);
|
|
}
|
|
|
|
|
|
static void
|
|
newnatrule(void)
|
|
{
|
|
ipnat_t *n;
|
|
|
|
n = calloc(1, sizeof(*n));
|
|
if (n == NULL)
|
|
return;
|
|
|
|
if (nat == NULL) {
|
|
nattop = nat = n;
|
|
n->in_pnext = &nattop;
|
|
} else {
|
|
nat->in_next = n;
|
|
n->in_pnext = &nat->in_next;
|
|
nat = n;
|
|
}
|
|
|
|
n->in_flineno = yylineNum;
|
|
n->in_ifnames[0] = -1;
|
|
n->in_ifnames[1] = -1;
|
|
n->in_plabel = -1;
|
|
n->in_pconfig = -1;
|
|
n->in_size = sizeof(*n);
|
|
|
|
suggest_port = 0;
|
|
}
|
|
|
|
|
|
static void
|
|
setnatproto(int p)
|
|
{
|
|
nat->in_pr[0] = p;
|
|
nat->in_pr[1] = 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;
|
|
#ifdef USE_INET6
|
|
case IPPROTO_ICMPV6 :
|
|
#endif
|
|
case IPPROTO_ICMP :
|
|
nat->in_flags &= ~IPN_TCPUDP;
|
|
if (!(nat->in_flags & IPN_ICMPQUERY) &&
|
|
!(nat->in_redir & NAT_DIVERTUDP)) {
|
|
nat->in_dcmp = 0;
|
|
nat->in_scmp = 0;
|
|
nat->in_dpmin = 0;
|
|
nat->in_dpmax = 0;
|
|
nat->in_dpnext = 0;
|
|
nat->in_spmin = 0;
|
|
nat->in_spmax = 0;
|
|
nat->in_spnext = 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_dpmin = 0;
|
|
nat->in_dpmax = 0;
|
|
nat->in_dpnext = 0;
|
|
nat->in_spmin = 0;
|
|
nat->in_spmax = 0;
|
|
nat->in_spnext = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
|
|
nat->in_stop = 0;
|
|
nat->in_dtop = 0;
|
|
nat->in_osport = 0;
|
|
nat->in_odport = 0;
|
|
nat->in_stop = 0;
|
|
nat->in_osport = 0;
|
|
nat->in_dtop = 0;
|
|
nat->in_odport = 0;
|
|
}
|
|
if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
|
|
nat->in_flags &= ~IPN_FIXEDDPORT;
|
|
}
|
|
|
|
|
|
int
|
|
ipnat_addrule(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 = ipn->in_size;
|
|
obj.ipfo_type = IPFOBJ_IPNAT;
|
|
obj.ipfo_ptr = ptr;
|
|
|
|
if ((opts & OPT_DONOTHING) != 0)
|
|
fd = -1;
|
|
|
|
if (opts & OPT_ZERORULEST) {
|
|
add = SIOCZRLST;
|
|
del = 0;
|
|
} else if (opts & OPT_PURGE) {
|
|
add = 0;
|
|
del = SIOCPURGENAT;
|
|
} else {
|
|
add = SIOCADNAT;
|
|
del = SIOCRMNAT;
|
|
}
|
|
|
|
if ((opts & OPT_VERBOSE) != 0)
|
|
printnat(ipn, opts);
|
|
|
|
if (opts & OPT_DEBUG)
|
|
binprint(ipn, ipn->in_size);
|
|
|
|
if ((opts & OPT_ZERORULEST) != 0) {
|
|
if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
|
|
if ((opts & OPT_DONOTHING) == 0) {
|
|
char msg[80];
|
|
|
|
snprintf(msg, sizeof(msg), "%d:ioctl(zero nat rule)",
|
|
ipn->in_flineno);
|
|
return(ipf_perror_fd(fd, ioctlfunc, msg));
|
|
}
|
|
} else {
|
|
PRINTF("hits %lu ", ipn->in_hits);
|
|
#ifdef USE_QUAD_T
|
|
PRINTF("bytes %"PRIu64" ",
|
|
ipn->in_bytes[0] + ipn->in_bytes[1]);
|
|
#else
|
|
PRINTF("bytes %lu ",
|
|
ipn->in_bytes[0] + ipn->in_bytes[1]);
|
|
#endif
|
|
printnat(ipn, opts);
|
|
}
|
|
} else if ((opts & OPT_REMOVE) != 0) {
|
|
if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
|
|
if ((opts & OPT_DONOTHING) == 0) {
|
|
char msg[80];
|
|
|
|
snprintf(msg, sizeof(msg), "%d:ioctl(delete nat rule)",
|
|
ipn->in_flineno);
|
|
return(ipf_perror_fd(fd, ioctlfunc, msg));
|
|
}
|
|
}
|
|
} else {
|
|
if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
|
|
if ((opts & OPT_DONOTHING) == 0) {
|
|
char msg[80];
|
|
|
|
snprintf(msg, sizeof(msg), "%d:ioctl(add/insert nat rule)",
|
|
ipn->in_flineno);
|
|
if (errno == EEXIST) {
|
|
int strlen_msg = strlen(msg);
|
|
snprintf(msg + strlen_msg, sizeof(msg) -strlen_msg, "(line %d)",
|
|
ipn->in_flineno);
|
|
}
|
|
return(ipf_perror_fd(fd, ioctlfunc, msg));
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
static void
|
|
setmapifnames()
|
|
{
|
|
if (nat->in_ifnames[1] == -1)
|
|
nat->in_ifnames[1] = 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_pr[1]);
|
|
|
|
if (((nat->in_redir & NAT_MAPBLK) != 0) ||
|
|
((nat->in_flags & IPN_AUTOPORTMAP) != 0))
|
|
nat_setgroupmap(nat);
|
|
}
|
|
|
|
|
|
static void
|
|
setrdrifnames(void)
|
|
{
|
|
if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
|
|
nat->in_flags |= IPN_TCPUDP;
|
|
|
|
if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
|
|
(nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
|
|
setnatproto(IPPROTO_TCP);
|
|
|
|
if (nat->in_ifnames[1] == -1)
|
|
nat->in_ifnames[1] = nat->in_ifnames[0];
|
|
}
|
|
|
|
|
|
static void
|
|
proxy_setconfig(int proxy)
|
|
{
|
|
if (proxy == IPNY_DNS) {
|
|
yysetfixeddict(dnswords);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
proxy_unsetconfig(void)
|
|
{
|
|
yyresetdict();
|
|
}
|
|
|
|
|
|
static namelist_t *
|
|
proxy_dns_add_pass(char *prefix, char *name)
|
|
{
|
|
namelist_t *n;
|
|
|
|
n = calloc(1, sizeof(*n));
|
|
if (n != NULL) {
|
|
if (prefix == NULL || *prefix == '\0') {
|
|
n->na_name = strdup(name);
|
|
} else {
|
|
n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
|
|
strcpy(n->na_name, prefix);
|
|
strcat(n->na_name, name);
|
|
}
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
|
|
static namelist_t *
|
|
proxy_dns_add_block(char *prefix, char *name)
|
|
{
|
|
namelist_t *n;
|
|
|
|
n = calloc(1, sizeof(*n));
|
|
if (n != NULL) {
|
|
if (prefix == NULL || *prefix == '\0') {
|
|
n->na_name = strdup(name);
|
|
} else {
|
|
n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
|
|
strcpy(n->na_name, prefix);
|
|
strcat(n->na_name, name);
|
|
}
|
|
n->na_value = 1;
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
|
|
static void
|
|
proxy_addconfig(char *proxy, int proto, char *conf, namelist_t *list)
|
|
{
|
|
proxyrule_t *pr;
|
|
|
|
pr = calloc(1, sizeof(*pr));
|
|
if (pr != NULL) {
|
|
pr->pr_proto = proto;
|
|
pr->pr_proxy = proxy;
|
|
pr->pr_conf = conf;
|
|
pr->pr_names = list;
|
|
pr->pr_next = prules;
|
|
prules = pr;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
proxy_loadrules(int fd, ioctlfunc_t ioctlfunc, proxyrule_t *rules)
|
|
{
|
|
proxyrule_t *pr;
|
|
|
|
while ((pr = rules) != NULL) {
|
|
proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
|
|
pr->pr_conf, pr->pr_names);
|
|
rules = pr->pr_next;
|
|
free(pr->pr_conf);
|
|
free(pr);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
proxy_loadconfig(int fd, ioctlfunc_t ioctlfunc, char *proxy, int proto,
|
|
char *conf, namelist_t *list)
|
|
{
|
|
namelist_t *na;
|
|
ipfobj_t obj;
|
|
ap_ctl_t pcmd;
|
|
|
|
obj.ipfo_rev = IPFILTER_VERSION;
|
|
obj.ipfo_type = IPFOBJ_PROXYCTL;
|
|
obj.ipfo_size = sizeof(pcmd);
|
|
obj.ipfo_ptr = &pcmd;
|
|
|
|
while ((na = list) != NULL) {
|
|
if ((opts & OPT_REMOVE) != 0)
|
|
pcmd.apc_cmd = APC_CMD_DEL;
|
|
else
|
|
pcmd.apc_cmd = APC_CMD_ADD;
|
|
pcmd.apc_dsize = strlen(na->na_name) + 1;
|
|
pcmd.apc_data = na->na_name;
|
|
pcmd.apc_arg = na->na_value;
|
|
pcmd.apc_p = proto;
|
|
|
|
strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
|
|
pcmd.apc_label[APR_LABELLEN - 1] = '\0';
|
|
|
|
strncpy(pcmd.apc_config, conf, APR_LABELLEN);
|
|
pcmd.apc_config[APR_LABELLEN - 1] = '\0';
|
|
|
|
if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
|
|
if ((opts & OPT_DONOTHING) == 0) {
|
|
char msg[80];
|
|
|
|
snprintf(msg, sizeof(msg), "%d:ioctl(add/remove proxy rule)",
|
|
yylineNum);
|
|
ipf_perror_fd(fd, ioctlfunc, msg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
list = na->na_next;
|
|
free(na->na_name);
|
|
free(na);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
setifname(ipnat_t **np, int idx, char *name)
|
|
{
|
|
int pos;
|
|
|
|
pos = addname(np, name);
|
|
if (pos == -1)
|
|
return;
|
|
(*np)->in_ifnames[idx] = pos;
|
|
}
|
|
|
|
|
|
static int
|
|
addname(ipnat_t **np, char *name)
|
|
{
|
|
ipnat_t *n;
|
|
int nlen;
|
|
int pos;
|
|
|
|
nlen = strlen(name) + 1;
|
|
n = realloc(*np, (*np)->in_size + nlen);
|
|
if (*np == nattop)
|
|
nattop = n;
|
|
*np = n;
|
|
if (n == NULL)
|
|
return(-1);
|
|
if (n->in_pnext != NULL)
|
|
*n->in_pnext = n;
|
|
n->in_size += nlen;
|
|
pos = n->in_namelen;
|
|
n->in_namelen += nlen;
|
|
strcpy(n->in_names + pos, name);
|
|
n->in_names[n->in_namelen] = '\0';
|
|
return(pos);
|
|
}
|