网络分析shell脚本(实时流量+连接统计)

有服务器方面的问题无法解决?点击这里寻求帮助。

介绍一个强大的分析网络的shell脚本,此脚本是从EZHTTP拆分出来的,觉得有必要单独介绍下。
脚本运行效果截图:
连接概览1

连接概览2

实时流量
此脚本包含的功能有:

  • 1、实时监控任意网卡的流量
  • 2、统计10秒内平均流量
  • 3、统计每个端口在10秒内的平均流量,基于客户端和服务端端口统计。可以看出哪些端口占流量比较大,对于web服务器,一般是80端口。其它端口受到攻击时,也有可能其它端口流量比较大。所以此功能可以帮助我们端口流量是否正常。
  • 4、统计在10s内占用带宽最大的前10个ip。此项功能可以帮助我们来查出是否有恶意占用带宽的ip。
  • 5、统计连接状态。此项功能可以让我们看出哪些连接状态比较大。如果SYN-RECV状态比较多的话,有可以受到半连接攻击。如果ESTABLISED非常大,但通过日志发现没有那么多请求,或者通过tcpdump发现大量ip只建立连接不请求数据的话,可能是受到了全连接攻击,这时候如果你使用的是nginx服务器,可以在配置文件增加listen 80 deferred来防止。
  • 6、统计各端口连接状态。当可能受到攻击时,此项功能可以帮助我们发现是哪个端口受到攻击。
  • 7、统计端口为80且状态为ESTAB连接数最多的前10个IP。此项功能可以帮助我们来找出创建连接过多的Ip,进而屏蔽。
  • 8、统计端口为80且状态为SYN-RECV连接数最多的前10个IP。当受到半连接攻击时,此项功能可以帮助我们找到恶意ip。

用到的网络分析工具:

  • 1、tcpdump:此脚本用tcpdump来统计基于ip或基于端口的流量。
  • 2、ss: 此脚本用ss命令来统计连接状态,实际使用发现ss比netstat高效得多。
  • 3、/proc/net/dev,用来统计指定网卡的流量。

