あるインタフェースから別のインタフェースへのICMPパケットの送信元アドレスの変更

あるインタフェースから別のインタフェースへのICMPパケットの送信元アドレスの変更

私のボックスには2つのイーサネットインターフェイスがあります。作業中のシステムの制限により、インターフェイス1の送信元アドレスを持つには、すべてのICMP応答メッセージが必要です。

一例:

インターフェイス0から着信TTLが0のパケットはドロップされ、ソースアドレスが0のICMP応答が生成され、0からルーティングされます。 TTLが0の別のパケットがインターフェイス1から入ると、破棄され、ICMP応答が生成されます。送信元アドレスはインターフェイス 1 ではなくインターフェイス 0 である必要があり、インターフェイス 1 でルーティングする必要があります。可能ですか?

どちらのインターフェイスのいずれかから来る他のプロトコルのソースアドレスに影響を与えたくありません。

編集する:

特定のボックスの現在の設定は次のとおりです。

IP-BRリンク

lo           UNKNOWN   00:00:00:00:00:00 <LOOPBACK, UP, LOWER_UP>
sit0@NONE    DOWN      0.0.0.0 <NOARP>
np0          UNKNOWN   <POINTTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>
np1          UNKNOWN   <POINTTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>
eth0         UP        <POINTTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>

ip -4 -br アドレス

lo           UNKNOWN   127.0.0.1/8
np0          UNKNOWN   192.0.0.1/24
np1          UNKNOWN   192.10.1.1/24
eth0         UP        193.10.1.1/24

IPルーティング

default dev np1 scope linke
192.0.0.0/24 dev np0 proto kernel scope link src 192.0.0.1
192.10.1.0/24 dev np1 proto kernel scope link src 192.10.1.1
193.10.1.0/24 dev eth0 proto kernel scope link src 193.10.1.1

システムがVPNを実行するように設定されていません。システムには1つの物理イーサネット(eth0)と2つの仮想イーサネットインターフェース(np0とnp1)があります。

上記の命名を使用して、インターフェイス0をeth0、インターフェイス1をnp1に設定します。

答え1

L4プロトコルベースのルーティングルール

Linuxカーネル >= 4.17ポリシールーティングは、IPのレイヤ4プロトコルに基づいて実行できます。

  • スポーツ、dport、IPプロトタイプマッチング(完全な5タプルマッチングをサポート)データセンターのポリシーベースルーティングの一般的なユースケースでは、5タプルマッチングが必要です。

[...]

最初にシステムによって生成されたすべてのICMP応答(名前は) 元のソースノードに戻ると、ホストからそのノードへのすべてのトラフィックと同様に、そのソースに向かうインターフェイスのアドレスが使用されます。

# ip route get to 192.10.1.201
192.10.1.201 dev np1 src 192.10.1.1 uid 0 
    cache 
# ip route get to 193.10.1.200
193.10.1.200 dev eth0 src 193.10.1.1 uid 0 
    cache 

一般的に使用されているものとは異なる暗黙的なソースアドレスを使用して、関連するパスに対して重複していますが、変更されたエントリを表示するルーティングテーブルを追加し、ルーティングルールを使用してそのルーティングテーブルを選択できます。ただし、プロトコルがICMPの場合にのみ可能です。このルーティングテーブルは、アドレスと(通常の)ルートを設定した後に入力しなければ追加できないルートとして拒否されません。いつものように、何らかの理由でパスが消えた場合(インターフェイスがダウンして再び表示される場合など)、デフォルトのルーティングproto kernelテーブルのパスとは異なり、再追加されません。そのたびに再追加する必要があります。イベントが発生します。

ここで、インターフェイスからのトラフィックの冗長パスを変更する動作は、np1他の送信元アドレス(192.10.1.1ではなく193.10.1.1)を暗示します。

ip route add 192.10.1.0/24 dev np1 src 193.10.1.1 table 1000

上書きするには、この内容を適用する必要があります。基本ICMP専用テーブル:

ip rule add pref 100 ipproto icmp lookup 1000

非ICMPトラフィックに変更はありませんnp1

# ip route get to 192.10.1.201
192.10.1.101 dev np1 src 192.10.1.1 uid 0 
    cache 

ただし、ICMP トラフィックの場合np1:

# ip route get to 192.10.1.201 ipproto icmp
192.10.1.201 dev np1 table 1000 src 193.10.1.1 uid 0 
    cache 

