faketime 是一個強大的工具,它可以讓你在測試中操控時間。這篇文章將教你如何在 Ubuntu 上安裝和使用 faketime。
Ubuntu 安裝
首先,我們需要更新我們的套件列表,然後安裝 faketime:
1
2
3
4
|
# 更新套件列表
sudo apt update
# 安裝 faketime
sudo apt install faketime
|
接著,我們需要設定一個環境變數,讓系統知道 faketime 的位置:
1
|
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
|
Mac 安裝
Warning
請注意,我沒有 Mac ,所以無法親自測試這段。如果你在使用過程中遇到問題,請參考 faketime 的官方文件或者在網路上尋找解答。
在 Mac 上,我們可以使用 Homebrew 來安裝 faketime:
1
|
brew install libfaketime
|
然後,我們需要設定兩個環境變數。這兩個環境變數會讓系統在執行程式時,強制使用我們指定的動態連結庫:
1
2
|
export DYLD_FORCE_FLAT_NAMESPACE=1
export DYLD_INSERT_LIBRARIES=/path/to/libfaketime.1.dylib
|
但我沒有 Mac ,所以無法測試這段
指令相關操作
在這部分,我們將介紹如何使用 faketime 來操控時間。
faketime 指令包起來
我們可以使用 faketime 來改變指令的執行時間。例如,我們可以將時間設定為上週五下午五點,或者設定為 2018 年 12 月 24 日的 08:15:42:
1
2
3
4
5
|
faketime 'last Friday 5 pm' date
# Fri Aug 11 17:00:00 CST 2023
faketime '2018-12-24 08:15:42' /bin/date
# Mon Dec 24 08:15:42 CST 2018
|
在這裡, date
可以替換為你想要的指令。
設定相對時間
我們也可以使用 faketime
來設定相對時間。例如,我們可以將時間設定為一小時前:
1
2
3
4
5
6
7
|
date
# Wed Aug 16 09:23:00 CST 2023
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="-1h" /bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
# Wed Aug 16 08:23:12 CST 2023
# Wed Aug 16 08:23:13 CST 2023
# Wed Aug 16 08:23:14 CST 2023
# Wed Aug 16 08:23:15 CST 2023
|
設定開始時間
我們也可以使用 faketime 來設定開始時間。例如,我們可以將時間設定為 2023 年 1 月 2 日的 03:04:05:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
date
# Wed Aug 16 09:23:00 CST 2023
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="@2023-01-02 03:04:05" /bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
# Mon Jan 2 03:04:05 CST 2023
# Mon Jan 2 03:04:05 CST 2023
# Mon Jan 2 03:04:05 CST 2023
# Mon Jan 2 03:04:05 CST 2023
# Mon Jan 2 03:04:05 CST 2023
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="@2023-01-02 03:04:05" FAKETIME_DONT_RESET=1 /bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
# Mon Jan 2 03:04:05 CST 2023
# Mon Jan 2 03:04:06 CST 2023
# Mon Jan 2 03:04:07 CST 2023
# Mon Jan 2 03:04:08 CST 2023
# Mon Jan 2 03:04:09 CST 2023
|
在這裡,時間前面加上@
,需要持續時間要加上FAKETIME_DONT_RESET=1
環境變數。格式也可以是(+|-)(0-9)+[d|h|m|s|...]
。
容器執行
如果你想在 Docker 容器中使用 faketime,你可以使用以下的 Docker 映像檔:
以下是一些使用範例:
1
|
docker run --rm -it --name some-faketime-machine -e "FAKETIME=-15d" andy23512/faketime-machine bash
|
1
|
docker run --rm -it --name some-faketime-machine -e "FAKETIME=1989-01-01 00:00:00" andy23512/faketime-machine bash
|
1
|
docker run --rm -it --name some-faketime-machine -e "FAKETIME=@'1989-01-01 00:00:00'" -e FAKETIME_DONT_RESET=1 andy23512/faketime-machine bash
|
Tip
事後想想可以手動開 VM 改 Date,把 ntpdate 關掉更新時間,這樣應該也能達到一樣效果?但 Docker 時間好像跟系統綁在一起的,所以沒辦法做更動。
相關指令
相關文章
FAKETIME_STOP_AFTER_SECONDS=3
裡面提到幾秒後會還原時間。
1
2
3
4
5
6
|
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="@2023-01-02 03:04:05" FAKETIME_DONT_RESET=1 FAKETIME_STOP_AFTER_SECONDS=3 /bin/bash -c 'while [ $SECONDS -lt 5 ]; do date; sleep 1; done'
# Mon Jan 2 03:04:05 CST 2023
# Mon Jan 2 03:04:06 CST 2023
# Mon Jan 2 03:04:07 CST 2023
# Wed Aug 16 09:55:02 CST 2023
# Wed Aug 16 09:55:03 CST 2023
|
問題是faketime使用LD_PRELOAD環境變數來指示程序的動態載入器libfaketime在啟動時載入。libfaketime將執行所謂的“插入” - 用這些例程的自己的副本替換正常的動態庫例程 - 這樣當將來進行動態庫呼叫時,libfaketime可以影響發生的事情。特別是,libfaketime插入與時間相關的呼叫,因此它能夠向程序返回假值。
這適用於大多數程序的原因是它們用於libc進行系統呼叫。libc提供與系統呼叫互動的高級函數,使系統程式設計更容易。在大多數使用 的語言中libc,二進制檔案是動態連結的,這意味著它libc實際上並不包含在二進制檔案中,而是預期libc在運行二進制檔案時系統上將存在(稱為“目標檔案”)的編譯版本,然後就可以載入動態庫了。這種動態載入是faketime通過LD_PRELOAD指令實現的,它改變了載入器的行為。
然而,Go 有兩個不同之處。首先,它是靜態連結的,因此沒有載入器可以關注LD_PRELOAD. 其次,它不使用libc,因此即使它是動態連結的,並且該LD_PRELOAD技巧有效,libc也永遠不會被呼叫,因此它實際上仍然無法實現欺騙程序使用假時間函數的預期目標。
看來 libfaketime 不是萬靈丹。
彩蛋