tinc というものを使えば簡単に VPN ができるようなので試してみました。
クライアント/サーバ型で VPN 作ります。クライアント・サーバともに CentOS 7 です。VPN の端点は次の通り IP アドレスにします。
- Server: 192.169.255.1
- Client: 192.169.255.2
tinc はホストが元々持っている NIC とは別に TUN デバイスを作成してその TUN 同士を接続します。TUN というのは L3 をエミュレーションする仮想デバイスです。OpenVPN や OpenSSL で作る VPN もだいたい同じ仕組みなので Linux でソフトウェア VPN といえば TUN なのかもしれません。なお TAP という L2 をエミュレーションする仮想デバイスもあるのですが今回は使いません。
インストール
tinc は CentOS 7 なら epel からインストールできます。
yum install -y epel-release yum install -y tinc
以下のファイルが含まれていました。
rpm -ql tinc # /usr/lib/systemd/system/tinc.service # /usr/lib/systemd/system/tinc@.service # /usr/sbin/tincd # /usr/share/doc/tinc-1.0.35 # /usr/share/doc/tinc-1.0.35/AUTHORS # /usr/share/doc/tinc-1.0.35/COPYING.README # /usr/share/doc/tinc-1.0.35/NEWS # /usr/share/doc/tinc-1.0.35/README # /usr/share/doc/tinc-1.0.35/THANKS # /usr/share/doc/tinc-1.0.35/sample-config # /usr/share/doc/tinc-1.0.35/sample-config/hosts # /usr/share/doc/tinc-1.0.35/sample-config/hosts/alpha # /usr/share/doc/tinc-1.0.35/sample-config/hosts/beta # /usr/share/doc/tinc-1.0.35/sample-config/rsa_key.priv # /usr/share/doc/tinc-1.0.35/sample-config/tinc-down # /usr/share/doc/tinc-1.0.35/sample-config/tinc-up # /usr/share/doc/tinc-1.0.35/sample-config/tinc.conf # /usr/share/doc/tinc-1.0.35/texinfo.tex # /usr/share/info/tinc.info.gz # /usr/share/licenses/tinc-1.0.35 # /usr/share/licenses/tinc-1.0.35/COPYING # /usr/share/man/man5/tinc.conf.5.gz # /usr/share/man/man8/tincd.8.gz
サーバの設定
まずはサーバを設定します。
作成する VPN に関係するファイルを配置するディレクトリを作成します。このディレクトリの名前は最後に行う tuncd
の -n
オプションの名前になります(systemd のテンプレートユニットのパラメータ部分でもあります)。
mkdir -p /etc/tinc/my_vpn/hosts
tinc が開始したときと終了したときに実行されるスクリプトを作成します。このスクリプトで TUN デバイスのアクティブ化や IP アドレスの設定を行います。tinc が開始する前は TUN デバイスがまだ無いので開始時に行う必要があります。
cat <<'EOS'> /etc/tinc/my_vpn/tinc-up #!/bin/sh ip link set $INTERFACE up ip addr add 192.168.255.1/32 dev $INTERFACE ip route add 192.168.255.0/24 dev $INTERFACE EOS cat <<'EOS'> /etc/tinc/my_vpn/tinc-down #!/bin/sh ip route del 192.168.255.0/24 dev $INTERFACE ip addr del 192.168.255.1/32 dev $INTERFACE ip link set $INTERFACE down EOS chmod +x /etc/tinc/my_vpn/tinc-up chmod +x /etc/tinc/my_vpn/tinc-down
tinc の設定ファイルを作ります。Name
は /etc/tinc/my_vpn/hosts/
に作成するファイル名と一致する必要があります。Device
には TUN デバイスを指定します。/dev/net/tun
とすれば良いようです。
cat <<'EOS'> /etc/tinc/my_vpn/tinc.conf Name = server Device = /dev/net/tun EOS
次にこのサーバのホスト設定ファイルを作成します。前述の通り↑の Name
と一致している必要があります。Address
にはクライアントから見たサーバの IP アドレスを、Subnet
はこの VPN 上でのネットワークアドレスを指定します。
cat <<EOS> /etc/tinc/my_vpn/hosts/server Address = 203.0.113.100 Subnet = 192.168.255.0/24 EOS
サーバの認証用の RSA 鍵を作成します。
tincd -n my_vpn -K4096
↑のコマンドでサーバのホスト設定ファイルに公開鍵が追記されます。
cat /etc/tinc/my_vpn/hosts/server
クライアントの設定
次にクライアントを設定します。ディレクトリや開始・終了のスクリプトの作成はサーバと同じです。ただし、スクリプトにはクライアント側の IP アドレスを記載する必要があります。
mkdir -p /etc/tinc/my_vpn/hosts cat <<'EOS'> /etc/tinc/my_vpn/tinc-up #!/bin/sh ip link set $INTERFACE up ip addr add 192.168.255.2/32 dev $INTERFACE ip route add 192.168.255.0/24 dev $INTERFACE EOS cat <<'EOS'> /etc/tinc/my_vpn/tinc-down #!/bin/sh ip route del 192.168.255.0/24 dev $INTERFACE ip addr del 192.168.255.2/32 dev $INTERFACE ip link set $INTERFACE down EOS chmod +x /etc/tinc/my_vpn/tinc-up chmod +x /etc/tinc/my_vpn/tinc-down
tinc の設定ファイルを作ります。クライアントは ConnectTo
で接続するサーバ名を指定します。この名前も /etc/tinc/my_vpn/hosts/
の中のファイル名に一致する必要があります。その他はサーバと特に変わりありません。
cat <<'EOS'> /etc/tinc/my_vpn/tinc.conf Name = client Device = /dev/net/tun ConnectTo = server EOS
クライアントのホスト設定ファイルを作成します。クライアントは Address
は不要です。Subnet
には VPN 接続上のこのホストの IP アドレスを指定します。
cat <<EOS> /etc/tinc/my_vpn/hosts/client Subnet = 192.168.255.2/32 EOS
認証用の RSA 鍵を作成します。
tincd -n my_vpn -K4096
↑のコマンドでクライアントのホスト設定ファイルに公開鍵が追記されます。
cat /etc/tinc/my_vpn/hosts/client
ホストの設定ファイルの交換
何らかの方法でサーバとクライアントのホスト設定ファイルをコピーします。
- サーバの
/etc/tinc/my_vpn/hosts/server
をクライアントの同ディレクトリにコピー - クライアントの
/etc/tinc/my_vpn/hosts/client
をサーバの同ディレクトリにコピー
クライアント・サーバともに次のようなディレクトリ構成になります。
/etc/tinc/my_vpn/ ├── hosts │ ├── client │ └── server ├── rsa_key.priv ├── tinc.conf ├── tinc-down └── tinc-up
VPN の開始
クライアントとサーバの両方で tincd をお試しで開始します。
tincd -n my_vpn -D -d3
起動に成功して接続も問題なさそうなら殺します。
pkill tincd
systemd でサービスとして実行します。
systemctl start tinc@my_vpn.service systemctl status tinc@my_vpn.service systemctl enable tinc@my_vpn.service
相互に ping が通れば成功です。
ping -n 192.168.255.1 ping -n 192.168.255.2
サーバで NAT して VPN 経由で外に出る
これだけだとサーバとクライアントが P2P で繋がっているだけなので、クライアントから VPN を通ってサーバを経由して外に出られるようにしてみます。
まず、サーバのホスト設定ファイルで Subnet = 0.0.0.0/0
を追加します。これはクライアントとサーバの両方で行います。
vim /etc/tinc/my_vpn/hosts/server
Address = 203.0.113.100 Subnet = 192.168.255.0/24 Subnet = 0.0.0.0/0 -----BEGIN RSA PUBLIC KEY----- ... -----END RSA PUBLIC KEY-----
サーバに NAT のために firewalld を入れます。
yum install -y firewalld systemctl start firewalld systemctl status firewalld systemctl enable firewalld
サーバの I/F を external にして 655 ポートを許可します。 なお、external はデフォでマスカレードが有効なので VPN 経由でこのポートから出るときに NAT されるようになります。
firewall-cmd --zone=external --add-interface=eth0 firewall-cmd --zone=external --add-port=655/tcp firewall-cmd --zone=external --add-port=655/udp firewall-cmd --runtime-to-permanent
サーバで VPN が開始したときに VPN の I/F が trusted ゾーンになるようにします。
cat <<'EOS'> /etc/tinc/my_vpn/tinc-up #!/bin/sh ip link set $INTERFACE up ip addr add 192.168.255.1/32 dev $INTERFACE ip route add 192.168.255.0/24 dev $INTERFACE firewall-cmd --zone=trusted --add-interface=$INTERFACE EOS cat <<'EOS'> /etc/tinc/my_vpn/tinc-down #!/bin/sh firewall-cmd --zone=trusted --remove-interface=$INTERFACE ip route del 192.168.255.0/24 dev $INTERFACE ip addr del 192.168.255.1/32 dev $INTERFACE ip link set $INTERFACE down EOS chmod +x /etc/tinc/my_vpn/tinc-up chmod +x /etc/tinc/my_vpn/tinc-down
次にクライアント側で VPN に接続したときにデフォルトゲートウェイが VPN を向くようにします。
cat <<'EOS'>> /etc/tinc/my_vpn/hosts/server-up #!/bin/sh ip route save match 0.0.0.0/0 > /etc/tinc/my_vpn/route.dump ip route replace default via 192.168.255.1 EOS cat <<'EOS'>> /etc/tinc/my_vpn/hosts/server-down #!/bin/sh ip route flush match 0.0.0.0/0 ip route restore < /etc/tinc/my_vpn/route.dump EOS chmod +x /etc/tinc/my_vpn/hosts/server-up chmod +x /etc/tinc/my_vpn/hosts/server-down
クライアントとサーバの両方で tinc デーモンをリスタートします。
systemctl restart tinc@my_vpn.service
クライアントでルーティングが設定されていることを確認します。
ip route list match 0.0.0.0/0 #=> default via 192.168.255.1 dev my_vpn
サーバで firewlld が設定されていることを確認します。
firewall-cmd --get-active-zone #=> external #=> interfaces: eth0 #=> trusted #=> interfaces: my_vpn
サーバで tcpdump で VPN を監視して
tcpdump -nn -i my_vpn
クライアントで適当に外部にアクセスして反応があれば OK です。
curl httpbin.org/get
あ、よく考えたら今回はクライアントとサーバが同じサブネットにあったのでガスっとデフォルトゲートウェイ変更しましたけど普通はそうじゃないのでクライアントのルーティングテーブルでサーバへの経路を確保しておく必要がありますね。
さいごに
OpenVPN と比べると ip
や firewall-cmd
で自前でネットワーク関係の構成を設定する必要があるぶん tinc
自体はシンプルですかね(OpenVPN はもっとサクッと NAT とかさせられた気がする? うろ覚え)
また、以下のように Windows でも動きそうです(未確認)(OpenVPN も Windows で動くだろうけど)
- https://www.tinc-vpn.org/examples/windows-install/
- https://chocolatey.org/packages/tinc/1.0.36.20190831
そのうち Windows でも試してみようと思います。