Python 运维作业3
两个代码:有问题记得跟咱说
两个代码:有问题记得跟咱说
更新地址:
在当前路径下创建文件夹,并用自己的姓名命名,该文件夹下有若干中文命名的文件和文件夹。
(1)编写FTP程序,设置用户名、密码、上传下载速率限制,家目录为姓名命名的目录。用户具有更改目录、删除文件或目录、创建目录、上传下载文件的权限。FTP日志分别输出到屏幕和以学号命名的.Log文件中,输出至屏幕的日志等级为INFO,输出文件的日志等级为WARNING。该目录下,仅当有文件或文件被修改时,记录一条日志事件,要求包括事件发生时间、事件发生位置、事件的严重程度、事件内容,并将该事件输出至以学号命名的.Log文件中。
(2)编写程序实现邮件发送,将.log文件的内容作为邮件正文,.log文件为附件。
提交要求:粘贴两个程序的代码,上传运行过程的截图,截图形式如下所示。

安装包:
pip install -i https://mirrors.ustc.edu.cn/pypi/web/simple chardet colorama colorlog watchdog ansi2html pyftpdlib如果有奇怪的报错,请不要用python 3.12
这里具体可以去看章节:QQ邮箱SMTP地址
这个能跑,但是你想学到东东还是要自己写比较好。

再来个邮箱方便参考

这里,授权码没改的缘故。
其他的邮箱服务商同理

老板QQ:


密保信息填完之后,复制授权码

点击立即下载后,普通下载,证书忽略过期(速度快)
用户名,密码在主程序的传参里


日志正常输出(等级为WARNING)



感觉跟差不多,多弄点图




邮件图:


pip install -i https://mirrors.ustc.edu.cn/pypi/web/simple chardet colorama colorlog watchdog ansi2html pyftpdlib运行样子:
有个小bug,可能会重复发送两次邮件(但是完全不影响结果,晚点再改)

当当:








内容:

