libfaketime,版本0.9.10(2022年3月)
本文件内容:
-
简介
-
兼容性问题
-
安装
-
使用 a) 基础知识 b) 使用绝对日期 c) 使用"开始于"日期 d) 使用偏移量表示相对日期 e) 高级功能和注意事项 f) 系统范围内模拟日期和时间 g) 使用"faketime"包装脚本 h) 基于经过时间或调用次数"限制"libfaketime i) 按进程"限制"libfaketime j) 启动外部进程 k) 将时间戳保存到文件,从文件加载时间戳 l) 用确定性数字序列替换随机数
-
许可证
-
联系方式
-
简介
libfaketime拦截程序用于获取当前日期和时间的各种系统调用。然后它向这些程序报告修改后的(伪造的)日期和时间(由你这个用户指定)。这意味着你可以修改程序看到的系统时间,而无需更改系统范围的时间。
libfaketime允许你指定绝对日期(例如2004年1月1日)和相对日期(例如10天前)。
libfaketime可用于各种目的,例如
- 确定性构建过程
- 调试与时间相关的问题,如过期的SSL证书
- 测试软件的2038年兼容性
libfaketime附带一个名为"faketime"的命令行包装器,使其更易于使用,但不会暴露libfaketime的所有功能。如果faketime命令不能满足你的用例,请确保查看此文档,看看是否可以通过直接使用libfaketime来实现。
- 兼容性问题
-
libfaketime应该可以在Linux和macOS上运行。 你的体验可能会有所不同;据报道一些其他*NIX系统也可以工作。
-
libfaketime使用操作系统链接器的库预加载机制(涉及启动程序),因此不能与静态链接的二进制文件或设置了setuid标志的二进制文件(例如,suidroot程序如"ping"或"passwd")一起工作。有关更多详细信息,请参阅系统链接器的手册页。
-
libfaketime支持pthreads环境。构建了一个单独的库(libfaketimeMT.so.1),其中包含pthread同步调用。该库还单线程调用time()拦截,因为库静态缓存了几个变量,如果在没有同步的情况下访问可能会导致问题。
但是,对某些应用程序来说,这种性能损失可能是个问题。如果是这种情况,你可以尝试通过从Makefile中删除-DPTHREAD_SINGLETHREADED_TIME并重新构建libfaketimeMT.so.1来使用未同步的time()拦截。
-
基于Java/JVM的应用程序可以工作,但你需要传入一个额外的参数(FAKETIME_DONT_FAKE_MONOTONIC)。有关详细信息,请参阅下面的使用基础知识。没有这个参数,java命令通常会挂起。
-
libfaketime最终会被那些动态加载系统库(如librt)的应用程序绕过,这些应用程序显式地自己加载系统库,而不是依赖链接器在应用程序启动时加载。除非你能修改这些应用程序,否则libfaketime将无法与它们一起工作。
这种情况在复杂的运行时环境中经常发生,例如用golang编写的程序,一些Java虚拟机实现等。由于libfaketime在这种情况下实际上被绕过了,我们对此无能为力。请考虑要求相关开发人员和供应商以支持通过LD_PRELOAD拦截选定系统调用的方式实现其运行时环境。
-
应用程序可以明确设计为防止libfaketime工作,例如,通过检查是否设置了某些环境变量或是否存在libfaketime特定的文件。
-
CLOCK_MONOTONIC测试:成功编译libfaketime库后,"make test"会执行一系列测试。在某些平台上,"CLOCK_MONOTONIC测试"显然会永远挂起。如果且仅当在你的平台上发生这种情况时,将CFLAG -DFORCE_MONOTONIC_FIX添加到src/Makefile并重新编译libfaketime。不要在测试不会挂起的平台上设置FORCE_MONOTONIC_FIX。
如果你在CLOCK_REALTIME测试中观察到挂起,请添加CFLAG -DFORCE_PTHREAD_NONVER。如果单独的FORCE_MONOTONIC_FIX不能解决MONOTONIC_CLOCK测试中的挂起,也要设置这个FORCE_PTHREAD_NONVER标志。
如果FORCE_MONOTONIC_FIX没有设置为编译时标志,你也可以设置环境变量FAKETIME_FORCE_MONOTONIC_FIX=1,如果你想在运行时启用修复,或设置为0,如果你明确想禁用它。如果libfaketime是在使用glibc作为底层libc实现的系统上编译的,并且在运行时检测到假定需要此变通方法的glibc版本,则自动启用修复。请使用GitHub问题https://github.com/wolfcw/libfaketime/issues 报告CLOCK_MONOTONIC测试期间观察到的任何挂起,并报告你的CPU架构、libc实现(例如glibc 2.30)以及可能有帮助的任何其他详细信息(例如,Linux发行版,在Docker容器内使用等)。
请尝试避免在不需要的平台上使用FORCE_MONOTONIC_FIX进行编译。虽然在大多数情况下不会有什么区别,但根据使用的特定FAKETIME设置,它会导致某些被拦截的函数(如pthread_cond_timedwait())过早或过晚返回超时,这可能会破坏某些应用程序。 首先尝试不使用FORCE_MONOTONIC_FIX编译,并检查测试是否似乎挂起。如果是,你可以将FAKETIME_FORCE_MONOTONIC_FIX环境变量设置为1,或使用设置了FORCE_MONOTONIC_FIX重新编译。
- 安装
运行"make"会编译两个库版本和一个测试程序,然后执行它。
如果测试运行良好,你应该将libfaketime库(libfaketime.so.1和libfaketimeMT.so.1)复制到你想要的位置。运行"make install"将尝试将它们放在/usr/local/lib/faketime中,并将包装shell脚本"faketime"安装在/usr/local/bin中,这两个操作很可能需要root权限。但是,从技术角度来看,没有必要进行系统范围的安装,因此你也可以在没有root权限的机器上使用libfaketime。你可能想相应地调整Makefile中的PREFIX变量。
默认情况下,Makefile为你的默认系统架构编译/链接libfaketime。如果你需要在64位平台上构建32位文件,请参阅src/Makefile中有关CFLAGS和LDFLAGS的注释。
自0.6版本以来,文件时间戳的系统调用也被拦截,这要感谢Philipp Hachtmann的贡献。这在与下面4d)节中解释的相对时间偏移结合使用时特别有用,如果程序写入和读取文件,这些文件的时间戳也应该被伪造。如果你不需要此功能,或者如果它使你想要使用FTPL的应用程序感到困惑,请定义环境变量NO_FAKE_STAT,被拦截的stat调用将不经更改地通过。
在macOS上,由于dyld的行为不同,需要以不同方式编译。使用提供的Makefile.OSX文件编译libfaketime.1.dylib。此外,不要使用LD_PRELOAD, 应该将变量DYLD_INSERT_LIBRARIES设置为libfaketime.1.dylib的路径,并应设置变量DYLD_FORCE_FLAT_NAMESPACE(设置为任何值)。macOS用户应阅读README.OSX以获取更多详细信息。
- 使用
4a) 使用基础知识
在你选择的程序上使用libfaketime包括两个步骤:
- 确保系统链接器加载libfaketime。
- 指定伪造的时间。
例如,我们希望"date"命令报告我们伪造的时间。为此,我们可以在Linux上使用以下命令行:
user@host> date Tue Nov 23 12:01:05 CEST 2016
user@host> LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-15d" date Mon Nov 8 12:01:12 CEST 2016
user@host> LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-15d" FAKETIME_DONT_FAKE_MONOTONIC=1 java -version java version "1.8.0_111" Java(TM) SE Runtime Environment (build 1.8.0_111-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
使用libfaketime运行任何命令/程序的基本方法是确保环境变量LD_PRELOAD包含libfaketime库的路径和文件名。这可以通过事先设置一次来完成:
export LD_PRELOAD=/path/to/libfaketime.so.1 (现在运行你想要的任何命令)
或者可以在命令行本身上指定:
LD_PRELOAD=/path/to/libfaketime.so.1 your_command_here
(这些例子是针对bash shell的;如何设置环境变量可能因系统而异。)
在Linux上,库搜索路径可以作为链接器配置的一部分设置。 然后LD_PRELOAD也可以使用相对路径。例如,当libfaketime.so.1 安装为/path/to/libfaketime.so.1时,你可以将/path/to添加到适当的 链接器配置文件中,例如/etc/ld.so.conf.d/local.conf,然后运行 "ldconfig"命令。之后,使用LD_PRELOAD=libfaketime.so.1就足够了。
然而,还应该指定伪造的时间;否则,libfaketime将被加载,但只报告真实的系统时间。有多种方法可以指定伪造的时间:
a) 通过设置环境变量FAKETIME。 b) 通过使用环境变量FAKETIME_TIMESTAMP_FILE中给出的文件。 c) 通过使用主目录中的.faketimerc文件。 d) 通过使用/etc/faketimerc文件作为系统范围的默认值。 e) 通过使用FAKETIME_UPDATE_TIMESTAMP_FILE和date -s "
如果你想使用b) c)或d),$HOME/.faketimerc或/etc/faketimerc只包含 一行文本,内容与FAKETIME环境变量完全相同,下面将对其进行描述。请注意,只有在没有$HOME/.faketimerc且不存在FAKETIME_TIMESTAMP_FILE文件时,才会使用/etc/faketimerc。 此外,FAKETIME环境变量始终优先于文件。 有关FAKETIME_UPDATE_TIMESTAMP_FILE,请参见下文。
4b) 使用绝对日期
对于绝对日期,必须使用的格式是"YYYY-MM-DD hh:mm:ss"。 例如,2020年12月24日晚上8:30必须指定为 FAKETIME="2020-12-24 20:30:00"。
4c) 使用"开始于"日期
(感谢David North, TDI在0.7版本中的重要贡献)
对于开始于日期,必须使用的格式是"@YYYY-MM-DD hh:mm:ss"。 例如,2020年12月24日晚上8:30必须指定为 FAKETIME="@2020-12-24 20:30:00"。
4b)中描述的绝对日期模拟在指定的绝对时间停止的系统时钟。"开始于"格式允许如下4d)节所述的"相对"时钟操作,但使用"开始于"时间而不是偏移时间。
如果启动的进程本身启动其他(子)进程,默认情况下它们将再次从指定的开始日期开始。如果这不是你需要的,请设置环境变量FAKETIME_DONT_RESET=1。尝试以下示例以查看差异:
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="@2000-01-01 11:12:13"
FAKETIME_DONT_RESET=1
/bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
LD_PRELOAD=src/libfaketime.so.1 FAKETIME="@2000-01-01 11:12:13"
/bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
在第二个示例中,"date"命令将始终打印相同的时间,而在第一个示例中
一些简单的例子:
LD_PRELOAD=./libfaketime.so.1 FAKETIME_FMT=%s FAKETIME="date +%s -d'1 year ago'
" date
LD_PRELOAD=./libfaketime.so.1 FAKETIME_FMT=%s FAKETIME="stat -c %Y somefile
" date
LD_PRELOAD=./libfaketime.so.1 FAKETIME_FMT=%c FAKETIME="date
" date
4e) 高级功能和注意事项
高级时间指定选项:
从0.8版本开始,得益于Karl Chen的贡献,可以在时间偏移量的指定中使用分数。例如,
FAKETIME="+1,5h"
等同于FAKETIME="+90m"。请注意,分数分隔符取决于你的区域设置,所以实际上你可能需要使用
FAKETIME="+1.5h"
你应该找出正确的分隔符,例如,通过在像/bin/date这样的命令上使用libfaketime,你可以立即验证它是否按预期工作。
同样由Karl Chen在v0.8中贡献的是加快或减慢使用libfaketime执行的程序的挂钟时间的选项。例如,
FAKETIME="+1y x2"
将把伪造的时间设置为一年后,并使时钟运行速度加快一倍。类似地,
FAKETIME="+1y x0,5"
将使时钟运行速度减半。如上所述,分数分隔符取决于你的区域设置。此外,
FAKETIME="+1y i2,0"
将使时钟在每次time()等调用时步进2秒,完全独立于系统时钟。它有助于使程序具有一定的确定性。在这种特殊情况下,所有衍生进程将使用相同的全局时钟,而不会在每个进程开始时重新启动它。
请注意,在FAKETIME中使用"x"或"i"仍然需要给出一个偏移量(参见4d节)。这意味着"+1y x2"将起作用,但单独的"x2"不会。如果你不想伪造时间,而只是修改时钟速度,请使用类似"+0 x2"的方式,即在你的FAKETIME中使用显式的零偏移作为前缀。
为了测试,你应该运行一个类似这样的命令
LD_PRELOAD=./libfaketime.so.1 FAKETIME="+1,5y x10,0"
/bin/bash -c 'while true; do echo $SECONDS ; sleep 1 ; done'
对于无限循环睡眠的每一秒,执行的bash shell会认为已经过去了10秒($SECONDS是一个bash内部变量,用于测量shell启动以来的时间)。
(请注意,将"echo $SECONDS"替换为例如"/bin/date"的调用不会得到预期的结果,因为/bin/date将总是作为一个新进程启动,对于这个新进程libfaketime也会重新初始化。它将显示正确的偏移量(1.5年后),但不会显示加速或减速。)
对于每次运行时应使用不同日期和时间的应用程序,请考虑使用包含的timeprivacy包装器shell脚本(由adrelanos at riseup dot net贡献)。
注意事项:
只要可能,你应该使用相对偏移量或"从何时开始"日期,而不要使用绝对日期。
为什么?因为你设置的绝对日期/时间是固定的,即如果一个程序检索当前时间,并在5分钟后再次检索当前时间,它仍然会得到相同的结果两次。这可能会破坏测量时间流逝的程序(例如,每隔X分钟检查新邮件的邮件程序)。
使用相对偏移量或"从何时开始"日期解决了这个问题。libfaketime将始终根据真实当前时间和你指定的偏移量报告伪造的时间。
还请注意,为了提高库的性能,你的默认伪造时间规范会被缓存10秒。因此,如果你在程序运行时更改$HOME/.faketimerc或/etc/faketimerc的内容,可能需要最多10秒才能应用新的伪造时间。如果这在你的场景中是一个问题,你可以使用环境变量FAKETIME_CACHE_DURATION更改再次读取文件之前的秒数,或者使用FAKETIME_NO_CACHE=1完全禁用缓存。请记住,禁用缓存可能会对性能产生负面影响(特别是当不使用FAKETIME环境变量而使用配置文件时,例如FAKETIME_TIMESTAMP_FILE)。
通过文件时间戳设置FAKETIME
基于Hitoshi Harada (umitanuki)的建议,"从何时开始"时间现在可以通过文件系统中的任何文件来设置,方法是将FAKETIME环境变量设置为"%"(百分号),并将FAKETIME_FOLLOW_FILE设置为要用作"从何时开始"时间源的文件的修改时间戳。
使用示例:
创建任何文件,时间戳为2009年12月24日12:34:56
touch -t 0912241234.56 /tmp/my-demo-file.tmp
运行一个bash shell,其中包含一个无限循环,打印当前时间
LD_PRELOAD=/path/to/libfaketime.so.1
FAKETIME='%' FAKETIME_FOLLOW_FILE=/tmp/my-demo-file.tmp
FAKETIME_DONT_RESET=1
bash -c 'while true ; do date ; sleep 1 ; done'
现在,在上面的程序运行时,更改文件的时间戳
(在不同的终端窗口或其他地方)
touch -t 2002290123.45 /tmp/my-demo-file.tmp
在运行时更改'x'修饰符
使用FAKETIME_TIMESTAMP_FILE可以在程序运行时轻松更改FAKETIME设置:
echo "+0 x1" > /tmp/my-faketime.rc
LD_PRELOAD=libfaketime.so.1 FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc"
FAKETIME_NO_CACHE=1 ./some-program &
sleep 10 ; echo "+0 x10" > /tmp/my-faketime.rc
在运行时更改挂钟时间的速度,即使用不同的'x'修饰符,默认情况下可能会导致更大的跳跃,这可能会使程序感到困惑。例如,如果程序在'x1'上运行了10秒,然后设置更改为'x10',伪造的时间对程序来说就好像它已经运行了超过100秒,而不是刚刚超过10秒。
通过将环境变量FAKETIME_XRESET设置为任何值,不同'x'修饰符值之间的过渡将显著平滑:
LD_PRELOAD=libfaketime.so.1 FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc"
FAKETIME_NO_CACHE=1 FAKETIME_XRESET=1 ./some-program &
设置FAKETIME_XRESET确保挂钟时间只在'x'修饰符被更改后才开始运行得更快(当增加它时),并且还确保报告的伪造时间不会跳回到过去的值(当减少它时)。
请注意,FAKETIME_XRESET在内部通过重置libfaketime的内部时间保持数据结构来工作,这可能对报告的文件时间戳产生副作用。目前使用FAKETIME_XRESET应被视为实验性的。
清理共享内存
libfaketime在支持的平台上使用信号量和共享内存,以便在父子进程之间同步faketime设置。
请注意,这不会共享由settimeofday设置的时间(关于这一点,请参见下面的FAKETIME_UPDATE_TIMESTAMP_FILE)。
libfaketime在正常退出时会进行清理。 然而,当进程被终止时(例如,通过命令行上的Ctrl-C), 共享内存无法正确清理。在这种情况下,你应该偶尔手动删除
/dev/shm/faketime_shm_* 和 /dev/shm/sem.faketime_sem_*
(或适当自动化)。那里来自已经终止的进程的遗留文件通常不是问题,但在下次启动一个进程时,如果该进程ID存在这样一个过时的信号量/共享内存,就会导致libfaketime错误。因此,如果你遇到以下错误消息
libfaketime: In ft_shm_create(), shm_open failed: File exists
请按上述方式清理/dev/shm。这对于长时间运行的系统(高正常运行时间的服务器)和启动大量进程的系统(例如,处理许多容器或类似虚拟化机制的服务器)尤其重要。
通过设置FAKETIME_DISABLE_SHM环境变量,或等效地,向faketime传递--disable-shm,可以禁用共享内存的使用。
拦截时间设置调用
libfaketime可以使用CFLAG "-DFAKE_SETTIME"编译,以便 也拦截时间设置函数,即clock_settime(), settimeofday()和adjtime()。FAKETIME环境 变量将在每次调用时进行调整。
当环境变量FAKETIME_TIMESTAMP_FILE被设置,指向一个 可写(可创建)的自定义配置文件,并且环境变量 FAKETIME_UPDATE_TIMESTAMP_FILE为"1"时,该文件也会在每次 调用时更新。通过这种方式,可以在几个 进程之间共享一个共同的"虚拟时间",每个进程都可以为所有进程调整时间。
在独立进程之间共享"可设置的虚拟时间"
当libfaketime使用FAKETIME_COMPILE_CFLAGS="-DFAKE_SETTIME"编译时, 它可以被配置为支持多个进程的共同时间偏移。 这例如允许普通用户使用"ntpdate"而不影响 系统时钟,交互式测试使用不同日期的软件或测试 内部使用settime的复杂软件的多个独立进程。
示例:
$ export LD_PRELOAD=libfaketime.so.1 $ export FAKETIME_TIMESTAMP_FILE="/tmp/my-faketime.rc" $ export FAKETIME_UPDATE_TIMESTAMP_FILE=1 $ export FAKETIME_CACHE_DURATION=1 # 以秒为单位
或: export FAKETIME_NO_CACHE=1
$ date -s "1999-12-24 16:00:00" Fri Dec 24 16:00:00 CET 1999 $ LD_PRELOAD="" date Thu Apr 9 15:19:38 CEST 2020 $ date Fri Dec 24 16:00:02 CET 1999 $ /usr/sbin/ntpdate -u clock.isc.org 9 Apr 15:18:37 ntpdate[718]: step time server xx offset 640390517.057257 sec $ date Thu Apr 9 15:18:40 CEST 2020
在另一个终端、脚本或环境中,可以设置相同的变量, 并会打印相同的时间。 这也避免了直接更新rc配置文件以使用 不同时间的需要,但当然只支持时间偏移。
请注意,此功能与其他几个功能不兼容, 如FAKETIME_FOLLOW_FILE、FAKETIME_XRESET等。在第一次 settime之后,FAKETIME_TIMESTAMP_FILE中将使用偏移量,即使它 最初使用了高级时间规范选项。
4f) 在系统范围内伪造日期和时间
SourceForge公司的David Burley报告了一个有趣的系统范围应用libfaketime的用例:目前,在OpenVZ主机内运行的所有虚拟机都有相同的系统日期和时间。为了使用具有不同系统日期的多个沙箱,可以将libfaketime库放入/etc/ld.so.preload;然后它将自动应用于所有命令和程序。这当然最好与系统范围的/etc/faketimerc文件一起使用。感谢SourceForge公司提供这个补丁!
注意事项:如果你运行虚拟机,当你重新启动时,其实时时钟可能会重置为真实世界的日期和时间。根据你的FAKETIME设置,这可能会导致副作用,例如每次重新启动时强制进行文件系统检查。系统范围的伪造时间也可能导致软件自动更新工具出现意外的副作用,如果真实世界时间和伪造系统时间之间的偏移太大。如有疑问,请将系统的日期设置为伪造时间,并尝试是否一切仍按预期工作,然后再系统范围地应用libfaketime。
4g) 使用"faketime"包装器
从0.8版本开始,libfaketime提供了一个名为"faketime"的命令,通过"make install"放置在/usr/bin中。它省去了手动设置LD_PRELOAD和FAKETIME环境变量的麻烦,但只暴露了libfaketime功能的一个子集。另一方面,它使用/bin/date的日期解释函数,以提供更高的灵 这种方法不如在运行时更改FAKETIME环境变量灵活,但可能更易使用,适用于每个程序(而不是每个用户或整个系统)范围,并且只有很小的性能开销。
使用另一对环境变量,你可以限制libfaketime的活动时间,不是基于挂钟秒数,而是基于启动程序执行的与时间相关的函数调用次数。这种替代方法可能只适合于了解程序代码以确定有用的启动/停止值的程序员,或想进行模糊测试的程序员。
这两对环境变量可以组合使用,以进一步限制libfaketime的活动,尽管这只在很少的场景中有用。
通常不建议以这种方式限制libfaketime的活动。许多程序在时间突然变化时会崩溃,特别是如果它们使用当前(真实)时间启动,然后在例如5分钟后被送回过去。例如,它们可能看起来冻结或卡住,因为它们在等待某个特定时间点,但由于libfaketime活动延迟,永远无法到达该时间点。除非你确定真的需要并且知道自己在做什么,否则避免使用此功能。
4i) 对每个进程"限制"libfaketime
可以指示faketime只对选定的命令伪造时间相关调用,或者对每个命令伪造时间,但排除某些命令子集。
相应的环境变量是FAKETIME_ONLY_CMDS和FAKETIME_SKIP_CMDS。
示例: FAKETIME_ONLY_CMDS=javadoc faketime '2008-12-24 08:15:42' make 将运行"make"命令,但时间伪造只会应用于javadoc进程。
多个命令用逗号分隔。
示例: FAKETIME_SKIP_CMDS="javadoc,ctags" faketime '2008-12-24 08:15:42' make 将运行"make"命令,并对"make"所做的一切应用时间伪造,但javadoc和ctags进程除外。
FAKETIME_ONLY_CMDS和FAKETIME_SKIP_CMDS是互斥的,即你不能同时设置它们。如果同时设置了这两个环境变量,faketime将终止并显示错误消息。
4j) 生成外部进程
从0.9版本开始,libfaketime可以在a)任意秒数过去后或b)程序自启动以来进行了一定数量的与时间相关的系统调用后执行一个shell命令。这有两个需要注意的限制:
-
生成外部进程发生在原始程序的与时间相关的系统调用期间。如果你希望外部进程在程序启动5秒后启动,但该程序在运行时第8秒之前没有进行任何与时间相关的系统调用,那么外部进程的启动将延迟到运行时第8秒。
-
原始程序会被阻塞直到外部进程完成,因为拦截的与时间相关的系统调用不会更早返回。如果你需要启动一个长时间运行的外部进程,请确保它分叉到后台。
生成外部进程由三个环境变量控制: FAKETIME_SPAWN_TARGET, FAKETIME_SPAWN_SECONDS, FAKETIME_SPAWN_NUMCALLS。
示例(在Linux上使用bash):
(... 这里是通常的libfaketime设置,设置LD_PRELOAD和FAKETIME ...) export FAKETIME_SPAWN_TARGET="/bin/echo 'Hello world'" export FAKETIME_SPAWN_SECONDS=5 /opt/local/bin/myprogram
这将在"myprogram"运行5秒后执行的第一个与时间相关的系统函数调用期间运行给定参数的"echo"命令。
4k) 将时间戳保存到文件,从文件加载时间戳
要使用同一个文件存储和加载时间戳_偏移量_,以便在独立进程之间共享共同的"虚拟时间",请参阅上面的FAKETIME_UPDATE_TIMESTAMP_FILE。FAKETIME_SAVE_FILE功能是不同的。
faketime可以将伪造的时间戳保存到由FAKETIME_SAVE_FILE环境变量指定的文件中。它还可以使用由FAKETIME_LOAD_FILE指定的文件从中重放时间戳。在消耗完整个文件后,libfaketime会回到使用FAKETIME变量中设置的规则,但时间戳进程将从文件中的最后一个时间戳开始计数。
该文件以saved_timestamp结构流的形式存储每个时间戳,没有任何元数据或填充:
/* 写入文件的时间戳的存储格式。大端字节序。 */ struct saved_timestamp { int64_t sec; uint64_t nsec; };
faketime需要使用faketime包装器运行才能使用这些文件。这个功能是由Balint Reczey在v0.9.5中添加的。
4l) 用确定性数字序列替换随机数
libfaketime可以使用CFLAG FAKE_RANDOM编译(参见src/Makefile)。
当这样编译时,libfaketime还会拦截对getrandom()函数的调用,该函数目前是特定于Linux的。
这个功能旨在向使用getrandom()的应用程序提供一个确定性的、可重复的数字序列,而不是/dev/[u]random提供的随机数。
为了创建确定性数字序列,libfaketime内部使用Bernard Widynski的中平方Weyl序列随机数生成器, 参见https://mswsrng.wixsite.com/rand。
它需要一个64位种子值,必须通过环境变量FAKERANDOM_SEED传递,例如:
LD_PRELOAD=src/libfaketime.so.1
FAKERANDOM_SEED="0x12345678DEADBEEF"
test/getrandom_test
只要使用相同的种子值,就会生成相同的"看似随机"的数字序列。
请注意,这肯定会破坏可能归因于getrandom()提供的随机数的任何安全属性,例如在密码操作的上下文中。仅将其用于确定性测试目的。切勿在生产环境中使用。
关于为什么这个显然与日期/时间无关的函数被添加到libfaketime以及它可能如何演变的讨论,请参见Github问题#275。
- 许可证
libfaketime已根据GNU通用公共许可证(GPL)发布。 请参阅包含的COPYING文件。
- 联系方式
非常欢迎错误报告、功能建议、成功报告以及补丁/拉取请求:
https://github.com/wolfcw/libfaketime