美文网首页
Linux 主机实现监控对外访问的 HTTP(s) 和流量

Linux 主机实现监控对外访问的 HTTP(s) 和流量

作者: awker | 来源:发表于2019-06-27 20:49 被阅读0次

需求背景

目前公司部分业务使用阿里云环境,Linux 主机使用的是 ECS

  1. 部分 Linux 主机使用阿里云 SNAT 直接访问外网(没办法监控这部分主机对外访问的 http(s) 请求和流量)
  2. 部分 Linux 主机使用 Squid 正向代理,再通过 SNAT 访问外网(可以通过 Squid 监控这部分主机对外访问的 http(s) 请求和流量)

使用 Squid 正向代理,也有部分问题,一个是无法代理 TCP 协议,另一个是部分 Java 服务使用的 http(s) Client 无法直接使用 Squid 正向代理,要做代码修改。阿里云ECS也不支持修改主机网关IP,因此透明代理的方案也行不通

产生的问题

平时偶尔会收到 SNAT 的 EIP 入方向量告警,也就是对 Linux 主机对外请求的流量


解决过程:

如何实现监控 Linux 主机对外访问的 http(s) 和流量呢?(需求背景 1 的 Linux 主机)
思路1:
通过监控 SNAT 可以实现吗?
不能,SNAT 只能监控到哪台主机往外发的流量大小,并且还要提工单让阿里云工程师查询

思路2:可以通过阿里云 云防火墙 监控整个 VPC 对外访问的 HTTP(s) 和流量
可以,但是价格昂贵

思路3:有没有开源工具可以实现监控 Linux 主机对外访问的 http(s) 和流量
尝试过 iftop、httpry、jnettop 等工具,基本都无法监控 https 流量

思路4:自己编写 Python 脚本,实现监控 Linux 主机对外访问的 http(s) 和流量
可以使用 Python scapy 模块监控网络流量,但从 https 原理上来说, scapy 是不能获取到 https 的请求地址的

但可以做个变通,把 DNS 解析的记录也监控,就知道请求了哪个 https 地址
示例脚本如下:

# coding: utf-8
from scapy.all import *
import logging
import re

logging.basicConfig(filename='/data/scripts/tcp_sniffer/packet.log',
                    format='%(asctime)s - %(name)s - %(levelname)s - %(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    level=10)
# 匹配阿里云SLB健康探测网段 100.64.0.0/10,参考:https://www.regextester.com/97320
pattern01 = re.compile(r'100\.(?:6[4-9]|[7-9]\d|1[0-1]\d|12[0-7])\.\d{1,3}\.\d{1,3}')
# 匹配一些阿里云内网DNS解析字段和NTP解析字段
pattern02 = re.compile(r'in-addr\.arpa|cnszsc|localdomain|aliyuncs\.com|aliyun\.com|NTP')


def packet_callback(pkt):
    for x in pkt:
        if x.haslayer(UDP):
            # x.getlayer(IP).dst --> IP数据包里的目标IP
            # 阿里云内网DNS ['100.100.2.136', '100.100.2.138'] 也在 100.64.0.0/10 网段范围内,所以这里先做个判断
            if (x.getlayer(IP).dst in ['100.100.2.136', '100.100.2.138']):
                msg = pkt.sprintf(pkt.summary() + " / packet_size: %IP.len%")
                # 过滤掉 一些阿里云内网DNS解析字段和NTP解析字段
                if not pattern02.search(msg):
                    # print '1' + msg
                    logging.info(msg)
        # 过滤掉 阿里云SLB健康探测网段 100.64.0.0/10 的请求
        if not pattern01.match(x.getlayer(IP).dst):
            msg = pkt.sprintf(pkt.summary() + " / packet_size: %IP.len%")
            if not pattern02.search(msg):
                # print '2' + msg
                logging.info(msg)


# 增加 store=0 参数,不然内存会持续升高,
# 参见:https://stackoverflow.com/questions/31116970/strange-python-memory-usage-with-scapy
sniff(filter="not (dst net 10.0.0.0/8)", prn=packet_callback, store=0)

// 运行 tcp_sniffer.py
# python tcp_sniffer.py 

在另一个终端测试 http(s) 请求

# curl -I https://www.baidu.com
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: Keep-Alive
Content-Length: 277
Content-Type: text/html
Date: Thu, 27 Jun 2019 12:02:55 GMT
Etag: "575e1f72-115"
Last-Modified: Mon, 13 Jun 2016 02:50:26 GMT
Pragma: no-cache
Server: bfe/1.0.8.18

实现效果:

2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / UDP / DNS Qry "www.baidu.com." / packet_size: 59
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / UDP / DNS Qry "www.baidu.com." / packet_size: 59
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https S/ packet_size: 60
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https PA / Raw/ packet_size: 227
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https PA / Raw/ packet_size: 166
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 52
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https A/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https PA / Raw/ packet_size: 147
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https PA / Raw/ packet_size: 71
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https FA/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https R/ packet_size: 40
2019-06-27 20:02:55 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:37626 > 14.215.177.39:https R/ packet_size: 40
2019-06-27 20:03:05 - root - INFO - tcp_sniffer:  Ether / IP / TCP 10.1.18.250:40646 > 116.31.68.142:http FA/ packet_size: 52

这样就可以把对外访问的 HTTP(s) 和流量,记录到日志文件里,或者收集到 ELK、Graylog 等日志系统中。
等到出现告警的时间点,就可以检查到是 对外访问的哪些 HTTP(s) URL 引起的告警。



其它问题

内存占用问题:
脚本启动后,发现内存持续升高,经过排查搜索发现,scapy 会保存所有捕获的数据包在内存中
加一个参数 scapy sniff store=0 即可解决


参见:
https://stackoverflow.com/questions/31116970/strange-python-memory-usage-with-scapy
https://bitbucket.org/secdev/scapy/issues/296/memory-leak-in-sniff-function-with-prn-set

相关文章

网友评论

      本文标题:Linux 主机实现监控对外访问的 HTTP(s) 和流量

      本文链接:https://www.haomeiwen.com/subject/vqsdcctx.html