本帖最后由 1073 于 2023-3-1 07:27 编辑
工具介绍:https://www.52pojie.cn/thread-1747412-1-1.html
邮件效果和配置文件
2023/3/1
添加了两条错误日志输出
2023/2/23
使用python3.10编译,优化了一下代码,
执行过程:
1.使用 ConfigParser() 函数创建一个 config 实例,并使用 read() 方法读取名为 Mail.ini 的配置文件。然后获取 WL 段中的 add 选项的值并按逗号分隔成列表,将其保存到 wl_list 变量中。接着遍历 port 段中的所有选项,如果选项的名称以 net_port 开头且选项的值是数字,则将其转换为整数并调用 get_remote_ips() 函数获取当前连接到该端口的所有远程IP地址,将其保存到 remote_ips_dict 字典中。
2.定义函数 get_remote_ips(),它接收两个参数 port 和 wl_list,并使用 net_connections() 函数获取当前系统上所有建立连接的信息。然后使用生成器表达式筛选出所有远程IP地址,使得地址不是空值、状态为 ESTABLISHED、不是本地回环地址、不包含冒号,且本地地址的端口号等于 port 参数。然后使用列表推导式去重并过滤掉在 wl_list 中出现的地址,最终返回远程IP地址列表。
3.定义函数 send_mail(),它接收两个参数 remote_ips_dict 和 config。函数首先获取当前计算机的主机名、用户名和当前时间,并将其插入到邮件正文中。然后遍历 remote_ips_dict 字典中的所有端口及其对应的远程IP地址,如果有远程IP地址则将其插入到邮件正文中,最终将邮件正文和邮件标题通过 zmail 模块发送到指定的收件人。
4.如果 remote_ips_dict 字典中至少有一个非空列表,则调用 send_mail() 函数将所有远程IP地址发送到指定的收件人。
[Python] 纯文本查看 复制代码 from configparser import ConfigParser
from time import strftime, localtime
from psutil import net_connections
from os import environ
import zmail
# 获取远程IP地址
def get_remote_ips(port, wl_list):
# 使用psutil库中的net_connections函数获取所有网络连接信息
# 筛选出对应端口、处于已建立状态、远程地址不是回环地址和IPv6地址的网络连接
remote_ips = (conn.raddr[0] for conn in net_connections()
if conn.raddr and conn.status == 'ESTABLISHED'
and not conn.raddr[0].startswith('127.')
and ':' not in conn.raddr[0]
and conn.laddr[1] == port)
# 返回远程IP地址列表中不在白名单中的地址
return [ip for ip in set(remote_ips)
if not any(ip.startswith(wl) for wl in wl_list if wl.strip())] or []
# 发送邮件
def send_mail(remote_ips_dict, config):
# 获取计算机名称、用户名和当前时间
try:
hostname, username = environ["COMPUTERNAME"], environ["USERNAME"]
time = strftime("%Y-%m-%d %H:%M:%S", localtime())
# 构造邮件正文
content = [f'<font size="4">检测时间: {time}<br>主机名: {hostname}<br>用户名: {username}<br></font><br>']
for port, remote_ips in remote_ips_dict.items():
if remote_ips:
content.append(
f'连接端口<font color="#0000ff"><b>"{port}"</b></font>的IP地址:<br>'
f'<b><font color="#ff0000" size="5">{"<br>".join(remote_ips)}</font></b><br>'
f'<a <br>".join(remote_ips)}'
f'">查询IP归属地</a><br>====================<br><br>')
content = "".join(content)
# 从配置文件中读取发件人地址、密码和邮件标题
from_addr, pwd, title = (
config.get('Mail', key) for key in ('from_addr', 'pwd', 'title')
)
# 从配置文件中读取收件人地址列表
to_addr = config.get('to_addr', 'add').split(',')
# 使用zmail库发送邮件
zmail.server(from_addr, pwd).send_mail(to_addr, {'subject': title, 'content_html': content})
except Exception as e:
with open("Mail.log", "a", encoding="utf-8") as f:
f.write(f"[{strftime('%Y-%m-%d %H:%M:%S', localtime())}] [ERROR] 邮件发送失败: {str(e)}\n")
# 从配置文件中读取白名单和需要检测的端口
config = ConfigParser()
config.read('Mail.ini', encoding='utf-8')
wl_list = config.get('WL', 'add').split(',')
remote_ips_dict = {}
for port_key, port in config.items('port'):
if port_key.startswith('net_port') and (port := port.strip()).isdigit():
remote_ips = get_remote_ips(int(port), wl_list)
if remote_ips:
remote_ips_dict[int(port)] = remote_ips
else:
with open('Mail.log', 'w', encoding="utf-8") as f:
f.write(f"[{strftime('%Y-%m-%d %H:%M:%S', localtime())}] "
f"[INFO] 端口{port}外部IP不存在或与白名单匹配,程序退出。\n")
# 如果有需要发送的远程IP地址,则发送邮件
if remote_ips_dict.values():
send_mail(remote_ips_dict, config)
|