From nobody Tue Dec 17 10:07:48 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4YCCDP4H32z5h0dw; Tue, 17 Dec 2024 10:07:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4YCCDN710pz49Tv; Tue, 17 Dec 2024 10:07:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1734430069; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1VogO9jXqU6DKpnYe7X9QNe6B3XWvpZnDCQ3K5RD3w0=; b=Z0/1z/kekwTBb9oFXiaG8LjB08CBJELd4dCsneIwOxdqXSIv8LmrAyZ2Ydwy/iSU5lUAMU UMphder60XkeMYb2O3Mudixej384WcD/eCACiyOQqY5Zzs26JoUQ1LGN/lYDE1bSLmnb/P +ozNzFskgLMHIgK4fa0yWoL5F/4m+va3EpcRhfS/yYprUw6p/kmv/Ar3YGWclgYLX+bnZv UxFfWyLJ89tPSUr03y77OYyl1jXpRpZy3PuYP5zu8JxY5BWGRTnCBRZsmfZUEx9+KGvQ4m UjammHNMA80q/SbTD38+OgGV+X5MkxcAZqb2SsxYC3KhBYscEjETSjrOAmoSaw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1734430069; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1VogO9jXqU6DKpnYe7X9QNe6B3XWvpZnDCQ3K5RD3w0=; b=gmCh1iQBZz/4Y5r7cBkeH5V+chGKrdhgtpEYvBG36SUh0skqPynHP/qz8vEJInZ+7LBbDw x5gk70rc466Ne+e+vWAFTDvCGtS0XaA0LSS0yruycWPl40u65jKl3r5nD/zALABHyRQf83 ExSgg/7+oThUlIyDRD59CWPAhltcmh720tjXexn6YHnOHFpmaioRAtG5Crh4LhTjX2xrZl tIOTaOvFeie9KULGwJA0BWZ47bqul32wFK/vuIk+pu8ZCGrYeiFx7J7wyWRmbojvCq3n0O 2/kMPyQtZmkI99sndsuWTnehDeS8iwkhUtss6rkHjwEX0uQdugKZUeFdwBke6A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1734430069; a=rsa-sha256; cv=none; b=oXjFcA75UF3H2RY62wq0AiEgdS64h2LUNjrl+M2SVoMNzPM/eFcuxmNwqeszMTdYVxgoEh SMh7Lfxq//1rBwCHcHoA4uCASNoIVLpmhPPMs7B6m41bjUXcubyeCDRQI3yJS7IXNmcFeZ XAesohKwdcTdZBFrXEO3UuWYYYDLcDu8OZqBZ8VtrCqSei51slRZ95Xv925pD/2cewSJOC wqnxO208m58HP4GjC5FTZ06IlynBr1ew1enCMrQ7V6AKRuDVKiGHyzwzp9sWSgVO4IJUPx QJ9dbVTSdnPQf6LBGCRwj/T77AVX+ZzcNDZhCyFgE0KwtbmV90V0sOFrzJkY8Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4YCCDN61SHzJtw; Tue, 17 Dec 2024 10:07:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 4BHA7msZ023651; Tue, 17 Dec 2024 10:07:48 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 4BHA7m2l023648; Tue, 17 Dec 2024 10:07:48 GMT (envelope-from git) Date: Tue, 17 Dec 2024 10:07:48 GMT Message-Id: <202412171007.4BHA7m2l023648@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: aa69fdf1542d - main - pfctl: change for af-to / NAT64 support. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: aa69fdf1542db0247e9b991002603fc2046bcfbc Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=aa69fdf1542db0247e9b991002603fc2046bcfbc commit aa69fdf1542db0247e9b991002603fc2046bcfbc Author: Kristof Provost AuthorDate: 2024-10-10 08:09:34 +0000 Commit: Kristof Provost CommitDate: 2024-12-17 10:07:13 +0000 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@ Obtained from: OpenBSD, claudio , 0cde32ce3f Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D47790 --- lib/libpfctl/libpfctl.c | 13 ++- lib/libpfctl/libpfctl.h | 7 +- sbin/pfctl/parse.y | 190 +++++++++++++++++++++++++++++++++++--------- sbin/pfctl/pf_print_state.c | 20 +++-- sbin/pfctl/pfctl.c | 38 ++++++--- sbin/pfctl/pfctl_parser.c | 19 ++++- sys/net/pfvar.h | 1 + sys/netpfil/pf/pf_nl.c | 1 + sys/netpfil/pf/pf_nl.h | 1 + 9 files changed, 225 insertions(+), 65 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 9fec8e77de26..2e4cdb91bad9 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -1285,6 +1285,7 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct snl_add_msg_attr_u8(nw, PF_RT_PRIO, r->prio); snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO, r->set_prio[0]); snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO_REPLY, r->set_prio[1]); + snl_add_msg_attr_u8(nw, PF_RT_NAF, r->naf); snl_add_msg_attr_ip6(nw, PF_RT_DIVERT_ADDRESS, &r->divert.addr.v6); snl_add_msg_attr_u16(nw, PF_RT_DIVERT_PORT, r->divert.port); @@ -1662,6 +1663,7 @@ static struct snl_attr_parser ap_getrule[] = { { .type = PF_RT_RCV_IFNAME, .off = _OUT(r.rcv_ifname), .arg = (void*)IFNAMSIZ, .cb = snl_attr_copy_string }, { .type = PF_RT_MAX_SRC_CONN, .off = _OUT(r.max_src_conn), .cb = snl_attr_get_uint32 }, { .type = PF_RT_RPOOL_NAT, .off = _OUT(r.nat), .arg = &pool_parser, .cb = snl_attr_get_nested }, + { .type = PF_RT_NAF, .off = _OUT(r.naf), .cb = snl_attr_get_uint8 }, }; static struct snl_field_parser fp_getrule[] = {}; #undef _OUT @@ -2770,7 +2772,7 @@ pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket) } int -pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which __unused) +pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which) { struct snl_writer nw; struct snl_errmsg_data e = {}; @@ -2794,6 +2796,7 @@ pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int whic snl_add_msg_attr_u8(&nw, PF_AA_AF, pa->af); snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, pa->anchor); snl_add_msg_attr_pool_addr(&nw, PF_AA_ADDR, &pa->addr); + snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which); if ((hdr = snl_finalize_msg(&nw)) == NULL) return (ENXIO); @@ -2817,7 +2820,7 @@ SNL_DECLARE_PARSER(get_addrs_parser, struct genlmsghdr, fp_get_addrs, ap_get_add int pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, - uint8_t r_action, const char *anchor, uint32_t *nr) + uint8_t r_action, const char *anchor, uint32_t *nr, int which) { struct snl_writer nw; struct snl_errmsg_data e = {}; @@ -2836,6 +2839,7 @@ pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, r_num); snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action); snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor); + snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which); if ((hdr = snl_finalize_msg(&nw)) == NULL) return (ENXIO); @@ -2879,7 +2883,8 @@ SNL_DECLARE_PARSER(get_addr_parser, struct genlmsghdr, fp_get_addr, ap_get_addr) int pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, - uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa) + uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa, + int which) { struct snl_writer nw; struct snl_errmsg_data e = {}; @@ -2899,6 +2904,7 @@ pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action); snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor); snl_add_msg_attr_u32(&nw, PF_AA_NR, nr); + snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which); if ((hdr = snl_finalize_msg(&nw)) == NULL) return (ENXIO); @@ -3023,6 +3029,7 @@ static struct snl_attr_parser ap_srcnode[] = { { .type = PF_SN_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint64 }, { .type = PF_SN_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint64 }, { .type = PF_SN_CONNECTION_RATE, .off = _OUT(conn_rate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested }, + { .type = PF_SN_NAF, .off = _OUT(naf), .cb = snl_attr_get_uint8 }, }; static struct snl_field_parser fp_srcnode[] = {}; #undef _OUT diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index 7b4aa0555758..79756286563b 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -256,6 +256,7 @@ struct pfctl_rule { uint8_t flush; uint8_t prio; uint8_t set_prio[2]; + sa_family_t naf; struct { struct pf_addr addr; @@ -407,6 +408,7 @@ struct pfctl_src_node { uint32_t states; uint32_t conn; sa_family_t af; + sa_family_t naf; uint8_t ruletype; uint64_t creation; uint64_t expire; @@ -528,9 +530,10 @@ int pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit); int pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket); int pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which); int pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, - uint8_t r_action, const char *anchor, uint32_t *nr); + uint8_t r_action, const char *anchor, uint32_t *nr, int which); int pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num, - uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa); + uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa, + int which); int pfctl_get_rulesets(struct pfctl_handle *h, const char *path, uint32_t *nr); int pfctl_get_ruleset(struct pfctl_handle *h, const char *path, uint32_t nr, struct pfioc_ruleset *rs); typedef int (*pfctl_get_srcnode_fn)(struct pfctl_src_node*, void *); diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index f198dcb0b054..fc24cbc238ba 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -222,6 +222,34 @@ struct node_qassign { char *pqname; }; +struct range { + int a; + int b; + int t; +}; +struct redirection { + struct node_host *host; + struct range rport; +}; + +static struct pool_opts { + int marker; +#define POM_TYPE 0x01 +#define POM_STICKYADDRESS 0x02 +#define POM_ENDPI 0x04 + u_int8_t opts; + int type; + int staticport; + struct pf_poolhashkey *key; + struct pf_mape_portset mape; +} pool_opts; + +struct redirspec { + struct redirection *rdr; + struct pool_opts pool_opts; + int af; +}; + static struct filter_opts { int marker; #define FOM_FLAGS 0x0001 @@ -231,7 +259,7 @@ static struct filter_opts { #define FOM_SRCTRACK 0x0010 #define FOM_MINTTL 0x0020 #define FOM_MAXMSS 0x0040 -#define FOM_AFTO 0x0080 /* not yet implemmented */ +#define FOM_AFTO 0x0080 #define FOM_SETTOS 0x0100 #define FOM_SCRUB_TCP 0x0200 #define FOM_SETPRIO 0x0400 @@ -274,6 +302,8 @@ static struct filter_opts { struct node_host *addr; u_int16_t port; } divert; + struct redirspec nat; + struct redirspec rdr; /* new-style scrub opts */ int nodf; int minttl; @@ -323,19 +353,6 @@ static struct table_opts { struct node_tinithead init_nodes; } table_opts; -static struct pool_opts { - int marker; -#define POM_TYPE 0x01 -#define POM_STICKYADDRESS 0x02 -#define POM_ENDPI 0x04 - u_int8_t opts; - int type; - int staticport; - struct pf_poolhashkey *key; - struct pf_mape_portset mape; - -} pool_opts; - static struct codel_opts codel_opts; static struct node_hfsc_opts hfsc_opts; static struct node_fairq_opts fairq_opts; @@ -365,6 +382,7 @@ void expand_eth_rule(struct pfctl_eth_rule *, struct node_host *, struct node_host *, const char *, const char *); void expand_rule(struct pfctl_rule *, struct node_if *, + struct node_host *, struct node_host *, struct node_proto *, struct node_os *, struct node_host *, struct node_port *, struct node_host *, struct node_port *, struct node_uid *, struct node_gid *, @@ -417,11 +435,7 @@ typedef struct { u_int16_t w; u_int16_t w2; } b; - struct range { - int a; - int b; - int t; - } range; + struct range range; struct node_if *interface; struct node_proto *proto; struct node_etherproto *etherproto; @@ -453,10 +467,7 @@ typedef struct { sa_family_t af; struct pf_poolhashkey *key; } route; - struct redirection { - struct node_host *host; - struct range rport; - } *redirection; + struct redirection *redirection; struct { int action; struct node_state_opt *options; @@ -517,7 +528,7 @@ int parseport(char *, struct range *r, int); %token STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS -%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE +%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO %token STRING %token NUMBER %token PORTBINARY @@ -1071,8 +1082,9 @@ 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, $5, NULL, $7, $8.src_os, + expand_rule(&r, $5, NULL, NULL, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, pf->astack[pf->asd + 1] ? pf->alast->name : $2); @@ -1095,7 +1107,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto decide_address_family($6.src.host, &r.af); decide_address_family($6.dst.host, &r.af); - expand_rule(&r, $3, NULL, $5, $6.src_os, + expand_rule(&r, $3, NULL, NULL, $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 0, 0, 0, 0, $2); free($2); @@ -1137,7 +1149,7 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto r.dst.port_op = $6.dst.port->op; } - expand_rule(&r, $3, NULL, $5, $6.src_os, + expand_rule(&r, $3, NULL, NULL, $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 0, 0, 0, 0, $2); free($2); @@ -1460,7 +1472,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts r.match_tag_not = $8.match_tag_not; r.rtableid = $8.rtableid; - expand_rule(&r, $4, NULL, $6, $7.src_os, + expand_rule(&r, $4, NULL, NULL, $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, NULL, NULL, NULL, NULL, ""); } @@ -1625,7 +1637,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { } if (h != NULL) - expand_rule(&r, j, NULL, NULL, NULL, h, + expand_rule(&r, j, NULL, NULL, NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ""); @@ -1647,7 +1659,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, NULL, NULL, NULL, NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ""); } else @@ -2414,6 +2426,19 @@ pfrule : action dir logquick interface route af proto fromto r.scrub_flags |= PFSTATE_SETPRIO; } + if ($9.marker & FOM_AFTO) { + if (!$6) { + yyerror("must indicate source address " + "family with af-to"); + YYERROR; + } + if ($6 == $9.nat.af) { + yyerror("incorrect address family " + "translation"); + YYERROR; + } + } + r.af = $6; if ($9.tag) if (strlcpy(r.tagname, $9.tag, @@ -2699,6 +2724,7 @@ pfrule : action dir logquick interface route af proto fromto decide_address_family($8.src.host, &r.af); decide_address_family($8.dst.host, &r.af); + r.naf = r.af; if ($5.rt) { if (!r.direction) { @@ -2801,9 +2827,14 @@ pfrule : action dir logquick interface route af proto fromto r.free_flags |= PFRULE_DN_IS_QUEUE; } - expand_rule(&r, $4, $5.host, $7, $8.src_os, - $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - $9.uid, $9.gid, $9.rcv, $9.icmpspec, ""); + if ($9.marker & FOM_AFTO) + r.naf = $9.nat.af; + + r.nat.opts = $9.nat.pool_opts.type; + r.nat.opts |= $9.nat.pool_opts.opts; + expand_rule(&r, $4, $5.host, $9.nat.rdr ? $9.nat.rdr->host : NULL, + $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, + $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, ""); } ; @@ -3017,6 +3048,64 @@ filter_opt : USER uids { filter_opts.marker |= FOM_SCRUB_TCP; filter_opts.marker |= $3.marker; } + | AFTO af FROM redirspec pool_opts { + if (filter_opts.nat.rdr) { + yyerror("cannot respecify af-to"); + YYERROR; + } + if ($2 == 0) { + yyerror("no address family specified"); + YYERROR; + } + if ($4->af && $4->af != $2) { + yyerror("af-to addresses must be in the " + "target address family"); + YYERROR; + } + filter_opts.nat.af = $2; + filter_opts.nat.rdr = calloc(1, sizeof(struct redirection)); + if (filter_opts.nat.rdr == NULL) + err(1, "af-to: calloc"); + filter_opts.nat.rdr->host = $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 redirspec pool_opts TO redirspec pool_opts { + if (filter_opts.nat.rdr) { + yyerror("cannot respecify af-to"); + YYERROR; + } + if ($2 == 0) { + yyerror("no address family specified"); + YYERROR; + } + if (($4->af && $4->af != $2) || + ($7->af && $7->af != $2)) { + yyerror("af-to addresses must be in the " + "target address family"); + YYERROR; + } + filter_opts.nat.af = $2; + filter_opts.nat.rdr = calloc(1, sizeof(struct redirection)); + if (filter_opts.nat.rdr == NULL) + err(1, "af-to: calloc"); + filter_opts.nat.rdr->host = $4; + memcpy(&filter_opts.nat.pool_opts, &$5, + sizeof(filter_opts.nat.pool_opts)); + filter_opts.rdr.af = $2; + filter_opts.rdr.rdr = calloc(1, sizeof(struct redirection)); + if (filter_opts.rdr.rdr == NULL) + err(1, "af-to: calloc"); + filter_opts.rdr.rdr->host = $7; + memcpy(&filter_opts.nat.pool_opts, &$8, + sizeof(filter_opts.nat.pool_opts)); + filter_opts.marker |= FOM_AFTO; + } | filter_sets ; @@ -4891,7 +4980,7 @@ natrule : nataction interface af proto fromto tag tagged rtable o = o->next; } - expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, + expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, NULL, $4, $5.src_os, $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 0, 0, 0, 0, ""); free($9); @@ -5407,6 +5496,10 @@ filter_consistent(struct pfctl_rule *r, int anchor_call) "must not be used on match rules"); problems++; } + if (r->naf != r->af) { + yyerror("af-to is not supported on match rules"); + problems++; + } } if (r->rpool.opts & PF_POOL_STICKYADDR && !r->keep_state) { yyerror("'sticky-address' requires 'keep state'"); @@ -6041,7 +6134,8 @@ expand_eth_rule(struct pfctl_eth_rule *r, void expand_rule(struct pfctl_rule *r, - struct node_if *interfaces, struct node_host *rpool_hosts, + struct node_if *interfaces, struct node_host *rdr_hosts, + struct node_host *nat_hosts, struct node_proto *protos, struct node_os *src_oses, struct node_host *src_hosts, struct node_port *src_ports, struct node_host *dst_hosts, struct node_port *dst_ports, @@ -6186,8 +6280,8 @@ expand_rule(struct pfctl_rule *r, r->os_fingerprint = PF_OSFP_ANY; } - TAILQ_INIT(&r->rpool.list); - for (h = rpool_hosts; h != NULL; h = h->next) { + TAILQ_INIT(&r->rdr.list); + for (h = rdr_hosts; h != NULL; h = h->next) { pa = calloc(1, sizeof(struct pf_pooladdr)); if (pa == NULL) err(1, "expand_rule: calloc"); @@ -6201,6 +6295,24 @@ expand_rule(struct pfctl_rule *r, pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); } + TAILQ_INIT(&r->nat.list); + for (h = nat_hosts; h != NULL; h = h->next) { + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "expand_rule: calloc"); + pa->addr = h->addr; + if (h->ifname != NULL) { + if (strlcpy(pa->ifname, h->ifname, + sizeof(pa->ifname)) >= + sizeof(pa->ifname)) + errx(1, "expand_rule: strlcpy"); + } else + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&r->nat.list, pa, entries); + } + + r->nat.proxy_port[0] = PF_NAT_PROXY_PORT_LOW; + r->nat.proxy_port[1] = PF_NAT_PROXY_PORT_HIGH; if (rule_consistent(r, anchor_call[0]) < 0 || error) yyerror("skipping rule due to errors"); @@ -6231,7 +6343,8 @@ expand_rule(struct pfctl_rule *r, FREE_LIST(struct node_uid, uids); FREE_LIST(struct node_gid, gids); FREE_LIST(struct node_icmp, icmp_types); - FREE_LIST(struct node_host, rpool_hosts); + FREE_LIST(struct node_host, rdr_hosts); + FREE_LIST(struct node_host, nat_hosts); if (!added) yyerror("rule expands to no valid combination"); @@ -6305,6 +6418,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 96da1e109fa8..e6495dfa4ca6 100644 --- a/sbin/pfctl/pf_print_state.c +++ b/sbin/pfctl/pf_print_state.c @@ -243,6 +243,8 @@ print_state(struct pfctl_state *s, int opts) int min, sec; sa_family_t af; uint8_t proto; + int afto = (s->key[PF_SK_STACK].af != s->key[PF_SK_WIRE].af); + int idx; #ifndef __NO_STRICT_ALIGNMENT struct pfctl_state_key aligned_key[2]; @@ -276,22 +278,26 @@ print_state(struct pfctl_state *s, int opts) else printf("%u ", proto); - print_host(&nk->addr[1], nk->port[1], af, opts); - if (PF_ANEQ(&nk->addr[1], &sk->addr[1], af) || + print_host(&nk->addr[1], nk->port[1], nk->af, opts); + if (nk->af != sk->af || PF_ANEQ(&nk->addr[1], &sk->addr[1], nk->af) || nk->port[1] != sk->port[1]) { + idx = afto ? 0 : 1; printf(" ("); - print_host(&sk->addr[1], sk->port[1], af, opts); + print_host(&sk->addr[idx], sk->port[idx], sk->af, + 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], af, opts); - if (PF_ANEQ(&nk->addr[0], &sk->addr[0], af) || + print_host(&nk->addr[0], nk->port[0], nk->af, opts); + if (nk->af != sk->af || PF_ANEQ(&nk->addr[0], &sk->addr[0], nk->af) || nk->port[0] != sk->port[0]) { + idx = afto ? 1 : 0; printf(" ("); - print_host(&sk->addr[0], sk->port[0], af, opts); + print_host(&sk->addr[idx], sk->port[idx], sk->af, + opts); printf(")"); } diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 4d77c7937a74..09d6774b324f 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -93,7 +93,7 @@ int pfctl_load_hostid(struct pfctl *, u_int32_t); int pfctl_load_reassembly(struct pfctl *, u_int32_t); int pfctl_load_syncookies(struct pfctl *, u_int8_t); int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int, - char *); + char *, int); void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int); void pfctl_print_rule_counters(struct pfctl_rule *, int); int pfctl_show_eth_rules(int, char *, int, enum pfctl_show, char *, int, int); @@ -956,7 +956,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts) int pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr, - u_int32_t ticket, int r_action, char *anchorname) + u_int32_t ticket, int r_action, char *anchorname, int which) { struct pfioc_pooladdr pp; struct pf_pooladdr *pa; @@ -964,14 +964,14 @@ pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr, int ret; memset(&pp, 0, sizeof(pp)); - if ((ret = pfctl_get_addrs(pfh, ticket, nr, r_action, anchorname, &mpnr)) != 0) { + if ((ret = pfctl_get_addrs(pfh, ticket, nr, r_action, anchorname, &mpnr, which)) != 0) { warnc(ret, "DIOCGETADDRS"); return (-1); } TAILQ_INIT(&pool->list); for (pnr = 0; pnr < mpnr; ++pnr) { - if ((ret = pfctl_get_addr(pfh, ticket, nr, r_action, anchorname, pnr, &pp)) != 0) { + if ((ret = pfctl_get_addr(pfh, ticket, nr, r_action, anchorname, pnr, &pp, which)) != 0) { warnc(ret, "DIOCGETADDR"); return (-1); } @@ -1303,7 +1303,11 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, } if (pfctl_get_pool(dev, &rule.rpool, - nr, ri.ticket, PF_SCRUB, path) != 0) + nr, ri.ticket, PF_SCRUB, path, PF_RDR) != 0) + goto error; + + if (pfctl_get_pool(dev, &rule.nat, + nr, ri.ticket, PF_SCRUB, path, PF_NAT) != 0) goto error; switch (format) { @@ -1334,7 +1338,11 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, } if (pfctl_get_pool(dev, &rule.rpool, - nr, ri.ticket, PF_PASS, path) != 0) + nr, ri.ticket, PF_PASS, path, PF_RDR) != 0) + goto error; + + if (pfctl_get_pool(dev, &rule.nat, + nr, ri.ticket, PF_PASS, path, PF_NAT) != 0) goto error; switch (format) { @@ -1491,7 +1499,10 @@ pfctl_show_nat(int dev, char *path, int opts, char *anchorname, int depth, return (-1); } if (pfctl_get_pool(dev, &rule.rpool, nr, - ri.ticket, nattype[i], path) != 0) + ri.ticket, nattype[i], path, PF_RDR) != 0) + return (-1); + if (pfctl_get_pool(dev, &rule.nat, nr, + ri.ticket, nattype[i], path, PF_NAT) != 0) return (-1); if (dotitle) { @@ -1692,11 +1703,6 @@ pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af, int which struct pf_pooladdr *pa; int ret; - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if ((ret = pfctl_begin_addrs(pf->h, &pf->paddr.ticket)) != 0) - errc(1, ret, "DIOCBEGINADDRS"); - } - pf->paddr.af = af; TAILQ_FOREACH(pa, &p->list, entries) { memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); @@ -2045,8 +2051,16 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) was_present = false; if ((pf->opts & PF_OPT_NOACTION) == 0) { + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if ((error = pfctl_begin_addrs(pf->h, + &pf->paddr.ticket)) != 0) + errc(1, error, "DIOCBEGINADDRS"); + } + if (pfctl_add_pool(pf, &r->rpool, r->af, PF_RDR)) return (1); + if (pfctl_add_pool(pf, &r->nat, r->naf ? r->naf : r->af, PF_NAT)) + return (1); error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket, pf->paddr.ticket); switch (error) { diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index d6d04ba2a7de..7cbca9a75af2 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -665,7 +665,7 @@ print_src_node(struct pfctl_src_node *sn, int opts) print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); printf(" -> "); 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, sn->conn, sn->conn_rate.count / 1000, (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); @@ -1237,8 +1237,21 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer } #endif } - if (!anchor_call[0] && (r->action == PF_NAT || - r->action == PF_BINAT || r->action == PF_RDR)) { + if (!anchor_call[0] && ! TAILQ_EMPTY(&r->nat.list) && + 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_NAT); + if (r->rdr.cur != NULL && !TAILQ_EMPTY(&r->rdr.list)) { + printf(" to "); + print_pool(&r->rdr, r->rdr.proxy_port[0], + r->rdr.proxy_port[1], r->naf ? r->naf : r->af, + PF_RDR); + } + } + if (!anchor_call[0] && + (r->action == PF_NAT || r->action == PF_BINAT || + r->action == PF_RDR)) { printf(" -> "); print_pool(&r->rpool, r->rpool.proxy_port[0], r->rpool.proxy_port[1], r->af, r->action); diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 094bc38c4a1b..e0ac9561f463 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -901,6 +901,7 @@ struct pf_ksrc_node { u_int32_t creation; u_int32_t expire; sa_family_t af; + sa_family_t naf; u_int8_t ruletype; struct mtx *lock; }; diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 3af27e11d27f..79d6c380e31e 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -1796,6 +1796,7 @@ pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt) nlattr_add_u32(nw, PF_SN_STATES, n->states); nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn); nlattr_add_u8(nw, PF_SN_AF, n->af); + nlattr_add_u8(nw, PF_SN_NAF, n->naf); nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype); nlattr_add_u64(nw, PF_SN_CREATION, secs - n->creation); diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h index 3af931978860..0f534bd623c4 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -419,6 +419,7 @@ enum pf_srcnodes_types_t { PF_SN_CREATION = 12, /* u64 */ PF_SN_EXPIRE = 13, /* u64 */ PF_SN_CONNECTION_RATE = 14, /* nested, pf_threshold */ + PF_SN_NAF = 15, /* u8 */ }; #ifdef _KERNEL