def get_if_raw_addr(ifname): """Returns the IPv4 address configured on 'ifname', packed with inet_pton.""" # noqa: E501 ifname = network_name(ifname) # Get ifconfig output subproc = subprocess.Popen( [conf.prog.ifconfig, ifname], close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout, stderr = subproc.communicate() if subproc.returncode: warning("Failed to execute ifconfig: (%s)", plain_str(stderr).strip()) return b"\0\0\0\0" # Get IPv4 addresses addresses = [ line.strip() for line in plain_str(stdout).splitlines() if "inet " in line ] if not addresses: warning("No IPv4 address found on %s !", ifname) return b"\0\0\0\0" # Pack the first address address = addresses[0].split(' ')[1] if '/' in address: # NetBSD 8.0 address = address.split("/")[0] return socket.inet_pton(socket.AF_INET, address)
def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None, replay_args=None, # noqa: E501 parse_results=False): """Send packets at layer 2 using tcpreplay for performance :param pps: packets per second :param mpbs: MBits per second :param realtime: use packet's timestamp, bending time with real-time value :param loop: number of times to process the packet list :param file_cache: cache packets in RAM instead of reading from disk at each iteration :param iface: output interface :param replay_args: List of additional tcpreplay args (List[str]) :param parse_results: Return a dictionary of information outputted by tcpreplay (default=False) :returns: stdout, stderr, command used """ if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % network_name(iface)] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%f" % mbps) elif realtime is not None: argv.append("--multiplier=%f" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--preload-pcap") # Check for any additional args we didn't cover. if replay_args is not None: argv.extend(replay_args) f = get_temp_file() argv.append(f) wrpcap(f, x) results = None with ContextManagerSubprocess(conf.prog.tcpreplay): try: cmd = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception: os.unlink(f) raise else: stdout, stderr = cmd.communicate() if stderr: log_runtime.warning(stderr.decode()) if parse_results: results = _parse_tcpreplay_result(stdout, stderr, argv) elif conf.verb > 2: log_runtime.info(stdout.decode()) os.unlink(f) return results
def get_if_raw_hwaddr(ifname): """Returns the packed MAC address configured on 'ifname'.""" NULL_MAC_ADDRESS = b'\x00' * 6 ifname = network_name(ifname) # Handle the loopback interface separately if ifname == conf.loopback_name: return (ARPHDR_LOOPBACK, NULL_MAC_ADDRESS) # Get ifconfig output subproc = subprocess.Popen([conf.prog.ifconfig, ifname], close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = subproc.communicate() if subproc.returncode: raise Scapy_Exception("Failed to execute ifconfig: (%s)" % plain_str(stderr).strip()) # Get MAC addresses addresses = [ line.strip() for line in plain_str(stdout).splitlines() if ("ether" in line or "lladdr" in line or "address" in line) ] if not addresses: raise Scapy_Exception("No MAC address found on %s !" % ifname) # Pack and return the MAC address mac = addresses[0].split(' ')[1] mac = [chr(int(b, 16)) for b in mac.split(':')] return (ARPHDR_ETHER, ''.join(mac))
def send(self, x): # type: (Packet) -> int iff = x.route()[0] if iff is None: iff = network_name(conf.iface) sdto = (iff, self.type) self.outs.bind(sdto) sn = self.outs.getsockname() ll = lambda x: x # type: Callable[[Packet], Packet] type_x = type(x) if type_x in conf.l3types: sdto = (iff, conf.l3types.layer2num[type_x]) if sn[3] in conf.l2types: ll = lambda x: conf.l2types.num2layer[sn[3]]() / x if self.lvl == 3 and type_x != self.LL: warning("Incompatible L3 types detected using %s instead of %s !", type_x, self.LL) self.LL = type_x sx = raw(ll(x)) x.sent_time = time.time() try: return self.outs.sendto(sx, sdto) except socket.error as msg: if msg.errno == 22 and len(sx) < conf.min_pkt_size: return self.outs.send(sx + b"\x00" * (conf.min_pkt_size - len(sx))) elif conf.auto_fragment and msg.errno == 90: i = 0 for p in x.fragment(): i += self.outs.sendto(raw(ll(p)), sdto) return i else: raise
def __init__( self, iface=None, # type: Optional[_GlobInterfaceType] promisc=False, # type: bool filter=None, # type: Optional[str] nofilter=False, # type: bool prog=None, # type: Optional[str] *arg, # type: Any **karg # type: Any ): # type: (...) -> None self.outs = None args = ['-w', '-', '-s', '65535'] if iface is None and (WINDOWS or DARWIN): iface = conf.iface self.iface = iface if iface is not None: args.extend(['-i', network_name(iface)]) if not promisc: args.append('-p') if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: args.append(filter) self.tcpdump_proc = tcpdump(None, prog=prog, args=args, getproc=True) self.reader = PcapReader(self.tcpdump_proc.stdout) self.ins = self.reader # type: ignore
def _read_routes_c_v1(): """Retrieve Windows routes through a GetIpForwardTable call. This is compatible with XP but won't get IPv6 routes.""" def _extract_ip(obj): return inet_ntop(socket.AF_INET, struct.pack("<I", obj)) routes = [] for route in GetIpForwardTable(): ifIndex = route['ForwardIfIndex'] dest = route['ForwardDest'] netmask = route['ForwardMask'] nexthop = _extract_ip(route['ForwardNextHop']) metric = route['ForwardMetric1'] # Build route try: iface = dev_from_index(ifIndex) if not iface.ip or iface.ip == "0.0.0.0": continue except ValueError: continue ip = iface.ip netw = network_name(iface) # RouteMetric + InterfaceMetric metric = metric + iface.ipv4_metric routes.append((dest, netmask, nexthop, netw, ip, metric)) return routes
def __init__( self, type=ETH_P_IP, # type: int filter=None, # type: Optional[str] iface=None, # type: Optional[_GlobInterfaceType] promisc=None, # type: Optional[bool] nofilter=0 # type: int ): # type: (...) -> None self.outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) # noqa: E501 self.outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1) self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) # noqa: E501 self.iface = iface if iface is not None: iface = network_name(iface) self.ins.bind((iface, type)) if not six.PY2: try: # Receive Auxiliary Data (VLAN tags) self.ins.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1) self.ins.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPNS, 1) self.auxdata_available = True except OSError: # Note: Auxiliary Data is only supported since # Linux 2.6.21 msg = "Your Linux Kernel does not support Auxiliary Data!" log_runtime.info(msg)
def __init__(self, device, snaplen, promisc, to_ms, monitor=None): device = network_name(device) self.errbuf = create_string_buffer(PCAP_ERRBUF_SIZE) self.iface = create_string_buffer(device.encode("utf8")) self.dtl = None if monitor: if WINDOWS and not conf.use_npcap: raise OSError("On Windows, this feature requires NPcap !") # Npcap-only functions from scapy.libs.winpcapy import pcap_create, \ pcap_set_snaplen, pcap_set_promisc, \ pcap_set_timeout, pcap_set_rfmon, pcap_activate 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: log_runtime.error("Could not set monitor mode") if pcap_activate(self.pcap) != 0: raise OSError("Could not activate the pcap handler") else: self.pcap = pcap_open_live(self.iface, snaplen, promisc, to_ms, self.errbuf) error = bytes(bytearray(self.errbuf)).strip(b"\x00") if error: raise OSError(error) if WINDOWS: # Winpcap/Npcap exclusive: make every packet to be instantly # returned, and not buffered within Winpcap/Npcap pcap_setmintocopy(self.pcap, 0) self.header = POINTER(pcap_pkthdr)() self.pkt_data = POINTER(c_ubyte)() self.bpf_program = bpf_program()
def __init__(self, iface=None, promisc=None, filter=None, nofilter=False, prog=None, *arg, **karg): self.outs = None args = ['-w', '-', '-s', '65535'] if iface is None and (WINDOWS or DARWIN): iface = conf.iface self.iface = iface if iface is not None: args.extend(['-i', network_name(iface)]) if not promisc: args.append('-p') if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: args.append(filter) self.tcpdump_proc = tcpdump(None, prog=prog, args=args, getproc=True) self.ins = PcapReader(self.tcpdump_proc.stdout)
def get_if(iff, cmd): """Ease SIOCGIF* ioctl calls""" iff = network_name(iff) sck = socket.socket() try: return ioctl(sck, cmd, struct.pack("16s16x", iff.encode("utf8"))) finally: sck.close()
def get_if(iff, cmd): # type: (Union[NetworkInterface, str], int) -> bytes """Ease SIOCGIF* ioctl calls""" iff = network_name(iff) sck = socket.socket() try: return ioctl(sck, cmd, struct.pack("16s16x", iff.encode("utf8"))) finally: sck.close()
def compile_filter( filter_exp, # type: str iface=None, # type: Optional[Union[str, 'scapy.interfaces.NetworkInterface']] # noqa: E501 linktype=None, # type: Optional[int] promisc=False # type: bool ): # type: (...) -> bpf_program """Asks libpcap to parse the filter, then build the matching BPF bytecode. :param iface: if provided, use the interface to compile :param linktype: if provided, use the linktype to compile """ try: from scapy.libs.winpcapy import (PCAP_ERRBUF_SIZE, pcap_open_live, pcap_compile, pcap_compile_nopcap, pcap_close) except OSError: raise ImportError("libpcap is not available. Cannot compile filter !") from ctypes import create_string_buffer bpf = bpf_program() bpf_filter = create_string_buffer(filter_exp.encode("utf8")) if not linktype: # Try to guess linktype to avoid root if not iface: if not conf.iface: raise Scapy_Exception( "Please provide an interface or linktype!") iface = conf.iface # Try to guess linktype to avoid requiring root try: arphd = get_if_raw_hwaddr(iface)[0] linktype = ARPHRD_TO_DLT.get(arphd) except Exception: # Failed to use linktype: use the interface pass if not linktype and conf.use_bpf: linktype = ARPHDR_ETHER if linktype is not None: ret = pcap_compile_nopcap(MTU, linktype, ctypes.byref(bpf), bpf_filter, 0, -1) elif iface: err = create_string_buffer(PCAP_ERRBUF_SIZE) iface_b = create_string_buffer(network_name(iface).encode("utf8")) pcap = pcap_open_live(iface_b, MTU, promisc, 0, err) error = bytes(bytearray(err)).strip(b"\x00") if error: raise OSError(error) ret = pcap_compile(pcap, ctypes.byref(bpf), bpf_filter, 0, -1) pcap_close(pcap) if ret == -1: raise Scapy_Exception("Failed to compile filter expression %s (%s)" % (filter_exp, ret)) return bpf
def send(self, pkt): """Send a packet""" from scapy.layers.l2 import Loopback # Use the routing table to find the output interface iff = pkt.route()[0] if iff is None: iff = network_name(conf.iface) # Assign the network interface to the BPF handle if self.assigned_interface != iff: try: fcntl.ioctl(self.outs, BIOCSETIF, struct.pack("16s16x", iff.encode())) # noqa: E501 except IOError: raise Scapy_Exception("BIOCSETIF failed on %s" % iff) self.assigned_interface = iff # Build the frame # # LINKTYPE_NULL / DLT_NULL (Loopback) is a special case. From the # bpf(4) man page (from macOS/Darwin, but also for BSD): # # "A packet can be sent out on the network by writing to a bpf file # descriptor. [...] Currently only writes to Ethernets and SLIP links # are supported." # # Headers are only mentioned for reads, not writes, and it has the # name "NULL" and id=0. # # The _correct_ behaviour appears to be that one should add a BSD # Loopback header to every sent packet. This is needed by FreeBSD's # if_lo, and Darwin's if_lo & if_utun. # # tuntaposx appears to have interpreted "NULL" as "no headers". # Thankfully its interfaces have a different name (tunX) to Darwin's # if_utun interfaces (utunX). # # There might be other drivers which make the same mistake as # tuntaposx, but these are typically provided with VPN software, and # Apple are breaking these kexts in a future version of macOS... so # the problem will eventually go away. They already don't work on Macs # with Apple Silicon (M1). if DARWIN and iff.startswith('tun') and self.guessed_cls == Loopback: frame = raw(pkt) else: frame = raw(self.guessed_cls() / pkt) pkt.sent_time = time.time() # Send the frame L2bpfSocket.send(self, frame)
def __init__(self, iface=None, *args, **karg): _usbpcap_check() if iface is None: warning("Available interfaces: [%s]", " ".join(x[0] for x in get_usbpcap_interfaces())) raise NameError("No interface specified !" " See get_usbpcap_interfaces()") iface = network_name(iface) self.outs = None args = ['-d', iface, '-b', '134217728', '-A', '-o', '-'] self.usbpcap_proc = subprocess.Popen([conf.prog.usbpcapcmd] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.ins = PcapReader(self.usbpcap_proc.stdout)
def _read_routes_c(ipv6=False): """Retrieve Windows routes through a GetIpForwardTable2 call. This is not available on Windows XP !""" af = socket.AF_INET6 if ipv6 else socket.AF_INET sock_addr_name = 'Ipv6' if ipv6 else 'Ipv4' sin_addr_name = 'sin6_addr' if ipv6 else 'sin_addr' metric_name = 'ipv6_metric' if ipv6 else 'ipv4_metric' if ipv6: lifaddr = in6_getifaddr() routes = [] def _extract_ip(obj): ip = obj[sock_addr_name][sin_addr_name] ip = bytes(bytearray(ip['byte'])) # Build IP ip = inet_ntop(af, ip) return ip for route in GetIpForwardTable2(af): # Extract data ifIndex = route['InterfaceIndex'] dest = _extract_ip(route['DestinationPrefix']['Prefix']) netmask = route['DestinationPrefix']['PrefixLength'] nexthop = _extract_ip(route['NextHop']) metric = route['Metric'] # Build route try: iface = dev_from_index(ifIndex) if not iface.ip or iface.ip == "0.0.0.0": continue except ValueError: continue ip = iface.ip netw = network_name(iface) # RouteMetric + InterfaceMetric metric = metric + getattr(iface, metric_name) if ipv6: _append_route6(routes, dest, netmask, nexthop, netw, lifaddr, metric) else: routes.append( (atol(dest), itom(int(netmask)), nexthop, netw, ip, metric)) return routes
def __init__( self, iface=None, # type: Optional[Union[str, NetworkInterface]] type=ETH_P_ALL, # type: int promisc=None, # type: Optional[Any] filter=None, # type: Optional[Any] nofilter=0, # type: int monitor=None, # type: Optional[Any] ): # type: (...) -> None self.iface = network_name(iface or conf.iface) self.type = type self.promisc = conf.sniff_promisc if promisc is None else promisc self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: try: attach_filter(self.ins, filter, self.iface) except (ImportError, Scapy_Exception) as ex: log_runtime.error("Cannot set filter: %s", ex) if self.promisc: set_promisc(self.ins, self.iface) self.ins.bind((self.iface, type)) _flush_fd(self.ins.fileno()) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, conf.bufsize) if not six.PY2: # Receive Auxiliary Data (VLAN tags) try: self.ins.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1) self.ins.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPNS, 1) self.auxdata_available = True except OSError: # Note: Auxiliary Data is only supported since # Linux 2.6.21 msg = "Your Linux Kernel does not support Auxiliary Data!" log_runtime.info(msg) if not isinstance(self, L2ListenSocket): self.outs = self.ins # type: socket.socket self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, conf.bufsize) else: self.outs = None # type: ignore sa_ll = self.ins.getsockname() if sa_ll[3] in conf.l2types: self.LL = conf.l2types.num2layer[sa_ll[3]] self.lvl = 2 elif sa_ll[1] in conf.l3types: self.LL = conf.l3types.num2layer[sa_ll[1]] self.lvl = 3 else: self.LL = conf.default_l2 self.lvl = 2 warning( "Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], self.LL.name) # noqa: E501
def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0, monitor=None): self.iface = network_name(iface or conf.iface) self.type = type self.promisc = conf.sniff_promisc if promisc is None else promisc if monitor is not None: log_runtime.info( "The 'monitor' argument has no effect on native linux sockets." ) self.ins = socket.socket( socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: try: attach_filter(self.ins, filter, iface) except ImportError as ex: log_runtime.error("Cannot set filter: %s", ex) if self.promisc: set_promisc(self.ins, self.iface) self.ins.bind((self.iface, type)) _flush_fd(self.ins) self.ins.setsockopt( socket.SOL_SOCKET, socket.SO_RCVBUF, conf.bufsize ) if not six.PY2: # Receive Auxiliary Data (VLAN tags) try: self.ins.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1) self.ins.setsockopt( socket.SOL_SOCKET, SO_TIMESTAMPNS, 1 ) self.auxdata_available = True except OSError: # Note: Auxiliary Data is only supported since # Linux 2.6.21 msg = "Your Linux Kernel does not support Auxiliary Data!" log_runtime.info(msg) if isinstance(self, L2ListenSocket): self.outs = None else: self.outs = self.ins self.outs.setsockopt( socket.SOL_SOCKET, socket.SO_SNDBUF, conf.bufsize ) sa_ll = self.ins.getsockname() if sa_ll[3] in conf.l2types: self.LL = conf.l2types[sa_ll[3]] self.lvl = 2 elif sa_ll[1] in conf.l3types: self.LL = conf.l3types[sa_ll[1]] self.lvl = 3 else: self.LL = conf.default_l2 self.lvl = 2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s", sa_ll[0], sa_ll[1], sa_ll[3], self.LL.name) # noqa: E501
def compile_filter(filter_exp, iface=None, linktype=None, promisc=False): """Asks libpcap to parse the filter, then build the matching BPF bytecode. :param iface: if provided, use the interface to compile :param linktype: if provided, use the linktype to compile """ try: from scapy.libs.winpcapy import ( PCAP_ERRBUF_SIZE, pcap_open_live, pcap_compile, pcap_compile_nopcap, pcap_close ) from scapy.libs.structures import bpf_program except OSError: raise ImportError( "libpcap is not available. Cannot compile filter !" ) from ctypes import create_string_buffer bpf = bpf_program() bpf_filter = create_string_buffer(filter_exp.encode("utf8")) if not linktype: # Try to guess linktype to avoid root if not iface: if not conf.iface: raise Scapy_Exception( "Please provide an interface or linktype!" ) iface = conf.iface # Try to guess linktype to avoid requiring root try: arphd = get_if_raw_hwaddr(iface)[0] linktype = ARPHRD_TO_DLT.get(arphd) except Exception: # Failed to use linktype: use the interface pass if linktype is not None: ret = pcap_compile_nopcap( MTU, linktype, ctypes.byref(bpf), bpf_filter, 0, -1 ) elif iface: err = create_string_buffer(PCAP_ERRBUF_SIZE) iface = network_name(iface) iface = create_string_buffer(iface.encode("utf8")) pcap = pcap_open_live( iface, MTU, promisc, 0, err ) error = bytes(bytearray(err)).strip(b"\x00") if error: raise OSError(error) ret = pcap_compile( pcap, ctypes.byref(bpf), bpf_filter, 0, -1 ) pcap_close(pcap) if ret == -1: raise Scapy_Exception( "Failed to compile filter expression %s (%s)" % (filter_exp, ret) ) if conf.use_pypy and sys.pypy_version_info <= (7, 3, 2): # PyPy < 7.3.2 has a broken behavior # https://foss.heptapod.net/pypy/pypy/-/issues/3298 return struct.pack( 'HL', bpf.bf_len, ctypes.addressof(bpf.bf_insns.contents) ) return bpf
def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0, monitor=False): self.fd_flags = None self.assigned_interface = None # SuperSocket mandatory variables if promisc is None: self.promisc = conf.sniff_promisc else: self.promisc = promisc self.iface = network_name(iface or conf.iface) # Get the BPF handle self.ins = None (self.ins, self.dev_bpf) = get_dev_bpf() self.outs = self.ins # Set the BPF buffer length try: fcntl.ioctl(self.ins, BIOCSBLEN, struct.pack('I', BPF_BUFFER_LENGTH)) # noqa: E501 except IOError: raise Scapy_Exception("BIOCSBLEN failed on /dev/bpf%i" % self.dev_bpf) # Assign the network interface to the BPF handle try: fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface.encode())) # noqa: E501 except IOError: raise Scapy_Exception("BIOCSETIF failed on %s" % self.iface) self.assigned_interface = self.iface # Set the interface into promiscuous 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)) except IOError: raise Scapy_Exception("BIOCIMMEDIATE failed on /dev/bpf%i" % self.dev_bpf) # Scapy will provide the link layer source address # Otherwise, it is written by the kernel try: fcntl.ioctl(self.ins, BIOCSHDRCMPLT, struct.pack('i', 1)) except IOError: raise Scapy_Exception("BIOCSHDRCMPLT failed on /dev/bpf%i" % self.dev_bpf) # Configure the BPF filter if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: try: attach_filter(self.ins, filter, self.iface) except ImportError as ex: warning("Cannot set filter: %s" % ex) # Set the guessed packet class self.guessed_cls = self.guess_cls()
def __init__(self, iface=None, mode_tun=None, default_read_size=MTU, strip_packet_info=True, *args, **kwargs): self.iface = bytes_encode( network_name(conf.iface if iface is None else iface)) self.mode_tun = mode_tun if self.mode_tun is None: if self.iface.startswith(b"tun"): self.mode_tun = True elif self.iface.startswith(b"tap"): self.mode_tun = False else: raise ValueError( "Could not determine interface type for %r; set " "`mode_tun` explicitly." % (self.iface, )) self.strip_packet_info = bool(strip_packet_info) # This is non-zero when there is some kernel-specific packet info. # We add this to any MTU value passed to recv(), and use it to # remove leading bytes when strip_packet_info=True. self.mtu_overhead = 0 # The TUN packet specification sends raw IP at us, and doesn't specify # which version. self.kernel_packet_class = IPv46 if self.mode_tun else Ether if LINUX: devname = b"/dev/net/tun" # Having an EtherType always helps on Linux, then we don't need # to use auto-detection of IP version. if self.mode_tun: self.kernel_packet_class = LinuxTunPacketInfo self.mtu_overhead = 4 # len(LinuxTunPacketInfo) else: warning("tap devices on Linux do not include packet info!") self.strip_packet_info = True if len(self.iface) > LINUX_IFNAMSIZ: warning("Linux interface names are limited to %d bytes, " "truncating!" % (LINUX_IFNAMSIZ, )) self.iface = self.iface[:LINUX_IFNAMSIZ] elif BSD: # also DARWIN if not (self.iface.startswith(b"tap") or self.iface.startswith(b"tun")): raise ValueError("Interface names must start with `tun` or " "`tap` on BSD and Darwin") devname = b"/dev/" + self.iface if not self.strip_packet_info: warning("tun/tap devices on BSD and Darwin never include " "packet info!") self.strip_packet_info = True else: raise NotImplementedError("TunTapInterface is not supported on " "this platform!") sock = open(devname, "r+b", buffering=0) if LINUX: if self.mode_tun: flags = LINUX_IFF_TUN else: # Linux can send us LinuxTunPacketInfo for TAP interfaces, but # the kernel sends the wrong information! # # Instead of type=1 (Ether), it sends that of the payload # (eg: 0x800 for IPv4 or 0x86dd for IPv6). # # tap interfaces always send Ether frames, which include a # type parameter for the IPv4/v6/etc. payload, so we set # IFF_NO_PI. flags = LINUX_IFF_TAP | LINUX_IFF_NO_PI tsetiff = raw(LinuxTunIfReq(ifrn_name=self.iface, ifru_flags=flags)) ioctl(sock, LINUX_TUNSETIFF, tsetiff) self.closed = False self.default_read_size = default_read_size super(TunTapInterface, self).__init__(sock)
def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0, monitor=False): self.fd_flags = None self.assigned_interface = None # SuperSocket mandatory variables if promisc is None: self.promisc = conf.sniff_promisc else: self.promisc = promisc self.iface = network_name(iface or conf.iface) # Get the BPF handle self.ins = None (self.ins, self.dev_bpf) = get_dev_bpf() self.outs = self.ins # Set the BPF buffer length try: fcntl.ioctl(self.ins, BIOCSBLEN, struct.pack('I', BPF_BUFFER_LENGTH)) # noqa: E501 except IOError: raise Scapy_Exception("BIOCSBLEN failed on /dev/bpf%i" % self.dev_bpf) # Assign the network interface to the BPF handle try: fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface.encode())) # noqa: E501 except IOError: raise Scapy_Exception("BIOCSETIF failed on %s" % self.iface) self.assigned_interface = self.iface # Set the interface into promiscuous 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: # Convert macOS version to an integer try: tmp_mac_version = platform.mac_ver()[0].split(".") tmp_mac_version = [int(num) for num in tmp_mac_version] macos_version = tmp_mac_version[0] * 10000 macos_version += tmp_mac_version[1] * 100 + tmp_mac_version[2] except (IndexError, ValueError): warning("Could not determine your macOS version!") macos_version = sys.maxint # Disable 802.11 monitoring on macOS Catalina (aka 10.15) and upper if macos_version < 101500: 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) else: warning("Scapy won't activate 802.11 monitoring, " "as it will crash your macOS kernel!") # Don't block on read try: fcntl.ioctl(self.ins, BIOCIMMEDIATE, struct.pack('I', 1)) except IOError: raise Scapy_Exception("BIOCIMMEDIATE failed on /dev/bpf%i" % self.dev_bpf) # Scapy will provide the link layer source address # Otherwise, it is written by the kernel try: fcntl.ioctl(self.ins, BIOCSHDRCMPLT, struct.pack('i', 1)) except IOError: raise Scapy_Exception("BIOCSHDRCMPLT failed on /dev/bpf%i" % self.dev_bpf) # Configure the BPF filter filter_attached = False if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: try: attach_filter(self.ins, filter, self.iface) filter_attached = True except ImportError as ex: warning("Cannot set filter: %s" % ex) if NETBSD and filter_attached is False: # On NetBSD, a filter must be attached to an interface, otherwise # no frame will be received by os.read(). When no filter has been # configured, Scapy uses a simple tcpdump filter that does nothing # more than ensuring the length frame is not null. filter = "greater 0" try: attach_filter(self.ins, filter, self.iface) except ImportError as ex: warning("Cannot set filter: %s" % ex) # Set the guessed packet class self.guessed_cls = self.guess_cls()