相信不少朋友都知道,使用Linux搭建路由网关,提供nat上网服务是非常简单的事情,而且性能也不错。但现在p2p的工具很多,有时候带宽会被这些工具在无意中就占满了(例如:使用迅雷、BT下载等)。这时候,总希望看看到底是谁在占用带宽。这样的工具有很多,如ntop、bandwidthd、iftop、IPTraf、MRTG等等,它们也提供了非常方便的图形监控界面,操作也非常简单。可惜,它们都有一些缺点,像实时性不够、IP流量分散、需要使用Web来查看等,恰好这些就是好我需要的。
    为此,我 利用iptables的统计功能 ,编写了一个小脚本来实现要求。(原想用Perl的Net::Pcap模块的对数据包解码统计的,但既然有现成的,为什么不用呢?)O(∩_∩)O哈哈~

一、查看网卡流量
首先,可能我们需要查看的是服务器上总的网卡流量。这个Linux提供了很好的数据:
引用
# cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:10020933   79976    0    0    0     0          0         0 10020933   79976    0    0    0     0       0          0
  eth0:3274190272 226746109 438150 858758 369237     0          0         0 2496830239 218418052    0    0    0     0       0          0
  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  tun0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  tun1:    4675      51    0    0    0     0          0         0     8116      48    0    0    0     0       0          0
  tun2:   51960     562    0    0    0     0          0         0   249612    3077    0    0    0     0       0          0
  ppp0:4163571679 12086605    0    0    0     0          0         0 3089285665 15934370    0    0    0     0       0          0

这是网络启动后,通过服务器上各网卡的总流量,但不是很直观。(受排版影响,不太好看)
这里,提供一个小工具:
这工具不是我写的,作者是 。使用非常简单:
引用
# sh flow.sh
Usage: flow.sh <ethernet device> <sleep time>
    e.g. flow.sh eth0 2
# sh flow.sh ppp0 2
IN: 232 KByte/s   OUT: 30 KByte/s
IN: 230 KByte/s   OUT: 38 KByte/s
IN: 241 KByte/s   OUT: 30 KByte/s

给出您要监控的网卡设备,然后是间隔时间,即会告诉您该设备的流量。

二、查看客户端IP实际流量的原理
接下来,进入我们的正题。除了通过上述脚本可以查看到网卡的实际流量外,我们该如何查看每个客户端的单独流量呢?先说说原理吧。
1、iptables设置
该过程最主要的就是利用了iptables的统计功能。
当我们用iptables实现nat转发后,所有的数据包要出去,必须要通过这台网关服务器,也就是说,我们只要在上面监控即可。并且,这些数据包都会经过iptables的FORWARD chain。这时,我们只要给iptables加上下述语句:

# iptables -I FORWARD -s 192.168.228.200 -j ACCEPT
# iptables -I FORWARD -d 192.168.228.200 -j ACCEPT

那么,通过192.168.228.200(客户端)经该服务器路由网关转发出去的数据包就会记录在iptables FORWARD chain中。
如:
引用
# iptables -v -n -x -L FORWARD
Chain FORWARD (policy DROP 5 packets, 351 bytes)
    pkts      bytes target     prot opt in     out     source               destination
2834533  360907743 ACCEPT     all  --  *      *       192.168.228.200      0.0.0.0/0
3509528  3253144061 ACCEPT     all  --  *      *       0.0.0.0/0            192.168.228.200

这样,我们通过一些简单的运算,就可以得到实际的流量:
引用
# iptables -L -v -n -x|grep '192.168.228.200';sleep 3;iptables -L -v -n -x|grep '192.168.228.200'
2872143 365711591 ACCEPT     all  --  *      *       192.168.228.200      0.0.0.0/0
3555831 3297100630 ACCEPT     all  --  *      *       0.0.0.0/0            192.168.228.200
2872750 365777302 ACCEPT     all  --  *      *       192.168.228.200      0.0.0.0/0
3556591 3297814562 ACCEPT     all  --  *      *       0.0.0.0/0            192.168.228.200
# echo '(3297814562-3297100630)/1024/3'|bc
232
# echo '(365777302-365711591)/1024/3'|bc
21

