Repository: secdev/scapy

Issue:
monitor mode of wireless device in OSX not working
When trying to run a simple program like
```
def pktIdentifier(pkt):
    if pkt.haslayer(Dot11Beacon):
        print("[+] Detected 802.11 Beacon Frame")
    elif pkt.haslayer(Dot11ProbeReq):
        print("[+] Detected 802.11 Probe Frame")
sniff(iface="en0", prn=pktIdentifier)
```
Scapy isn't able to set the network interface into proper monitoring mode. Whereas `tcpdump -i en0 -I -py IEEE802_11` immediately turns monitoring mode on and the icon in the menu bar changes to: ![bildschirmfoto 2018-02-16 um 19 57 41](https://user-images.githubusercontent.com/1454661/36324154-cecc6d60-1353-11e8-8b90-2807c8d286bc.png)

Using `conf.use_pcap` didn't work either, there is also a StackOverflow stub [here](https://stackoverflow.com/a/46914983/336633) 




Discussion:
Scapy does not enable monitor mode, as some users want to sniff the real IP traffic, while others want the 802.12 one.

 You need to do it yourself for example, using airmon-ng or ifconfig depending on your OS.




It seems that it used to be better in the old days according to this comment: https://github.com/the-tcpdump-group/libpcap/blob/7a04be7771d44a2f7e74210cc39e4df0ccef8d97/pcap-bpf.c#L752

I will try to hack something, but won't have time to push a proper fix anytime soon.
Thanks for investigating that issue! There seems to be no way in OSX to set the Airport Card into Monitor Mode, without capturing into that program. The ways I found to enter Monitor Mode was with WireShark, KisMac, `sudo tcpdump -Ii en0` and `airport sniff CHANNEL` 
But when having a capture session with i.e. tcpdump it is not possible to attach scapy on the same interface. 

pcap's [pcap_set_rfmon()](https://www.tcpdump.org/manpages/pcap_set_rfmon.3pcap.html) seems to be the sticking point here.
Hello !
I managed to implement monitor mode in Windows (https://github.com/secdev/scapy/pull/1165).

What's annoying with it is that `pcap_set_rfmon` needs to be called on non-activated handles, which means you can't use `pcap_open_live` functions (or any equivalent). For instance, I had to call even lower API (see PR: `pcap_create`, `pcap_activate`...).

You might want to grab ideas from the Windows implementation (which uses pcap)

Good week
I've poked `pypcap` to see if they could implement `pcap_set_rfmon`.

They nicely responded that there was an awaiting PR: https://github.com/pynetwork/pypcap/pull/67 that supports it.

I don't have access to an OSX machine with WiFi enabled. Would be really cool if someone could implement monitor mode.
Note: proper way to start the pcap with monitor mode enabled is

```
self.pcap = pcap_create(self.iface, self.errbuf)
pcap_set_snaplen(self.pcap, snaplen)
pcap_set_promisc(self.pcap, promisc)
pcap_set_timeout(self.pcap, to_ms)
if pcap_set_rfmon(self.pcap, 1) != 0:
    warning("Could not set monitor mode")
if pcap_activate(self.pcap) != 0:
    warning("Could not activate the handler")
```

( see #1165)
As Scapy does not need a pcap module on OS X, I want this feature to be implemented with ctypes only.

I didn't know :/ sry

Resolving patch:
diff --git a/scapy/arch/bpf/consts.py b/scapy/arch/bpf/consts.py
--- a/scapy/arch/bpf/consts.py
+++ b/scapy/arch/bpf/consts.py
@@ -19,5 +19,7 @@
 BIOCSBLEN = 0xc0044266
 BIOCGBLEN = 0x40044266
 BIOCSETF = 0x80104267
+BIOCSDLT = 0x80044278
 BIOCSHDRCMPLT = 0x80044275
 BIOCGDLT = 0x4004426a
+DLT_IEEE802_11_RADIO = 127
diff --git a/scapy/arch/bpf/supersocket.py b/scapy/arch/bpf/supersocket.py
--- a/scapy/arch/bpf/supersocket.py
+++ b/scapy/arch/bpf/supersocket.py
@@ -14,9 +14,9 @@
 from scapy.arch.bpf.core import get_dev_bpf, attach_filter
 from scapy.arch.bpf.consts import BIOCGBLEN, BIOCGDLT, BIOCGSTATS, \
     BIOCIMMEDIATE, BIOCPROMISC, BIOCSBLEN, BIOCSETIF, BIOCSHDRCMPLT, \
-    BPF_BUFFER_LENGTH
+    BPF_BUFFER_LENGTH, BIOCSDLT, DLT_IEEE802_11_RADIO
 from scapy.config import conf
-from scapy.consts import FREEBSD, NETBSD
+from scapy.consts import FREEBSD, NETBSD, DARWIN
 from scapy.data import ETH_P_ALL
 from scapy.error import Scapy_Exception, warning
 from scapy.supersocket import SuperSocket
@@ -40,7 +40,8 @@ class _L2bpfSocket(SuperSocket):
     ins = None
     closed = False
 
-    def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0):
+    def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None,
+                 nofilter=0, monitor=False):
 
         # SuperSocket mandatory variables
         if promisc is None:
@@ -75,6 +76,17 @@ def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilt
         if self.promisc:
             self.set_promisc(1)
 
+        # Set the interface to monitor mode
+        # Note: - trick from libpcap/pcap-bpf.c - monitor_mode()
+        #       - it only works on OS X 10.5 and later
+        if DARWIN and monitor:
+            dlt_radiotap = struct.pack('I', DLT_IEEE802_11_RADIO)
+            try:
+                fcntl.ioctl(self.ins, BIOCSDLT, dlt_radiotap)
+            except IOError:
+                raise Scapy_Exception("Can't set %s into monitor mode!" %
+                                      self.iface)
+
         # Don't block on read
         try:
             fcntl.ioctl(self.ins, BIOCIMMEDIATE, struct.pack('I', 1))


Test patch: