ntpd and statistics (5)

とある早朝、玄関前で一服してたら、新聞配達の一見おねーちゃん風おばさんが近寄って来た。 すわ、新聞の勧誘かと身構えたぞ。だって、手に新聞持ってるんだもの。

そのおばちゃんが言う事には、配り終えたんだけど、一部余っちゃったのよねと。それで、ちゃんと配ったか、ご丁寧に配達先を確認してたとの事。

お隣さんは新聞を取っているんだけど、そに日には空になってた。で、そのおばちゃんが聞いてきたんだ。お隣さんって、朝が早いんですか? 朝が早いなら、配達された新聞を取り込んで、朝食でも食べながら読んでいるんだろうって推測だな。

それにしては、まだ車が有るのに、室内の電気が付いていない。で、不審に思ったのだろう。素晴らしい洞察力。

もう一度、配達先を見回ってきて、問題なければ、隣に(再度?)入れておきますって、さ。 なかなか素晴らしい。こういう人の協力で、孤独死してる人の早期発見に繋げましょう。村長さんに推挙しようかな。

traceroute

前回の最後で、traceroute失敗したよって書いた。で、Windowsのtracertに逃げちゃったんだけど、負けた気がしたので、何とかならないか調べてみた。まずは失敗例の再掲。

ob$ traceroute time.google.com
traceroute: Warning: time.google.com has multiple addresses; using 216.239.35.4
traceroute to time.google.com (216.239.35.4), 64 hops max, 40 byte packets
 :
29  * * *
30  * * *
31  * * *
^C

40byteのパケットを64のルーターを辿るまで流すよって案内。そしてのんびりと実行。待ちきれなくて止めてしまった。

送られるパケットの形式がUDPなんで、何か悪意が有るんじゃなかろうかと拒否されてしまうそうな。でも、普通にpingは動く。悪意の無い、ネットワークの疎通だけを確認するパケットなんで、安心して応答するらしい。ってか、ちゃんと答えろよって圧力が働いているんだ。

ならば、tracerouteに使うパケット形式を疎通確認専用パケット(ICMP)にしたらどうよ。そういう発想のオプションが用意されてる。

ob$ traceroute -I time.google.com
traceroute: Warning: time.google.com has multiple addresses; using 216.239.35.0
traceroute to time.google.com (216.239.35.0), 64 hops max, 60 byte packets
 :
28  * * *
29  time1.google.com (216.239.35.0)  56.499 ms  54.625 ms  53.638 ms

今度は60byteのパケットが使われた。そしてググルは複数のアドレスを持っているんで、先程とは違うアドレスを求めて偵察を始めた。無事に到達出来たよ。29か所目でやっと辿りついたね。 国内のサーバーだと17ホップだったんで、随分とネットワーク的には遠い所だって分かる。

この事情はリナでも一緒。但し、-Iのオプションは権限が必要って言う変な制限が課されていたぞ。

sakae@pen:~$ sudo traceroute -I time.google.com
  :
27  time4.google.com (216.239.35.12)  57.749 ms  57.660 ms  53.975 ms

微妙に近い所を選んでくれたね。 ちなみに、ググルのntpサーバーは何台構成か、調べてみる。

ob$ dig time.google.com
     :
;; ANSWER SECTION:
time.google.com.        5       IN      A       216.239.35.0
time.google.com.        5       IN      A       216.239.35.12
time.google.com.        5       IN      A       216.239.35.4
time.google.com.        5       IN      A       216.239.35.8

ああ、今回使ったLinuxは、Windows10 + VMWarePlayer + Debian10.3 な環境。今までリナは vartualBoxで動かしてた。VMWare上ではCentOSが動いてた(過去形ね)。が、ある日そのCentOSがbootしなくなったんだ。リナ方面は暗い為、深く原因追及せずにばっさり削除。その空地にdebianを進出させたって訳。何たってVMWareの方が断然レスポンスが良いですから。

ホスト名でディストリビューションを区別する必要も無くなったので、ペンギンのpenにしたよ。

犯人捜し

