efeb8bffe3
Convert ipfilter userland function declarations from K&R to ANSI. This syncs our function declarations with NetBSD hg commit 75edcd7552a0 (apply our changes). Though not copied from NetBSD, this change was partially inspired by NetBSD's work and inspired by style(9). Reviewed by: glebius (for #network) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D33595
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;
|
|
}
|