仮想インターフェイスとPREROUTINGチェーン

仮想インターフェイスとPREROUTINGチェーン

私の一般的な質問は次のとおりです。コマンドラインで単一のホスト(ネットワーク接続なしなど)でローカルにiptables NATルールを確認するための最良の方法(最も簡単、最も簡単、最速、エラーの可能性が最も低いなど)は何ですか?

以下は、NetCatを使用して単純なDNATルールを確認しようとする特定の(失敗した)試みの詳細です。この場合、私の具体的な質問が解決されることを願っていますが、一般的な質問にも答えがあります。


私はDebian 8(Jessie)を使ってVirtualBox仮想マシンを実行しています。簡単なDNATルールの基本テストを実行するためにnetcatを使用したいと思います。

私のテストで私が望むのは、あるデータをあるローカルアドレス(たとえば192.168.0.1)に送信し、別のローカルアドレス(たとえば192.168.0.2)に到着させることです。

私はこれまでいくつかの異なるアプローチを試しました。

  1. 仮想インターフェイスとPREROUTINGチェーン

  2. 仮想インターフェイスとPREROUTINGチェーン

  3. PREROUTINGの代わりにOUTPUTチェーンを使用してください。

仮想インターフェイスとPREROUTINGチェーン

私の最初の試みは、PREROUTINGチェーンにDNATルールを追加し、適切なアドレスを持つ2つの仮想インターフェイスを追加することでした。

私のルールは次のとおりです。

sudo iptables \
-t nat \
-A PREROUTING \
-d 192.168.0.1 \
-j DNAT --to-destination 192.168.0.2

ファイアウォールには他のnetfilterルールはありません。ただし、確実にするために、出力は次のようになりますiptables-save

#iptables-save v1.4.21で作成

*鎌
:事前ルーティングを許可[0:0]
:入力承認[0:0]
:出力を許可[0:0]
:ルーティング後承認[0:0]
-A 事前経路 -d 192.168.0.1/32 -j DNAT --目的地 192.168.0.2
犯罪

*フィルター
:入力承認[0:0]
:転送を受け入れる[0:0]
:出力を許可[0:0]
犯罪

繰り返しますが、私が望むのは、192.168.0.1いくつかのデータをそのアドレスに送信し、そのアドレスに到着させることです192.168.0.2

192.168.0.0/24私のVMではサブネットが使用されていないことに言及する価値があります。まず、いくつかの仮想インターフェイスを追加します。

sudo ip link add dummy1 type dummy

sudo ip link add dummy2 type dummy

次に、目的のサブネット範囲の仮想インターフェイスにIPアドレスを割り当てます。

sudo ip addr add 192.168.0.1/24 dev dummy1

sudo ip addr add 192.168.0.2/24 dev dummy2

次にインターフェイスを開きます。

sudo ip link set dummy1 up

sudo ip link set dummy2 up

現在私のルーティングテーブルは次のとおりです。

10.0.2.2 dev eth0によるデフォルト値
10.0.2.0/24 dev eth0プロトタイプカーネルスコープリンクsrc 10.0.2.15
192.168.0.0/24 dev dummy1 proto カーネルスコープリンク src 192.168.0.1
192.168.0.0/24 dev dummy2 proto カーネルスコープリンク src 192.168.0.2
192.168.56.0/24 dev eth1プロトタイプカーネルスコープリンクsrc 192.168.56.100

netcatを使用して最初の(ソース)アドレスを受信します。

nc -l -p 1234 -s 192.168.0.1

私はnetcatクライアントを使ってnetcatサーバーに接続します(別のターミナルウィンドウで):

nc 192.168.0.1 1234

あるウィンドウに入力したテキストは、予想どおり別のウィンドウに表示されます。

2番目のアドレスにも同じことをしました。

nc -l -p 1234 -s 192.168.0.2

nc 192.168.0.2 1234

同様に、あるウィンドウに入力したテキストが期待どおりに別のウィンドウに表示されます。

最後に、ターゲット(DNAT)アドレスでリッスンし、ソース(DNAT)アドレスを介して接続しようとしました。

nc -l -p 1234 -s 192.168.0.2

nc 192.168.0.1 1234

残念ながら、次のエラーが原因で接続が失敗します。

(不明) [192.168.0.1] 1234(?): 接続が拒否されました。

