From nobody Fri May 09 22:16:23 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 4ZvNd46blmz5wCV1; Fri, 09 May 2025 22:16:24 +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 4ZvNd35g3Nz3RVg; Fri, 09 May 2025 22:16:23 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1746828983; 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=OCfXDstlJTiY+1uhnsqLhkAZJm7dpq9FB97IjyoN4MU=; b=QFBYV3/vf90lTCBSqXp4SSXMFoe7hyzlQLn/d8z1IPcGOtL4UgKfYAQW95GhVxY74gKdsj TgipiuurhyeGqIcqbp/f49HQ8okG9H+uKIyVjOXcIcqAW0IX5EyumJlhhhDRCFsPtS5gdr 8iIeLw2IEez1xjaoSdPoUz2WwVR/0JHhJ4+wWXmy6cAj6MU4UcFYQasJpQKuobwSoyKTw2 JPu4C8s2BcLM8pDrso+yanZwF3k1BOD43en5wMV1LfPjZQMMWg0gqR1RVNKBg+zHcNW9DL LZLGB36IqBFP5YT5OBoavrqK4le8eLwPgjqCk2Aw/tWhveL4ZT2EmZab+Krdtw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1746828983; 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=OCfXDstlJTiY+1uhnsqLhkAZJm7dpq9FB97IjyoN4MU=; b=Jzk7NxAsOfViPFzvODALfxGNOs1c3ImhgQl8GE+jEhPMKVYL9fBgpU6LWHbV1QWRdjj35B bM5BpqRlwofrQ5gWVbVdsTiLRNF50BFG3Y/XrZU60uHJKsuWZ/7f8cjPFF56YIecsTd9+a +ighccRlh7rrPIfPo6kgUxZGkxkIAX8rvk6yC0GR6gGnLhII+Q67FV2sQ8UqsSPEZ2CL69 PMqjkd7RwAsc8MCO0bjyefYhJG2mf1847tOV63a8+hkSTzDNCgPTc1mRUBZT1MGGotUOAW mzU+P0XqKXMpwH5NeE6D712rCX/euBDU+YD/RskGjn5oyxwDHFCzqfB5ht/yKw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1746828983; a=rsa-sha256; cv=none; b=iZzrYouJFWcYDi2E6vZN7t3Ktux/c4wkJQQWYLyq0MGQMHb+5jBPqsaa7RAHP4VDubeEYK 0XGfH0FHZe0LqAkmaKO06TigUdtznGkDN4H4jruXbuT2RSxueuWq9uidLIKcxOMFZdCa3t a1WgUc+7P87LuSZBpCZtkgtQ88EWiIBfEq/2lgN9W8rtAFxlt6GIUu3D7yeNjCfPVRgYmv /elNTkcAqEAp1tSxpOf3vLeNos0Iu7c5CLwh2N/W9ThcGWdHvJAKbJXgmO1akEmXqAn1Qt NPqoqnyEXaUrpWxrdpI91SBFkCGvSOkIeRDbnJ3KdvPVDrHYL/ZoHHK0NnZ01w== 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 4ZvNd32BWwz40b; Fri, 09 May 2025 22:16:23 +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 549MGNOi063087; Fri, 9 May 2025 22:16:23 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 549MGNWc063085; Fri, 9 May 2025 22:16:23 GMT (envelope-from git) Date: Fri, 9 May 2025 22:16:23 GMT Message-Id: <202505092216.549MGNWc063085@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: be0e5f0221dc - main - pfctl: support killing states by key 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: be0e5f0221dc2875c6a832f8c285d6afff4e94bb Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=be0e5f0221dc2875c6a832f8c285d6afff4e94bb commit be0e5f0221dc2875c6a832f8c285d6afff4e94bb Author: Kristof Provost AuthorDate: 2025-05-09 13:29:12 +0000 Commit: Kristof Provost CommitDate: 2025-05-09 20:49:30 +0000 pfctl: support killing states by key Add "key" modifier for -k to make pfctl can kill a state by specifying the key of the state. ok sasha Obtained from: OpenBSD, yasuoka , c42801d935 Sponsored by: Rubicon Communications, LLC ("Netgate") --- sbin/pfctl/pfctl.8 | 18 ++++++-- sbin/pfctl/pfctl.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8 index 5029d8438ed7..acf1bacee08f 100644 --- a/sbin/pfctl/pfctl.8 +++ b/sbin/pfctl/pfctl.8 @@ -24,7 +24,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd February 10, 2025 +.Dd May 9, 2025 .Dt PFCTL 8 .Os .Sh NAME @@ -254,13 +254,14 @@ 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 | gateway | nat +.Ar host | network | label | id | key | gateway | nat .Xc Kill all of the state entries matching the specified .Ar host , .Ar network , .Ar label , .Ar id , +.Ar key , .Ar gateway, or .Ar nat. @@ -293,7 +294,7 @@ To kill all states with the target .Pp .Dl # pfctl -k 0.0.0.0/0 -k host2 .Pp -It is also possible to kill states by rule label or state ID. +It is also possible to kill states by rule label, state key or state ID. In this mode the first .Fl k argument is used to specify the type @@ -304,6 +305,17 @@ from rules carrying the label .Pp .Dl # pfctl -k label -k foobar .Pp +To kill one specific state by its key +(protocol, host1, port1, direction, host2 and port2 in the same format +of pfctl -s state), +use the +.Ar key +modifier and as a second argument the state key. +To kill a state whose protocol is TCP and originating from +10.0.0.101:32123 to 10.0.0.1:80 use: +.Pp +.Dl # pfctl -k key -k 'tcp 10.0.0.1:80 <- 10.0.0.101:32123' +.Pp To kill one specific state by its unique state ID (as shown by pfctl -s state -vv), use the diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 595f688d6139..c540a62f0409 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -83,6 +83,8 @@ 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); +int pfctl_key_kill_states(int, const char *, int); +int pfctl_parse_host(char *, struct pf_rule_addr *); void pfctl_init_options(struct pfctl *); int pfctl_load_options(struct pfctl *); int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); @@ -954,6 +956,123 @@ pfctl_id_kill_states(int dev, const char *iface, int opts) return (0); } +int +pfctl_key_kill_states(int dev, const char *iface, int opts) +{ + struct pfctl_kill kill; + char *s, *token, *tokens[4]; + struct protoent *p; + u_int i, sidx, didx; + int ret, killed; + + if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { + warnx("no key specified"); + usage(); + } + memset(&kill, 0, sizeof(kill)); + + if (iface != NULL && + strlcpy(kill.ifname, iface, sizeof(kill.ifname)) >= + sizeof(kill.ifname)) + errx(1, "invalid interface: %s", iface); + + s = strdup(state_kill[1]); + if (!s) + errx(1, "%s: strdup", __func__); + i = 0; + while ((token = strsep(&s, " \t")) != NULL) + if (*token != '\0') { + if (i < 4) + tokens[i] = token; + i++; + } + if (i != 4) + errx(1, "%s: key must be " + "\"protocol host1:port1 direction host2:port2\" format", + __func__); + + if ((p = getprotobyname(tokens[0])) == NULL) + errx(1, "invalid protocol: %s", tokens[0]); + kill.proto = p->p_proto; + + if (strcmp(tokens[2], "->") == 0) { + sidx = 1; + didx = 3; + } else if (strcmp(tokens[2], "<-") == 0) { + sidx = 3; + didx = 1; + } else + errx(1, "invalid direction: %s", tokens[2]); + + if (pfctl_parse_host(tokens[sidx], &kill.src) == -1) + errx(1, "invalid host: %s", tokens[sidx]); + if (pfctl_parse_host(tokens[didx], &kill.dst) == -1) + errx(1, "invalid host: %s", tokens[didx]); + + if ((ret = pfctl_kill_states_h(pfh, &kill, &killed)) != 0) + errc(1, ret, "DIOCKILLSTATES"); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states\n", killed); + + return (0); +} + +int +pfctl_parse_host(char *str, struct pf_rule_addr *addr) +{ + char *s = NULL, *sbs, *sbe; + struct addrinfo hints, *ai; + struct sockaddr_in *sin4; + struct sockaddr_in6 *sin6; + + s = strdup(str); + if (!s) + errx(1, "pfctl_parse_host: strdup"); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; /* dummy */ + hints.ai_flags = AI_NUMERICHOST; + + if ((sbs = strchr(s, '[')) != NULL && (sbe = strrchr(s, ']')) != NULL) { + hints.ai_family = AF_INET6; + *(sbs++) = *sbe = '\0'; + } else if ((sbs = strchr(s, ':')) != NULL) { + hints.ai_family = AF_INET; + *(sbs++) = '\0'; + } else + goto error; + + if (getaddrinfo(s, sbs, &hints, &ai) != 0) + goto error; + + switch (ai->ai_family) { + case AF_INET: + sin4 = (struct sockaddr_in *)ai->ai_addr; + addr->addr.v.a.addr.v4 = sin4->sin_addr; + addr->port[0] = sin4->sin_port; + break; + + case AF_INET6: + sin6 = (struct sockaddr_in6 *)ai->ai_addr; + addr->addr.v.a.addr.v6 = sin6->sin6_addr; + addr->port[0] = sin6->sin6_port; + break; + } + freeaddrinfo(ai); + free(s); + + memset(&addr->addr.v.a.mask, 0xff, sizeof(struct pf_addr)); + addr->port_op = PF_OP_EQ; + addr->addr.type = PF_ADDR_ADDRMASK; + + return (0); + +error: + free(s); + return (-1); +} + int pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr, u_int32_t ticket, int r_action, const char *anchorname, int which) @@ -3282,6 +3401,8 @@ main(int argc, char *argv[]) pfctl_id_kill_states(dev, ifaceopt, opts); else if (!strcmp(state_kill[0], "gateway")) pfctl_gateway_kill_states(dev, ifaceopt, opts); + else if (!strcmp(state_kill[0], "key")) + pfctl_key_kill_states(dev, ifaceopt, opts); else pfctl_net_kill_states(dev, ifaceopt, opts); }