猛士设计了Netfilter,在失眠的时候就有事做了,安息日应守为圣日,否则会激怒神,因此双休日我一般不学习和工作,相反,我会在午夜玩一些自己喜欢的东西。我没有受过洗,不是因为不是笃信者,没有安息夜...
识别了协议好坏的标准之后,扩展字段如何布局就纯粹成了一个编码问题,一般而言,“类型-长度-值”的方式是首选,它可以很方便的编码任意类型,任意长度的扩展字段,在TCP的协议头扩展中,其名称叫做options,即TCP选项,它便是采用了上述的编码方式,每一个选项我可以称之为一个“块”,整个TCP options由多个块组成,每一个块由下面的结构组成:
/* * xt_yyy - kernel module to drop TCP timestamps * * Original author: Wanagran <[email protected]> */ #include <linux/module.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter.h> #include <linux/skbuff.h> #include <linux/tcp.h> #include <net/tcp.h> #include <linux/ip.h> #include "compat_xtables.h" MODULE_AUTHOR("Wanagran <[email protected]>"); MODULE_DESCRIPTION("Xtables: yyy match module"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_yyy"); static unsigned int yyy_tg4(struct sk_buff **skb, const struct xt_action_param *par) { const struct iphdr *iph = (struct iphdr *)((*skb)->data); struct tcphdr *hdr; unsigned int hdroff = iph->ihl*4; int datalen = (*skb)->len - hdroff; int hdrsize = 8; /* TCP connection tracking guarantees this much */ const unsigned char *ptr; unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; int length; int recalc = 0; if (iph->protocol != IPPROTO_TCP) { return XT_CONTINUE; } hdr = (struct tcphdr *)((*skb)->data + hdroff); /** * 以下这个判断不适合在代码中写死,因为: * iptables完全可以用TCP的flags match来完成这个判断 * * if (!hdr->syn) { * return XT_CONTINUE; * } * * 另外,很多人应该觉得检查一下conntrack是否已经加载,如果没有加载就 * 直接CONTINUE,但是我没有这么做,因为NAT的实现并不一定要基于conntrack */ if ((*skb)->len >= hdroff + sizeof(struct tcphdr)) hdrsize = sizeof(struct tcphdr); if (!skb_make_writable(skb, hdroff + hdrsize)) return XT_CONTINUE; length = (hdr->doff*4) - sizeof(struct tcphdr); ptr = skb_header_pointer(*skb, sizeof(struct tcphdr) + hdroff, length, buff); while (length > 0) { int opcode=*ptr++; int opsize; switch (opcode) { case TCPOPT_EOL: returni XT_CONTINUE; case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ length--; continue; case TCPOPT_TIMESTAMP: { int i = 0; char *base = ptr-1; opsize=*ptr; /** * 为了减少数据移动以及指针移动,进而减少内存拷贝 * 我只是将时间戳替换成了NOP而已 */ for (; i < opsize; i++, base++) { *base = 0x01; } recalc = 1; } default: opsize=*ptr++; length -= opsize; ptr += opsize - 2; } } /** * 改变了TCP头后,重新计算校验码是必然的,但是以下的 * 代码太粗糙,因为它没有考虑硬件也有能力计算校验码 * 这么一件事! */ if (recalc) { hdr->check = 0; hdr->check = tcp_v4_check(datalen, iph->saddr, iph->daddr, csum_partial(hdr, datalen, 0)); } return XT_CONTINUE; } static struct xt_target yyy_tg_reg[] __read_mostly = { { .name = "YYY", .revision = 1, .family = NFPROTO_IPV4, .target = yyy_tg4, .me = THIS_MODULE, }, }; static int __init xt_yyy_target_init(void) { int status = 0; status = xt_register_targets(yyy_tg_reg, ARRAY_SIZE(yyy_tg_reg)); if (status < 0) { printk("YYY: register target error\n"); goto err; } err: return status; } static void __exit xt_yyy_target_exit(void) { return xt_unregister_targets(yyy_tg_reg, ARRAY_SIZE(yyy_tg_reg)); } module_init(xt_yyy_target_init); module_exit(xt_yyy_target_exit);
新建连接的SYN包:
ESTABLISHED状态的非SYN包: