fail2ban 时间模块 MyTime 全解析:可注入时钟、时间表达式解析与格式化
网络安全运维【免费下载链接】fail2banDaemon to ban hosts that cause multiple authentication errors项目地址https://gitcode.com/gh_mirrors/fa/fail2ban点击查看免费下载导读MyTime是 fail2ban 守护进程内部统一的时钟封装它包一层time.time()/time.gmtime()/datetime.now()让测试可以注入固定时间同时提供了str2seconds把1h 30m这类表达式换算成秒与seconds2str把秒数格式化成人类可读时长两套时间解析工具。本文以 doc/fail2ban.server.mytime.rst 所指向的 fail2ban/server/mytime.py 为主体结合仓库中 filter、observer、database 等模块的调用点与 fail2ban/tests/misctestcase.py 的测试用例讲清楚该模块的 API、实现原理与实战用法。说明doc/fail2ban.server.mytime.rst是 Sphinx 的 automodule 占位文档通过:members:指令把mytime.py中的类与静态方法自动生成 API 文档。因此本文的技术主体即MyTime类的完整实现文档与源码一一对应。MyTime 是什么为测试而生的时钟封装MyTime是 fail2ban/server/mytime.py 中定义的静态类类注释明确说明了设计动机A wrapper around time.time() and time.gmtime(). When performing unit test, it is very useful to get a fixed value from these functions. Thus, time.time() and time.gmtime() should never be called directly.也就是说fail2ban 的核心代码约定不直接调用time.time()、time.gmtime()而是统一走MyTime。这样在单元测试里可以注入固定时间点让间隔findtime秒内的多次失败这类时间敏感逻辑变得完全确定、可复现。类级状态只有三个静态变量mytime.py#L43-L45变量含义myTime注入的固定 Unix 时间戳秒为None时返回真实系统时间alternateNowTime与myTime配套的替代时间戳用于datetime.now()路径alternateNow由alternateNowTime预先算好的datetime对象核心 API注入与读取当前时间注入时钟setTime与setAlternateNowsetTime(t)设置固定时间戳。传None则恢复为始终读取真实系统时间mytime.py#L60-L69。setAlternateNow(t)除了记录alternateNowTime还会预先执行datetime.datetime.fromtimestamp(t)生成alternateNow供now()直接返回mytime.py#L47-L58。读取时间的四个装饰方法方法等价于注入时行为time()time.time()返回MyTime.myTimemytime.py#L71-L81gmtime()time.gmtime()返回time.gmtime(MyTime.myTime)mytime.py#L83-L92now()datetime.datetime.now()myTime与alternateNowTime相等时直接返回alternateNow否则datetime.fromtimestamp(myTime)mytime.py#L94-L104localtime(xNone)time.localtime(x)仅在x is None且已注入时返回time.localtime(myTime)mytime.py#L106-L115这些方法在代码库中大量被调用例如 fail2ban/server/filter.py 用MyTime.time()记录日志行时间戳fail2ban/server/observer.py 用MyTime.time()判断解封事件是否到期。时间戳格式化time2strtime2str(unixTime, format%Y-%m-%d %H:%M:%S)把 Unix 时间戳格式化为日期时间字符串默认输出 ISO 风格YYYY-MM-DD HH:MM:SS不带微秒见 mytime.py#L117-L128。实现细节正常时间datetime.fromtimestamp(unixTime).replace(microsecond0)后按format输出边界保护当unixTime 253402214400即超出 9999 年末尾时直接返回9999-12-31 23:59:59避免跨时区溢出导致strftime抛异常。调用示例fail2ban/server/filter.py#L732 记录[%s] Found %s - %s时把命中时间MyTime.time2str(unixTime)写入日志fail2ban/server/observer.py#L403 展示time2str(unixTime)的输出fail2ban/server/database.py也在读写数据库时间字段时大量使用。时间表达式解析str2seconds这是配置层最常用的 API把人类可读的时长表达式换算成秒数。定义见 mytime.py#L149-L176解析分四步数字直通如果传入的是int/float/complex原样返回补齐空格用正则(?i)(?[a-z])(\d)在字母后紧跟数字处插入空格例如1d12h变成1d 12h单位替换按预编译的单位正则把days/weeks/months/years/seconds/minutes/hours及其缩写替换成*秒数表达式补加号并求值用(\d)\s(\d)把相邻的数字组之间补最后eval求值。支持的时间单位与换算单位支持写法不区分大小写换算秒数秒seconds/sec/s/ss*1分钟minutes/min/m/mm*60小时hours/hour/h/hh*3600天days/da/d/dd*86400周weeks/wee/w/ww*604800月months/mon/mo*((365*3366)*86400/4/12)≈30.4375天年years/yea/y/yy*((365*3366)*86400/4)≈365.25天值得注意的语义月不是 30 天注释与 docstring 明确警告——1 个月按一年秒数 ÷ 12计算4 年3 平年 1 闰年平均下来约30.4375天1 年约365.25天mytime.py#L160-L164大小写不敏感、缩写可重叠由于m/mm被分钟占用月的短缩写是mo或mon表达式是数学求值支持 - * /、括号与小数例如2 * 0.5 yea 1*1 mon - 3*1/3 wee 2/2 day空格即加法0d 1h 30m等价于0d 1h 30m。官方示例str2seconds(1hour30min) # 5400 str2seconds(0d 1h 30m) # 5400 str2seconds(1year-6mo) # 15778800 str2seconds(6 months) # 15778800在 fail2ban/tests/misctestcase.py#L445-L459 的MyTimeTest.testStr2Seconds中对多种书写风格做了回归断言包括1y6mo30w15d12h35m25s 66821725、1ye -2mo -3we -4da -5ho -6mi -7se 24119633等。配置中的实际落地str2seconds是 jail 配置参数findtime的解析入口fail2ban/server/filter.py#L283-L288 的setFindTime直接调用MyTime.str2seconds(value)因此配置里既能写findtime 600也能写findtime 10m或findtime 1h 30m。fail2ban/server/action.py中对bantime等参数同样经由该函数归一化为秒。反向格式化seconds2strseconds2str是str2seconds的逆操作负责在展示场景如日志、fail2ban-client status输出把秒数变成紧凑可读的时长字符串。它是MyTime的嵌套类实现__str__/__repr__见 mytime.py#L178-L235。自动精度随量级递减 315360001 年按天取整输出y / w / d 6048001 周按小时取整输出w / d / h 864001 天按分钟取整输出d / h / m 3595接近 1 小时按 10 秒取整输出h / m更小值按 1 秒精度输出m / s0秒输出0。官方示例与测试断言一致seconds2str(86400*390) # 1y 3w 4d seconds2str(86400*368) # 1y 3d seconds2str(86400*365.5) # 1y seconds2str(86400*23600*760*15) # 2d 7h 15m seconds2str(86400*23599) # 2d 1h seconds2str(3600-5) # 1h seconds2str(3600-10) # 59m 50s seconds2str(59) # 59s对应测试位于 fail2ban/tests/misctestcase.py#L461-L475 的testSec2Str。实际调用点包括 fail2ban/server/observer.py#L459-L488日志中展示封禁时长与 fail2ban/server/filter.py#L693日志时间偏移提示。MyTime 在 fail2ban 各模块中的角色从源码调用统计看MyTime贯穿 fail2ban 几乎所有时间相关逻辑fail2ban/server/filter.py23 处调用。日志解析时用MyTime.time()作为当前时间基准setFindTime/setMaxRetry相关配置经str2seconds归一化日志输出用time2strfail2ban/server/observer.py12 处调用。维护starttime/endtime事件队列用MyTime.time()判断何时该触发解封、何时重启进程fail2ban/server/strptime.py5 处调用。日期模板匹配以MyTime.now()/MyTime.alternateNow为当前时间锚点推导年份与世纪fail2ban/server/database.py7 处调用。封禁记录的时间戳读写统一走MyTimefail2ban/server/banmanager.py、fail2ban/server/actions.py、fail2ban/server/jail.py分别负责封禁到期判定、动作执行时间点与 jail 生命周期中的时间计算客户端fail2ban/client/fail2bancmdline.py、fail2ban/client/fail2banregex.py 也引用MyTime用于命令行的正则校验与时间格式化。测试中的固定时钟技巧在 fail2ban/tests/filtertestcase.py 中可以看到MyTime的典型测试用法MyTime.setTime(1572137999) # 固定到某一秒 # ... 注入日志行、推进时间 ... MyTime.setTime(1572138001) # 再前进 2 秒验证 findtime 窗口fail2ban/tests/servertestcase.py、fail2ban/tests/databasetestcase.py、fail2ban/tests/observertestcase.py同样依赖setTime模拟时间流逝从而在不真实等待的情况下验证多久之后解封多长时间窗口内累计多少次失败触发封禁等时序逻辑。使用注意与边界调用约定业务代码不要直接调time.time()/time.gmtime()/datetime.now()否则测试注入会失效——这是MyTime存在的根本原因月份语义1month在str2seconds中等于30.4375天1year等于365.25天考虑闰年不是整数天数eval的输入约束str2seconds最终对替换后的表达式做eval因此它只应被用来处理受信任的配置值jail 配置中写死的内容不应把用户可控输入直接传给它精度取舍seconds2str的量级越大精度越低年级别按天、周级别按小时这是为了在日志中保持紧凑可读是刻意设计而非缺陷9999 年保护time2str对超界时间戳做了兜底避免strftime在极端时区下溢出。小结MyTime以不到 240 行的实现为 fail2ban 提供了三样关键能力可注入的时钟可测试性、宽松的人类可读时长解析配置体验与自适应精度的时长格式化日志可读性。理解这个模块有助于读懂 fail2ban 中findtime、bantime等配置的取值语法也能为阅读 filter、observer、database 等核心模块的时间逻辑打下基础。如需深入可继续阅读 doc/fail2ban.server.mytime.rst 对应的 API 文档、fail2ban/server/strptime.py 的时间戳模板实现以及 fail2ban/tests/misctestcase.py 中的完整测试。赞分享网络安全运维【免费下载链接】fail2banDaemon to ban hosts that cause multiple authentication errors项目地址https://gitcode.com/gh_mirrors/fa/fail2ban点击查看免费下载相关推荐根治DICOM转NIfTI时间错乱dcm2niix时间格式化全解析根治DICOM转NIfTI时间错乱dcm2niix时间格式化全解析 引言被时间戳折磨的影像科医师 你是否遇到过这样的困境DICOM文件转换为NIfTI格式CRON表达式与时间区间计算getNextRunDate和getPreviousRunDate深度解析CRON表达式与时间区间计算getNextRunDate和getPreviousRunDate深度解析 想要掌握PHP中的任务调度和定时执行吗CRON表达式任务调度后端OpenMed 时间归一化完全指南TIMEX3 风格临床时间表达解析与事件锚定OpenMed 时间归一化完全指南TIMEX3 风格临床时间表达解析与事件锚定 本文聚焦 OpenMed本地优先的医疗 AI 去标识化与临床 NLP 套件人工智能NLP医疗健康数据脱敏本地部署大模型AI 应用MCP 服务联邦学习上一篇MindIE/FramePack环境搭建全攻略CANN、MindIE、Torch_npu安装指南下一篇G-Helper 为 AMD Ryzen 笔记本降压 15℃不降频调校实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考