Mar
16
[原]在Linux路由网关下查看客户端IP的实际流量
相信不少朋友都知道,使用Linux搭建路由网关,提供nat上网服务是非常简单的事情,而且性能也不错。但现在p2p的工具很多,有时候带宽会被这些工具在无意中就占满了(例如:使用迅雷、BT下载等)。这时候,总希望看看到底是谁在占用带宽。这样的工具有很多,如ntop、bandwidthd、iftop、IPTraf、MRTG等等,它们也提供了非常方便的图形监控界面,操作也非常简单。可惜,它们都有一些缺点,像实时性不够、IP流量分散、需要使用Web来查看等,恰好这些就是好我需要的。
为此,我利用iptables的统计功能,编写了一个小脚本来实现要求。(原想用Perl的Net::Pcap模块的对数据包解码统计的,但既然有现成的,为什么不用呢?)O(∩_∩)O哈哈~
一、查看网卡流量
首先,可能我们需要查看的是服务器上总的网卡流量。这个Linux提供了很好的数据:
这是网络启动后,通过服务器上各网卡的总流量,但不是很直观。(受排版影响,不太好看)
这里,提供一个小工具:
这工具不是我写的,作者是他。使用非常简单:
给出您要监控的网卡设备,然后是间隔时间,即会告诉您该设备的流量。
二、查看客户端IP实际流量的原理
接下来,进入我们的正题。除了通过上述脚本可以查看到网卡的实际流量外,我们该如何查看每个客户端的单独流量呢?先说说原理吧。
1、iptables设置
该过程最主要的就是利用了iptables的统计功能。
当我们用iptables实现nat转发后,所有的数据包要出去,必须要通过这台网关服务器,也就是说,我们只要在上面监控即可。并且,这些数据包都会经过iptables的FORWARD chain。这时,我们只要给iptables加上下述语句:
那么,通过192.168.228.200(客户端)经该服务器路由网关转发出去的数据包就会记录在iptables FORWARD chain中。
如:
这样,我们通过一些简单的运算,就可以得到实际的流量:
原理就是这么简单。
※ 注意,FORWARD chain记录的流量中,不经过该网关转发的流量不会记录。也就是说,若你从该服务器上直接下载,流量是记录在INPUT和OUTPUT chain,而不是FORWARD中的。要统计那些数据,方法是相同的。
三、脚本
1、源码
$SEC是间隔的时间,时间太短误差比较大;$ZERO决定是否显示没变化IP。同时,显示被屏蔽的IP地址。
2、结果
◎ ZERO为非1的情况
◎ ZERO为1的情况
本地下载:
四、进阶
既然能捕获到每个客户端的实际流量,就可以根据实际流量执行tc或iptables的操作。例如流量大于200KB/s则限速,或暂时断开该IP。我准备进一步完善该脚本。
为此,我利用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
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
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
# 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
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
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";
}
# 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
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
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。我准备进一步完善该脚本。
我使用# 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'
再计算流量之后,为什么流量很小呢?实际上不应该很小,因为我在用网页看着视频呢。
是不是只有给一个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多个不是要一个一个加进来- -
[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: