Scapy network stack
Scapy maintains its own network stack, which is independent from the one of your operating system. It possesses its own interfaces list, routing table, ARP cache, IPv6 neighbour cache, nameservers config… and so on, all of which is configurable.
Here are a few examples of where this is used::
- When you use sr()/send()
, Scapy will use internally its own routing table (conf.route
) in order to find which interface to use, and eventually send an ARP request.
- When using dns_resolve()
, Scapy uses its own nameservers list (conf.nameservers
) to perform the request
- etc.
Note
What’s important to note is that Scapy initializes its own tables by querying the OS-specific ones. It has therefore implemented bindings for Linux/Windows/BSD.. in order to retrieve such data, which may also be used as a high-level API, documented below.
Interfaces list
Scapy stores its interfaces list in the conf.ifaces
object.
It provides a few utility functions such as dev_from_networkname()
, dev_from_name()
or dev_from_index()
in order to access those.
>>> conf.ifaces
Source Index Name MAC IPv4 IPv6
sys 1 lo 00:00:00:00:00:00 127.0.0.1 ::1
sys 2 eth0 Microsof:12:cb:ef 10.0.0.5 fe80::10a:2bef:dc12:afae
>>> conf.ifaces.dev_from_index(2)
<NetworkInterface eth0 [UP+BROADCAST+RUNNING+SLAVE]>
You can also use the older get_if_list()
function in order to only get the interface names.
>>> get_if_list()
['lo', 'eth0']
Extcap interfaces
Scapy supports sniffing on Wireshark’s extcap interfaces. You can simply enable it using load_extcap()
(from scapy.libs.extcap
).
>>> load_extcap()
>>> conf.ifaces
Source Index Name Address
ciscodump 100 Cisco remote capture ciscodump
dpauxmon 100 DisplayPort AUX channel monitor capture dpauxmon
randpktdump 100 Random packet generator randpkt
sdjournal 100 systemd Journal Export sdjournal
sshdump 100 SSH remote capture sshdump
udpdump 100 UDP Listener remote capture udpdump
wifidump 100 Wi-Fi remote capture wifidump
Source Index Name MAC IPv4 IPv6
sys 1 lo 00:00:00:00:00:00 127.0.0.1 ::1
sys 2 eth0 Microsof:12:cb:ef 10.0.0.5 fe80::10a:2bef:dc12:afae
Here’s an example of how to use sshdump. As you can see you can pass arguments that are properly converted:
>>> load_extcap()
>>> sniff(
... iface="sshdump",
... prn=lambda x: x.summary(),
... remote_host="192.168.0.1",
... remote_username="root",
... remote_password="SCAPY",
... )
IPv4 routes
Note
If you want to change or edit the routes, have a look at the “Routing” section in Usage
The routes are stores in conf.route
. You can use it to display the routes, or get specific routing
>>> conf.route
Network Netmask Gateway Iface Output IP Metric
0.0.0.0 0.0.0.0 10.0.0.1 eth0 10.0.0.5 100
10.0.0.0 255.255.255.0 0.0.0.0 eth0 10.0.0.5 0
127.0.0.0 255.0.0.0 0.0.0.0 lo 127.0.0.1 1
168.63.129.16 255.255.255.255 10.0.0.1 eth0 10.0.0.5 100
169.254.169.254 255.255.255.255 10.0.0.1 eth0 10.0.0.5 100
Get the route for a specific IP: conf.route.route()
will return (interface, outgoing_ip, gateway)
>>> conf.route.route("127.0.0.1")
('lo', '127.0.0.1', '0.0.0.0')
IPv6 routes
Same than IPv4 but with conf.route6
Get default gateway IP address
>>> gw = conf.route.route("0.0.0.0")[2]
>>> gw
'10.0.0.1'
Get the IP of an interface
Use conf.iface
>>> ip = get_if_addr(conf.iface) # default interface
>>> ip = get_if_addr("eth0")
>>> ip
'10.0.0.5'
Get the MAC of an interface
>>> mac = get_if_hwaddr(conf.iface) # default interface
>>> mac = get_if_hwaddr("eth0")
>>> mac
'54:3f:19:c9:38:6d'
Get MAC by IP
This basically performs a cached ARP who-has.
>>> mac = getmacbyip("10.0.0.1")
>>> mac
'f3:ae:5e:76:31:9b'