世界中で新型コロナウイルスが拡がっていますが、私の住むバンコクでも、娯楽施設を中心として人が集まる施設の封鎖が命じられ、会社はリモートワーク(Work From Home)に切り替え、タイ入国には非感染証明書を求められ(日本では健常者に発行していない)、事実上国外へ移動できない生活が始まりました。
外食もできず、夜な夜な飲み歩くこともできず、家に引きこもり生活になったので、以前トライしたものの実用性が低すぎたVPN接続に代わって、興味本位でプロキシのブリッジを組んでみました。
作りたいネットワーク
用意したもの
サーバー側(日本)
すでに構築済みになりますが、Linuxが入っているマシンと、インターネット環境を用意しました。(前回と同じ)
- インターネット回線(NTTフレッツ光、固定IPがもらえる某プロバイダ)
- ルーター(中古のRTX1100)
- 自作PC(Debian Linux 10)
ブリッジ側(海外)
Raspberry Pi以外は前回のものを流用しました。
- インターネット回線(AIS Fibre HomeBOADBAND 50/20Mbps ※英語ページ)599THB/month(2,000円強/月)
- Raspberry Pi (新しく買ったModel 4)Raspbianインストール済み
- USB-LANアダプタ(余ってたLogitec LAN-GTJU3)
- 無線LAN中継器(余ってたTP-Link RE450)
※Raspberry Pi 4には無線LANアダプタも搭載しているので、下2つはそれに代えられると思います。
SSHによるSOCKS Proxyの接続
あらかじめ、SSHサーバー側にユーザー socks
を作成し、SSH鍵ペアを生成しておき、秘密鍵をRaspberry Piに転送しておきます。
~/.ssh/id_rsa_server.example.com_socks
に保存しました。
SSH接続時にDynamic Forwardを有効にするには、 -D スイッチを付けます。
ssh socks@server.example.com -D 1080 -i ~/.ssh/id_rsa_server.example.com_socks
これで localhost:1080
にSOCKSプロキシを立てることができましたが、さすがにこれで終わらせるわけにはいかないので、サービス化します。
[Unit]
Description=SOCKS Client (SSH DynamicForward)
ConditionPathExists=|/usr/bin
After=network.target
[Service]
Type=simple
User=pi
ExecStart=/usr/bin/ssh -gNTC -D 1080 -i /home/pi/.ssh/id_rsa_server.example.com_socks -o 'ServerAliveInterval=60' -o 'ExitOnForwardFailure=yes' -o 'StrictHostKeyChecking=no' socks@server.example.com
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
ssh
コマンドにいくつかオプションを設定していますが、以下のとおりです。
オプション | 説明 |
---|---|
-g |
port forward実施時(Local/Remote/Dynamicすべて)、 0.0.0.0 でLISTENするようになる(※もしかしたら必要ないかも?) |
-N |
リモートコマンドを実行しない(通常ログイン後の /bin/bash などを実行しない)ポートフォワード目的のみの場合に有用 |
-T |
擬似端末の割当を無効にする |
-C |
圧縮を有効にする |
-D 1080 |
Dynamic port forwardingを1080ポートで開く |
-i ファイル名 |
秘密鍵 |
-o ServerAliveInterval=60 |
60秒ごとにKeep Alive |
-o ExitOnForwardFailure=yes |
ポートフォワードに失敗したら終了する |
-o StrictHostKeyChecking=no |
ホストキーのチェックを無効にする(不要かも?) |
これを作成し、サービスを有効化、起動します。
$ sudo systemctl daemon-reload
$ sudo systemctl start socks-proxy-client
1080がLISTENできているかを確認します。
$ lsof -i:1080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ssh 983 pi 4u IPv4 19905 0t0 TCP *:socks (LISTEN)
ssh 983 pi 5u IPv6 19906 0t0 TCP *:socks (LISTEN)
Privoxy
インストール
$ sudo apt install privoxy
設定
Privoxyには、広告ブロックなどの機能もありますが、今回はそれを使うつもりがないので、無効化します。
コメント部分がとても長いので、変更した設定項目だけ抜粋します。
# 2.5. actionsfile
# ================
#
#actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.
#actionsfile default.action # Main actions file
#actionsfile user.action # User customizations
↑これら3行をコメントアウト
# 2.6. filterfile
# ================
#
#filterfile default.filter
#filterfile user.filter # User customizations
↑これら2行をコメントアウト
# 4.1. listen-address
# ====================
#
#listen-address 127.0.0.1:8118
#listen-address [::1]:8118
listen-address 0.0.0.0:8118
localhostをコメントアウトし、0.0.0.0を追加
# 5.2. forward-socks4, forward-socks4a, forward-socks5 and forward-socks5t
# =========================================================================
#
forward-socks5 / localhost:1080 .
forward 10.*.*.*/ .
forward 127.*.*.*/ .
forward 172.16.*.*/ .
forward 192.168.*.*/ .
↑追加
一度すべてのリクエストを、SOCKSに転送するが、ローカルアドレス宛の場合は転送しない。
すべてのコメント行を省くと、このようなファイルになります。
user-manual /usr/share/doc/privoxy/user-manual
confdir /etc/privoxy
logdir /var/log/privoxy
logfile logfile
listen-address 0.0.0.0:8118
toggle 1
enable-remote-toggle 0
enable-remote-http-toggle 0
enable-edit-actions 0
enforce-blocks 0
buffer-limit 4096
enable-proxy-authentication-forwarding 0
forward-socks5 / localhost:1080 .
forward 10.*.*.*/ .
forward 127.*.*.*/ .
forward 172.16.*.*/ .
forward 192.168.*.*/ .
forwarded-connect-retries 0
accept-intercepted-requests 1
allow-cgi-request-crunching 0
split-large-forms 0
keep-alive-timeout 5
tolerate-pipelining 1
socket-timeout 300
起動
$ sudo systemctl enable privoxy
$ sudo systemctl start privoxy
8118がLISTENできているかを確認します。
$ netstat -an | grep "0.0.0.0:8118"
tcp 0 0 0.0.0.0:8118 0.0.0.0:* LISTEN
二重ルーター化
これまでの手順でも、ブラウザやOSの設定で 192.168.1.105:1080
に向けてSOCKSプロキシを、もしくは 192.168.1.105:8118
に向けてHTTP(S)プロキシを設定すれば利用できます。
が、以下の二点の手間を省きたくて、二重ルーター化しました。
- 常にProxyを使いたいわけではない→ネットワークを分離したい
- クライアントにわざわざプロキシを設定するのが手間→透過プロキシにしたい
ネットワークは、 eth0
がRaspberry Pi内蔵のLANコネクタであり 192.168.1.0/24
、 eth1
が外付LANアダプタであり 192.168.2.0/24
となります。
192.168.2.0/24
に属しているクライアントは、プロキシ経由でのアクセスができるようになります。
※ADSL時代はよく「二重ルーターは悪だ!」みたいな流れをよく見ましたけど、今回はありかなと思ってます。
IPフォワード許可設定
$ sudo sysctl -w net.ipv4.ip_forward=1
DNSサーバー
インストール
$ sudo apt install bind9
設定
forwarders
のコメントアウトを外し、インターネット側ネットワークのDNSサーバーを指定したのみです。
options {
forwarders {
192.168.1.1;
};
}
IPv4しか使わないので、 OPTIONS
に -4
を追加します。
#
# run resolvconf?
RESOLVCONF=no
# startup options for the server
OPTIONS="-u bind -4"
起動
$ sudo systemctl enable bind9
$ sudo systemctl start bind9
DHCPサーバー
インストール
$ sudo apt install isc-dhcp-server
設定ファイル例
default-lease-time 600;
max-lease-time 7200;
ddns-update-style none;
authoritative;
option wpad code 252 = string;
subnet 192.168.2.0 netmask 255.255.255.0 {
range 192.168.2.100 192.168.2.200;
option subnet-mask 255.255.255.0;
option routers 192.168.2.1;
option broadcast-address 192.168.2.255;
option domain-name-servers 192.168.2.1;
option wpad "http://192.168.2.1/proxy.pac"; # ←後ほど解説
ignore declines;
}
起動
$ sudo systemctl enable isc-dhcp-server
$ sudo systemctl start isc-dhcp-server
nginx
DHCP設定で指定した、WPAD (Web Proxy Auto-Discovery)のためのサーバーです。
インストール
$ sudo apt install nginx
PACファイルの作成
PAC(プロキシ自動設定)ファイルについては、MDNが参考になります。
プロキシ自動設定ファイル - HTTP | MDN
function FindProxyForURL(url, host) {
if (isInNet(host, "192.168.0.0", "255.255.0.0")) {
return "DIRECT";
}
return "SOCKS 192.168.2.1:1080; PROXY 192.168.2.1:8118";
}
※ privoxyでローカルアドレスを避けているはずなので、if文はいらないかもです。
起動
$ sudo systemctl enable nginx
$ sudo systemctl start nginx
iptables設定
iptablesがインストールされていなければインストールします。
# Generated by xtables-save v1.8.2 on Sun Mar 22 03:02:25 2020
*filter
:INPUT ACCEPT [8784577:1664198362]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [9256785:1527135805]
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT # SSHサーバー
-A INPUT -p tcp -m state --state NEW --dport 53 -j ACCEPT # DNSサーバー
-A INPUT -p udp --dport 53 -j ACCEPT # DNSサーバー
-A INPUT -i eth1 -p udp --sport bootpc --dport bootps -j ACCEPT # DHCPサーバー(内側ネットワークのみ)
-A INPUT -p tcp -m state --state NEW --dport 80 -j ACCEPT # Webサーバー
-A INPUT -p tcp -m state --state NEW --dport 1080 -j ACCEPT # SOCKSプロキシ
-A INPUT -p tcp -m state --state NEW --dport 8118 -j ACCEPT # Privoxy
-A INPUT -j REJECT
-A FORWARD -j REJECT
-A FORWARD -i eth1 -o eth0 -s 192.168.2.0/24 -j ACCEPT
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -j ACCEPT
-A OUTPUT -o eth0 -d 10.0.0.0/8 -j DROP
-A OUTPUT -o eth0 -d 176.16.0.0/12 -j DROP
-A OUTPUT -o eth0 -d 192.168.0.0/16 -j DROP
-A OUTPUT -o eth0 -d 127.0.0.0/8 -j DROP
COMMIT
# Completed on Sun Mar 22 03:02:25 2020
# Generated by xtables-save v1.8.2 on Sun Mar 22 03:02:25 2020
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -i eth1 -p tcp -m multiport --dports 21,80,443 ! -d 192.168.2.0/24 -j DNAT --to-destination 127.0.0.1:8118 # 内側ネットワークより、ローカルアドレス以外宛にポート21,80,443への通信があれば、Privoxyに渡す
-A POSTROUTING -o eth0 -s 192.168.2.0/24 -j MASQUERADE # NAT設定
COMMIT
# Completed on Sun Mar 22 03:02:25 2020
iptables適用
$ sudo iptables-apply /etc/iptables/rules.v4
Raspberry Pi上で開いているポートの確認
$ netstat -an | grep "LISTEN "
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 192.168.1.105:53 0.0.0.0:* LISTEN
tcp 0 0 192.168.2.1:53 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8118 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:1080 0.0.0.0:* LISTEN
tcp6 0 0 :::5900 :::* LISTEN
tcp6 0 0 :::80 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 :::1080 :::* LISTEN
接続確認
iPadで試しました。
Proxy非経由 (192.168.1.0/24)
ちゃんとプロバイダのIPアドレスになっており、国判定も正しいです。
Proxy経由 (192.168.2.0/24)
あれ、うまくいっていない…。
はい、DHCPからWPADを使って教えたところで、どうもOSのプロキシ設定までは自動で変わらないようです。
なので、ちょっとだけWi-Fiの設定をいじります。
iOSの場合、Wi-Fi→アクセスポイント名→プロキシを構成、とたどると、初期値は「オフ」となっているので、「自動」に変更して「保存」をクリックします。
なお、この際、URL入力欄が現れますが、WPADのおかげで、未入力のままでも問題ありません。WPADを設定していない場合は、ここで先程のPACがファイルのアドレス http://192.168.2.1/proxy.pac
を入力します。
この結果…
無事に接続できました。
IPアドレスが、SSHサーバーのものとなっており、国判定も正しいです。
速度測定
以前VPNを組んだときは100Kbps程度の遅さで使い物にならなかったのですが…
なぜ50Mbps以上出るのか謎ですけど、必要十分な速度は出そうです。
某IPサイマルラジオ放送も途切れず聞けました。
注意事項
セキュリティには注意してください。万が一、これを実践してトラブルがありましても、責任はとれませんので…。