nat: recompute IPv4 header checksum after pf rewrote the addresses (OpenBSD ip_output does this)
This commit is contained in:
1 parent
d520172753
commit
917d3e3fe0
2 files changed
+42
-3
No files matched your search
@@ -6254,8 +6254,17 @@ pf_icmp_state_lookup(struct pf_pdesc *pd, struct pf_state_key_cmp *key,
|
||||
&key->addr[0], &key->addr[1], 0, 0);
|
||||
|
||||
action = pf_find_state(pd, key, stp);
|
||||
pr_info("pfk: ICMPDBG dir=%d sidx=%d icmp_dir=%d key0=%08x key1=%08x p0=%u p1=%u act=%d\n",
|
||||
pd->dir, pd->sidx, icmp_dir, key->addr[0].v4.s_addr,
|
||||
key->addr[1].v4.s_addr, key->port[0], key->port[1], action);
|
||||
if (action != PF_MATCH)
|
||||
return (action);
|
||||
pr_info("pfk: ICMPDBG st wire0=%08x wire1=%08x wp0=%u wp1=%u stack0=%08x stack1=%08x\n",
|
||||
(*stp)->key[PF_SK_WIRE]->addr[0].v4.s_addr,
|
||||
(*stp)->key[PF_SK_WIRE]->addr[1].v4.s_addr,
|
||||
(*stp)->key[PF_SK_WIRE]->port[0], (*stp)->key[PF_SK_WIRE]->port[1],
|
||||
(*stp)->key[PF_SK_STACK]->addr[0].v4.s_addr,
|
||||
(*stp)->key[PF_SK_STACK]->addr[1].v4.s_addr);
|
||||
|
||||
if ((*stp)->state_flags & PFSTATE_SLOPPY)
|
||||
return (-1);
|
||||
|
||||
@@ -92,6 +92,8 @@ pfk_reroute(struct sk_buff *skb)
|
||||
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
|
||||
|
||||
rt = ip_route_output_key(&init_net, &fl4);
|
||||
pr_info("pfk: RERDBG src=%08x dst=%08x rt=%px dev=%s\n", fl4.saddr, fl4.daddr,
|
||||
rt, (rt && !IS_ERR(rt) && rt->dst.dev) ? rt->dst.dev->name : "?");
|
||||
if (IS_ERR(rt) || rt == NULL) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
@@ -102,18 +104,38 @@ pfk_reroute(struct sk_buff *skb)
|
||||
rt->dst.output(&init_net, skb->sk, skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* PFLINUX: pf rewrote the IPv4 addresses of the packet (NAT). OpenBSD's
|
||||
* ip_output() recomputes the IP header checksum on every packet it sends;
|
||||
* Linux does not, so fix it up here after pf touched the header.
|
||||
*/
|
||||
static void
|
||||
pfk_fix_ip_csum(struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
|
||||
return;
|
||||
iph = ip_hdr(skb);
|
||||
iph->check = 0;
|
||||
iph->check = csum_fold(csum_partial(skb->data, iph->ihl * 4, 0));
|
||||
/* the transport checksum was already fixed by pf */
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
pfk_pkt_work(struct work_struct *w)
|
||||
{
|
||||
struct pfk_pkt *pk = container_of(w, struct pfk_pkt, work);
|
||||
struct mbuf *m, *m0;
|
||||
struct sk_buff *orig;
|
||||
__be32 orig_dst = 0;
|
||||
__be32 orig_dst = 0, orig_src = 0;
|
||||
int action;
|
||||
|
||||
if (pk->af == AF_INET && pk->dir == PF_IN &&
|
||||
pskb_may_pull(pk->skb, sizeof(struct iphdr)))
|
||||
if (pk->af == AF_INET && pskb_may_pull(pk->skb, sizeof(struct iphdr))) {
|
||||
orig_dst = ip_hdr(pk->skb)->daddr;
|
||||
orig_src = ip_hdr(pk->skb)->saddr;
|
||||
}
|
||||
|
||||
m = pfk_m_wrap_skb(pk->skb, pk->af);
|
||||
if (!m) {
|
||||
@@ -129,6 +151,12 @@ pfk_pkt_work(struct work_struct *w)
|
||||
* and packet walk run concurrently from here on — documented. */
|
||||
action = pf_test(pk->af, pk->dir, pk->ifp, &m);
|
||||
|
||||
if (pk->af == AF_INET && orig_src != 0 &&
|
||||
pskb_may_pull(pk->skb, sizeof(struct iphdr)) &&
|
||||
(ip_hdr(pk->skb)->saddr != orig_src ||
|
||||
ip_hdr(pk->skb)->daddr != orig_dst))
|
||||
pfk_fix_ip_csum(pk->skb);
|
||||
|
||||
|
||||
if (m == m0) {
|
||||
/* same buffer, possibly rewritten in place: our wrapper
|
||||
@@ -138,6 +166,8 @@ pfk_pkt_work(struct work_struct *w)
|
||||
pk->af == AF_INET && pk->dir == PF_IN &&
|
||||
pskb_may_pull(pk->skb, sizeof(struct iphdr)) &&
|
||||
ip_hdr(pk->skb)->daddr != orig_dst) {
|
||||
pr_info("pfk: RERDBG trigger old=%08x new=%08x\n", orig_dst,
|
||||
ip_hdr(pk->skb)->daddr);
|
||||
/* pf translated the destination (reverse NAT):
|
||||
* re-route instead of delivering locally */
|
||||
pfk_reroute(pk->skb);
|
||||
|
||||
Reference in new issue
Block a user