Repository: secdev/scapy

Issue:
Scapy no longer imports nexthop routes properly
Nexthop routes with the form `ip route add 48.0.54.0/24 via 80.0.12.2 dev eth6.474` no longer appear in scapy's routing table after #554 was committed, causing errors when attempting to send to ip addresses in the routed subnet `48.0.54.0/24`.

### Prior Behavior
As can be seen below, prior to #554, nexthop routes were populated into scapy's routing table properly, allowing us to send traffic to `48.0.54.1` properly. Apologies in advance for the wall of text.

```
[~/scapy]$ git show -q | cat
commit 63f75c596f4ca167b0f95e4401f8ec53866ad1f5
Author: gpotter2 <gabriel@potter.fr>
Date:   Fri Apr 14 16:49:32 2017 +0200

    Remove unused import
[~/scapy]$ ip route
# ...
48.0.54.0/24 via 80.0.12.2 dev eth6.474 
# ...
80.0.12.0/24 dev eth6.474  proto kernel  scope link  src 80.0.12.1 
# ...
[~/scapy]$ sudo ./run_scapy 
INFO: Can't import matplotlib. Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
INFO: Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption.
INFO: Can't import python-cryptography v1.7+. Disabled IPsec encryption/authentication.
INFO: Can't import python-cryptography v1.7+. Disabled PKI & TLS crypto-related features.
Welcome to Scapy (2.3.3.dev388)
>>> conf.route
Network     Netmask        Gateway     Iface     Output IP  
# ...
48.0.54.0   255.255.255.0  80.0.12.2   eth6.474  80.0.12.1  
# ...
80.0.12.0   255.255.255.0  0.0.0.0     eth6.474  80.0.12.1  
# ...
>>> send(IP(dst='48.0.54.1') / TCP(dport=53, sport=RandShort()) / DNS(rd=1,qd=DNSQR(qname="www.google.com")),verbose=0, inter=1,loop=1)
^C>>>
```
### Current (broken) Behavior
However after #554, nexthop routes no longer appear in scapy's routing table, no longer allowing us to send traffic to `48.0.54.1`.
```
[~/scapy]$ git show -q | cat
commit e936a20529e473fe420db2002c0845e6ae15808a
Merge: 63f75c5 797544c
Author: Pierre Lalet <pierre@droids-corp.org>
Date:   Sat Apr 15 20:01:24 2017 +0200

    Merge pull request #554 from guedou/prxyg3n
    
    [rewritten] PR #280
[~/scapy]$ ip route
# ...
48.0.54.0/24 via 80.0.12.2 dev eth6.474 
# ...
80.0.12.0/24 dev eth6.474  proto kernel  scope link  src 80.0.12.1 
# ...
[~/scapy]$ sudo ./run_scapy 
INFO: Can't import matplotlib. Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
INFO: Can't import python-cryptography v1.7+. Disabled WEP decryption/encryption.
INFO: Can't import python-cryptography v1.7+. Disabled IPsec encryption/authentication.
INFO: Can't import python-cryptography v1.7+. Disabled PKI & TLS crypto-related features.
Welcome to Scapy (2.3.3.dev394)
>>> conf.route
Network     Netmask        Gateway    Iface     Output IP  
# ...
80.0.12.0   255.255.255.0  0.0.0.0    eth6.474  80.0.12.1  
# ...
>>> send(IP(dst='48.0.54.1') / TCP(dport=53, sport=RandShort()) / DNS(rd=1,qd=DNSQR(qname="www.google.com")),verbose=0, inter=1,loop=1)
WARNING: No route found (no default route?)
WARNING: No route found (no default route?)
WARNING: more No route found (no default route?)
WARNING: No route found (no default route?)
WARNING: No route found (no default route?)
WARNING: more No route found (no default route?)
^C>>> 
```
### Full output
The full output from the above tests can be found here: https://gist.github.com/jonesnl/8985bf978b337862994bec096ec38166


Discussion:
Thanks for this detailed issue.

