pf: ensure we have the correct source/destination IP address in ICMP errors
When we route-to a packet that later turns out to not fit in the outbound interface MTU we generate an ICMP error. However, if we've already changed those (i.e. we've passed through a NAT rule) we have to undo the transformation first. Obtained from: pfSense MFC after: 3 weeks Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D32571
This commit is contained in:
parent
cfd8fda159
commit
ab238f1454
@ -320,6 +320,8 @@ static u_int pf_purge_expired_states(u_int, int);
|
|||||||
static void pf_purge_unlinked_rules(void);
|
static void pf_purge_unlinked_rules(void);
|
||||||
static int pf_mtag_uminit(void *, int, int);
|
static int pf_mtag_uminit(void *, int, int);
|
||||||
static void pf_mtag_free(struct m_tag *);
|
static void pf_mtag_free(struct m_tag *);
|
||||||
|
static void pf_packet_rework_nat(struct mbuf *, struct pf_pdesc *,
|
||||||
|
int, struct pf_state_key *);
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
static void pf_route(struct mbuf **, struct pf_krule *, int,
|
static void pf_route(struct mbuf **, struct pf_krule *, int,
|
||||||
struct ifnet *, struct pf_kstate *,
|
struct ifnet *, struct pf_kstate *,
|
||||||
@ -341,6 +343,16 @@ extern struct proc *pf_purge_proc;
|
|||||||
|
|
||||||
VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
|
VNET_DEFINE(struct pf_limit, pf_limits[PF_LIMIT_MAX]);
|
||||||
|
|
||||||
|
#define PACKET_UNDO_NAT(_m, _pd, _off, _s, _dir) \
|
||||||
|
do { \
|
||||||
|
struct pf_state_key *nk; \
|
||||||
|
if ((_dir) == PF_OUT) \
|
||||||
|
nk = (_s)->key[PF_SK_STACK]; \
|
||||||
|
else \
|
||||||
|
nk = (_s)->key[PF_SK_WIRE]; \
|
||||||
|
pf_packet_rework_nat(_m, _pd, _off, nk); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define PACKET_LOOPED(pd) ((pd)->pf_mtag && \
|
#define PACKET_LOOPED(pd) ((pd)->pf_mtag && \
|
||||||
(pd)->pf_mtag->flags & PF_PACKET_LOOPED)
|
(pd)->pf_mtag->flags & PF_PACKET_LOOPED)
|
||||||
|
|
||||||
@ -446,6 +458,83 @@ pf_addr_cmp(struct pf_addr *a, struct pf_addr *b, sa_family_t af)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pf_packet_rework_nat(struct mbuf *m, struct pf_pdesc *pd, int off,
|
||||||
|
struct pf_state_key *nk)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (pd->proto) {
|
||||||
|
case IPPROTO_TCP: {
|
||||||
|
struct tcphdr *th = &pd->hdr.tcp;
|
||||||
|
|
||||||
|
if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af))
|
||||||
|
pf_change_ap(m, pd->src, &th->th_sport, pd->ip_sum,
|
||||||
|
&th->th_sum, &nk->addr[pd->sidx],
|
||||||
|
nk->port[pd->sidx], 0, pd->af);
|
||||||
|
if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af))
|
||||||
|
pf_change_ap(m, pd->dst, &th->th_dport, pd->ip_sum,
|
||||||
|
&th->th_sum, &nk->addr[pd->didx],
|
||||||
|
nk->port[pd->didx], 0, pd->af);
|
||||||
|
m_copyback(m, off, sizeof(*th), (caddr_t)th);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IPPROTO_UDP: {
|
||||||
|
struct udphdr *uh = &pd->hdr.udp;
|
||||||
|
|
||||||
|
if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af))
|
||||||
|
pf_change_ap(m, pd->src, &uh->uh_sport, pd->ip_sum,
|
||||||
|
&uh->uh_sum, &nk->addr[pd->sidx],
|
||||||
|
nk->port[pd->sidx], 1, pd->af);
|
||||||
|
if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af))
|
||||||
|
pf_change_ap(m, pd->dst, &uh->uh_dport, pd->ip_sum,
|
||||||
|
&uh->uh_sum, &nk->addr[pd->didx],
|
||||||
|
nk->port[pd->didx], 1, pd->af);
|
||||||
|
m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IPPROTO_ICMP: {
|
||||||
|
struct icmp *ih = &pd->hdr.icmp;
|
||||||
|
|
||||||
|
if (nk->port[pd->sidx] != ih->icmp_id) {
|
||||||
|
pd->hdr.icmp.icmp_cksum = pf_cksum_fixup(
|
||||||
|
ih->icmp_cksum, ih->icmp_id,
|
||||||
|
nk->port[pd->sidx], 0);
|
||||||
|
ih->icmp_id = nk->port[pd->sidx];
|
||||||
|
pd->sport = &ih->icmp_id;
|
||||||
|
|
||||||
|
m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih);
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af)) {
|
||||||
|
switch (pd->af) {
|
||||||
|
case AF_INET:
|
||||||
|
pf_change_a(&pd->src->v4.s_addr,
|
||||||
|
pd->ip_sum, nk->addr[pd->sidx].v4.s_addr,
|
||||||
|
0);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af)) {
|
||||||
|
switch (pd->af) {
|
||||||
|
case AF_INET:
|
||||||
|
pf_change_a(&pd->dst->v4.s_addr,
|
||||||
|
pd->ip_sum, nk->addr[pd->didx].v4.s_addr,
|
||||||
|
0);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static __inline uint32_t
|
static __inline uint32_t
|
||||||
pf_hashkey(struct pf_state_key *sk)
|
pf_hashkey(struct pf_state_key *sk)
|
||||||
{
|
{
|
||||||
@ -5937,6 +6026,11 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
|
|||||||
error = EMSGSIZE;
|
error = EMSGSIZE;
|
||||||
KMOD_IPSTAT_INC(ips_cantfrag);
|
KMOD_IPSTAT_INC(ips_cantfrag);
|
||||||
if (r->rt != PF_DUPTO) {
|
if (r->rt != PF_DUPTO) {
|
||||||
|
if (s && pd->nat_rule != NULL)
|
||||||
|
PACKET_UNDO_NAT(m0, pd,
|
||||||
|
(ip->ip_hl << 2) + (ip_off & IP_OFFMASK),
|
||||||
|
s, dir);
|
||||||
|
|
||||||
icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
|
icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
|
||||||
ifp->if_mtu);
|
ifp->if_mtu);
|
||||||
goto done;
|
goto done;
|
||||||
@ -6104,9 +6198,14 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
|
|||||||
nd6_output_ifp(ifp, ifp, m0, &dst, NULL);
|
nd6_output_ifp(ifp, ifp, m0, &dst, NULL);
|
||||||
else {
|
else {
|
||||||
in6_ifstat_inc(ifp, ifs6_in_toobig);
|
in6_ifstat_inc(ifp, ifs6_in_toobig);
|
||||||
if (r->rt != PF_DUPTO)
|
if (r->rt != PF_DUPTO) {
|
||||||
|
if (s && pd->nat_rule != NULL)
|
||||||
|
PACKET_UNDO_NAT(m0, pd,
|
||||||
|
((caddr_t)ip6 - m0->m_data) +
|
||||||
|
sizeof(struct ip6_hdr), s, dir);
|
||||||
|
|
||||||
icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
|
icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
|
||||||
else
|
} else
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user