def start(self): # type: () -> None super(CANReceiverThread, self).start() if not self._thread_started.wait(5): raise Scapy_Exception("CAN RX thread not started in 5s.")
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
# the filter from cooked mode to raw mode # mode if not TCPDUMP: return try: f = os.popen("%s -i %s -ddd -s 1600 '%s'" % ( conf.prog.tcpdump, conf.iface if iface is None else iface, bpf_filter, )) except OSError, msg: log_interactive.warning("Failed to execute tcpdump: (%s)") return lines = f.readlines() if f.close(): raise Scapy_Exception("Filter parse error") nb = int(lines[0]) bpf = "" for l in lines[1:]: bpf += struct.pack("HBBI", *map(long, l.split())) # XXX. Argl! We need to give the kernel a pointer on the BPF, # python object header seems to be 20 bytes. 36 bytes for x86 64bits arch. if scapy.arch.X86_64 or scapy.arch.ARM_64: bpfh = struct.pack("HL", nb, id(bpf) + 36) else: bpfh = struct.pack("HI", nb, id(bpf) + 20) s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh) def set_promisc(s, iff, val=1):
def get_data_length(self): """ Must be overridden in a subclass to return the correct value """ raise Scapy_Exception( "This method must be overridden in a specific subclass")
def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0): # SuperSocket mandatory variables if promisc is None: self.promisc = conf.sniff_promisc else: self.promisc = promisc if iface is None: self.iface = conf.iface else: self.iface = iface # Get the BPF handle (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)) 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)) 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) # 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: attach_filter(self.ins, self.iface, filter) # Set the guessed packet class self.guessed_cls = self.guess_cls()
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() # pkt = pkt.__class__(raw(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = [x for x in pb if x[6] == osgenre] if osdetails: pb = [x for x in pb if x[7] == osdetails] elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = [x for x in pb if 'K' in x[5]] else: pb = [x for x in pb if 'K' not in x[5]] if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) # Take the options already set as "hints" to use in the new packet if we # can. MSS, WScale and Timestamp can all be wildcarded in a signature, so # we'll use the already-set values if they're valid integers. orig_opts = dict(pkt.payload.options) int_only = lambda val: val if isinstance(val, six.integer_types) else None mss_hint = int_only(orig_opts.get('MSS')) wscale_hint = int_only(orig_opts.get('WScale')) ts_hint = [int_only(o) for o in orig_opts.get('Timestamp', (None, None))] options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16 - 1) // int(pers[0][1:]) else: maxmss = (2**16 - 1) # disregard hint if out of range if mss_hint and not 0 <= mss_hint <= maxmss: mss_hint = None # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': if mss_hint is not None: options.append(('MSS', mss_hint)) else: options.append(('MSS', random.randint(1, maxmss))) elif opt[1] == '%': coef = int(opt[2:]) if mss_hint is not None and mss_hint % coef == 0: options.append(('MSS', mss_hint)) else: options.append( ('MSS', coef * random.randint(1, maxmss // coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if wscale_hint and not 0 <= wscale_hint < 2**8: wscale_hint = None if opt[1:] == '*': if wscale_hint is not None: options.append(('WScale', wscale_hint)) else: options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) if wscale_hint is not None and wscale_hint % coef == 0: options.append(('WScale', wscale_hint)) else: options.append( ('WScale', coef * RandNum(min=1, max=(2**8 - 1) // coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': # Determine first timestamp. if uptime is not None: ts_a = uptime elif ts_hint[0] and 0 < ts_hint[0] < 2**32: # Note: if first ts is 0, p0f registers it as "T0" not "T", # hence we don't want to use the hint if it was 0. ts_a = ts_hint[0] else: ts_a = random.randint(120, 100 * 60 * 60 * 24 * 365) # Determine second timestamp. if 'T' not in pers[5]: ts_b = 0 elif ts_hint[1] and 0 < ts_hint[1] < 2**32: ts_b = ts_hint[1] else: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) ts_b = random.randint(1, 2**32 - 1) options.append(('Timestamp', (ts_a, ts_b))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append( (optname, struct.unpack( optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) # FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1, max=(2**16 - 1) // coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': # needs MSS set mss = [x for x in options if x[0] == 'MSS'] if not mss: raise Scapy_Exception( "TCP window value requires MSS, and MSS option not set") pkt.payload.window = mss[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1] - extrahops # DF flag pkt.flags |= (2 * pers[2]) # FIXME: ss (packet size) not handled (how ? may be with D quirk # if present) # Quirks if pers[5] != '.': for qq in pers[5]: # FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= random.choice([8, 32, 40]) # P/U/PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint( 1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack # elif qq == '0': pkt.payload.seq = 0 # if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
def dns_compress(pkt): """This function compresses a DNS packet according to compression rules. """ if DNS not in pkt: raise Scapy_Exception("Can only compress DNS layers") pkt = pkt.copy() dns_pkt = pkt.getlayer(DNS) build_pkt = raw(dns_pkt) def field_gen(dns_pkt): """Iterates through all DNS strings that can be compressed""" for lay in [dns_pkt.qd, dns_pkt.an, dns_pkt.ns, dns_pkt.ar]: if lay is None: continue current = lay while not isinstance(current, NoPayload): if isinstance(current, InheritOriginDNSStrPacket): for field in current.fields_desc: if isinstance(field, DNSStrField) or \ (isinstance(field, MultipleTypeField) and current.type in [2, 5, 12]): # Get the associated data and store it accordingly # noqa: E501 dat = current.getfieldval(field.name) yield current, field.name, dat current = current.payload def possible_shortens(dat): """Iterates through all possible compression parts in a DNS string""" yield dat for x in range(1, dat.count(b".")): yield dat.split(b".", x)[x] data = {} burned_data = 0 for current, name, dat in field_gen(dns_pkt): for part in possible_shortens(dat): # Encode the data encoded = dns_encode(part, check_built=True) if part not in data: # We have no occurrence of such data, let's store it as a # possible pointer for future strings. # We get the index of the encoded data index = build_pkt.index(encoded) index -= burned_data # The following is used to build correctly the pointer fb_index = ((index >> 8) | 0xc0) sb_index = index - (256 * (fb_index - 0xc0)) pointer = chb(fb_index) + chb(sb_index) data[part] = [(current, name, pointer)] else: # This string already exists, let's mark the current field # with it, so that it gets compressed data[part].append((current, name)) # calculate spared space burned_data += len(encoded) - 2 break # Apply compression rules for ck in data: # compression_key is a DNS string replacements = data[ck] # replacements is the list of all tuples (layer, field name) # where this string was found replace_pointer = replacements.pop(0)[2] # replace_pointer is the packed pointer that should replace # those strings. Note that pop remove it from the list for rep in replacements: # setfieldval edits the value of the field in the layer val = rep[0].getfieldval(rep[1]) assert val.endswith(ck) kept_string = dns_encode(val[:-len(ck)], check_built=True)[:-1] new_val = kept_string + replace_pointer rep[0].setfieldval(rep[1], new_val) try: del (rep[0].rdlen) except AttributeError: pass # End of the compression algorithm # Destroy the previous DNS layer if needed if not isinstance(pkt, DNS) and pkt.getlayer(DNS).underlayer: pkt.getlayer(DNS).underlayer.remove_payload() return pkt / dns_pkt return dns_pkt
def add_payload(self, payload): raise Scapy_Exception("Can't add payload to NoPayload instance")
def fragment(self, *args, **kargs): raise Scapy_Exception("cannot fragment this packet")
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()
p1.stdout.close() if p1.wait() == 0 and p2.wait() == 0 and b"can_isotp" in p2.stdout.read(): p = subprocess.Popen(["isotpsend", "-s1", "-d0", iface0], stdin=subprocess.PIPE) p.communicate(b"01") if p.returncode == 0: ISOTP_KERNEL_MODULE_AVAILABLE = True # ############################################################################ # """ Save configuration """ # ############################################################################ conf.contribs['ISOTP'] = \ {'use-can-isotp-kernel-module': ISOTP_KERNEL_MODULE_AVAILABLE} # ############################################################################ # """ reload ISOTP kernel module in case configuration changed """ # ############################################################################ if six.PY3: import importlib if "scapy.contrib.isotp" in sys.modules: importlib.reload(scapy.contrib.isotp) # type: ignore # noqa: F405 load_contrib("isotp", globals_dict=globals()) if six.PY3 and ISOTP_KERNEL_MODULE_AVAILABLE: if ISOTPSocket is not ISOTPNativeSocket: # type: ignore raise Scapy_Exception("Error in ISOTPSocket import!") else: if ISOTPSocket is not ISOTPSoftSocket: # type: ignore raise Scapy_Exception("Error in ISOTPSocket import!")
def pre_dissect(self, s): if not all(isinstance(f, SignalField) for f in self.fields_desc): raise Scapy_Exception("Use only SignalFields in a SignalPacket") return s
def pair(self, sock): # type: (TestSocket) -> None if sock.__paired_socket or self.__paired_socket: raise Scapy_Exception("Socket already paired") self.__paired_socket = sock sock.__paired_socket = self
def fragment(self, *args, **kargs): # type: (*Any, **Any) -> List[Packet] """Helper function to fragment an ISOTP message into multiple CAN frames. :return: A list of CAN frames """ data_bytes_in_frame = 7 if self.rx_ext_address is not None: data_bytes_in_frame = 6 if len(self.data) > ISOTP_MAX_DLEN_2015: raise Scapy_Exception("Too much data in ISOTP message") if len(self.data) <= data_bytes_in_frame: # We can do this in a single frame frame_data = struct.pack('B', len(self.data)) + self.data if self.rx_ext_address: frame_data = struct.pack('B', self.rx_ext_address) + frame_data if self.rx_id is None or self.rx_id <= 0x7ff: pkt = CAN(identifier=self.rx_id, data=frame_data) else: pkt = CAN(identifier=self.rx_id, flags="extended", data=frame_data) return [pkt] # Construct the first frame if len(self.data) <= ISOTP_MAX_DLEN: frame_header = struct.pack(">H", len(self.data) + 0x1000) else: frame_header = struct.pack(">HI", 0x1000, len(self.data)) if self.rx_ext_address: frame_header = struct.pack('B', self.rx_ext_address) + frame_header idx = 8 - len(frame_header) frame_data = self.data[0:idx] if self.rx_id is None or self.rx_id <= 0x7ff: frame = CAN(identifier=self.rx_id, data=frame_header + frame_data) else: frame = CAN(identifier=self.rx_id, flags="extended", data=frame_header + frame_data) # Construct consecutive frames n = 1 pkts = [frame] while idx < len(self.data): frame_data = self.data[idx:idx + data_bytes_in_frame] frame_header = struct.pack("b", (n % 16) + N_PCI_CF) n += 1 idx += len(frame_data) if self.rx_ext_address: frame_header = struct.pack('B', self.rx_ext_address) + frame_header # noqa: E501 if self.rx_id is None or self.rx_id <= 0x7ff: pkt = CAN(identifier=self.rx_id, data=frame_header + frame_data) # noqa: E501 else: pkt = CAN(identifier=self.rx_id, flags="extended", data=frame_header + frame_data) pkts.append(pkt) return pkts
def execute(self, socket, state, **kwargs): # type: (_SocketUnion, EcuState, Any) -> None self.check_kwargs(kwargs) timeout = kwargs.pop('timeout', 1) execution_time = kwargs.pop("execution_time", 1200) state_block_list = kwargs.get('state_block_list', list()) if state_block_list and state in state_block_list: self._state_completed[state] = True log_interactive.debug("[i] State %s in block list!", repr(state)) return state_allow_list = kwargs.get('state_allow_list', list()) if state_allow_list and state not in state_allow_list: self._state_completed[state] = True log_interactive.debug("[i] State %s not in allow list!", repr(state)) return it = self.__get_request_iterator(state, **kwargs) # log_interactive.debug("[i] Using iterator %s in state %s", it, state) start_time = time.time() log_interactive.debug("[i] Start execution of enumerator: %s", time.ctime(start_time)) for req in it: try: res = socket.sr1(req, timeout=timeout, verbose=False) except (OSError, ValueError, Scapy_Exception) as e: if not self._populate_retry(state, req): log_interactive.critical( "[-] Exception during retry. This is bad") raise e if socket.closed: if not self._populate_retry(state, req): log_interactive.critical( "[-] Socket closed during retry. This is bad") log_interactive.critical("[-] Socket closed during scan.") raise Scapy_Exception("Socket closed during scan") self._store_result(state, req, res) if self._evaluate_response(state, req, res, **kwargs): log_interactive.debug("[i] Stop test_case execution because " "of response evaluation") return if (start_time + execution_time) < time.time(): log_interactive.debug( "[i] Finished execution time of enumerator: %s", time.ctime()) return log_interactive.info("[i] Finished iterator execution") self._state_completed[state] = True log_interactive.debug("[i] States completed %s", repr(self._state_completed))
def sprintf(self, fmt, relax): if relax: return "??" else: raise Scapy_Exception("Format not found [%s]"%fmt)
# Handle the loopback interface separately if ifname == LOOPBACK_NAME: return (ARPHDR_LOOPBACK, NULL_MAC_ADDRESS) # Get ifconfig output try: fd = os.popen("%s %s" % (conf.prog.ifconfig, ifname)) except OSError, msg: raise Scapy_Exception("Failed to execute ifconfig: (%s)" % msg) # Get MAC addresses addresses = [l for l in fd.readlines() if l.find("ether") >= 0 or l.find("lladdr") >= 0 or l.find("address") >= 0] 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)) # BPF specific functions def get_dev_bpf(): """Returns an opened BPF file object""" # Get the first available BPF handle for bpf in range(0, 8): try:
def sprintf(self, fmt, relax=1): """sprintf(format, [relax=1]) -> str where format is a string that can include directives. A directive begins and ends by % and has the following format %[fmt[r],][cls[:nb].]field%. fmt is a classic printf directive, "r" can be appended for raw substitution (ex: IP.flags=0x18 instead of SA), nb is the number of the layer we want (ex: for IP/IP packets, IP:2.src is the src of the upper IP layer). Special case : "%.time%" is the creation time. Ex : p.sprintf("%.time% %-15s,IP.src% -> %-15s,IP.dst% %IP.chksum% " "%03xr,IP.proto% %r,TCP.flags%") Moreover, the format string can include conditional statements. A conditional statement looks like : {layer:string} where layer is a layer name, and string is the string to insert in place of the condition if it is true, i.e. if layer is present. If layer is preceded by a "!", the result is inverted. Conditions can be imbricated. A valid statement can be : p.sprintf("This is a{TCP: TCP}{UDP: UDP}{ICMP:n ICMP} packet") p.sprintf("{IP:%IP.dst% {ICMP:%ICMP.type%}{TCP:%TCP.dport%}}") A side effect is that, to obtain "{" and "}" characters, you must use "%(" and "%)". """ escape = { "%": "%", "(": "{", ")": "}" } # Evaluate conditions while "{" in fmt: i = fmt.rindex("{") j = fmt[i+1:].index("}") cond = fmt[i+1:i+j+1] k = cond.find(":") if k < 0: raise Scapy_Exception("Bad condition in format string: [%s] (read sprintf doc!)"%cond) cond,format = cond[:k],cond[k+1:] res = False if cond[0] == "!": res = True cond = cond[1:] if self.haslayer(cond): res = not res if not res: format = "" fmt = fmt[:i]+format+fmt[i+j+2:] # Evaluate directives s = "" while "%" in fmt: i = fmt.index("%") s += fmt[:i] fmt = fmt[i+1:] if fmt and fmt[0] in escape: s += escape[fmt[0]] fmt = fmt[1:] continue try: i = fmt.index("%") sfclsfld = fmt[:i] fclsfld = sfclsfld.split(",") if len(fclsfld) == 1: f = "s" clsfld = fclsfld[0] elif len(fclsfld) == 2: f,clsfld = fclsfld else: raise Scapy_Exception if "." in clsfld: cls,fld = clsfld.split(".") else: cls = self.__class__.__name__ fld = clsfld num = 1 if ":" in cls: cls,num = cls.split(":") num = int(num) fmt = fmt[i+1:] except: raise Scapy_Exception("Bad format string [%%%s%s]" % (fmt[:25], fmt[25:] and "...")) else: if fld == "time": val = time.strftime("%H:%M:%S.%%06i", time.localtime(self.time)) % int((self.time-int(self.time))*1000000) elif cls == self.__class__.__name__ and hasattr(self, fld): if num > 1: val = self.payload.sprintf("%%%s,%s:%s.%s%%" % (f,cls,num-1,fld), relax) f = "s" elif f[-1] == "r": # Raw field value val = getattr(self,fld) f = f[:-1] if not f: f = "s" else: val = getattr(self,fld) if fld in self.fieldtype: val = self.fieldtype[fld].i2repr(self,val) else: val = self.payload.sprintf("%%%s%%" % sfclsfld, relax) f = "s" s += ("%"+f) % val s += fmt return s
def _run(self, count=0, store=True, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None, started_callback=None, session=None, *arg, **karg): self.running = True # Start main thread c = 0 session = session or DefaultSession session = session(prn, store) # instantiate session # sniff_sockets follows: {socket: label} sniff_sockets = {} if opened_socket is not None: if isinstance(opened_socket, list): sniff_sockets.update( (s, "socket%d" % i) for i, s in enumerate(opened_socket)) elif isinstance(opened_socket, dict): sniff_sockets.update( (s, label) for s, label in six.iteritems(opened_socket)) else: sniff_sockets[opened_socket] = "socket0" if offline is not None: flt = karg.get('filter') from scapy.arch.common import TCPDUMP if not TCPDUMP and flt is not None: message = "tcpdump is not available. Cannot use filter!" raise Scapy_Exception(message) if isinstance(offline, list): sniff_sockets.update( (PcapReader(fname if flt is None else tcpdump( fname, args=["-w", "-", flt], getfd=True)), fname) for fname in offline) elif isinstance(offline, dict): sniff_sockets.update( (PcapReader(fname if flt is None else tcpdump( fname, args=["-w", "-", flt], getfd=True)), label) for fname, label in six.iteritems(offline)) else: sniff_sockets[PcapReader(offline if flt is None else tcpdump( offline, args=["-w", "-", flt], getfd=True))] = offline if not sniff_sockets or iface is not None: if L2socket is None: L2socket = conf.L2listen if isinstance(iface, list): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), ifname) for ifname in iface) elif isinstance(iface, dict): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), iflabel) for ifname, iflabel in six.iteritems(iface)) else: sniff_sockets[L2socket(type=ETH_P_ALL, iface=iface, *arg, **karg)] = iface # Get select information from the sockets _main_socket = next(iter(sniff_sockets)) read_allowed_exceptions = _main_socket.read_allowed_exceptions select_func = _main_socket.select _backup_read_func = _main_socket.__class__.recv nonblocking_socket = _main_socket.nonblocking_socket # We check that all sockets use the same select(), or raise a warning if not all(select_func == sock.select for sock in sniff_sockets): warning("Warning: inconsistent socket types ! " "The used select function " "will be the one of the first socket") # Fill if empty if not read_allowed_exceptions: read_allowed_exceptions = (IOError, ) if nonblocking_socket: # select is non blocking def stop_cb(): self.continue_sniff = False self.stop_cb = stop_cb close_pipe = None else: # select is blocking: Add special control socket from scapy.automaton import ObjectPipe close_pipe = ObjectPipe() sniff_sockets[close_pipe] = "control_socket" def stop_cb(): if self.running: close_pipe.send(None) self.continue_sniff = False self.stop_cb = stop_cb try: if started_callback: started_callback() self.continue_sniff = True # Start timeout if timeout is not None: stoptime = time.time() + timeout remain = None while sniff_sockets and self.continue_sniff: if timeout is not None: remain = stoptime - time.time() if remain <= 0: break sockets, read_func = select_func(sniff_sockets, remain) read_func = read_func or _backup_read_func dead_sockets = [] for s in sockets: if s is close_pipe: break try: p = read_func(s) except EOFError: # End of stream dead_sockets.append(s) continue except read_allowed_exceptions: continue except Exception as ex: msg = " It was closed." try: # Make sure it's closed s.close() except Exception as ex: msg = " close() failed with '%s'" % ex warning("Socket %s failed with '%s'." % (s, ex) + msg) dead_sockets.append(s) continue if p is None: continue if lfilter and not lfilter(p): continue p.sniffed_on = sniff_sockets[s] c += 1 # on_packet_received handles the prn/storage session.on_packet_received(p) # check if (stop_filter and stop_filter(p)) or (0 < count <= c): self.continue_sniff = False break # Removed dead sockets for s in dead_sockets: del sniff_sockets[s] except KeyboardInterrupt: pass self.running = False if opened_socket is None: for s in sniff_sockets: s.close() elif close_pipe: close_pipe.close() self.results = session.toPacketList()
def _recv_cf(self, data): # type: (bytes) -> None """Process a received 'Consecutive Frame' frame""" if self.rx_state != ISOTP_WAIT_DATA: return if self.rx_timeout_handle is not None: self.rx_timeout_handle.cancel() self.rx_timeout_handle = None # CFs are never longer than the FF if len(data) > self.rx_ll_dl: return # CFs have usually the LL_DL length if len(data) < self.rx_ll_dl: # this is only allowed for the last CF if self.rx_len - self.rx_idx > self.rx_ll_dl: if conf.verb > 2: warning("Received a CF with insufficient length") return if six.indexbytes(data, 0) & 0x0f != self.rx_sn: # Wrong sequence number if conf.verb > 2: warning("RX state was reset because wrong sequence number was " "received") self.rx_state = ISOTP_IDLE return if self.rx_buf is None: raise Scapy_Exception("rx_buf not filled with data!") self.rx_sn = (self.rx_sn + 1) % 16 self.rx_buf += data[1:] self.rx_idx = len(self.rx_buf) if self.rx_idx >= self.rx_len: # we are done self.rx_buf = self.rx_buf[0:self.rx_len] self.rx_state = ISOTP_IDLE self.rx_queue.send((self.rx_buf, self.rx_ts)) for cb in self.rx_callbacks: cb(self.rx_buf) self.rx_buf = None return # perform blocksize handling, if enabled if self.rxfc_bs != 0: self.rx_bs += 1 # check if we reached the end of the block if self.rx_bs >= self.rxfc_bs and not self.listen_only: # send our FC frame load = self.ea_hdr load += struct.pack("BBB", N_PCI_FC, self.rxfc_bs, self.rxfc_stmin) self.can_send(load) # wait for another CF self.rx_timeout_handle = TimeoutScheduler.schedule( self.cf_timeout, self._rx_timer_handler)
def dns_get_str(s, pointer=0, pkt=None, _fullpacket=False): """This function decompresses a string s, starting from the given pointer. :param s: the string to decompress :param pointer: first pointer on the string (default: 0) :param pkt: (optional) an InheritOriginDNSStrPacket packet :returns: (decoded_string, end_index, left_string) """ # The _fullpacket parameter is reserved for scapy. It indicates # that the string provided is the full dns packet, and thus # will be the same than pkt._orig_str. The "Cannot decompress" # error will not be prompted if True. max_length = len(s) # The result = the extracted name name = b"" # Will contain the index after the pointer, to be returned after_pointer = None processed_pointers = [] # Used to check for decompression loops # Analyse given pkt if pkt and hasattr(pkt, "_orig_s") and pkt._orig_s: s_full = pkt._orig_s else: s_full = None bytes_left = None while True: if abs(pointer) >= max_length: warning("DNS RR prematured end (ofs=%i, len=%i)" % (pointer, len(s))) break cur = orb(s[pointer]) # get pointer value pointer += 1 # make pointer go forward if cur & 0xc0: # Label pointer if after_pointer is None: # after_pointer points to where the remaining bytes start, # as pointer will follow the jump token after_pointer = pointer + 1 if pointer >= max_length: warning("DNS incomplete jump token at (ofs=%i)" % pointer) break # Follow the pointer pointer = ((cur & ~0xc0) << 8) + orb(s[pointer]) - 12 if pointer in processed_pointers: warning("DNS decompression loop detected") break if not _fullpacket: # Do we have access to the whole packet ? if s_full: # Yes -> use it to continue bytes_left = s[after_pointer:] s = s_full max_length = len(s) _fullpacket = True else: # No -> abort raise Scapy_Exception("DNS message can't be compressed" + "at this point!") processed_pointers.append(pointer) continue elif cur > 0: # Label # cur = length of the string name += s[pointer:pointer + cur] + b"." pointer += cur else: break if after_pointer is not None: # Return the real end index (not the one we followed) pointer = after_pointer if bytes_left is None: bytes_left = s[pointer:] # name, end_index, remaining return name, pointer, bytes_left
def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() #pkt = pkt.__class__(str(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") if uptime is None: uptime = random.randint(120, 100 * 60 * 60 * 24 * 365) db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = filter(lambda x: x[6] == osgenre, pb) if osdetails: pb = filter(lambda x: x[7] == osdetails, pb) elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = filter(lambda x: 'K' in x[5], pb) else: pb = filter(lambda x: 'K' not in x[5], pb) if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) ## TODO: let the options already set if they are valid options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2**16 - 1) / int(pers[0][1:]) else: maxmss = (2**16 - 1) # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': options.append(('MSS', random.randint(1, maxmss))) elif opt[1] == '%': coef = int(opt[2:]) options.append( ('MSS', coef * random.randint(1, maxmss / coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if opt[1:] == '*': options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) options.append( ('WScale', coef * RandNum(min=1, max=(2**8 - 1) / coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': if 'T' in pers[5]: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) options.append( ('Timestamp', (uptime, random.randint(1, 2**32 - 1)))) else: options.append(('Timestamp', (uptime, 0))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append( (optname, struct.unpack( optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) ## FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1, max=(2**16 - 1) / coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': ## needs MSS set MSS = filter(lambda x: x[0] == 'MSS', options) if not filter(lambda x: x[0] == 'MSS', options): raise Scapy_Exception( "TCP window value requires MSS, and MSS option not set") pkt.payload.window = filter(lambda x: x[0] == 'MSS', options)[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1] - extrahops # DF flag pkt.flags |= (2 * pers[2]) ## FIXME: ss (packet size) not handled (how ? may be with D quirk ## if present) # Quirks if pers[5] != '.': for qq in pers[5]: ## FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= RandChoice(8, 32, 40) #P / U / PU elif qq == 'D' and db != p0fo_kdb: pkt /= conf.raw_layer(load=RandString(random.randint( 1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack #elif qq == '0': pkt.payload.seq = 0 #if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt
fcntl.ioctl(self.ins, BIOCSETIF, struct.pack("16s16x", self.iface)) except IOError, err: msg = "BIOCSETIF failed on %s" % self.iface raise Scapy_Exception(msg) self.assigned_interface = self.iface # Set the interface into promiscuous if self.promisc: self.set_promisc(1) # Don't block on read try: fcntl.ioctl(self.ins, BIOCIMMEDIATE, struct.pack('I', 1)) except IOError, err: msg = "BIOCIMMEDIATE failed on /dev/bpf%i" % self.dev_bpf raise Scapy_Exception(msg) # 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, err: msg = "BIOCSHDRCMPLT failed on /dev/bpf%i" % self.dev_bpf raise Scapy_Exception(msg) # Configure the BPF filter if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else:
import struct import socket import time import scapy.modules.six as six from scapy.error import Scapy_Exception, warning from scapy.packet import Packet from scapy.fields import StrField from scapy.supersocket import SuperSocket from scapy.sendrecv import sndrcv, sniff from scapy.arch.linux import get_last_packet_timestamp, SIOCGIFINDEX from scapy.config import conf from scapy.consts import WINDOWS if six.PY2: Scapy_Exception("ISOTP is not supported on python2, yet. " "Switch to python3 and try it again.") if not WINDOWS: LIBC = ctypes.cdll.LoadLibrary(find_library("c")) warning("Loading libc with ctypes") else: warning("libc is unavailable") """ ISOTP Packet """ class ISOTP(Packet): name = 'ISOTP' fields_desc = [StrField('data', B"")]
def list_contrib(name=None, ret=False, _debug=False): """Show the list of all existing contribs. :param name: filter to search the contribs :param ret: whether the function should return a dict instead of printing it :returns: None or a dictionary containing the results if ret=True """ # _debug: checks that all contrib modules have correctly defined: # # scapy.contrib.description = [...] # # scapy.contrib.status = [...] # # scapy.contrib.name = [...] (optional) # or set the flag: # # scapy.contrib.description = skip # to skip the file if name is None: name = "*.py" elif "*" not in name and "?" not in name and not name.endswith(".py"): name += ".py" results = [] dir_path = os.path.join(os.path.dirname(__file__), "contrib") if sys.version_info >= (3, 5): name = os.path.join(dir_path, "**", name) iterator = glob.iglob(name, recursive=True) else: name = os.path.join(dir_path, name) iterator = glob.iglob(name) for f in iterator: mod = f.replace(os.path.sep, ".").partition("contrib.")[2] if mod.startswith("__"): continue if mod.endswith(".py"): mod = mod[:-3] desc = {"description": None, "status": None, "name": mod} with io.open(f, errors="replace") as fd: for l in fd: if l[0] != "#": continue p = l.find("scapy.contrib.") if p >= 0: p += 14 q = l.find("=", p) key = l[p:q].strip() value = l[q + 1:].strip() desc[key] = value if desc["status"] == "skip": break if desc["description"] and desc["status"]: results.append(desc) break if _debug: if desc["status"] == "skip": pass elif not desc["description"] or not desc["status"]: raise Scapy_Exception("Module %s is missing its " "contrib infos !" % mod) results.sort(key=lambda x: x["name"]) if ret: return results else: for desc in results: print("%(name)-20s: %(description)-40s status=%(status)s" % desc)
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, 1, -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, 1, -1 ) pcap_close(pcap) if ret == -1: raise Scapy_Exception( "Failed to compile filter expression %s (%s)" % (filter_exp, ret) ) return bpf
def __init__(self, iface=None, type=ETH_P_ALL, promisc=None, filter=None, nofilter=0, monitor=False): # SuperSocket mandatory variables if promisc is None: self.promisc = conf.sniff_promisc else: self.promisc = promisc if iface is None: self.iface = conf.iface else: self.iface = iface # Get the BPF handle (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)) 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())) 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: attach_filter(self.ins, self.iface, filter) # Set the guessed packet class self.guessed_cls = self.guess_cls()
def send(self, x): # type: (Packet) -> NoReturn raise Scapy_Exception("Can't send anything with L2ListenSocket")
def send(self, x): raise Scapy_Exception("Can't send anything with L2ListenSocket")
def sniff(count=0, store=True, offline=None, prn=None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, iface=None, started_callback=None, session=None, *arg, **karg): """Sniff packets and return a list of packets. Args: count: number of packets to capture. 0 means infinity. store: whether to store sniffed packets or discard them prn: function to apply to each packet. If something is returned, it is displayed. --Ex: prn = lambda x: x.summary() session: a session = a flow decoder used to handle stream of packets. e.g: IPSession (to defragment on-the-flow) or NetflowSession filter: BPF filter to apply. lfilter: Python function applied to each packet to determine if further action may be done. --Ex: lfilter = lambda x: x.haslayer(Padding) offline: PCAP file (or list of PCAP files) to read packets from, instead of sniffing them timeout: stop sniffing after a given time (default: None). L2socket: use the provided L2socket (default: use conf.L2listen). opened_socket: provide an object (or a list of objects) ready to use .recv() on. stop_filter: Python function applied to each packet to determine if we have to stop the capture after this packet. --Ex: stop_filter = lambda x: x.haslayer(TCP) iface: interface or list of interfaces (default: None for sniffing on all interfaces). monitor: use monitor mode. May not be available on all OS started_callback: called as soon as the sniffer starts sniffing (default: None). The iface, offline and opened_socket parameters can be either an element, a list of elements, or a dict object mapping an element to a label (see examples below). Examples: >>> sniff(filter="arp") >>> sniff(filter="tcp", ... session=IPSession, # defragment on-the-flow ... prn=lambda x: x.summary()) >>> sniff(lfilter=lambda pkt: ARP in pkt) >>> sniff(iface="eth0", prn=Packet.summary) >>> sniff(iface=["eth0", "mon0"], ... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on, ... pkt.summary())) >>> sniff(iface={"eth0": "Ethernet", "mon0": "Wifi"}, ... prn=lambda pkt: "%s: %s" % (pkt.sniffed_on, ... pkt.summary())) """ c = 0 session = session or DefaultSession session = session(prn, store) # instantiate session sniff_sockets = {} # socket: label dict if opened_socket is not None: if isinstance(opened_socket, list): sniff_sockets.update((s, "socket%d" % i) for i, s in enumerate(opened_socket)) elif isinstance(opened_socket, dict): sniff_sockets.update((s, label) for s, label in six.iteritems(opened_socket)) else: sniff_sockets[opened_socket] = "socket0" if offline is not None: flt = karg.get('filter') from scapy.arch.common import TCPDUMP if not TCPDUMP and flt is not None: message = "tcpdump is not available. Cannot use filter!" raise Scapy_Exception(message) if isinstance(offline, list): sniff_sockets.update((PcapReader( fname if flt is None else tcpdump(fname, args=["-w", "-", flt], getfd=True) ), fname) for fname in offline) elif isinstance(offline, dict): sniff_sockets.update((PcapReader( fname if flt is None else tcpdump(fname, args=["-w", "-", flt], getfd=True) ), label) for fname, label in six.iteritems(offline)) else: sniff_sockets[PcapReader( offline if flt is None else tcpdump(offline, args=["-w", "-", flt], getfd=True) )] = offline if not sniff_sockets or iface is not None: if L2socket is None: L2socket = conf.L2listen if isinstance(iface, list): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), ifname) for ifname in iface ) elif isinstance(iface, dict): sniff_sockets.update( (L2socket(type=ETH_P_ALL, iface=ifname, *arg, **karg), iflabel) for ifname, iflabel in six.iteritems(iface) ) else: sniff_sockets[L2socket(type=ETH_P_ALL, iface=iface, *arg, **karg)] = iface if timeout is not None: stoptime = time.time() + timeout remain = None # Get select information from the sockets _main_socket = next(iter(sniff_sockets)) read_allowed_exceptions = _main_socket.read_allowed_exceptions select_func = _main_socket.select # We check that all sockets use the same select(), or raise a warning if not all(select_func == sock.select for sock in sniff_sockets): warning("Warning: inconsistent socket types ! The used select function" "will be the one of the first socket") # Now let's build the select function, used later on _select = lambda sockets, remain: select_func(sockets, remain)[0] try: if started_callback: started_callback() continue_sniff = True while sniff_sockets and continue_sniff: if timeout is not None: remain = stoptime - time.time() if remain <= 0: break for s in _select(sniff_sockets, remain): try: p = s.recv() except socket.error as ex: warning("Socket %s failed with '%s' and thus" " will be ignored" % (s, ex)) del sniff_sockets[s] continue except read_allowed_exceptions: continue if p is None: try: if s.promisc: continue except AttributeError: pass del sniff_sockets[s] break if lfilter and not lfilter(p): continue p.sniffed_on = sniff_sockets[s] c += 1 # on_packet_received handles the prn/storage session.on_packet_received(p) if stop_filter and stop_filter(p): continue_sniff = False break if 0 < count <= c: continue_sniff = False break except KeyboardInterrupt: pass if opened_socket is None: for s in sniff_sockets: s.close() return session.toPacketList()