Mar 16

[原]在Linux路由网关下查看客户端IP的实际流量 晴

linuxing , 10:31 , 编程 » 示例 , 评论(3) , 引用(0) , 阅读(45092) , Via 本站原创 | |
    相信不少朋友都知道,使用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

本地下载:
四、进阶
既然能捕获到每个客户端的实际流量,就可以根据实际流量执行tc或iptables的操作。例如流量大于200KB/s则限速,或暂时断开该IP。我准备进一步完善该脚本。
Tags:
lydwsh
2011/12/07 15:58
你好,
我使用# iptables -I FORWARD -s 192.168.228.200 -j ACCEPT
# iptables -I FORWARD -d 192.168.228.200 -j ACCEPT

# iptables -L -v -n -x|grep '192.168.228.200';sleep 3;iptables -L -v -n -x|grep '192.168.228.200'

再计算流量之后,为什么流量很小呢?实际上不应该很小,因为我在用网页看着视频呢。
hello
2011/04/02 19:49
你好,我想问下
是不是只有给一个ip运行
# iptables -I FORWARD -s 192.168.228.200 -j ACCEPT
# iptables -I FORWARD -d 192.168.228.200 -j ACCEPT
这两条语句,执行ipflow.pl才能看到这个ip的流量信息,否则就看不到?

如果是的话,我这里ip100多个不是要一个一个加进来- -
linuxing 回复于 2011/04/07 23:40
是的,否则脚本无法通过iptables -L 的结果来识别IP的流量信息。100多个IP,写个脚本循环一下就可以了。
sxq5858 Email
2009/08/23 03:44
您好,,这个统计出来的不准。为什么每次统计出来的IP数不对呢,,有时候IP多,有时候IP少!!
[root@zhonghui home]# perl flow.pl
Now is Sun Aug 23 03:35:05 2009
-----------------------------------------------------
IP Address              In Flow Rate    Out Flow Rate
192.168.1.223           3 KByte/s       1 KByte/s
192.168.1.233           43 KByte/s      1 KByte/s
192.168.1.235           4 KByte/s       4 KByte/s
192.168.1.117           1 KByte/s       1 KByte/s
192.168.1.199           3 KByte/s       2 KByte/s
192.168.1.69            1 KByte/s       1 KByte/s
192.168.1.202           70 KByte/s      41 KByte/s
192.168.1.104           60 KByte/s      1 KByte/s
192.168.1.206           6 KByte/s       55 KByte/s
192.168.1.169           2 KByte/s       0 KByte/s
192.168.1.123           4 KByte/s       1 KByte/s
192.168.1.86            6 KByte/s       0 KByte/s
192.168.1.146           5 KByte/s       2 KByte/s
192.168.1.221           186 KByte/s     9 KByte/s
192.168.1.94            3 KByte/s       2 KByte/s
192.168.1.65            2 KByte/s       2 KByte/s
192.168.1.187           2 KByte/s       1 KByte/s
192.168.1.234           4 KByte/s       1 KByte/s
-----------------------------------------------------
Banned IP Address:
linuxing 回复于 2009/08/24 18:07
这统计的是前后两个时间段的流量差,并用$ZERO决定是否显示没变化IP。如果设定该参数为1,则会显示所用的IP。
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]