struct ipc_counters
{
u_int64_t pcnt, bcnt; /* Packet and byte counters */
spinlock_t lock;
};
和在struct ip_conntrack末尾添加
struct ipc_counters counters;
以及net/ipv4/netfilter/ip_conntrack_core.c的init_conntrack中增加
spin_lock_init(conntrack->counters.lock);
其他添加或修改全部取消
2.现在的tctable_filter.c
#include
#include
#include
#include
#define ADD_COUNTER(c,b,p) do { spin_lock(&c.lock);(c).bcnt += (b); (c).pcnt += (p);spin_unlock(&c.lock);} while(0)
static void sum(struct sk_buff * skb,const char * msg)
{
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
ct = ip_conntrack_get(skb, &ctinfo);
if(ct)//有跟踪
{
ADD_COUNTER(ct->counters, ntohs(skb->nh.iph->tot_len), 1);
}
else
{
if (net_ratelimit())
printk(KERN_DEBUG "%s:got untracked packet %p %u %u.%u.%u.%u -> %u.%u.%u.%u %u\n",
msg,
skb,
skb->nh.iph->protocol,
NIPQUAD(skb->nh.iph->saddr),
NIPQUAD(skb->nh.iph->daddr),
skb->nh.iph->protocol
);
}
}
/* The work comes in here from netfilter.c. */
static unsigned int
tct_forward_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
sum(*pskb,"tct_forward_hook");
return NF_ACCEPT;
}
static unsigned int
tct_local_in_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
sum(*pskb,"tct_local_in_hook");
return NF_ACCEPT;
}
static unsigned int
tct_local_out_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct iphdr)
|| (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("ipt_hook: happy cracking.\n");
return NF_ACCEPT;
}
sum(*pskb,"tct_local_out_hook");
return NF_ACCEPT;
}
static struct nf_hook_ops tct_ops[]
= { { { NULL, NULL }, tct_local_in_hook, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_FILTER+10 },
{ { NULL, NULL }, tct_forward_hook, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER+10 },
{ { NULL, NULL }, tct_local_out_hook, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_FILTER+10 }
};
static int __init init(void)
{
int ret;
/* Register hooks */
ret = nf_register_hook(&tct_ops[0]);
if (ret < 0)
return ret;
ret = nf_register_hook(&tct_ops[1]);
if (ret < 0)
goto cleanup_hook0;
ret = nf_register_hook(&tct_ops[2]);
if (ret < 0)
goto cleanup_hook1;
if (ip_conntrack_module)
__MOD_INC_USE_COUNT(ip_conntrack_module);//要使用conntrack
return ret;
cleanup_hook1:
nf_unregister_hook(&tct_ops[1]);
cleanup_hook0:
nf_unregister_hook(&tct_ops[0]);
return ret;
}
static void __exit fini(void)
{
unsigned int i;
for (i = 0; i < sizeof(tct_ops)/sizeof(struct nf_hook_ops); i++)
nf_unregister_hook(&tct_ops[i]);
if (ip_conntrack_module)
__MOD_DEC_USE_COUNT(ip_conntrack_module);
}
module_init(init);
module_exit(fini);
需要注意的地方有两点
a.在查询包的连接跟踪时可能为空,因此需要判断
b.由于tctable需要使用ip_conntrack,因此在初始化引用了ip_conntrack模块,反正卸载时要递减引用计数。
编译并加载tctable_filter看看计数功能是否有效
dmesg
tct_local_out_hook:got untracked packet dfdd2b20 1 10.1.9.30 -> 10.1.9.45 1
tct_local_in_hook:got untracked packet cc02ef00 1 192.168.18.1 -> 224.0.0.1 1
tct_local_in_hook:got untracked packet cc02ef00 1 192.168.2.1 -> 224.0.0.1 1
这些conntrack的包都是icmp.原因在net/ipv4/netfilter/ip_conntrack_proto_icmp.c的代码中
static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple,
const struct ip_conntrack_tuple *orig)
{
/* Add 1; spaces filled with 0. */
static u_int8_t invmap[]
= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
[ICMP_ECHOREPLY] = ICMP_ECHO + 1,
[ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
[ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
[ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
[ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
[ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
[ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
if (orig->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[orig->dst.u.icmp.type])
return 0;
tuple->src.u.icmp.id = orig->src.u.icmp.id;
tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
return 1;
}
/* Returns verdict for packet, or -1 for invalid. */
static int icmp_packet(struct ip_conntrack *ct,
struct iphdr *iph, size_t len,
enum ip_conntrack_info ctinfo)
{
/* Try to delete connection immediately after all replies:
won't actually vanish as we still have skb, and del_timer
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
if (atomic_dec_and_test(&ct->proto.icmp.count)
&& del_timer(&ct->timeout))
ct->timeout.function((unsigned long)ct);
} else {
atomic_inc(&ct->proto.icmp.count);
ip_ct_refresh(ct, ICMP_TIMEOUT);
}
ip_ct_refresh(ct, ICMP_TIMEOUT);
return NF_ACCEPT;
}
/* Called when a new connection for this protocol found. */
static int icmp_new(struct ip_conntrack *conntrack,
struct iphdr *iph, size_t len)
{
static u_int8_t valid_new[]
= { [ICMP_ECHO] = 1,
[ICMP_TIMESTAMP] = 1,
[ICMP_INFO_REQUEST] = 1,
[ICMP_ADDRESS] = 1 };
if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
|| !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
/* Can't create a new ICMP `conn' with this. */
DEBUGP("icmp: can't create new conn with type %u\n",
conntrack->tuplehash[0].tuple.dst.u.icmp.type);
DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0;
}
atomic_set(&conntrack->proto.icmp.count, 0);
return 1;
}
可以修改这三个函数,使得conn可见
修改如下
static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple,
const struct ip_conntrack_tuple *orig)
{
/* Add 1; spaces filled with 0. */
static u_int8_t invmap[]
= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
[ICMP_ECHOREPLY] = ICMP_ECHO + 1,
[ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
[ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
[ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
[ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
[ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
[ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
if (orig->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[orig->dst.u.icmp.type])
//return 0;
{
tuple->src.u.icmp.id = 0;
tuple->dst.u.icmp.type = 0;
tuple->dst.u.icmp.code = 0;
return 1;
}
tuple->src.u.icmp.id = orig->src.u.icmp.id;
tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
return 1;
}
/* Returns verdict for packet, or -1 for invalid. */
static int icmp_packet(struct ip_conntrack *ct,
struct iphdr *iph, size_t len,
enum ip_conntrack_info ctinfo)
{
ip_ct_refresh(ct, ICMP_TIMEOUT);
return NF_ACCEPT;
}
/* Called when a new connection for this protocol found. */
static int icmp_new(struct ip_conntrack *conntrack,
struct iphdr *iph, size_t len)
{
return 1;
}
make modules
make modules_install
重新加载ip_conntrack和tctable_filter发现icmp出现在/proc/net/ip_conntrack中,而tctable_filter也不报错了
测试时候发现linux下ping发出的icmp包id值为进程id,而windows下的值都是1024,不知道windows下如何处理的多个ping同一地址, icmp包id和seq发生冲突怎么办?