これも前回からの続きになるんだけど、ntpdした時に、突然delayとかが乱れて暫くすると復帰する事があった。(前回のグラフ参照)

再現性が有るか、今度はリナ上のopenbtpdで試してみた。

ntp3.jst.mfeed.ad.jp debian(64Bit) on VMWare

 *  1 10  2    7s   34s        -1.601ms    19.409ms     2.108ms
 *  1 10  2    8s   31s        -1.183ms    19.646ms     1.366ms
 *  1 10  2   10s   32s         0.047ms    20.583ms     2.879ms
 *  1 10  2   14s   33s         6.159ms    36.028ms    47.515ms
 *  1 10  2   17s   32s         7.990ms    35.891ms    47.975ms
 *  1 10  2   19s   31s         7.779ms    35.765ms    47.970ms
 *  1 10  2   20s   31s         7.734ms    35.265ms    48.548ms
 *  1 10  2   20s   30s         7.305ms    36.204ms    48.697ms
 *  1 10  2   22s   32s         7.177ms    36.427ms    48.716ms
 *  1 10  2   22s   30s         7.293ms    36.888ms    48.769ms
 *  1 10  2   22s   30s         6.924ms    35.992ms    48.644ms
 *  1 10  2   25s   33s         0.583ms    20.361ms     5.317ms
 *  1 10  2   28s   33s        -0.425ms    20.976ms     5.801ms
 *  1 10  2   30s   32s        -0.814ms    21.834ms     6.696ms

やっぱりばらけてる。けど、よく見ると8サイクル分が異常(jitterが顕著だ)。この8サイクルって、8個のデータを演算してるからでjitterについては説明が付く。でもdelayは、その場その場の実測値でしょ。8サイクルに渡っての根拠が乏しいな。

octave:2> statistics (mfeed3)
ans =
  ; offset    delay      jitter
   -6.51100   17.21100    1.36600  ; min
   -1.18725   18.16650    2.37700  ; 1/4 posision
   -0.30600   19.22950    3.90700  ; median
    0.58725   20.82725    7.98925  ; 3/4 posision
    7.99000   51.16100   71.28500  ; max
    0.20341   22.43341   12.15643  ; mean
    2.56610    8.44798   19.64381  ; sd
    1.47876    2.31024    2.06153  ; skewness
    6.19042    7.32395    5.71659  ; kurtosis

一応その時の統計データ。上から5行分のデータは、箱ひげ図を書く時に使う。mean(平均値)とsd(標準偏差)は、統計でお馴染みのものだ。

目に若葉じゃなくて、(オイラーには)目新しいskewnessってのは歪度と言うものらしい。 度数分布を取った時、平均値を頂上にした釣鐘型になるのが理想なんだけど、左右対称にならない事も往々にして有るとな。その崩れ具合を指標にしたとな。

分布の山が左にずれて裾が右に伸びているときは正の値を、山が右にずれて裾が左に伸びているときは負の値をとる。正規分布では0となる。

delay時間なんてのは、ある一定時間以下になる事は絶対に無い。大きな方向にずれる事はあるはず。よって、histを描いてみるまでもなく、右に裾が伸びるものとなる。

狂ったネットワークオペレータが突然、ネットワーク経路を人工衛星経由に切り替えたり、EME(月面反射)の実験に巻き込んじゃったりしたら、deleyは3秒とかを平気で超えるぞ。

もう一つ目新しいkurtosisは尖度って言う統計値。分布が正規分布からどれだけ逸脱しているかを表す統計量で、山の尖り度と裾の広がり度を示す。3未満のときは尖りが緩やかで裾が短い。3より大きいときは尖りが急で裾が長い。正規分布では3となる。

soですか。無線家に言わせたらQみたいなものか。急峻度だな。共振回路で共振周波数から3dB下がった所の帯域幅で共振周波数を除した値の事だ。思わぬ統計の勉強をしちゃったな。