したがって、OP質問の両方のケースが満たされます。 ICMP(たとえば、ICMPタイムアウト)、応答の有無にかかわらずeth0ヒントがあるアドレスから応答します。eth0np1

これは、pingなどのローカルで起動されたICMPにも影響します(下記参照)。


注意事項と詳細

  • 警告:(レイヤ2)イーサネットインターフェイスとARP

    イーサネットインターフェイスでは、np1これらのICMPエラーによって直接トリガされたARP要求もルーティングルールに従い、上記の192.10.1.1ではなく193.10.1.1から192.10.1.201を要求するようにマークされています。ただし、ノードにARPエントリがない場合にのみ適用されます。既存のノードがARPリクエスト自体を解析しない場合直前(つまり、ノードが時々発生する場合にのみ発生します)ARPキャッシュにあるがノードはARPキャッシュにはなく、通常はそうではありません。他のLinuxシステムは基本的に気にしません。ホストモデルデフォルトでは、これらのARP要求を受け入れます。他のオペレーティングシステムによっては、この「誤った」ARP要求に興味があり、応答しないことがあります。

    本当に重要な場合、すでにまれなこの状態は完全に予防することができます。arp_announce=1:

    - 1 - Try to avoid local addresses that are not in the target's
      subnet for this interface. [...]
    

    したがって、np1インターフェースの場合:

    sysctl -w net.ipv4.conf.np1.arp_announce=1
    
  • このpingコマンドは、変更されたソースアドレスも使用します。

    pingICMP応答ではないため、通常どおりに動作する必要があります。

    実際には、文書化されていないオプションの影響を受けるICMPタイプ(およびコード)を制限できます。ソースで処理される方法に応じて、ICMP タイプ + コードをルーティング ルール セレクタの宛先ポートにマッピングします。

    include/net/flow.h:

    union flowi_uli {
        struct {
            __be16  dport;
            __be16  sport;
        } ports;
    
        struct {
            __u8    type;
            __u8    code;
        } icmpt;
    
    
    union flowi_uli     uli;
    #define fl4_sport       uli.ports.sport
    #define fl4_dport       uli.ports.dport
    #define fl4_icmp_type       uli.icmpt.type
    #define fl4_icmp_code       uli.icmpt.code
    

    net/ipv4/fib_rules.c:

        if (fib_rule_port_range_set(&rule->dport_range) &&
            !fib_rule_port_inrange(&rule->dport_range, fl4->fl4_dport))
            return 0;
    

    共用体のおかげで、<=>fl4->fl4_dportは専用の構文を持たない型+コードで使用fl4_icmp_type * 256 + fl4_icmp_codeできます。ip rule ... ipproto icmp dport ...

    したがって、タイプ8(ICMP要求)以外のものに制限することは、0-7 + 9-255に制限することを意味します。 256を掛けて十分な終了間隔(+255)に調整すると、1〜2047になります(0は無効で、1から始まります)。タイプ0コード0のICMP応答は一致しませんが、一致する必要はありません。実際に応答されるため、暗黙のソースは使用されず、代わりにリモートICMP要求に使用される実際のローカル宛先が使用され、応答ソースとして使用されます) + 2304-65534(65535 ditto).元のルーティングルールから始めます。

    ip rule add pref 100 ipproto icmp lookup 1000
    
    • 2つのルールに置き換えてください。

      ip rule del pref 100
      
      ip rule add pref 100 ipproto icmp dport 1-2047 lookup 1000
      ip rule add pref 101 ipproto icmp dport 2304-65534 lookup 1000
      
    • または、初期ルールを維持してスキップするようにルールを追加します(ICMP Echoリクエストには常にコード0があるため、2048に簡素化できます)。

      ip rule del pref 100
      ip rule del pref 101
      
      ip rule add pref 100 ipproto icmp lookup 1000
      ip rule add pref 101 lookup 424242
      ip rule add pref 99 ipproto icmp dport 2048-2303 goto 101
      

    どちらを選択しても、pingコマンドは変更されません。

    # ip route get to 192.10.1.201 ipproto icmp dport 2048
    192.10.1.201 dev np1 src 192.10.1.1 uid 0 
        cache 
    

    ICMPリダイレクト(タイプ5)も同様に例外に追加する必要があります。

関連情報