本次完成区分两个方向的包数和字节数统计功能,并记录最后一次跟新时间戳
1.修改include/linux/netfilter_ipv4/ip_conntrack.h
struct ipc_counters
{
struct
{
u_int64_t pcnt, bcnt; /*Packet and byte counters */
}
cnt[IP_CT_DIR_MAX];//两个方向
unsigned long last; /*最后一次更新时的jiffies值*/
spinlock_t lock;
};
2.修改net/ipv4/netfilter/ip_conntrack_standalone.c
print_conntrack函数
{
....
//spin_lock(&conntrack->counters.lock);
len += sprintf(buffer + len, "orig_pcnt=%Lu ",
conntrack->counters.cnt[IP_CT_DIR_ORIGINAL].pcnt);
len += sprintf(buffer + len, "orig_bcnt=%Lu ",
conntrack->counters.cnt[IP_CT_DIR_ORIGINAL].bcnt);
len += sprintf(buffer + len, "rply_pcnt=%Lu ",
conntrack->counters.cnt[IP_CT_DIR_REPLY].pcnt);
len += sprintf(buffer + len, "rply_bcnt=%Lu ",
conntrack->counters.cnt[IP_CT_DIR_REPLY].bcnt);
len += sprintf(buffer + len, "last=%u ",
conntrack->counters.last);
//spin_unlock(&conntrack->counters.lock);
....
}
3.修改tctable_filter.c
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)//有跟踪
{
struct ipc_counters *cc=&(ct->counters);
int dir=CTINFO2DIR(ctinfo);//取得方向
spin_lock(&(cc->lock));
cc->cnt[dir].pcnt++;
cc->cnt[dir].bcnt+=ntohs(skb->nh.iph->tot_len);
cc->last=jiffies;//取jiffies
spin_unlock(&(cc->lock));
}
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
);
}
}
4.额外修改
tcp的established状态的超时时间在
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
被设成5天,太长,我们改成8分钟
static unsigned long tcp_timeouts[]
= { 30 MINS, /* TCP_CONNTRACK_NONE, */
//5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */
8 MINS, /* TCP_CONNTRACK_ESTABLISHED, */
2 MINS, /* TCP_CONNTRACK_SYN_SENT, */
60 SECS, /* TCP_CONNTRACK_SYN_RECV, */
2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */
2 MINS, /* TCP_CONNTRACK_TIME_WAIT, */
10 SECS, /* TCP_CONNTRACK_CLOSE, */
60 SECS, /* TCP_CONNTRACK_CLOSE_WAIT, */
30 SECS, /* TCP_CONNTRACK_LAST_ACK, */
2 MINS, /* TCP_CONNTRACK_LISTEN, */
};
5.编译并测试
make modules
make moduels_install
[root@localhost linux-2.4]# cat /proc/net/ip_conntrack
udp 17 0 src=10.1.9.30 dst=192.168.168.16 sport=32813 dport=53 src=192.168.168.16 dst=10.1.9.30 sport=53 dport=32813 use=1 orig_pcnt=1 orig_bcnt=68 rply_pcnt=1 rply_bcnt=118 last=666922
tcp 6 32 SYN_RECV src=192.168.199.1 dst=10.1.9.30 sport=1424 dport=139 src=10.1.9.30 dst=192.168.199.1 sport=139 dport=1424 use=1 orig_pcnt=1 orig_bcnt=48 rply_pcnt=5 rply_bcnt=240 last=667055
成功.
6.为何要增加last时间戳
为了计算连接的包速和字节速,第一时间能想到的方法是在内核中计算,使用类似于net/sched/estimator.c中的方法定时计算.经过仔细分析,有如下的缺点:
>连接数很多的情况下,将占用大量的cpu时间
>计算结果只对管理者要查询时有意义,绝大多数情况下无用
考虑到这两点,可以想办法把这个计算工作移交给监控的客户端,通过last时间戳,客户端可以定时获取连接信息,并根据前后两次的时间戳来计算包速和字节速.
7.如何获取连接信息
通过/proc/net/ip_conntrack方式获取连接信息的方法不可靠,因为通常不能一次就能读取/proc/net/ip_conntrack,proc文件系统的做法是,根据offset来决定下一次的读取位置.在conntrack中,offset是遍历ip_conntrack hash的每个conntrack的编号,list_conntracks是根据offset来定位到本次要读取的连接信息开始处读取信息
static int
list_conntracks(char *buffer, char **start, off_t offset, int length)
{
unsigned int i;
unsigned int len = 0;
off_t upto = 0;
struct list_head *e;
READ_LOCK(&ip_conntrack_lock);
/* Traverse hash; print originals then reply. */
for (i = 0; i < ip_conntrack_htable_size; i++) {
if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
struct ip_conntrack_tuple_hash *,
buffer, offset, &upto, &len, length))
goto finished;
}
但是conntrack变动是非常频繁的,可能在两次读取之间,offset之间插入或删除了大量的连接,这样看来
/proc/net/ip_conntrack有用,但不可靠。
8.如何保证信息的可靠性
最好的方法是给每个连接编上唯一号码id,然后根据id来取信息。先获取所有连接的id值,这通过很少的几次读取操作就能完成,然后根据id值取连接信息,例如每次取50个,直至读完,这样就能增加信息的可靠性。
经过几轮的循环,那些长连接的信息将能被可靠获取.
阅读(2670) | 评论(0) | 转发(0) |