web-dev-qa-db-ja.com

カーネルをバイパスする自己IPアドレスにpingを実行する

自分のIPアドレスにpingを実行するときに、カーネルをバイパスしてpingパケットをネットワークゲートウェイにリダイレクトする方法があるのだろうか。

たとえば、私のプライベートIPアドレスは172.31.42.99で、ゲートウェイIPは172.31.32.1です。私がやりたいのは、「ping 172.31.42.99」を実行すると、「ping172.31.32.1」の結果が得られることです。

私はIPルーティングテーブルまたはiptablesの専門家ではありませんが、ルーティングテーブルまたはiptablesを編集してこれを実現する方法があるかどうかわかりません。

Sudo ip route add 172.31.42.99/32 via 172.31.32.1を使用してルーティングテーブルを編集しようとし、natテーブルのiptables PREROUTINGチェーンを編集しようとしました。どちらも機能しませんでした。

私はどんな助けやアイデアにも感謝します。

1
chengzx

更新:ここにもっと忠実な答えを与える

「ping172.31.42.99」を実行すると、「ping172.31.32.1」の結果が得られます。

特別なルーティングを含まない、または172.31.32.1をルーターにする必要がない:単純なDNAT。

netfilter OUTPUTフックの使用

Linuxネットワークスタックには、これに見られるように、異なるルーティングステップの間に挿入されたnetfilterフックがあります 回路図 。着信パケットは、ローカルで発信された発信パケットと同じ場所で処理されないことに注意する必要があります。前者のnetfilterフックはPREROUTINGフックにありますが、後者のフックはOUTPUTフックにあります。このトラフィックを認識しないnat/PREROUTINGではなく、natルールを配置する必要があります。他に何が存在するかわからないので、念のため、他のルールの前に挿入します。

iptables -t nat -I OUTPUT -p icmp -d 172.31.42.99 -j DNAT --to-destination 172.31.32.1

OUTPUTフックで実行されたアクションは、再ルーティングチェックをトリガーする資格があります(前の図に示されているように)。指定されたパケットの最初に選択されたルートを変更します。これはIPパケットの他の特性を変更しないことに注意してください。たとえば、ソースIPは変更されません。 OPの特定のケースでは問題ありませんが、ソースはすでに正しいはずです。他の多くの場合、多くの場合、他の厄介な変更も行う必要があります(nat/POSTROUTINGのSNATなど)。

# ping 172.31.42.99
PING 172.31.42.99 (172.31.42.99) 56(84) bytes of data.
64 bytes from 172.31.42.99: icmp_seq=1 ttl=64 time=0.090 ms
64 bytes from 172.31.42.99: icmp_seq=2 ttl=64 time=0.122 ms
64 bytes from 172.31.42.99: icmp_seq=3 ttl=64 time=0.105 ms
^C
--- 172.31.42.99 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 89ms
rtt min/avg/max/mdev = 0.090/0.105/0.122/0.017 ms

同時に:

# conntrack -E -p icmp
    [NEW] icmp     1 30 src=172.31.42.99 dst=172.31.42.99 type=8 code=0 id=2029 [UNREPLIED] src=172.31.32.1 dst=172.31.42.99 type=0 code=0 id=2029
 [UPDATE] icmp     1 30 src=172.31.42.99 dst=172.31.42.99 type=8 code=0 id=2029 src=172.31.32.1 dst=172.31.42.99 type=0 code=0 id=2029

(今度いつか)

[DESTROY] icmp     1 src=172.31.42.99 dst=172.31.42.99 type=8 code=0 id=2029 src=172.31.32.1 dst=172.31.42.99 type=0 code=0 id=2029

iptablesの代わりにnftablesを使用する同等のものは次のとおりです。

# nft add table ip mynat
# nft add chain ip mynat dnaticmp '{ type nat hook output priority -100; policy accept; }'
# nft add rule ip mynat dnaticmp ip protocol icmp ip daddr 172.31.42.99 dnat to 172.31.32.1

ルーティングテーブルでトリックを行うことに基づく以前の回答

...これはおそらくOPが意図したものではありませんでした

私はここであなたに首を吊るすのに十分なロープを与えています。

前提条件(OPで満たされている):172.31.32.1はルーターである必要があります(意図された動作はLinuxルーターでのみテストされているため、次のようにする必要がある場合もあります)動作が異なる場合のLinuxルーター)。

IPネットワークは172.31.32.0/20であり、システムのネットワークインターフェイスはeth0と呼ばれていると仮定します(OPでは指定されていません)。

visibleルートを変更して結果を変更できなかった理由は、インターフェイスにアドレスを追加すると、一部のルートが...hiddenlocalルーティングテーブル。このテーブルは、rule優先度0から呼び出されるため、優先度が最も低くなります。

# ip rule show
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

# ip route show table local
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 
local 127.0.0.0/8 dev lo proto kernel scope Host src 127.0.0.1 
local 127.0.0.1 dev lo proto kernel scope Host src 127.0.0.1 
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 
broadcast 172.31.32.0 dev eth0 proto kernel scope link src 172.31.42.99 
local 172.31.42.99 dev eth0 proto kernel scope Host src 172.31.42.99 
broadcast 172.31.47.255 dev eth0 proto kernel scope link src 172.31.42.99 

# ip route get from 172.31.42.99 172.31.42.99
local 172.31.42.99 from 172.31.42.99 dev lo uid 0 
    cache <local> 

ここでの目的は、ローカルケースの前のエントリを上書きすることです。唯一の方法は、ルール0をより高い優先順位の値に「移動」して、前に何かを挿入できるようにすることです。

# ip rule add pref 100 from all lookup local
# ip rule delete pref 0

ルートを新しいルーティングテーブルに上書きするルールを追加しますが、ローカルで生成された出力の場合のみであり、特別な構文iif looutgoingを意味します。 thanfrom interface lo

# ip rule add pref 50 iif lo lookup 500

および必要なルート(ルーターのIPをゲートウェイとして設定することでARP解決を処理します):

# ip route add table 500 172.31.42.99/32 via 172.31.32.1

これで、2つの有効なルートができました(したがって、インターフェイスを交換するときに、各方向は 厳密なリバースパス転送 を通過します:eth0およびlo )。

  • 追加された特別ルート:

    # ip route get from 172.31.42.99 172.31.42.99
    172.31.42.99 from 172.31.42.99 via 172.31.32.1 dev eth0 table 500 uid 0 
        cache 
    
  • また、今から他の方向でのみ有効になります。

    # ip route get from 172.31.42.99 iif eth0 172.31.42.99
    local 172.31.42.99 from 172.31.42.99 dev lo table local 
        cache <local> iif eth0 
    

結果:

# ping 172.31.42.99
PING 172.31.42.99 (172.31.42.99) 56(84) bytes of data.
From 172.31.32.1: icmp_seq=1 Redirect Host(New nexthop: 172.31.42.99)
64 bytes from 172.31.42.99: icmp_seq=1 ttl=63 time=0.147 ms
From 172.31.32.1: icmp_seq=2 Redirect Host(New nexthop: 172.31.42.99)
64 bytes from 172.31.42.99: icmp_seq=2 ttl=63 time=0.129 ms
From 172.31.32.1: icmp_seq=3 Redirect Host(New nexthop: 172.31.42.99)
[...]

172.31.32.1はルーターであるため、これは機能しているだけです。 1回のpingで実際に発生することは次のとおりです。

  • システムは、構成されたゲートウェイ(ルーター、ルーター)にICMP要求を送信します。
  • ルーターは、システムが正しく構成されていないことを検出し、同じLAN(たまたまシステム自体)にこの要求を処理するためのより適切な直接宛先があり、ICMPリダイレクトを送信してその動作を修正するように指示します。非ルーティングノードは単にパケットをドロップしただけで、
  • ルーターは引き続きICMPエコー要求を宛先172.31.42.99にルーティングします:送信者に戻り、
  • システムはICMPエコーを受信し(有効なルートを使用し、Strict Reverse Path Forwardingルールを通過することさえあります)、以前と同じ方法でICMP応答を送り返します。
  • ルーターは再びICMPリダイレクトを送信し、
  • ルーターはまだICMP応答をルーティングし、
  • システム(およびコマンドping)がICMP応答を受信します。
2
A.B