-
Notifications
You must be signed in to change notification settings - Fork 55.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
netfilter: factor out packet duplication for IPv4/IPv6
Extracted from the xtables TEE target. This creates two new modules for IPv4 and IPv6 that are shared between the TEE target and the new nf_tables dup expressions. Signed-off-by: Pablo Neira Ayuso <[email protected]>
- Loading branch information
Showing
10 changed files
with
254 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#ifndef _NF_DUP_IPV4_H_ | ||
#define _NF_DUP_IPV4_H_ | ||
|
||
void nf_dup_ipv4(struct sk_buff *skb, unsigned int hooknum, | ||
const struct in_addr *gw, int oif); | ||
|
||
#endif /* _NF_DUP_IPV4_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#ifndef _NF_DUP_IPV6_H_ | ||
#define _NF_DUP_IPV6_H_ | ||
|
||
void nf_dup_ipv6(struct sk_buff *skb, unsigned int hooknum, | ||
const struct in6_addr *gw, int oif); | ||
|
||
#endif /* _NF_DUP_IPV6_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* (C) 2007 by Sebastian Claßen <[email protected]> | ||
* (C) 2007-2010 by Jan Engelhardt <[email protected]> | ||
* | ||
* Extracted from xt_TEE.c | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 or later, as | ||
* published by the Free Software Foundation. | ||
*/ | ||
#include <linux/ip.h> | ||
#include <linux/module.h> | ||
#include <linux/percpu.h> | ||
#include <linux/route.h> | ||
#include <linux/skbuff.h> | ||
#include <net/checksum.h> | ||
#include <net/icmp.h> | ||
#include <net/ip.h> | ||
#include <net/route.h> | ||
#include <net/netfilter/ipv4/nf_dup_ipv4.h> | ||
#if IS_ENABLED(CONFIG_NF_CONNTRACK) | ||
#include <net/netfilter/nf_conntrack.h> | ||
#endif | ||
|
||
static struct net *pick_net(struct sk_buff *skb) | ||
{ | ||
#ifdef CONFIG_NET_NS | ||
const struct dst_entry *dst; | ||
|
||
if (skb->dev != NULL) | ||
return dev_net(skb->dev); | ||
dst = skb_dst(skb); | ||
if (dst != NULL && dst->dev != NULL) | ||
return dev_net(dst->dev); | ||
#endif | ||
return &init_net; | ||
} | ||
|
||
static bool nf_dup_ipv4_route(struct sk_buff *skb, const struct in_addr *gw, | ||
int oif) | ||
{ | ||
const struct iphdr *iph = ip_hdr(skb); | ||
struct net *net = pick_net(skb); | ||
struct rtable *rt; | ||
struct flowi4 fl4; | ||
|
||
memset(&fl4, 0, sizeof(fl4)); | ||
if (oif != -1) | ||
fl4.flowi4_oif = oif; | ||
|
||
fl4.daddr = gw->s_addr; | ||
fl4.flowi4_tos = RT_TOS(iph->tos); | ||
fl4.flowi4_scope = RT_SCOPE_UNIVERSE; | ||
fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH; | ||
rt = ip_route_output_key(net, &fl4); | ||
if (IS_ERR(rt)) | ||
return false; | ||
|
||
skb_dst_drop(skb); | ||
skb_dst_set(skb, &rt->dst); | ||
skb->dev = rt->dst.dev; | ||
skb->protocol = htons(ETH_P_IP); | ||
|
||
return true; | ||
} | ||
|
||
void nf_dup_ipv4(struct sk_buff *skb, unsigned int hooknum, | ||
const struct in_addr *gw, int oif) | ||
{ | ||
struct iphdr *iph; | ||
|
||
if (__this_cpu_read(nf_skb_duplicated)) | ||
return; | ||
/* | ||
* Copy the skb, and route the copy. Will later return %XT_CONTINUE for | ||
* the original skb, which should continue on its way as if nothing has | ||
* happened. The copy should be independently delivered to the gateway. | ||
*/ | ||
skb = pskb_copy(skb, GFP_ATOMIC); | ||
if (skb == NULL) | ||
return; | ||
|
||
#if IS_ENABLED(CONFIG_NF_CONNTRACK) | ||
/* Avoid counting cloned packets towards the original connection. */ | ||
nf_conntrack_put(skb->nfct); | ||
skb->nfct = &nf_ct_untracked_get()->ct_general; | ||
skb->nfctinfo = IP_CT_NEW; | ||
nf_conntrack_get(skb->nfct); | ||
#endif | ||
/* | ||
* If we are in PREROUTING/INPUT, the checksum must be recalculated | ||
* since the length could have changed as a result of defragmentation. | ||
* | ||
* We also decrease the TTL to mitigate potential loops between two | ||
* hosts. | ||
* | ||
* Set %IP_DF so that the original source is notified of a potentially | ||
* decreased MTU on the clone route. IPv6 does this too. | ||
*/ | ||
iph = ip_hdr(skb); | ||
iph->frag_off |= htons(IP_DF); | ||
if (hooknum == NF_INET_PRE_ROUTING || | ||
hooknum == NF_INET_LOCAL_IN) | ||
--iph->ttl; | ||
ip_send_check(iph); | ||
|
||
if (nf_dup_ipv4_route(skb, gw, oif)) { | ||
__this_cpu_write(nf_skb_duplicated, true); | ||
ip_local_out(skb); | ||
__this_cpu_write(nf_skb_duplicated, false); | ||
} else { | ||
kfree_skb(skb); | ||
} | ||
} | ||
EXPORT_SYMBOL_GPL(nf_dup_ipv4); | ||
|
||
MODULE_AUTHOR("Sebastian Claßen <[email protected]>"); | ||
MODULE_AUTHOR("Jan Engelhardt <[email protected]>"); | ||
MODULE_DESCRIPTION("nf_dup_ipv4: Duplicate IPv4 packet"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* (C) 2007 by Sebastian Claßen <[email protected]> | ||
* (C) 2007-2010 by Jan Engelhardt <[email protected]> | ||
* | ||
* Extracted from xt_TEE.c | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 or later, as | ||
* published by the Free Software Foundation. | ||
*/ | ||
#include <linux/module.h> | ||
#include <linux/percpu.h> | ||
#include <linux/skbuff.h> | ||
#include <net/ipv6.h> | ||
#include <net/ip6_route.h> | ||
#include <net/netfilter/ipv6/nf_dup_ipv6.h> | ||
#if IS_ENABLED(CONFIG_NF_CONNTRACK) | ||
#include <net/netfilter/nf_conntrack.h> | ||
#endif | ||
|
||
static struct net *pick_net(struct sk_buff *skb) | ||
{ | ||
#ifdef CONFIG_NET_NS | ||
const struct dst_entry *dst; | ||
|
||
if (skb->dev != NULL) | ||
return dev_net(skb->dev); | ||
dst = skb_dst(skb); | ||
if (dst != NULL && dst->dev != NULL) | ||
return dev_net(dst->dev); | ||
#endif | ||
return &init_net; | ||
} | ||
|
||
static bool nf_dup_ipv6_route(struct sk_buff *skb, const struct in6_addr *gw, | ||
int oif) | ||
{ | ||
const struct ipv6hdr *iph = ipv6_hdr(skb); | ||
struct net *net = pick_net(skb); | ||
struct dst_entry *dst; | ||
struct flowi6 fl6; | ||
|
||
memset(&fl6, 0, sizeof(fl6)); | ||
if (oif != -1) | ||
fl6.flowi6_oif = oif; | ||
|
||
fl6.daddr = *gw; | ||
fl6.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) | | ||
(iph->flow_lbl[1] << 8) | iph->flow_lbl[2]; | ||
dst = ip6_route_output(net, NULL, &fl6); | ||
if (dst->error) { | ||
dst_release(dst); | ||
return false; | ||
} | ||
skb_dst_drop(skb); | ||
skb_dst_set(skb, dst); | ||
skb->dev = dst->dev; | ||
skb->protocol = htons(ETH_P_IPV6); | ||
|
||
return true; | ||
} | ||
|
||
void nf_dup_ipv6(struct sk_buff *skb, unsigned int hooknum, | ||
const struct in6_addr *gw, int oif) | ||
{ | ||
if (__this_cpu_read(nf_skb_duplicated)) | ||
return; | ||
skb = pskb_copy(skb, GFP_ATOMIC); | ||
if (skb == NULL) | ||
return; | ||
|
||
#if IS_ENABLED(CONFIG_NF_CONNTRACK) | ||
nf_conntrack_put(skb->nfct); | ||
skb->nfct = &nf_ct_untracked_get()->ct_general; | ||
skb->nfctinfo = IP_CT_NEW; | ||
nf_conntrack_get(skb->nfct); | ||
#endif | ||
if (hooknum == NF_INET_PRE_ROUTING || | ||
hooknum == NF_INET_LOCAL_IN) { | ||
struct ipv6hdr *iph = ipv6_hdr(skb); | ||
--iph->hop_limit; | ||
} | ||
if (nf_dup_ipv6_route(skb, gw, oif)) { | ||
__this_cpu_write(nf_skb_duplicated, true); | ||
ip6_local_out(skb); | ||
__this_cpu_write(nf_skb_duplicated, false); | ||
} else { | ||
kfree_skb(skb); | ||
} | ||
} | ||
EXPORT_SYMBOL_GPL(nf_dup_ipv6); | ||
|
||
MODULE_AUTHOR("Sebastian Claßen <[email protected]>"); | ||
MODULE_AUTHOR("Jan Engelhardt <[email protected]>"); | ||
MODULE_DESCRIPTION("nf_dup_ipv6: IPv6 packet duplication"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.