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


13

ネットワーク名前空間を設定し、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内のコンピューターでブラウザーを開き、http:// my-server-ip:8112で Webインターフェースを取得することです(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出力tcpdump -nn -q tcp port 8112。当然のことながら、最初のコマンドは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 TCPプロキシについて説明しているDebian管理記事を指摘してくれました。当面の問題に適用すると、スクリプトは次のようになります。

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インターフェイスを通過している間に奇妙なポートがシャッフルされることをまだ理解していませんが、私の問題は解決しました。


免責事項:vethデバイスの使用経験はまったくありません(ただし、これは非常に興味深いものですが... ;-))。tcpdump着信パケットがどこまで到達するかを確認するために使用しましたか?tcpdump -i veth0何も表示されない場合はtcpdumo -i lo、必要な場合があります。
ハウケレイジング

tcpdumpの非冗長出力を追加しました
-pskiebe

回答:


8

私は常に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、最初のプロキシ接続が閉じられた後に停止しないようにするために必要です)。

編集reuseaddrコメントで提案されているように追加されました。

iptablesで絶対にやりたい場合は、Debian管理サイトにガイドがあります。しかしsocat、IPv4をIPv6にプロキシする、SSLを除去して古いJavaプログラムが安全なサービスに接続できるようにするなど、より高度なものが今でも好きです...

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


1
あなたは私の一日を作りました!私は出会ったことはありませんでしたしsocat、かなり長い間iptablesでやろうとしていたことを正確に達成しています。複数のアプリケーションをテストしましたが、それらはすべてtun0を介して外部の世界に接続しながら、veth1を介してWebインターフェースへのアクセスを提供しながら、問題なく動作しています。
pskiebe

1
いくつかのテストを行った後、reuseaddrフラグを追加しました。これによりport already in use、socatをすばやく連続して開始および停止する際のエラーが防止されますsocat -4 TCP-LISTEN:8112,reuseaddr,fork TCP:10.200.200.2:8112
。– pskiebe

7

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

しかし、孤立していても、便宜上、ネットワーク上でそれを突きたいと思っています。

このソリューションにより、分離を維持し、何らかの接続を転送できます。 1つのポートを転送するために、2つのネットワーク名前空間の間にすべてのネットワークを作成する必要はありません。 接続を許可するネームスペースでこれを実行します。動作するにはrootとして実行する必要がありますip netns exec

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ます。


チャームのように動作する
近似

私はLinux管理の経験があまりないので、見つけるのに時間がかかりました::単一引用符内の両方の文字をエスケープしないと、... wrong number of parameters (2 instead of 1)(2または3)というエラーが発生する可能性があります。それ以外の場合:うまくいきます!本当にありがとうございます!
イゴール

2

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

  1. openvpnトンネルを開始します
  2. 名前空間を作成し、そこにopenvpnトンネルをもたらします:
ip netnsは$ NSを追加します
#TUNが現れるのを待つ
while [[$(ip route | grep $ TUN | wc -l)== 0]]; 寝る1; やった
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 netns exec $ NS ifconfig veth1 10.1.1.2/24 up
#TODO:veth1とethインターフェースの間にブリッジを設定して、LANと通信できるようにします
#DNSクライアントをセットアップします。ip netnsは、次のファイルを使用して/etc/resolv.confをエミュレートします。
mkdir -p / etc / netns / $ NS
echo "nameserver 8.8.4.4"> /etc/netns/$NS/resolv.conf
  1. デフォルトのネームスペースで$ NSおよびdeluge-webでdelugedを実行します。deluge-webが10.1.1.2 veth IPアドレスをポイントします。ここで、delugedはその接続をリッスンします。

出来上がり!deluge-webがホームネットワーク上で自由にアクセスできる一方で、VPNの背後で安全に保護されています


2

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

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リッスンされます。着信接続はlocalhost:8112(myvpn名前空間内)に転送されます。2番目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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.