Mar 23

[原]流量监控脚本 v1.3 晴

linuxing , 15:54 , 编程 » 示例 , 评论(3) , 引用(0) , 阅读(15835) , Via 本站原创 | |
      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:

#!/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
}

2、定时执行脚本
该脚本用于放在crontab中定时检测,当检测时发现有客户端超出限定的流量,就调用banip.sh暂时禁用它。
(为什么不把两个脚本放在一起?我的想法是暂时把功能独立开,可能今后有需要调整的地方。但你也可以修改一下,把两个脚本合并)
mon_ip.sh:

#!/bin/bash
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

本地下载:
三、显示结果
点击在新窗口中浏览此图片
初看显示结果差不多,但这可是个实时的界面,你可以刷新再看看结果。
不过,我对这个界面仍不太满意,若能在该界面上可直接进行管理会更好。所以,后续的改动会往这方面进行。
※ 注意,这时apache用户对路由网关有了root权限,务必做好安全检查的工作哦!
Tags:
sxq5858 Email
2009/08/24 23:15
你好,,又来麻烦你了!!

如何在网页上面直接显示流量的总和呢,,谢谢!!!
linuxing 回复于 2009/08/25 09:56
这个脚本中没有考虑到这点,可能要晚些时候有空才能修改了。
sxq5858 Email
2009/05/02 21:08
您好,请教这个能不能在centos 5.3上面安装,给个安装说明可以吗?谢谢!
linuxing 回复于 2009/05/04 10:33
可以用在centos 5.3上面,安装请参考v1.1上的说明,先部署好iptables,然后把脚本放在apache的cgi-bin目录下即可。
sxq5858 Email
2009/05/02 14:01
很好。。想问一下,您的,流量超过时。。是对这台IP进行限速。还是直接中断连接。。我想是限速会好点!!!!!
linuxing 回复于 2009/05/04 10:36
您可以修改脚本中对超出流量控制的部分内容,改用iptables对链路进行标记,然后用tc来限速就可以了。tc的使用,可以参考这里:
http://www.linuxfly.org/post/223/
http://www.linuxfly.org/post/224/
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]