ntp (Network Time Protocol)

[ 戻る | トップページに戻る ]

概要

ntp とは NTP (Network Time Protocol) および SNTP (Simple Network Time Protocol) による時刻同期のためのサーバー、および クライアントである。MS Windows の桜時計などのサーバーになることも可能。

URL

http://www.eecis.udel.edu/~ntp/

インストール環境

Plamo Linux 1.4.4 (Kernel 2.2.10 + libc5)
Plamo Linux 2.2.1 (Kernel 2.2.19 + glibc 2.2)
Slackware 7.0 (Kernel 2.2.14 + glibc 2.1.2)
Solaris 8
Digital UNIX V4.0E (Alpha)

必要なもの

特になし

バージョン

4.0.98h, 4.0.99k, 4.0.99k23, 4.1.71, 4.1.1

インストール手順 (for Plamo Linux 1.4.4 / Slackware 7.0)

$ tar xvfz ntp-4.0.98h.tar.gz
$ cd ntp-4.0.98h
$ ./configure
$ make
$ make check
$ su
# make install
# exit

クライアントとして NTP サーバに接続する場合には cron 等で ntpdate を実行する。 cron の設定例は以下の通り。
0 * * * * /usr/local/bin/ntpdate -s ntp.hoge.co.jp

NTP サーバとして動作させる場合には /etc/ntp.conf ファイルを作成する。 内容は以下のとおり。
server xxx.xxx.xxx.xxx      <--- タイムサーバーのアドレス
driftfile /etc/ntp.drift

次に /etc/rc.d/rc.local に以下のエントリを追加する。
if [ -f /usr/local/bin/ntpd ]; then
  echo -n "Starting NTP server "
  /usr/local/bin/ntpd
  echo "."
fi

ntpd を起動。しばらくすると /etc/ntp.drift ができた。 この状態で Windows ホストで桜時計 Ver.0.2.1 を起動する。が...
交信開始...
length=48 addr=xxx.xxx.xxx.xxx:123
LI3 VN4 MODE4 Stratum0 Poll0 Precision-16
サーバーの準備がまだのようです(LI=ALARM)

と表示されてしまう。この時、NTP サーバーの動作を確認すると...
$ ntpq xxx.xxx.xxx.xxx
ntpq> pe
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ntpserver           0.0.0.0     16 u  686 1024    0    0.000    0.000 4000.00
ntpq> rv
status=c011 sync_alarm, sync_unspec, 1 event, event_restart,
processor="i686", system="Linux2.2.10", leap=11, stratum=16,
precision=-16, rootdelay=0.000, rootdispersion=70.200, peer=0,
refid=0.0.0.0, reftime=00000000.00000000  Thu, Feb  7 2036 15:28:16.000,
poll=6, clock=bc0c52f9.74d0bb6e  Thu, Dec 23 1999 16:51:21.456, state=1,
phase=0.000, frequency=0.000, jitter=0.000, stability=0.000
ntpq> quit

うーん。precision がマイナスだから? いつまで待てばいいのだろう? /var/log/messages には以下のログしか出ていない
Dec 23 15:33:20 host ntpd[9130]: ntpd 4.0.98h Thu Dec 23 14:32:09 JST 1999 (1)
Dec 23 15:33:20 host ntpd[9130]: precision = 18 usec
Dec 23 15:33:20 host ntpd[9130]: using kernel phase-lock loop 0040

ものすごく待った。6H 近いのか...。ちょい変化があった。
$ cat ntp.drift
3.530

$ ntpq
ntpq> pe
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*ntpserver      xxx.xxx.xxx.xxx   4 u  232  512  377    2.317   43.246  17.635
ntpq> rv
status=0664 leap_none, sync_ntp, 6 events, event_peer/strat_chg,
processor="i686", system="Linux2.2.10", leap=00, stratum=5,
precision=-16, rootdelay=60.545, rootdispersion=164.937, peer=65060,
refid=ntpserver.hoge.co.jp,
reftime=bc0c8cbd.42cd39da  Thu, Dec 23 1999 20:57:49.260, poll=9,
clock=bc0c8dab.e38af3e4  Thu, Dec 23 1999 21:01:47.888, state=4,
phase=43.246, frequency=7.961, jitter=32.337, stability=0.462

