ろうとるがPythonを扱う、、（その17：Scapyでルーティングおよびブリッジ）

# Scapyでルーティングおよびブリッジを実現
Scapy（Pythonにてネットワークパケットを生成などするライブラリ）の２回目（前回は「[tracerouteを考察](https://qiita.com/infinite1oop/items/14a4e5fb0bac894bcbcc)」でとりあげた）。今回は、ルーティングおよびブリッジを実現してみる。

## ルーティング
ネットワーク的には下記のようなもの。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/21ec13c4-471a-d690-f862-7d8e40df13ce.png)
VirtualBoxの３つのVMを利用。両側の異なるネットワークを中央のVM(Lubuntu)でルーティングする。

### ソースコード
```python
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上にもかかわらず、とても遅い。無駄なことをしているのであろう。ブリッジでの結果に続く。

## ブリッジ
ネットワーク的には下記のようなもの。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/1b9d415e-9d91-becc-4f78-5a8c54552ee2.png)
中央のVM(Lubuntu)ネットワークブリッジ、両端は同一ネットワークセグメントに属する。

### ソースコード
調べると、”bridge_and_sniff()”として、scapy内に用意されていることがわかった。ソースコード的には、[こちら](https://github.com/secdev/scapy/blob/master/scapy/sendrecv.py)にある。
```python
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