はじめに
時計大事ですよね。
私の持っているandroidはWifi専用運用のため、時刻を合わせることができず、困っておりました。
SIMがささっていれば、携帯基地局から時刻を取得することができるようなのですが、SIMすらないので、簡単に時刻がズレてしまいます。
root化するという手もあるかもしれませんが、あまりやりたくはないです。
これを何とかしようとGoogleさんに色々が聞いてみましたが、かなりハマったので、記録しておこうと思います。
環境
- Pixel 5a(SIMフリー版)
- Android 12
- SIMカードなし・Wifi接続のみ
- LAN外のNTPサーバーは参照不可
DNSサーバーをLAN内にたてる方法(失敗)
Googleで「android ntp time sync」とかで調べると、どうも簡単には時刻同期できないということがすぐに分かりました。
もう少し調べてみると、情報としては古いですが、Android 4.1以降では、2.android.pool.ntp.orgにNTPサーバーがハードコーディングされているという情報も出てきました。なるほど、それでは、LAN外のNTPサーバーを参照できない当方の環境では時刻同期しないわけです(と、この時は一度は納得する)。
そこで、下記ページでは、DNSサーバーをLAN内に立てて、androidが参照するNTPのアドレスをLAN内のNTPサーバーに向かわせるように上書きするという方法をとっていました。
https://syn.cocolog-nifty.com/access/2014/10/udpandroid-8ea5.html
少々トリッキーですが、私もこの作戦をやってみます(この後失敗します)。
DNSサーバーとしては、適当なUbuntu serverを用意して、Bind9を使ってサーバーを立てました。
環境としては、下記になります。
- LAN: 192.168.8.0/24
- DNS(Ubuntu 20.04): 192.168.8.1
- android(Android12): 192.168.8.2
- NTP:192.168.8.3
まずは、BINDをインストールします。
sudo apt install bind9 bind9utils
インストールはとても簡単です。
さて、今回は、特定のURLだけLAN内のNTPサーバーに向かわせて、それ以外は外部のDNSサーバーにフォワードさせるという設定になります。これを実現するには、Response Policy Zone (RPZ)という機能を使うようです。以下、その設定を行っていきます。
まず、以下のような設定ファイルに修正します。
acl mynetwork {
192.168.8.0/24;
};
options {
directory "/var/cache/bind";
// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113
// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.
forwarders {
8.8.8.8;
};
forward only;
allow-recursion { localhost; mynetwork; };
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation no;
allow-query {localhost; mynetwork; };
listen-on port 53 {127.0.0.1; 192.168.8.1; };
listen-on-v6 { any; };
response-policy { zone "rpz.zone"; };
};
設定ファイルにあるacl
は、単なる設定ファイル中でのネットワーク名をaliasするもののようです。
ポイントは、forwardersとresponse-policyです。forwardersに適当な外部のDNSサーバーを設定しておくことで、今回たてるDNSサーバーで名前解決できないときにそちらを参照してくれます。また、response-policyは、BIND9でのRPZ機能のことで、ここでrpz.zone
という名前のゾーンの設定に従って、ドメイン名を上書きします。
allow-query は問い合わせを受け付ける範囲を記述します。セキュリティリスクを抑えるため、LAN内のみ許可にした方が良いと思います。
次に、rpz.zoneを以下のファイルに定義します。
zone "rpz.zone" {
type master;
file "/etc/bind/rpz.zone";
};
そして、rpz.zoneにドメイン書き換えのレコードを書いていきます。
ひとまず、androidが参照していそうなNTPのドメイン名を思いつく限り列挙して、全てLAN内のNTPサーバー(192.168.8.3)に向かわせます。
$TTL 86400
@ IN SOA localhost. root.localhost. (
2022090900 ;Serial
3600 ;Refresh
1800 ;Retry
604800 ;Expire
86400 ;Minimum TTL
)
@ IN NS localhost.
android.pool.ntp.org IN A 192.168.8.3
*.android.pool.ntp.org IN A 192.168.8.3
pool.ntp.org IN A 192.168.8.3
*.pool.ntp.org IN A 192.168.8.3
time.google.com IN A 192.168.8.3
*.time.google.com IN A 192.168.8.3
time.android.com IN A 192.168.8.3
*.time.android.com IN A 192.168.8.3
念のため、下記の設定ファイルで/etc/bind/named.conf.local
を読み込んでいるかどうか確かめておきます。
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
一通りの設定が完了したら、bind9を再起動します。
sudo systemctl restart named
なお、設定ファイルの記入ミス等はnamed-checkconf
コマンドやnamed-checkzone
コマンドで確認できます。
うまくDNSが設定できたかどうかを確かめるために、適当なPC(192.168.8.4)からDNSサーバー(192.168.8.1)にntpサーバーのドメインのみ上書きできているかどうか確かめてみます。
host time.android.com
# Using domain server:
# Name: 192.168.8.1
# Address: 192.168.8.1#53
# Aliases:
#
# time.android.com has address 192.168.8.3
host google.com
# Using domain server:
# Name: 192.168.8.1
# Address: 192.168.8.1#53
# Aliases:
#
# google.com has address 172.217.161.78
# google.com has IPv6 address 2404:6800:4004:80b::200e
# google.com mail is handled by 10 smtp.google.com.
良さそうですね。
さて、これにてうまくいくと思って意気揚々とandroidでWifi接続の設定にあるDNSに今回つくったサーバー(192.168.8.1)を指定して、androidを再起動したり色々とやってみますが、一向に時刻が治りません。おかしいです。
任意のNTPサーバーの時刻を参照するアプリ(NTP Time)とかをインストールしてみると、きちんと時刻表示されるのにです。androidの日付と時刻
の設定で、「日時を自動的に設定」の項目もONにしています。とほほです。
参考ページ
- https://www.server-world.info/query?os=Ubuntu_20.04&p=dns&f=1
- https://kuroneko666.hatenadiary.jp/entry/20150411/1428731971
Android studioを使って本体のNTPサーバーを指定する(成功)
困り果てて、さらにGoogleさんに質問しまくります。すると、下記ページにandroid studio を使ってうまくいった?ような記述を発見します。
https://gist.github.com/xujiaao/63cb3bbea9fe22e79206e5eb7ba82d0e
早速試してみます。
まずは、android studio をインストールします(私は元々インストールしてあるのでスキップ)。
そして、適当な空のプロジェクトを作成し、androidをワイヤレスデバックでPCに接続します(USBデバックでも良いです)。やり方は、googleに聞けばたくさん出てくるので、省略します。
次に、SDK Platform-Toolsを下記よりダウンロードして、適当な場所に展開します。
https://developer.android.com/studio/releases/platform-tools?hl=ja
android studioでpower shellを開き、展開したPlatform-Toolsの場所に移動します。
$ cd C:\Users\hoge\Downloads\platform-tools_r33.0.3-windows\platform-tools
次は、接続されているデバイスのシリアルナンバーを確認します。
$ .\adb.exe devices
List of devices attached
adb-xxxxxxxxxxxxxxxxxx._adb-tls-connect._tcp device
あとは、次のコマンドでandroidのシェルを開きます。
$ .\adb.exe -s adb-xxxxxxxxxxxxxxxxxx._adb-tls-connect._tcp shell
ここで、今の時刻同期に関する設定を確認してみます。
$ dumpsys time_detector
TimeDetectorStrategy:
mLastAutoSystemClockTimeSet=null
mEnvironment.isAutoTimeDetectionEnabled()=true
mEnvironment.elapsedRealtimeMillis()=224743
mEnvironment.systemClockMillis()=1662689471787
mEnvironment.systemClockUpdateThresholdMillis()=2000
mEnvironment.autoTimeLowerBound()=2022-05-25T22:13:51Z(1653516831000)
mEnvironment.autoOriginPriorities()=[network,telephony]
Time change log:
Telephony suggestion history:
{Empty}
Network suggestion history:
{Empty}
Gnss suggestion history:
{Empty}
External suggestion history:
{Empty}
androidのドキュメントの解説曰く、mEnvironment.autoOriginPriorities()=[network,telephony]
となっているのは、NTPがNITZよりも優先されているという意味のようでうです。それにもかかわらず、Network suggestion history
は空になっており、まったく時刻同期できていないことが分かります。なお、SIMがないので、Telephony suggestion history
は当然空になります。
となると、気になるのは、今なんのNTPサーバーを参照しているのか、ということになります。調べてみると、
$ settings get global ntp_server
null
なんと!参照先のNTPサーバーがそもそも存在していません。驚きましたが、これでは何やっても時刻同期しないのは当たり前です。
ここで、LAN内のNTPサーバーを指定してあげます。
$ settings put global ntp_server 192.168.8.1
$ settings get global ntp_server
192.168.8.1
これにて、あっさり時計が合いました。めでたし。
参考ページ
- https://source.android.com/devices/tech/connect/time-source?authuser=1&hl=ja
- https://developer.android.com/studio/command-line/adb?hl=ja
- https://gist.github.com/xujiaao/63cb3bbea9fe22e79206e5eb7ba82d0e
- https://techacademy.jp/magazine/2989
余談
ところで、今回の問題解決に至る前に不思議な現象も確認できました。
きちんとSIMをさしてあるスマホのデザリングにWifi接続すると、なぜか時刻同期に成功するのです。NTPサーバーは何も参照していないはずにもかかわらずです。謎です。