
これはかなり初心者的な質問かもしれませんが...
私はUbuntu 18.04.3 LTSを使っていて、仮想プライベートネットワークいくつかのアプリケーションで使用したいのですが、namespaced-openvpn
そして、それは動作します! 注意点は、このアプリケーションにローカルで接続できないことです (管理目的のため)。
VPNトンネル内の特定のポートをローカルホストに転送する方法はありますかVPN トンネルが他の目的に使用され、情報が漏洩しすぎることはありませんか?
私がすでにできること:
- 走る
namespaced-openvpn
-脚本:sudo ./namespaced-openvpn --namespace vpn --config /etc/openvpn/vpn-xxxxx.ovpn
- ネットワーク名前空間内でアプリケーションを実行します。
sudo ip netns exec vpn application
達成したいこと:
1234
実際のローカルホスト(enp3s0
イーサネットアダプタ)からVPNトンネル内(例:ポート)で起動されたアプリケーションに接続する- このポートを転送して、LAN内の他のコンピュータからアクセスできるようにします。
答え1
何年も遅れましたが、ここ数日私が望んでいたように、誰かがこれを見つけるかもしれないので。
誰かの役に立てば幸いです。
まず、すべてを実行する作業の 90% を実行する namespaced-vpn があります。
https://github.com/slingamn/namespaced-openvpn
そして、これがこれとほぼ同じ質問に対する答えです。何がなぜ行われているのか理解していなかったにもかかわらず、私にとって非常に役立ちました。 https://unix.stackexchange.com/questions/391193/how-to-forward-traffic-between-linux-network-namespaces
検索で見つけた断片的な情報を使って、何度も試行錯誤して理解したことを、ここで説明したいと思います。
サービスへの接続を転送する場合 (サービスが実行されている PC からではなく) に最も関係のある部分は、次の部分だと思います (PREROUTING の後の感嘆符に注意してください)。
iptables -t nat -A PREROUTING ! -s 10.0.0.0/24 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
ここで、 は、10.0.0.0/24
転送したくない IP 範囲を表します。
これは主に、サブネットを使用してアクセス可能なサービスが10.0.0.0/24
それ自体にルーティングされるルーティング ループを防ぐためです。
--dport 80 は、ポート 80 (つまり、Web サーバー接続) を求めるパケットのみを転送します。
10.0.0.2
は、サーバーが稼働している名前空間内に移動された veth インターフェイスです。 これにより、サブネットからではなく、ポート 80 サービスを求めるパケットが、宛先 IP を に変換されるよう
になります。例:は、サーバーが存在する名前空間内のインターフェイスであると考えられます。10.0.0.0/24
10.0.0.2
192.168.1.200:80
10.0.0.2:80
複数の名前空間で複数の VPN トンネルが稼働しています。PREROUTING ルールを iptables に追加しないと、LAN 上の PC の外部からリソースにアクセスできません。
自分の PC からアクセスできるようにするには、次のようなルールを追加する必要があります。
iptables --table nat --append OUTPUT --destination 192.168.1.2 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
つまり、サーバーがインストールされている PC のブラウザーに入力して192.168.1.2
自分のサーバーにアクセスすると、代わりにルーティングされます10.0.0.2
。
私の設定の一部を説明してみます...
名前空間の例:ip netns add ns_example
veth ペアを作成します。一方はルート/通常の名前空間(私はこれを と呼びますhost
)に留まり、もう一方は VPN を使用した名前空間に移動します。
ip link add dev ihost type veth peer name ivpn
veth ペアの VPN 側をターゲット名前空間に移動します。
ip link set dev ivpn netns ns_example
作成した veth ペアに ips を割り当てます。
/32 を使用するのは、範囲ではなく、この正確な IP のみを割り当てたいからです。そうしないと、デバイスを起動したときに、いくつかのルートがテーブルに自動的に挿入されip route
、他の名前空間のルーティングが混乱します。
ホスト側に割り当てます。
ip addr add 10.0.0.1/32 dev ihost
名前空間に移動された VPN 側に割り当てるには、コマンドの前に . を付ける必要があります。
ip netns exec TARGET_NAMESPACE
したがって、VPN 側に IP を割り当てるには、次のようにします。
ip netns exec ns_example ip addr add 10.0.0.2/32 dev ivpn
次にインターフェースを起動します。
ip link set dev ihost up
ip netns exec ns_example ip link set dev ivpn up
ここで、ルートと iptables を追加して、それらの間でトラフィックが流れるようにします。
ルート名前空間から VPN 側 ( 10.0.0.2
) に到達するには、インターフェイス ihost を使用して、送信元アドレスをルート名前空間側 ( ) に書き換えます10.0.0.1
。
ip route add 10.0.0.2/32 dev ihost src 10.0.0.1
VPN 名前空間内でまったく同じことを、反対の視点から実行します。
ip netns exec ns_example ip route add 10.0.0.1/32 dev ivpn src 10.0.0.2
iptables
ここで、別個でありながら同様のタスクを実行する同じ操作を追加しますip route
。
送信されるパケットの送信10.0.0.2
元アドレスは次のように書き換えられます。10.0.0.1
iptables --table nat --append POSTROUTING --destination 10.0.0.2/32 --jump SNAT --to-source 10.0.0.1
まったく同じものですが、視点は反対で、名前空間内にあります。
ip netns exec ns_example iptables --table nat --append POSTROUTING --destination 10.0.0.1/32 --jump SNAT --to-source 10.0.0.2
私の理解が正しければ、送信元アドレスの書き換えは、パケットが名前空間から戻る方法を認識していることを確認するため、およびその逆のためです。
さて、たとえば、ポート 8080 の名前空間でトレント WebUI にアクセスするには、次のようにします。LAN
IP (例: ブラウザーに入力192.168.1.2:8080
) に送信されるすべてのパケット。宛先が、トレント クライアントが実行している名前空間 (例: 10.0.0.2
) に書き換えられます。
iptables --table nat --append OUTPUT --destination 192.168.1.2/32 --protocol tcp --match tcp --dport 8080 --jump DNAT --to-destination 10.0.0.2
このルールは、具体的にはポート 8080 のみを転送し、このルールは、サービスが実行されている PC 上のサービスにアクセスするためのものです。ネットワークにアクセスする他のすべての PC には、192.168.1.2:8080
回答の冒頭で述べた PREROUTING ルールが必要です (--dport 80 を --dport 8080 または必要なポート/プロトコルに変更するだけです)。
この方法と namespaced-vpn.py スクリプトを使用する人向け。VPN をリセットする必要がある場合、問題が発生する可能性があります。Namespaced VPN は、lo
ループバック インターフェイス以外のターゲット名前空間内のインターフェイスを検出すると例外をスローします。
ターゲット名前空間がすでに存在し、veth ペアがある場合に namespaced-vpn.py を使用すると例外がスローされる部分を次に示します 。
if os.path.exists(os.path.join('/var/run/netns', namespace)):
adapters = _adapter_names(namespace)
if adapters != [b'lo']:
LOG.error('Namespace %s already has adapters %s, exiting.' % (namespace, adapters))
raise Exception
以下は私が使用した変更例です。
allowed_adapters = [b'lo', b'ivpn']
if os.path.exists(os.path.join('/var/run/netns', namespace)):
adapters = _adapter_names(namespace)
# Iterate and ensure all are in allowed list
for a in adapters:
if not a.split(b'@')[0] in allowed_adapters:
LOG.error('Namespace %s has non-whitelisted adapters %s, exiting.' % (namespace, adapters))
raise Exception
`def setup_namespace(namespace)`関数の最後に、既に存在すると予想される各インターフェースに対して、次のような呼び出しを追加してください。LOをデバイス名に置き換えます。
subprocess.check_call(_enter_namespace_cmd(namespace) + [IP_CMD, 'link', 'set', 'LO', 'up'])
例:
subprocess.check_call(_enter_namespace_cmd(namespace) + [IP_CMD, 'link', 'set', 'ivpn', 'up'])
VPN インターフェイスに接続された BitTorrent クライアントを実行している場合、何らかの理由でクライアントがランダムに接続を停止するという問題に遭遇することがあります。たとえば、朝起きると、外出してから 10 分後にすべてのすばらしいダウンロードがフリーズしているのに気づくことが
あります。この問題は、VPN ソフトウェア (IE OpenVPN) が何らかの理由 (エラー、ping の再起動など) で VPN プロバイダーに再接続し、新しい IP アドレスが割り当てられているためであると私は考えています。VPN インターフェイスは、構成をリセットするために一瞬オフラインにする必要がある可能性があり、これによりクライアントに不具合が発生します (qBittorrent は確実にこれを行います)。私が検討し始めた「修正」は、VPN インターフェイスが新しい IP アドレスを受け取ったとき、または何らかの理由でオフラインになったときを検出するスクリプトを作成することです。スクリプトは、適切に (重要: 何かを破損したりファイルシステム エラーが発生しないように適切に) Torrent クライアントを終了し、再起動する必要があります。まだ動作するスクリプトはありませんが、この問題を解決するのに適したベクトルのようです。
答え2
わかりました。この質問は複雑すぎて誰も答えられないようです。あるいは、以前に答えられていて誰も返答しなかったのかもしれません。
とにかく、私はもう一日作業しましたが、アプリケーションのWebインターフェースに1つのポートを公開することだけに興味があるので、socat
。それで私はそうしました。
namespaced-openvpn 接続を作成し、そのネットワーク名前空間内でアプリケーションを起動した後、専用のターミナルで次のコマンドを実行しました。
sudo socat tcp-listen:PORT-TO-FORWARD-TO,fork,reuseaddr exec:'ip netns exec vpn socat STDIO tcp-connect\:127.0.0.1\:PORT-TO-LISTEN-TO',nofork
ノート:
PORT-TO-FORWARD-TO
ポートを転送したいポートです(ルートネットワーク名前空間内)PORT-TO-LISTEN-TO
ルート名前空間に公開したいアプリケーションのポートです127.0.0.1
実際のローカルホストIPを使用する必要がありました(localhost
名前ではなく、適切に解決されないようです):
一重引用符内の二重小数点文字( )を必ずエスケープしてください。- これがDNSリークを引き起こすかどうかはわかりません。私が調べたところ、そうではないようですが、テスト方法がわからないため、確信はありません。
残っていること:
- アプリケーションを起動し、起動時にポートを転送するためのすべてのコマンドを自動化します。現在は必要ありませんが、方法がわかったらここに追加します。