识别了协议好坏的标准之后,扩展字段如何布局就纯粹成了一个编码问题,一般而言,“类型-长度-值”的方式是首选,它可以很方便的编码任意类型,任意长度的扩展字段,在TCP的协议头扩展中,其名称叫做options,即TCP选项,它便是采用了上述的编码方式,每一个选项我可以称之为一个“块”,整个TCP options由多个块组成,每一个块由下面的结构组成:
/*
* xt_yyy - kernel module to drop TCP timestamps
*
* Original author: Wanagran
*/
#include
#include
#include
#include
#include
#include
#include
#include "compat_xtables.h"
MODULE_AUTHOR("Wanagran ");
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包: