web-dev-qa-db-ja.com

VPNを使用したネットワーク名前空間のアプリケーションへのポート転送

ネットワーク名前空間をセットアップし、openvpnでトンネルを確立し、名前空間内でこのトンネルを使用するアプリケーションを起動することができました。これまでのところ良好ですが、このアプリケーションはWebインターフェイス経由でアクセスでき、LAN内のWebインターフェイスにリクエストをルーティングする方法がわかりません。

私は@schnoukiからのガイドに従って説明しました ネットワーク名前空間を設定し、その中でOpenVPNを実行する方法

ip netns add myvpn
ip netns exec myvpn ip addr add 127.0.0.1/8 dev lo
ip netns exec myvpn ip link set lo up
ip link add vpn0 type veth peer name vpn1
ip link set vpn0 up
ip link set vpn1 netns myvpn up
ip addr add 10.200.200.1/24 dev vpn0
ip netns exec myvpn ip addr add 10.200.200.2/24 dev vpn1
ip netns exec myvpn ip route add default via 10.200.200.1 dev vpn1
iptables -A INPUT \! -i vpn0 -s 10.200.200.0/24 -j DROP
iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o en+ -j MASQUERADE
sysctl -q net.ipv4.ip_forward=1
mkdir -p /etc/netns/myvpn
echo 'nameserver 8.8.8.8' > /etc/netns/myvpn/resolv.conf

その後、意図したとおりに、外部IPをチェックして、名前空間の内外で異なる結果を取得できます。

curl -s ipv4.icanhazip.com
<my-isp-ip>
ip netns exec myvpn curl -s ipv4.icanhazip.com
<my-vpn-ip>

アプリケーションが起動し、この例では大洪水を使用しています。私はそれが大洪水の特定の問題ではないことを確認するために、Webインターフェイスでいくつかのアプリケーションを試しました。

ip netns exec myvpn Sudo -u <my-user> /usr/bin/deluged
ip netns exec myvpn Sudo -u <my-user> /usr/bin/deluge-web -f
ps $(ip netns pids myvpn)
 PID TTY      STAT   TIME COMMAND
1468 ?        Ss     0:13 openvpn --config /etc/openvpn/myvpn/myvpn.conf
9302 ?        Sl    10:10 /usr/bin/python /usr/bin/deluged
9707 ?        S      0:37 /usr/bin/python /usr/bin/deluge-web -f

Veth vpn1のIPを指定すると、名前空間内および外部からポート8112のWebインターフェイスにアクセスできます。

ip netns exec myvpn curl -Is localhost:8112 | head -1
HTTP/1.1 200 OK
ip netns exec myvpn curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK
curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK

しかし、サーバーからポート8112をネームスペースのアプリケーションにリダイレクトしたいのですが。目標は、LAN内のコンピューターでブラウザーを開き、Webインターフェイスを http:// my-server-ip:8112 で取得することです(my-server-ipはサーバーの静的IPです)ネットワークインターフェースをインスタンス化したもの)

編集:iptablesルールを作成する試みを削除しました。私がやろうとしていることは上記で説明されており、次のコマンドはHTTP 200を出力するはずです。

curl -I localhost:8112
curl: (7) Failed to connect to localhost port 8112: Connection refused
curl -I <my-server-ip>:8112
curl: (7) Failed to connect to <my-server-ip> port 8112: Connection refused

私はDNATとSNATのルールを試し、マスカレードを適切に投入しましたが、自分が何をしているのかわからないので、私の試みは無駄です。おそらく誰かが私がこの構造を組み立てるのを手伝ってくれるでしょう。

編集:tcpdump -nn -q tcp port 8112のtcpdump出力。当然のことながら、最初のコマンドはHTTP 200を返し、2番目のコマンドは拒否された接続で終了します。

curl -Is 10.200.200.2:8112 | head -1
listening on vpn0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.200.200.1.36208 > 10.200.200.2.8112: tcp 82
IP 10.200.200.2.8112 > 10.200.200.1.36208: tcp 145

curl -Is <my-server-ip>:8112 | head -1
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
IP <my-server-ip>.58228 > <my-server-ip>.8112: tcp 0
IP <my-server-ip>.8112 > <my-server-ip>.58228: tcp 0

編集:@schnouki自身が私に 一般的なiptablesを説明するDebian管理の記事TCPプロキシ を指摘しました。手元の問題に適用すると、スクリプトは次のようになります:

YourIP=<my-server-ip>
YourPort=8112
TargetIP=10.200.200.2
TargetPort=8112

iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \
--to-source $YourIP
iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort

残念ながら、vethインターフェース間のトラフィックは捕捉され、他には何も起こりませんでした。しかし、@ schnoukiはsocatをTCPプロキシとして使用することも提案しており、これは完全に機能しています。

curl -Is <my-server-ip>:8112 | head -1
IP 10.200.200.1.43384 > 10.200.200.2.8112: tcp 913
IP 10.200.200.2.8112 > 10.200.200.1.43384: tcp 1495

トラフィックがvethインターフェイスを通過しているときに奇妙なポートがシャッフルすることをまだ理解していませんが、私の問題はこれで解決しました。

13
pskiebe

私は常にiptablesのリダイレクトに関する問題を抱えてきました(おそらく私のせいです、私はそれができると確信しています)。しかし、あなたのようなケースでは、iptablesなしでユーザーランドでそれを行うほうがIMOの方が簡単です。

基本的に、TCPポート8112でリッスンし、すべてのトラフィックを10.200.200.2ポート8112にリダイレクトする「デフォルト」ワークスペースにデーモンを配置する必要があります。したがって、これは単純なTCPプロキシ。

socat でそれを行う方法は次のとおりです:

socat tcp-listen:8112,reuseaddr,fork tcp-connect:10.200.200.2:8112

forkオプションは、最初のプロキシ接続が閉じられた後にsocatが停止しないようにするために必要です)。

[〜#〜] edit [〜#〜]:コメントで提案されているようにreuseaddrを追加しました。

どうしてもiptablesを使用したい場合は、 Debian Administration サイトにガイドがあります。しかし、私はより高度なもののためにsocatを好みます-IPv4からIPv6へのプロキシ、またはSSLを取り除いて古いJavaプログラムが安全なサービスに接続できるようにする...

ただし、Delugeでのすべての接続は、実際のクライアントIPではなくサーバーIPから行われることに注意してください。これを避けたい場合は、元のクライアントIPをHTTPヘッダーのプロキシされたリクエストに追加する実際のHTTPリバースプロキシを使用する必要があります。

9
Schnouki

ネットワークの名前空間とメインの名前空間を相互接続することは常に私を悩ませます。名前空間を通常作成するのは、それを分離したいからです。それが何であるかに応じて、相互接続を作成する名前空間で達成しようとしていることは、その目的を無効にする可能性があります。

しかし、孤立していても、便宜上、ネットワーク経由でそれを突く必要があります。

このソリューションを使用すると、分離を維持し、とにかくいくつかの接続を転送できます。 1つのポートを転送するためだけに、2つのネットワーク名前空間間にすべてのネットワークを作成する必要はありません。接続を受け入れる名前空間でこれを実行します。 ip netns execが機能するには、rootとして実行する必要があります。

socat tcp-listen:8112,fork,reuseaddr \
  exec:'ip netns exec myvpn socat STDIO tcp-connect\:127.0.0.1\:8112',nofork

ポート8112で実行する1つのネットワーク名前空間で接続をリッスンし、接続されたクライアントはexecを取得してip netns exec myvpn ...を実行し、myvpnネットワーク名前空間内の残りを実行します。 myvpnネットワーク名前空間内に入ると、別のsocatとの2番目の接続が再び作成されます。

8
AnyDev

@AndrDevEKの回答が役立ちます。それを拡張するために、socatをインストールしたくない場合があります。その場合、わずかに複雑なSSHポート転送設定で同じことを実現できます。 unix-domainソケットはネットワーク名前空間とは独立して動作するため、特にunix-domainソケットとの間のポート転送機能はここで役立ちます。

Sudo ip netns exec myvpn su -c "ssh -N -L /tmp/myunixsock:localhost:8112 localhost" $USER &
ssh_pid1=$!
ssh -N -L localhost:8112:/tmp/myunixsock localhost &
ssh_pid2=$!

掃除:

Sudo kill $ssh_pid1
kill $ssh_pid2
rm /tmp/myunixsock

最初 ssh -N -Lは、myvpn名前空間内で開始されます。これにより、UNIXドメインソケットが作成されます/tmp/myunixsockとそれをリッスンします。着信接続は(myvpn名前空間内の)localhost:8112に転送されます。二番目 ssh -N -Lはデフォルトの名前空間で開始されます。これにより、リスニングTCP=ポートが作成され、着信接続がUNIXドメインソケットに転送されます。

これが機能するためには、ネットワークネームスペース内のsshがまだ機能していない場合は機能している必要があります(パスワードなしのpubkey操作が役立つ)。

Sudo ip netns exec myvpn ip link set up dev lo
Sudo ip netns exec myvpn /usr/sbin/sshd -o PidFile=/run/sshd-myvpn.pid
ssh-copy-id localhost
2
Digital Trauma

ここで大洪水が私の解決策です。 iptablesは必要ありません。手順は次のとおりです。

  1. Openvpnトンネルを開始する
  2. 名前空間を作成し、openvpnトンネルをそこに移動します。
ip netns add $ NS 
#TUNが起動するのを待ちます
 while [[$(ip route | grep $ TUN | wc -l)== 0]];寝る1; done 
 MY_IP = $(ip addr show $ TUN | grep inet | cut -d '' -f6 | cut -d '/' -f1)
#ゲートウェイIPを抽出する方法はopenvpn接続では異なります。
 GATEWAY_IP = $ MY_IP 
#$ TUN(VPNインターフェース)を名前空間にジェイルします
 ip link set $ TUN netns $ NS 
#サブネットを使用してインターフェースを起動します(VPNサーバーから与えられたものと同等)
 ip netns exec $ NS ifconfig $ TUN $ MY_IP/24 up 
#ループバックを起動します
 ip netns exec $ NS ifconfig lo 127.0.0.1/8 up 
#リモートゲートウェイをセットアップします(ポイントツーポイントVPN IPアドレス)
 ip netns exec $ NS route add default gw $ GATEWAY_IP
  1. デフォルトの名前空間と作成した名前空間の間にveth接続を確立します。
#名前空間間の通信用のvethインターフェースを設定します
 ip link add veth0 type veth peer name veth1 
#2番目のvethを名前空間に移動します
 ip link set veth1 netns $ NS 
#未使用のIP範囲から最初のvethにIPを割り当てます
 ifconfig veth0 10.1.1.1/24 up 
#そして2番目のIPは
 ip netns exec $ NS ifconfig veth1 10.1 .1.2/24 up 
#TODO:LANと通信できるようにveth1とethインターフェイスの間にブリッジをセットアップします
#DNSクライアントをセットアップします。 ip netnsは、次のファイルを使用して/etc/resolv.confをエミュレートします。
 mkdir -p /etc/netns/$NS
echo "nameserver 8.8.4.4">/etc/netns/$ NS/resolv.conf 
  1. $ NSでdelugedを実行し、デフォルトの名前空間でdeluge-webを実行します。 deluge-webを10.1.1.2 veth IPアドレスにポイントします。ここで、delugedはその接続をリッスンします。

出来上がり! VPNの背後でセキュリティが侵害され、ホームネットワークで自由にWebにアクセスできる

2
Vlad