使用u32和扩展头(如何跳过它们?)

我试图过滤有效负载的某些部分,用于扩展头的IPv6数据包(例如Destination Options)。

即使数据包有扩展头,ip6tables也可以正常工作,如--proto udp--dport 109 。 Netfilter显然知道如何跳过目的地选项来查找UDP标头。

现在,我想使用u32模块来匹配有效载荷中的一个字节(比如说“我希望有效负载的第三个字节是42)。如果数据包没有扩展头,就像--u32 "48&0x0000ff00=0x2800"̀ 48 = 40个字节的IPv6头+8的UDP头)工作正常,如果数据包有一个目的地选项,它不再匹配。我想写一个规则,无论数据包是否有目的地选项或不。

我没有find一种方式告诉Netfilterparsing,直到UDP头(它能够做的事,否则--dport 109不会工作),然后离开u32parsing其余的。

我正在寻找一个简单的方法,否则,正如BatchyX提到的,我可以编写一个内核模块来做我想做的事情。

答案主要集中在解决IPv4数据包的问题,​​并没有解决在计算适当的偏移量之前需要考虑的(多个)扩展头的问题才能得到真实的数据部分。

以下规则由2部分组成

  • 检查是否udp 6&0xFF=17
  • 检查第三个数据字节是否设置为42(hex0x2A) 0>>22&0x3C@7&0xFF=0x2A

iptables -I INPUT -m u32 --u32 "6&0xFF=17&&0>>22&0x3C@7&0xFF=0x2A" -m comment --comment "Match udp packet with 3rd data byte set to 42" -j LOG

检查第3个字节是棘手的,因为您需要dynamic地在UDP头中定位。 UDP报头在IP报头之后开始;

检查此标题模型,以更好地了解什么地方。

正如你所看到的,20个字节是IP头的最小长度,但是如果有任何数据的选项,它可以超过20个字节,所以你需要dynamic地将你自己定位到UDP头的起始位置。

从前4个字节读取(32位/ u32)

来自 :

为了得到头部长度,我们需要第一个字节:“0 >> 24”,但是我们只需要抓取下半部分,我们需要将这个数字乘以4来得到头部中的实际字节数。 为了进行乘法运算,我们将右移22位而不是24位。有了这个转换,我们需要使用0x3C的掩码,而不是我们已经使用的0x0F。 到目前为止的expression式是:“0 >> 22&0x3C”。

现在我们已经抵消了UDP头部开始的位置(0 >> 22&0x3C),我们可以自己读取字节7,8,9,10(数据字节是8,9,10),并用掩码0xFF 4(第3个数据字节)。 “7为0xFF”

我遇到了同样的问题,并修补了u32模块。 我有两个用于2.6.30内核的补丁,一个用于内核,另一个用于用户登陆,他们可能不会处理零碎的有效载荷比原始的u32匹配器更好,但是它对我的问题起作用。


