#include "compat_xtables.h"
#include "xt_TEE.h"
-static const union nf_inet_addr zero_address;
+static const union nf_inet_addr tee_zero_address;
/*
* Try to route the packet according to the routing keys specified in
* true - if the packet was succesfully routed to the
* destination desired
*/
-static bool tee_routing(struct sk_buff *skb,
- const struct xt_tee_tginfo *info)
+static bool
+tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
{
int err;
struct rtable *rt;
- struct iphdr *iph = ip_hdr(skb);
- struct flowi fl = {
- .nl_u = {
- .ip4_u = {
- .daddr = info->gw.ip,
- .scope = RT_SCOPE_UNIVERSE,
- }
- }
- };
+ struct flowi fl;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.nl_u.ip4_u.daddr = info->gw.ip;
+ fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE;
/* Trying to route the packet using the standard routing table. */
err = ip_route_output_key(&init_net, &rt, &fl);
return false;
}
- /* Drop old route. */
dst_release(skb->dst);
- skb->dst = NULL;
-
- /*
- * Success if no oif specified or if the oif correspond to the
- * one desired.
- * [SC]: always the case, because we have no oif.
- */
skb->dst = &rt->u.dst;
skb->dev = skb->dst->dev;
skb->protocol = htons(ETH_P_IP);
return true;
}
-static bool dev_hh_avail(const struct net_device *dev)
+static inline bool dev_hh_avail(const struct net_device *dev)
{
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return dev->hard_header != NULL;
* POST: the packet is sent with the link layer header pushed
* the packet is destroyed
*/
-static void tee_ip_direct_send(struct sk_buff *skb)
+static void tee_tg_send4(struct sk_buff *skb)
{
const struct dst_entry *dst = skb->dst;
const struct net_device *dev = dst->dev;
unsigned int hh_len = LL_RESERVED_SPACE(dev);
/* Be paranoid, rather than too clever. */
- if (unlikely(skb_headroom(skb) < hh_len) && dev_hh_avail(dev)) {
+ if (unlikely(skb_headroom(skb) < hh_len && dev_hh_avail(dev))) {
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
* packets when we see they already have that ->nfct.
*/
static unsigned int
-tee_tg(struct sk_buff **pskb, const struct xt_target_param *par)
+tee_tg4(struct sk_buff **pskb, const struct xt_target_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
struct sk_buff *skb = *pskb;
nf_conntrack_get(skb->nfct);
#endif
- if (tee_routing(skb, info))
- tee_ip_direct_send(skb);
+ /*
+ * Normally, we would just use ip_local_out. Because iph->check is
+ * already correct, we could take a shortcut and call dst_output
+ * [forwards to ip_output] directly. ip_output however will invoke
+ * Netfilter hooks and cause reentrancy. So we skip that too and go
+ * directly to ip_finish_output. Since we should not do XFRM, control
+ * passes to ip_finish_output2. That function is not exported, so it is
+ * copied here as tee_ip_direct_send.
+ *
+ * We do no XFRM on the cloned packet on purpose! The choice of
+ * iptables match options will control whether the raw packet or the
+ * transformed version is cloned.
+ *
+ * Also on purpose, no fragmentation is done, to preserve the
+ * packet as best as possible.
+ */
+ if (tee_tg_route4(skb, info))
+ tee_tg_send4(skb);
return XT_CONTINUE;
}
const struct xt_tee_tginfo *info = par->targinfo;
/* 0.0.0.0 and :: not allowed */
- return memcmp(&info->gw, &zero_address, sizeof(zero_address)) != 0;
+ return memcmp(&info->gw, &tee_zero_address,
+ sizeof(tee_zero_address)) != 0;
}
static struct xt_target tee_tg_reg __read_mostly = {
.revision = 0,
.family = NFPROTO_IPV4,
.table = "mangle",
- .target = tee_tg,
+ .target = tee_tg4,
.targetsize = sizeof(struct xt_tee_tginfo),
.checkentry = tee_tg_check,
.me = THIS_MODULE,
module_init(tee_tg_init);
module_exit(tee_tg_exit);
MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_DESCRIPTION("Xtables: Reroute packet copy");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_TEE");