+++ /dev/null
-/*
- * "TEE" target extension for iptables
- * Copyright © Sebastian Claßen <sebastian.classen [at] freenet.ag>, 2007
- * Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2009
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License; either
- * version 2 of the License, or any later version, as published by the
- * Free Software Foundation.
- */
-#include <sys/socket.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/in.h>
-
-#include <xtables.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/x_tables.h>
-#include "xt_TEE.h"
-#include "compat_user.h"
-
-enum {
- FLAG_GATEWAY = 1 << 0,
-};
-
-static const struct option tee_tg_opts[] = {
- {.name = "gateway", .has_arg = true, .val = 'g'},
- {NULL},
-};
-
-static void tee_tg_help(void)
-{
- printf(
-"TEE target options:\n"
-" --gateway IPADDR Route packet via the gateway given by address\n"
-"\n");
-}
-
-static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
-{
- struct xt_tee_tginfo *info = (void *)(*target)->data;
- const struct in_addr *ia;
-
- switch (c) {
- case 'g':
- if (*flags & FLAG_GATEWAY)
- xtables_error(PARAMETER_PROBLEM,
- "Cannot specify --gateway more than once");
-
- ia = xtables_numeric_to_ipaddr(optarg);
- if (ia == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid IP address %s", optarg);
-
- memcpy(&info->gw, ia, sizeof(*ia));
- *flags |= FLAG_GATEWAY;
- return true;
- }
-
- return false;
-}
-
-static int tee_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
- const void *entry, struct xt_entry_target **target)
-{
- struct xt_tee_tginfo *info = (void *)(*target)->data;
- const struct in6_addr *ia;
-
- switch (c) {
- case 'g':
- if (*flags & FLAG_GATEWAY)
- xtables_error(PARAMETER_PROBLEM,
- "Cannot specify --gateway more than once");
-
- ia = xtables_numeric_to_ip6addr(optarg);
- if (ia == NULL)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid IP address %s", optarg);
-
- memcpy(&info->gw, ia, sizeof(*ia));
- *flags |= FLAG_GATEWAY;
- return true;
- }
-
- return false;
-}
-
-static void tee_tg_check(unsigned int flags)
-{
- if (flags == 0)
- xtables_error(PARAMETER_PROBLEM, "TEE target: "
- "--gateway parameter required");
-}
-
-static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct xt_tee_tginfo *info = (const void *)target->data;
-
- if (numeric)
- printf(" TEE gw:%s ", xtables_ipaddr_to_numeric(&info->gw.in));
- else
- printf(" TEE gw:%s ", xtables_ipaddr_to_anyname(&info->gw.in));
-}
-
-static void tee_tg6_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- const struct xt_tee_tginfo *info = (const void *)target->data;
-
- if (numeric)
- printf(" TEE gw:%s ", xtables_ip6addr_to_numeric(&info->gw.in6));
- else
- printf(" TEE gw:%s ", xtables_ip6addr_to_anyname(&info->gw.in6));
-}
-
-static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct xt_tee_tginfo *info = (const void *)target->data;
-
- printf(" --gateway %s ", xtables_ipaddr_to_numeric(&info->gw.in));
-}
-
-static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
-{
- const struct xt_tee_tginfo *info = (const void *)target->data;
-
- printf(" --gateway %s ", xtables_ip6addr_to_numeric(&info->gw.in6));
-}
-
-static struct xtables_target tee_tg_reg[] = {
- {
- .name = "TEE",
- .version = XTABLES_VERSION,
- .revision = 0,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
- .help = tee_tg_help,
- .parse = tee_tg_parse,
- .final_check = tee_tg_check,
- .print = tee_tg_print,
- .save = tee_tg_save,
- .extra_opts = tee_tg_opts,
- },
- {
- .name = "TEE",
- .version = XTABLES_VERSION,
- .revision = 0,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
- .help = tee_tg_help,
- .parse = tee_tg6_parse,
- .final_check = tee_tg_check,
- .print = tee_tg6_print,
- .save = tee_tg6_save,
- .extra_opts = tee_tg_opts,
- },
-};
-
-static __attribute__((constructor)) void tee_tg_ldr(void)
-{
- xtables_register_targets(tee_tg_reg,
- sizeof(tee_tg_reg) / sizeof(*tee_tg_reg));
-}
+++ /dev/null
-/*
- * "TEE" target extension for Xtables
- * Copyright © Sebastian Claßen <sebastian.classen [at] freenet de>, 2007
- * Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2008
- *
- * based on ipt_ROUTE.c from Cédric de Launois
- * <delaunois [at] info ucl ac be>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, as published by the Free Software Foundation.
- */
-#include <linux/ip.h>
-#include <linux/module.h>
-#include <linux/route.h>
-#include <linux/skbuff.h>
-#include <linux/version.h>
-#include <net/checksum.h>
-#include <net/icmp.h>
-#include <net/ip.h>
-#include <net/ip6_route.h>
-#include <net/route.h>
-#include <linux/netfilter/x_tables.h>
-
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-# define WITH_CONNTRACK 1
-# include <net/netfilter/nf_conntrack.h>
-#endif
-#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-# define WITH_IPV6 1
-#endif
-
-#include "compat_xtables.h"
-#include "xt_TEE.h"
-
-static bool tee_active[NR_CPUS];
-static const union nf_inet_addr tee_zero_address;
-
-static bool
-tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
-{
- const struct iphdr *iph = ip_hdr(skb);
- struct rtable *rt;
- struct flowi fl;
-
- memset(&fl, 0, sizeof(fl));
- fl.nl_u.ip4_u.daddr = info->gw.ip;
- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
- fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE;
-
- if (ip_route_output_key(&init_net, &rt, &fl) != 0)
- return false;
-
- dst_release(skb_dst(skb));
- skb_dst_set(skb, rt_dst(rt));
- skb->dev = rt_dst(rt)->dev;
- skb->protocol = htons(ETH_P_IP);
- return true;
-}
-
-static inline bool dev_hh_avail(const struct net_device *dev)
-{
- return dev->header_ops != NULL;
-}
-
-/*
- * Stolen from ip_finish_output2
- * PRE : skb->dev is set to the device we are leaving by
- * skb->dst is not NULL
- * POST: the packet is sent with the link layer header pushed
- * the packet is destroyed
- */
-static void tee_tg_send(struct sk_buff *skb)
-{
- const struct dst_entry *dst = skb_dst(skb);
- 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))) {
- struct sk_buff *skb2;
-
- skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
- if (skb2 == NULL) {
- kfree_skb(skb);
- return;
- }
- if (skb->sk != NULL)
- skb_set_owner_w(skb2, skb->sk);
- kfree_skb(skb);
- skb = skb2;
- }
-
- if (dst->hh != NULL)
- neigh_hh_output(dst->hh, skb);
- else if (dst->neighbour != NULL)
- dst->neighbour->output(skb);
- else
- kfree_skb(skb);
-}
-
-static unsigned int
-tee_tg4(struct sk_buff **pskb, const struct xt_action_param *par)
-{
- const struct xt_tee_tginfo *info = par->targinfo;
- struct sk_buff *skb = *pskb;
- struct iphdr *iph;
- unsigned int cpu = smp_processor_id();
-
- if (tee_active[cpu])
- return XT_CONTINUE;
- /*
- * 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 TEE
- * --gateway.
- */
- skb = pskb_copy(skb, GFP_ATOMIC);
- if (skb == NULL)
- return XT_CONTINUE;
- /*
- * 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 TEE 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 (par->hooknum == NF_INET_PRE_ROUTING ||
- par->hooknum == NF_INET_LOCAL_IN)
- --iph->ttl;
- ip_send_check(iph);
-
-#ifdef WITH_CONNTRACK
- /*
- * Tell conntrack to forget this packet. It may have side effects to
- * see the same packet twice, as for example, accounting the original
- * connection for the cloned packet.
- */
- nf_conntrack_put(skb->nfct);
- skb->nfct = &nf_conntrack_untracked.ct_general;
- skb->nfctinfo = IP_CT_NEW;
- nf_conntrack_get(skb->nfct);
-#endif
-
- /*
- * 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_active[cpu] = true;
- tee_tg_send(skb);
- tee_active[cpu] = false;
- } else {
- kfree_skb(skb);
- }
- return XT_CONTINUE;
-}
-
-#ifdef WITH_IPV6
-static bool
-tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
-{
- const struct ipv6hdr *iph = ipv6_hdr(skb);
- struct dst_entry *dst;
- struct flowi fl;
-
- memset(&fl, 0, sizeof(fl));
- fl.nl_u.ip6_u.daddr = info->gw.in6;
- fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
- (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
-
- dst = ip6_route_output(dev_net(skb->dev), NULL, &fl);
- if (dst == NULL)
- return false;
-
- dst_release(skb_dst(skb));
- skb_dst_set(skb, dst);
- skb->dev = dst->dev;
- skb->protocol = htons(ETH_P_IPV6);
- return true;
-}
-
-static unsigned int
-tee_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
-{
- const struct xt_tee_tginfo *info = par->targinfo;
- struct sk_buff *skb = *pskb;
- unsigned int cpu = smp_processor_id();
-
- if (tee_active[cpu])
- return XT_CONTINUE;
- skb = pskb_copy(skb, GFP_ATOMIC);
- if (skb == NULL)
- return XT_CONTINUE;
-
-#ifdef WITH_CONNTRACK
- nf_conntrack_put(skb->nfct);
- skb->nfct = &nf_conntrack_untracked.ct_general;
- skb->nfctinfo = IP_CT_NEW;
- nf_conntrack_get(skb->nfct);
-#endif
- if (par->hooknum == NF_INET_PRE_ROUTING ||
- par->hooknum == NF_INET_LOCAL_IN) {
- struct ipv6hdr *iph = ipv6_hdr(skb);
- --iph->hop_limit;
- }
- if (tee_tg_route6(skb, info)) {
- tee_active[cpu] = true;
- tee_tg_send(skb);
- tee_active[cpu] = false;
- } else {
- kfree_skb(skb);
- }
- return XT_CONTINUE;
-}
-#endif /* WITH_IPV6 */
-
-static int tee_tg_check(const struct xt_tgchk_param *par)
-{
- const struct xt_tee_tginfo *info = par->targinfo;
-
- /* 0.0.0.0 and :: not allowed */
- return (memcmp(&info->gw, &tee_zero_address,
- sizeof(tee_zero_address)) == 0) ? -EINVAL : 0;
-}
-
-static struct xt_target tee_tg_reg[] __read_mostly = {
- {
- .name = "TEE",
- .revision = 0,
- .family = NFPROTO_IPV4,
- .target = tee_tg4,
- .targetsize = sizeof(struct xt_tee_tginfo),
- .checkentry = tee_tg_check,
- .me = THIS_MODULE,
- },
-#ifdef WITH_IPV6
- {
- .name = "TEE",
- .revision = 0,
- .family = NFPROTO_IPV6,
- .target = tee_tg6,
- .targetsize = sizeof(struct xt_tee_tginfo),
- .checkentry = tee_tg_check,
- .me = THIS_MODULE,
- },
-#endif
-};
-
-static int __init tee_tg_init(void)
-{
- return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
-}
-
-static void __exit tee_tg_exit(void)
-{
- xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
-}
-
-module_init(tee_tg_init);
-module_exit(tee_tg_exit);
-MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
-MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
-MODULE_DESCRIPTION("Xtables: Reroute packet copy");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("ipt_TEE");
-MODULE_ALIAS("ip6t_TEE");