内核补丁:

 diff -ruNd linux-2.6.30.4patch/net/netfilter/xt_u32.c linux-2.6.30/net/netfilter/xt_u32.c --- linux-2.6.30.4patch/net/netfilter/xt_u32.c 2014-03-19 13:24:06.000000000 +0100 +++ linux-2.6.30/net/netfilter/xt_u32.c 2014-10-02 13:12:33.244444192 +0200 @@ -13,9 +13,13 @@ #include <linux/types.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_u32.h> +#include <net/tcp.h> +#include <net/udp.h> + static bool u32_match_it(const struct xt_u32 *data, - const struct sk_buff *skb) + const struct sk_buff *skb, + unsigned int PayloadOffset) { const struct xt_u32_test *ct; unsigned int testind; @@ -34,7 +38,7 @@ for (testind = 0; testind < data->ntests; ++testind) { ct = &data->tests[testind]; at = 0; - pos = ct->location[0].number; + pos = PayloadOffset + ct->location[0].number; if (skb->len < 4 || pos > skb->len - 4) return false; @@ -92,27 +96,91 @@ const struct xt_u32 *data = par->matchinfo; bool ret; - ret = u32_match_it(data, skb); + ret = u32_match_it(data, skb, 0); return ret ^ data->invert; } -static struct xt_match xt_u32_mt_reg __read_mostly = { - .name = "u32", - .revision = 0, - .family = NFPROTO_UNSPEC, - .match = u32_mt, - .matchsize = sizeof(struct xt_u32), - .me = THIS_MODULE, +static bool u32_tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +{ + const struct xt_u32 *data = par->matchinfo; + const struct tcphdr *th; + struct tcphdr _tcph; + bool ret; + + th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return false; + + if (th->doff*4 < sizeof(*th)) + return false; + + /* printk("TCP payload match @%d\n", par->thoff + 4*th->doff); */ + ret = u32_match_it(data, skb, par->thoff + 4*th->doff); + return ret ^ data->invert; +} + +static bool u32_udp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +{ + const struct xt_u32 *data = par->matchinfo; + bool ret; + + /* printk("UDP payload match @%d\n", par->thoff + sizeof(struct udphdr) ); */ + ret = u32_match_it(data, skb, par->thoff + sizeof(struct udphdr) ); + return ret ^ data->invert; +} + +static struct xt_match xt_u32_mt_reg[] __read_mostly = { + { + .name = "u32", + .revision = 0, + .family = NFPROTO_UNSPEC, + .match = u32_mt, + .matchsize = sizeof(struct xt_u32), + .me = THIS_MODULE, + }, + { + .name = "payload", + .family = NFPROTO_IPV4, + .match = u32_tcp_mt, + .matchsize = sizeof(struct xt_u32), + .proto = IPPROTO_TCP, + .me = THIS_MODULE, + }, + { + .name = "payload", + .family = NFPROTO_IPV6, + .match = u32_tcp_mt, + .matchsize = sizeof(struct xt_u32), + .proto = IPPROTO_TCP, + .me = THIS_MODULE, + }, + { + .name = "payload", + .family = NFPROTO_IPV4, + .match = u32_udp_mt, + .matchsize = sizeof(struct xt_u32), + .proto = IPPROTO_UDP, + .me = THIS_MODULE, + }, + { + .name = "payload", + .family = NFPROTO_IPV6, + .match = u32_udp_mt, + .matchsize = sizeof(struct xt_u32), + .proto = IPPROTO_UDP, + .me = THIS_MODULE, + }, + }; static int __init u32_mt_init(void) { - return xt_register_match(&xt_u32_mt_reg); + return xt_register_matches(xt_u32_mt_reg, ARRAY_SIZE(xt_u32_mt_reg)); } static void __exit u32_mt_exit(void) { - xt_unregister_match(&xt_u32_mt_reg); + xt_unregister_matches(xt_u32_mt_reg, ARRAY_SIZE(xt_u32_mt_reg)); } module_init(u32_mt_init); @@ -122,3 +190,5 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_u32"); MODULE_ALIAS("ip6t_u32"); +MODULE_ALIAS("ipt_payload"); +MODULE_ALIAS("ip6t_payload"); 

用户地块:

 diff -ruNd iptables-1.4.12.1.4patch/extensions/GNUmakefile.in iptables-1.4.12.1/extensions/GNUmakefile.in --- iptables-1.4.12.1.4patch/extensions/GNUmakefile.in 2014-10-02 14:43:19.000000000 +0200 +++ iptables-1.4.12.1/extensions/GNUmakefile.in 2014-10-02 14:29:54.000000000 +0200 @@ -73,6 +73,7 @@ install: ${targets_install} @mkdir -p "${DESTDIR}${xtlibdir}"; if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi; + test -f "${DESTDIR}${xtlibdir}/libxt_u32.so" && ln -s "${DESTDIR}${xtlibdir}/libxt_u32.so" "${DESTDIR}${xtlibdir}/libxt_payload.so" clean: rm -f *.o *.oo *.so *.a {matches,targets}[46].man initext.c initext4.c initext6.c; diff -ruNd iptables-1.4.12.1.4patch/extensions/libxt_u32.c iptables-1.4.12.1/extensions/libxt_u32.c --- iptables-1.4.12.1.4patch/extensions/libxt_u32.c 2014-10-02 14:43:19.000000000 +0200 +++ iptables-1.4.12.1/extensions/libxt_u32.c 2014-10-02 13:57:24.000000000 +0200 @@ -31,7 +31,7 @@ static void u32_help(void) { printf( - "u32 match options:\n" + "u32/payload match options:\n" "[!] --u32 tests\n" "\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n" "\t\t""value := range | value \",\" range\n" @@ -249,7 +249,7 @@ int numeric) { const struct xt_u32 *data = (const void *)match->data; - printf(" u32"); + printf(" %s", match->u.user.name); if (data->invert) printf(" !"); u32_dump(data); @@ -277,7 +277,21 @@ .x6_options = u32_opts, }; +static struct xtables_match payload_match = { + .name = "payload", + .family = NFPROTO_UNSPEC, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_u32)), + .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), + .help = u32_help, + .print = u32_print, + .save = u32_save, + .x6_parse = u32_parse, + .x6_options = u32_opts, +}; + void _init(void) { xtables_register_match(&u32_match); + xtables_register_match(&payload_match); }