iptables u32 match 对字节后退的支持
偶尔怀旧,总想起十几年前修改优化 iptables,总是不经意间修改几行代码,或照猫画虎写个 Netfilter 模块就能获得质的飞跃,不管是功能还是性能。这么多年过去了,我还是一如既往不会编程,还是只能改几行代码,这种能力迫使我思考最简单的方案,而不是为了展现高尚的编程能力把问题复杂化,精巧的事总是懒人才做。
上周花了 5 分钟改了一下代码,算上 xt_u32.ko 内核模块和 libxt_u32.so iptables 模块,一共改了不到 5 行,让 u32 可以在任意 offset 后做减法,从而支持任意字节后退,但它依然不支持 “@” 直接寻址后的字节后退,如下指令:
0>>22&0x3C@12>>26&0x3C@-1=0:255
虽然我可以用下面已经支持的指令等价:
0>>22&0x3C@12>>26&0x3C-1@0=0:255
但实在闲着没事了,那就再改几行代码,把它全部支持了。我不会编程,所以只能做这种只改几行代码的事。
下面是 iptables libxt_u32.so 代码的修改:
// iptables-1.8.8# vi extensions/libxt_u32.c
static void u32_parse(struct xt_option_call *cb)
{...} else if (*arg == '@') {ct->location[locind].nextop = XT_U32_AT;
# ifdef pixie if (*(arg + 1) == '-') {ct->location[locind].nextop = XT_U32_AT + 2; // AT_NEG++arg;}} else if (*arg == '-') {ct->location[locind].nextop = XT_U32_NEG; // XT_U32_NEG = XT_U32_AT + 1
# endif } else {...
}
下面是内核模块 xt_u32.ko 的修改:
// linux-source/net/netfilter# vi xt_u32.c
static bool u32_match_it(const struct xt_u32 *data,const struct sk_buff *skb)
{...for (testind = 0; testind < data->ntests; ++testind) {...for (i = 1; i < nnums; ++i) {...
# ifdef pixiecase /*XT_U32_NEG*/XT_U32_AT + 1:val -= number;if (val < 0)return false;break;case /*XT_U32_AT_NEG*/XT_U32_AT + 2:val -= number;number = 0;case XT_U32_AT:// if (at + val < at) // 这里明确不支持 @负数,注释掉它if (at + val < 0) // 保持在 IP 头后即可
# elsecase XT_U32_AT:if (at + val < at)
# endif return false;at += val;pos = number;...
}
如此修改,match 中普通 uint32 数字和 “@” 后都可以跟负数实现任意后退了。非常皮鞋,而且又非常经理。
不过貌似什么需求能用到负数,因为任何 offset @ -n 都可以手工算出一个正数直接寻址,大可不必先前进再后退,但如果匹配 “TCP 是否有 payload” 这件事时就很麻烦,就不能用下面的指令:
0>>22&0x3C@12>>26&0x3C@0&0xFF
这个指令希望巧妙利用 u32 manual 中描述的 match fali:
Any access of memory outside [skb->data,skb->end] causes the match to fail.
但由于 u32 match 只能 u32 4 字节对齐,如果 packet 拥有 1,2,3 个字节的 payload,上述指令依然会 match fail,故而剥夺了炫技的机会,为了炫技,我才修改了代码。
所以说,抛开炫技因素,这个问题更直接的解法不是像我这样修改代码,而是 u32 match 改成 u8 match,就可以匹配任意 offset 了。
浙江温州皮鞋湿,下雨进水不会胖。