で、この異常を起こす犯人を見つけて たいーほ したいぞ。刑事は熟考します。 ntpdやってる時、pingでサーバーまでの往復時間を測ってみたらどうよ。 下記の観察スクリプトは、サーバーにntp1.jst.mfeed.ad.jp を仮定。pingはワンショット動作させてます。

ob$ cat loop.sh
#!/bin/sh
while :
do
    ntpctl -sp | grep ms >> LOG
    ping -c 1 ntp1.jst.mfeed.ad.jp | grep icmp >> PLOG
    sleep 30
done

適当な時間走らせてから、下記により必要なデータの加工。2つのデータをマージ。

ob$ cat LOG | awk '{print($7,$8,$9)}' | sed -e 's/ms//g' >log1
ob$ cat PLOG | cut -f7 -d' ' | cut -f2 -d'=' >plog1
ob$ paste log1 plog1 >aa
64 bytes from 210.173.160.27: icmp_seq=0 ttl=128 time=17.292 ms
64 bytes from 210.173.160.27: icmp_seq=0 ttl=128 time=17.676 ms
64 bytes from 210.173.160.27: icmp_seq=0 ttl=128 time=17.775 ms

こちらはPLOGの一部。加工し易いように気を使っててくれて、有難い。

octave:3> statistics (aa)  ;; 母数 145
ans =
  ; offset     delay       jitter      ping
   -1.043000   17.417000    1.293000   15.194000 ; min
    0.079000   18.554000    2.599000   16.548000
    0.518000   19.062000    3.362000   17.765000 ; median
    3.178000   23.275000   13.224000   19.033000
    8.083000   32.432000   42.688000   25.672000 ; max
    1.710069   21.632393   10.865910   17.924814 ; mean
    2.393757    4.451630   12.048407    1.708660 ; sd
    1.113494    1.170779    1.300984    0.908765 ; 非対称度
    3.239035    3.070332    3.488720    4.680467 ; とんがり度

今回は余り顕著に現象が出ていないけど、グラフにしてみると、前回と同様な傾向が伺える。でも、pingの結果はランダムになってるぞ。

比較の為、純粋な debian(32Bit)機でも実施。4朝に渡って測定したけど、顕著なdelayの変化は無かった。

octave:11> statistics (log1)
ans =
 ; offset     delay       jitter
  -10.56500   15.44500    1.50900  ; min
   -2.31925   17.07300    2.34900
   -0.60300   17.34500    2.86150  ; median
    0.47100   17.60275    3.76700
   11.55600   18.48400    6.16200  ; max
   -1.02142   17.31440    3.11005  ; mean
    3.28436    0.50861    1.10994  ; sd
   -0.35509   -0.57379    1.05588
    5.68608    4.47135    3.49409

ここまでの所をまとめると、

発症  Windows10 + VMWare + OpenBSD + ntpd 
発症  Windows10 + VMWare + Debian(64) + openntpd
陰性  Debian(32) + Openntpd

数学では、無い事を証明する事を、悪魔の証明と言うそうな。それに対して有る事の証明は簡単。一つでも有る事が見つかればいいのですから。今、陰性になってるpureなdebian機で、未来永劫、発症は無いのか? 証明は不可能だな。でも刑事の心象としては、推定無罪じゃなくて、推定有罪としたい。だって、たった4回しか張り込みしてないからね。発症時、8回分おかしくなるって言う、XXXntpdの癖が観察されてるから、XXXntpdは心象有罪かな。

後試すとしたら、Windows10 + VMWareな環境で、本物のntpdを試す。VMWareの影響を排除する為、vboxに入れてるFreeBSDで試す or WSL上で試す、ぐらいかなあ。待て、WSLと言うかWindowsには極力ファイルを増やさない主義。gccとかの開発環境は入れていない。よって、WSL上でのntpd実験は出来ないな。

sakae@pen:~$ ldd /usr/local/sbin/ntpd
        linux-vdso.so.1 (0x00007ffe9d666000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1afd553000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1afd392000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1afd708000)

待て、VMWare上のntpdを持って行けば動くんではなかろうか。幸い変なlibは使っていないみたいだから。

