使用 prometheus_client 和 Flask 实现端口探测 Exporter

安装 pyyaml prometheus_client flask scapy

# pip install pyyaml prometheus_client flask scapy

编写 active_check_exporter.py

# coding: utf-8
from scapy.all import *
import yaml
import os
from prometheus_client.core import CollectorRegistry
from prometheus_client import Gauge, generate_latest
from flask import Flask, Response


def get_config(filename):
    with open(filename, "r") as ymlfile:
        cfg = yaml.safe_load(ymlfile)
    return cfg


def tcp_connect_scan(dst_ip, dst_port, dst_timeout):
    """
    Open: 1
    Closed: 0
    CHECK: 0
    """
    src_port = RandShort()
    # 发送 SYN 数据包
    tcp_connect_scan_resp = sr1(IP(dst=dst_ip) / TCP(sport=src_port, dport=dst_port, flags="S"), timeout=dst_timeout,
                                verbose=0)
    # 无法连接目标时,tcp_connect_scan_resp 为 None,str(type(res)) --> ""
    if (str(type(tcp_connect_scan_resp)) == ""):
        return 0
    # 判断是否有TCP包返回
    elif (tcp_connect_scan_resp.haslayer(TCP)):
        # flags == 0x12,即 A 0x10 Ack + S 0x02 Syn --> 0x10 + 0x02 = 0x12
        # 判断返回的TCP包是否为 SA(tcp_connect_scan_resp.getlayer(TCP).flags == "SA")
        if (tcp_connect_scan_resp.getlayer(TCP).flags == 0x12):
            # 发送 A Ack + R Reset 数据包,断开连接
            send_rst = sr(IP(dst=dst_ip) / TCP(sport=src_port, dport=dst_port, flags="AR"), timeout=dst_timeout,
                          verbose=0)
            return 1
        # flags == 0x14,即 A 0x10 Ack + R 0x04 Reset --> 0x10 + 0x 04 = 0x14
        # 目标端口不存在时,判断返回的TCP包是否为 RA(tcp_connect_scan_resp.getlayer(TCP).flags == 'RA')
        elif (tcp_connect_scan_resp.getlayer(TCP).flags == 0x14):
            return 0
    else:
        return 0


# 设置 metrics
registry = CollectorRegistry(auto_describe=False)
active_num = Gauge('active', 'active port num', ['service'], registry=registry)
app = Flask(__name__)


@app.route("/metrics")
def main():
    filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.yml")
    config = get_config(filename)
    status = {}
    for key, value in config.iteritems():
        for ip_port in value:
            ip, port = ip_port.split(':')[0], int(ip_port.split(':')[1]),
            active = tcp_connect_scan(ip, port, 1)
            if key in status:
                status[key] += active
            else:
                status[key] = active
        active_num.labels(service=key).set(float(status[key]))
    return Response(generate_latest(registry), mimetype="text/plain")


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001)

要探测的端口加到 config.yml 即可,格式:

服务名称:
  - IP1:PORT
  - IP2:PORT
# cat config.yml
fdfs_storaged:
  - 10.1.29.222:23000
  - 10.1.32.251:23000
  - 10.1.29.223:23000
  - 10.1.32.252:23000

fdfs_trackerd:
  - 10.1.29.221:22122
  - 10.1.32.242:22122

最终采集到的的数据

# python active_check_exporter.py

参考:

  1. https://resources.infosecinstitute.com/port-scanning-using-scapy/
  2. https://github.com/interference-security/Multiport/blob/master/multiport.py
  3. https://github.com/prometheus/client_python

你可能感兴趣的:(使用 prometheus_client 和 Flask 实现端口探测 Exporter)