diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2009-09-07 12:21:11 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2009-09-07 12:21:11 +0000 |
commit | 3f872ca110aa5111df3aa0096bee73d68ea560eb (patch) | |
tree | 063d08aba8b0ad6bc56524cddd7f0dd479e470b4 | |
parent | 5bcf2868d2ef7ccdb0e6684353054732140d44f0 (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.in | 6 | ||||
-rw-r--r-- | regress/sbin/pfctl/pfail19.ok | 6 | ||||
-rw-r--r-- | sbin/pfctl/parse.y | 134 | ||||
-rw-r--r-- | share/man/man5/pf.conf.5 | 37 |
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 ] |