Scapyでルーティングおよびブリッジを実現
Scapy(Pythonにてネットワークパケットを生成などするライブラリ)の2回目(前回は「tracerouteを考察」でとりあげた)。今回は、ルーティングおよびブリッジを実現してみる。
ルーティング
ネットワーク的には下記のようなもの。
VirtualBoxの3つのVMを利用。両側の異なるネットワークを中央のVM(Lubuntu)でルーティングする。
ソースコード
from scapy.all import *
s0 = conf.L3socket(iface='enp0s3')
s1 = conf.L3socket(iface='enp0s8')
while True:
p0 = s0.recv()
if p0:
#print(p0)
send(p0, iface='enp0s8')
p1 = s1.recv()
if p1:
#print(p1)
send(p1, iface='enp0s3')
L3ソケットを定義。あるネットワークI/Fにてパケットを受信したら、別のネットワークI/Fに送信(send())するのみ。
検証
末端PC間のpingの結果。
$ ping -c 5 -w 10000 192.168.10.1
PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data.
64 bytes from 192.168.10.1: icmp_seq=1 ttl=64 time=3046 ms
64 bytes from 192.168.10.1: icmp_seq=2 ttl=64 time=2034 ms
64 bytes from 192.168.10.1: icmp_seq=3 ttl=64 time=1036 ms
64 bytes from 192.168.10.1: icmp_seq=4 ttl=64 time=1009 ms
64 bytes from 192.168.10.1: icmp_seq=5 ttl=64 time=988 ms
VM上にもかかわらず、とても遅い。無駄なことをしているのであろう。ブリッジでの結果に続く。
ブリッジ
ネットワーク的には下記のようなもの。
中央のVM(Lubuntu)ネットワークブリッジ、両端は同一ネットワークセグメントに属する。
ソースコード
調べると、”bridge_and_sniff()”として、scapy内に用意されていることがわかった。ソースコード的には、こちらにある。
from scapy.all import *
def callback(p):
if p.haslayer(Raw):
#p.show()
wrpcap('test.pcap', p, append=True)
return True
# If it returns True, the packet is forwarded as it.
# All works
bridge_and_sniff('enp0s3', 'enp0s8', xfrm12=callback, xfrm21=callback)
#bridge_and_sniff('enp0s3', 'enp0s8')
#bridge_and_sniff('enp0s3', 'enp0s8', prn= lambda x: x.summary())
#bridge_and_sniff('enp0s3', 'enp0s8', prn=callback)
単に、ネットワークI/Fを指定するだけである。さらに、Callback関数を定義し、付加的な動作をすることができる(転送するには、Callback関数の最後に”return”が必要)。ここでは、TCPなどのデータ(Raw)が存在するパケットを、'test.pcap'としてキャプチャファイル化(追加)している。なお、コメント”# All works”以下のものはすべて動作する。
検証
「bridge_and_sniff('enp0s3', 'enp0s8')」を利用した時の末端PC間のpingの結果。
$ ping -c 5 10.1.1.2
PING 10.1.1.2 (10.1.1.2) 56(84) bytes of data.
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=4.75 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=2.92 ms
64 bytes from 10.1.1.2: icmp_seq=3 ttl=64 time=3.77 ms
64 bytes from 10.1.1.2: icmp_seq=4 ttl=64 time=2.13 ms
64 bytes from 10.1.1.2: icmp_seq=5 ttl=64 time=2.71 ms
ルーティング時の結果と比べて、格段に速い。ユーザーランドのL3処理(ソケット)に負荷がかかっていることがわかる。
おまけ(Linuxカーネルにてルーティング)
ルーティング時のネットワーク構成で、Linuxカーネルレベル(net.ipv4.ip_forward = 1)でルーティングした時の結果は下記となる。
$ ping -c 5 192.168.10.1
PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data.
64 bytes from 192.168.10.1: icmp_seq=1 ttl=63 time=2.17 ms
64 bytes from 192.168.10.1: icmp_seq=2 ttl=63 time=1.10 ms
64 bytes from 192.168.10.1: icmp_seq=3 ttl=63 time=0.693 ms
64 bytes from 192.168.10.1: icmp_seq=4 ttl=63 time=0.827 ms
64 bytes from 192.168.10.1: icmp_seq=5 ttl=63 time=0.785 ms
やはり、これが最も速い。
EOF