それより、他人様にすがってみるのはどうだ。いわゆる論文の追試ね。これが一番まっとうな方法かも知れない。そうだ、CDCの長官に頼むのはどうだ。

ベイズの定理

刑事の経験で、推定有罪なんて印象を持ったけど、もっと科学的に何とか出来ないかねぇ。 頭を巡らしていたら、ふとベイズの定理なんてのを思い出した。

よく引き合いに出される例題。ある家族に子供が2人いる。そのうちの一人は男の子って情報が与えられた。もう一人の子供がやはり男の子である確率はいかに?

一人が男の子であろうとなかろうと、男女が生まれる確率は独立してるはずだから、1/2でしょ。いや、生物学的に幼少期は、男の子の方が弱いから、それを補うため、わずかに男の子の方が確率的に高い(どうだ、みんなが知らない事まで知ってるぞ)。

残念でしたね。答えは1/3です。何故って? 生まれる順番を考慮すると、男男、男女、女男、女女の4通りの組み合わせが考えられる。

最初の情報、片方は男の子ってのから、女女と言う組み合わせは除外出来る。そうすると、この3組の組み合わせの中でもう片方も男って組み合わせは1組。すなわち、1/3の確率。

情報が与えられた後で、確率が変化する。これがベイズの定理の本質。

刑事もこれを応用出来ないか考えるべし、難しいわな。考えるの放棄かな。

発症(陽性)だ、陰性だ。加えて(偽)陰性だなんて、世界を騒がしている語句を使っちゃったんで、 今度は明るく行くか。

星(*)に願いを

ntpctlした時にsyncedに成っていたり、peerの左端に星が付けているのは、内部的なstatusを保持してるconf構造体のメンバーsyncedだ(何ていう悪文だ)。 場所を探し出すと、

