summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2009-09-07 12:21:11 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2009-09-07 12:21:11 +0000
commit3f872ca110aa5111df3aa0096bee73d68ea560eb (patch)
tree063d08aba8b0ad6bc56524cddd7f0dd479e470b4
parent5bcf2868d2ef7ccdb0e6684353054732140d44f0 (diff)
implement binat-to as a macro-like rule: a rule using the new binat-to
syntax will be expanded by the parser to a nat-to+rdr-to combination to be loaded into the kernel. this simplifies the migration from old binat rules and is less error-prone. feedback from many, manpage bits from jmc@ ok henning@
-rw-r--r--regress/sbin/pfctl/pfail19.in6
-rw-r--r--regress/sbin/pfctl/pfail19.ok6
-rw-r--r--sbin/pfctl/parse.y134
-rw-r--r--share/man/man5/pf.conf.537
4 files changed, 150 insertions, 33 deletions
diff --git a/regress/sbin/pfctl/pfail19.in b/regress/sbin/pfctl/pfail19.in
index f9107c9fdf1..5529d4c956f 100644
--- a/regress/sbin/pfctl/pfail19.in
+++ b/regress/sbin/pfctl/pfail19.in
@@ -1,10 +1,8 @@
# invalid table constructs
match in on lo0 from any to any rdr-to <sometable>
match out on lo0 from any to any nat-to <sometable>
-match out on lo0 from 1.1.1.1 to any nat-to <sometable> static-port
-match in on lo0 from any to <sometable> rdr-to 1.1.1.1
-match out on lo0 from <sometable> to any nat-to 1.1.1.1 static-port
-match in on lo0 from any to 1.1.1.1 rdr-to <sometable>
+match on lo0 from 1.1.1.1 to any binat-to <sometable>
+match on lo0 from <sometable> to any binat-to 1.1.1.1
pass in from any to any dup-to (lo0 <sometable>)
pass in from any to any route-to (lo0 <sometable>)
pass in from any to any reply-to (lo0 <sometable>)
diff --git a/regress/sbin/pfctl/pfail19.ok b/regress/sbin/pfctl/pfail19.ok
index ba4a4e7dcb8..332c0d07c16 100644
--- a/regress/sbin/pfctl/pfail19.ok
+++ b/regress/sbin/pfctl/pfail19.ok
@@ -1,2 +1,4 @@
-stdin:4: invalid use of table <sometable> as the redirect address of a binat rule
-stdin:5: invalid use of table <sometable> as the source address of a binat rule
+stdin:5: invalid use of table <sometable> as the source address of a binat-to rule
+stdin:5: invalid use of table <sometable> as the redirect address of a binat-to rule
+stdin:5: skipping rule due to errors
+stdin:5: rule expands to no valid combination
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 5ea316f83d3..c7c00b6b92d 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.566 2009/09/03 12:16:21 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.567 2009/09/07 12:21:09 reyk Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -226,6 +226,7 @@ struct pool_opts {
struct redirspec {
struct redirection *rdr;
struct pool_opts pool_opts;
+ int binat;
};
struct filter_opts {
@@ -342,7 +343,7 @@ void expand_label(char *, size_t, const char *, u_int8_t,
struct node_port *, u_int8_t);
int apply_redirspec(struct pf_pool *, struct pf_rule *,
struct redirspec *, int, struct node_port *);
-void expand_rule(struct pf_rule *, struct node_if *,
+void expand_rule(struct pf_rule *, int, struct node_if *,
struct redirspec *, struct redirspec *, struct node_proto *,
struct node_os *, struct node_host *, struct node_port *,
struct node_host *, struct node_port *, struct node_uid *,
@@ -446,7 +447,7 @@ int parseport(char *, struct range *r, int);
%token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
-%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT NODF
+%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINATTO NODF
%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
@@ -901,7 +902,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
decide_address_family($8.src.host, &r.af);
decide_address_family($8.dst.host, &r.af);
- expand_rule(&r, $5, NULL, NULL, $7, $8.src_os,
+ expand_rule(&r, 0, $5, NULL, NULL, $7, $8.src_os,
$8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
$9.uid, $9.gid, $9.icmpspec,
pf->astack[pf->asd + 1] ? pf->alast->name : $2);
@@ -1070,7 +1071,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
}
if (h != NULL)
- expand_rule(&r, j, NULL, NULL, NULL,
+ expand_rule(&r, 0, j, NULL, NULL, NULL,
NULL, h, NULL, NULL, NULL, NULL,
NULL, NULL, "");
@@ -1091,7 +1092,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
else
h = ifa_lookup(i->ifname, 0);
if (h != NULL)
- expand_rule(&r, NULL, NULL,
+ expand_rule(&r, 0, NULL, NULL,
NULL, NULL, NULL, h, NULL,
NULL, NULL, NULL, NULL,
NULL, "");
@@ -2094,7 +2095,7 @@ pfrule : action dir logquick interface af proto fromto
}
}
- expand_rule(&r, $4, &$8.nat, &$8.rdr, $6, $7.src_os,
+ expand_rule(&r, 0, $4, &$8.nat, &$8.rdr, $6, $7.src_os,
$7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
$8.uid, $8.gid, $8.icmpspec, "");
}
@@ -2238,7 +2239,7 @@ filter_opt : USER uids {
}
| NATTO redirpool pool_opts {
if (filter_opts.nat.rdr) {
- yyerror("cannot respecify nat-to");
+ yyerror("cannot respecify nat-to/binat-to");
YYERROR;
}
filter_opts.nat.rdr = $2;
@@ -2254,6 +2255,17 @@ filter_opt : USER uids {
memcpy(&filter_opts.rdr.pool_opts, &$3,
sizeof(filter_opts.rdr.pool_opts));
}
+ | BINATTO redirpool pool_opts {
+ if (filter_opts.nat.rdr) {
+ yyerror("cannot respecify nat-to/binat-to");
+ YYERROR;
+ }
+ filter_opts.nat.rdr = $2;
+ filter_opts.nat.binat = 1;
+ memcpy(&filter_opts.nat.pool_opts, &$3,
+ sizeof(filter_opts.nat.pool_opts));
+ filter_opts.nat.pool_opts.staticport = 1;
+ }
| FASTROUTE {
filter_opts.route.host = NULL;
filter_opts.route.rt = PF_FASTROUTE;
@@ -4505,7 +4517,7 @@ apply_redirspec(struct pf_pool *rpool, struct pf_rule *r, struct redirspec *rs,
void
-expand_rule(struct pf_rule *r, struct node_if *interfaces,
+expand_rule(struct pf_rule *r, int keeprule, struct node_if *interfaces,
struct redirspec *nat, struct redirspec *rdr,
struct node_proto *protos, struct node_os *src_oses,
struct node_host *src_hosts, struct node_port *src_ports,
@@ -4520,6 +4532,10 @@ expand_rule(struct pf_rule *r, struct node_if *interfaces,
char tagname[PF_TAG_NAME_SIZE];
char match_tagname[PF_TAG_NAME_SIZE];
u_int8_t flags, flagset, keep_state;
+ struct node_host *srch, *dsth;
+ struct redirspec binat;
+ struct pf_rule rb;
+ int dir = r->direction;
if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
errx(1, "expand_rule: strlcpy");
@@ -4642,6 +4658,37 @@ expand_rule(struct pf_rule *r, struct node_if *interfaces,
r->os_fingerprint = PF_OSFP_ANY;
}
+ if (nat && nat->rdr && nat->binat) {
+ if (disallow_table(src_host, "invalid use of table "
+ "<%s> as the source address of a binat-to rule") ||
+ disallow_alias(src_host, "invalid use of interface "
+ "(%s) as the source address of a binat-to rule")) {
+ error++;
+ } else if (src_host->af == AF_UNSPEC) {
+ yyerror("binat-to requires a specified "
+ "source and redirect address");
+ error++;
+ }
+ if (disallow_table(src_host, "invalid use of table "
+ "<%s> as the redirect address of a "
+ "binat-to rule") ||
+ disallow_alias(dst_host, "invalid use of interface "
+ "(%s) as the redirect address of a "
+ "binat-to rule") ||
+ disallow_urpf_failed(dst_host, "\"urpf-failed\" "
+ "is not permitted as a binat-to destination")) {
+ error++;
+ }
+ if (r->direction != PF_INOUT) {
+ yyerror("binat-to cannot be specified "
+ "with a direction");
+ error++;
+ }
+
+ /* first specify outbound NAT rule */
+ r->direction = PF_OUT;
+ }
+
error += apply_redirspec(&r->nat, r, nat, 0, dst_port);
error += apply_redirspec(&r->rdr, r, rdr, 1, dst_port);
@@ -4652,23 +4699,61 @@ expand_rule(struct pf_rule *r, struct node_if *interfaces,
pfctl_add_rule(pf, r, anchor_call);
added++;
}
+ r->direction = dir;
+
+ /* Generate binat's matching inbound rule */
+ if (!error && nat && nat->rdr && nat->binat) {
+ bcopy(r, &rb, sizeof(rb));
+
+ /* now specify inbound rdr rule */
+ rb.direction = PF_IN;
+
+ if ((srch = calloc(1, sizeof(*srch))) == NULL)
+ err(1, "expand_rule: calloc");
+ bcopy(src_host, srch, sizeof(*srch));
+ srch->ifname = NULL;
+ srch->next = NULL;
+ srch->tail = NULL;
+
+ if ((dsth = calloc(1, sizeof(*dsth))) == NULL)
+ err(1, "expand_rule: calloc");
+ bcopy(nat->rdr->host, dsth, sizeof(*dsth));
+ dsth->ifname = NULL;
+ dsth->next = NULL;
+ dsth->tail = NULL;
+
+ if ((binat.rdr =
+ calloc(1, sizeof(*binat.rdr))) == NULL)
+ err(1, "expand_rule: calloc");
+ bcopy(nat->rdr, binat.rdr, sizeof(*binat.rdr));
+ bcopy(&nat->pool_opts, &binat.pool_opts,
+ sizeof(binat.pool_opts));
+ binat.pool_opts.staticport = 0;
+ binat.rdr->host = srch;
+
+ expand_rule(&rb, 1, interface, NULL, &binat, proto,
+ src_os, dst_host, dst_port, dsth, src_port,
+ uid, gid, icmp_type, anchor_call);
+ }
))))))))));
- FREE_LIST(struct node_if, interfaces);
- FREE_LIST(struct node_proto, protos);
- FREE_LIST(struct node_host, src_hosts);
- FREE_LIST(struct node_port, src_ports);
- FREE_LIST(struct node_os, src_oses);
- FREE_LIST(struct node_host, dst_hosts);
- FREE_LIST(struct node_port, dst_ports);
- FREE_LIST(struct node_uid, uids);
- FREE_LIST(struct node_gid, gids);
- FREE_LIST(struct node_icmp, icmp_types);
- if (nat && nat->rdr)
- FREE_LIST(struct node_host, nat->rdr->host);
- if (rdr && rdr->rdr)
- FREE_LIST(struct node_host, rdr->rdr->host);
+ if (!keeprule) {
+ FREE_LIST(struct node_if, interfaces);
+ FREE_LIST(struct node_proto, protos);
+ FREE_LIST(struct node_host, src_hosts);
+ FREE_LIST(struct node_port, src_ports);
+ FREE_LIST(struct node_os, src_oses);
+ FREE_LIST(struct node_host, dst_hosts);
+ FREE_LIST(struct node_port, dst_ports);
+ FREE_LIST(struct node_uid, uids);
+ FREE_LIST(struct node_gid, gids);
+ FREE_LIST(struct node_icmp, icmp_types);
+ if (nat && nat->rdr)
+ FREE_LIST(struct node_host, nat->rdr->host);
+ if (rdr && rdr->rdr)
+ FREE_LIST(struct node_host, rdr->rdr->host);
+ }
if (!added)
yyerror("rule expands to no valid combination");
@@ -4743,8 +4828,7 @@ lookup(char *s)
{ "antispoof", ANTISPOOF},
{ "any", ANY},
{ "bandwidth", BANDWIDTH},
- { "binat", BINAT},
- { "binat-anchor", BINATANCHOR},
+ { "binat-to", BINATTO},
{ "bitmask", BITMASK},
{ "block", BLOCK},
{ "block-policy", BLOCKPOLICY},
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 238e5d79dcd..db3119b74f2 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pf.conf.5,v 1.454 2009/09/07 11:28:34 jmc Exp $
+.\" $OpenBSD: pf.conf.5,v 1.455 2009/09/07 12:21:10 reyk Exp $
.\"
.\" Copyright (c) 2002, Daniel Hartmeier
.\" All rights reserved.
@@ -754,6 +754,16 @@ and correctly direct return traffic for that connection.
.Pp
Different types of translation are possible with pf:
.Bl -tag -width xxxxxxxx
+.It Ar binat-to
+A
+.Ar binat-to
+rule specifies a bidirectional mapping between an external IP
+netblock and an internal IP netblock.
+It expands to an outbound
+.Ar nat-to
+rule and an inbound
+.Ar rdr-to
+rule.
.It Ar nat-to
A
.Ar nat-to
@@ -792,6 +802,9 @@ implicitly in the case of
options and explicitly in the case of
.Ar rdr-to
ones.
+Port numbers are never translated with a
+.Ar binat-to
+rule.
.Pp
Translation options apply only to packets that pass through the specified
interface, and if no interface is specified, translation is applied
@@ -2553,6 +2566,24 @@ match out on $ext_if inet from any to any nat-to 192.0.2.16/28 \e
match in on $ext_if proto tcp from any to any port 80 \e
rdr-to { 10.1.2.155, 10.1.2.160, 10.1.2.161 } round-robin
.Ed
+.Pp
+The bidirectional address translation example uses a single
+.Ar binat-to
+rule that expands to a
+.Ar nat-to
+and an
+.Ar rdr-to
+rule.
+.Bd -literal -offset 4n
+pass on $ext_if from 10.1.2.120 to any binat-to 192.0.2.17
+.Ed
+.Pp
+The previous example is identical to the following set of rules:
+.Bd -literal -offset 4n
+pass out on $ext_if inet from 10.1.2.120 to any \e
+ nat-to 192.0.2.17 static-port
+pass in on $ext_if inet from any to 192.0.2.17 rdr-to 10.1.2.120
+.Ed
.Sh GRAMMAR
Syntax for
.Nm
@@ -2594,10 +2625,12 @@ filteropt = user | group | flags | icmp-type | icmp6-type |
"label" string | "tag" string | [ ! ] "tagged" string |
"queue" ( string | "(" string [ [ "," ] string ] ")" ) |
"rtable" number | "probability" number"%" |
+ "binat-to" ( redirhost | "{" redirhost-list "}" )
+ [ portspec ] [ pooltype ] |
"rdr-to" ( redirhost | "{" redirhost-list "}" )
[ portspec ] [ pooltype ] |
"nat-to" ( redirhost | "{" redirhost-list "}" )
- [ portspec ] [ pooltype ] [ "static-port" ]
+ [ portspec ] [ pooltype ] [ "static-port" ] |
[ "fastroute" | route ]
scrubopts = scrubopt [ [ "," ] scrubopts ]