git: 7d381d0a5b50 - main - pf: exclude link local address from the dynamic interface address pool
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 19 Sep 2024 20:21:26 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=7d381d0a5b50539638a2460c9ae2213af5c3fad8 commit 7d381d0a5b50539638a2460c9ae2213af5c3fad8 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2024-09-05 15:38:20 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-09-19 20:20:14 +0000 pf: exclude link local address from the dynamic interface address pool so that rules like "pass out on vr1 inet6 nat-to (vr1)" won't map to the non routable ipv6 link local address; with suggestions and ok claudio, henning Reviewed by: zlei Obtained from: OpenBSD, mikeb <mikeb@openbsd.org>, e41548933f Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D46594 --- sys/net/pfvar.h | 4 +++- sys/netpfil/pf/pf_lb.c | 17 +++++++++++++---- sys/netpfil/pf/pf_table.c | 9 ++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 8335fbfaedb8..a5a0ed257ef3 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1228,6 +1228,7 @@ typedef void pfsync_clear_states_t(u_int32_t, const char *); typedef int pfsync_defer_t(struct pf_kstate *, struct mbuf *); typedef void pfsync_detach_ifnet_t(struct ifnet *); typedef void pflow_export_state_t(const struct pf_kstate *); +typedef bool pf_addr_filter_func_t(const sa_family_t, const struct pf_addr *); VNET_DECLARE(pfsync_state_import_t *, pfsync_state_import_ptr); #define V_pfsync_state_import_ptr VNET(pfsync_state_import_ptr) @@ -2429,7 +2430,8 @@ void pfr_cleanup(void); int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, u_int64_t, int, int, int); -int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, sa_family_t); +int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, sa_family_t, + pf_addr_filter_func_t); void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *); struct pfr_ktable * pfr_attach_table(struct pf_kruleset *, char *); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index 6541a42aa236..b322bd65cfd3 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -71,6 +71,7 @@ static int pf_get_sport(sa_family_t, uint8_t, struct pf_krule *, struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *, uint16_t *, uint16_t, uint16_t, struct pf_ksrc_node **, struct pf_udp_mapping **); +static bool pf_islinklocal(const sa_family_t, const struct pf_addr *); #define mix(a,b,c) \ do { \ @@ -401,6 +402,14 @@ failed: return (1); /* none available */ } +static bool +pf_islinklocal(const sa_family_t af, const struct pf_addr *addr) +{ + if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr->v6)) + return (true); + return (false); +} + static int pf_get_mape_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r, struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr, @@ -585,11 +594,11 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, if (rpool->cur->addr.type == PF_ADDR_TABLE) { if (!pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af)) + &rpool->tblidx, &rpool->counter, af, NULL)) goto get_addr; } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af)) + &rpool->tblidx, &rpool->counter, af, pf_islinklocal)) goto get_addr; } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af)) goto get_addr; @@ -602,7 +611,7 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, if (rpool->cur->addr.type == PF_ADDR_TABLE) { rpool->tblidx = -1; if (pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, af)) { + &rpool->tblidx, &rpool->counter, af, NULL)) { /* table contains no address of type 'af' */ if (rpool->cur != acur) goto try_next; @@ -612,7 +621,7 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr, } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { rpool->tblidx = -1; if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, af)) { + &rpool->tblidx, &rpool->counter, af, pf_islinklocal)) { /* table contains no address of type 'af' */ if (rpool->cur != acur) goto try_next; diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index 4d248e40443d..690cb6d9ab90 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -2240,7 +2240,7 @@ pfr_detach_table(struct pfr_ktable *kt) int pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, - sa_family_t af) + sa_family_t af, pf_addr_filter_func_t filter) { struct pf_addr addr, cur, mask, umask_addr; union sockaddr_union uaddr, umask; @@ -2299,6 +2299,10 @@ _next_block: if (!KENTRY_NETWORK(ke)) { /* this is a single IP address - no possible nested block */ + if (filter && filter(af, &addr)) { + idx++; + goto _next_block; + } PF_ACPY(counter, &addr, af); *pidx = idx; pfr_kstate_counter_add(&kt->pfrkt_match, 1); @@ -2319,12 +2323,15 @@ _next_block: /* no need to check KENTRY_RNF_ROOT() here */ if (ke2 == ke) { /* lookup return the same block - perfect */ + if (filter && filter(af, &addr)) + goto _next_entry; PF_ACPY(counter, &addr, af); *pidx = idx; pfr_kstate_counter_add(&kt->pfrkt_match, 1); return (0); } +_next_entry: /* we need to increase the counter past the nested block */ pfr_prepare_network(&umask, AF_INET, ke2->pfrke_net); pfr_sockaddr_to_pf_addr(&umask, &umask_addr);