From nobody Fri Jan 24 10:25:03 2025 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 4YfYpm3RpRz5lC6s; Fri, 24 Jan 2025 10:25:04 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4YfYpm14CYz3tRm; Fri, 24 Jan 2025 10:25:04 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1737714304; 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=OmH2TApBYr2cvIXA1GaZW5EjxyW8SVn0jsESNDM+Qyo=; b=So7o0DFJwYn5KcfWZM3GJ/srK2w4SRNXHHILhxdztnNnClK3Vnz+E1vVnZJGSjNNY3jZLV 1LZqhflTFqbcIsVaNKvn5xVJWUl3StOvRzqTV8IE8YiSwHSp67PMwa2TZpXVWqxoIGo8Xd 5t8JhvLU9a0z8w5gDATQMSZG1dxKrzWjOCALj4GHRB4inLVYtsPvaMwghVh4BWT+kLQDh2 XUH60LVovfEdJcptf4J2ugGV567F6UM2I0Cpuyah1pHNgUhUNwjdMTV+VqLDYSYn5OALJF kLQKSuXiitj5WhlX9tA78gkiwRJolHm6GaGvW95Fae6nb4BMup2hc7U4ZNvzwg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1737714304; 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=OmH2TApBYr2cvIXA1GaZW5EjxyW8SVn0jsESNDM+Qyo=; b=bfUqkR7g+ZVkfBEUeQHopwQ9Q0qqT0PWVBzidlbbdLvr4ZgAWj8jJ9ChHLTrhKfAQ1pUbC TZ5EpagSV5ySSXefYQVq+Vosawc1xhmD8CJlL4vd0aULClzkzkHMP848CLU0CtevfBfvxd s4Qb1y3xz/ZhcHOHxoGCcJJ30QdawnC6p1LSMfE5nhtfi34d1To557aZVnmYZsj9HBsCsb peMPxoDT0VBLm+lETqr1k11YHCoeyB4kaN/VjRB7nq2Q12k9TSvQdgzJYrsjKUAZCgB2Zd eaiaeUousm5/lUS6FlR6Q3mcuwf8vXPLMiogzh4h7ZaUQ83NnPDmIhP2cuNV+A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1737714304; a=rsa-sha256; cv=none; b=D6o33OwFDteiu4Cga9wC+mRv7EUYCabyAFopV9cqIzAr6VZoR9yiYYF4JDU2jBjh7wc4H5 IJ6SULK+Le2zTdRo5M7sdkwEiAB3hQ4nG9M5h3E/GPPlVygU4NhOS2RbhayAABcawQldwt Mfqz3RWmIkM7MXNYHgd4Km/z73iCt/dOd6uN7Qg+nJ8Pxx8lhIDyS3VeFj9jXKdpw5rGkK H3qYThnfzVrX08dq2gtuGSotwQdGR5CL322olSk5TY8AQYKEVh1UAO4ceGvSSfserD6375 yb3FS5QwJ1oSr4wJjJLsllJSZoRxwjozs6rBZGCVgDMj6O6qFu2iW1L0dqx23A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none 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 4YfYpm0QRXz5qP; Fri, 24 Jan 2025 10:25:04 +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 50OAP3YY038465; Fri, 24 Jan 2025 10:25:03 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 50OAP3gf038462; Fri, 24 Jan 2025 10:25:03 GMT (envelope-from git) Date: Fri, 24 Jan 2025 10:25:03 GMT Message-Id: <202501241025.50OAP3gf038462@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: 0972294ef034 - main - pf: add a dedicated pf pool for route options 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: 0972294ef034d92f59857b8312dd2e1e3a7adc9c Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=0972294ef034d92f59857b8312dd2e1e3a7adc9c commit 0972294ef034d92f59857b8312dd2e1e3a7adc9c Author: Kristof Provost AuthorDate: 2025-01-20 17:25:37 +0000 Commit: Kristof Provost CommitDate: 2025-01-24 10:20:30 +0000 pf: add a dedicated pf pool for route options As suggested by henning. Which unbreaks ie route-to after the recent pf changes. With much help debugging and pointing out of missing bits from claudio@ ok claudio@ "looks good" henning@ Obtained from: OpenBSD, jsg , 7fa5c09028 Sponsored by: Rubicon Communications, LLC ("Netgate") --- lib/libpfctl/libpfctl.c | 2 + lib/libpfctl/libpfctl.h | 1 + sbin/pfctl/parse.y | 95 +++++++++++++++++++++++++++------------------ sbin/pfctl/pfctl.c | 16 ++++++++ sbin/pfctl/pfctl_optimize.c | 7 ++++ sbin/pfctl/pfctl_parser.c | 1 + sys/net/pfvar.h | 3 +- sys/netpfil/pf/if_pfsync.c | 8 +++- sys/netpfil/pf/pf.c | 11 +++++- sys/netpfil/pf/pf.h | 2 +- sys/netpfil/pf/pf_ioctl.c | 53 +++++++++++++++++++------ sys/netpfil/pf/pf_nl.c | 2 + sys/netpfil/pf/pf_nl.h | 1 + 13 files changed, 147 insertions(+), 55 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index f0708c8f0439..2297b24d37a0 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -1227,6 +1227,7 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct snl_add_msg_attr_string(nw, PF_RT_OVERLOAD_TBLNAME, r->overload_tblname); snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RDR, &r->rdr); snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_NAT, &r->nat); + snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RT, &r->route); snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint); snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid); snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout); @@ -1661,6 +1662,7 @@ static struct snl_attr_parser ap_getrule[] = { { .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 }, + { .type = PF_RT_RPOOL_RT, .off = _OUT(r.route), .arg = &pool_parser, .cb = snl_attr_get_nested }, }; #undef _OUT SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, snl_f_p_empty, ap_getrule); diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index 14ea06fd151a..2532894ffa21 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -180,6 +180,7 @@ struct pfctl_rule { struct pfctl_pool rpool; struct pfctl_pool rdr; }; + struct pfctl_pool route; uint64_t evaluations; uint64_t packets[2]; diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index ab74d2dd57ab..830581c57f9c 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -304,6 +304,7 @@ static struct filter_opts { } divert; struct redirspec nat; struct redirspec rdr; + struct redirspec rroute; /* new-style scrub opts */ int nodf; int minttl; @@ -382,11 +383,12 @@ 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 redirspec *, struct redirspec *, 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 *, - struct node_if *, struct node_icmp *, const char *); + struct redirspec *, struct redirspec *, struct redirspec *, + struct node_host *, 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 *, struct node_if *, + struct node_icmp *, const char *); int expand_altq(struct pf_altq *, struct node_if *, struct node_queue *, struct node_queue_bw bwspec, struct node_queue_opt *); @@ -1080,9 +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); - expand_rule(&r, $5, NULL, NULL, 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, + expand_rule(&r, $5, NULL, NULL, NULL, NULL, 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); free($2); pf->astack[pf->asd + 1] = NULL; @@ -1103,9 +1105,9 @@ 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, NULL, NULL, NULL, $5, $6.src_os, - $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, - 0, 0, 0, 0, $2); + expand_rule(&r, $3, NULL, NULL, NULL, NULL, 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); } | RDRANCHOR string interface af proto fromto rtable { @@ -1145,9 +1147,9 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto r.dst.port_op = $6.dst.port->op; } - expand_rule(&r, $3, NULL, NULL, NULL, NULL, $5, $6.src_os, - $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, - 0, 0, 0, 0, $2); + expand_rule(&r, $3, NULL, NULL, NULL, NULL, 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); } | BINATANCHOR string interface af proto fromto rtable { @@ -1468,9 +1470,9 @@ 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, NULL, NULL, NULL, $6, $7.src_os, - $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, - NULL, NULL, NULL, NULL, ""); + expand_rule(&r, $4, NULL, NULL, NULL, NULL, NULL, NULL, + $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host, + $7.dst.port, NULL, NULL, NULL, NULL, ""); } ; @@ -1633,8 +1635,8 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { } if (h != NULL) - expand_rule(&r, j, NULL, NULL, NULL, NULL, NULL, NULL, h, - NULL, NULL, NULL, NULL, NULL, + expand_rule(&r, j, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ""); if ((i->ifa_flags & IFF_LOOPBACK) == 0) { @@ -1656,7 +1658,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { h = ifa_lookup(i->ifname, 0); if (h != NULL) expand_rule(&r, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, h, NULL, NULL, + NULL, NULL, NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ""); } else free(hh); @@ -2726,9 +2728,9 @@ pfrule : action dir logquick interface route af proto fromto YYERROR; } r.rt = $5.rt; - r.rdr.opts = $5.pool_opts; + r.route.opts = $5.pool_opts; if ($5.key != NULL) - memcpy(&r.rdr.key, $5.key, + memcpy(&r.route.key, $5.key, sizeof(struct pf_poolhashkey)); } if (r.rt) { @@ -2739,26 +2741,26 @@ pfrule : action dir logquick interface route af proto fromto "matching address family found."); YYERROR; } - if ((r.rdr.opts & PF_POOL_TYPEMASK) == + if ((r.route.opts & PF_POOL_TYPEMASK) == PF_POOL_NONE && ($5.host->next != NULL || $5.host->addr.type == PF_ADDR_TABLE || DYNIF_MULTIADDR($5.host->addr))) - r.rdr.opts |= PF_POOL_ROUNDROBIN; - if ((r.rdr.opts & PF_POOL_TYPEMASK) != + r.route.opts |= PF_POOL_ROUNDROBIN; + if ((r.route.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN && disallow_table($5.host, "tables are only " "supported in round-robin routing pools")) YYERROR; - if ((r.rdr.opts & PF_POOL_TYPEMASK) != + if ((r.route.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN && disallow_alias($5.host, "interface (%s) " "is only supported in round-robin " "routing pools")) YYERROR; if ($5.host->next != NULL) { - if ((r.rdr.opts & PF_POOL_TYPEMASK) != + if ((r.route.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { - yyerror("r.rdr.opts must " + yyerror("r.route.opts must " "be PF_POOL_ROUNDROBIN"); YYERROR; } @@ -2833,7 +2835,8 @@ pfrule : action dir logquick interface route af proto fromto YYERROR; } - expand_rule(&r, $4, &$9.nat, &$9.rdr, $5.host, $9.nat.rdr ? $9.nat.rdr->host : NULL, + expand_rule(&r, $4, &$9.nat, &$9.rdr, &$9.rroute, + NULL, $9.nat.rdr ? $9.nat.rdr->host : NULL, $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, ""); } @@ -4989,8 +4992,9 @@ natrule : nataction interface af proto fromto tag tagged rtable o = o->next; } - expand_rule(&r, $2, NULL, NULL, $9 == NULL ? NULL : $9->host, - NULL, $4, $5.src_os, $5.src.host, $5.src.port, $5.dst.host, + expand_rule(&r, $2, NULL, NULL, NULL, + $9 == NULL ? NULL : $9->host, NULL, NULL, $4, + $5.src_os, $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 0, 0, 0, 0, ""); free($9); } @@ -6149,13 +6153,13 @@ expand_eth_rule(struct pfctl_eth_rule *r, void expand_rule(struct pfctl_rule *r, struct node_if *interfaces, struct redirspec *nat, - struct redirspec *rdr, 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, - struct node_uid *uids, struct node_gid *gids, struct node_if *rcv, - struct node_icmp *icmp_types, const char *anchor_call) + struct redirspec *rdr, struct redirspec *route, + struct node_host *rdr_hosts, struct node_host *nat_hosts, + struct node_host *route_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, struct node_uid *uids, struct node_gid *gids, + struct node_if *rcv, struct node_icmp *icmp_types, const char *anchor_call) { sa_family_t af = r->af; int added = 0, error = 0; @@ -6331,6 +6335,21 @@ expand_rule(struct pfctl_rule *r, pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&r->nat.list, pa, entries); } + TAILQ_INIT(&r->route.list); + for (h = route_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->route.list, pa, entries); + } r->nat.proxy_port[0] = PF_NAT_PROXY_PORT_LOW; r->nat.proxy_port[1] = PF_NAT_PROXY_PORT_HIGH; diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 7b54bc1c7c7a..ec07a5da999c 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1310,6 +1310,10 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, nr, ri.ticket, PF_SCRUB, path, PF_NAT) != 0) goto error; + if (pfctl_get_pool(dev, &rule.route, + nr, ri.ticket, PF_SCRUB, path, PF_RT) != 0) + goto error; + switch (format) { case PFCTL_SHOW_LABELS: break; @@ -1325,6 +1329,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, } pfctl_clear_pool(&rule.rdr); pfctl_clear_pool(&rule.nat); + pfctl_clear_pool(&rule.route); } ret = pfctl_get_rules_info_h(pfh, &ri, PF_PASS, path); if (ret != 0) { @@ -1346,6 +1351,10 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, nr, ri.ticket, PF_PASS, path, PF_NAT) != 0) goto error; + if (pfctl_get_pool(dev, &rule.route, + nr, ri.ticket, PF_PASS, path, PF_RT) != 0) + goto error; + switch (format) { case PFCTL_SHOW_LABELS: { bool show = false; @@ -1506,6 +1515,9 @@ pfctl_show_nat(int dev, char *path, int opts, char *anchorname, int depth, if (pfctl_get_pool(dev, &rule.nat, nr, ri.ticket, nattype[i], path, PF_NAT) != 0) return (-1); + if (pfctl_get_pool(dev, &rule.route, nr, + ri.ticket, nattype[i], path, PF_RT) != 0) + return (-1); if (dotitle) { pfctl_print_title("TRANSLATION RULES:"); @@ -1761,6 +1773,8 @@ pfctl_append_rule(struct pfctl *pf, struct pfctl_rule *r, pfctl_move_pool(&r->rdr, &rule->rdr); TAILQ_INIT(&rule->nat.list); pfctl_move_pool(&r->nat, &rule->nat); + TAILQ_INIT(&rule->route.list); + pfctl_move_pool(&r->route, &rule->route); TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); return (0); @@ -2065,6 +2079,8 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth) return (1); if (pfctl_add_pool(pf, &r->nat, r->naf ? r->naf : r->af, PF_NAT)) return (1); + if (pfctl_add_pool(pf, &r->route, r->af, PF_RT)) + return (1); error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket, pf->paddr.ticket); switch (error) { diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c index a97664e0c929..7817bcfd284a 100644 --- a/sbin/pfctl/pfctl_optimize.c +++ b/sbin/pfctl/pfctl_optimize.c @@ -137,6 +137,7 @@ static struct pf_rule_field { PF_RULE_FIELD(flush, BREAK), PF_RULE_FIELD(rdr, BREAK), PF_RULE_FIELD(nat, BREAK), + PF_RULE_FIELD(route, BREAK), PF_RULE_FIELD(logif, BREAK), /* @@ -303,6 +304,12 @@ pfctl_optimize_ruleset(struct pfctl *pf, struct pfctl_ruleset *rs) } else bzero(&por->por_rule.nat, sizeof(por->por_rule.nat)); + if (TAILQ_FIRST(&r->route.list) != NULL) { + TAILQ_INIT(&por->por_rule.route.list); + pfctl_move_pool(&r->route, &por->por_rule.route); + } else + bzero(&por->por_rule.route, + sizeof(por->por_rule.route)); TAILQ_INSERT_TAIL(&opt_queue, por, por_entry); } diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 85f1797e58e1..df76f8312cf3 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -943,6 +943,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" dup-to"); printf(" "); print_pool(&r->rdr, 0, 0, r->af, PF_PASS); + print_pool(&r->route, 0, 0, r->af, PF_PASS); } if (r->af) { if (r->af == AF_INET) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 6e9418f59aef..e50fbc96a8ba 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -787,6 +787,7 @@ struct pf_krule { TAILQ_ENTRY(pf_krule) entries; struct pf_kpool nat; struct pf_kpool rdr; + struct pf_kpool route; struct pf_counter_u64 evaluations; struct pf_counter_u64 packets[2]; @@ -2217,7 +2218,7 @@ VNET_DECLARE(struct unrhdr64, pf_stateid); TAILQ_HEAD(pf_altqqueue, pf_altq); VNET_DECLARE(struct pf_altqqueue, pf_altqs[4]); #define V_pf_altqs VNET(pf_altqs) -VNET_DECLARE(struct pf_kpalist, pf_pabuf[2]); +VNET_DECLARE(struct pf_kpalist, pf_pabuf[3]); #define V_pf_pabuf VNET(pf_pabuf) VNET_DECLARE(u_int32_t, ticket_altqs_active); diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c index 60bfb05d1570..98a2367b79b0 100644 --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -574,6 +574,12 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) * from the local ruleset. */ if (r != &V_pf_default_rule) { + struct pf_kpool *pool = &r->route; + + /* Backwards compatibility. */ + if (TAILQ_EMPTY(&pool->list)) + pool = &r->rdr; + /* * The ruleset is identical, try to recover. If the rule * has a redirection pool with a single interface, there @@ -582,7 +588,7 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version) * give up, as we can't be sure that we will pick the * same one as the pfsync peer did. */ - rpool_first = TAILQ_FIRST(&(r->rdr.list)); + rpool_first = TAILQ_FIRST(&(pool->list)); if ((rpool_first == NULL) || (TAILQ_NEXT(rpool_first, entries) != NULL)) { DPFPRINTF(PF_DEBUG_MISC, diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 83eca735d2bb..00d6583234c7 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -164,7 +164,7 @@ SDT_PROBE_DEFINE2(pf, purge, state, rowcount, "int", "size_t"); /* state tables */ VNET_DEFINE(struct pf_altqqueue, pf_altqs[4]); -VNET_DEFINE(struct pf_kpalist, pf_pabuf[2]); +VNET_DEFINE(struct pf_kpalist, pf_pabuf[3]); VNET_DEFINE(struct pf_altqqueue *, pf_altqs_active); VNET_DEFINE(struct pf_altqqueue *, pf_altq_ifs_active); VNET_DEFINE(struct pf_altqqueue *, pf_altqs_inactive); @@ -1267,6 +1267,7 @@ pf_initialize(void) TAILQ_INIT(&V_pf_altqs[3]); TAILQ_INIT(&V_pf_pabuf[0]); TAILQ_INIT(&V_pf_pabuf[1]); + TAILQ_INIT(&V_pf_pabuf[2]); V_pf_altqs_active = &V_pf_altqs[0]; V_pf_altq_ifs_active = &V_pf_altqs[1]; V_pf_altqs_inactive = &V_pf_altqs[2]; @@ -5900,6 +5901,12 @@ nextrule: if (r->rt) { struct pf_ksrc_node *sn = NULL; struct pf_srchash *snh = NULL; + struct pf_kpool *pool = &r->route; + + /* Backwards compatibility. */ + if (TAILQ_EMPTY(&pool->list)) + pool = &r->rdr; + /* * Set act.rt here instead of in pf_rule_to_actions() because * it is applied only from the last pass rule. @@ -5907,7 +5914,7 @@ nextrule: pd->act.rt = r->rt; /* Don't use REASON_SET, pf_map_addr increases the reason counters */ reason = pf_map_addr_sn(pd->af, r, pd->src, &pd->act.rt_addr, - &pd->act.rt_kif, NULL, &sn, &snh, &r->rdr); + &pd->act.rt_kif, NULL, &sn, &snh, pool); if (reason != 0) goto cleanup; } diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h index 5de85c1fe7ef..24249ead6ba2 100644 --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -49,7 +49,7 @@ enum { PF_INOUT, PF_IN, PF_OUT }; enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT, PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER, - PF_MATCH, PF_AFRT }; + PF_MATCH, PF_AFRT, PF_RT }; enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT, PF_RULESET_BINAT, PF_RULESET_RDR, PF_RULESET_MAX }; enum { PF_OP_NONE, PF_OP_IRG, PF_OP_EQ, PF_OP_NE, PF_OP_LT, diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index d206a9f8da43..340e7c25a501 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -436,7 +436,7 @@ pf_get_kpool(const char *anchor, u_int32_t ticket, u_int8_t rule_action, struct pf_krule *rule; int rs_num; - MPASS(which == PF_RDR || which == PF_NAT); + MPASS(which == PF_RDR || which == PF_NAT || which == PF_RT); ruleset = pf_find_kruleset(anchor); if (ruleset == NULL) @@ -470,10 +470,16 @@ pf_get_kpool(const char *anchor, u_int32_t ticket, u_int8_t rule_action, if (rule == NULL) return (NULL); - if (which == PF_NAT) - return (&rule->nat); - else + switch (which) { + case PF_RDR: return (&rule->rdr); + case PF_NAT: + return (&rule->nat); + case PF_RT: + return (&rule->route); + default: + panic("Unknow pool type %d", which); + } } static void @@ -612,6 +618,7 @@ pf_free_rule(struct pf_krule *rule) pf_kanchor_remove(rule); pf_empty_kpool(&rule->rdr.list); pf_empty_kpool(&rule->nat.list); + pf_empty_kpool(&rule->route.list); pf_krule_free(rule); } @@ -1832,6 +1839,7 @@ pf_krule_alloc(void) rule = malloc(sizeof(struct pf_krule), M_PFRULE, M_WAITOK | M_ZERO); mtx_init(&rule->nat.mtx, "pf_krule_nat_pool", NULL, MTX_DEF); mtx_init(&rule->rdr.mtx, "pf_krule_rdr_pool", NULL, MTX_DEF); + mtx_init(&rule->route.mtx, "pf_krule_route_pool", NULL, MTX_DEF); rule->timestamp = uma_zalloc_pcpu(pf_timestamp_pcpu_zone, M_WAITOK | M_ZERO); return (rule); @@ -1871,6 +1879,7 @@ pf_krule_free(struct pf_krule *rule) mtx_destroy(&rule->nat.mtx); mtx_destroy(&rule->rdr.mtx); + mtx_destroy(&rule->route.mtx); free(rule, M_PFRULE); } @@ -2106,6 +2115,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, rule->cpid = pid; TAILQ_INIT(&rule->rdr.list); TAILQ_INIT(&rule->nat.list); + TAILQ_INIT(&rule->route.list); PF_CONFIG_LOCK(); PF_RULES_WLOCK(); @@ -2203,7 +2213,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, (rule->set_prio[0] > PF_PRIO_MAX || rule->set_prio[1] > PF_PRIO_MAX)) error = EINVAL; - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries) if (pa->addr.type == PF_ADDR_TABLE) { pa->addr.p.tbl = pfr_attach_table(ruleset, @@ -2225,10 +2235,12 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, pf_mv_kpool(&V_pf_pabuf[0], &rule->nat.list); pf_mv_kpool(&V_pf_pabuf[1], &rule->rdr.list); + pf_mv_kpool(&V_pf_pabuf[2], &rule->route.list); if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || (rule->action == PF_BINAT)) && rule->anchor == NULL) || (rule->rt > PF_NOPFROUTE)) && - (TAILQ_FIRST(&rule->rdr.list) == NULL)) + (TAILQ_FIRST(&rule->rdr.list) == NULL && + TAILQ_FIRST(&rule->route.list) == NULL)) error = EINVAL; if (rule->action == PF_PASS && rule->rdr.opts & PF_POOL_STICKYADDR && @@ -2244,6 +2256,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, rule->nat.cur = TAILQ_FIRST(&rule->nat.list); rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list); + rule->route.cur = TAILQ_FIRST(&rule->route.list); TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, rule, entries); ruleset->rules[rs_num].inactive.rcount++; @@ -2553,6 +2566,7 @@ pf_ioctl_begin_addrs(uint32_t *ticket) PF_RULES_WLOCK(); pf_empty_kpool(&V_pf_pabuf[0]); pf_empty_kpool(&V_pf_pabuf[1]); + pf_empty_kpool(&V_pf_pabuf[2]); *ticket = ++V_ticket_pabuf; PF_RULES_WUNLOCK(); @@ -2566,7 +2580,8 @@ pf_ioctl_add_addr(struct pf_nl_pooladdr *pp) struct pfi_kkif *kif = NULL; int error; - if (pp->which != PF_RDR && pp->which != PF_NAT) + if (pp->which != PF_RDR && pp->which != PF_NAT && + pp->which != PF_RT) return (EINVAL); #ifndef INET @@ -2613,8 +2628,17 @@ pf_ioctl_add_addr(struct pf_nl_pooladdr *pp) PF_RULES_WUNLOCK(); goto out; } - TAILQ_INSERT_TAIL(&V_pf_pabuf[pp->which == PF_RDR ? 1 : 0], - pa, entries); + switch (pp->which) { + case PF_NAT: + TAILQ_INSERT_TAIL(&V_pf_pabuf[0], pa, entries); + break; + case PF_RDR: + TAILQ_INSERT_TAIL(&V_pf_pabuf[1], pa, entries); + break; + case PF_RT: + TAILQ_INSERT_TAIL(&V_pf_pabuf[2], pa, entries); + break; + } PF_RULES_WUNLOCK(); return (0); @@ -2632,7 +2656,8 @@ pf_ioctl_get_addrs(struct pf_nl_pooladdr *pp) PF_RULES_RLOCK_TRACKER; - if (pp->which != PF_RDR && pp->which != PF_NAT) + if (pp->which != PF_RDR && pp->which != PF_NAT && + pp->which != PF_RT) return (EINVAL); pp->anchor[sizeof(pp->anchor) - 1] = 0; @@ -2659,7 +2684,8 @@ pf_ioctl_get_addr(struct pf_nl_pooladdr *pp) struct pf_kpooladdr *pa; u_int32_t nr = 0; - if (pp->which != PF_RDR && pp->which != PF_NAT) + if (pp->which != PF_RDR && pp->which != PF_NAT && + pp->which != PF_RT) return (EINVAL); PF_RULES_RLOCK_TRACKER; @@ -3652,6 +3678,7 @@ DIOCGETRULENV_error: newrule->cpid = td->td_proc ? td->td_proc->p_pid : 0; TAILQ_INIT(&newrule->nat.list); TAILQ_INIT(&newrule->rdr.list); + TAILQ_INIT(&newrule->route.list); } #define ERROUT(x) ERROUT_IOCTL(DIOCCHANGERULE_error, x) @@ -3748,7 +3775,7 @@ DIOCGETRULENV_error: error = ENOMEM; if (pf_kanchor_setup(newrule, ruleset, pcr->anchor_call)) error = EINVAL; - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { TAILQ_FOREACH(pa, &V_pf_pabuf[i], entries) if (pa->addr.type == PF_ADDR_TABLE) { pa->addr.p.tbl = @@ -3772,6 +3799,7 @@ DIOCGETRULENV_error: pf_mv_kpool(&V_pf_pabuf[0], &newrule->nat.list); pf_mv_kpool(&V_pf_pabuf[1], &newrule->rdr.list); + pf_mv_kpool(&V_pf_pabuf[2], &newrule->route.list); if (((((newrule->action == PF_NAT) || (newrule->action == PF_RDR) || (newrule->action == PF_BINAT) || @@ -3792,6 +3820,7 @@ DIOCGETRULENV_error: } pf_empty_kpool(&V_pf_pabuf[0]); pf_empty_kpool(&V_pf_pabuf[1]); + pf_empty_kpool(&V_pf_pabuf[2]); if (pcr->action == PF_CHANGE_ADD_HEAD) oldrule = TAILQ_FIRST( diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 3e7a6965d387..c0f722b1fd18 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -736,6 +736,7 @@ static const struct nlattr_parser nla_p_rule[] = { { .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 }, { .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested }, { .type = PF_RT_NAF, .off = _OUT(naf), .cb = nlattr_get_uint8 }, + { .type = PF_RT_RPOOL_RT, .off = _OUT(route), .arg = &pool_parser, .cb = nlattr_get_nested }, }; NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule); #undef _OUT @@ -909,6 +910,7 @@ pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt) nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname); nlattr_add_pool(nw, PF_RT_RPOOL_RDR, &rule->rdr); nlattr_add_pool(nw, PF_RT_RPOOL_NAT, &rule->nat); + nlattr_add_pool(nw, PF_RT_RPOOL_RT, &rule->route); nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint); nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid); nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout); diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h index 8c0149891773..d749ef3ab99e 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -267,6 +267,7 @@ enum pf_rule_type_t { PF_RT_MAX_SRC_CONN = 74, /* u32 */ PF_RT_RPOOL_NAT = 75, /* nested, pf_rpool_type_t */ PF_RT_NAF = 76, /* u8 */ + PF_RT_RPOOL_RT = 77, /* nested, pf_rpool_type_t */ }; enum pf_addrule_type_t {