![将 u32 与扩展头一起使用(如何跳过它们?)](https://linux22.com/image/795728/%E5%B0%86%20u32%20%E4%B8%8E%E6%89%A9%E5%B1%95%E5%A4%B4%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8%EF%BC%88%E5%A6%82%E4%BD%95%E8%B7%B3%E8%BF%87%E5%AE%83%E4%BB%AC%EF%BC%9F%EF%BC%89.png)
我正在尝试过滤 IPv6 数据包的有效载荷的某些部分 和扩展头(例如目标选项)。
ip6tables 在诸如--proto udp
或 之类的条件下工作良好--dport 109
,即使数据包具有扩展报头。Netfilter 清楚地知道如何跳过目标选项来查找 UDP 报头。
现在,我想使用 u32 模块来匹配有效载荷中的一个字节(例如“我希望有效载荷的第三个字节为 42”。如果数据包没有扩展报头,则类似--u32 "48&0x0000ff00=0x2800"̀
(48 = IPv6 报头的 40 个字节 + UDP 报头的 8 个字节)的规则可以正常工作,如果数据包具有目标选项,则它不再匹配。我想编写一条规则,无论数据包是否具有目标选项,该规则都可以正常工作。
我没有找到一种方法来告诉 Netfilter 解析 UDP 标头(它可以做到这一点,否则--dport 109
将不起作用)然后让 u32 解析其余部分。
我正在寻找简单的方法,否则,正如 BatchyX 提到的,我可以编写一个内核模块来做我想做的事情。
答案1
答案主要集中于解决 IPv4 数据包的问题,并没有解决在计算适当的偏移量以获取真实数据部分之前需要考虑的(多个)扩展头的问题。
以下规则由两部分组成
- 检查是否为 udp
6&0xFF=17
- 检查第三个数据字节是否设置为 42(十六进制 0x2A)
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 个字节比较棘手,因为您需要在 UDP 报头中动态定位。UDP 报头在 IP 报头之后开始;
检查一下标题模型以更好地了解什么东西在哪里。
如您所见,20 字节是 IP 报头的最小长度,但是如果有任何数据的选项,则长度可能会超过 20 字节,因此您需要动态地将自己定位到 UDP 报头的开头。
从前 4 个字节读取位置( 32 位 / u32)
引用从:
要获取报头长度,我们需要第一个字节:“0>>24”,但我们只需要抓取低半字节,并将该数字乘以 4 即可获得报头中的实际字节数。要进行乘法,我们将右移 22 而不是 24。进行此移位后,我们需要使用掩码 0x3C,而不是我们原本使用的 0x0F。到目前为止的表达式为:“0>>22&0x3C”。
现在我们已经知道了 UDP 报头的起始偏移量(0>>22&0x3C),我们可以定位自己去读取字节 7、8、9、10(其中数据字节为 8、9、10),并用掩码 0xFF(最后一个 4 个字节,即第 3 个数据字节)截断。“7&0xFF”
答案2
我遇到了同样的问题,并修补了 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);
}