--- b/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -283,8 +283,8 @@ static u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t, sa_family_t); static u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t, int, u_int16_t); -static void pf_set_rt_ifp(struct pf_state *, - struct pf_addr *); +static int pf_set_rt_ifp(struct pf_state *, + struct pf_addr *, sa_family_t af); static int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); static void pf_print_state_parts(struct pf_state *, @@ -3103,29 +3103,32 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, int rtableid, u_int16_t offer) return (mss); } -static void -pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) +static int +pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr, sa_family_t af) { struct pf_rule *r = s->rule.ptr; struct pf_src_node *sn = NULL; + int map_status = 0; s->rt_kif = NULL; if (!r->rt || r->rt == PF_FASTROUTE) - return; - switch (s->key[PF_SK_WIRE]->af) { + return 0; + switch (af) { #ifdef INET case AF_INET: - pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn); + map_status = pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn); s->rt_kif = r->rpool.cur->kif; break; #endif /* INET */ #ifdef INET6 case AF_INET6: - pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn); + map_status = pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn); s->rt_kif = r->rpool.cur->kif; break; #endif /* INET6 */ } + + return map_status; } static u_int32_t @@ -3690,6 +3693,19 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, s->timeout = PFTM_OTHER_FIRST_PACKET; } + /* Call pf_set_rt_ifp (and thus pf_map_addr). If pf_map_addr fails, + remove the state and drop the packet. It makes no sense forwarding + it if redirection mapping has failed. Do it before setting timeouts, + csfailed won't remove the src_node otherwise. */ + if (pf_set_rt_ifp(s, pd->src, pd->af)) { + REASON_SET(&reason, PFRES_MAPFAILED); + pf_src_tree_remove_state(s); + STATE_DEC_COUNTERS(s); + uma_zfree(V_pf_state_z, s); + /* Try to remove (nat_)src_node. */ + goto csfailed; + } + s->creation = time_uptime; s->expire = time_uptime; @@ -3755,7 +3771,6 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, } else *sm = s; - pf_set_rt_ifp(s, pd->src); /* needs s->state_key set */ if (tag > 0) s->tag = tag; if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == --- b/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -125,7 +125,8 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL, #define PFRES_MAXSTATES 12 /* State limit */ #define PFRES_SRCLIMIT 13 /* Source node/conn limit */ #define PFRES_SYNPROXY 14 /* SYN proxy */ -#define PFRES_MAX 15 /* total+1 */ +#define PFRES_MAPFAILED 15 /* pf_map_addr failed */ +#define PFRES_MAX 16 /* total+1 */ #define PFRES_NAMES { \ "match", \ @@ -143,6 +144,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL, "state-limit", \ "src-limit", \ "synproxy", \ + "map-failed", \ NULL \ }