Could you also share the output of /proc/net/route ? That will help me reproduce and fix the issue.

Here's the complete routing table and the output from `/proc/net/route`. The routing table may have changed from when I submitted the bug, as it's on one of our shared Linux testbed devices.

```
[~/scapy]$ ip route
10.0.0.0/8 via 10.8.22.1 dev eth0  metric 3 
10.8.22.0/23 dev eth0  proto kernel  scope link  src 10.8.22.106 
16.0.16.0/24 dev eth7.461  proto kernel  scope link  src 16.0.16.1 
16.0.46.0/24 dev eth1.745  proto kernel  scope link  src 16.0.46.1 
16.0.48.0/24 dev eth2.456  proto kernel  scope link  src 16.0.48.2 
16.0.49.0/24 dev eth7.817  proto kernel  scope link  src 16.0.49.2 
32.0.5.0/24 dev eth1.444  proto kernel  scope link  src 32.0.5.1 
32.0.31.0/24 dev eth7.489  proto kernel  scope link  src 32.0.31.1 
32.0.37.0/24 dev eth1.578  proto kernel  scope link  src 32.0.37.1 
32.0.46.0/24 dev eth7.718  proto kernel  scope link  src 32.0.46.2 
32.0.52.0/24 via 144.0.72.2 dev eth6.743 
32.0.74.0/24 dev eth2.956  proto kernel  scope link  src 32.0.74.2 
48.0.22.0/24 dev eth1.749  proto kernel  scope link  src 48.0.22.1 
48.0.54.0/24 via 80.0.12.2 dev eth6.474 
48.0.56.0/24 dev eth7.886  proto kernel  scope link  src 48.0.56.1 
64.0.0.0/24 dev eth6.677  proto kernel  scope link  src 64.0.0.3 
64.0.2.0/24 via 32.0.31.2 dev eth7.489 
64.0.13.0/24 dev eth1.533  proto kernel  scope link  src 64.0.13.1 
64.0.18.0/24 dev eth6.537  proto kernel  scope link  src 64.0.18.2 
64.0.35.0/24 via 32.0.5.2 dev eth1.444 
64.0.67.0/24 via 112.0.69.1 dev eth2.885 
80.0.12.0/24 dev eth6.474  proto kernel  scope link  src 80.0.12.1 
80.0.21.0/24 dev eth6.722  proto kernel  scope link  src 80.0.21.1 
80.0.42.0/24 dev eth2.772  proto kernel  scope link  src 80.0.42.2 
80.0.45.0/24 dev eth1.546  proto kernel  scope link  src 80.0.45.1 
80.0.52.0/24 dev eth7.843  proto kernel  scope link  src 80.0.52.2 
80.0.54.0/24 via 48.0.22.2 dev eth1.749  metric 37 
80.0.55.0/24 dev eth7.584  proto kernel  scope link  src 80.0.55.3 
80.0.65.0/24 dev eth2.883  proto kernel  scope link  src 80.0.65.1 
96.0.27.0/24 via 32.0.37.2 dev eth1.578 
96.0.29.0/24 dev eth2.518  proto kernel  scope link  src 96.0.29.3 
96.0.41.0/24 dev eth6.667  proto kernel  scope link  src 96.0.41.2 
96.0.52.0/24 dev eth2.864  proto kernel  scope link  src 96.0.52.1 
112.0.35.0/24 dev eth6.447  proto kernel  scope link  src 112.0.35.3 
112.0.50.0/24 dev eth2.899  proto kernel  scope link  src 112.0.50.3 
112.0.59.0/24 via 16.0.49.1 dev eth7.817 
112.0.69.0/24 dev eth2.885  proto kernel  scope link  src 112.0.69.2 
127.0.0.0/8 dev lo  scope host 
127.0.0.0/8 via 127.0.0.1 dev lo 
128.0.68.0/24 dev eth2.816  proto kernel  scope link  src 128.0.68.2 
128.0.72.0/24 dev eth1.901  proto kernel  scope link  src 128.0.72.2 
144.0.16.0/24 via 80.0.21.2 dev eth6.722 
144.0.63.0/24 dev eth7.950  proto kernel  scope link  src 144.0.63.3 
144.0.72.0/24 dev eth6.743  proto kernel  scope link  src 144.0.72.1 
144.0.73.0/24 via 96.0.52.2 dev eth2.864  metric 56 
[~/scapy]$ cat /proc/net/route 
Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                       
eth0	0000000A	0116080A	0003	0	0	3	000000FF	0	0	0                                                                               
eth0	0016080A	00000000	0001	0	0	0	00FEFFFF	0	0	0                                                                               
eth7.461	00100010	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.745	002E0010	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.456	00300010	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.817	00310010	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.444	00050020	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.489	001F0020	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.578	00250020	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.718	002E0020	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.743	00340020	02480090	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.956	004A0020	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.749	00160030	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.474	00360030	020C0050	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.886	00380030	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.677	00000040	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.489	00020040	021F0020	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.533	000D0040	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.537	00120040	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.444	00230040	02050020	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.885	00430040	01450070	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.474	000C0050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.722	00150050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.772	002A0050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.546	002D0050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.843	00340050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.749	00360050	02160030	0003	0	0	37	00FFFFFF	0	0	0                                                                          
eth7.584	00370050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.883	00410050	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.578	001B0060	02250020	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.667	00290060	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.864	00340060	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.447	00230070	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.899	00320070	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.817	003B0070	01310010	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.885	00450070	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
lo	0000007F	00000000	0001	0	0	0	000000FF	0	0	0                                                                                 
lo	0000007F	0100007F	0003	0	0	0	000000FF	0	0	0                                                                                 
eth2.816	00440080	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth1.901	00480080	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.722	00100090	02150050	0003	0	0	0	00FFFFFF	0	0	0                                                                           
eth7.950	003F0090	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth6.743	00480090	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                           
eth2.864	00490090	02340060	0003	0	0	56	00FFFFFF	0	0	0                                                                          
```
I tried to reproduce the issue and failed: `conf.route` displays the route to 48.0.54.0/24. I will need more time to mock the function behavior with your `/proc/net/route`.

