git: 339a1977c324 - main - pf: Add a sysctl to limit work done for rdr source port rewriting
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 10 Sep 2024 14:59:30 UTC
The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=339a1977c32414f3d23733504955245ca6f3802d commit 339a1977c32414f3d23733504955245ca6f3802d Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2024-09-10 14:33:47 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2024-09-10 14:58:19 +0000 pf: Add a sysctl to limit work done for rdr source port rewriting It was pointed out that the current approach of exhaustively searching for a free source port might be very time consuming. Limit the amount of work that we might do before giving up. Reviewed by: kp Reported by: Eirik Øverby <ltning-freebsd@anduin.net> MFC after: 3 months Sponsored by: Klara, Inc. Sponsored by: Modirum Differential Revision: https://reviews.freebsd.org/D46495 --- share/man/man4/pf.4 | 7 ++++++- share/man/man5/pf.conf.5 | 6 +++++- sys/netpfil/pf/pf_lb.c | 18 ++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4 index 3855d07faead..92e1a6fdf87b 100644 --- a/share/man/man4/pf.4 +++ b/share/man/man4/pf.4 @@ -102,8 +102,13 @@ This tells .Nm to also filter on the loopback output hook. This is typically used to allow redirect rules to adjust the source address. -.It net.pf.request_maxcount +.It Va net.pf.request_maxcount The maximum number of items in a single ioctl call. +.It Va net.pf.rdr_srcport_rewrite_tries +The maximum number of times to try and find a free source port when handling +redirects. +Such rules are typically applied to external traffic, so an exhaustive search +may be too expensive. .El .Pp Read only diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 index 5aa936d509ed..733b00cc6732 100644 --- a/share/man/man5/pf.conf.5 +++ b/share/man/man5/pf.conf.5 @@ -1407,7 +1407,11 @@ A .Ar rdr rule may cause the source port to be modified if doing so avoids a conflict with an existing connection. -A random source port in the range 50001-65535 is chosen in this case. +A random source port in the range 50001-65535 is chosen in this case; to +avoid excessive CPU consumption, the number of searches for a free port is +limited by the +.Va net.pf.rdr_srcport_rewrite_tries +sysctl. Port numbers are never translated with a .Ar binat rule. diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index cdd68aaf5dab..dbd85d530bb7 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -52,6 +52,13 @@ #include <net/pfvar.h> #include <net/if_pflog.h> +/* + * Limit the amount of work we do to find a free source port for redirects that + * introduce a state conflict. + */ +#define V_pf_rdr_srcport_rewrite_tries VNET(pf_rdr_srcport_rewrite_tries) +VNET_DEFINE_STATIC(int, pf_rdr_srcport_rewrite_tries) = 16; + #define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x static void pf_hash(struct pf_addr *, struct pf_addr *, @@ -822,6 +829,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, break; case PF_RDR: { struct pf_state_key_cmp key; + int tries; uint16_t cut, low, high, nport; reason = pf_map_addr(pd->af, r, saddr, naddr, NULL, NULL, sn); @@ -873,11 +881,15 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, if (!pf_find_state_all_exists(&key, PF_OUT)) break; + tries = 0; + low = 50001; /* XXX-MJ PF_NAT_PROXY_PORT_LOW/HIGH */ high = 65535; cut = arc4random() % (1 + high - low) + low; for (uint32_t tmp = cut; - tmp <= high && tmp <= UINT16_MAX; tmp++) { + tmp <= high && tmp <= UINT16_MAX && + tries < V_pf_rdr_srcport_rewrite_tries; + tmp++, tries++) { key.port[0] = htons(tmp); if (!pf_find_state_all_exists(&key, PF_OUT)) { /* Update the source port. */ @@ -885,7 +897,9 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, goto out; } } - for (uint32_t tmp = cut - 1; tmp >= low; tmp--) { + for (uint32_t tmp = cut - 1; + tmp >= low && tries < V_pf_rdr_srcport_rewrite_tries; + tmp--, tries++) { key.port[0] = htons(tmp); if (!pf_find_state_all_exists(&key, PF_OUT)) { /* Update the source port. */