IP ルールがパケット生成を尊重していません。どうすれば修正できますか?

IP ルールがパケット生成を尊重していません。どうすれば修正できますか?

問題: 特定のインターフェースから L4 トラフィックをルーティングするように構築された IP ルールは、異なる送信元アドレスでパケットが生成された場合には尊重されません。

概要 ホストのアドレスとは異なる送信元アドレスを持つパケットを生成したいです。これを実現するために、Python のパッケージ Scapy を使用しています。注: 私の目標は DNS トラフィックを送信することですが、DNS 要求の送信元アドレスを偽装できる簡単な解決策が見つからなかったため、ポート 53 で src および dst アドレスを持つ UDP パケットを生成しています。現時点では実際の DNS プロトコルではなく、L3 と L4 のみをテストしているため、これはまだ機能すると思います。これが私のスクリプトです。

#!/usr/bin/python3

# The following is designed to generate a packet with a different source address

import sys 
from scapy.all import *

def main():
    S = "10.0.26.122" # spoofed source IP address
    D = "10.0.26.123" # destination IP address
    SP = 53 # source port
    DP = 53 # destination port
    payload = "This is a fake message" # packet payload

    spoofed_packet = IP(src=S, dst=D) / UDP(sport=53, dport=53) / payload
    send(spoofed_packet)

#Entry point
main()

スクリプトを実行する前のルート テーブルは次のようになります。

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.104.8.1      0.0.0.0         UG    101    0        0 ens192
10.0.21.0       0.0.0.0         255.255.255.0   U     104    0        0 ens256
10.0.26.0       0.0.0.0         255.255.255.0   U     0      0        0 ens224
10.0.27.0       0.0.0.0         255.255.255.0   U     102    0        0 ens193
10.0.28.0       10.0.29.1       255.255.255.0   UG    100    0        0 ens161
10.0.29.0       0.0.0.0         255.255.255.0   U     100    0        0 ens161
10.104.8.0      0.0.0.0         255.255.255.0   U     101    0        0 ens192
10.212.134.0    10.104.8.1      255.255.255.0   UG    101    0        0 ens192
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

IPインターフェースはこちら

# ip -br a
lo               UNKNOWN        127.0.0.1/8
ens161           UP             10.0.29.122/24
ens192           UP             10.104.8.122/24
ens193           UP             10.0.27.122/24
ens224           UP             10.0.26.122/24
ens256           UP             10.0.21.122/24
virbr0           DOWN           192.168.122.1/24
virbr0-nic       DOWN
ip_vti0@NONE     DOWN

スクリプトを実行すると、./packet-gen.py "10.0.26.122" "10.0.26.123"動作します。これは、IP ルール / 個別のルーティング テーブルをまだ構築していないためです。ホスト (10.0.26.122) と遠端ホスト (10.0.26.123) で tcpdump を実行すると、UDP パケットが送信されていることがわかります。また、 でテストしdig www.google.com @10.0.26.123、実際の DNS 要求が実行され、応答が返されることを確認しました。

ここで問題です。メイン テーブルのルート エントリを削除し、ポート番号に基づいてのみルートを設定したいと考えています。これを行うには、まず次のコマンドを実行して、10.0.26.0/24 へのルート エントリを削除します。

# ip route del 10.0.26.0/24 dev ens224
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.104.8.1      0.0.0.0         UG    101    0        0 ens192
10.0.21.0       0.0.0.0         255.255.255.0   U     104    0        0 ens256
10.0.27.0       0.0.0.0         255.255.255.0   U     102    0        0 ens193
10.0.28.0       10.0.29.1       255.255.255.0   UG    100    0        0 ens161
10.0.29.0       0.0.0.0         255.255.255.0   U     100    0        0 ens161
10.104.8.0      0.0.0.0         255.255.255.0   U     101    0        0 ens192
10.212.134.0    10.104.8.1      255.255.255.0   UG    101    0        0 ens192
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

エントリは削除されました。スクリプトを再度実行しても機能しません。dig 要求も失敗します。メイン カーネル ルーティング テーブルに L3 ルートがないため、これは予想どおりです。

L4 でルーティングするには、まず、すべてのトラフィックを ens224 経由で送信する新しい IP ルート テーブルを作成しました。

# ip route add table 53 0.0.0.0/0 dev ens224

次に、ポート 53 を使用するすべてのトラフィックをキャプチャする IP ルールを作成し、カスタム テーブル 53 を送信します。

# ip rule add ipproto udp dport 53 lookup 53

また、厳格なリバースパス転送ルールを緩和するために、rp_filter用の特別なsysctlルールも作成しました。

# sysctl -w "net.ipv4.conf.ens224.rp_filter=2"

自分の作業を確認するには、次のようになります。

# ip route list table 53
default dev ens224 scope link
# ip rule list
0:      from all lookup local
32765:  from all ipproto udp dport 53 lookup 53
32766:  from all lookup main
32767:  from all lookup default
# ip route get 10.0.26.123 ipproto udp dport 53
10.0.26.123 dev ens224 table 53 src 10.0.26.122 uid 0
    cache
# ip route get 10.0.26.123
10.0.26.123 via 10.104.8.1 dev ens192 src 10.104.8.122 uid 0
    cache

最後のコマンドは、通信が DNS でない場合はデフォルトでデフォルト ルートが使用されることを示しています。

これをテストするために、まず 10.0.26.123 に ping を試みます。予想どおり失敗します。次に、dig リクエストを実行してみるdig www.google.com @10.0.26.123と、成功します。dig リクエストは、メイン テーブルに行く前に IP ルールにヒットし、適切にルーティングされます。トラフィックが tcpdump (10.0.26.123) でサービスに到達し、ホスト (10.0.26.122) から来ていることがわかります。

もう一度 scapy スクリプトを実行してみましたが、何も起こりません。ホストと同じソース アドレスを使用しても、ホストまたはサーバーの tcpdump には何も表示されません。ソース アドレスを変更してみましたが、変化はなく、何も起こりません。メイン テーブルに 10.0.26.0/24 のメイン L3 ルートを追加し直すと、scapy スクリプトは再び動作します。ここで何が欠けているのでしょうか。なぜ、生成したトラフィックは、作成した IP ルール セットを尊重しないのでしょうか。

答え1

Scapy は OS のルーティング メカニズムを使用せず、 Scapy の起動時 (またはメソッドが呼び出されるたびに) conf.routeOS ルーティング テーブルから同期される独自のルーティング テーブル (オブジェクト)を使用します。conf.route.resync()

Scapy のルーティング メカニズムはソース ルーティングをサポートしていないため、説明されている動作が説明されます。

関連情報