git: be0e5f0221dc - main - pfctl: support killing states by key
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 09 May 2025 22:16:23 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=be0e5f0221dc2875c6a832f8c285d6afff4e94bb commit be0e5f0221dc2875c6a832f8c285d6afff4e94bb Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2025-05-09 13:29:12 +0000 Commit: Kristof Provost <kp@FreeBSD.org> 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 <yasuoka@openbsd.org>, 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); }