Mar
23
v1.2版的脚本已经实现了通过Web网页监控流量的功能,可惜受root权限的影响,没有达到实时的效果,也就是显示我访问Web网页所在一刻的流量。要解决这问题,就需要在Web页面上可调用iptables命令。幸亏通过这两天的测试,我已经实现了让apache可执行本地及远程需root权限的命令。OK,既然前提条件都解决了,脚本的编写就简单了。
一、准备工作
实际上,前两天的日志就是我后面的脚本真正能实现的前提。当然,我的现实环境中,路由网关(流量所在)的机器与Web服务器确实就是分开的。所以,在部署以下脚本前需要做的,就是按照 [原]让apache可执行远程需root权限的命令 部分的内容,来做好ssh的密钥信任关系。
虽然做好了该验证,但使用中我还发现一个问题:如果查看网页时,万一就有客户端超出了限定的IP流量,网页会暂停显示,直到后台banip.sh脚本运行完毕(sleep操作)后,才完全显示出来。
这是一个很明显的问题。经判断,原因是通过ssh调用远程服务器上的命令时,即使把命令使放到后台运行(用&符号),ssh也会一直等待,直到后台命令退出,ssh才结束。所以,就产生了上面Web页面的等待问题。(若是本地把一个程序放到后台就没有这问题)
解决方法嘛,我想到的就是把对流量的检测部分独立出来。为此,我加了一个“-b”的参数,带该参数运行ipflow.pl,就仅输出超出流量的IP,由另一个独立的脚本mon_ipflow.sh来定时调用即可。
二、脚本
1、路由网关上的脚本
流量监控脚本,默认输出普通字符格式,-p输出HTML格式,-b仅输出超出流量IP。
ipflow.pl:
2、定时执行脚本
该脚本用于放在crontab中定时检测,当检测时发现有客户端超出限定的流量,就调用banip.sh暂时禁用它。
(为什么不把两个脚本放在一起?我的想法是暂时把功能独立开,可能今后有需要调整的地方。但你也可以修改一下,把两个脚本合并)
mon_ip.sh:
banip.sh没有改动,请参考之前的v1.2版本。
3、网页上的查看程序
view_ipflow.pl:
本地下载:
三、显示结果
初看显示结果差不多,但这可是个实时的界面,你可以刷新再看看结果。
不过,我对这个界面仍不太满意,若能在该界面上可直接进行管理会更好。所以,后续的改动会往这方面进行。
※ 注意,这时apache用户对路由网关有了root权限,务必做好安全检查的工作哦!
一、准备工作
实际上,前两天的日志就是我后面的脚本真正能实现的前提。当然,我的现实环境中,路由网关(流量所在)的机器与Web服务器确实就是分开的。所以,在部署以下脚本前需要做的,就是按照 [原]让apache可执行远程需root权限的命令 部分的内容,来做好ssh的密钥信任关系。
虽然做好了该验证,但使用中我还发现一个问题:如果查看网页时,万一就有客户端超出了限定的IP流量,网页会暂停显示,直到后台banip.sh脚本运行完毕(sleep操作)后,才完全显示出来。
这是一个很明显的问题。经判断,原因是通过ssh调用远程服务器上的命令时,即使把命令使放到后台运行(用&符号),ssh也会一直等待,直到后台命令退出,ssh才结束。所以,就产生了上面Web页面的等待问题。(若是本地把一个程序放到后台就没有这问题)
解决方法嘛,我想到的就是把对流量的检测部分独立出来。为此,我加了一个“-b”的参数,带该参数运行ipflow.pl,就仅输出超出流量的IP,由另一个独立的脚本mon_ipflow.sh来定时调用即可。
二、脚本
1、路由网关上的脚本
流量监控脚本,默认输出普通字符格式,-p输出HTML格式,-b仅输出超出流量IP。
ipflow.pl:
#!/usr/bin/perl -w
# Date:2009-03-14
# Author:HyphenWang
# Version:1.3
use strict;
my $IPTABLES_CMD="/sbin/iptables -v -n -x -L FORWARD";
my $BANIP_CMD="/root/banip.sh";
my $SEC="3";
my $ZERO="1";
#my $BANIP="1";
my $BANSEC="60";
my ($HTML,$BANIP);
my $limit_input_rate=200;
my $limit_output_rate=35;
my @exclude_ip=qw(30 153 155 200 221);
my @vzserver_ip=qw(135);
#@exclude_ip=(@exclude_ip,@vzserver_ip);
push (@exclude_ip,@vzserver_ip);
my (%first_input,%first_output);
my (%second_input,%second_output);
my (%ban_ip,$input_rate,$output_rate);
# 检查输入的参数
if (defined $ARGV[0]) {
for (@ARGV) {
$HTML = 1 if $_ eq "-p";
$BANIP = 1 if $_ eq "-b";
}
}
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);
if (! defined $BANIP) {
if (! defined $HTML) {
print "Now is ".localtime()."\n";
print "-"x53,"\n";
print "IP Address\t\tIn Flow Rate\tOut Flow Rate\n";
}
else {
print<<EOF;
<table cellspacing="0">
<tr><td><table border="1" align="left" cellspacing="0">
<tr align="center" bgcolor="#FFFF00">
<td width="200">IP Address</td>
<td width="200">In Flow Rate</td>
<td width="200">Out flow Rate</td>
</tr>
EOF
}
}
for my $ip (keys %first_input) {
if ($ZERO != 1) {
if (defined $second_input{$ip} and defined $second_output{$ip} and int(($second_input{$ip}-$first_input{$ip})/1024/$SEC) == 0) {
next;
}
}
if (defined $second_input{$ip} and defined $second_output{$ip}) {
$input_rate = ($second_input{$ip}-$first_input{$ip})/1024/$SEC;
$output_rate = ($second_output{$ip}-$first_output{$ip})/1024/$SEC;
if (! defined $BANIP) {
if (! defined $HTML) {
printf ("%s\t\t%.f KByte/s\t%.f KByte/s\n",$ip,$input_rate,$output_rate);
}
else {
printf ("<tr><td>%s</td>\n<td>%.f KByte/s</td>\n<td>%.f KByte/s</td>\n</tr>\n",$ip,$input_rate,$output_rate);
}
}
if ($input_rate >= $limit_input_rate and ! grep ("192.168.228.$_" eq $ip,@exclude_ip)) {
#system ("$BANIP_CMD INPUT $ip $BANSEC &");
print $ip,"\n" if defined $BANIP;
$ban_ip{$ip}=1;
}
if ($output_rate >= $limit_output_rate and ! grep ("192.168.228.$_" eq $ip,@exclude_ip)) {
#system ("$BANIP_CMD OUTPUT $ip $BANSEC &");
print $ip,"\n" if defined $BANIP;
$ban_ip{$ip}=1;
}
}
}
if (! defined $BANIP) {
if (! defined $HTML) {
print "-"x53,"\n";
print "Banned IP Address:\n";
}
else {
print<<EOF;
</table></td></tr>
<tr><td><p><br></p></td></tr>
<tr><td><table border="1" align="left" cellspacing="0">
<tr>
<td width="200" align="center" bgcolor="#FF0000">Banned IP Address</td>
</tr>
EOF
}
}
if (! defined $BANIP) {
for (keys %ban_ip) {
if (! defined $HTML) {
print "$_\n";
}
else {
print<<EOF;
<tr>
<td>$_</td>
</tr>
EOF
}
}
}
if (defined $HTML) {
print<<EOF;
</table></td></tr></td></table>
<br>
限速:200 KByte/s,若检查时发现超出该值,会自动中断对应的客户端IP一分钟。
若您被中断了,请等待,或告诉我。
EOF
}
# Date:2009-03-14
# Author:HyphenWang
# Version:1.3
use strict;
my $IPTABLES_CMD="/sbin/iptables -v -n -x -L FORWARD";
my $BANIP_CMD="/root/banip.sh";
my $SEC="3";
my $ZERO="1";
#my $BANIP="1";
my $BANSEC="60";
my ($HTML,$BANIP);
my $limit_input_rate=200;
my $limit_output_rate=35;
my @exclude_ip=qw(30 153 155 200 221);
my @vzserver_ip=qw(135);
#@exclude_ip=(@exclude_ip,@vzserver_ip);
push (@exclude_ip,@vzserver_ip);
my (%first_input,%first_output);
my (%second_input,%second_output);
my (%ban_ip,$input_rate,$output_rate);
# 检查输入的参数
if (defined $ARGV[0]) {
for (@ARGV) {
$HTML = 1 if $_ eq "-p";
$BANIP = 1 if $_ eq "-b";
}
}
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);
if (! defined $BANIP) {
if (! defined $HTML) {
print "Now is ".localtime()."\n";
print "-"x53,"\n";
print "IP Address\t\tIn Flow Rate\tOut Flow Rate\n";
}
else {
print<<EOF;
<table cellspacing="0">
<tr><td><table border="1" align="left" cellspacing="0">
<tr align="center" bgcolor="#FFFF00">
<td width="200">IP Address</td>
<td width="200">In Flow Rate</td>
<td width="200">Out flow Rate</td>
</tr>
EOF
}
}
for my $ip (keys %first_input) {
if ($ZERO != 1) {
if (defined $second_input{$ip} and defined $second_output{$ip} and int(($second_input{$ip}-$first_input{$ip})/1024/$SEC) == 0) {
next;
}
}
if (defined $second_input{$ip} and defined $second_output{$ip}) {
$input_rate = ($second_input{$ip}-$first_input{$ip})/1024/$SEC;
$output_rate = ($second_output{$ip}-$first_output{$ip})/1024/$SEC;
if (! defined $BANIP) {
if (! defined $HTML) {
printf ("%s\t\t%.f KByte/s\t%.f KByte/s\n",$ip,$input_rate,$output_rate);
}
else {
printf ("<tr><td>%s</td>\n<td>%.f KByte/s</td>\n<td>%.f KByte/s</td>\n</tr>\n",$ip,$input_rate,$output_rate);
}
}
if ($input_rate >= $limit_input_rate and ! grep ("192.168.228.$_" eq $ip,@exclude_ip)) {
#system ("$BANIP_CMD INPUT $ip $BANSEC &");
print $ip,"\n" if defined $BANIP;
$ban_ip{$ip}=1;
}
if ($output_rate >= $limit_output_rate and ! grep ("192.168.228.$_" eq $ip,@exclude_ip)) {
#system ("$BANIP_CMD OUTPUT $ip $BANSEC &");
print $ip,"\n" if defined $BANIP;
$ban_ip{$ip}=1;
}
}
}
if (! defined $BANIP) {
if (! defined $HTML) {
print "-"x53,"\n";
print "Banned IP Address:\n";
}
else {
print<<EOF;
</table></td></tr>
<tr><td><p><br></p></td></tr>
<tr><td><table border="1" align="left" cellspacing="0">
<tr>
<td width="200" align="center" bgcolor="#FF0000">Banned IP Address</td>
</tr>
EOF
}
}
if (! defined $BANIP) {
for (keys %ban_ip) {
if (! defined $HTML) {
print "$_\n";
}
else {
print<<EOF;
<tr>
<td>$_</td>
</tr>
EOF
}
}
}
if (defined $HTML) {
print<<EOF;
</table></td></tr></td></table>
<br>
限速:200 KByte/s,若检查时发现超出该值,会自动中断对应的客户端IP一分钟。
若您被中断了,请等待,或告诉我。
EOF
}
2、定时执行脚本
该脚本用于放在crontab中定时检测,当检测时发现有客户端超出限定的流量,就调用banip.sh暂时禁用它。
(为什么不把两个脚本放在一起?我的想法是暂时把功能独立开,可能今后有需要调整的地方。但你也可以修改一下,把两个脚本合并)
mon_ip.sh:
#!/bin/bash
for i in `/root/ipflow.pl -b`
do
/root/banip.sh INPUT $i 60 &
done
for i in `/root/ipflow.pl -b`
do
/root/banip.sh INPUT $i 60 &
done
banip.sh没有改动,请参考之前的v1.2版本。
下载文件
3、网页上的查看程序
view_ipflow.pl:
#!/usr/bin/perl -w
use strict;
print "Content-type:text/html\n\n";
print<<HEADER;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>网关上出互联网的各客户端IP流量</title>
</head>
<body>
HEADER
print qq(<b><font face=楷体_GB2312 size=4>网关上出互联网的各客户端IP流量</font></b>\n<br><br>);
my ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst) = localtime();
printf ("时间:%s年%s月%s日 %s:%s:%s\n<br>\n",$year+1900,$mon+1,$day,$hour,$min,$sec);
my $HTML=qx(/usr/bin/ssh -l root 192.168.228.153 /root/ipflow.pl -p);
print $HTML;
print<<FOOTER;
</body>
</html>
FOOTER
use strict;
print "Content-type:text/html\n\n";
print<<HEADER;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>网关上出互联网的各客户端IP流量</title>
</head>
<body>
HEADER
print qq(<b><font face=楷体_GB2312 size=4>网关上出互联网的各客户端IP流量</font></b>\n<br><br>);
my ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst) = localtime();
printf ("时间:%s年%s月%s日 %s:%s:%s\n<br>\n",$year+1900,$mon+1,$day,$hour,$min,$sec);
my $HTML=qx(/usr/bin/ssh -l root 192.168.228.153 /root/ipflow.pl -p);
print $HTML;
print<<FOOTER;
</body>
</html>
FOOTER
本地下载:
下载文件
三、显示结果
初看显示结果差不多,但这可是个实时的界面,你可以刷新再看看结果。
不过,我对这个界面仍不太满意,若能在该界面上可直接进行管理会更好。所以,后续的改动会往这方面进行。
※ 注意,这时apache用户对路由网关有了root权限,务必做好安全检查的工作哦!
如何在网页上面直接显示流量的总和呢,,谢谢!!!
http://www.linuxfly.org/post/223/
http://www.linuxfly.org/post/224/