diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1228,6 +1228,7 @@ 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 @@ 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 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -64,6 +64,7 @@ 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 { \ @@ -394,6 +395,14 @@ 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, @@ -578,11 +587,11 @@ 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; @@ -595,7 +604,7 @@ 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; @@ -605,7 +614,7 @@ } 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 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -2240,7 +2240,7 @@ 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 @@ 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 @@ /* 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);