Skip to content

Commit 0bc40c6

Browse files
authored
Use L3RawSocket(6) automatically on lo (#4099)
1 parent 8eab848 commit 0bc40c6

File tree

8 files changed

+136
-100
lines changed

8 files changed

+136
-100
lines changed

doc/scapy/installation.rst

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -309,41 +309,6 @@ Screenshots
309309
:scale: 80
310310
:align: center
311311

312-
Known bugs
313-
^^^^^^^^^^
314-
315-
You may bump into the following bugs, which are platform-specific, if Scapy didn't manage work around them automatically:
316-
317-
* You may not be able to capture WLAN traffic on Windows. Reasons are explained on the `Wireshark wiki <https://wiki.wireshark.org/CaptureSetup/WLAN>`_ and in the `WinPcap FAQ <https://www.winpcap.org/misc/faq.htm>`_. Try switching off promiscuous mode with ``conf.sniff_promisc=False``.
318-
* Packets sometimes cannot be sent to localhost (or local IP addresses on your own host).
319-
320-
Winpcap/Npcap conflicts
321-
^^^^^^^^^^^^^^^^^^^^^^^
322-
323-
As ``Winpcap`` is becoming old, it's recommended to use ``Npcap`` instead. ``Npcap`` is part of the ``Nmap`` project.
324-
325-
.. note::
326-
This does NOT apply for Windows XP, which isn't supported by ``Npcap``.
327-
328-
1. If you get the message ``'Winpcap is installed over Npcap.'`` it means that you have installed both Winpcap and Npcap versions, which isn't recommended.
329-
330-
You may first **uninstall winpcap from your Program Files**, then you will need to remove::
331-
332-
C:/Windows/System32/wpcap.dll
333-
C:/Windows/System32/Packet.dll
334-
335-
And if you are on an x64 machine::
336-
337-
C:/Windows/SysWOW64/wpcap.dll
338-
C:/Windows/SysWOW64/Packet.dll
339-
340-
To use ``Npcap`` instead, as those files are not removed by the ``Winpcap`` un-installer.
341-
342-
2. If you get the message ``'The installed Windump version does not work with Npcap'`` it surely means that you have installed an old version of ``Windump``, made for ``Winpcap``.
343-
Download the correct one on https://github.com/hsluoyz/WinDump/releases
344-
345-
In some cases, it could also mean that you had installed ``Npcap`` and ``Winpcap``, and that ``Windump`` is using ``Winpcap``. Fully delete ``Winpcap`` using the above method to solve the problem.
346-
347312
Build the documentation offline
348313
===============================
349314

doc/scapy/troubleshooting.rst

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,33 @@ FAQ
88
I can't sniff/inject packets in monitor mode.
99
---------------------------------------------
1010

11-
The use monitor mode varies greatly depending on the platform.
11+
The use monitor mode varies greatly depending on the platform, reasons are explained on the `Wireshark wiki <https://wiki.wireshark.org/CaptureSetup/WLAN>`_:
12+
13+
*Unfortunately, changing the 802.11 capture modes is very platform/network adapter/driver/libpcap dependent, and might not be possible at all (Windows is very limited here).*
14+
15+
Here is some guidance on how to properly use monitor mode with Scapy:
16+
17+
- **Using Libpcap (or Npcap)**:
18+
``libpcap`` must be called differently by Scapy in order for it to create the sockets in monitor mode. You will need to pass the ``monitor=True`` to any calls that open a socket (``send``, ``sniff``...) or to a Scapy socket that you create yourself (``conf.L2Socket``...)
19+
20+
**On Windows**, you additionally need to turn on monitor mode on the WiFi card, use::
21+
22+
# Of course, conf.iface can be replaced by any interfaces accessed through conf.ifaces
23+
>>> conf.iface.setmonitor(True)
1224

13-
- **Using Libpcap**
14-
``libpcap`` must be called differently by Scapy in order for it to create the sockets in monitor mode. You will need to pass the ``monitor=True`` to any calls that open a socket (``send``, ``sniff``...) or to a Scapy socket that you create yourself (``conf.L2Socket``...)
1525
- **Native Linux (with libpcap disabled):**
16-
You should set the interface in monitor mode on your own. I personally like
17-
to use iwconfig for that (replace ``monitor`` by ``managed`` to disable)::
26+
You should set the interface in monitor mode on your own. The easiest way to do that is to use ``airmon-ng``::
27+
28+
$ sudo airmon-ng start wlan0
29+
30+
You can also use::
1831

19-
$ sudo ifconfig IFACE down
20-
$ sudo iwconfig IFACE mode monitor
21-
$ sudo ifconfig IFACE up
32+
$ iw dev wlan0 interface add mon0 type monitor
33+
$ ifconfig mon0 up
2234

23-
**If you are using Npcap:** please note that Npcap ``npcap-0.9983`` broke the 802.11 util back in 2019. It has yet to be fixed (as of Npcap 0.9994) so in the meantime, use `npcap-0.9982.exe <https://nmap.org/npcap/dist/npcap-0.9982.exe>`_
35+
If you want to enable monitor mode manually, have a look at https://wiki.wireshark.org/CaptureSetup/WLAN#linux
2436

25-
.. note:: many adapters do not support monitor mode, especially on Windows, or may incorrectly report the headers. See `the Wireshark doc about this <https://wiki.wireshark.org/CaptureSetup/WLAN>`_
37+
.. warning:: **If you are using Npcap:** please note that Npcap ``npcap-0.9983`` broke the 802.11 support until ``npcap-1.3.0``. Avoid using those versions.
2638

2739
We make our best to make this work, if your adapter works with Wireshark for instance, but not with Scapy, feel free to report an issue.
2840

@@ -35,12 +47,14 @@ I can't ping 127.0.0.1 (or ::1). Scapy does not work with 127.0.0.1 (or ::1) on
3547

3648
The loopback interface is a very special interface. Packets going through it are not really assembled and disassembled. The kernel routes the packet to its destination while it is still stored an internal structure. What you see with ```tcpdump -i lo``` is only a fake to make you think everything is normal. The kernel is not aware of what Scapy is doing behind his back, so what you see on the loopback interface is also a fake. Except this one did not come from a local structure. Thus the kernel will never receive it.
3749

38-
On Linux, in order to speak to local IPv4 applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems than Linux)::
50+
.. note:: Starting from Scapy > **2.5.0**, Scapy will automatically use ``L3RawSocket`` when necessary when using L3-functions (sr-like) on the loopback interface, when libpcap is not in use.
51+
52+
**On Linux**, in order to speak to local IPv4 applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems than Linux)::
3953