桜時計を確認すると...おお、同期できている。やり。 しかし、何故こんなに時間がかかるのだ。
[linux-users:63745] に詳しい説明があるのだが、要はその ntpd が参照している ntp サーバーとの間で連続して一定回数以上、正常な応答が得られないと、 その ntpd 自身が他のホストに時刻情報を提供することはないということらしい。 具体的には、ntpq -p した時に reach のエントリに 5 回以上連続して受信に成功して いることを表す 37, 77, 177, 377 のいずれかが表示されている必要がある。 時間で言えば、タイムソースに対する問い合わせは poll に表示されている秒数毎に 行われるので poll x 5 [sec.] は安定して時刻が取得できる必要があるということ。
$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*ntpserver     xxx.xxx.xxx.xxx    5 u   45   64  377    1.222   21.993   0.568

そういえば poll の値。最初は 1024 で、次は 512 。今は 64 になってる。 むぅ。これって自動的に調節される...のか?

インストール手順 (4.0.99k23〜 on Slackware)

$ tar xvfz ntp-4.0.99k23.tar.gz
$ cd ntp-4.0.99k23
$ ./configure
(snip)
checking if we'll use clock_settime or settimeofday or stime... settimeofday()
configure: WARNING: *** But clock_settime() would be better (if we had it) ***
(snip)

まあ、しようがないか。clock_settime なんてないんだもの。
$ make
$ make check
$ su
# make install
# exit

インストール手順 (for Digital UNIX 4.0E)

$ tar xvfz ntp-4.0.98h.tar.gz
$ cd ntp-4.0.98h
$ ./configure
$ make
(snip)
gcc  -g -O2 -Wall -Wshadow -Wconversion -Wpointer-arith -Wcast-qual -Wstrict-prototypes
     -o ntptime  ntptime.o ../libntp/libntp.a -lrt -lmld
No suffix list.
Compiling with GCC now generates lots of new warnings.

Don't be concerned. They're just warnings.

Don't send bug reports about the warnings, either.

Feel free to send patches that fix these warnings, though.

cd .  && CONFIG_FILES=Makefile CONFIG_HEADERS= /bin/sh ./config.status
creating Makefile

うーん、いっぱい warning が出たけど、まいいか。
$ make check
No suffix list.
Making check in scripts
No suffix list.
Making check in include
No suffix list.
Making check in libntp
Making check in libparse
Making check in librsaref
Making check in ntpd
make
make  check-local
LOCK:  -z ""
 || ./
sh: コマンド使用エラー 行番号 1: `||' が予期されませんでした。

*** Exit 2
Stop.
*** Exit 1
Stop.
*** Exit 1
Stop.

むむ。何故か Linux と Digital UNIX の /bin/sh では動作が違う。後者だと上記の エラーになっちゃう。 ちなみに該当箇所は ./ntp-4.0.98h/ntpd/Makefile の以下の箇所。
check-local:
        [ -z "" ] || ./

うーん。このターゲット意味あるのか? 特に必要とも思われないので削除してしまう。
check-local:
#         [ -z "" ] || ./     <--- コメントアウト

では、もう一度 make check から。
$ make check
(snip)
Making check in parseutil
make  check-local
source='dcfd.c' object='dcfd.o' libtool=no  depfile='.deps/dcfd.Po' tmpdepfile='.deps/dcfd.TPo'
        depmode=gcc /bin/sh ../depcomp  gcc -DHAVE_CONFIG_H -I. -I. -I.. -I../include
        -g -O2 -Wall -Wshadow -Wconversion -Wpointer-arith -Wcast-qual
        -Wstrict-prototypes -c -o dcfd.o dcfd.c
dcfd.c: In function `cvt_rawdcf':
dcfd.c:568: warning: int format, different type arg (arg 3)
dcfd.c: In function `adjust_clock':
dcfd.c:1023: warning: suggest parentheses around && within ||
dcfd.c: In function `check_y2k':
dcfd.c:1290: warning: long unsigned int format, different type arg (arg 4)
dcfd.c: In function `rawdcf_init':
dcfd.c:1368: warning: passing arg 2 of `ioctl' with different width due to prototype
dcfd.c: In function `main':
dcfd.c:1591: warning: assignment from incompatible pointer type
dcfd.c:1664: warning: passing arg 3 of `read' with different width due to prototype
dcfd.c:1680: warning: suggest parentheses around && within ||
gcc -g -O2 -Wall -Wshadow -Wconversion -Wpointer-arith -Wcast-qual -Wstrict-prototypes -o dcfd
    dcfd.o -lrt -lmld
./dcfd -Y
  starting year 1998
  ending year   3100
2098: dcf_to_unixtime(1998,0) FAILURE: was=883612800 s/b=18446744073453957120  (1139207296)
(snip)

FAILURE? しようがない。ソースを見てみるか。 vi で ./ntp-4.0.98h/parseutil/dcfd.c を開くと...
"dcfd.c"不完全なあるいは無効なマルチバイト文字があります。変換に失敗しました。

