diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2011-10-13 18:30:55 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2011-10-13 18:30:55 +0000 |
commit | b5007cc677518df9758320bd9fa7aa6113ca8b53 (patch) | |
tree | 6e89857fedf03ae1fa17fc9be46b14caa27f38d2 | |
parent | d0ab30fdb97104766da99fa8da4eb3371d2d4163 (diff) |
pfctl change for af-to / NAT64 support.
The general syntax is:
pass in inet from any to 192.168.1.1 af-to inet6 from 2001::1 to 2001::2
In the NAT64 case the "to" is not needed in af-to and the IP is extraced
from the IPv6 dst (assuming a /64 prefix).
Again most work by sperreault@, mikeb@ and reyk@
OK mcbride@, put it in deraadt@
-rw-r--r-- | sbin/pfctl/parse.y | 84 | ||||
-rw-r--r-- | sbin/pfctl/pf_print_state.c | 22 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 26 |
3 files changed, 113 insertions, 19 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 8bf5604583f..b90334cb59d 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.609 2011/09/07 23:40:52 haesbaert Exp $ */ +/* $OpenBSD: parse.y,v 1.610 2011/10/13 18:30:54 claudio Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -217,6 +217,7 @@ struct redirspec { struct redirection *rdr; struct pool_opts pool_opts; int binat; + int af; }; struct filter_opts { @@ -228,6 +229,7 @@ struct filter_opts { #define FOM_SRCTRACK 0x0010 #define FOM_MINTTL 0x0020 #define FOM_MAXMSS 0x0040 +#define FOM_AFTO 0x0080 #define FOM_SETTOS 0x0100 #define FOM_SCRUB_TCP 0x0200 #define FOM_PRIO 0x0400 @@ -460,7 +462,7 @@ int parseport(char *, struct range *r, int); %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS -%token DIVERTTO DIVERTREPLY DIVERTPACKET NATTO RDRTO RECEIVEDON NE LE GE +%token DIVERTTO DIVERTREPLY DIVERTPACKET NATTO AFTO RDRTO RECEIVEDON NE LE GE %token <v.string> STRING %token <v.number> NUMBER %token <v.i> PORTBINARY @@ -897,6 +899,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); + r.naf = r.af; expand_rule(&r, 0, $5, NULL, NULL, NULL, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, @@ -1715,7 +1718,20 @@ pfrule : action dir logquick interface af proto fromto if ($8.marker & FOM_ONCE) r.rule_flag |= PFRULE_ONCE; + if ($8.marker & FOM_AFTO) { + if (!$5) { + yyerror("must indicate source address " + "family with af-to"); + YYERROR; + } + if ($5 == $8.nat.af) { + yyerror("incorrect address family " + "translation"); + YYERROR; + } + } r.af = $5; + if ($8.tag) if (strlcpy(r.tagname, $8.tag, PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { @@ -1999,6 +2015,7 @@ pfrule : action dir logquick interface af proto fromto decide_address_family($7.src.host, &r.af); decide_address_family($7.dst.host, &r.af); + r.naf = r.af; if ($8.route.rt) { if (!r.direction) { @@ -2265,6 +2282,55 @@ filter_opt : USER uids { memcpy(&filter_opts.nat.pool_opts, &$3, sizeof(filter_opts.nat.pool_opts)); } + | AFTO af FROM redirpool pool_opts { + if (filter_opts.nat.rdr) { + yyerror("cannot respecify af-to"); + YYERROR; + } + if ($2 == 0) { + yyerror("no address family specified"); + YYERROR; + } + if ($4->host->af && $4->host->af != $2) { + yyerror("af-to addresses must be in the " + "target address family"); + YYERROR; + } + filter_opts.nat.af = $2; + filter_opts.nat.rdr = $4; + memcpy(&filter_opts.nat.pool_opts, &$5, + sizeof(filter_opts.nat.pool_opts)); + filter_opts.rdr.rdr = + calloc(1, sizeof(struct redirection)); + bzero(&filter_opts.rdr.pool_opts, + sizeof(filter_opts.rdr.pool_opts)); + filter_opts.marker |= FOM_AFTO; + } + | AFTO af FROM redirpool pool_opts TO redirpool pool_opts { + if (filter_opts.nat.rdr) { + yyerror("cannot respecify af-to"); + YYERROR; + } + if ($2 == 0) { + yyerror("no address family specified"); + YYERROR; + } + if (($4->host->af && $4->host->af != $2) || + ($7->host->af && $7->host->af != $2)) { + yyerror("af-to addresses must be in the " + "target address family"); + YYERROR; + } + filter_opts.nat.af = $2; + filter_opts.nat.rdr = $4; + memcpy(&filter_opts.nat.pool_opts, &$5, + sizeof(filter_opts.nat.pool_opts)); + filter_opts.rdr.af = $2; + filter_opts.rdr.rdr = $7; + memcpy(&filter_opts.nat.pool_opts, &$8, + sizeof(filter_opts.nat.pool_opts)); + filter_opts.marker |= FOM_AFTO; + } | RDRTO redirpool pool_opts { if (filter_opts.rdr.rdr) { yyerror("cannot respecify rdr-to"); @@ -4131,6 +4197,10 @@ rule_consistent(struct pf_rule *r, int anchor_call) "must not be used on match rules"); problems++; } + if (r->nat.addr.type != PF_ADDR_NONE && r->naf != r->af) { + yyerror("af-to is not supported on match rules"); + problems++; + } } return (-problems); } @@ -4630,6 +4700,9 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, struct pf_rule_addr ra; int i = 0; + if (rs && rs->af) + r->naf = rs->af; + if (!rs || !rs->rdr || rs->rdr->host == NULL) { rpool->addr.type = PF_ADDR_NONE; return (0); @@ -4637,7 +4710,7 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, /* count matching addresses */ for (h = rs->rdr->host; h != NULL; h = h->next) { - if (!r->af || !h->af || h->af == r->af) { + if (!r->af || !h->af || rs->af || h->af == r->af) { i++; if (h->af && !r->af) r->af = h->af; @@ -4650,7 +4723,7 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, return (1); } else if (i == 1) { /* only one address */ for (h = rs->rdr->host; h != NULL; h = h->next) - if (!h->af || !r->af || r->af == h->af) + if (!h->af || !r->af || rs->af || r->af == h->af) break; rpool->addr = h->addr; if (!allow_if && h->ifname) { @@ -4672,7 +4745,7 @@ collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, return (1); } for (h = rs->rdr->host; h != NULL; h = h->next) { - if (r->af != h->af) + if (!rs->af && r->af != h->af) continue; if (h->addr.type != PF_ADDR_ADDRMASK && h->addr.type != PF_ADDR_NONE) { @@ -5117,6 +5190,7 @@ lookup(char *s) { /* this has to be sorted always */ static const struct keywords keywords[] = { + { "af-to", AFTO}, { "all", ALL}, { "allow-opts", ALLOWOPTS}, { "altq", ALTQ}, diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c index 657044da17a..63a76d3315b 100644 --- a/sbin/pfctl/pf_print_state.c +++ b/sbin/pfctl/pf_print_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.c,v 1.58 2010/11/12 13:14:41 claudio Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.59 2011/10/13 18:30:54 claudio Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -213,6 +213,8 @@ print_state(struct pfsync_state *s, int opts) struct pfsync_state_key *sk, *nk; struct protoent *p; int min, sec; + int afto = (s->key[PF_SK_STACK].af != s->key[PF_SK_WIRE].af); + int idx; if (s->direction == PF_OUT) { src = &s->src; @@ -235,24 +237,28 @@ print_state(struct pfsync_state *s, int opts) else printf("%u ", s->proto); - print_host(&nk->addr[1], nk->port[1], s->af, nk->rdomain, opts); - if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || + print_host(&nk->addr[1], nk->port[1], nk->af, nk->rdomain, opts); + if (nk->af != sk->af || PF_ANEQ(&nk->addr[1], &sk->addr[1], nk->af) || nk->port[1] != sk->port[1] || nk->rdomain != sk->rdomain) { + idx = afto ? 0 : 1; printf(" ("); - print_host(&sk->addr[1], sk->port[1], s->af, sk->rdomain, opts); + print_host(&sk->addr[idx], sk->port[idx], sk->af, + sk->rdomain, opts); printf(")"); } - if (s->direction == PF_OUT) + if (s->direction == PF_OUT || (afto && s->direction == PF_IN)) printf(" -> "); else printf(" <- "); - print_host(&nk->addr[0], nk->port[0], s->af, nk->rdomain, opts); - if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || + print_host(&nk->addr[0], nk->port[0], nk->af, nk->rdomain, opts); + if (nk->af != sk->af || PF_ANEQ(&nk->addr[0], &sk->addr[0], nk->af) || nk->port[0] != sk->port[0] || nk->rdomain != sk->rdomain) { + idx = afto ? 1 : 0; printf(" ("); - print_host(&sk->addr[0], sk->port[0], s->af, sk->rdomain, opts); + print_host(&sk->addr[idx], sk->port[idx], sk->af, + sk->rdomain, opts); printf(")"); } diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 10dc9c94f5e..2b92e133a16 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.280 2011/08/30 00:43:57 mikeb Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.281 2011/10/13 18:30:54 claudio Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -644,7 +644,8 @@ print_src_node(struct pf_src_node *sn, int opts) else printf(" ??? (%u) ", sn->type); aw.v.a.addr = sn->raddr; - print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); + print_addr(&aw, sn->naf ? sn->naf : sn->af, + opts & PF_OPT_VERBOSE2); } printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, @@ -1052,12 +1053,25 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) } if (r->divert_packet.port) printf(" divert-packet port %u", ntohs(r->divert_packet.port)); - if (!anchor_call[0] && r->nat.addr.type != PF_ADDR_NONE) { + + if (!anchor_call[0] && r->nat.addr.type != PF_ADDR_NONE && + r->naf != r->af) { + printf(" af-to %s from ", r->naf == AF_INET ? "inet" : "inet6"); + print_pool(&r->nat, r->nat.proxy_port[0], + r->nat.proxy_port[1], r->naf ? r->naf : r->af, + PF_POOL_NAT, verbose); + if (r->rdr.addr.type != PF_ADDR_NONE) { + printf(" to "); + print_pool(&r->rdr, r->rdr.proxy_port[0], + r->rdr.proxy_port[1], r->naf ? r->naf : r->af, + PF_POOL_RDR, verbose); + } + } else if (!anchor_call[0] && r->nat.addr.type != PF_ADDR_NONE) { printf (" nat-to "); print_pool(&r->nat, r->nat.proxy_port[0], - r->nat.proxy_port[1], r->af, PF_POOL_NAT, verbose); - } - if (!anchor_call[0] && r->rdr.addr.type != PF_ADDR_NONE) { + r->nat.proxy_port[1], r->naf ? r->naf : r->af, + PF_POOL_NAT, verbose); + } else if (!anchor_call[0] && r->rdr.addr.type != PF_ADDR_NONE) { printf (" rdr-to "); print_pool(&r->rdr, r->rdr.proxy_port[0], r->rdr.proxy_port[1], r->af, PF_POOL_RDR, verbose); |