4054
>>> conf.L3socket
4155
<class __main__.L3PacketSocket at 0xb7bdf5fc>
4256
>>> conf.L3socket = L3RawSocket
43-
>>> sr1(IP(dst) / ICMP())
57+
>>> sr1(IP() / ICMP())
4458
<IP version=4L ihl=5L tos=0x0 len=28 id=40953 flags= frag=0L ttl=64 proto=ICMP chksum=0xdce5 src=127.0.0.1 dst=127.0.0.1 options='' |<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |>>
4559

4660
With IPv6, you can simply do::
@@ -50,11 +64,20 @@ With IPv6, you can simply do::
5064
<IPv6 version=6 tc=0 fl=866674 plen=8 nh=ICMPv6 hlim=64 src=::1 dst=::1 |<ICMPv6EchoReply type=Echo Reply code=0 cksum=0x7ebb id=0x0 seq=0x0 |>>
5165

5266
# Layer 2
53-
>>> conf.iface = "lo"
54-
>>> srp1(Ether() / IPv6() / ICMPv6EchoRequest())
67+
>>> srp1(Ether() / IPv6() / ICMPv6EchoRequest(), iface=conf.loopback_name)
5568
<Ether dst=00:00:00:00:00:00 src=00:00:00:00:00:00 type=IPv6 |<IPv6 version=6 tc=0 fl=866674 plen=8 nh=ICMPv6 hlim=64 src=::1 dst=::1 |<ICMPv6EchoReply type=Echo Reply code=0 cksum=0x7ebb id=0x0 seq=0x0 |>>>
5669

