安装 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)) --> "<type 'NoneType'>"
if (str(type(tcp_connect_scan_resp)) == "<type 'NoneType'>"):
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
参考: