6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Privoxyでプロキシのブリッジを行う

Last updated at Posted at 2020-03-22

世界中で新型コロナウイルスが拡がっていますが、私の住むバンコクでも、娯楽施設を中心として人が集まる施設の封鎖が命じられ、会社はリモートワーク(Work From Home)に切り替え、タイ入国には非感染証明書を求められ(日本では健常者に発行していない)、事実上国外へ移動できない生活が始まりました。

外食もできず、夜な夜な飲み歩くこともできず、家に引きこもり生活になったので、以前トライしたものの実用性が低すぎたVPN接続に代わって、興味本位でプロキシのブリッジを組んでみました。

作りたいネットワーク

SOCKS Proxy.png

用意したもの

サーバー側(日本)

すでに構築済みになりますが、Linuxが入っているマシンと、インターネット環境を用意しました。(前回と同じ)

  • インターネット回線(NTTフレッツ光、固定IPがもらえる某プロバイダ)
  • ルーター(中古のRTX1100
  • 自作PC(Debian Linux 10)

ブリッジ側(海外)

Raspberry Pi以外は前回のものを流用しました。

※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プロキシを立てることができましたが、さすがにこれで終わらせるわけにはいかないので、サービス化します。

/etc/systemd/system/socks-proxy-client.service
[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には、広告ブロックなどの機能もありますが、今回はそれを使うつもりがないので、無効化します。

コメント部分がとても長いので、変更した設定項目だけ抜粋します。

/etc/privoxy/config
#  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行をコメントアウト

/etc/privoxy/config
#  2.6. filterfile
#  ================
#
#filterfile default.filter
#filterfile user.filter      # User customizations

↑これら2行をコメントアウト

/etc/privoxy/config
#  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を追加

/etc/privoxy/config
#  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に転送するが、ローカルアドレス宛の場合は転送しない。

すべてのコメント行を省くと、このようなファイルになります。

/etc/privoxy/config
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/24eth1 が外付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サーバーを指定したのみです。

/etc/bind/named.conf.options
options {
        forwarders {
                192.168.1.1;
        };
}

IPv4しか使わないので、 OPTIONS -4 を追加します。

/etc/default/bind9
#
# 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

設定ファイル例

/etc/dhcp/dhcpd.conf
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

/var/www/html/proxy.pac
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がインストールされていなければインストールします。

/etc/iptables/rules.v4
# 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)

image.png

ちゃんとプロバイダのIPアドレスになっており、国判定も正しいです。

Proxy経由 (192.168.2.0/24)

File copy 2.jpg

あれ、うまくいっていない…。

はい、DHCPからWPADを使って教えたところで、どうもOSのプロキシ設定までは自動で変わらないようです。
なので、ちょっとだけWi-Fiの設定をいじります。
iOSの場合、Wi-Fi→アクセスポイント名→プロキシを構成、とたどると、初期値は「オフ」となっているので、「自動」に変更して「保存」をクリックします。
なお、この際、URL入力欄が現れますが、WPADのおかげで、未入力のままでも問題ありません。WPADを設定していない場合は、ここで先程のPACがファイルのアドレス http://192.168.2.1/proxy.pac を入力します。
File copy 3.jpg

この結果…

image.png

無事に接続できました。
IPアドレスが、SSHサーバーのものとなっており、国判定も正しいです。

速度測定

以前VPNを組んだときは100Kbps程度の遅さで使い物にならなかったのですが…

image.png

なぜ50Mbps以上出るのか謎ですけど、必要十分な速度は出そうです。
某IPサイマルラジオ放送も途切れず聞けました。

注意事項

セキュリティには注意してください。万が一、これを実践してトラブルがありましても、責任はとれませんので…。

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?