In the meantime, could you try to reproduce the issue on a smaller case ? For example, I would like to know how these interfaces are created.

Thanks.
I am getting some progress here. Does the following patch work for you ?

```
diff --git a/scapy/arch/linux.py b/scapy/arch/linux.py
index 28e5db9..cee492c 100644
--- a/scapy/arch/linux.py
+++ b/scapy/arch/linux.py
@@ -254,7 +254,7 @@ def read_routes():
         dst_int = socket.htonl(int(dst, 16)) & 0xffffffff
         msk_int = socket.htonl(int(msk, 16)) & 0xffffffff
         ifaddr_int = struct.unpack("!I", ifreq[20:24])[0]
-        if ifaddr_int & msk_int != dst_int:
+        if ":" in iff and ifaddr_int & msk_int != dst_int:
             tmp_route = get_alias_address(iff, dst_int)
             if tmp_route:
                 routes.append(tmp_route)
```

That does seem to have fixed the issue we were seeing. The routes are now being populated in scapy's routing table properly.

I'm guessing that interface aliases must have a colon in them?
@guedou Could you submit your fix for that ?
@jonesnl I am still trying to fix this issue but I cannot find a way to reproduce the content of your routing table. Could you send me a small command example to add a similar entry ?
Could you clarify on what part of the routing table you're having trouble reproducing? is it the VLAN subinterfaces, the nexthop routes, or something else?
Well, it seems that my VLAN interface was down =/
FTR, the following commands seem to reproduce the issue:
```
sudo ip link add name scapy0 type dummy
sudo ip addr add 40.40.40.1/24 dev scapy0

sudo ip link set scapy0 up
sudo ifconfig scapy0:0 inet 41.41.41.1/24 up

sudo ip link add link scapy0 name scapy0.42 type vlan id 42
sudo ip addr add 42.42.42.1/24 dev scapy0.42
sudo ip route add 43.43.43.43/32 via 42.42.42.42
sudo ip link set scapy0.42 up

```

Resolving patch:
diff --git a/scapy/arch/linux.py b/scapy/arch/linux.py
--- a/scapy/arch/linux.py
+++ b/scapy/arch/linux.py
@@ -165,7 +165,7 @@ def set_promisc(s,iff,val=1):
     s.setsockopt(SOL_PACKET, cmd, mreq)
 
 
-def get_alias_address(iface_name, ip_mask):
+def get_alias_address(iface_name, ip_mask, gw_str):
     """
     Get the correct source IP address of an interface alias
     """
@@ -208,7 +208,7 @@ def get_alias_address(iface_name, ip_mask):
         # Check if the source address is included in the network
         if (ifaddr & msk) == ip_mask:
             sck.close()
-            return (ifaddr & msk, msk, "0.0.0.0", ifname,
+            return (ifaddr & msk, msk, gw_str, ifname,
                     scapy.utils.ltoa(ifaddr))
 
     sck.close()
@@ -258,14 +258,17 @@ def read_routes():
         dst_int = socket.htonl(int(dst, 16)) & 0xffffffff
         msk_int = socket.htonl(int(msk, 16)) & 0xffffffff
         ifaddr_int = struct.unpack("!I", ifreq[20:24])[0]
+        gw_str = scapy.utils.inet_ntoa(struct.pack("I", int(gw, 16)))
+
         if ifaddr_int & msk_int != dst_int:
-            tmp_route = get_alias_address(iff, dst_int)
+            tmp_route = get_alias_address(iff, dst_int, gw_str)
             if tmp_route:
                 routes.append(tmp_route)
+            else:
+                routes.append((dst_int, msk_int, gw_str, iff, ifaddr))
+
         else:
-            routes.append((dst_int, msk_int,
-                           scapy.utils.inet_ntoa(struct.pack("I", int(gw, 16))),
-                           iff, ifaddr))
+            routes.append((dst_int, msk_int, gw_str, iff, ifaddr))
     
     f.close()
     return routes


Test patch:
diff --git a/test/linux.uts b/test/linux.uts
--- a/test/linux.uts
+++ b/test/linux.uts
@@ -85,7 +85,7 @@ x is not None and ICMP in x and x[ICMP].type == 0
 #select.select([socket],[],[],2)
 #_flush_fd(socket.ins)
 
-= Interface aliases
+= Interface aliases & sub-interfaces
 ~ linux needs_root
 
 import os
@@ -96,8 +96,18 @@ exit_status = os.system("ifconfig scapy0:0 inet 198.51.100.1/24 up")
 exit_status = os.system("ip addr show scapy0")
 print(get_if_list())
 conf.route.resync()
-exit_status = os.system("ip link del name dev scapy0")
 print(conf.route.routes)
 assert(conf.route.route("198.51.100.254") == ("scapy0", "198.51.100.1", "0.0.0.0"))
 route_alias = (3325256704, 4294967040, "0.0.0.0", "scapy0", "198.51.100.1")
 assert(route_alias in conf.route.routes)
+exit_status = os.system("ip link add link scapy0 name scapy0.42 type vlan id 42")
+exit_status = os.system("ip addr add 203.0.113.42/24 dev scapy0.42")
+exit_status = os.system("ip link set scapy0.42 up")
+exit_status = os.system("ip route add 192.0.2.43/32 via 203.0.113.41")
+print(get_if_list())
+conf.route.resync()
+print(conf.route.routes)
+assert(conf.route.route("192.0.2.43") == ("scapy0.42", "203.0.113.42", "203.0.113.41"))
+route_specific = (3221226027, 4294967295, "203.0.113.41", "scapy0.42", "203.0.113.42")
+assert(route_specific in conf.route.routes)
+exit_status = os.system("ip link del name dev scapy0")