OpenNTPD and ntpd (2)
前回のまくらで、感染症のシュミレーションから出発して、有名なローレンツアトラクタまで行っちゃった。
ローレンツの式で、天下り的に係数が提示されてるけど、これの意味する所を説明した文献には、とんと出会っていない。式の意味、係数の意味を知らずに、論じるな。
自分で考えてみろ。風邪じゃなくて風の発生、流れだな。X,Y,Zは、経度、緯度、高度とかだろうね。気圧差があれば空気の 流れが発生。他には温度か、コレオリの力、空気の粘度。ありゃ、係数が 4つになっちゃったぞ。
文献を探してみた。 ローレンツ・カオスの理解の仕方
難しい。一度読んだだけでは意味不。読書100遍、意義自ずと通じるかな。(根性論を振りかざしてどうしろと)
気象予報士さん達は、こういう難しい事が出てくるであろう難関を突破してきた猛者なんでしょうね。尊敬しちゃうぞ。
こういう楽しい研究も有るとな。
ntpdに潜る
前回の続きで、ntpdの中身追跡。目標と言うか目的地は、-sで強制時刻同期はどう実行されるか? ぐぐるのサーバーが提示する時刻と、ntpしたずれはどこまで許容範囲? 最初の目標では、adjtimeとかadjfreqを見るはめになりそう。だってマニュアルに明記されてるもの。
use gdb
フォークされる実行によると、 set follow-fork-mode childとか set detach-on-fork offを有効に使えとな。
o32# gdb -q ntpd Reading symbols from ntpd...done. (gdb) set detach-on-fork off (gdb) b ntpd_adjtime Breakpoint 1 at 0x66f5: file ntpd.c, line 463. (gdb) b ntpd_adjfreq Breakpoint 2 at 0x67fa: file ntpd.c, line 485. (gdb) r -s -d Starting program: /usr/sbin/ntpd -s -d [New process 95328] [New process 54988] Reading symbols from /usr/lib/libm.so.10.1...done. : Reading symbols from /usr/libexec/ld.so...done. Warning: Cannot insert breakpoint -17. Temporarily disabling shared library breakpoints: breakpoint #-17 Cannot insert breakpoint 1. Cannot access memory at address 0x188646f5 Cannot insert breakpoint 2. Cannot access memory at address 0x188647fa [Switching to process 95328] ntp engine ready _thread_sys_fork () at -:3 3 -: No such file or directory. (gdb) bt #0 _thread_sys_fork () at -:3 #1 0x04da7d76 in _libc_fork_wrap () at /usr/src/lib/libc/sys/w_fork.c:51 #2 0x1886d60c in start_child (pname=0x188605a6 "ntp_main", cfd=4, argc=3, argv=0xcf7ee274) at util.c:182 #3 0x1886379d in main (argc=<optimized out>, argv=0xcf7ee274) at ntpd.c:256
この後gdbが言う事を聞かなくなる。
o32# gdb -q ntpd Reading symbols from ntpd...done. (gdb) set detach-on-fork off (gdb) r -s -d Starting program: /usr/sbin/ntpd -s -d [New process 21551] [New process 77818] ntp engine ready set local clock to Sat Feb 22 08:27:25 JST 2020 (offset 0.041653s) [New process 76911] Couldn't get registers: Operation not permitted. (gdb) bt #0 _thread_sys_fork () at -:3 #1 0x0d83fd76 in _libc_fork_wrap () at /usr/src/lib/libc/sys/w_fork.c:51 #2 0x1a95560c in start_child (pname=0x1a949f0f "constraint", cfd=6, argc=3, argv=0xcf7dff44) at util.c:182 #3 0x1a957b76 in priv_constraint_msg (id=2, data=0x4c807200 "", len=289, argc=3, argv=0xcf7dff44) at constraint.c:289 #4 0x1a94c5e2 in dispatch_imsg (lconf=0xcf7dfdf8, argc=3, argv=0xcf7dff44) at ntpd.c:431 #5 0x1a94ba7b in main (argc=<optimized out>, argv=0xcf7dff44) at ntpd.c:336
同様にこちらも、この後言う事を聞かなくなる。
このようなdaemon化されちゃうやつは、ダエモン君をgdbにattachするのが本流みたいだ。 今回の例だとntpを実際に行うやつとdnsの面倒を見るやつと、まれに走るhttpsで取ってくる時刻情報。
親のntpdは、それらのワーカーからの報告を元に、クリチカルなシステムコールを実行するとな。そうと分かれば、親のクリチカルな実行部分にBPを置いてみる。
o32# gdb -q ntpd (gdb) b ntpd_adjfreq Breakpoint 2 at 0x1578a7fa: file ntpd.c, line 485. (gdb) b ntpd_adjtime Breakpoint 3 at 0x1578a6f5: file ntpd.c, line 463. (gdb) c Continuing. [New process 1137] ntp engine ready set local clock to Sat Feb 22 14:13:44 JST 2020 (offset 0.081993s) constraint reply from 172.217.175.68: offset -0.372634 Thread 1 hit Breakpoint 3, ntpd_adjtime (d=0.0024835) at ntpd.c:463 463 d += getoffset(); (gdb) bt #0 ntpd_adjtime (d=0.0024835) at ntpd.c:463 #1 0x1578a4ea in dispatch_imsg (lconf=0xcf7be418, argc=3, argv=0xcf7be564) at ntpd.c:404 #2 0x15789a7b in main (argc=<optimized out>, argv=0xcf7be564) at ntpd.c:336
早速引っかかってきた。
470 if (adjtime(&tv, &olddelta) == -1) (gdb) p tv $2 = {tv_sec = 0, tv_usec = 2483} (gdb) p olddelta $3 = {tv_sec = 0, tv_usec = 0}
今度は周波数の調整
Thread 1 hit Breakpoint 2, ntpd_adjfreq (relfreq=2.0197570350998011e-05, wrlog=1) at ntpd.c:485 485 if (adjfreq(NULL, &curfreq) == -1) { (gdb) bt #0 ntpd_adjfreq (relfreq=2.0197570350998011e-05, wrlog=1) at ntpd.c:485 #1 0x188b35be in dispatch_imsg (lconf=0xcf7de068, argc=3, argv=0xcf7de1b4) at ntpd.c:412 #2 0x188b2a7b in main (argc=<optimized out>, argv=0xcf7de1b4) at ntpd.c:336 (gdb) p curfreq $1 = 7111535759620059216 adjusting clock frequency by 20.197570 to -13.094430ppm
いずれも、dispatch_imsgのループの中から呼ばれている。パケットが来たかは、
if ((nfds = poll(pfd, i, timeout)) == -1) if (errno != EINTR) { log_warn("poll error"); quit = 1; }
このpollで監視と言うか待機してる。
ntp engine
今度はクライアント側と言うか、ワーカー側を見る。セオリー通りに、動いているダエモン君にアタッチする。
o32# ps awx | grep ntpd 82537 ?? I<pU 0:00.04 ntpd 63573 ?? S<p 0:00.08 ntpd: ntp engine (ntpd) 53808 ?? Ip 0:00.05 ntpd: dns engine (ntpd)
ntpdは、何のオプションも指定しないで起動しておいた。エンジンは本体のコピーなので、gdbの対象はntpdで良いはず。
o32# gdb -q ntpd -p 63573 Reading symbols from ntpd...done. Attaching to program: /usr/sbin/ntpd, process 63573 : Reading symbols from /usr/libexec/ld.so...done. [Switching to thread 495638] _thread_sys_poll () at -:3 3 -: No such file or directory. (gdb) b priv_adjtime Breakpoint 1 at 0x1ade03d6: file ntp.c, line 720.
アタッチするとgdbは別にプロセスをコピーするみたいで、新たにライブラリィーが読み込まれている風だ。
(gdb) c Continuing. Breakpoint 1, priv_adjtime () at ntp.c:720 720 TAILQ_FOREACH(p, &conf->ntp_peers, entry) { (gdb) bt #0 priv_adjtime () at ntp.c:720 #1 0x1ade5e24 in sensor_update (s=0x7ea34400) at sensors.c:250 #2 0x1ade5d25 in sensor_query (s=0x7ea34400) at sensors.c:220 #3 0x1addf751 in ntp_main (nconf=0xcf7e6b88, pw=0x62c39000, argc=1, argv=0x74812560) at ntp.c:418 #4 0x1addcd1a in main (argc=<optimized out>, argv=0xcf7e6cd4) at ntpd.c:217
どうやら、目的地に達したみたい。余り本物のntpサーバーに負担をかけるのは気が引けるので、sensorデバイスとのやり取りだけにしてる。
349 if ((nfds = poll(pfd, i, timeout * 1000)) == -1)
待ちはやはりpollルーチンだった。sensor_updateとかは、それぞれのタイミングで動いていて、用が有ったら、告げるって事なんだな。
初回の時刻合わせ
目標の一つ、初回の時刻合わせ -s のスイッチはどう働くかを見ておく。 大事な事(システムコール)は、ntpdに集中させてある事を忘れない。裏を返せば、下働きをするntpとかは、権限が剥奪されててシステムコールは出来ないようにしてるんだった。
o32# gdb -q ntpd Reading symbols from ntpd...done. (gdb) b ntpd_settime Breakpoint 1 at 0x697e: file ntpd.c, line 520. (gdb) r -s -d Starting program: /usr/sbin/ntpd -s -d [New process 99557] ntp engine ready Thread 1 hit Breakpoint 1, ntpd_settime (d=0.030098) at ntpd.c:520 520 if (d == 0) (gdb) bt #0 ntpd_settime (d=0.030098) at ntpd.c:520 #1 0x18211562 in dispatch_imsg (lconf=0xcf7e8038, argc=3, argv=0xcf7e8184) at ntpd.c:422 #2 0x18210a7b in main (argc=<optimized out>, argv=0xcf7e8184) at ntpd.c:336
時間のずれが、差分で送られてくるんで、それを元に正しい時刻を算出。settimeofdayシステムコールを使って、一気に正しい時刻に設定。
(gdb) c Continuing. set local clock to Sun Feb 23 05:29:09 JST 2020 (offset 0.030098s) adjusting local clock by 0.037160s constraint reply from 172.217.31.132: offset -1.442186
ローカルクロックも調整してる。
o32# gdb -q ntpd Reading symbols from ntpd...done. (gdb) r -d Starting program: /usr/sbin/ntpd -d [New process 50273] ntp engine ready constraint reply from 172.217.175.68: offset -0.857104
こちらは、一気合わせを省略した場合だ。ずれが有っても、adjtimeを使って緩やかに調整されて行く。から、同期されるまで、場合によっては長大な時間がかかる。
imsg_compose
上の一気合わせもそうだけど、ワーカーのdaemonから、ntpdにデータを届ける必要が出て来る。それを担っているのが、imsg系の通信装置になる。知らなかったな。
DESCRIPTION The imsg functions provide a simple mechanism for communication between local processes using sockets. Each transmitted message is guaranteed to be presented to the receiving program whole. They are commonly used in privilege separated processes, where processes with different rights are required to cooperate. A program using these functions should be linked with -lutil.
色々調べたい事が有るけど、いい加減に飽きてきたんで、他の事を少しやってみる。
OpenNTPD
OpenBSDが開発したntpdが、汎用OSでも使えるように、OpenNTPDって形で公開されている。 debianでは、パッケージになってたけど、CentOSには見当たらないので、野良で入れてみる。
取って来るtar玉は、https://mirror.leaseweb.com/pub/OpenBSD/OpenNTPD/openntpd-6.2p3.tar.gzぐらい。
普通にconfigして入れればお終い。じゃ記事にならないので、ひねくれてみる。 ntpd.confを/usr/local/etcに置く。出来たsrc/ntpdを/usr/local/sbinに置く。 /usr/local/sbin/ntpdをntpctlにハードリンクしておく。
On most Linux and BSD systems, something like should work: groupadd _ntp useradd -g _ntp -s /sbin/nologin -d /var/empty -c 'OpenNTP daemon' _ntp mkdir -p /var/empty chown 0 /var/empty chgrp 0 /var/empty chmod 0755 /var/empty
特権を持たないユーザー _ntp を作り、そのユーザーで悪さ出来ないように空dirを用意してあげる。
起動はフルパスを指定して行う。
reply from 133.243.238.163: offset 0.000175 delay 0.016090, next query 30s reply from 162.159.200.1: offset -0.003346 delay 0.020809, next query 31s reply from 162.159.200.123: offset -0.000412 delay 0.015803, next query 30s reply from 211.19.59.28: offset -0.010333 delay 0.019376, next query 31s
エージングがなかなか完了しないため、煩雑にアクセスに行ってる。
(base) [sakae@c8 tmp]$ sudo /usr/local/sbin//ntpctl -s all 4/4 peers valid, clock synced, stratum 4 peer wt tl st next poll offset delay jitter 162.159.200.123 from pool pool.ntp.org 1 10 3 23s 30s -0.103ms 17.471ms 1.807ms 211.19.59.28 from pool pool.ntp.org 1 10 1 29s 32s -1.885ms 22.143ms 2.944ms 162.159.200.1 from pool pool.ntp.org * 1 10 3 17s 33s 0.346ms 16.721ms 2.939ms 133.243.238.163 from pool pool.ntp.org 1 10 1 14s 32s 2.123ms 17.125ms 2.521ms
でも、一応同期は取れた風です。
これで終わっては単なるインストール記になるんで、ソースの見どころを上げておく。 それは、OpenBSDの人達が、密かに他のOSへの不満を表している所だ。OpenBSD流に 他のOSを似せるため、補助のファイルが提供されてる。
(base) [sakae@c8 compat]$ ls -ltr *.o -rw-rw-r-- 1 sakae sakae 3656 Feb 24 14:33 socket.o -rw-rw-r-- 1 sakae sakae 21560 Feb 24 14:33 adjfreq_linux.o -rw-rw-r-- 1 sakae sakae 17640 Feb 24 14:33 closefrom.o -rw-rw-r-- 1 sakae sakae 4472 Feb 24 14:33 freezero.o -rw-rw-r-- 1 sakae sakae 29920 Feb 24 14:33 imsg.o -rw-rw-r-- 1 sakae sakae 25216 Feb 24 14:33 imsg-buffer.o -rw-rw-r-- 1 sakae sakae 15024 Feb 24 14:33 md5.o -rw-rw-r-- 1 sakae sakae 3800 Feb 24 14:33 progname.o -rw-rw-r-- 1 sakae sakae 9312 Feb 24 14:33 recallocarray.o -rw-rw-r-- 1 sakae sakae 12336 Feb 24 14:33 setproctitle.o -rw-rw-r-- 1 sakae sakae 7760 Feb 24 14:33 strlcat.o -rw-rw-r-- 1 sakae sakae 4512 Feb 24 14:33 strlcpy.o -rw-rw-r-- 1 sakae sakae 6648 Feb 24 14:33 strtonum.o -rw-rw-r-- 1 sakae sakae 38456 Feb 24 14:33 arc4random.o -rw-rw-r-- 1 sakae sakae 4584 Feb 24 14:33 arc4random_uniform.o
strlcpyはOpenBSD流の安心安全なやつです。他のOSでは提供されていなので、提供しましたとかね。普通のOSはstrncpyを提供してる。その危険性を
DESCRIPTION The strncat() function appends not more than count characters of the string append to the end of the string found in the buffer dst. Space for the terminating `\0' should not be included in count. Bounds checking must be performed manually with great care. If the buffer dst is not large enough to hold the result, subsequent memory will be damaged.
十分に注意は、往々にして破られると。
debina方面はどうなってるか、openntpdを一応入れてみた。
debian:~$ cat /etc/openntpd/ntpd.conf # Choose servers announced from Debian NTP Pool servers 0.debian.pool.ntp.org servers 1.debian.pool.ntp.org servers 2.debian.pool.ntp.org servers 3.debian.pool.ntp.org debian:~$ cat /var/lib/openntpd/db/ntpd.drift -14.652
さすが、自前でサーバー持ってるよ。
debian:~$ sudo /usr/sbin/ntpctl -s all 16/20 peers valid, clock synced, stratum 3 peer wt tl st next poll offset delay jitter 202.181.103.212 from pool 0.debian.pool.ntp.org * 1 10 2 15s 34s -8.611ms 18.329ms 2.604ms 2001:2c0:cf08:4800::123 from pool 2.debian.pool.ntp.org 1 2 - 1s 15s ---- peer not valid ---- 162.159.200.1 from pool 2.debian.pool.ntp.org 1 10 3 17s 31s -10.648ms 18.516ms 3.207ms
しかも、そのうちの一台は、IPv6対応。オイラーの所では、IPv6を殺しているから、通信が成立しないんだだ。もう、小一時間ランニングしてるけど、poll間隔が短いなあ。
もう状況は分かったので停止しよう。systemdではどうやるんだ。
全く、新発明のsystemdは、大嫌いだ。