原理就是这么简单。
※ 注意,FORWARD chain记录的流量中,不经过该网关转发的流量不会记录。也就是说,若你从该服务器上直接下载,流量是记录在INPUT和OUTPUT chain,而不是FORWARD中的。要统计那些数据,方法是相同的。

三、脚本
1、源码
$SEC是间隔的时间,时间太短误差比较大;$ZERO决定是否显示没变化IP。同时,显示被屏蔽的IP地址。

#!/usr/bin/perl -w
# Date:2009-03-12
# Author:HyphenWang
# Version:1.0
use strict;
my $IPTABLES_CMD="iptables -v -n -x -L FORWARD";
my $SEC="3";
my $ZERO="0";
my (%first_input,%first_output);
my (%second_input,%second_output);
my %ban_ip;

sub get_ipflow {
  my ($ip_input,$ip_output)=@_;
  for my $line (`$IPTABLES_CMD`) {
    my @columns = split(/\s+/,$line);
    $ip_input->{$columns[-1]}=$columns[2] if ($columns[3] eq "ACCEPT" and $columns[-1] =~ m/192\.168\.228\.\d+/);
    $ip_output->{$columns[-2]}=$columns[2] if ($columns[3] eq "ACCEPT" and $columns[-2] =~ m/192\.168\.228\.\d+/);
    $ban_ip{$columns[-1]}=1 if ($columns[3] eq "DROP" and $columns[-1] =~ m/192\.168\.228\.\d+/);
    $ban_ip{$columns[-2]}=1 if ($columns[3] eq "DROP" and $columns[-2] =~ m/192\.168\.228\.\d+/);
  }
}
get_ipflow(\%first_input,\%first_output);
sleep $SEC;
get_ipflow(\%second_input,\%second_output);
print "Now is ".localtime()."\n";
print "-"x53,"\n";
print "IP Address\t\tIn Flow Rate\tOut Flow Rate\n";
for (keys %first_input) {
  if ($ZERO != 1) {
    if (defined $second_input{$_} and defined $second_output{$_} and int(($second_input{$_}-$first_input{$_})/1024/$SEC) == 0) {
      next;
    }
  }
  if (defined $second_input{$_} and defined $second_output{$_}) {
  printf ("%s\t\t%.fKB\t\t%.fKB\n",$_,($second_input{$_}-$first_input{$_})/1024/$SEC,($second_output{$_}-$first_output{$_})/1024/$SEC);
  }
}
print "-"x53,"\n";
print "Banned IP Address:\n";
for (keys %ban_ip) {
  print "$_\n";
}

2、结果
◎ ZERO为非1的情况
引用
# perl ipflow.pl
Now is Thu Mar 12 18:35:10 2009
-----------------------------------------------------
IP Address              In Flow Rate    Out Flow Rate
192.168.228.212         277 KByte/s     27 KByte/s
192.168.228.200         40 KByte/s      16 KByte/s

-----------------------------------------------------
Banned IP Address:
192.168.228.50

◎ ZERO为1的情况
引用
# perl ipflow.pl
Now is Thu Mar 12 18:36:21 2009
-----------------------------------------------------
IP Address              In Flow Rate    Out Flow Rate
192.168.228.219         0 KByte/s       0 KByte/s
192.168.228.150         0 KByte/s       0 KByte/s
192.168.228.153         0 KByte/s       0 KByte/s
192.168.228.215         0 KByte/s       0 KByte/s
192.168.228.212         220 KByte/s     27 KByte/s
192.168.228.200         14 KByte/s      9 KByte/s

192.168.228.154         0 KByte/s       0 KByte/s
192.168.228.220         0 KByte/s       0 KByte/s
192.168.228.99          0 KByte/s       0 KByte/s
192.168.228.216         0 KByte/s       0 KByte/s
192.168.228.211         0 KByte/s       0 KByte/s
192.168.228.155         0 KByte/s       0 KByte/s
192.168.228.218         21 KByte/s      1 KByte/s
192.168.228.30          0 KByte/s       0 KByte/s
192.168.228.221         0 KByte/s       0 KByte/s
-----------------------------------------------------
Banned IP Address:

192.168.228.50


Logo

更多推荐