import ipaddress
import platform
import re
from sys import exit
from loguru import logger
dst = "C:/Windows/System32/drivers/etc/hosts"
if str(platform.system()) != "Windows":
dst = "/etc/hosts"
def read_file(filename):
"""
读取文件
:param filename:
:return:
"""
txt = ''
try:
with open(filename, 'r') as f:
lines = f.readlines()
for line in lines:
if not line.strip().startswith('#'):
if len(line) >= 2:
txt += line
print(txt)
s = txt.split("\n")
if len(s) == 1:
logger.warning(f"[ {dst} ]文件未配置任何有效记录")
else:
logger.info(f'当前数据量: {len(s) - 1}')
return txt
except Exception as e:
logger.error(e)
exit(1)
def is_ipv4_or_ipv6(ip_str):
try:
ip = ipaddress.ip_address(ip_str)
if isinstance(ip, ipaddress.IPv4Address) or isinstance(ip, ipaddress.IPv6Address):
logger.info("IP格式符合")
return True
except ValueError:
logger.warning(f"IP地址格式错误: {ValueError}")
return False
def is_valid_domain(domain):
pattern = re.compile(r'^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$')
return bool(pattern.match(domain))
def list_to_str(list_ip, list_name: list):
logger.debug("列表1: ")
print(list_ip)
logger.debug("列表2: ")
print(list_name)
if len(list_ip) == 0 or len(list_name) == 0:
logger.error("列表数据: 0")
exit(4)
txt = ''
for index, vip in enumerate(list_ip):
txt += f"\n{vip}\t{list_name[index]}"
logger.debug(f"{vip}\t{list_name[index]}")
return txt
def GenerateDictionary(txt: str):
"""
生成字典
:param txt:
:return: dict
"""
domain_dict = {}
txt_sp = txt.split("\n")
for i in txt_sp:
if len(i) <= 10:
continue
info = str(i).split(" ")
if len(info) != 2:
info = str(i).split("\t")
else:
continue
if len(info) != 2:
continue
logger.debug(info)
if len(info[1]) >= 2 and is_valid_domain(info[1]) and is_ipv4_or_ipv6(info[0]):
logger.info(f"符合格式: {info}")
domain_dict[info[0]] = info[1]
else:
logger.warning(f"忽略内容: {info}")
return domain_dict
def dict_to_string(domain_dict: dict):
"""
字典转字符串
:param domain_dict:
:return:
"""
txt = ''
if len(domain_dict) == 0:
logger.error('No domain...')
return txt
for key, value in domain_dict.items():
txt += f"{key}\t{value}\n"
return txt
def write_domain(txt: str):
"""
写入解析参数
:param txt:
:return:
"""
try:
with open(file=dst, mode='w', encoding='utf-8') as f:
f.write(txt)
except IOError:
logger.error(IOError)
exit(3)
print(read_file(filename=dst))
def delete_domain():
"""
删除解析
:return:
"""
dict_ = {0: "domain"}
data = GenerateDictionary(read_file(dst))
if len(data) == 0:
logger.warning("不存在数据,无需删除")
return
for index, value_ip in enumerate(data):
print(f"[ {index} ] -> [ {value_ip} : {str(data[value_ip])}]")
dict_[int(index)] = str(value_ip)
index += 1
ids = input("请输入需要删除的记录值ID,默认: 0\n")
if len(ids) == 0:
ids = 0
try:
ids = int(ids)
except ValueError:
logger.warning(f"格式输入错误,仅支持数字: {ValueError}")
return
print(data)
print(dict_)
if 0 <= int(ids) <= index:
try:
del data[dict_[ids]]
except KeyError:
logger.error("不存在该记录")
return
write_domain(dict_to_string(data))
def add_hosts():
"""
添加解析记录到hosts文件
:return:
"""
# 获取新数据
ip = input("请输入需要解析的IP\n")
domain = input("请输入需要解析的域名,默认: tt.cc\n")
if len(ip) <= 6:
logger.error("IP长度不满足")
return
if len(domain) == 0:
domain = "tt.cc"
if not is_ipv4_or_ipv6(ip):
return
if not is_valid_domain(domain):
logger.warning("Invalid domain")
return
data = GenerateDictionary(read_file(dst))
if len(data) != 0:
logger.debug("正在检查是否已存在")
for vip in data:
print(f"{vip} {data[vip]}")
if str(vip).lower() == str(ip).lower():
logger.warning(f"IP已存在,请先删除再添加: {vip} {data[vip]}")
return
if str(domain).lower() == str(data[vip]).lower():
logger.warning(f"域名已存在,请先删除再添加{vip} {data[vip]}")
return
data[ip] = domain
write_domain(dict_to_string(data))
else:
write_domain(f"{ip}\t{domain}\n")
if __name__ == '__main__':
while True:
print("请选择需要的操作")
print("[1] 添加解析")
print("[2] 删除单个解析")
print("[3] 清空解析")
print("[4] 查看当前配置")
se = input("请输入序号\n")
try:
se = int(se)
except ValueError:
print("输入错误,请重新输入")
continue
if int(se) == 1:
add_hosts()
elif int(se) == 2:
delete_domain()
elif int(se) == 3:
write_domain(txt="\n")
logger.info("清空完成...")
elif int(se) == 4:
c = GenerateDictionary(read_file(dst))
print("------------当前配置如下-----")
print(c)
print("-------------------------\n")
else:
print("输入错误,请重新输入")
效果
PS D:\code\coding\ywgl\tools\运维自动化> python .\HOSTS更新.py
请选择需要的操作
[1] 添加解析
[2] 删除单个解析
[3] 清空解析
[4] 查看当前配置
请输入序号
4
172.22.10.4 tt.cc
2024-03-19 13:23:28.301 | INFO | __main__:read_file:32 - 当前数据量: 1
2024-03-19 13:23:28.302 | DEBUG | __main__:GenerateDictionary:89 - ['172.22.10.4', 'tt.cc']
2024-03-19 13:23:28.302 | INFO | __main__:is_ipv4_or_ipv6:43 - IP格式符合
2024-03-19 13:23:28.302 | INFO | __main__:GenerateDictionary:91 - 符合格式: ['172.22.10.4', 'tt.cc']
------------当前配置如下-----
{'172.22.10.4': 'tt.cc'}
-------------------------
请选择需要的操作
[1] 添加解析
[2] 删除单个解析
[3] 清空解析
[4] 查看当前配置
请输入序号
2
172.22.10.4 tt.cc
2024-03-19 13:23:31.129 | INFO | __main__:read_file:32 - 当前数据量: 1
2024-03-19 13:23:31.130 | DEBUG | __main__:GenerateDictionary:89 - ['172.22.10.4', 'tt.cc']
2024-03-19 13:23:31.130 | INFO | __main__:is_ipv4_or_ipv6:43 - IP格式符合
2024-03-19 13:23:31.130 | INFO | __main__:GenerateDictionary:91 - 符合格式: ['172.22.10.4', 'tt.cc']
[ 0 ] -> [ 172.22.10.4 : tt.cc]
请输入需要删除的记录值ID,默认: 0
{'172.22.10.4': 'tt.cc'}
{0: '172.22.10.4'}
2024-03-19 13:23:33.354 | ERROR | __main__:dict_to_string:106 - No domain...
2024-03-19 13:23:33.370 | WARNING | __main__:read_file:30 - [ C:/Windows/System32/drivers/etc/hosts ]文件未配置任何有效记录
请选择需要的操作
[1] 添加解析
[2] 删除单个解析
[3] 清空解析
[4] 查看当前配置
请输入序号
4
2024-03-19 13:23:38.885 | WARNING | __main__:read_file:30 - [ C:/Windows/System32/drivers/etc/hosts ]文件未配置任何有效记录
------------当前配置如下-----
{}
-------------------------
请选择需要的操作
[1] 添加解析
[2] 删除单个解析
[3] 清空解析
[4] 查看当前配置
请输入序号