ftp_server.pyimport logging.handlers
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
import os
# 好看的日志输出,初始化日志模块
import prog_1
def main(username="dayi",password="abc123...",home_dir="./dayi",log_file="202123030408.log"):
# 初始化日志模块
os.makedirs(home_dir, exist_ok=True) # 创建日志目录
logger = prog_1.init_logger(output_filename=log_file)
logger.info("Ftp 服务器启动~~~~~~~~~~~~~~~~")
handler = FTPHandler
authorizer = DummyAuthorizer()
authorizer.add_user(username, password, home_dir, perm="elradfmwM") # 全部权限
handler.authorizer = authorizer
handler.banner = "Welcome to my FTP server! ovo! hello~~~~~~~~~my friend!"
handler.masquerade_address = "127.0.0.1" # 伪装地址
handler.max_login_attempts = 3 # 最大登录尝试次数
handler.permit_foreign_addresses = True # 允许远程访问
# 下载上传速度设置
dtp_handler = handler.dtp_handler
dtp_handler.read_limit = 1024 * 1024
dtp_handler.write_limit = 1024 * 1024
handler.dtp_handler = dtp_handler
handler.tcp_no_delay = True # 禁用Nagle算法
handler.passive_ports = range(60000, 65535) # 被动模式端口范围
# 启动FTP服务器
server = FTPServer(("127.0.0.1", 21), handler)
logging.info("FTP server started on 127.0.0.1:21")
server.serve_forever()
if __name__ == "__main__":
main()prog_1.pyfrom watchdog.observers import Observer # 导入watchdog库中的Observer类,用于监控文件系统事件
from watchdog.events import FileSystemEventHandler # 导入FileSystemEventHandler类,用于处理文件系统事件
import time
import logging
import colorlog
import os
from colorlog.escape_codes import escape_codes
import chardet
logger = logging.getLogger() # 获取logger实例
def log_init(output_filename="114514.log"):
global logger
logger.setLevel(logging.INFO) # 设置日志级别
handler = colorlog.StreamHandler() # 创建一个StreamHandler用于输出到控制台
# -[func:%(funcName)s]
handler.setFormatter(colorlog.ColoredFormatter(
'[%(log_color)s%(asctime)s.%(msecs)03d%(reset)s][%(log_color)s%(levelname)s%(reset)s]: %(log_color)s%(message)s', # 设置日志输出格式
datefmt='%Y-%m-%d %H:%M:%S', # 设置时间格式
reset=True, # 重置终端属性
log_colors={ # 设置日志级别和日期时间的颜色
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_white',
'asctime': 'blue', # 设置日期时间的颜色
},
))
logger.addHandler(handler)
# 输出到文件
log_dir = '.'
# os.makedirs(log_dir, exist_ok=True) # 创建日志目录
file_handler = logging.FileHandler(os.path.join(log_dir, output_filename), 'a', encoding='utf-8')
file_formatter = logging.Formatter('[%(asctime)s.%(msecs)03d][%(levelname)s]: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(file_formatter)
file_handler.setLevel(logging.WARNING) # 只输出WARNING及以上级别的日志到文件
logger.addHandler(file_handler)
def colorize_string(s, color):
return f"{escape_codes[color]}{s}{escape_codes['reset']}"
# 用chardet来检测编码
def detect_encoding(file_path):
# 先尝试GBK读取
try:
with open(file_path, 'r', encoding='gbk') as f:
f.read()
return 'gbk'
except:
with open(file_path, 'rb') as f:
result = chardet.detect(f.read())
return result['encoding']
class MyHandler(FileSystemEventHandler):
def __init__(self):
self.emit_once = True # 减少事件触发次数
def on_any_event(self, event):
# 如果包含__pycache__,则忽略
if "__pycache__" in event.src_path:
return
# 事件类型描述
event_description = {
'modified': colorize_string("[修改]", 'red'),
'created': colorize_string("[创建]", 'green'),
'deleted': colorize_string("[删除]", 'yellow'),
'moved': colorize_string("[移动]", 'blue')
}
# 目录或文件描述
file_dir_desc = {
True: colorize_string("【目录】", 'blue'),
False: colorize_string("【文件】", 'yellow')
}
# 是否是目录
dir_or_file = file_dir_desc[event.is_directory]
logger_str = f"{event_description.get(event.event_type, '未知事件'+str(event.event_type))}{dir_or_file}: 路径:{event.src_path}"
# 记录事件信息
logger.warning(logger_str)
# 对于文件的修改和创建事件,进一步处理
if event.event_type in ['modified', 'created'] and not event.is_directory:
file_name_without_path = event.src_path.split("\\")[-1] # 从路径中提取文件名
action = "被修改" if event.event_type == 'modified' else "被创建"
# logger.info(f'文件: {file_name_without_path} {action}')
# 修改事件
if event.event_type == 'modified':
return
# bin
try:
with open(event.src_path, 'rb') as file:
logger.info('读取文件内容成功(二进制)')
file_contents = file.read()
print(f"=============={file_name_without_path}文件内容如下(二进制)==============")
print(f"{file_name_without_path}文件内容(二进制):\n{file_contents}") # 打印文件内容
print(f"=============={file_name_without_path}文件内容如上(二进制)==============")
except Exception as e:
logger.error(f'读取文件时发生错误(二进制读取失败?!): {e}')
# UTF-8 + GBK + ANY
try:
encoding=detect_encoding(event.src_path)
logger.info("检测到编码为:"+encoding)
with open(event.src_path, 'r', encoding=encoding) as file:
file_contents = file.read()
print(f"=============={file_name_without_path}文件修改后内容如下({encoding})==============")
print(f"文件内容({encoding}):\n{file_contents}") # 打印文件内容
print(f"=============={file_name_without_path}文件修改后内容如上({encoding})==============")
#下面的代码应该不会触发,历史遗留
except Exception as e:
try:
logger.info('尝试UTF-8编码读取...')
with open(event.src_path, 'r',encoding="utf-8") as file:
logger.info('读取文件内容成功(UTF-8)')
file_contents = file.read()
print("==============新文件内容如下==============")
print(f"文件内容(UTF-8):\n{file_contents}") # 打印文件内容
print("==============新文件内容如上==============")
except Exception as e:
logger.error(f'读取文件时发生错误: {e}') # 使用日志记录异常信息
logger.info('尝试GBK编码读取...')
try:
with open(event.src_path, 'r',encoding="gbk") as file:
logger.info('读取文件内容成功(GBK)')
file_contents = file.read()
print("==============新文件内容如下==============")
print(f"文件内容:\n{file_contents}") # 打印文件内容
print("==============新文件内容如上==============")
except Exception as e:
logger.error(f'读取文件再次发生错误,未知报错: {e}')
# # 邮件发送!
# logger.info('正在尝试发送邮件')
# time.sleep(1) # 减少CPU占用
# try:
# import sendmail3
# sendmail3.main()
# except Exception as e:
# logger.error(f'发送邮件时发生错误: {e}')
def monitor_folder(path='.'):
event_handler = MyHandler() # 创建MyHandler实例
observer = Observer() # 创建Observer实例
observer.schedule(event_handler, path, recursive=False) # 配置Observer监控的目录和事件处理器
observer.start() # 启动Observer
try: # 等待捕获键盘中断异常
while True:
time.sleep(1) # 减少CPU占用
except KeyboardInterrupt: # 捕获键盘中断(Ctrl+C)
observer.stop() # 停止Observer
# print("[-]捕获到键盘中断,停止监控")
logger.warning("[-]捕获到键盘中断,停止监控")
observer.join() # 等待Observer线程结束
# 初始化日志模块
# 监控
def watch_file(path=".",output_filename="202123030408.log"):
log_init(output_filename=output_filename) #初始化日志
logger.info("看门狗!启动~~~~~~~~~~~~~~~~")
# 这里实际上是两个模块,子进程
now_path = path # 获取当前脚本的路径
logger.info("[+]当前目录为:"+now_path)
logger.info("[+]开始监控文件夹:"+ now_path)
monitor_folder(now_path) # 调用monitor_folder函数开始监控当前脚本所在的目录
def init_logger(output_filename="202123030408.log"):
log_init(output_filename=output_filename) #初始化日志
logger.info("logger被初始化咧,当前输出文件为:"+output_filename)
return logger
def getlogger():
global logger
return logger
#
if __name__=="__main__": # 如果此脚本作为主程序运行
log_init() #初始化日志
logger.info("logger测试")
now_path = os.getcwd() # 获取当前脚本的路径
logger.info("[+]当前目录为:"+now_path)
logger.info("[+]开始监控文件夹:"+ now_path)
monitor_folder(now_path) # 调用monitor_folder函数开始监控当前脚本所在的目录
彩色日志!
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
import os
from ansi2html import Ansi2HTMLConverter
import re
import prog_1
def send_email(sender, receivers, subject, body, attachment_path, log_path, image_path, smtp_server, smtp_server_port, mail_user, mail_pass,logger):
logger.info("发送邮件配置如下:")
logger.info("SMTP服务器:" + smtp_server)
logger.info("SMTP服务器端口:" + str(smtp_server_port))
logger.info("发件人:" + sender)
logger.info("收件人:" + str(receivers))
logger.info("主题:" + subject)
logger.info("附件路径:" + attachment_path)
logger.info("日志路径:" + log_path)
msg = MIMEMultipart('related') # 创建邮件对象,'related' 用于发送内嵌资源的邮件
msg['From'] = sender
msg['To'] = ";".join(receivers)
msg['Subject'] = subject
# HTML 邮件正文
with open(log_path, "r", encoding="utf-8") as f:
content = f.read()
# 彩色
conv = Ansi2HTMLConverter()
with open(log_path, 'r',encoding='utf-8') as f:
content = f.read()
content = re.sub(r'\n', '\n', content)
html_content = conv.convert(content, full=False)
# 彩色!
def colorize(ansi_code, text):
color_map = {
'31': 'red',
'32': 'green',
'33': 'pink',
'34': 'blue'
}
color = color_map.get(ansi_code, 'black')
return f'<span style="color:{color}">{text}</span>'
def colorize_info(color, text):
return f'<span style="color:{color}">{text}</span>'
level_pattern = r'\[(WARNING|ERROR)\]'
html_content = re.sub(level_pattern, lambda m: colorize_info('orange' if m.group(1) == 'WARNING' else 'red', m.group(0)), html_content)
timestamp_pattern = r'\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+\]'
html_content = re.sub(timestamp_pattern, lambda m: colorize_info('green', m.group(0)), html_content)
pattern = r'<span class="ansi(\d+)">([^<]+)</span>'
html_content = re.sub(pattern, lambda m: colorize(m.group(1), m.group(2)), html_content)
with open("test.html",'w',encoding='utf-8') as f:
f.write(f'<html><body>{html_content}</body></html>')
html_content = re.sub(r'\n', '<br>', html_content)
html_body = MIMEText(f'<html><body>{html_content}</body></html>', 'html', 'utf-8')
# html_body = MIMEText(f'ovo', 'html', 'utf-8')
msg.attach(html_body)
# 添加图片
# with open(image_path, 'rb') as f:
# mime_image = MIMEImage(f.read(), 'webp')
# mime_image.add_header('Content-ID', '<image1>')
# msg.attach(mime_image)
# 添加附件
with open(attachment_path, 'rb') as f:
att1 = MIMEText(f.read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
att1["Content-Disposition"] = f'attachment; filename="{os.path.basename(attachment_path)}"'
msg.attach(att1)
# 添加日志文件作为附件
with open(log_path, 'rb') as f:
att2 = MIMEText(f.read(), 'base64', 'utf-8')
att2["Content-Type"] = 'application/octet-stream'
att2["Content-Disposition"] = f'attachment; filename="{os.path.basename(log_path)}"'
msg.attach(att2)
# 发送邮件
try:
smtpObj = smtplib.SMTP(smtp_server, smtp_server_port)
smtpObj.ehlo()
smtpObj.starttls() # 如果SMTP服务器要求安全连接,则需要
smtpObj.login(mail_user, mail_pass)
smtpObj.sendmail(sender, receivers, msg.as_string())
logger.info("邮件发送成功")
except smtplib.SMTPException as e:
logger.error(f"发送邮件出线错误!, 错误信息: {e}")
finally:
smtpObj.quit()
def main(logpath='202123030408.log',smtp_server='smtp.qq.com',smtp_server_port=587,mail_user='',mail_pass='',sender='',recipients='[]',subject='日志!'):
logger=prog_1.init_logger(output_filename=logpath) #初始化日志
logger.info("我是发邮件滴!!正在尝试发送邮件~~~~~~~~~~~~~~~")
# sender = '851845341@qq.com' #发件人
# receivers = ['lamu10@163.com'] #收件人
receivers = recipients
# subject = '日志!'
body = '你好呀呀呀' # 其实没什么用
attachment_path = 'test.html' #这个是html的渲染格式
log_path = logpath #日志路径
image_path = '====.pic' #已经废弃!
# smtp_server = 'smtp.qq.com'
# smtp_server_port = 587
# mail_user = "851845341@qq.com"
# mail_pass = "授权码"
send_email(sender, receivers, subject, body, attachment_path, log_path, image_path, smtp_server, smtp_server_port, mail_user, mail_pass,logger)
if __name__ == '__main__':
# 配置
file_path = '202123030408.log' # 日志文件
smtp_server = 'smtp.qq.com' # smtp 服务器
smtp_server_port = 587 # smtp 服务器端口
mail_user = '81@qq.com' # SMTP登录名
sender = '8@qq.com' # 发件人
mail_pass = 'lof' #SMTP密码
recipients = ['l0@163.com'] #收件人
subject = '日志!'
# 发送邮件
main(logpath=file_path, smtp_server=smtp_server,smtp_server_port=smtp_server_port,mail_user=mail_user,sender=sender,mail_pass=mail_pass,recipients=recipients,subject=subject)
import time
import logging
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import os
from multiprocessing import Process
from prog_1 import watch_file
import prog_1
import ftp_server
from send_mail_ovo import main as send_mail_
if __name__ == '__main__':
# 日志文件名
logger_file_name = '202123030408.log'
# 初始化日志模块
logger=prog_1.init_logger(output_filename=logger_file_name)
logger.info("主进程启动~~~~~~~~~~~~~~~~")
# 看门狗!日志文件:logger_file_name
p = Process(target=watch_file, args=("./dayi",logger_file_name))
p.start()
# FTP服务器, 用户名dayi,密码abc123...,主目录./dayi,日志文件:logger_file_name
p2 = Process(target=ftp_server.main, args=("dayi","abc123...","./dayi","202123030408.log"))
p2.start()
# 主进程保持运行,直到手动中断
# 发送邮件!(CTRL+C) 会自动发送哦,请记得修改配置文件
file_path = '202123030408.log' # 日志文件
smtp_server = 'smtp.exmail.qq.com' # smtp 服务器
smtp_server_port = 587 # smtp 服务器端口
mail_user = '202123030408@sdust.edu.cn' # SMTP登录名
sender = 'dayi@sdust.edu.cn' # 发件人
mail_pass = 'DvWsv' #SMTP密码(授权码)
recipients = ['lamu10@163.com'] #收件人
subject = '日志!'
try:
while True:
time.sleep(0.5)
except KeyboardInterrupt:
print("[-]捕获到键盘中断,停止主进程")
p2.kill()
p.kill()
logger.info('正在尝试发送邮件')
time.sleep(1) # 减少CPU占用
mail_sent = False
if not mail_sent:
try:
send_mail_(logpath=file_path, smtp_server=smtp_server,smtp_server_port=smtp_server_port,mail_user=mail_user,sender=sender,mail_pass=mail_pass,recipients=recipients,subject=subject)
mail_sent = True
except Exception as e:
logger.error(f'发送邮件时发生错误: {e}')
print("主进程已中断")记得自己改名字哦
更新:
加了点日志模块,但是好看了,大概这个样子


运行之后输出
执行prog_2.py:
文件student.ini不存在,将创建默认配置文件
执行prog_3.py:
网络运维技术
执行prog_4.py:
文件内容如下:
[DEFAULTI]
course = 网络运维技术
university = 山东科技大学
grade = 3
[student]
name = ?
class = ?
studentid = ?
sex = ?
==========修改后的值:===================
姓名: dayi
班级: 网络21
学号: 2021233333333
性别: Male
全部日志:(10秒执行一个程序,可以根据时间来区分)
(.venv) PS E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi> py .\prog_1.py
[2024-03-07 11:14:32][INFO]: logger测试
[2024-03-07 11:14:32][INFO]: [+]当前目录为:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi
[2024-03-07 11:14:32][INFO]: [+]开始监控文件夹:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi
[2024-03-07 11:14:33][INFO]: [删除]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\dayi-GBK.txt
[2024-03-07 11:14:33][INFO]: [删除]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\dayi-UTF-8.txt
[2024-03-07 11:14:33][INFO]: [删除]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\student.ini
[2024-03-07 11:14:43][INFO]: [创建]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\student.ini
[2024-03-07 11:14:43][INFO]: [修改]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\student.ini
[2024-03-07 11:14:43][INFO]: 读取文件内容成功(二进制)
==============student.ini文件内容如下(二进制)==============
student.ini文件内容(二进制):
b'[DEFAULTI]\r\ncourse = \xe7\xbd\x91\xe7\xbb\x9c\xe8\xbf\x90\xe7\xbb\xb4\xe6\x8a\x80\xe6\x9c\xaf\r\nuniversity = \xe5\xb1\xb1\xe4\xb8\x9c\xe7\xa7\x91\xe6\x8a\x80\xe5\xa4\xa7\xe5\xad\xa6\r\ngrade = 3\r\n\r\n[student]\r\nname = ?\r\nclass = ?\r\nstudentid = ?\r\nsex = ?\r\n\r\n'
==============student.ini文件内容如上(二进制)==============
[2024-03-07 11:14:43][INFO]: 检测到编码为:utf-8
==============student.ini文件修改后内容如下(utf-8)==============
文件内容(utf-8):
[DEFAULTI]
course = 网络运维技术
university = 山东科技大学
grade = 3
[student]
name = ?
class = ?
studentid = ?
sex = ?
==============student.ini文件修改后内容如上(utf-8)==============
[2024-03-07 11:14:53][INFO]: [创建]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\dayi-UTF-8.txt
[2024-03-07 11:14:53][INFO]: [修改]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\dayi-UTF-8.txt
[2024-03-07 11:14:53][INFO]: 读取文件内容成功(二进制)
==============dayi-UTF-8.txt文件内容如下(二进制)==============
dayi-UTF-8.txt文件内容(二进制):
b'\xe7\xbd\x91\xe7\xbb\x9c\xe8\xbf\x90\xe7\xbb\xb4\xe6\x8a\x80\xe6\x9c\xaf'
==============dayi-UTF-8.txt文件内容如上(二进制)==============
[2024-03-07 11:14:53][INFO]: 检测到编码为:utf-8
==============dayi-UTF-8.txt文件修改后内容如下(utf-8)==============
文件内容(utf-8):
网络运维技术
==============dayi-UTF-8.txt文件修改后内容如上(utf-8)==============
[2024-03-07 11:14:53][INFO]: [创建]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\dayi-GBK.txt
[2024-03-07 11:14:53][INFO]: [修改]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\dayi-GBK.txt
[2024-03-07 11:14:53][INFO]: 读取文件内容成功(二进制)
==============dayi-GBK.txt文件内容如下(二进制)==============
dayi-GBK.txt文件内容(二进制):
b'\xcd\xf8\xc2\xe7\xd4\xcb\xce\xac\xbc\xbc\xca\xf5'
==============dayi-GBK.txt文件内容如上(二进制)==============
[2024-03-07 11:14:53][INFO]: 检测到编码为:gbk
==============dayi-GBK.txt文件修改后内容如下(gbk)==============
文件内容(gbk):
网络运维技术
==============dayi-GBK.txt文件修改后内容如上(gbk)==============
[2024-03-07 11:15:03][INFO]: [修改]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\student.ini
[2024-03-07 11:15:03][INFO]: 读取文件内容成功(二进制)
==============student.ini文件内容如下(二进制)==============
student.ini文件内容(二进制):
b'[DEFAULTI]\r\ncourse = \xe7\xbd\x91\xe7\xbb\x9c\xe8\xbf\x90\xe7\xbb\xb4\xe6\x8a\x80\xe6\x9c\xaf\r\nuniversity = \xe5\xb1\xb1\xe4\xb8\x9c\xe7\xa7\x91\xe6\x8a\x80\xe5\xa4\xa7\xe5\xad\xa6\r\ngrade = 3\r\n\r\n[student]\r\nname = dayi\r\nclass = \xe7\xbd\x91\xe7\xbb\x9c21\r\nstudentid = 2021233333333\r\nsex = Male\r\n\r\n'
==============student.ini文件内容如上(二进制)==============
[2024-03-07 11:15:03][INFO]: 检测到编码为:utf-8
==============student.ini文件修改后内容如下(utf-8)==============
文件内容(utf-8):
[DEFAULTI]
course = 网络运维技术
university = 山东科技大学
grade = 3
[student]
name = dayi
class = 网络21
studentid = 2021233333333
sex = Male
==============student.ini文件修改后内容如上(utf-8)==============
[2024-03-07 11:15:03][INFO]: [修改]【文件】: 路径:E:\dayi_\@docs_大三下\1.自动化运维\作业\作业1\dayi\student.ini
[2024-03-07 11:15:03][INFO]: 读取文件内容成功(二进制)
==============student.ini文件内容如下(二进制)==============
student.ini文件内容(二进制):
b'[DEFAULTI]\r\ncourse = \xe7\xbd\x91\xe7\xbb\x9c\xe8\xbf\x90\xe7\xbb\xb4\xe6\x8a\x80\xe6\x9c\xaf\r\nuniversity = \xe5\xb1\xb1\xe4\xb8\x9c\xe7\xa7\x91\xe6\x8a\x80\xe5\xa4\xa7\xe5\xad\xa6\r\ngrade = 3\r\n\r\n[student]\r\nname = dayi\r\nclass = \xe7\xbd\x91\xe7\xbb\x9c21\r\nstudentid = 2021233333333\r\nsex = Male\r\n\r\n'
==============student.ini文件内容如上(二进制)==============
[2024-03-07 11:15:03][INFO]: 检测到编码为:utf-8
==============student.ini文件修改后内容如下(utf-8)==============
文件内容(utf-8):
[DEFAULTI]
course = 网络运维技术
university = 山东科技大学
grade = 3
[student]
name = dayi
class = 网络21
studentid = 2021233333333
sex = Male
==============student.ini文件修改后内容如上(utf-8)==============记得安装依赖
from watchdog.observers import Observer # 导入watchdog库中的Observer类,用于监控文件系统事件
from watchdog.events import FileSystemEventHandler # 导入FileSystemEventHandler类,用于处理文件系统事件
import time
import logging
import colorlog
import os
from colorlog.escape_codes import escape_codes
import chardet
logger = logging.getLogger() # 获取logger实例
def log_init():
global logger
logger.setLevel(logging.INFO) # 设置日志级别
handler = colorlog.StreamHandler() # 创建一个StreamHandler用于输出到控制台
# -[func:%(funcName)s]
handler.setFormatter(colorlog.ColoredFormatter(
'[%(log_color)s%(asctime)s%(reset)s][%(log_color)s%(levelname)s%(reset)s]: %(log_color)s%(message)s', # 设置日志输出格式
datefmt='%Y-%m-%d %H:%M:%S', # 设置时间格式
reset=True, # 重置终端属性
log_colors={ # 设置日志级别和日期时间的颜色
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_white',
'asctime': 'blue', # 设置日期时间的颜色
},
))
logger.addHandler(handler)
def colorize_string(s, color):
return f"{escape_codes[color]}{s}{escape_codes['reset']}"
# 用chardet来检测编码
def detect_encoding(file_path):
# 先尝试GBK读取
try:
with open(file_path, 'r', encoding='gbk') as f:
f.read()
return 'gbk'
except:
with open(file_path, 'rb') as f:
result = chardet.detect(f.read())
return result['encoding']
# # UTF-8 和GBK的前几位编码不一样
# def detect_encoding(file_path):
# with open(file_path, 'rb') as f:
# first_three_bytes = f.read(3)
# if first_three_bytes == b'\xef\xbb\xbf':
# try:
# open(file_path,'r',encoding="utf-8").read()
# return 'utf-8'
# except:
# return 'gbk'
# return 'gbk'
class MyHandler(FileSystemEventHandler):
def __init__(self):
self.emit_once = True # 减少事件触发次数
def on_any_event(self, event):
# 事件类型描述
event_description = {
'modified': colorize_string("[修改]", 'red'),
'created': colorize_string("[创建]", 'green'),
'deleted': colorize_string("[删除]", 'yellow'),
'moved': colorize_string("[移动]", 'blue')
}
# 目录或文件描述
file_dir_desc = {
True: colorize_string("【目录】", 'blue'),
False: colorize_string("【文件】", 'yellow')
}
# 是否是目录
dir_or_file = file_dir_desc[event.is_directory]
logger_str = f"{event_description.get(event.event_type, '未知事件'+str(event.event_type))}{dir_or_file}: 路径:{event.src_path}"
# 记录事件信息
logger.info(logger_str)
# 对于文件的修改和创建事件,进一步处理
if event.event_type in ['modified', 'created'] and not event.is_directory:
file_name_without_path = event.src_path.split("\\")[-1] # 从路径中提取文件名
action = "被修改" if event.event_type == 'modified' else "被创建"
# logger.info(f'文件: {file_name_without_path} {action}')
# 修改事件
if event.event_type == 'modified':
# bin
try:
with open(event.src_path, 'rb') as file:
logger.info('读取文件内容成功(二进制)')
file_contents = file.read()
print(f"=============={file_name_without_path}文件内容如下(二进制)==============")
print(f"{file_name_without_path}文件内容(二进制):\n{file_contents}") # 打印文件内容
print(f"=============={file_name_without_path}文件内容如上(二进制)==============")
except Exception as e:
logger.error(f'读取文件时发生错误(二进制读取失败?!): {e}')
# UTF-8 + GBK + ANY
try:
encoding=detect_encoding(event.src_path)
logger.info("检测到编码为:"+encoding)
with open(event.src_path, 'r', encoding=encoding) as file:
file_contents = file.read()
print(f"=============={file_name_without_path}文件修改后内容如下({encoding})==============")
print(f"文件内容({encoding}):\n{file_contents}") # 打印文件内容
print(f"=============={file_name_without_path}文件修改后内容如上({encoding})==============")
#下面的代码应该不会触发,历史遗留
except Exception as e:
try:
logger.info('尝试UTF-8编码读取...')
with open(event.src_path, 'r',encoding="utf-8") as file:
logger.info('读取文件内容成功(UTF-8)')
file_contents = file.read()
print("==============新文件内容如下==============")
print(f"文件内容(UTF-8):\n{file_contents}") # 打印文件内容
print("==============新文件内容如上==============")
except Exception as e:
logger.error(f'读取文件时发生错误: {e}') # 使用日志记录异常信息
logger.info('尝试GBK编码读取...')
try:
with open(event.src_path, 'r',encoding="gbk") as file:
logger.info('读取文件内容成功(GBK)')
file_contents = file.read()
print("==============新文件内容如下==============")
print(f"文件内容:\n{file_contents}") # 打印文件内容
print("==============新文件内容如上==============")
except Exception as e:
logger.error(f'读取文件再次发生错误,未知报错: {e}')
def monitor_folder(path='.'):
event_handler = MyHandler() # 创建MyHandler实例
observer = Observer() # 创建Observer实例
observer.schedule(event_handler, path, recursive=False) # 配置Observer监控的目录和事件处理器
observer.start() # 启动Observer
try: # 等待捕获键盘中断异常
while True:
time.sleep(1) # 减少CPU占用
except KeyboardInterrupt: # 捕获键盘中断(Ctrl+C)
observer.stop() # 停止Observer
# print("[-]捕获到键盘中断,停止监控")
logger.warning("[-]捕获到键盘中断,停止监控")
observer.join() # 等待Observer线程结束
if __name__=="__main__": # 如果此脚本作为主程序运行
log_init() #初始化日志
logger.info("logger测试")
now_path = os.getcwd() # 获取当前脚本的路径
logger.info("[+]当前目录为:"+now_path)
logger.info("[+]开始监控文件夹:"+ now_path)
monitor_folder(now_path) # 调用monitor_folder函数开始监控当前脚本所在的目录import configparser
import os
def create_default_ini(filename):
config = configparser.ConfigParser()
config['DEFAULTI'] = {
'course': '网络运维技术',
'university': '山东科技大学',
'grade': '3'
}
config['student'] = {
'name': '?',
'class': '?',
'studentid': '?',
'seX': '?'
}
with open(filename, 'w',encoding="utf-8") as configfile:
config.write(configfile)
filename = "student.ini"
if not os.path.exists(filename):
print(f"文件{filename}不存在,将创建默认配置文件")
create_default_ini(filename)def main():
import os
filename = "student.ini"
if not os.path.exists(filename):
print(f"[PROG_3]文件{filename}不存在,程序退出")
return
# 解析配置文件
import configparser
config = configparser.ConfigParser()
config.read(filename,encoding="utf-8")
# 读取配置
res = config.get('DEFAULTI', 'course')
print(res)
# 保存TXT
c_name = 'dayi'
with open(c_name+"-UTF-8.txt","w+",encoding="utf-8") as file:
file.write(res)
with open(c_name+"-GBK.txt","w+",encoding="GBK") as file:
file.write(res)
if __name__ == '__main__':
main()import os
import configparser
import os
def read_modify_output():
# 文件名
filename = "student.ini"
if not os.path.exists(filename):
print(f"[PROG_4]文件{filename}不存在,程序退出")
return
config = configparser.ConfigParser()
config.read(filename,encoding="utf-8")
print('文件内容如下:')
for section in config.sections():
print(f"[{section}]")
for key in config[section]:
print(f"{key} = {config[section][key]}")
# 修改内容
config.set('student', 'name', 'dayi')
config.set('student', 'class', '网络21')
config.set('student', 'studentid', '2021233333333')
config.set('student', 'seX', 'Male')
# 保存文件
with open(filename, 'w',encoding="utf-8") as configfile:
config.write(configfile)
# 重新读取INI文件以确认修改是否成功
config.read(filename,encoding="utf-8")
# 打印修改后的值
print("==========修改后的值:===================")
print("姓名:", config.get('student', 'name'))
print("班级:", config.get('student', 'class'))
print("学号:", config.get('student', 'studentid'))
print("性别:", config.get('student', 'seX'))
if __name__ == '__main__':
read_modify_output()import os
import time
os.remove('dayi-GBK.txt')
os.remove('dayi-UTF-8.txt')
os.remove('student.ini')
time.sleep(10)
print("执行prog_2.py:")
os.system("py prog_2.py")
time.sleep(10)
print("执行prog_3.py:")
os.system("py prog_3.py")
time.sleep(10)
print("执行prog_4.py:")
os.system("py prog_4.py")
requirements.txt
chardet==5.2.0
colorama==0.4.6
colorlog==6.8.2
watchdog==4.0.0安装:
pip install -i https://mirrors.ustc.edu.cn/pypi/web/simple chardet colorama colorlog watchdoghttps://p.dabbit.net/blog/pic_bed/sharex/_pn-2024-03-07-12-08-29_Iggypops_Attentive_Circular.rar
文章版本1.1
更好的阅读地址:
某企业购买了防火墙设备,现需要进行企业网络建设,考虑到安全性,要求实现权限最小化,所有非必要端口和业务不可以对外开放。

外网区域:202.96.137.2/24 -> 202.96.137.1 -> SNAT 到租户区域外,这里的IP地址是172.16开头的


需要的拓扑图:

实际上172.172.0.0/16 也是公网IP段

内网机器:172.172.4.10/24
内网服务器: 172.172.3.100/24
不知道为什么分的号有所区别,不同的号有不同的AF版本,最后的章节里有老板AF的信息。目前看,四班的号似乎只有scsa19、scsa16 的号是新系统,剩下老板的AF比较多。

内网区域

都是三层的哦,是有IP的。

然后分配端口:

这个端口将会作为外网出口,这也就是外网区域。
eth3 -> 路由器,外网出口
这里允许Ping。

也作为服务器网关的出口IP
172.172.3.254/24服务器的网络将会从这里出来。

这里作为PC网关、内网区域的网关。
172.172.4.254/24
ping之前记得先把服务器IP和PC的IP配好。
服务器IP配置可以通过这个命令:
sudo ip addr add 172.172.3.100/24 dev eth0
sudo ifdown eth0 && sudo ifup eth0界面位置:系统->分析工具

输入下面的内容即可ping通。
ping 202.96.137.1
# CTRL+C 可以停止
# ping 服务器
ping 172.172.3.100
# ping PC
ping 172.172.4.10能通即可。
ping网关:
ping内网:
这里配置AF的出口路由,也就是路由表,可以配置到外网:静态路由(网络,然后路由)
0.0.0.0/0 via 202.96.137.1 
配置防火墙策略,允许相关区域上网。
界面位置:策略->访问控制

基本的全通,简单粗暴。允许所有区域相互访问。

服务器地址段和客户机地址段
新建地址段:

配置不同区域不同的上网策略
目的地址:any
pc、服务器 区域可以访问任意区域,但是仅可以访问PC地址、服务器地址的IP段。



也就是SNAT 源地址转换


配置NAT,转换后的数据包为出接口地址

控制台确实挺难进入的。


172.172.4.10/24





可以正常上网。

为了配置服务器的IP地址,请按照以下步骤操作:
sudo ip addr add 172.16.3.100/24 dev eth0
sudo ifdown eth0 && sudo ifup eth0确保服务器能够正常访问互联网。

PC机可以通过访问防火墙的映射端口8080,访问到内网WEB服务器的80端口服务。需要配置防火墙和进行一些测试。
也叫端口映射和虚拟服务器
202.96.137.2:8080 转换到 172.172.3.100:80以下是相关配置和说明:
配置截图:

地址组配置:
这里不需要配置地址组,服务器的单IP已新建一个地址组。
注意是目的地址转换。


配置完毕后,应能够通过公网IP的8080端口访问内网的HTTP服务,对应到80端口的服务器。
访问截图:

目前,8080端口无法打开。

这个机子的IP不像是云服务器的IP,更像是家庭宽带,不过访问的话可以在外网区域进行添加机器访问。

113.120.111.90

为保障内网终端安全,需开启以下安全策略:
添加僵尸网络策略:此策略有助于防止内网PC网段加入僵尸网络。

添加非法网站检测策略:此策略用于防止内网用户访问非法网站,避免下载病毒文件。

新建安全策略,以确保终端的安全性。
服务器IP段配置:针对服务器IP段进行安全设置。

防护策略配置:设置具体的安全策略以保护内网。




暂时禁用其他人策略:在配置期间,可以暂时禁用其他人的策略,以避免干扰。配置完成后,记得将其改回。

在AF内网PC口和外网口进行抓包操作,分析查看恶意域名访问拦截过程。
进行抓包时,动作需迅速以捕捉相关数据。


Windows终端尝试访问恶意域名,发现无法访问,显示访问已被拦截。

抓包结果显示恶意访问被成功拦截。

数据包 eth1:

数据包 eth3:

日志显示相关恶意访问已经被AF系统过滤掉。

这里已经被成功过滤啦!


为模拟SYN Flood攻击,使用服务器对PC机发起攻击。
# 打SMB端口
ab -n 50 -c 10 http://172.172.4.10:445/
#先不要回车

回车,执行命令,开始SYN Flood攻击。

过一会就好啦,过一会攻击完成,查看捕获的包。



抓包结果显示,eth2接口捕捉到大量数据包。


会发现少了一些包,被防火墙拦截了一些包。

平台显示记录了SYN Flood攻击的拦截过程。



拦截过程:

可以看出AF系统有效地识别并拦截了大规模的SYN Flood攻击,保护了内网环境不受该类型攻击的影响。
移除PC机从黑名单
首先将PC机从黑名单中移除,以确保其能正常访问网络。

添加安全策略
配置针对服务器网段的安全策略,确保WEB应用的安全性。




只开WEB防护

只记录日志

策略信息:

准备抓包
准备抓包过程,以监测网络活动。
先准备着:

使用用户名gordonb和密码abc123登录平台,执行SQL注入攻击测试。


用户名gordonb
密码abc123
输入-1 union select 1,2,3,观察反应。

输入-1 union select 1,2,3

会卡住
PHP远程执行木马测试
也会出现卡住的情况。

也会卡住

停止抓包分析
抓包结束后,分析数据包。

会发现数据包没有出现,不管是php木马的还是文件上传的。

已经被AF拦截。
未发现攻击相关的数据包,被AF拦截。
平台显示了拦截过程和相关信息。



没检测到木马,直接显示的php意外哈哈哈哈,也可以。

okay
有一些版本是老板的。
这里的配网:
内网:172.16.4.10/24 via 172.16.4.1
服务器:172.16.3.100/24 via 172.16.3.100
后来发现可能会有点小冲突(跟租户出口)

登录后这个样子:

外网:
内网:

服务器:

172.16.4.10/24




这样就差不多啦,剩下跟新版AF的大同小异,都是一些功能(感觉老板AF好用)。
(才不是服务器关了上不去了。)