脚本下载地址:https://www.centos.bz/wp-content/uploads/2014/06/network-analysis.sh
下面贴出完整的脚本:

  1. #!/bin/bash
  2.  
  3. #write by zhumaohai(admin#centos.bz)
  4. #author blog: www.centos.bz
  5.  
  6.  
  7. #显示菜单(单选)
  8. display_menu(){
  9. local soft=$1
  10. local prompt="which ${soft} you'd select: "
  11. eval local arr=(\${${soft}_arr[@]})
  12. while true
  13. do
  14.     echo -e "#################### ${soft} setting ####################\n\n"
  15.     for ((i=1;i<=${#arr[@]};i++ )); do echo -e "$i) ${arr[$i-1]}"; done
  16.     echo
  17.     read -p "${prompt}" $soft
  18.     eval local select=\$$soft
  19.     if [ "$select" == "" ] || [ "${arr[$soft-1]}" == ""  ];then
  20.         prompt="input errors,please input a number: "
  21.     else
  22.         eval $soft=${arr[$soft-1]}
  23.         eval echo "your selection: \$$soft"             
  24.         break
  25.     fi
  26. done
  27. }
  28.  
  29. #把带宽bit单位转换为人类可读单位
  30. bit_to_human_readable(){
  31.     #input bit value
  32.     local trafficValue=$1
  33.  
  34.     if [[ ${trafficValue%.*} -gt 922 ]];then
  35.         #conv to Kb
  36.         trafficValue=`awk -v value=$trafficValue 'BEGIN{printf "%0.1f",value/1024}'`
  37.         if [[ ${trafficValue%.*} -gt 922 ]];then
  38.             #conv to Mb
  39.             trafficValue=`awk -v value=$trafficValue 'BEGIN{printf "%0.1f",value/1024}'`
  40.             echo "${trafficValue}Mb"
  41.         else
  42.             echo "${trafficValue}Kb"
  43.         fi
  44.     else
  45.         echo "${trafficValue}b"
  46.     fi
  47. }
  48.  
  49. #判断包管理工具
  50. check_package_manager(){
  51.     local manager=$1
  52.     local systemPackage=''
  53.     if cat /etc/issue | grep -q -E -i "ubuntu|debian";then
  54.         systemPackage='apt'
  55.     elif cat /etc/issue | grep -q -E -i "centos|red hat|redhat";then
  56.         systemPackage='yum'
  57.     elif cat /proc/version | grep -q -E -i "ubuntu|debian";then
  58.         systemPackage='apt'
  59.     elif cat /proc/version | grep -q -E -i "centos|red hat|redhat";then
  60.         systemPackage='yum'
  61.     else
  62.         echo "unkonw"
  63.     fi
  64.  
  65.     if [ "$manager" == "$systemPackage" ];then
  66.         return 0
  67.     else
  68.         return 1
  69.     fi   
  70. }
  71.  
  72.  
  73. #实时流量
  74. realTimeTraffic(){
  75.     local eth=""
  76.     local nic_arr=(`ifconfig | grep -E -o "^[a-z0-9]+" | grep -v "lo" | uniq`)
  77.     local nicLen=${#nic_arr[@]}
  78.     if [[ $nicLen -eq 0 ]]; then
  79.         echo "sorry,I can not detect any network device,please report this issue to author."
  80.         exit 1
  81.     elif [[ $nicLen -eq 1 ]]; then
  82.         eth=$nic_arr
  83.     else
  84.         display_menu nic
  85.         eth=$nic
  86.     fi   
  87.  
  88.     local clear=true
  89.     local eth_in_peak=0
  90.     local eth_out_peak=0
  91.     local eth_in=0
  92.     local eth_out=0
  93.  
  94.     while true;do
  95.         #移动光标到0:0位置
  96.         printf "\033[0;0H"
  97.         #清屏并打印Now Peak
  98.         [[ $clear == true ]] && printf "\033[2J" && echo "$eth--------Now--------Peak-----------"
  99.         traffic_be=(`awk -v eth=$eth -F'[: ]+' '{if ($0 ~eth){print $3,$11}}' /proc/net/dev`)
  100.         sleep 2
  101.         traffic_af=(`awk -v eth=$eth -F'[: ]+' '{if ($0 ~eth){print $3,$11}}' /proc/net/dev`)
  102.         #计算速率
  103.         eth_in=$(( (${traffic_af[0]}-${traffic_be[0]})*8/2 ))
  104.         eth_out=$(( (${traffic_af[1]}-${traffic_be[1]})*8/2 ))
  105.         #计算流量峰值
  106.         [[ $eth_in -gt $eth_in_peak ]] && eth_in_peak=$eth_in
  107.         [[ $eth_out -gt $eth_out_peak ]] && eth_out_peak=$eth_out
  108.         #移动光标到2:1
  109.         printf "\033[2;1H"
  110.         #清除当前行
  111.         printf "\033[K"   
  112.         printf "%-20s %-20s\n" "Receive:  $(bit_to_human_readable $eth_in)" "$(bit_to_human_readable $eth_in_peak)"
  113.         #清除当前行
  114.         printf "\033[K"
  115.         printf "%-20s %-20s\n" "Transmit: $(bit_to_human_readable $eth_out)" "$(bit_to_human_readable $eth_out_peak)"
  116.         [[ $clear == true ]] && clear=false
  117.     done
  118. }
  119.  
  120. #流量和连接概览
  121. trafficAndConnectionOverview(){
  122.     if ! which tcpdump > /dev/null;then
  123.         echo "tcpdump not found,going to install it."
  124.         if check_package_manager apt;then
  125.             apt-get -y install tcpdump
  126.         elif check_package_manager yum;then
  127.             yum -y install tcpdump
  128.         fi
  129.     fi
  130.  
  131.     local reg=""
  132.     local eth=""
  133.     local nic_arr=(`ifconfig | grep -E -o "^[a-z0-9]+" | grep -v "lo" | uniq`)
  134.     local nicLen=${#nic_arr[@]}
  135.     if [[ $nicLen -eq 0 ]]; then
  136.         echo "sorry,I can not detect any network device,please report this issue to author."
  137.         exit 1
  138.     elif [[ $nicLen -eq 1 ]]; then
  139.         eth=$nic_arr
  140.     else
  141.         display_menu nic
  142.         eth=$nic
  143.     fi
  144.  
  145.     echo "please wait for 10s to generate network data..."
  146.     echo
  147.     #当前流量值
  148.     local traffic_be=(`awk -v eth=$eth -F'[: ]+' '{if ($0 ~eth){print $3,$11}}' /proc/net/dev`)
  149.     #tcpdump监听网络
  150.     tcpdump -v -i $eth -tnn > /tmp/tcpdump_temp 2>&1 &
  151.     sleep 10
  152.     clear
  153.     kill `ps aux | grep tcpdump | grep -v grep | awk '{print $2}'`
  154.  
  155.     #10s后流量值
  156.     local traffic_af=(`awk -v eth=$eth -F'[: ]+' '{if ($0 ~eth){print $3,$11}}' /proc/net/dev`)
  157.     #打印10s平均速率
  158.     local eth_in=$(( (${traffic_af[0]}-${traffic_be[0]})*8/10 ))
  159.     local eth_out=$(( (${traffic_af[1]}-${traffic_be[1]})*8/10 ))
  160.     echo -e "\033[32mnetwork device $eth average traffic in 10s: \033[0m"
  161.     echo "$eth Receive: $(bit_to_human_readable $eth_in)/s"
  162.     echo "$eth Transmit: $(bit_to_human_readable $eth_out)/s"
  163.     echo
  164.  
  165.     local regTcpdump=$(ifconfig | grep -A 1 $eth | awk -F'[: ]+' '$0~/inet addr:/{printf $4"|"}' | sed -e 's/|$//' -e 's/^/(/' -e 's/$/)\\\\\.[0-9]+:/')
  166.  
  167.     #新旧版本tcpdump输出格式不一样,分别处理
  168.     if awk '/^IP/{print;exit}' /tmp/tcpdump_temp | grep -q ")$";then
  169.         #处理tcpdump文件
  170.         awk '/^IP/{print;getline;print}' /tmp/tcpdump_temp > /tmp/tcpdump_temp2
  171.     else
  172.         #处理tcpdump文件
  173.         awk '/^IP/{print}' /tmp/tcpdump_temp > /tmp/tcpdump_temp2
  174.         sed -i -r 's#(.*: [0-9]+\))(.*)#\1\n    \2#' /tmp/tcpdump_temp2
  175.     fi
  176.     
  177.     awk '{len=$NF;sub(/\)/,"",len);getline;print $0,len}' /tmp/tcpdump_temp2 > /tmp/tcpdump
  178.  
  179.     #统计每个端口在10s内的平均流量
  180.     echo -e "\033[32maverage traffic in 10s base on server port: \033[0m"
  181.     awk -F'[ .:]+' -v regTcpdump=$regTcpdump '{if ($0 ~ regTcpdump){line="clients > "$8"."$9"."$10"."$11":"$12}else{line=$2"."$3"."$4"."$5":"$6" > clients"};sum[line]+=$NF*8/10}END{for (line in sum){printf "%s %d\n",line,sum[line]}}' /tmp/tcpdump | \
  182.     sort -k 4 -nr | head -n 10 | while read a b c d;do
  183.         echo "$a $b $c $(bit_to_human_readable $d)/s"
  184.     done
  185.     echo -ne "\033[11A"
  186.     echo -ne "\033[50C"
  187.     echo -e "\033[32maverage traffic in 10s base on client port: \033[0m"
  188.     awk -F'[ .:]+' -v regTcpdump=$regTcpdump '{if ($0 ~ regTcpdump){line=$2"."$3"."$4"."$5":"$6" > server"}else{line="server > "$8"."$9"."$10"."$11":"$12};sum[line]+=$NF*8/10}END{for (line in sum){printf "%s %d\n",line,sum[line]}}' /tmp/tcpdump | \
  189.     sort -k 4 -nr | head -n 10 | while read a b c d;do
  190.             echo -ne "\033[50C"
  191.             echo "$a $b $c $(bit_to_human_readable $d)/s"
  192.     done   
  193.         
  194.     echo
  195.  
  196.     #统计在10s内占用带宽最大的前10个ip
  197.     echo -e "\033[32mtop 10 ip average traffic in 10s base on server: \033[0m"
  198.     awk -F'[ .:]+' -v regTcpdump=$regTcpdump '{if ($0 ~ regTcpdump){line=$2"."$3"."$4"."$5" > "$8"."$9"."$10"."$11":"$12}else{line=$2"."$3"."$4"."$5":"$6" > "$8"."$9"."$10"."$11};sum[line]+=$NF*8/10}END{for (line in sum){printf "%s %d\n",line,sum[line]}}' /tmp/tcpdump | \
  199.     sort -k 4 -nr | head -n 10 | while read a b c d;do
  200.         echo "$a $b $c $(bit_to_human_readable $d)/s"
  201.     done
  202.     echo -ne "\033[11A"
  203.     echo -ne "\033[50C"
  204.     echo -e "\033[32mtop 10 ip average traffic in 10s base on client: \033[0m"
  205.     awk -F'[ .:]+' -v regTcpdump=$regTcpdump '{if ($0 ~ regTcpdump){line=$2"."$3"."$4"."$5":"$6" > "$8"."$9"."$10"."$11}else{line=$2"."$3"."$4"."$5" > "$8"."$9"."$10"."$11":"$12};sum[line]+=$NF*8/10}END{for (line in sum){printf "%s %d\n",line,sum[line]}}' /tmp/tcpdump | \
  206.     sort -k 4 -nr | head -n 10 | while read a b c d;do
  207.         echo -ne "\033[50C"
  208.         echo "$a $b $c $(bit_to_human_readable $d)/s"
  209.     done
  210.  
  211.     echo
  212.     #统计连接状态
  213.     local regSS=$(ifconfig | grep -A 1 $eth | awk -F'[: ]+' '$0~/inet addr:/{printf $4"|"}' | sed -e 's/|$//')
  214.     ss -an | grep -v -E "LISTEN|UNCONN" | grep -E "$regSS" > /tmp/ss
  215.     echo -e "\033[32mconnection state count: \033[0m"
  216.     awk 'NR>1{sum[$(NF-4)]+=1}END{for (state in sum){print state,sum[state]}}' /tmp/ss | sort -k 2 -nr
  217.     echo
  218.     #统计各端口连接状态
  219.     echo -e "\033[32mconnection state count by port base on server: \033[0m"
  220.     awk 'NR>1{sum[$(NF-4),$(NF-1)]+=1}END{for (key in sum){split(key,subkey,SUBSEP);print subkey[1],subkey[2],sum[subkey[1],subkey[2]]}}' /tmp/ss | sort -k 3 -nr | head -n 10   
  221.     echo -ne "\033[11A"
  222.     echo -ne "\033[50C"
  223.     echo -e "\033[32mconnection state count by port base on client: \033[0m"
  224.     awk 'NR>1{sum[$(NF-4),$(NF)]+=1}END{for (key in sum){split(key,subkey,SUBSEP);print subkey[1],subkey[2],sum[subkey[1],subkey[2]]}}' /tmp/ss | sort -k 3 -nr | head -n 10 | awk '{print "\033[50C"$0}'   
  225.     echo   
  226.     #统计端口为80且状态为ESTAB连接数最多的前10个IP
  227.     echo -e "\033[32mtop 10 ip ESTAB state count at port 80: \033[0m"
  228.     cat /tmp/ss | grep ESTAB | awk -F'[: ]+' '{sum[$(NF-2)]+=1}END{for (ip in sum){print ip,sum[ip]}}' | sort -k 2 -nr | head -n 10
  229.     echo
  230.     #统计端口为80且状态为SYN-RECV连接数最多的前10个IP
  231.     echo -e "\033[32mtop 10 ip SYN-RECV state count at port 80: \033[0m"
  232.     cat /tmp/ss | grep -E "$regSS" | grep SYN-RECV | awk -F'[: ]+' '{sum[$(NF-2)]+=1}END{for (ip in sum){print ip,sum[ip]}}' | sort -k 2 -nr | head -n 10
  233. }
  234.  
  235. main(){
  236.     while true; do
  237.         echo -e "1) real time traffic.\n2) traffic and connection overview.\n"
  238.         read -p "please input your select(ie 1): " select
  239.         case  $select in
  240.             1) realTimeTraffic;break;;
  241.             2) trafficAndConnectionOverview;break;;
  242.             *) echo "input error,please input a number.";;
  243.         esac
  244.     done   
  245. }
  246.  
  247. main

脚本中如有不明白的地方,可以留言咨询。

转载请保留原文链接:Linux运维日志 » 网络分析shell脚本(实时流量+连接统计)

打赏

如果此文对你有所帮助,请随意打赏鼓励作者^_^

评论 33

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. 情朗大神,我执行此脚本的2) traffic and connection overview.功能时,系统报错(167行), line 167: : command not found回复
    • 朱 茂海@情朗 167是哪一行回复
      • 情朗@朱 茂海 awk -F'[ .:]' -v regTcpdump=$regTcpdump '{if ($0 ~ regTcpdump){line="clients > "$8"."$9"."$10"."$11":"$12}else{line=$2"."$3"."$4"."$5":"$6" > clients"};sum[line]+=$NF*8/10}END{for (line in sum){printf "%s %d\n",line,sum[line]}}' /tmp/tcpdump | \回复
        • 朱 茂海@情朗 不知道什么原因,你可以使用如下命令来运行下。 wget https://www.centos.bz/wp-content/uploads/2014/06/network-analysis.sh chmod +x network-analysis.sh ./network-analysis.sh回复
  2. watchsky@朱 茂海 挺好的,收藏了,不过如果网卡做了bond呢?回复
    • 朱 茂海@watchsky 这个没考虑到bond回复
  3. cody如何查看 80 端口被占用的 ip 对应的 进程 呢?发现有些奇怪的ip,不知道是不是恶意的。回复
    • 朱 茂海@cody 你这句话说得好绕,不明白你说什么回复
      • kkk@朱 茂海 用lsof -i:80 这样可以看到使用80端口的进程回复
  4. 学徒真是好东西尼。回复
  5. Mallux:razz: 很强大的脚本,分析研究下~~回复
  6. rocdk890大神,我想请问下为什么我执行脚本后,会出现下面的错误呢? please input your select(ie 1): 2 kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]回复
    • 朱 茂海@rocdk890 编辑脚本,在第一行后面加-x,如#!/bin/bash -x,然后执行脚本,把输出贴出来才能找出问题。回复
  7. ryan博主你好,运行时有错误。错误如下 11: network-analysis.sh: Syntax error: "(" unexpected (expecting "}") 有点疑惑回复
  8. snom群主, #统计端口为80且状态为ESTAB连接数最多的前10个IP #统计端口为80且状态为SYN-RECV连接数最多的前10个IP 这里貌似没有用来判断是否是80端口,这里统计的是全部的端口回复
    • 朱 茂海@snom 嗯,注释有错回复
  9. 心碎随风请教一下,怎么样把脚本的菜单的1 和2 分开?这样就可以直接用定时任务调了。另外关于top 10 统计出来的ip流量,能不能把公网和私网的ip分开列出,比较好观察。回复
    • 朱 茂海@心碎随风 菜单1和2是根据机器网卡数量生成的,如果只有一个网卡,就不会有菜单;公网和私网ip统计分开,假如你这两种流量是分布在不同网卡,就可以分别统计不同网卡的流量回复
      • 心碎随风问题是公网和私网的ip都是走同一块网卡。@朱 茂海回复
  10. 心碎随风脚本执行后的结果中,server 和client分别指的是什么?回复
    • 朱 茂海server就是你运行脚本的机器,client是其它连接server的机器回复