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);