def get_if_raw_hwaddr(ifname): """Returns the packed MAC address configured on 'ifname'.""" NULL_MAC_ADDRESS = b'\x00' * 6 # 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))) # Get MAC addresses addresses = [ line 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 get_if_raw_addr(ifname): """Returns the IPv4 address configured on 'ifname', packed with inet_pton.""" # noqa: E501 # 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)) return b"\0\0\0\0" # Get IPv4 addresses addresses = [ line 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 load_winpcapy(): """This functions calls libpcap ``pcap_findalldevs`` function, and extracts and parse all the data scapy will need to build the Interface List. The date will be stored in ``conf.cache_iflist``, or accessible with ``get_if_list()`` """ err = create_string_buffer(PCAP_ERRBUF_SIZE) devs = POINTER(pcap_if_t)() if_list = {} if pcap_findalldevs(byref(devs), err) < 0: return try: p = devs # Iterate through the different interfaces while p: name = plain_str(p.contents.name) # GUID description = plain_str(p.contents.description) # NAME flags = p.contents.flags # FLAGS ips = [] a = p.contents.addresses while a: # IPv4 address family = a.contents.addr.contents.sa_family ap = a.contents.addr if family == socket.AF_INET: val = cast(ap, POINTER(sockaddr_in)) val = val.contents.sin_addr[:] elif family == socket.AF_INET6: val = cast(ap, POINTER(sockaddr_in6)) val = val.contents.sin6_addr[:] else: # Unknown address family # (AF_LINK isn't a thing on Windows) a = a.contents.next continue addr = inet_ntop(family, bytes(bytearray(val))) if addr != "0.0.0.0": ips.append(addr) a = a.contents.next if_list[name] = (description, ips, flags) p = p.contents.next conf.cache_iflist = if_list except Exception: raise finally: pcap_freealldevs(devs)
def get_if_list(): """Returns a list containing all network interfaces.""" # Get ifconfig output subproc = subprocess.Popen([conf.prog.ifconfig], 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))) interfaces = [ line[:line.find(':')] for line in plain_str(stdout).splitlines() if ": flags" in line.lower() ] return interfaces
def inet_pton(af, addr): """Convert an IP address from text representation into binary form.""" # Will replace Net/Net6 objects addr = plain_str(addr) # Use inet_pton if available try: return socket.inet_pton(af, addr) except AttributeError: try: return _INET_PTON[af](addr) except KeyError: raise socket.error("Address family not supported by protocol")
def get_alias_address(iface_name, ip_mask, gw_str, metric): """ Get the correct source IP address of an interface alias """ # Detect the architecture if consts.IS_64BITS: offset, name_len = 16, 40 else: offset, name_len = 32, 32 # Retrieve interfaces structures sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) names = array.array('B', b'\0' * 4096) ifreq = ioctl(sck.fileno(), SIOCGIFCONF, struct.pack("iL", len(names), names.buffer_info()[0])) # Extract interfaces names out = struct.unpack("iL", ifreq)[0] names = names.tobytes() if six.PY3 else names.tostring() names = [ names[i:i + offset].split(b'\0', 1)[0] for i in range(0, out, name_len) ] # noqa: E501 # Look for the IP address for ifname in names: # Only look for a matching interface name if not ifname.decode("utf8").startswith(iface_name): continue # Retrieve and convert addresses ifreq = ioctl(sck, SIOCGIFADDR, struct.pack("16s16x", ifname)) ifaddr = struct.unpack(">I", ifreq[20:24])[0] ifreq = ioctl(sck, SIOCGIFNETMASK, struct.pack("16s16x", ifname)) msk = struct.unpack(">I", ifreq[20:24])[0] # Get the full interface name ifname = plain_str(ifname) if ':' in ifname: ifname = ifname[:ifname.index(':')] else: continue # Check if the source address is included in the network if (ifaddr & msk) == ip_mask: sck.close() return (ifaddr & msk, msk, gw_str, ifname, utils.ltoa(ifaddr), metric) sck.close() return
def fixname(x): """ Modifies a string to make sure it can be used as an attribute name. """ x = plain_str(x) if x and str(x[0]) in "0123456789": x = "n_" + x return x.translate("________________________________________________" "0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______" "abcdefghijklmnopqrstuvwxyz____________________________" "______________________________________________________" "___________________________________________________")
def read_routes6(): try: f = open("/proc/net/ipv6_route", "rb") except IOError: return [] # 1. destination network # 2. destination prefix length # 3. source network displayed # 4. source prefix length # 5. next hop # 6. metric # 7. reference counter (?!?) # 8. use counter (?!?) # 9. flags # 10. device name routes = [] def proc2r(p): ret = struct.unpack('4s4s4s4s4s4s4s4s', p) ret = b':'.join(ret).decode() return utils6.in6_ptop(ret) lifaddr = in6_getifaddr() for line in f.readlines(): d, dp, _, _, nh, metric, rc, us, fl, dev = line.split() metric = int(metric, 16) fl = int(fl, 16) dev = plain_str(dev) if fl & RTF_UP == 0: continue if fl & RTF_REJECT: continue d = proc2r(d) dp = int(dp, 16) nh = proc2r(nh) cset = [] # candidate set (possible source addresses) if dev == conf.loopback_name: if d == '::': continue cset = ['::1'] else: devaddrs = (x for x in lifaddr if x[2] == dev) cset = utils6.construct_source_candidate_set(d, dp, devaddrs) if len(cset) != 0: routes.append((d, dp, nh, dev, cset, metric)) f.close() return routes
def get_if_lists(): """Returns a list containing all network interfaces.""" # Get ifconfig output subproc = subprocess.Popen([conf.prog.ifconfig], 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))) interfaces = [] ips = [] for line in plain_str(stdout).splitlines(): if ": flags" in line.lower(): interfaces.append(line[:line.find(':')]) elif "inet " in line.lower(): ips.append( line.split("inet")[1].split("netmask")[0].replace(" ", '')) return interfaces, ips
def _inet6_pton(addr): """Convert an IPv6 address from text representation into binary form, used when socket.inet_pton is not available. """ joker_pos = None result = b"" addr = plain_str(addr) if addr == '::': return b'\x00' * 16 if addr.startswith('::'): addr = addr[1:] if addr.endswith('::'): addr = addr[:-1] parts = addr.split(":") nparts = len(parts) for i, part in enumerate(parts): if not part: # "::" indicates one or more groups of 2 null bytes if joker_pos is None: joker_pos = len(result) else: # Wildcard is only allowed once raise _INET6_PTON_EXC elif i + 1 == nparts and '.' in part: # The last part of an IPv6 address can be an IPv4 address if part.count('.') != 3: # we have to do this since socket.inet_aton('1.2') == # b'\x01\x00\x00\x02' raise _INET6_PTON_EXC try: result += socket.inet_aton(part) except socket.error: raise _INET6_PTON_EXC else: # Each part must be 16bit. Add missing zeroes before decoding. try: result += hex_bytes(part.rjust(4, "0")) except (binascii.Error, TypeError): raise _INET6_PTON_EXC # If there's a wildcard, fill up with zeros to reach 128bit (16 bytes) if joker_pos is not None: if len(result) == 16: raise _INET6_PTON_EXC result = (result[:joker_pos] + b"\x00" * (16 - len(result)) + result[joker_pos:]) if len(result) != 16: raise _INET6_PTON_EXC return result
def load_manuf(filename): """ Loads manuf file from Wireshark. :param filename: the file to load the manuf file from :returns: a ManufDA filled object """ manufdb = ManufDA(_name=filename) with open(filename, "rb") as fdesc: for line in fdesc: try: line = line.strip() if not line or line.startswith(b"#"): continue parts = line.split(None, 2) ouib, shrt = parts[:2] lng = parts[2].lstrip(b"#").strip() if len(parts) > 2 else b"" lng = lng or shrt oui = plain_str(ouib) manufdb[oui] = plain_str(shrt), plain_str(lng) except Exception: log_loading.warning("Couldn't parse one line from [%s] [%r]", filename, line, exc_info=True) return manufdb
def get_if_list(): try: f = open("/proc/net/dev", "rb") except IOError: try: f.close() except Exception: pass warning("Can't open /proc/net/dev !") return [] lst = [] f.readline() f.readline() for line in f: line = plain_str(line) lst.append(line.split(":")[0].strip()) f.close() return lst
def in6_getifaddr(): """ Returns a list of 3-tuples of the form (addr, scope, iface) where 'addr' is the address of scope 'scope' associated to the interface 'iface'. This is the list of all addresses of all interfaces available on the system. """ ret = [] try: fdesc = open("/proc/net/if_inet6", "rb") except IOError: return ret for line in fdesc: # addr, index, plen, scope, flags, ifname tmp = plain_str(line).split() addr = utils6.in6_ptop(b':'.join( struct.unpack('4s4s4s4s4s4s4s4s', tmp[0].encode())).decode()) # (addr, scope, iface) ret.append((addr, int(tmp[3], 16), tmp[5])) fdesc.close() return ret
def _inet6_ntop(addr): """Convert an IPv6 address from binary form into text representation, used when socket.inet_pton is not available. """ # IPv6 addresses have 128bits (16 bytes) if len(addr) != 16: raise ValueError("invalid length of packed IP address string") # Decode to hex representation address = ":".join(plain_str(bytes_hex(addr[idx:idx + 2])).lstrip('0') or '0' # noqa: E501 for idx in range(0, 16, 2)) try: # Get the longest set of zero blocks. We need to take a look # at group 1 regarding the length, as 0:0:1:0:0:2:3:4 would # have two matches: 0:0: and :0:0: where the latter is longer, # though the first one should be taken. Group 1 is in both # cases 0:0. match = max(_IP6_ZEROS.finditer(address), key=lambda m: m.end(1) - m.start(1)) return '{}::{}'.format(address[:match.start()], address[match.end():]) except ValueError: return address
def read_routes(): try: f = open("/proc/net/route", "rb") except IOError: warning("Can't open /proc/net/route !") return [] routes = [] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: ifreq = ioctl( s, SIOCGIFADDR, struct.pack("16s16x", conf.loopback_name.encode("utf8"))) # noqa: E501 addrfamily = struct.unpack("h", ifreq[16:18])[0] if addrfamily == socket.AF_INET: ifreq2 = ioctl( s, SIOCGIFNETMASK, struct.pack("16s16x", conf.loopback_name.encode("utf8"))) # noqa: E501 msk = socket.ntohl(struct.unpack("I", ifreq2[20:24])[0]) dst = socket.ntohl(struct.unpack("I", ifreq[20:24])[0]) & msk ifaddr = utils.inet_ntoa(ifreq[20:24]) routes.append((dst, msk, "0.0.0.0", conf.loopback_name, ifaddr, 1)) # noqa: E501 else: warning("Interface %s: unknown address family (%i)" % (conf.loopback_name, addrfamily)) # noqa: E501 except IOError as err: if err.errno == 99: warning("Interface %s: no address assigned" % conf.loopback_name) # noqa: E501 else: warning("Interface %s: failed to get address config (%s)" % (conf.loopback_name, str(err))) # noqa: E501 for line in f.readlines()[1:]: line = plain_str(line) iff, dst, gw, flags, _, _, metric, msk, _, _, _ = line.split() flags = int(flags, 16) if flags & RTF_UP == 0: continue if flags & RTF_REJECT: continue try: ifreq = ioctl(s, SIOCGIFADDR, struct.pack("16s16x", iff.encode("utf8"))) # noqa: E501 except IOError: # interface is present in routing tables but does not have any assigned IP # noqa: E501 ifaddr = "0.0.0.0" ifaddr_int = 0 else: addrfamily = struct.unpack("h", ifreq[16:18])[0] if addrfamily == socket.AF_INET: ifaddr = utils.inet_ntoa(ifreq[20:24]) ifaddr_int = struct.unpack("!I", ifreq[20:24])[0] else: warning("Interface %s: unknown address family (%i)", iff, addrfamily) # noqa: E501 continue # Attempt to detect an interface alias based on addresses inconsistencies # noqa: E501 dst_int = socket.htonl(int(dst, 16)) & 0xffffffff msk_int = socket.htonl(int(msk, 16)) & 0xffffffff gw_str = utils.inet_ntoa(struct.pack("I", int(gw, 16))) metric = int(metric) if ifaddr_int & msk_int != dst_int: tmp_route = get_alias_address(iff, dst_int, gw_str, metric) if tmp_route: routes.append(tmp_route) else: routes.append((dst_int, msk_int, gw_str, iff, ifaddr, metric)) else: routes.append((dst_int, msk_int, gw_str, iff, ifaddr, metric)) f.close() s.close() return routes
def _npcap_get(self, key): res, code = _exec_cmd(" ".join([_WlanHelper, self.guid[1:-1], key])) _windows_title() # Reset title of the window if code != 0: raise OSError(res.decode("utf8", errors="ignore")) return plain_str(res.strip())