あれ? less だとちゃんと見える。Linux では vi でも大丈夫。むむ。まあいいや。
調べてみると、check_y2k() の以下の部分でエラーになっている。
       if ( year >= YEAR_PIVOT+1900 )
       {
           /* check year % 100 code we put into dcf_to_unixtime() */
           ct.year = year % 100;
           Flag = 0;

           Observed = dcf_to_unixtime( &ct, &Flag );

           if ( Observed != Expected  ||  Flag )
           {   /* time difference */
               fprintf( stdout,
"%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
                  year, (int)ct.year, (int)Flag,
                  (unsigned long)Observed, (unsigned long)Expected,
                  ((long)Observed - (long)Expected) );
               Error(year);
               break;
           }

実行時にいくつかの変数をモニタしてみると...
year = 2036  t = 24106  Expected = 2082758400
year = 2037  t = 24472  Expected = 2114380800
year = 2038  t = 24837  Expected = 2145916800
year = 2039  t = 25202  Expected = -2117514496
year = 2040  t = 25567  Expected = -2085978496
year = 2041  t = 25933  Expected = -2054356096
(snip)
year = 2095  t = 45656  Expected = -350288896
year = 2096  t = 46021  Expected = -318752896
year = 2097  t = 46387  Expected = -287130496
year = 2098  t = 46752  Expected = -255594496
2098: dcf_to_unixtime(1998,0) FAILURE: was=883612800 s/b=18446744073453957120  (1139207296)

ふむ。year = 2039 で Expected の値がマイナスになっちゃっている。 これって 2036 年問題 (32bit な time_t のオーバーフロー) と関係ある? time_t が unsigned int な場合、2039 年がオーバーフロー。 ソースを見ると time_t を unsigned long だと期待しているようだけれど....。 調べてみると Digital UNIX では typedef int time_t; と定義されている。 このマシンは Alpha なので int は 32 bit だが、long は 64 bit である。 ちなみに Linux では typedef long time_t; になっている。こっちは int も long も 32 bit (x86 の場合) 。
そうそう。FAILURE と表示されている行で s/b が変な値になっているのは、 time_t(= int) を unsigned long として出力しているから。うーむ。

でも FAILURE になってるのは、2098 だけなんだよなぁ。 dcfd.c の先頭に以下の定義を追加しても現象変わらず。うーん、やっぱりこれだけ じゃあだめかぁ。
#define _TIME_T
typedef long    time_t;

Linux での動作を調べてみると、starting year 1998, ending year 2036 となって いる。むむ。どうやら (unsigned) long のサイズが Digital UNIX だと (というか Alpha だと) 64 bit なので、ending year が 3100 になるらしい。
int  year;                  /* current working year */
int  year0 = 1900;          /* sarting year for NTP time */
(snip)
year = ( sizeof( u_long ) > 4 )     /* save max span using year as temp */
            ? ( 400 * 3 )           /* three greater gregorian cycles */
            : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
                    /* NOTE: will automacially expand test years on
                     * 64 bit machines.... this may cause some of the
                     * existing ntp logic to fail for years beyond
                     * 2036 (the current 32-bit limit). If all checks
                     * fail ONLY beyond year 2036 you may ignore such
                     * errors, at least for a decade or so. */
yearend = year0 + year;

Linux でも強制的に ending year を 3100 にすると同じ現象になる。 ...という事でぇ、2036 年以降の動作なんて...無視だぁ。(^^;
# 2036 年移行でもちゃんと動くようなパッチをあてるほどの暇はない。それに このマシンは NTP サーバーにするつもりはないし。

上記ソースの最後に yearend = 2036; を追加して、make check を通してしまう。 あとは設定。実はこのマシン、xntpd が動いているのだが、ネットワーク環境の変更 により単なる NTP クライアント化することになったので、まずは xntpd を止める。
/etc/rc.config を以下のように修正する。すでに動いている xntpd も止める。
XNTPD_CONF="NO"        <--- NO に変更
#export XNTPD_CONF          以下、NTP 部分をすべてコメントアウト
#XNTP_SERV1="ntpserver.hoge.co.jp"
#export XNTP_SERV1
#XNTP_SERV2="host2"
#export XNTP_SERV2
#XNTP_SERV3="host3"
#export XNTP_SERV3
#XNTPD_OPTS="-g"
#export XNTPD_OPTS

あとは root の crontab に以下のエントリを追加しておしまい。
0 * * * * /usr/local/bin/ntpdate -s ntpserver.hoge.co.jp

[ 戻る | トップページに戻る ]