From 336683f24f08303aa9b59eb207f22b1122cd720a Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Wed, 12 Dec 2018 20:15:06 +0000 Subject: [PATCH] pf: Fix endless loop on NAT exhaustion with sticky-address When we try to find a source port in pf_get_sport() it's possible that all available source ports will be in use. In that case we call pf_map_addr() to try to find a new source IP to try from. If there are no more available source IPs pf_map_addr() will return 1 and we stop trying. However, if sticky-address is set we'll always return the same IP address, even if we've already tried that one. We need to check the supplied address, because if that's the one we'd set it means pf_get_sport() has already tried it, and we should error out rather than keep trying. PR: 233867 MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D18483 --- sys/netpfil/pf/pf.c | 4 ++++ sys/netpfil/pf/pf_lb.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 9fa2c06f452..2c7db9a7e5c 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -5513,6 +5513,8 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, dst.sin_len = sizeof(dst); dst.sin_addr = ip->ip_dst; + bzero(&naddr, sizeof(naddr)); + if (TAILQ_EMPTY(&r->rpool.list)) { DPFPRINTF(PF_DEBUG_URGENT, ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__)); @@ -5672,6 +5674,8 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, dst.sin6_len = sizeof(dst); dst.sin6_addr = ip6->ip6_dst; + bzero(&naddr, sizeof(naddr)); + if (TAILQ_EMPTY(&r->rpool.list)) { DPFPRINTF(PF_DEBUG_URGENT, ("%s: TAILQ_EMPTY(&r->rpool.list)\n", __func__)); diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index 030e7ee7684..5b95b7405a6 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -328,6 +328,12 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, src node was created just a moment ago in pf_create_state and it needs to be filled in with routing decision calculated here. */ if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) { + /* If the supplied address is the same as the current one we've + * been asked before, so tell the caller that there's no other + * address to be had. */ + if (PF_AEQ(naddr, &(*sn)->raddr, af)) + return (1); + PF_ACPY(naddr, &(*sn)->raddr, af); if (V_pf_status.debug >= PF_DEBUG_MISC) { printf("pf_map_addr: src tracking maps ");