クライアント側でルーティングテーブルとネットワークインターフェイスの情報を表示
# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.12.1 0.0.0.0 UG 0 0 0 eth0 192.168.12.0 0.0.0.0 255.255.255.248 U 0 0 0 eth0 # ip route default via 192.168.12.1 dev eth0 192.168.12.0/29 dev eth0 proto kernel scope link src 192.168.12.6 # ifconfig eth0 Link encap:Ethernet HWaddr 00:40:26:cb:df:03 inet addr:192.168.12.6 Bcast:192.168.12.7 Mask:255.255.255.248 inet6 addr: fe80::240:26ff:fecb:df03/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:44138 errors:4 dropped:0 overruns:0 frame:4 TX packets:41098 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:51186688 (48.8 MiB) TX bytes:4085461 (3.8 MiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) # ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000 link/ether 00:40:26:cb:df:03 brd ff:ff:ff:ff:ff:ff inet 192.168.12.6/29 brd 192.168.12.7 scope global eth0 inet6 fe80::240:26ff:fecb:df03/64 scope link valid_lft forever preferred_lft forever
openvpn server に接続して、その状態でクライアントのルーティングテーブルを確認。
# /etc/init.d/openvpn start # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.20.13 128.0.0.0 UG 0 0 0 tun0 0.0.0.0 192.168.12.1 0.0.0.0 UG 0 0 0 eth0 XXX.XXX.XXX.XXX 192.168.12.1 255.255.255.255 UGH 0 0 0 eth0 128.0.0.0 192.168.20.13 128.0.0.0 UG 0 0 0 tun0 192.168.12.0 0.0.0.0 255.255.255.248 U 0 0 0 eth0 192.168.20.0 192.168.20.13 255.255.255.0 UG 0 0 0 tun0 192.168.20.1 192.168.20.13 255.255.255.255 UGH 0 0 0 tun0 192.168.20.13 0.0.0.0 255.255.255.255 UH 0 0 0 tun0 # ip route 0.0.0.0/1 via 192.168.20.13 dev tun0 default via 192.168.12.1 dev eth0 XXX.XXX.XXX.XXX via 192.168.12.1 dev eth0 128.0.0.0/1 via 192.168.20.13 dev tun0 192.168.12.0/29 dev eth0 proto kernel scope link src 192.168.12.6 192.168.20.0/24 via 192.168.20.13 dev tun0 192.168.20.1 via 192.168.20.13 dev tun0 192.168.20.13 dev tun0 proto kernel scope link src 192.168.20.14
この状態で server 側で openvpn server をリスタート。
# /etc/init.d/openvpn restart Stopping virtual private network daemon: server. Starting virtual private network daemon: server.
クライアント側の syslog をみると以下のようなログが流れて再接続に失敗。名前解決に失敗しているようなので、resolv.confを確認。
# tail -f /var/log/syslog MMM DD 22:46:24 HHHHHH ovpn-client[2182]: RESOLVE: Cannot resolve host address: XXXXXXXXXXXXXX: [TRY_AGAIN] A temporary error occurred on an authoritative name server. MMM DD 22:47:49 HHHHHH ovpn-client[2182]: RESOLVE: Cannot resolve host address: XXXXXXXXXXXXXX: [TRY_AGAIN] A temporary error occurred on an authoritative name server. MMM DD 22:49:14 HHHHHH ovpn-client[2182]: RESOLVE: Cannot resolve host address: XXXXXXXXXXXXXX: [TRY_AGAIN] A temporary error occurred on an authoritative name server. MMM DD 22:50:40 HHHHHH ovpn-client[2182]: RESOLVE: Cannot resolve host address: XXXXXXXXXXXXXX: [TRY_AGAIN] A temporary error occurred on an authoritative name server. MMM DD 22:52:05 HHHHHH ovpn-client[2182]: RESOLVE: Cannot resolve host address: XXXXXXXXXXXXXX: [TRY_AGAIN] A temporary error occurred on an authoritative name server. MMM DD 22:53:30 HHHHHH ovpn-client[2182]: RESOLVE: Cannot resolve host address: XXXXXXXXXXXXXX: [TRY_AGAIN] A temporary error occurred on an authoritative name server. ... # cat /etc/resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver NNN.NNN.NNN.NNN nameserver MMM.MMM.MMM.MMM
適当なマシン(ここではサーバ側)でクライアント側のresolv.confにあったDNSサーバを使って名前解決を試みると成功。
# dig @NNN.NNN.NNN.NNN XXXXXXXXXXXXXX ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @NNN.NNN.NNN.NNN XXXXXXXXXXXXXX ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30439 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;XXXXXXXXXXXXXX. IN A ;; ANSWER SECTION: XXXXXXXXXXXXXX. 60 IN A XXX.XXX.XXX.XXX ;; Query time: 97 msec ;; SERVER: NNN.NNN.NNN.NNN#53(NNN.NNN.NNN.NNN) ;; WHEN: ************************ ;; MSG SIZE rcvd: 48 # dig @MMM.MMM.MMM.MMM XXXXXXXXXXXXXX ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @MMM.MMM.MMM.MMM XXXXXXXXXXXXXX ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13228 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;XXXXXXXXXXXXXX. IN A ;; ANSWER SECTION: XXXXXXXXXXXXXX. 60 IN A XXX.XXX.XXX.XXX ;; Query time: 98 msec ;; SERVER: MMM.MMM.MMM.MMM#53(MMM.MMM.MMM.MMM) ;; WHEN: ************************ ;; MSG SIZE rcvd: 48
クライアント側でルーティングテーブルを再確認。openvpnサーバに接続成功後のものと全く同じということが分かる。この状態で NNN.NNN.NNN.NNN または MMM.MMM.MMM.MMM 行きのパケットはどの Iface で外に行くかを調べるには ip route getを使う。ルーティングテーブル的には tun0 でパケットを外に出そうとするが、tun0 は未接続なので失敗する。これが原因で "RESOLVE: Cannot resolve host address" が止まらないわけだ。
# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.20.13 128.0.0.0 UG 0 0 0 tun0 0.0.0.0 192.168.12.1 0.0.0.0 UG 0 0 0 eth0 XXX.XXX.XXX.XXX 192.168.12.1 255.255.255.255 UGH 0 0 0 eth0 128.0.0.0 192.168.20.13 128.0.0.0 UG 0 0 0 tun0 192.168.12.0 0.0.0.0 255.255.255.248 U 0 0 0 eth0 192.168.20.0 192.168.20.13 255.255.255.0 UG 0 0 0 tun0 192.168.20.1 192.168.20.13 255.255.255.255 UGH 0 0 0 tun0 192.168.20.13 0.0.0.0 255.255.255.255 UH 0 0 0 tun0 # ip route 0.0.0.0/1 via 192.168.20.13 dev tun0 default via 192.168.12.1 dev eth0 XXX.XXX.XXX.XXX via 192.168.12.1 dev eth0 128.0.0.0/1 via 192.168.20.13 dev tun0 192.168.12.0/29 dev eth0 proto kernel scope link src 192.168.12.6 192.168.20.0/24 via 192.168.20.13 dev tun0 192.168.20.1 via 192.168.20.13 dev tun0 192.168.20.13 dev tun0 proto kernel scope link src 192.168.20.14 # ip route get NNN.NNN.NNN.NNN NNN.NNN.NNN.NNN via 192.168.20.13 dev tun0 src 192.168.20.14 cache # ip route get MMM.MMM.MMM.MMM MMM.MMM.MMM.MMM via 192.168.20.13 dev tun0 src 192.168.20.14 cache
これを解決するには、クライアント側で /etc/init.d/openvpn restart を行う方法が考えられる。しかし、サーバ側の openvpn 再起動や、IP アドレスの変化に伴って毎回クライアント側の再起動が必要になるため、クライアント側を操作する方法が限られているケースだとこの解決策は採用しづらい。そこで、DNS サーバへのアクセスだけは VPN を通らないような静的ルーティングをクライアント側に設定する。
# echo "route NNN.NNN.NNN.NNN 255.255.255.255 net_gateway 0" >> client.conf # echo "route MMM.MMM.MMM.MMM 255.255.255.255 net_gateway 0" >> client.conf
設定が終わったらクライアント側で client を再起動し、ルーティングの確認。NNN.NNN.NNN.NNN および MMM.MMM.MMM.MMM へのパケットは eth0 を通って外に出るようになったことが分かる。
# /etc/init.d/openvpn restart Stopping virtual private network daemon: client. Starting virtual private network daemon: client. # route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.20.13 128.0.0.0 UG 0 0 0 tun0 0.0.0.0 192.168.12.1 0.0.0.0 UG 0 0 0 eth0 XXX.XXX.XXX.XXX 192.168.12.1 255.255.255.255 UGH 0 0 0 eth0 128.0.0.0 192.168.20.13 128.0.0.0 UG 0 0 0 tun0 192.168.12.0 0.0.0.0 255.255.255.248 U 0 0 0 eth0 192.168.20.0 192.168.20.13 255.255.255.0 UG 0 0 0 tun0 192.168.20.1 192.168.20.13 255.255.255.255 UGH 0 0 0 tun0 192.168.20.13 0.0.0.0 255.255.255.255 UH 0 0 0 tun0 NNN.NNN.NNN.NNN 192.168.12.1 255.255.255.255 UGH 0 0 0 eth0 MMM.MMM.MMM.MMM 192.168.12.1 255.255.255.255 UGH 0 0 0 eth0 # ip route show 0.0.0.0/1 via 192.168.20.13 dev tun0 default via 192.168.12.1 dev eth0 XXX.XXX.XXX.XXX via 192.168.12.1 dev eth0 128.0.0.0/1 via 192.168.20.13 dev tun0 192.168.12.0/29 dev eth0 proto kernel scope link src 192.168.12.6 192.168.20.0/24 via 192.168.20.13 dev tun0 192.168.20.1 via 192.168.20.13 dev tun0 192.168.20.13 dev tun0 proto kernel scope link src 192.168.20.14 NNN.NNN.NNN.NNN via 192.168.12.1 dev eth0 MMM.MMM.MMM.MMM via 192.168.12.1 dev eth0 # ip route get NNN.NNN.NNN.NNN NNN.NNN.NNN.NNN via 192.168.12.1 dev eth0 src 192.168.12.6 cache # ip route get MMM.MMM.MMM.MMM MMM.MMM.MMM.MMM via 192.168.12.1 dev eth0 src 192.168.12.6 cache
この状態でサーバ側でマシンの再起動やopenvpnの再起動を行う。適当な時間後にクライアントが接続していることを確認する。
# /etc/init.d/openvpn restart Stopping virtual private network daemon: server. Starting virtual private network daemon: server. # cat /etc/openvpn/openvpn-status.log OpenVPN CLIENT LIST Updated,************************ Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since *******,192.168.12.6:34799,9336,9722,************************ ROUTING TABLE Virtual Address,Common Name,Real Address,Last Ref 192.168.20.14,*******,192.168.12.6:34799,************************ GLOBAL STATS Max bcast/mcast queue length,0 END
上に挙げた NNN.NNN.NNN.NNN や MMM.MMM.MMM.MMM は組織の提供する DNS サーバのアドレスである。可能であれば DNS だって組織の監視から逃れたいわけで、正直に DNS 問い合わせを組織の監視下に置く必要はないし、組織がアドレスを変えると再設定が必要になる。このようなケースを避けるために public dns を使うことを考える。以下の設定を client.conf に追加することで、dns 問い合わせは public dns を使うようになり、そのトラフィックは静的ルーティングで VPN ではない経路をたどるようになる。
dhcp-option DNS 129.250.35.250 dhcp-option DNS 8.8.8.8 dhcp-option DNS 129.250.35.251 dhcp-option DNS 8.8.4.4 route 129.250.35.250 255.255.255.255 net_gateway 0 route 8.8.8.8 255.255.255.255 net_gateway 0 route 129.250.35.251 255.255.255.255 net_gateway 0 route 8.8.4.4 255.255.255.255 net_gateway 0 script-security 2 up /etc/openvpn/update-resolv-conf down /etc/openvpn/update-resolv-conf
最終的なクライアント用設定ファイルと雛形との差分は以下。
# diff /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/client.conf 36,37c36,37 < ;proto tcp < proto udp --- > proto tcp > ;proto udp 42c42 < remote my-server-1 1194 --- > ;remote my-server-1 1194 43a44 > remote XXXXXXXXXXXXXX 443 89,90c90,91 < cert client.crt < key client.key --- > cert client2.crt > key client2.key 123a125,136 > > dhcp-option DNS 129.250.35.250 > dhcp-option DNS 8.8.8.8 > dhcp-option DNS 129.250.35.251 > dhcp-option DNS 8.8.4.4 > route 129.250.35.250 255.255.255.255 net_gateway 0 > route 8.8.8.8 255.255.255.255 net_gateway 0 > route 129.250.35.251 255.255.255.255 net_gateway 0 > route 8.8.4.4 255.255.255.255 net_gateway 0 > script-security 2 > up /etc/openvpn/update-resolv-conf > down /etc/openvpn/update-resolv-conf
DNS問い合わせ時に秘密が漏れることが問題。サーバをDDNSではなく固定アドレスで運用すればこのような問題は起きない。すべてのクライアントをこのような設定にするのではなく、手動で再起動がしづらいクライアントだけにこのような設定を行うべきである。