From f77a8e2eda03d6a33d71987a17bdee55128476f2 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 21 Nov 2008 00:41:56 +0100 Subject: [PATCH 1/5] TEE: do not use TOS for routing Otherwise the cloned packet may be subject to more policy routing rules than expected. --- extensions/xt_TEE.c | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/xt_TEE.c b/extensions/xt_TEE.c index 20d5d8a..447254d 100644 --- a/extensions/xt_TEE.c +++ b/extensions/xt_TEE.c @@ -57,7 +57,6 @@ static bool tee_routing(struct sk_buff *skb, .nl_u = { .ip4_u = { .daddr = info->gw.ip, - .tos = RT_TOS(iph->tos), .scope = RT_SCOPE_UNIVERSE, } } From 7a3f874753ca7d3964df7ab9f76dda011c332282 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 21 Nov 2008 00:16:11 +0100 Subject: [PATCH 2/5] TEE: various cleanups, add comments Normalize function names in light of upcoming IPv6 support. Reformat other lines. Add comment note about tee_send4. --- extensions/xt_TEE.c | 63 ++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/extensions/xt_TEE.c b/extensions/xt_TEE.c index 447254d..9ef79a8 100644 --- a/extensions/xt_TEE.c +++ b/extensions/xt_TEE.c @@ -29,7 +29,7 @@ static struct nf_conn tee_track; #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 @@ -47,20 +47,16 @@ static const union nf_inet_addr zero_address; * 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); @@ -71,22 +67,14 @@ static bool tee_routing(struct sk_buff *skb, 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; @@ -102,14 +90,14 @@ static bool dev_hh_avail(const struct net_device *dev) * 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)); @@ -141,7 +129,7 @@ static void tee_ip_direct_send(struct sk_buff *skb) * 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; @@ -199,8 +187,24 @@ tee_tg(struct sk_buff **pskb, const struct xt_target_param *par) 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; } @@ -210,7 +214,8 @@ static bool 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, &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 = { @@ -218,7 +223,7 @@ 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, @@ -252,7 +257,7 @@ static void __exit tee_tg_exit(void) module_init(tee_tg_init); module_exit(tee_tg_exit); MODULE_AUTHOR("Sebastian Claßen "); -MODULE_AUTHOR("Jan Engelhardt "); +MODULE_AUTHOR("Jan Engelhardt "); MODULE_DESCRIPTION("Xtables: Reroute packet copy"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_TEE"); From 4aad07bdc4efe1662fe43bd1b0379af4fcde1e0e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 21 Nov 2008 01:14:01 +0100 Subject: [PATCH 3/5] TEE: IPv6 support --- extensions/xt_TEE.c | 105 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/extensions/xt_TEE.c b/extensions/xt_TEE.c index 9ef79a8..fce7adf 100644 --- a/extensions/xt_TEE.c +++ b/extensions/xt_TEE.c @@ -1,7 +1,7 @@ /* * "TEE" target extension for Xtables * Copyright © Sebastian Claßen , 2007 - * Jan Engelhardt , 2007 + * Jan Engelhardt , 2007 - 2008 * * based on ipt_ROUTE.c from Cédric de Launois * @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -209,6 +210,73 @@ tee_tg4(struct sk_buff **pskb, const struct xt_target_param *par) return XT_CONTINUE; } +static bool +tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info) +{ + struct dst_entry *dst; + struct flowi fl; + + memset(&fl, 0, sizeof(fl)); + fl.nl_u.ip6_u.daddr = info->gw.in6; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 25) + dst = ip6_route_output(NULL, &fl); +#else + dst = ip6_route_output(dev_net(skb->dev), NULL, &fl); +#endif + if (dst == NULL) { + if (net_ratelimit()) + printk(KERN_ERR "ip6_route_output failed for tee\n"); + return false; + } + + dst_release(skb->dst); + skb->dst = dst; + skb->dev = skb->dst->dev; + skb->protocol = htons(ETH_P_IPV6); + return true; +} + +static void tee_tg_send6(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + + 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_tg6(struct sk_buff **pskb, const struct xt_target_param *par) +{ + const struct xt_tee_tginfo *info = par->targinfo; + struct sk_buff *skb = *pskb; + + /* Try silence. */ +#ifdef WITH_CONNTRACK + if (skb->nfct == &tee_track.ct_general) + return NF_DROP; +#endif + + if ((skb = skb_copy(skb, GFP_ATOMIC)) == NULL) + return XT_CONTINUE; + +#ifdef WITH_CONNTRACK + nf_conntrack_put(skb->nfct); + skb->nfct = &tee_track.ct_general; + skb->nfctinfo = IP_CT_NEW; + nf_conntrack_get(skb->nfct); +#endif + if (tee_tg_route6(skb, info)) + tee_tg_send6(skb); + + return XT_CONTINUE; +} + static bool tee_tg_check(const struct xt_tgchk_param *par) { const struct xt_tee_tginfo *info = par->targinfo; @@ -218,15 +286,27 @@ static bool tee_tg_check(const struct xt_tgchk_param *par) sizeof(tee_zero_address)) != 0; } -static struct xt_target tee_tg_reg __read_mostly = { - .name = "TEE", - .revision = 0, - .family = NFPROTO_IPV4, - .table = "mangle", - .target = tee_tg4, - .targetsize = sizeof(struct xt_tee_tginfo), - .checkentry = tee_tg_check, - .me = THIS_MODULE, +static struct xt_target tee_tg_reg[] __read_mostly = { + { + .name = "TEE", + .revision = 0, + .family = NFPROTO_IPV4, + .table = "mangle", + .target = tee_tg4, + .targetsize = sizeof(struct xt_tee_tginfo), + .checkentry = tee_tg_check, + .me = THIS_MODULE, + }, + { + .name = "TEE", + .revision = 0, + .family = NFPROTO_IPV6, + .table = "mangle", + .target = tee_tg6, + .targetsize = sizeof(struct xt_tee_tginfo), + .checkentry = tee_tg_check, + .me = THIS_MODULE, + }, }; static int __init tee_tg_init(void) @@ -245,12 +325,12 @@ static int __init tee_tg_init(void) tee_track.status |= IPS_NAT_DONE_MASK; #endif - return xt_register_target(&tee_tg_reg); + return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); } static void __exit tee_tg_exit(void) { - xt_unregister_target(&tee_tg_reg); + xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); /* [SC]: shoud not we cleanup tee_track here? */ } @@ -261,3 +341,4 @@ MODULE_AUTHOR("Jan Engelhardt "); MODULE_DESCRIPTION("Xtables: Reroute packet copy"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_TEE"); +MODULE_ALIAS("ip6t_TEE"); From b95e5f6417fac4437705e834b242823d59be4340 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 10 Jan 2009 10:19:21 +0100 Subject: [PATCH 4/5] TEE: IPv6 support for iptables module --- extensions/libxt_TEE.c | 65 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/extensions/libxt_TEE.c b/extensions/libxt_TEE.c index f6d5583..f1a65a1 100644 --- a/extensions/libxt_TEE.c +++ b/extensions/libxt_TEE.c @@ -1,7 +1,7 @@ /* * "TEE" target extension for iptables * Copyright © Sebastian Claßen , 2007 - * Jan Engelhardt , 2007 - 2008 + * Jan Engelhardt , 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 @@ -70,6 +70,35 @@ static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags, 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) + exit_error(PARAMETER_PROBLEM, + "Cannot specify --gw more than once"); + + if (check_inverse(optarg, &invert, NULL, 0)) + exit_error(PARAMETER_PROBLEM, + "Unexpected \"!\" after --gateway"); + + ia = numeric_to_ip6addr(optarg); + if (ia == NULL) + exit_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) @@ -88,6 +117,17 @@ static void tee_tg_print(const void *ip, const struct xt_entry_target *target, printf("TEE gw:%s ", 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 ", ip6addr_to_numeric(&info->gw.in6)); + else + printf("TEE gw:%s ", 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; @@ -95,6 +135,13 @@ static void tee_tg_save(const void *ip, const struct xt_entry_target *target) printf("--gateway %s ", 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 ", ip6addr_to_numeric(&info->gw.in6)); +} + static struct xtables_target tee_tg_reg = { .name = "TEE", .version = XTABLES_VERSION, @@ -110,7 +157,23 @@ static struct xtables_target tee_tg_reg = { .extra_opts = tee_tg_opts, }; +static struct xtables_target tee_tg6_reg = { + .name = "TEE", + .version = XTABLES_VERSION, + .revision = 0, + .family = PF_INET6, + .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_target(&tee_tg_reg); + xtables_register_target(&tee_tg6_reg); } From 9ed364ed369fb72cebc31c2da736b1a9d9396852 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 10 Jan 2009 13:58:19 +0100 Subject: [PATCH 5/5] TEE: collapse tee_tg_send{4,6} --- extensions/xt_TEE.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/extensions/xt_TEE.c b/extensions/xt_TEE.c index fce7adf..265fc90 100644 --- a/extensions/xt_TEE.c +++ b/extensions/xt_TEE.c @@ -91,7 +91,7 @@ static inline bool dev_hh_avail(const struct net_device *dev) * POST: the packet is sent with the link layer header pushed * the packet is destroyed */ -static void tee_tg_send4(struct sk_buff *skb) +static void tee_tg_send(struct sk_buff *skb) { const struct dst_entry *dst = skb->dst; const struct net_device *dev = dst->dev; @@ -205,7 +205,7 @@ tee_tg4(struct sk_buff **pskb, const struct xt_target_param *par) * packet as best as possible. */ if (tee_tg_route4(skb, info)) - tee_tg_send4(skb); + tee_tg_send(skb); return XT_CONTINUE; } @@ -237,19 +237,6 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info) return true; } -static void tee_tg_send6(struct sk_buff *skb) -{ - struct dst_entry *dst = skb->dst; - - 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_tg6(struct sk_buff **pskb, const struct xt_target_param *par) { @@ -272,7 +259,7 @@ tee_tg6(struct sk_buff **pskb, const struct xt_target_param *par) nf_conntrack_get(skb->nfct); #endif if (tee_tg_route6(skb, info)) - tee_tg_send6(skb); + tee_tg_send(skb); return XT_CONTINUE; }