また、DNATが機能していることを確認しようとしましたが、ping -c 1 -R 192.168.0.1次のようには見えません。

PING 192.168.0.1 (192.168.0.1) 56(124)バイトのデータ。
192.168.0.1の64バイト:icmp_seq=1 ttl=64 time=0.047 ms
RR:192.168.0.1
        192.168.0.1
        192.168.0.1
        192.168.0.1


--- 192.168.0.1 ping統計 ---
1個のデータパケット転送、1個のデータパケット受信、パケット損失0%、時間0ms
rtt 最小/平均/最大/mdev = 0.047/0.047/0.047/0.000 ミリ秒

なぜこれがうまくいかないのですか?私は何が間違っていましたか?

tcpdumpによる診断

tcpdumpこの問題を診断するために、仮想インターフェイスからトラフィックを聞いてみました。すべてのインターフェイスでリッスンを試みました(そしてSSHとDNSをフィルタリングしました):。

sudo tcpdump -i any -e port not 22 and port not 53

dummy1その後、インターフェイスにpingを送信します。

ping -n -c 1 -I dummy1 192.168.0.1

これにより、次のような結果が出ました。

listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo request, id 8071, seq 1, length 64
In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo reply, id 8071, seq 1, length 64

したがって、仮想インターフェイスがループバックインターフェイスに接続されているように見えます。これは、iptablesルールが完全にバイパスされることを意味します。

仮想インターフェイスとPREROUTINGチェーン

2回目の試みで、仮想インターフェイスの代わりにいわゆる仮想IPアドレスを試してみました。

eth0およびeth1インターフェイスに「仮想」IPアドレスを追加する方法は次のとおりです。

sudo ip addr add 192.168.0.100/24 dev eth0
sudo ip addr add 192.168.0.101/24 dev eth1

メモ:これらのインターフェイスには、仮想インターフェイスとは異なる IP アドレスを使用しました。

その後、iptables NATルールを更新して更新しました。

sudo iptables -F -t nat

sudo iptables \
-t nat \
-A PREROUTING \
-d 192.168.0.100 \
-j DNAT --to-destination 192.168.0.101

pingテストを再試行しました。

ping -n -c 1 -R 192.168.0.100

サイコロなし:

PING 192.168.0.100 (192.168.0.100) 56(124)バイトのデータです。
192.168.0.100の64バイト:icmp_seq=1 ttl=64 time=0.023 ms
パス:192.168.0.100
        192.168.0.100
        192.168.0.100
        192.168.0.100


--- 192.168.0.100 ping統計---
1個のデータパケット転送、1個のデータパケット受信、パケット損失0%、時間0ms
rtt 最小/平均/最大/mdev = 0.023/0.023/0.023/0.000 ミリ秒

その後、netcatテストを再実行してください。サーバーを起動します。

nc -l -p 1234 -s 192.168.0.101

クライアント接続を試みます。

nc 192.168.0.100 1234

サイコロもありません:

(不明) [192.168.0.100] 1234(?): 接続が拒否されました。

PREROUTINGの代わりにOUTPUTチェーンを使用してください。

次に、PREROUTINGチェーンからOUTPUTチェーンに2つのDNATルールを移動しました。

sudo iptables -F -t nat

sudo iptables \
-t nat \
-A OUTPUT \
-d 192.168.0.1 \
-j DNAT --to-destination 192.168.0.2

sudo iptables \
-t nat \
-A OUTPUT \
-d 192.168.0.100 \
-j DNAT --to-destination 192.168.0.101

これで、仮想インターフェイスと仮想インターフェイスの両方に対してpingを試みます。

ユーザー@ホスト:~$ ping -c 1 -R 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(124)バイトのデータ。
192.168.0.1の64バイト:icmp_seq=1 ttl=64 time=0.061 ms
RR:192.168.0.1
        192.168.0.2
        192.168.0.2
        192.168.0.1


--- 192.168.0.1 ping統計 ---
1個のデータパケット転送、1個のデータパケット受信、パケット損失0%、時間0ms
rtt 最小/平均/最大/mdev = 0.061/0.061/0.061/0.000 ミリ秒

ユーザー@ホスト:~$ ping -c 1 -R 192.168.0.100

PING 192.168.0.100 (192.168.0.100) 56(124)バイトのデータです。
192.168.0.100 の 64 バイト: icmp_seq=1 ttl=64 time=0.058 ms
パス:192.168.0.100
        192.168.0.101
        192.168.0.101
        192.168.0.100


