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);
|
&key->addr[0], &key->addr[1], 0, 0);
|
||||||
|
|
||||||
action = pf_find_state(pd, key, stp);
|
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)
|
if (action != PF_MATCH)
|
||||||
return (action);
|
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)
|
if ((*stp)->state_flags & PFSTATE_SLOPPY)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ pfk_reroute(struct sk_buff *skb)
|
|||||||
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
|
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
|
||||||
|
|
||||||
rt = ip_route_output_key(&init_net, &fl4);
|
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) {
|
if (IS_ERR(rt) || rt == NULL) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return;
|
return;
|
||||||
@@ -102,18 +104,38 @@ pfk_reroute(struct sk_buff *skb)
|
|||||||
rt->dst.output(&init_net, skb->sk, 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
|
static void
|
||||||
pfk_pkt_work(struct work_struct *w)
|
pfk_pkt_work(struct work_struct *w)
|
||||||
{
|
{
|
||||||
struct pfk_pkt *pk = container_of(w, struct pfk_pkt, work);
|
struct pfk_pkt *pk = container_of(w, struct pfk_pkt, work);
|
||||||
struct mbuf *m, *m0;
|
struct mbuf *m, *m0;
|
||||||
struct sk_buff *orig;
|
struct sk_buff *orig;
|
||||||
__be32 orig_dst = 0;
|
__be32 orig_dst = 0, orig_src = 0;
|
||||||
int action;
|
int action;
|
||||||
|
|
||||||
if (pk->af == AF_INET && pk->dir == PF_IN &&
|
if (pk->af == AF_INET && pskb_may_pull(pk->skb, sizeof(struct iphdr))) {
|
||||||
pskb_may_pull(pk->skb, sizeof(struct iphdr)))
|
|
||||||
orig_dst = ip_hdr(pk->skb)->daddr;
|
orig_dst = ip_hdr(pk->skb)->daddr;
|
||||||
|
orig_src = ip_hdr(pk->skb)->saddr;
|
||||||
|
}
|
||||||
|
|
||||||
m = pfk_m_wrap_skb(pk->skb, pk->af);
|
m = pfk_m_wrap_skb(pk->skb, pk->af);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
@@ -129,6 +151,12 @@ pfk_pkt_work(struct work_struct *w)
|
|||||||
* and packet walk run concurrently from here on — documented. */
|
* and packet walk run concurrently from here on — documented. */
|
||||||
action = pf_test(pk->af, pk->dir, pk->ifp, &m);
|
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) {
|
if (m == m0) {
|
||||||
/* same buffer, possibly rewritten in place: our wrapper
|
/* 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 &&
|
pk->af == AF_INET && pk->dir == PF_IN &&
|
||||||
pskb_may_pull(pk->skb, sizeof(struct iphdr)) &&
|
pskb_may_pull(pk->skb, sizeof(struct iphdr)) &&
|
||||||
ip_hdr(pk->skb)->daddr != orig_dst) {
|
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):
|
/* pf translated the destination (reverse NAT):
|
||||||
* re-route instead of delivering locally */
|
* re-route instead of delivering locally */
|
||||||
pfk_reroute(pk->skb);
|
pfk_reroute(pk->skb);
|
||||||
|
|||||||
Reference in new issue
Block a user