From owner-dev-commits-src-branches@freebsd.org Fri May 14 13:06:51 2021 Return-Path: Delivered-To: dev-commits-src-branches@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 3DA776473F0; Fri, 14 May 2021 13:06:51 +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 "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4FhTLy2szMz3kqm; Fri, 14 May 2021 13:06:50 +0000 (UTC) (envelope-from git@FreeBSD.org) 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 3AF8712C94; Fri, 14 May 2021 13:06:50 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 14ED6o1B052565; Fri, 14 May 2021 13:06:50 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 14ED6o8r052564; Fri, 14 May 2021 13:06:50 GMT (envelope-from git) Date: Fri, 14 May 2021 13:06:50 GMT Message-Id: <202105141306.14ED6o8r052564@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kristof Provost Subject: git: 32252d4ae79a - stable/12 - pf: Allow states to by killed per 'gateway' 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/stable/12 X-Git-Reftype: branch X-Git-Commit: 32252d4ae79afc9cf7e2f867a81870f19c14b04e Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-branches@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commits to the stable branches of the FreeBSD src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 May 2021 13:06:51 -0000 The branch stable/12 has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=32252d4ae79afc9cf7e2f867a81870f19c14b04e commit 32252d4ae79afc9cf7e2f867a81870f19c14b04e Author: Kristof Provost AuthorDate: 2021-04-30 13:15:05 +0000 Commit: Kristof Provost CommitDate: 2021-05-14 08:39:16 +0000 pf: Allow states to by killed per 'gateway' This allows us to kill states created from a rule with route-to/reply-to set. This is particularly useful in multi-wan setups, where one of the WAN links goes down. Submitted by: Steven Brown Obtained from: https://github.com/pfsense/FreeBSD-src/pull/11/ MFC after: 1 week Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D30058 (cherry picked from commit abbcba9cf5b1c26e837f00e0fbc205652cb05e51) --- lib/libpfctl/libpfctl.c | 1 + lib/libpfctl/libpfctl.h | 1 + sbin/pfctl/pfctl.8 | 20 +++++++++++--- sbin/pfctl/pfctl.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++- share/man/man4/pf.4 | 2 +- sys/net/pfvar.h | 1 + sys/netpfil/pf/pf_ioctl.c | 10 +++++++ 7 files changed, 96 insertions(+), 5 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 9f504237b4ee..f50afa7c78ef 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -642,6 +642,7 @@ _pfctl_clear_states(int dev, const struct pfctl_kill *kill, nvlist_add_number(nvl, "proto", kill->proto); pfctl_nv_add_rule_addr(nvl, "src", &kill->src); pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst); + pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr); nvlist_add_string(nvl, "ifname", kill->ifname); nvlist_add_string(nvl, "label", kill->label); diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index aa7f0ffd8fad..5c8b2108d937 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -191,6 +191,7 @@ struct pfctl_kill { int proto; struct pf_rule_addr src; struct pf_rule_addr dst; + struct pf_rule_addr rt_addr; char ifname[IFNAMSIZ]; char label[PF_RULE_LABEL_SIZE]; }; diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8 index f12489d9493a..f3905f850c5a 100644 --- a/sbin/pfctl/pfctl.8 +++ b/sbin/pfctl/pfctl.8 @@ -45,7 +45,7 @@ .Op Fl K Ar host | network .Xo .Oo Fl k -.Ar host | network | label | id +.Ar host | network | label | id | gateway .Oc Xc .Op Fl o Ar level .Op Fl p Ar device @@ -256,14 +256,15 @@ option may be specified, which will kill all the source tracking entries from the first host/network to the second. .It Xo .Fl k -.Ar host | network | label | id +.Ar host | network | label | id | gateway .Xc Kill all of the state entries matching the specified .Ar host , .Ar network , .Ar label , +.Ar id , or -.Ar id . +.Ar gateway. .Pp For example, to kill all of the state entries originating from .Dq host : @@ -317,6 +318,19 @@ To kill a state with ID 4823e84500000018 created from a backup firewall with hostid 00000002 use: .Pp .Dl # pfctl -k id -k 4823e84500000018/2 +.Pp +It is also possible to kill states created from a rule with the route-to/reply-to +parameter set to route the connection through a particular gateway. +Note that rules routing via the default routing table (not via a route-to +rule) will have their rt_addr set as 0.0.0.0 or ::. +To kill all states using a gateway of 192.168.0.1 use: +.Pp +.Dl # pfctl -k gateway -k 192.168.0.1 +.Pp +A network prefix length can also be specified. +To kill all states using a gateway in 192.168.0.0/24: +.Pp +.Dl # pfctl -k gateway -k 192.168.0.0/24 .It Fl m Merge in explicitly given options without resetting those which are omitted. diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 487dfb480cdc..96f3b4740d90 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -83,6 +83,7 @@ int pfctl_clear_iface_states(int, const char *, int); void pfctl_addrprefix(char *, struct pf_addr *); int pfctl_kill_src_nodes(int, const char *, int); int pfctl_net_kill_states(int, const char *, int); +int pfctl_gateway_kill_states(int, const char *, int); int pfctl_label_kill_states(int, const char *, int); int pfctl_id_kill_states(int, const char *, int); void pfctl_init_options(struct pfctl *); @@ -246,7 +247,7 @@ usage(void) fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n" "\t[-f file] [-i interface] [-K host | network]\n" - "\t[-k host | network | label | id] [-o level] [-p device]\n" + "\t[-k host | network | gateway | label | id] [-o level] [-p device]\n" "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n", __progname); @@ -744,6 +745,67 @@ pfctl_net_kill_states(int dev, const char *iface, int opts) return (0); } +int +pfctl_gateway_kill_states(int dev, const char *iface, int opts) +{ + struct pfctl_kill kill; + struct addrinfo *res, *resp; + struct sockaddr last_src; + unsigned int newkilled; + int killed = 0; + int ret_ga; + + if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { + warnx("no gateway specified"); + usage(); + } + + memset(&kill, 0, sizeof(kill)); + memset(&kill.rt_addr.addr.v.a.mask, 0xff, + sizeof(kill.rt_addr.addr.v.a.mask)); + memset(&last_src, 0xff, sizeof(last_src)); + if (iface != NULL && strlcpy(kill.ifname, iface, + sizeof(kill.ifname)) >= sizeof(kill.ifname)) + errx(1, "invalid interface: %s", iface); + + pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask); + + if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) { + errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp = res; resp; resp = resp->ai_next) { + if (resp->ai_addr == NULL) + continue; + /* We get lots of duplicates. Catch the easy ones */ + if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0) + continue; + last_src = *(struct sockaddr *)resp->ai_addr; + + kill.af = resp->ai_family; + + if (kill.af == AF_INET) + kill.rt_addr.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp->ai_addr)->sin_addr; + else if (kill.af == AF_INET6) + kill.rt_addr.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp->ai_addr)-> + sin6_addr; + else + errx(1, "Unknown address family %d", kill.af); + + if (pfctl_kill_states(dev, &kill, &newkilled)) + err(1, "DIOCKILLSTATES"); + killed += newkilled; + } + + freeaddrinfo(res); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states\n", killed); + return (0); +} + int pfctl_label_kill_states(int dev, const char *iface, int opts) { @@ -2455,6 +2517,8 @@ main(int argc, char *argv[]) pfctl_label_kill_states(dev, ifaceopt, opts); else if (!strcmp(state_kill[0], "id")) pfctl_id_kill_states(dev, ifaceopt, opts); + else if (!strcmp(state_kill[0], "gateway")) + pfctl_gateway_kill_states(dev, ifaceopt, opts); else pfctl_net_kill_states(dev, ifaceopt, opts); } diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4 index e71ef8f426e4..2fb132203908 100644 --- a/share/man/man4/pf.4 +++ b/share/man/man4/pf.4 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 5, 2018 +.Dd May 7, 2021 .Dt PF 4 .Os .Sh NAME diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index abbabd842c43..196a5edb874a 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1079,6 +1079,7 @@ struct pf_kstate_kill { int psk_proto; struct pf_rule_addr psk_src; struct pf_rule_addr psk_dst; + struct pf_rule_addr psk_rt_addr; char psk_ifname[IFNAMSIZ]; char psk_label[PF_RULE_LABEL_SIZE]; u_int psk_killed; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index f38261caa8e9..69d32b835a43 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -2456,6 +2456,12 @@ relock_DIOCKILLSTATES: &psk->psk_dst.addr.v.a.mask, dstaddr, sk->af)) continue; + if (! PF_MATCHA(psk->psk_rt_addr.neg, + &psk->psk_rt_addr.addr.v.a.addr, + &psk->psk_rt_addr.addr.v.a.mask, + &s->rt_addr, sk->af)) + continue; + if (psk->psk_src.port_op != 0 && ! pf_match_port(psk->psk_src.port_op, psk->psk_src.port[0], psk->psk_src.port[1], srcport)) @@ -2539,6 +2545,10 @@ pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl, return (EINVAL); PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"), &kill->psk_dst)); + if (nvlist_exists_nvlist(nvl, "rt_addr")) { + PFNV_CHK(pf_nvrule_addr_to_rule_addr( + nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr)); + } PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname, sizeof(kill->psk_ifname)));