--- 192.168.0.100 ping統計---
1個のデータパケット転送、1個のデータパケット受信、パケット損失0%、時間0ms
rtt 最小/平均/最大/mdev = 0.058/0.058/0.058/0.000 ミリ秒

また、各IPアドレスペアに対してnetcatクライアントとサーバーのテストを試みました。

nc -l -p 1234 -s 192.168.0.2

nc 192.168.0.1 1234

そして:

nc -l -p 1234 -s 192.168.0.101

nc 192.168.0.100 1234

今回のテストも成功しました。

したがって、DNATルールがPREROUTINGチェーンではなくOUTPUTチェーンにある場合、仮想インターフェイスと仮想インターフェイスの両方が機能するようです。

私の問題のいくつかは、どのパケットがどのチェーンを通過するのかがはっきりわからないことです。

ベストアンサー1

簡単な説明:仮想インターフェイスと仮想IPアドレスは、PREROUTINGチェーンの影響を受けないループバックインターフェイスを介してパケットを送信します。 vethインターフェイスを持つネットワークネームスペースを使用すると、あるIPアドレスから別のIPアドレスにトラフィックを送信できるため、マルチホストネットワークトラフィックをより正確にシミュレートし、必要に応じてPREROUTINGチェーンでDNATルールをテストできます。

以下は、ソリューションの詳細な説明です。


以下は、ネットワークインタフェースのペアを設定し、DNATルールが期待どおりに機能するかどうかをテストするBashスクリプトです。

# Create a network namespace to represent a client
sudo ip netns add 'client'

# Create a network namespace to represent a server
sudo ip netns add 'server'

# Create a veth virtual-interface pair
sudo ip link add 'client-eth0' type veth peer name 'server-eth0'

# Assign the interfaces to the namespaces
sudo ip link set 'client-eth0' netns 'client'
sudo ip link set 'server-eth0' netns 'server'

# Change the names of the interfaces (I prefer to use standard interface names)
sudo ip netns exec 'client' ip link set 'client-eth0' name 'eth0'
sudo ip netns exec 'server' ip link set 'server-eth0' name 'eth0'

# Assign an address to each interface
sudo ip netns exec 'client' ip addr add 192.168.1.1/24 dev eth0
sudo ip netns exec 'server' ip addr add 192.168.2.1/24 dev eth0

# Bring up the interfaces (the veth interfaces the loopback interfaces)
sudo ip netns exec 'client' ip link set 'lo' up
sudo ip netns exec 'client' ip link set 'eth0' up
sudo ip netns exec 'server' ip link set 'lo' up
sudo ip netns exec 'server' ip link set 'eth0' up

# Configure routes
sudo ip netns exec 'client' ip route add default via 192.168.1.1 dev eth0
sudo ip netns exec 'server' ip route add default via 192.168.2.1 dev eth0

# Test the connection (in both directions)
sudo ip netns exec 'client' ping -c 1 192.168.2.1
sudo ip netns exec 'server' ping -c 1 192.168.1.1

# Add a DNAT rule to the server namespace
sudo ip netns exec 'server' \
iptables \
-t nat \
-A PREROUTING \
-d 192.168.2.1 \
-j DNAT --to-destination 192.168.2.2

# Add a dummy interface to the server (we need a target for the destination address)
sudo ip netns exec 'server' ip link add dummy type dummy
sudo ip netns exec 'server' ip addr add 192.168.2.2/24 dev dummy
sudo ip netns exec 'server' ip link set 'dummy' up

# Test the DNAT rule using ping
sudo ip netns exec 'client' ping -c 1 -R 192.168.2.1

pingテストの出力は、ルールが実行中であることを示しています。

PING 192.168.2.1 (192.168.2.1) 56(124) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.025 ms
RR:     192.168.1.1
        192.168.2.2
        192.168.2.2
        192.168.1.1


--- 192.168.2.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms

これでNetCatテストも実行できます。まずサーバーから受信します。

sudo ip netns exec 'server' nc -l -p 1234 -s 192.168.2.2

次に、クライアントを介して接続します(別の端末ウィンドウで)。

sudo ip netns exec 'client' nc 192.168.2.1 1234

ある端末ウィンドウに入力したテキストが別のウィンドウに表示されます。成功しました!

おすすめ記事