Debian で Squid 4 透過プロキシ

[Debian で作ったルーター](https://qiita.com/kakinaguru_zo/items/2764dd8e83e54a6605f2) にsquidを入れた手順。その結果、アンドロイドLINEアプリはプロキシの設定を完全無視してポート番号443に謎の通信を流し込むことがわかった。外向きTCPポート番号をファイアーウォールで塞ぐとアンドロイドLINEアプリは使えない。以下の話はDebian Linux Bullseye (バージョン11) で行ったがUbuntu 20.04とかでもほぼ同じはず。[tproxy (透過プロキシ)](https://trafficserver.readthedocs.io/ja/5.3.x/admin/transparent-proxy.en.html) をsquidとnftablesで使う手順も書いた。それをやらないで外向きTCP 80番と443番をファイアーウォールで遮断するとLINEが使えなくなる。

# Squid のインストールと設定
## Squid のインストール
`apt-get --no-install-recommends install squid` で十分。
## Squid の設定
以下のような感じでよさげ…

```config:/etc/squid/squid.confの末尾あたりに下記を追加する
http_access allow localnet  # これ書かないとLANの他の機器から使えない
on_unsupported_protocol tunnel all # LINE の謎通信を通すため
# ↓外部インターネットに露出した機器で動作させるなら必ずLAN内のIPアドレスを明示する
http_port 192.168.1.2:3128
# 透過プロキシは異なるポート番号で要求を受け付ける必要がある
http_port 192.168.1.2:3129 tproxy
http_port 192.168.1.2:3130 tproxy
# ファイアーウォールで外向きTCP 80番と443番を遮断している場合、特別に通信を許可された
# 送信元アドレスからSquidにウェブサーバーをアクセスさせるように次の２行を書く
tcp_outgoing_address 外部と通信できるIPv6アドレス
tcp_outgoing_address 外部と通信できるIPv4アドレス
udp_incoming_address DNSの応答を受け付けられるアドレス（できればプライベートアドレス）
# ↓デフォルトでディスクキャッシュは無効なのでメモリーキャッシュはデフォルト値より大きくしてよい
cache_mem 512 MB
maximum_object_size_in_memory 10 MB
# euiはイーサネットMACアドレス
logformat mycombined   %>a %>eui %<A %<p %tl "%rm %ru HTTP/%rv" %>Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh
access_log daemon:/var/log/squid/access.log mycombined
log_mime_hdrs on
relaxed_header_parser warn
# ↓タイムアウトを短くしたほうがすぐにエラーが返ってくる
forward_timeout 10 seconds
connect_timeout 9 seconds
write_timeout 10 seconds
request_timeout 10 seconds
request_start_timeout 1 minute
shutdown_lifetime 12 seconds
mail_program /usr/sbin/sendmail
persistent_connection_after_error off
detect_broken_pconn on
# 使用するDNSがedns0に対応し巨大なパケットを受け付けるなら最大パケットサイズを大きくすべき
dns_packet_max 63 KB
dns_nameservers 127.0.0.1
connect_retries 3
retry_on_error on
uri_whitespace encode
pipeline_prefetch 100
```

# 透過プロキシ (tproxy) 設定
`iptables` は一切使われず、`apt-get install nftables` と `systemctl enable nftables.service` してパケットフィルター処理の設定が `/etc/nftables.conf` で一括して行われる状況を想定する。透過プロキシを用いる目的としてはアンドロイドLINEアプリのようにシステムのプロキシ設定を無視するアプリや、家で使っているONKYOのインターネットラジオ対応CDプレイヤーみたいにプロキシの設定がそもそも不可能な機器に対応することがある。`iptables` を用いた手順は[tproxy 構築メモ](https://qiita.com/kwi/items/b7c770d6b92c16c334fb) で説明されている。

## nftables の設定
基本的に[Linux kernelの付属文書](https://www.kernel.org/doc/Documentation/networking/tproxy.txt) にある通りで、以下の内容を `/etc/nftables.conf` に追加しておけばよい

```config
# IPv6 パケットにも透過プロキシする場合は次行の ip をinetにする必要あり
table ip my_tproxy {
	chain PREROUTING {
		type filter hook prerouting priority mangle;
		meta l4proto tcp socket transparent 1 meta mark set 300 counter accept
		tcp dport 80 ip daddr != 192.168.1.0/24 tproxy to 192.168.1.2:3129 meta mark set 300 counter log prefix "tproxy " level debug flags all
		tcp dport 443 ip daddr != 192.168.1.0/24 tproxy to 192.168.1.2:3130 meta mark set 300 counter log prefix "tproxy " level debug flags all
	}
}
```

## ip ruleとip routeを用いた設定

これだけでは動作せず、下記のポリシーベーストルーティングをLinux kernelにさせるスクリプトをsystemd起動時に実行させるようにする。そのために `systemctl daemon-reload && systemctl enable tproxyroute.service` する

```config:/etc/systemd/system/tproxyroute.service
[Unit]
Description=Set Routes for Transparent Proxy by Squid
After=network-online.target nftables.service
Requires=network-online.target nftables.service
Before=squid.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ip rule add fwmark 300 lookup 100
ExecStart=/sbin/ip route add local 0.0.0.0/0 dev lo table 100

[Install]
WantedBy=multi-user.target
```

## ip の代わりにsystemd設定ファイルだけで行う例

`systemd` がある程度新しければ、上記の`tproxyroute.service`の代わりに

```config:/etc/systemd/network/lo.network
[Match]
Name=lo

[Link]
RequiredForOnline=yes

[RoutingPolicyRule]
FirewallMark=300
Table=100
Family=ipv4

[Route]
Table=100
Destination=0.0.0.0/0
Type=local
```

というファイルを作ってもよい

# アンドロイドスマホのプロキシ設定
基本的に[Google の説明](https://support.google.com/android/answer/9654714?hl=ja) に書いてあるとおりだが、うちのスマホやタブレットは既に接続されているWiFiにプロキシを設定するためには、一旦その接続情報を消して改めて接続設定をやりなおすときに「詳細」を押さないと下記の画面が出なかった…そういう設定をしてもLINEアプリなど一部行儀が悪いアプリはプロキシ設定をガン無視するので上記の透過プロキシが必要となる。またプロキシ設定「自動」はどう頑張ってもうちのスマホがバグっていて動作しなかった

![Screenshot_20200607-050312~2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/c101f056-195a-0e7c-c9f4-becd55b45a8e.png)