背景
- TCP に加えて, UDP ポートを forward したい(proxy). ポート範囲(複数ポート)指定して.
- proxy だけほしい + 8000 番代以降のポートでよいのでユーザー権限で動かすで OK
情報
UDP通信のリバースプロキシサーバを立てる
https://qiita.com/trajanme/items/55975e37e9a6b12ca71e
NGINX を使った TCP/UDP Proxy の構築
https://tech-lab.sios.jp/archives/10313
nginxによるTCPロードバランサー
https://engineering.mercari.com/blog/entry/2016-08-17-170114/
ありがとうございます.
古い nginx だと udp には対応していない + ポート範囲指定できないので注意です!
最低限 v1.15.10 が必要です.
今回は 1.19.10 を使います.
Proxy 機能使うにはソースからビルドしないといけませんでした.
(最近の Ubuntu パッケージとかだとモジュール(動的ロード)でいけるかもですが)
nginx のビルド
configure で, 古きつらき autoconf configure かと思いきや自前 bash script でさらにつらいです(本当にやめてほしい)
--with-stream
でコンパイルします(デフォルトだと静的リンク). --with-stream=dynamic
でモジュールを動的リンクというのもできますが, あまり利点はないでしょう.
pcre, zlib 関連は不要なので off(--without-***
)でよいです.
ユーザー権限でうごかす
-p
で設定ファイルのフォルダ指定してやります.
mime.types とかのファイルは適宜コピってきましょう.
$ nginx -p <path/to/conf>
ログを stdout に出すモードほしいですが無いっぽい?
-t
で conf ファイルとかチェックできます
stream とかで指定するパスが wildcard 指定の場合, ファイルパスが間違っていてもエラー出さないので注意です!
設定例はこんな感じです.
# user nginx;
worker_processes 1;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
keepalive_timeout 65;
include /home/syoyo/local/nginx/conf.d/*.http.conf;
}
stream {
include /home/syoyo/local/nginx/conf.d/*.stream.conf;
# wildcard 使う場合, 存在しないパスでもエラー出さないので注意!
include /nonexit/syoyo/local/nginx/conf.d/*.stream.conf;
}
proxy.stream.conf
upstream backend {
server 10.8.0.6:8089;
}
server {
listen 8089 udp;
proxy_pass backend;
}
netcat, socat で通信試してみます.
# client(10.8.0.6)
$ socat UDP4-LISTEN:8089 stdout
# proxy(10.8.0.1)
$ nc -u 0.0.0.0 8089
hello
client 側に hello と表示されれば成功です!
うまく行かない場合, client と proxy は同一ネットワークにあり, firewall(CentOS の場合基本ブロックなのでポート開放しないといけない)でブロックされていないことも確認しておきましょう.
複数ポートのフォワーディング
v1.15.10 からポートを範囲で指定できるようになっています!
ただ, upstream
と server
で両方指定するのはダメで,
upstream backend {
server 10.8.0.6:8089-8099;
}
server {
listen 8089-8099;
proxy_pass backend;
}
以下のように inline で記述($server_port
変数)しないとダメでした.
# OK
server {
listen 8089-8099;
proxy_pass 10.8.0.6:$server_port;
}
upstream
に変数かなにかで指定できるかもしれませんが, いかんせん nginx のドキュメントがひどくてなにも書かれていませんので諦めました.
とりあえず inline 表示でうまく forward できるのでよしとします.
(ロードバランスしたいときはソースコードがんばって読んで設定できるか調べてね )
TCP, UDP ではそれぞれ別で設定が必要です.
server {
listen 8089-8099;
proxy_pass 10.8.0.6:$server_port;
}
server {
listen 8089-8099 udp;
proxy_pass 10.8.0.6:$server_port;
}
TODO
-
nginx, とりあえず UDP forward できるのは確認しましたが, 設定ファイルフォーマット独自だしソースコードはロシアンな C コードでつらいので他のツールに一刻も早く乗り換えたい. SOCKS5 proxy?
- SOCKS4 は TCP だけ.
- iptables or STUN がいいのかしら?
- Envoy? https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/udp_filters/udp_proxy
- 自作とか?
さらなる高みへのメモ
そして壁の向こうへ。 NAT/Firewallを越えて通信しよう―WebRTC入門2016
https://html5experts.jp/mganeko/20618/
gost - GO Simple Tunnel がすごい
https://qiita.com/tongari0/items/84f630483bef19a2e386
プロキシとの戦いに疲れたのでgoで透過プロキシを作ってみた
https://qiita.com/wadahiro/items/7fa852b7217940e6ef26