57-
On Windows, BSD, and macOS, you must deactivate the local firewall and set ````conf.iface``` to the loopback interface prior to using the following commands::
70+
.. warning::
71+
On Linux, libpcap does not support loopback IPv4 pings:
72+
>>> conf.use_pcap = True
73+
>>> sr1(IP() / ICMP())
74+
Begin emission:
75+
Finished sending 1 packets.
76+
.....................................
77+
78+
You can disable libpcap using ``conf.use_pcap = False`` or bypass it on layer 3 using ``conf.L3socket = L3RawSocket``.
79+
80+
**On Windows, BSD, and macOS**, you must deactivate/configure the local firewall prior to using the following commands::
5881

5982
# Layer 3
6083
>>> sr1(IP() / ICMP())
@@ -63,11 +86,45 @@ On Windows, BSD, and macOS, you must deactivate the local firewall and set ````c
6386
<IPv6 version=6 tc=0 fl=866674 plen=8 nh=ICMPv6 hlim=64 src=::1 dst=::1 |<ICMPv6EchoReply type=Echo Reply code=0 cksum=0x7ebb id=0x0 seq=0x0 |>>
6487

6588
# Layer 2
66-
>>> srp1(Loopback() / IP() / ICMP())
89+
>>> srp1(Loopback() / IP() / ICMP(), iface=conf.loopback_name)
6790
<Loopback type=IPv4 |<IP version=4 ihl=5 tos=0x0 len=28 id=56066 flags= frag=0 ttl=64 proto=icmp chksum=0x0 src=127.0.0.1 dst=127.0.0.1 |<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |>>>
68-
>>> srp1(Loopback() / IPv6() / ICMPv6EchoRequest())
91+
>>> srp1(Loopback() / IPv6() / ICMPv6EchoRequest(), iface=conf.loopback_name)
6992
<Loopback type=IPv6 |<IPv6 version=6 tc=0 fl=0 plen=8 nh=ICMPv6 hlim=64 src=::1 dst=::1 |<ICMPv6EchoReply type=Echo Reply code=0 cksum=0x7ebb id=0x0 seq=0x0 |>>>
7093

94+
Getting 'failed to set hardware filter to promiscuous mode' error
95+
-----------------------------------------------------------------
96+
97+
Disable promiscuous mode::
98+
99+
conf.sniff_promisc = False
100+
101+
Scapy says there are 'Winpcap/Npcap conflicts'
102+
----------------------------------------------
103+
104+
**On Windows**, as ``Winpcap`` is becoming old, it's recommended to use ``Npcap`` instead. ``Npcap`` is part of the ``Nmap`` project.
105+
106+
.. note::
107+
This does NOT apply for Windows XP, which isn't supported by ``Npcap``. On XP, uninstall ``Npcap`` and keep ``Winpcap``.
108+
109+
1. If you get the message ``'Winpcap is installed over Npcap.'`` it means that you have installed both Winpcap and Npcap versions, which isn't recommended.
110+
111+
You may first **uninstall winpcap from your Program Files**, then you will need to remove some files that are not deleted by the ``Winpcap`` uninstaller::
112+
113+
C:/Windows/System32/wpcap.dll
114+
C:/Windows/System32/Packet.dll
115+
116+
And if you are on an x64 machine, additionally the 32-bit variants::
117+
118+
C:/Windows/SysWOW64/wpcap.dll
119+
C:/Windows/SysWOW64/Packet.dll
120+
121+
Once that is done, you'll be able to use ``Npcap`` properly.
122+
123+
2. If you get the message ``'The installed Windump version does not work with Npcap'`` it means that you have probably installed an old version of ``Windump``, made for ``Winpcap``.
124+
Download the one compatible with ``Npcap`` on https://github.com/hsluoyz/WinDump/releases
125+
126+
In some cases, it could also mean that you had installed both ``Npcap`` and ``Winpcap``, and that the Npcap ``Windump`` is using ``Winpcap``. Fully delete ``Winpcap`` using the above method to solve the problem.
127+
71128

72129
BPF filters do not work. I'm on a ppp link
73130
------------------------------------------

doc/scapy/usage.rst

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,21 +1213,9 @@ Wireless frame injection
12131213
single: FakeAP, Dot11, wireless, WLAN
12141214

12151215
.. note::
1216-
See the TroubleShooting section for more information on the usage of Monitor mode among Scapy.
1216+
See the :doc:`TroubleShooting <troubleshooting>` section for more information on the usage of Monitor mode among Scapy.
12171217

1218-
Provided that your wireless card and driver are correctly configured for frame injection
1219-
1220-
::
1221-
1222-
$ iw dev wlan0 interface add mon0 type monitor
1223-
$ ifconfig mon0 up
1224-
1225-
On Windows, if using Npcap, the equivalent would be to call::
1226-
1227-
>>> # Of course, conf.iface can be replaced by any interfaces accessed through conf.ifaces
1228-
... conf.iface.setmonitor(True)
1229-
1230-
you can have a kind of FakeAP::
1218+
Provided that your wireless card and driver are correctly configured for frame injection, you can have a kind of FakeAP::
12311219

12321220
>>> sendp(RadioTap()/
12331221
Dot11(addr1="ff:ff:ff:ff:ff:ff",

scapy/config.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -747,10 +747,8 @@ class Conf(ConfClass):
747747
check_TCPerror_seqack = False
748748
verb = 2 #: level of verbosity, from 0 (almost mute) to 3 (verbose)
749749
prompt = Interceptor("prompt", ">>> ", _prompt_changer)
750-
#: default mode for listening socket (to get answers if you
750+
#: default mode for the promiscuous mode of a socket (to get answers if you
751751
#: spoof on a lan)
752-
promisc = True
753-
#: default mode for sniff()
754752
sniff_promisc = True # type: bool
755753
raw_layer = None # type: Type[Packet]
756754
raw_summary = False # type: Union[bool, Callable[[bytes], Any]]

scapy/interfaces.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@
1212
from collections import defaultdict
1313

1414
from scapy.config import conf
15-
from scapy.consts import WINDOWS
15+
from scapy.consts import WINDOWS, LINUX
1616
from scapy.utils import pretty_list
1717
from scapy.utils6 import in6_isvalid
1818

1919
# Typing imports
2020
import scapy
2121
from scapy.compat import UserDict
2222
from typing import (
23+
cast,
2324
Any,
2425
DefaultDict,
2526
Dict,
@@ -49,19 +50,27 @@ def reload(self):
4950
"""Same than load() but for reloads. By default calls load"""
5051
return self.load()
5152

52-
def l2socket(self):
53-
# type: () -> Type[scapy.supersocket.SuperSocket]
53+
def _l2socket(self, dev):
54+
# type: (NetworkInterface) -> Type[scapy.supersocket.SuperSocket]
5455
"""Return L2 socket used by interfaces of this provider"""
5556
return conf.L2socket
5657

57-
def l2listen(self):
58-
# type: () -> Type[scapy.supersocket.SuperSocket]
58+
def _l2listen(self, dev):
59+
# type: (NetworkInterface) -> Type[scapy.supersocket.SuperSocket]
5960
"""Return L2listen socket used by interfaces of this provider"""
6061
return conf.L2listen
6162

62-
def l3socket(self):
63-
# type: () -> Type[scapy.supersocket.SuperSocket]
63+
def _l3socket(self, dev, ipv6):
64+
# type: (NetworkInterface, bool) -> Type[scapy.supersocket.SuperSocket]
6465
"""Return L3 socket used by interfaces of this provider"""
66+
if LINUX and not self.libpcap and dev.name == conf.loopback_name:
67+
# handle the loopback case. see troubleshooting.rst
68+
if ipv6:
69+
from scapy.layers.inet6 import L3RawSocket6
70+
return cast(Type['scapy.supersocket.SuperSocket'], L3RawSocket6)
71+
else:
72+
from scapy.supersocket import L3RawSocket
73+
return L3RawSocket
6574
return conf.L3socket
6675

6776
def _is_valid(self, dev):
@@ -156,15 +165,15 @@ def is_valid(self):
156165

157166
def l2socket(self):
158167
# type: () -> Type[scapy.supersocket.SuperSocket]
159-
return self.provider.l2socket()
168+
return self.provider._l2socket(self)
160169

161170
def l2listen(self):
162171
# type: () -> Type[scapy.supersocket.SuperSocket]
163-
return self.provider.l2listen()
172+
return self.provider._l2listen(self)
164173

165-
def l3socket(self):
166-
# type: () -> Type[scapy.supersocket.SuperSocket]
167-
return self.provider.l3socket()
174+
def l3socket(self, ipv6):
175+
# type: (bool) -> Type[scapy.supersocket.SuperSocket]
176+
return self.provider._l3socket(self, ipv6)
168177

169178
def __repr__(self):
170179
# type: () -> str

scapy/sendrecv.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from threading import Thread, Event
1212
import os
1313
import re
14+
import socket
1415
import subprocess
1516
import time
1617

@@ -24,6 +25,7 @@
2425
NetworkInterface,
2526
)
2627
from scapy.packet import Packet
28+
from scapy.pton_ntop import inet_pton
2729
from scapy.utils import get_temp_file, tcpdump, wrpcap, \
2830
ContextManagerSubprocess, PcapReader, EDecimal
2931
from scapy.plist import (
@@ -439,10 +441,10 @@ def send(x, # type: _PacketIterable
439441
:param monitor: (not on linux) send in monitor mode
440442
:returns: None
441443
"""
442-
iface = _interface_selection(iface, x)
444+
iface, ipv6 = _interface_selection(iface, x)
443445
return _send(
444446
x,
445-
lambda iface: iface.l3socket(),
447+
lambda iface: iface.l3socket(ipv6),
446448
iface=iface,
447449
**kargs
448450
)
@@ -616,19 +618,26 @@ def _parse_tcpreplay_result(stdout_b, stderr_b, argv):
616618
def _interface_selection(iface, # type: Optional[_GlobInterfaceType]
617619
packet # type: _PacketIterable
618620
):
619-
# type: (...) -> _GlobInterfaceType
621+
# type: (...) -> Tuple[NetworkInterface, bool]
620622
"""
621623
Select the network interface according to the layer 3 destination
622624
"""
623-
625+
_iff, src, _ = next(packet.__iter__()).route()
626+
ipv6 = False
627+
if src:
628+
try:
629+
inet_pton(socket.AF_INET6, src)
630+
ipv6 = True
631+
except OSError:
632+
pass
624633
if iface is None:
625634
try:
626-
iff = next(packet.__iter__()).route()[0]
635+
iff = resolve_iface(_iff or conf.iface)
627636
except AttributeError:
628637
iff = None
629-
return iff or conf.iface
638+
return iff or conf.iface, ipv6
630639

631-
return iface
640+
return resolve_iface(iface), ipv6
632641

633642

634643
@conf.commands.register
@@ -644,9 +653,11 @@ def sr(x, # type: _PacketIterable
644653
"""
645654
Send and receive packets at layer 3
646655
"""
647-
iface = _interface_selection(iface, x)
648-
s = conf.L3socket(promisc=promisc, filter=filter,
649-
iface=iface, nofilter=nofilter)
656+
iface, ipv6 = _interface_selection(iface, x)
657+
s = iface.l3socket(ipv6)(
658+
promisc=promisc, filter=filter,
659+
iface=iface, nofilter=nofilter,
660+
)
650661
result = sndrcv(s, x, *args, **kargs)
651662
s.close()
652663
return result
@@ -887,8 +898,11 @@ def srflood(x, # type: _PacketIterable
887898
:param filter: provide a BPF filter
888899
:param iface: listen answers only on the given interface
889900
"""
890-
iface = resolve_iface(iface or conf.iface)
891-
s = iface.l3socket()(promisc=promisc, filter=filter, iface=iface, nofilter=nofilter) # noqa: E501
901+
iface, ipv6 = _interface_selection(iface, x)
902+
s = iface.l3socket(ipv6)(
903+
promisc=promisc, filter=filter,
904+
iface=iface, nofilter=nofilter,
905+
)
892906
r = sndrcvflood(s, x, *args, **kargs)
893907
s.close()
894908
return r
@@ -912,8 +926,11 @@ def sr1flood(x, # type: _PacketIterable
912926
:param filter: provide a BPF filter
913927
:param iface: listen answers only on the given interface
914928
"""
915-
iface = resolve_iface(iface or conf.iface)
916-
s = iface.l3socket()(promisc=promisc, filter=filter, nofilter=nofilter, iface=iface) # noqa: E501
929+
iface, ipv6 = _interface_selection(iface, x)
930+
s = iface.l3socket(ipv6)(
931+
promisc=promisc, filter=filter,
932+
nofilter=nofilter, iface=iface,
933+
)
917934
ans, _ = sndrcvflood(s, x, *args, **kargs)
918935
s.close()
919936
if len(ans) > 0:

0 commit comments

Comments
 (0)