ntp.c/priv_adjfreq

                case IMSG_ADJTIME:
                        memcpy(&n, imsg.data, sizeof(n));
                        if (n == 1 && !conf->status.synced) {
                                log_info("clock is now synced");
                                conf->status.synced = 1;
                                priv_dns(IMSG_SYNCED, NULL, 0);
                                constraint_reset();
                        } else if (n == 0 && conf->status.synced) {

次は、IMSG_ADJTIME の送出先を探す。 ntp.c/priv_adjtime が相当する。この中で、実質的に時間の調整等が実施されている。

このpriv_adjtimeを呼んでいるのは、client.c/client_updateの中。 このルーチン内で、 良いデータ(good)が8回続いたか検査。続いてたらsyncedの判定OKって事で、上位に伝えるとな。

sendto

勢いで、要求パケットを投げる所も調べておく。パケットの送出は、sendtoって事を知ってるぞ。sendmsgかと思ってたけどね。

ntp_msg.c/ntp_sendmsg の中で使われていた。じゃ、これを呼んでる所は何処? client.c/client_queryの中。

        /*
         * Send out a random 64-bit number as our transmit time.  The NTP
         * server will copy said number into the originate field on the
         * response that it sends us.  This is totally legal per the SNTP spec.
         *
         * The impact of this is two fold: we no longer send out the current
         * system time for the world to see (which may aid an attacker), and
         * it gives us a (not very secure) way of knowing that we're not
         * getting spoofed by an attacker that can't capture our traffic
         * but can spoof packets from the NTP server we're communicating with.
         *
         * Save the real transmit timestamp locally.
         */

	p->query->msg.xmttime.int_partl = arc4random();
        p->query->msg.xmttime.fractionl = arc4random();
        p->query->xmttime = gettime_corrected();

        if (ntp_sendmsg(p->query->fd, NULL, &p->query->msg) == -1) {

世の中の悪い奴に塩を送る事は無いから、攪乱するデータでも送っておけ。そこまで、気を回しますか。

更にclient_queryは、ntp.c/ntp_mainの大ループの中に鎮座してたよ。

good documents

ここまで、何の資料も見ないでやって来たけど、井の中の蛙はいかんとよ の原則により(本当は息抜きの為)、よそ様が作成されてる資料に当たってみる。

NTPによる同期について

NTPのパケットフォーマットとパケットキャプチャ

NTPプロトコルの概要と仕組み~誤差補正の計算,仕様,シーケンス

NTP: The Network Time Protocol

OpenBSDでもnet/ntpって名前でpkgになってた。山のようなコマンドで、これじゃBUGを誘発するわなぁ。シンプルが一番ですよ。 まあ、これって昔やった、sudo複雑過ぎるからdoasを提供しますと同じだな。 嫌味で複雑度を測っておく。

ob$ cat distinfo
SHA256 (ntp-4.2.8p10.tar.gz) = 3dI2bmQhm576D3Q44GgA0Ns5SsXIjhPBe3DQ3N+ZuZ8=
SIZE (ntp-4.2.8p10.tar.gz) = 6998648

tar玉のサイズは複雑度に比例する。ちなみに、OpenBSD備え付けのntpdは、圧縮しても

ob$ cd /usr/src/usr.sbin
ob$ tar zcf /tmp/ntpd.tgz ./ntpd/
ob$ ls -l /tmp/ntpd.tgz
-rw-r--r--  1 sakae  wheel  49665 Mar 10 06:16 /tmp/ntpd.tgz

正に桁違い!!

Index of /pub/OpenBSD/OpenNTPD

を見ると、外販してるopenntpdのtar玉は、437Kだから、オリジナルに比べて一桁大きいな。

rfc

上記の資料でRFCなんて言う懐かしい名前が出て来た。RFCと言ったら、そりゃFreeBSDでしょ。何それ?

FreeBSDのportsにはRFCを簡単に引くパッケージが用意されてるんだ。パッケージ名はrfcって名前。何の捻りもない。misc/rfcに作成の為のMakefileが置いてある。ただ使うだけなら pkg install rfc だけで入る。

はず、なんだけど、今やったら、未提供。なんでかな? misc/rfcは置いてあるので、自前でやってみる。

[sakae@fb /usr/ports/misc/rfc]$ sudo make install
===>  rfc-3.2.3_3 is marked as broken: unfetchable.
*** Error code 1

Stop.
make: stopped in /usr/ports/misc/rfc

哀れな事に壊れていますですってさ。Makefileに壊れてますマークが有るんで、それをコメント化して強引にインストールする(これって、事故責任だからね)。 dependでテキストモードのブラウザw3mが必要になる(原稿の取り寄せ、閲覧に必要)んで、事前にインストールしておく。rfcの本体はperlスクリプトだ。

インストール後、ルート権限で、インデックスを作っておく。(更新も同様)

[sakae@fb /usr/ports/misc/rfc]$ sudo rfc -i
* * Creating /root/.rfcrc * *

Modem users one moment, it's about 1024k (doesn't need to be updated often)
original lines  = 0     /usr/local/etc/rfc-index
new lines       = 36816 /usr/local/etc/rfc-index

後は普通にキーワードを入れて検索するだけ。

[sakae@fb /usr/ports/misc/rfc]$ rfc -k ntp
* * Creating /home/sakae/.rfcrc * *

The Result:
0958 Network Time Protocol (NTP). D.L. Mills. September 1985. (Format:
     TXT, HTML) (Obsoleted by RFC1059, RFC1119, RFC1305) (Status:
     UNKNOWN) (DOI: 10.17487/RFC0958)
      :
8143 Using Transport Layer Security (TLS) with Network News Transfer
     Protocol (NNTP). J. Elie. April 2017. (Format: TXT, HTML) (Updates
     RFC4642) (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC8143)

perlのマッチ機能を使っているので、ゴミも混じっているけど、意ながらにして検索できるのはありがたい。

そんじゃ、世界RFC遺産の部を見てみる。

[sakae@fb /usr/ports/misc/rfc]$ rfc -l 958
Found browser at /usr/local/bin/w3m
URL to get:  http://www.ietf.org/rfc/rfc0958.txt
    :
   5.2.  Message Processing
           :
      The destination peer calculates the roundtrip delay and clock
      offset relative to the source peer as follows.  Let t1, t2 and t3
      represent the contents of the Originate Timestamp, Receive
      Timestamp and Transmit Timestamp fields and t4 the local time the
      NTP message is received.  Then the roundtrip delay d and clock
      offset c is:

         d = (t4 - t1) - (t3 - t2)  and  c = (t2 - t1 + t3 - t4)/2 .

そして、付録にパケットフォーマットの解説が出てたり

   Reference Clock
   Identifier

      Code identifying the particular reference clock. In the case of
      type 1 (primary reference), this is a left-justified, zero-filled
      ASCII string identifying the clock, for example:

         WWVB    WWVB radio clock (60 KHz)
         GOES    GOES satellite clock (468 HMz)
         WWV     WWV radio clock (2.5/5/10/15/20 MHz)

こんな用語解説まで有った。JJYの米国版だな。いやー面白いな。WWV20MHzは、VFOの安定度を調べる為にBCLした事が有るぞ。

このRFCの発行は1985年9月。実時間の提供を目指しているのにNTPの始まりの時間が1900-01-01ってのは何故? epoc timeにしておけば十分だと思うけど、誰もRFCで提案しなかったのかね?

こんな楽しいrfcだけど、何でも収録してるdebianのパッケージには見当たらない。

http://www.dewn.com/rfc/ がマスターサイトなんだけど、繋がらないなあ。だから、BROKEN=unfetchable と言う理由だったのね。歴史はひっそりと消えてゆく。幸い、どこかのサイトが保持してたんで、パッケージを作成出来たんだな。世は無常也。

一応、インストールログを確認。

=> rfc-3.2.3.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch http://www.dewn.com/rfc/rfc-3.2.3.tar.gz
fetch: http://www.dewn.com/rfc/rfc-3.2.3.tar.gz: No address record
=> Attempting to fetch http://distcache.FreeBSD.org/ports-distfiles/rfc-3.2.3.tar.gz

偉いなあ、FreeBSD。ちゃんと世界遺産を保存してくれているよ。

ntpsec

世の中には、こんなのも有るとな。

[sakae@fb /usr/ports/net]$ cat ntpsec/pkg-descr
A reimplementation of the NTP protocol daemon and tools in a secure way.

A major new feature is that it implements IETF's Network Time Security standard
for strong cryptographic authentication of time service.

Security improvements:
* Network Time Security is implemented.
* The deprecated ntpdc utility, long a chronic locus of security
  vulnerabilities, has been removed
* Autokey is not supported; that code has been removed, as it was chronically
  prone to security vulnerabilities.
* Peer mode has been removed. The keyword peer in ntp.conf is now just an alias
  for keyword server.
* Broadcast- and multicast modes, which are impossible to secure, have been
  removed.
* The authentication requirement for remote configuration commands (e.g., via
  ntpq) can no longer be disabled.
* The deprecated and vulnerability-prone ntpdate program has been replaced with
  a shell wrapper around ntpdig.

WWW: https://gitlab.com/NTPsec/ntpsec/

こういうのを見ると、ntpは悪人にとって格好の餌食、餌場って事が伺える。それで、穴を塞ぎましょう運動があちこちで発生してるとな。

[sakae@fb /usr/ports/net/ntpsec]$ cat distinfo
TIMESTAMP = 1578632226
SHA256 (ntpsec-ntpsec-NTPsec_1_1_8_GH0.tar.gz) = 1becbdeeadb83e06893d049fae8e7ced7e34bf2ef4e0617fb9e04f1a711f6d1d
SIZE (ntpsec-ntpsec-NTPsec_1_1_8_GH0.tar.gz) = 2534248

こんなサイズです。この他にpythonのntp*.pyって助けを必要としてるみたい。でも、openntpdに比べて、随分大きいな。穴無いのかしら?

cont

上の資料中にVFOなんて言う懐かしい名前が出て来た。アマチュア無線やってる人なら知ってるだろうけど、日本語に直すと、可変周波数発生器だ。

これとntpにどんな関係が有るの? 深掘りしたいけど、紙面が足りないので、次回に回す。