ntpd
新型肺炎が猛威を奮っている。厚生労働省の水際作戦も失敗に終わり、隔離船で増殖とか、一体どうなってるの状態。
屋形船での新年会で菌を貰った人、さぞかし一期一会を実感している事でしょう。 でも、よくここまで突き止めたな。きっと裏で、警視庁の刑事が大量に投入されて、聞き込みに 回っていたに違いない。彼らは、こういうの得意中の得意ですから。
でもね、人海戦術もいいけど、もっと科学的に出来ないかねぇと思うこの頃。 んな訳で、シュミレーションとか無いの? 毎度こういうのはAIにお任せもあれなんでね。 探してみたら
こんなのが出て来た。そうかmatlabを使えば簡単なんだな。(世の中では凄くpython菌が増殖してて、バンデミックになってますが、そういうのにはオイラーは感染しないからね)
貧者のmatlabが有ったな。 えーと、 maxima じゃなくて octave だな。 試してみるか。
こちらは、有名なローレンツ アトラクタ
#lorentz.m function dx = lorentz(x,t) s=10; R=28; b=8/3; dx(1) = -s * ( x(1) - x(2) ); dx(2) = R * x(1) - x(2) -x(1) * x(3); dx(3) = x(1) * x(2) - b * x(3); endfunction t=linspace(0, 30, 3000); x=lsode("lorentz",[0; 0.03; 0],t); plot3( x(:,1), x(:,2), x(:,3));
2070年問題
前回はOpenBSDの起動時に参照されるRTCチップからデータを呼び出し、epocに変換する所を見た。チップは西暦年の下2桁しか保持してない。そこで、その数値が70以下なら2000年代。それを超えていたら1900年代として区別してた。同様なロジックはdateコマンドでも使われていた。
これって2070年問題じゃん。折角epocを64Bitにしたって、こういう問題に足を引っ張られていては、元の木阿弥である。
まてまて、2070年まで、そんな旧態依然のチップが使われたパソコンが残って(しかも現役で)使われているだろうか?
今流行りのスマホでは、そんな問題をさっぱり聞いた事ないぞ。それもそのはず、時間情報は電波に載って届くから、スマホ内にそんなチップは収納されていないんだ。
パソコンでそれをやろうとすると、ドコモ支給のパソコンとかAUと契約してとか、ややこしい話になる。んで、そんな面倒を避ける為、ntpが利用されている。これからは必須の技術なんで、是非この機会に習得しておこう。来る2070問題を避けるためにもね。(ジョークなんで真に受けないように!)
ntpctlとntpd.conf
ntpdを十分に動かして、エージングが完了すると、下記のような状態になる。
ob$ ntpctl -s all 5/5 peers valid, constraint offset -2s, clock synced, stratum 2 peer wt tl st next poll offset delay jitter 162.159.200.123 time.cloudflare.com 1 10 3 1018s 1555s -2.145ms 27.188ms 1.125ms 162.159.200.1 from pool pool.ntp.org 1 10 3 1118s 1611s -1.134ms 27.788ms 3.358ms 103.202.217.106 from pool pool.ntp.org 1 10 2 1000s 1568s 2.807ms 41.823ms 3.876ms 133.243.238.163 from pool pool.ntp.org * 1 10 1 1022s 1592s 2.638ms 19.568ms 2.089ms 195.50.171.101 from pool pool.ntp.org 1 10 2 897s 1500s 5.596ms 274.167ms 26.054ms
安定しているので、poll間隔も当初の30秒から大幅に伸びている。贅沢な事に1次標準に同期して、このマシンの時間精度は2次標準と見做せるよと、お墨付きを頂いた。目出度い事である。
/etc/ntpd.conf
servers pool.ntp.org server time.cloudflare.com sensor * constraints from "https://www.google.com"
これがデフォルトの設定。時間の元を貰ってくるのは、pool.ntp.orgとtime.cloudflare.comからである。どれかが死んでいても大丈夫と言う、安全対策、冗長系になっている。
sensorってのが有るけど、これは手元に、正確な時刻発生装置が有る場合に使える。その手の設備と言うかデバイスで代表的なものは、GPSである。GPSってカーナビとか、今ではスマホにも付いているやつの心臓部だ。正確な時計。時間を距離に換算する仕組みなんで、複数の人工衛星から届く時間を元に位置を決定するのがカーナビの原理。
民間で手に入る、もっとも正確な時計だろう。雑に言うと高精度の電波時計ね。素人が使う(うちにも有るような)電波時計は、
日本では「JJY」と呼ばれる標準電波の送信局があり、福島県大鷹鳥谷山のおおたかどや山 標準電波送信所(送信周波数40kHz)と、福岡県と佐賀県との県境に位置する羽金山の はがね山標準電波送信所(送信周波数60kHz)の2つの送信所からの電波を受信する
こちらの方ね。
GPS受信型NTPサーバ とか GPSタイムサーバー TSV-400GP こんな製品が有るようだ。 あっ、GPS装置はサツも使うし浮気調査にも使われる。そのためのレンタル品まで用意されてた。恐い世の中ですよ。
恐いと言えば、偽のntpサーバーを設置されて、それを利用させられてしまうと、アリバイ工作に加担させられてしまう。ntpプロトコルでは、それを防止するすべが無いので、constraintsってのが導入されている。
上の設定では、制約にググルのサーバーが指定されている。ここからの時間情報から大幅にずれていたら、良からぬ事(偽物時刻をつかまされている)が起こっているよってんで、時間同期を拒否するようになっている(そうだ)。
constraints
上でググルにアクセスして、時刻を得ているって説明が有ったけど、そんな事出来るの? ググルにアクセスすると、普段見慣れた入力画面しか出てこないんだけど。
まてまて、そんな素人みたいな事を言うな。この世界に何年住んでいるんだい! 思うに、きっとhttpのヘッダーに時間情報が載っているんだろう。検証してみる。
ob$ TZ=GMT date; w3m -dump_head https://www.google.com >zz Tue Feb 18 21:22:58 GMT 2020 ob$ less zz HTTP/1.0 200 OK Date: Tue, 18 Feb 2020 21:23:26 GMT : Set-Cookie: 1P_JAR=2020-02-18-21; expires=Thu, 19-Mar-2020 21:23:26 GMT; path=/; domain=.google.com; Secure
ローカル時間(OpenBSDが時を刻んでいるやつ)をGMTで表示(何たって世界共通時間ですから)、次にw3mを使ってヘッダー情報だけを採取。後は、ヘッダーから、時間関連のタグを抜き出してみた。クッキーの方は、ぐぐるの心持ち次第で変えられちゃう可能性が有るんで、使うとしたらDateタグの情報だな。
ob$ TZ=GMT date; w3m -dump_head https://www.yahoo.co.jp Tue Feb 18 21:56:44 GMT 2020 HTTP/1.0 200 OK Date: Tue, 18 Feb 2020 21:57:12 GMT
みんなのニュースであるやっほーも、今日の日付を返してくれているね。
w3mが無い環境だと、pythonで我慢だな。
o32$ cat aa.py import urllib.request response = urllib.request.urlopen('https://www.google.com') print(response.info()) o32$ TZ=gmt date; python3 aa.py
ここまで推測出来れば、後はソースに当たるだけ。
ob$ grep Date *.[ch] constraint.c: if (strcasecmp("Date:", line) != 0) constraint.c: * TLS handshake, based on the time specified by the server's HTTP Date: constraint.c: /* Report parsed Date: as "received time" */
ソースを雑見すると、ヘッダー情報の改変を心配してhttpsしか受け付けない、そしてアクセスしたサイトがほんまもんかdnsの検証機能を使って検証してるっぽい。ぽいなので、余り信用しないでね。今思い付いたぞ、httpsは暗号化も大事だけど、身元保証人制度が根本にあるから、こちらの機能を使っているんだろう。
ntpd
VMwareに入れているOpneBSD(amd64)で走らせてみる。例によって、-dでフォーグラウンド動作、-sでntpd起動時に、強制時刻合わせ。
/etc/rc.confのntpd起動フラグを確認すると、何も指定されていない。(NOに設定すると、起動するなの意思表示になる)すなわち、デフォの指定になるから、2つの機能は無しで起動って事になる。普通は起動時に、一度だけ強制時刻合わせをするのが流儀だと思うんだけど、あえてそれをしていない。深遠な理由が有るのだろうか。
ob$ doas ntpd -d -s ntp engine ready set local clock to Wed Feb 19 07:18:23 JST 2020 (offset -0.001565s) constraint reply from 172.217.175.68: offset -0.923849 peer 162.159.200.1 now valid peer 162.159.200.123 now valid peer 133.243.238.243 now valid peer 162.159.200.1 now valid peer 211.19.59.28 now valid adjusting local clock by -0.328642s clock is now synced constraint reply from 172.217.175.4: offset -0.169164 adjusting clock frequency by -4.992957 to 18.582043ppm adjusting clock frequency by 0.406461 to 18.988504ppm
暫くして、動作確認した。
ob$ ntpctl -s all 5/5 peers valid, 1/1 sensors valid, constraint offset -1s, clock synced, stratum 2 peer wt tl st next poll offset delay jitter 162.159.200.1 time.cloudflare.com 1 10 3 13s 34s -3.343ms 24.397ms 4.601ms 162.159.200.1 from pool pool.ntp.org 1 10 3 22s 30s -3.163ms 24.624ms 2.089ms 133.243.238.243 from pool pool.ntp.org 1 10 1 22s 30s 1.227ms 19.334ms 2.686ms 211.19.59.28 from pool pool.ntp.org * 1 10 1 4s 34s 1.127ms 22.873ms 4.293ms 162.159.200.123 from pool pool.ntp.org 1 10 3 7s 33s -1.381ms 28.804ms 12.642ms sensor wt gd st next poll offset correction vmt0 1 1 0 6s 15s 308.702ms 0.000ms
ちゃんと同期してるね。但し確認時間間隔(poll)は短い時間になっている。サーバーさんにご負担かけて、どうもすみません状態だな。
VMT(4) Device Drivers Manual VMT(4) NAME vmt - VMware Tools driver DESCRIPTION The vmt driver is a kernel level implementation of VMware Tools. VMware Tools are intended to provide better support for operating systems running inside virtual machines. provides access to the host machine's clock as a timedelta sensor.
sensorに見慣れないデバイスが使われていたので確認。VMwareさんからの回し者だな。なんて思っていたら、OpenBSDも認めるdriver扱い。4.4の時代からお仲間になったそうなんで、由緒ある者認定って事で宜しいかな。
それはそうと、vmtデバイスからの時刻オフセットが気のせいか大きいな。これはきっとVMwareの上流に位置するWindows10の時刻合わせがサボっていて真面目にやらないからだろう。素人なんてそんな事気にしないってMSが見くびっているに違いない。
暇な時に、Windows10の時刻合わせを頻繁にやってみよう。えーと、どうやればいいんだ。ぐぐってみろよ。 Windows 10で手動で時刻合わせを行なう方法これか。面倒っぽい。だからGUIは嫌いよ。
ntpd サーバーを受け継ぐ
VMwareの支援が有るなんて事を知ったものだから、それに頼ってみる。設定は簡単。/etc/ntpd.confのserver(s)の所をコメントアウトするだけ。
o32$ ntpctl -s all 1/1 sensors valid, constraint offset -2s, clock synced, stratum 1 sensor wt gd st next poll offset correction vmt0 * 1 1 0 9s 15s 3.769ms 0.000ms
peerが無くなって、時刻はvmtだけから供給されるようになった。一次サーバーに昇格ですよ。やったね。
でもね、Windows10の時計合わせがサボっている為、全く信用なりませんけど。上の方で、wgetしたぐぐるサーバーとdateコマンドを叩いた時のずれは、糞Windowsの時計合わせがさぼっていた為だった。時計合わせをしたら、両者は一致したよ。
次なるは、ゲストOSを動かして、その上でホスト側からの時刻を貰って来るように設定。この場合は、ゲスト側のntpd.confに、ホスト側のIPを登録するだけ。
vm$ ntpctl -s all 4/5 peers valid, constraint offset -1s, clock synced, stratum 2 peer wt tl st next poll offset delay jitter XXX.XXX.XXX.XXX 1 2 - 0s 0s ---- peer not valid ---- 82.193.117.90 from pool pool.ntp.org 1 10 1 12s 34s 0.825ms 350.944ms 42.466ms 62.116.162.126 from pool pool.ntp.org 1 10 2 10s 32s 19.180ms 310.747ms 29.266ms 216.197.156.83 from pool pool.ntp.org * 1 10 1 12s 34s 16.104ms 235.022ms 37.397ms 199.182.204.197 from pool pool.ntp.org 1 10 2 12s 34s 31.117ms 174.105ms 26.622ms
伏字がホスト側なんだけど、全く通信出来ていない。IP直の設定だと、信用ならんて事なんだろうね。IPだけじゃ身元保証人が同定出来ませんからね。
vmt
vmtでの受け継ぎが上手くいかないものだから、不貞腐れvmtのコードを見る事にした。ドライバーだよって説明が有ったので、devの中を探したら、pv/vmt.cに見つかった。 コードが長くて読み切れないので、コメントを拾い読み。
* Protocol reverse engineered by Ken Kato: * https://sites.google.com/site/chitchatvmback/backdoor * Notes on tracing backdoor activity in vmware-guestd: * * - Find the addresses of the inl / rep insb / rep outsb * instructions used to perform backdoor operations. * One way to do this is to disassemble vmware-guestd: * * $ objdump -S /emul/freebsd/sbin/vmware-guestd > vmware-guestd.S * * and search for '<tab>in ' in the resulting file. The rep insb and * rep outsb code is directly below that. * * - Run vmware-guestd under gdb, setting up breakpoints as follows: * (the addresses shown here are the ones from VMware-server-1.0.10-203137, * the last version that actually works in FreeBSD emulation on OpenBSD) * break *0x805497b (address of 'in' instruction) * commands 1 * silent * echo INOUT\n * print/x $ecx * print/x $ebx * print/x $edx * continue * end
backdoorなんてURLが恐いぞ。用心して行ってみると、日本人が開設された場所だった。みんなでリバースエンジニアリングして、あちこちのOSに移植しましょって趣旨。
上のコメントにも有る通り、リバースのやり方まで解説されてる。こういうの楽しいんだよな。 自宅で居ながらにして情報が手に入る。新型肺炎菌が充満してる都会に出かけなくて、リモートワークしながらってのが、超現代風ですよ。
ntp.h and ntpd.h
余勢を駆ってntpdのソースを閲覧。ぼーと眺めていると、あの子に怒られそうなので、取り合えず目標を立てる。 まずは、-sを付けて起動した時、どんな風に強制時刻合わせをやってるの? 次の目標は、身元保証人との時差が大きすぎると同期を中止するって言うけど、その許容範囲は?
定石に則りヘッダーファイルを見る。ntp.hとntpd.hだな。
RFC2030だよ、データのレイアウトはこうだよってのがntp.hに書いてあった。ntpd.hには、許容範囲が定義されてると思ったんだけど、それらしいのは見つからず。でも、どのファイルにどんな関数が有るかは定義されてた。ntp.cにoffset_compareなんてのが有るなあ。プチ気になる。
ntp.c
o32$ grep log_ ntp.c : log_info("ntp engine ready"); : log_info("clock is now synced"); log_info("clock is now unsynced");
こんなのが見られるので、実働部隊っぽい。期待してた、offset_compareは期待外れだった。文字列のcompreを時間のcompreに置き換えたものだったよ。
範囲拡大
一つのファイルに執着していても意味無いので、探索範囲を拡大。犬も歩けば棒に当たる作戦発動だな。
client.cに面白いコメントを発見
* From RFC 2030 (with a correction to the delay math): * * Timestamp Name ID When Generated * ------------------------------------------------------------ * Originate Timestamp T1 time request sent by client * Receive Timestamp T2 time request received by server * Transmit Timestamp T3 time reply sent by server * Destination Timestamp T4 time reply received by client * * The roundtrip delay d and local clock offset t are defined as * * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2.
これがntpの本質だな。図に書いてみると良く分かる。電波のスピードは30万km/sec、銅線の中だと誘電率の関係でスピードが落ちてしまい、20から25ぐらいになるかな。それにルーターとかのハンドリング時間も有るしね。上記はそれを考慮した式だ。
後は目が眩んで、おぼろですよ。んな事で、gdbに頼る事を思い付いた。結局それかいってのは、置いておいて。
run ntpd
恒例のソース一式をtmpに持ってきて自前で走らせる術。Makefileに -gを忘れず追加。
o32$ doas ./ntpd -d -s ntpd: start_child: execvp: No such file or directory Terminating o32$ doas /tmp/ntpd/ntpd -d -s ntp engine ready set local clock to Thu Feb 20 08:14:22 JST 2020 (offset 0.017677s) ntpd: start_child: execvp: No such file or directory ^Cntp engine exiting Terminating
OpenBSDのきつい監査に引っかかって、相対Pathでは起動出来ず。絶対Path指定したら、走り始めたけど、まだ不足品が有るな。
期待値は
o32$ doas ntpd -d -s ntp engine ready set local clock to Thu Feb 20 08:23:08 JST 2020 (offset 0.002892s) constraint reply from 172.217.175.68: offset -0.869282 peer 133.243.238.243 now valid peer 133.243.238.163 now valid ^Cntp engine exiting Terminating
こんな感じね。
この時に起動してるプロセスは、こんな感じ
47515 p1 I<+pU 0:00.07 ntpd -s -d 96513 p1 S<+p 0:00.09 ntpd: ntp engine (ntpd) 47762 p1 I+p 0:00.04 ntpd: dns engine (ntpd)
親子関係が生まれている。pid=47515が親で、他は子供。rootの特権が強すぎて超危険なので、権限を押さえた子供に仕事を任せている。ntpは時刻合わせ。dnsは安全機構を施したやつだろう。
ntpd.cのソースを見ると、ntpdの設置場所は、/usr/sbin/ntpdだよって固定してる。変な所(上でやったのは正にこれに当たる)に設置した親は、子供が仕事にかかれないように用心してるんだ。 隙が無いな。
そんな訳なんで、その場所を見てる所に手を入れて無視させるか、debug機能を盛り込んだntpdを正規の場所に置くか(元々のやつは保存しとく)の、2択になる。今回は後者を選択する。
o32$ wc *.[ch] 527 1766 14400 client.c 183 579 4138 config.c 1152 3337 27443 constraint.c 450 1187 10207 control.c 202 517 3636 log.c 49 249 1803 log.h 865 2426 21055 ntp.c 149 705 5284 ntp.h 250 691 5496 ntp_dns.c 71 285 1886 ntp_msg.c 916 2549 20882 ntpd.c 427 1232 11388 ntpd.h 251 758 5994 sensors.c 203 649 5639 server.c 237 635 4540 util.c 5932 17565 143791 total
こんな規模になるんで、ETAGSを作っちゃった。
長くなりそうなので、(たぶん)次回に続く。