def in6_getRandomizedIfaceId(ifaceid, previous=None): """ Implements the interface ID generation algorithm described in RFC 3041. The function takes the Modified EUI-64 interface identifier generated as described in RFC 4291 and an optional previous history value (the first element of the output of this function). If no previous interface identifier is provided, a random one is generated. The function returns a tuple containing the randomized interface identifier and the history value (for possible future use). Input and output values are provided in a "printable" format as depicted below. ex: >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3') ('4c61:76ff:f46a:a5f3', 'd006:d540:db11:b092') >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3', previous='d006:d540:db11:b092') ('fe97:46fe:9871:bd38', 'eeed:d79c:2e3f:62e') """ s = b"" if previous is None: d = b"".join(chb(x) for x in range(256)) for _ in range(8): s += chb(random.choice(d)) previous = s s = inet_pton(socket.AF_INET6, "::" + ifaceid)[8:] + previous import hashlib s = hashlib.md5(s).digest() s1, s2 = s[:8], s[8:] s1 = chb(orb(s1[0]) | 0x04) + s1[1:] s1 = inet_ntop(socket.AF_INET6, b"\xff" * 8 + s1)[20:] s2 = inet_ntop(socket.AF_INET6, b"\xff" * 8 + s2)[20:] return (s1, s2)
def in6_getRandomizedIfaceId(ifaceid, previous=None): # type: (str, Optional[str]) -> Tuple[str, str] """ Implements the interface ID generation algorithm described in RFC 3041. The function takes the Modified EUI-64 interface identifier generated as described in RFC 4291 and an optional previous history value (the first element of the output of this function). If no previous interface identifier is provided, a random one is generated. The function returns a tuple containing the randomized interface identifier and the history value (for possible future use). Input and output values are provided in a "printable" format as depicted below. ex:: >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3') ('4c61:76ff:f46a:a5f3', 'd006:d540:db11:b092') >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3', previous='d006:d540:db11:b092') ('fe97:46fe:9871:bd38', 'eeed:d79c:2e3f:62e') """ s = b"" if previous is None: b_previous = bytes(RandBin(8)) else: b_previous = inet_pton(socket.AF_INET6, "::" + previous)[8:] s = inet_pton(socket.AF_INET6, "::" + ifaceid)[8:] + b_previous import hashlib s = hashlib.md5(s).digest() s1, s2 = s[:8], s[8:] s1 = chb(orb(s1[0]) & (~0x04)) + s1[1:] # set bit 6 to 0 bs1 = inet_ntop(socket.AF_INET6, b"\xff" * 8 + s1)[20:] bs2 = inet_ntop(socket.AF_INET6, b"\xff" * 8 + s2)[20:] return (bs1, bs2)
def teredoAddrExtractInfo(x): """ Extract information from a Teredo address. Return value is a 4-tuple made of IPv4 address of Teredo server, flag value (int), mapped address (non obfuscated) and mapped port (non obfuscated). No specific checks are performed on passed address. """ addr = inet_pton(socket.AF_INET6, x) server = inet_ntop(socket.AF_INET, addr[4:8]) flag = struct.unpack("!H", addr[8:10])[0] mappedport = struct.unpack("!H", strxor(addr[10:12], b'\xff' * 2))[0] mappedaddr = inet_ntop(socket.AF_INET, strxor(addr[12:16], b'\xff' * 4)) return server, flag, mappedaddr, mappedport
def in6_getAddrType(addr): naddr = inet_pton(socket.AF_INET6, addr) paddr = inet_ntop(socket.AF_INET6, naddr) # normalize addrType = 0 # _Assignable_ Global Unicast Address space # is defined in RFC 3513 as those in 2000::/3 if ((orb(naddr[0]) & 0xE0) == 0x20): addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_GLOBAL) if naddr[:2] == b' \x02': # Mark 6to4 @ addrType |= IPV6_ADDR_6TO4 elif orb(naddr[0]) == 0xff: # multicast addrScope = paddr[3] if addrScope == '2': addrType = (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_MULTICAST) elif addrScope == 'e': addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) else: addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) elif ((orb(naddr[0]) == 0xfe) and ((int(paddr[2], 16) & 0xC) == 0x8)): addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL) elif paddr == "::1": addrType = IPV6_ADDR_LOOPBACK elif paddr == "::": addrType = IPV6_ADDR_UNSPECIFIED else: # Everything else is global unicast (RFC 3513) # Even old deprecated (RFC3879) Site-Local addresses addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) return addrType
def load(self): from scapy.fields import FlagValue data = {} ips = in6_getifaddr() for i in _get_if_list(): ifflags = struct.unpack("16xH14x", get_if(i, SIOCGIFFLAGS))[0] index = get_if_index(i) mac = scapy.utils.str2mac( get_if_raw_hwaddr(i, siocgifhwaddr=SIOCGIFHWADDR)[1] ) ip = inet_ntop(socket.AF_INET, get_if_raw_addr(i)) if ip == "0.0.0.0": ip = None ifflags = FlagValue(ifflags, _iff_flags) if_data = { "name": i, "network_name": i, "description": i, "flags": ifflags, "index": index, "ip": ip, "ips": [x[0] for x in ips if x[2] == i] + [ip] if ip else [], "mac": mac } data[i] = NetworkInterface(self, if_data) return data
def in6_getifaddr_raw(): """Returns all available IPv6 on the computer, read from winpcap.""" err = create_string_buffer(PCAP_ERRBUF_SIZE) devs = POINTER(pcap_if_t)() ret = [] if pcap_findalldevs(byref(devs), err) < 0: return ret try: p = devs ret = [] while p: a = p.contents.addresses while a: if a.contents.addr.contents.sa_family == socket.AF_INET6: ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in6)) addr = inet_ntop(socket.AF_INET6, b"".join( chb(x) for x in val.contents.sin6_addr[:])) # noqa: E501 scope = scapy.utils6.in6_getscope(addr) ret.append((addr, scope, plain_str(p.contents.name))) a = a.contents.next p = p.contents.next return ret finally: pcap_freealldevs(devs)
def in6_ptop(str): # type: (str) -> str """ Normalizes IPv6 addresses provided in printable format, returning the same address in printable format. (2001:0db8:0:0::1 -> 2001:db8::1) """ return inet_ntop(socket.AF_INET6, inet_pton(socket.AF_INET6, str))
def compressDestAddr(self, ipv6): # https://tools.ietf.org/html/rfc6282#section-3.1.1 tmp_ip = inet_pton(socket.AF_INET6, ipv6.dst) if self.m == 0 and self.dac == 0: if self.dam == 0x0: pass elif self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 0 and self.dac == 1: if self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 1 and self.dac == 0: if self.dam == 0x0: pass if self.dam == 0x1: tmp_ip = b"\x00" * 10 + tmp_ip[1:2] + tmp_ip[11:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 12 + tmp_ip[1:2] + tmp_ip[13:16] elif self.dam == 0x3: tmp_ip = b"\x00" * 15 + tmp_ip[15:16] elif self.m == 1 and self.dac == 1: if self.dam == 0: tmp_ip = b"\x00" * 10 + tmp_ip[1:3] + tmp_ip[12:16] self.dst = inet_ntop(socket.AF_INET6, tmp_ip)
def verify_vrf(self, vrf_id): """ Check if the FIB table / VRF ID is configured. :param int vrf_id: The FIB table / VRF ID to be verified. :return: 1 if the FIB table / VRF ID is configured, otherwise return 0. """ ip6_fib_dump = self.vapi.ip6_fib_dump() vrf_exist = False vrf_count = 0 for ip6_fib_details in ip6_fib_dump: if ip6_fib_details.table_id == vrf_id: if not vrf_exist: vrf_exist = True addr = inet_ntop(socket.AF_INET6, ip6_fib_details.address) found = False for pg_if in self.pg_if_by_vrf_id[vrf_id]: if found: break for host in pg_if.remote_hosts: if str(addr) == str(host.ip6): vrf_count += 1 found = True break if not vrf_exist and vrf_count == 0: self.logger.info("IPv6 VRF ID %d is not configured" % vrf_id) return VRFState.not_configured elif vrf_exist and vrf_count == 0: self.logger.info("IPv6 VRF ID %d has been reset" % vrf_id) return VRFState.reset else: self.logger.info("IPv6 VRF ID %d is configured" % vrf_id) return VRFState.configured
def in6_getLocalUniquePrefix(): """ Returns a pseudo-randomly generated Local Unique prefix. Function follows recommendation of Section 3.2.2 of RFC 4193 for prefix generation. """ # Extracted from RFC 1305 (NTP) : # NTP timestamps are represented as a 64-bit unsigned fixed-point number, # in seconds relative to 0h on 1 January 1900. The integer part is in the # first 32 bits and the fraction part in the last 32 bits. # epoch = (1900, 1, 1, 0, 0, 0, 5, 1, 0) # x = time.time() # from time import gmtime, strftime, gmtime, mktime # delta = mktime(gmtime(0)) - mktime(self.epoch) # x = x-delta tod = time.time() # time of day. Will bother with epoch later i = int(tod) j = int((tod - i) * (2**32)) tod = struct.pack("!II", i, j) mac = RandMAC() # construct modified EUI-64 ID eui64 = inet_pton(socket.AF_INET6, '::' + in6_mactoifaceid(mac))[8:] import hashlib globalid = hashlib.sha1(tod + eui64).digest()[:5] return inet_ntop(socket.AF_INET6, b'\xfd' + globalid + b'\x00' * 10)
def compressDestinyAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.dst) if self.m == 0 and self.dac == 0: if self.dam == 0x0: pass elif self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 0 and self.dac == 1: if self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 1 and self.dac == 0: if self.dam == 0x1: tmp_ip = b"\x00" * 10 + tmp_ip[1:2] + tmp_ip[11:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 12 + tmp_ip[1:2] + tmp_ip[13:16] elif self.dam == 0x3: tmp_ip = b"\x00" * 15 + tmp_ip[15:16] elif self.m == 1 and self.dac == 1: raise Exception('Unimplemented') self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip)
def verify_vrf(self, vrf_id): """ Check if the FIB table / VRF ID is configured. :param int vrf_id: The FIB table / VRF ID to be verified. :return: 1 if the FIB table / VRF ID is configured, otherwise return 0. """ ip6_fib_dump = self.vapi.ip6_fib_dump() vrf_exist = False vrf_count = 0 for ip6_fib_details in ip6_fib_dump: if ip6_fib_details[2] == vrf_id: if not vrf_exist: vrf_exist = True addr = inet_ntop(socket.AF_INET6, ip6_fib_details[4]) addrtype = in6_getAddrType(addr) vrf_count += 1 if addrtype == IPV6_ADDR_UNICAST else 0 if not vrf_exist and vrf_count == 0: self.logger.info("IPv6 VRF ID %d is not configured" % vrf_id) return VRF_NOT_CONFIGURED elif vrf_exist and vrf_count == 0: self.logger.info("IPv6 VRF ID %d has been reset" % vrf_id) return VRF_RESET else: self.logger.info("IPv6 VRF ID %d is configured" % vrf_id) return VRF_CONFIGURED
def m2i(self, pkt, s): family = None if pkt.type == 1: # A family = socket.AF_INET elif pkt.type in [2, 5, 12]: # NS, CNAME, PTR if hasattr(pkt, "_orig_s") and pkt._orig_s: if orb(s[0]) & 0xc0: s = dns_get_str(s, 0, pkt)[0] else: s = dns_get_str(pkt._orig_s, pkt._orig_p, _internal=True)[0] # noqa: E501 else: s = dns_get_str(s, 0)[0] elif pkt.type == 16: # TXT ret_s = list() tmp_s = s # RDATA contains a list of strings, each are prepended with # a byte containing the size of the following string. while tmp_s: tmp_len = orb(tmp_s[0]) + 1 if tmp_len > len(tmp_s): warning("DNS RR TXT prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) # noqa: E501 ret_s.append(tmp_s[1:tmp_len]) tmp_s = tmp_s[tmp_len:] s = ret_s elif pkt.type == 28: # AAAA family = socket.AF_INET6 if family is not None: s = inet_ntop(family, s) return s
def m2i(self, pkt, s): family = None if pkt.type == 1: # A family = socket.AF_INET elif pkt.type in [2, 5, 12]: # NS, CNAME, PTR s = dns_get_str(s, 0, pkt)[0] elif pkt.type == 16: # TXT ret_s = list() tmp_s = s # RDATA contains a list of strings, each are prepended with # a byte containing the size of the following string. while tmp_s: tmp_len = orb(tmp_s[0]) + 1 if tmp_len > len(tmp_s): warning( "DNS RR TXT prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) # noqa: E501 ret_s.append(tmp_s[1:tmp_len]) tmp_s = tmp_s[tmp_len:] s = ret_s elif pkt.type == 28: # AAAA family = socket.AF_INET6 if family is not None: s = inet_ntop(family, s) return s
def compressDestinyAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.dst) if self.m == 0 and self.dac == 0: if self.dam == 0x0: tmp_ip = tmp_ip elif self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 0 and self.dac == 1: if self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 1 and self.dac == 0: if self.dam == 0x1: tmp_ip = b"\x00" * 10 + tmp_ip[1:2] + tmp_ip[11:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 12 + tmp_ip[1:2] + tmp_ip[13:16] elif self.dam == 0x3: tmp_ip = b"\x00" * 15 + tmp_ip[15:16] elif self.m == 1 and self.dac == 1: raise Exception('Unimplemented') self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip)
def decompressSourceAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.sourceAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.sac == 0: if self.sam == 0x0: pass elif self.sam == 0x1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[16 - source_addr_mode2(self):16] # noqa: E501 elif self.sam == 0x2: tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_mode2(self):16] elif self.sam == 0x3: # EXTRACT ADDRESS FROM Dot15d4 tmp_ip = _extract_dot15d4address(self, source=True) else: warning("Unknown source address compression mode !") else: # self.sac == 1: if self.sam == 0x0: pass elif self.sam == 0x2: # TODO: take context IID tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_mode2(self):16] elif self.sam == 0x3: tmp_ip = LINK_LOCAL_PREFIX[0:8] + b"\x00" * 8 # TODO: CONTEXT ID # noqa: E501 else: raise Exception('Unimplemented') self.sourceAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.sourceAddr
def in6_getAddrType(addr): # type: (str) -> int naddr = inet_pton(socket.AF_INET6, addr) paddr = inet_ntop(socket.AF_INET6, naddr) # normalize addrType = 0 # _Assignable_ Global Unicast Address space # is defined in RFC 3513 as those in 2000::/3 if ((orb(naddr[0]) & 0xE0) == 0x20): addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_GLOBAL) if naddr[:2] == b' \x02': # Mark 6to4 @ addrType |= IPV6_ADDR_6TO4 elif orb(naddr[0]) == 0xff: # multicast addrScope = paddr[3] if addrScope == '2': addrType = (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_MULTICAST) elif addrScope == 'e': addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) else: addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) elif ((orb(naddr[0]) == 0xfe) and ((int(paddr[2], 16) & 0xC) == 0x8)): addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL) elif paddr == "::1": addrType = IPV6_ADDR_LOOPBACK elif paddr == "::": addrType = IPV6_ADDR_UNSPECIFIED else: # Everything else is global unicast (RFC 3513) # Even old deprecated (RFC3879) Site-Local addresses addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) return addrType
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 data will be stored in ``conf.cache_pcapiflist`` """ from scapy.fields import FlagValue 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 or "" ) # DESC flags = p.contents.flags # FLAGS ips = [] mac = "" 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[:] elif family == socket.AF_LINK: # Special case: MAC # (AF_LINK is mostly BSD specific) val = ap.contents.sa_data val = val[:6] mac = str2mac(bytes(bytearray(val))) a = a.contents.next continue else: # Unknown AF 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 flags = FlagValue(flags, _pcap_if_flags) if_list[name] = (description, ips, flags, mac) p = p.contents.next conf.cache_pcapiflist = if_list except Exception: raise finally: pcap_freealldevs(devs)
def in6_getLocalUniquePrefix(): # type: () -> str """ Returns a pseudo-randomly generated Local Unique prefix. Function follows recommendation of Section 3.2.2 of RFC 4193 for prefix generation. """ # Extracted from RFC 1305 (NTP) : # NTP timestamps are represented as a 64-bit unsigned fixed-point number, # in seconds relative to 0h on 1 January 1900. The integer part is in the # first 32 bits and the fraction part in the last 32 bits. # epoch = (1900, 1, 1, 0, 0, 0, 5, 1, 0) # x = time.time() # from time import gmtime, strftime, gmtime, mktime # delta = mktime(gmtime(0)) - mktime(self.epoch) # x = x-delta tod = time.time() # time of day. Will bother with epoch later i = int(tod) j = int((tod - i) * (2**32)) btod = struct.pack("!II", i, j) mac = RandMAC() # construct modified EUI-64 ID eui64 = inet_pton(socket.AF_INET6, '::' + in6_mactoifaceid(mac))[8:] import hashlib globalid = hashlib.sha1(btod + eui64).digest()[:5] return inet_ntop(socket.AF_INET6, b'\xfd' + globalid + b'\x00' * 10)
def in6_getifaddr_raw(): err = create_string_buffer(PCAP_ERRBUF_SIZE) devs = POINTER(pcap_if_t)() ret = [] if pcap_findalldevs(byref(devs), err) < 0: return ret try: p = devs ret = [] while p: a = p.contents.addresses while a: if a.contents.addr.contents.sa_family == socket.AF_INET6: ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in6)) addr = inet_ntop( socket.AF_INET6, b"".join( chb(x) for x in val.contents.sin6_addr[:])) scope = scapy.utils6.in6_getscope(addr) ret.append( (addr, scope, p.contents.name.decode('ascii'))) a = a.contents.next p = p.contents.next return ret finally: pcap_freealldevs(devs)
def decompressSourceAddr(self, packet): # https://tools.ietf.org/html/rfc6282#section-3.1.1 try: tmp_ip = inet_pton(socket.AF_INET6, self.src) except socket.error: tmp_ip = b"\x00" * 16 if self.sac == 0: if self.sam == 0x0: # Full address is carried in-line pass elif self.sam == 0x1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[16 - source_addr_size(self):16] # noqa: E501 elif self.sam == 0x2: tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_size(self):16] elif self.sam == 0x3: # Taken from encapsulating header tmp_ip = _extract_upperaddress(self, source=True) else: # self.sac == 1: if self.sam == 0x0: # Unspecified address :: pass elif self.sam == 0x1: # should use context IID pass elif self.sam == 0x2: # should use context IID tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_size(self):16] elif self.sam == 0x3: # should use context IID tmp_ip = LINK_LOCAL_PREFIX[0:8] + b"\x00" * 8 self.src = inet_ntop(socket.AF_INET6, tmp_ip) return self.src
def in6_getha(prefix): """ Return the anycast address associated with all home agents on a given subnet. """ r = in6_and(inet_pton(socket.AF_INET6, prefix), in6_cidr2mask(64)) r = in6_or(r, inet_pton(socket.AF_INET6, '::fdff:ffff:ffff:fffe')) return inet_ntop(socket.AF_INET6, r)
def genNdpNsPkt(src_mac, src_ip, target_ip): nsma = in6_getnsma(inet_pton(socket.AF_INET6, target_ip)) d = inet_ntop(socket.AF_INET6, nsma) dm = in6_getnsmac(nsma) p = Ether(dst=dm) / IPv6(dst=d, src=src_ip, hlim=255) p /= ICMPv6ND_NS(tgt=target_ip) p /= ICMPv6NDOptSrcLLAddr(lladdr=src_mac) return p
def _extract_ip_netmask(obj): ip = obj[sock_addr_name][sin_addr_name] ip = bytes(bytearray(ip['byte'])) # Extract netmask netmask = (ip_len - (len(ip) - len(ip.rstrip(b"\x00")))) * 8 # Build IP ip = inet_ntop(af, ip) return ip, netmask
def decompressDestAddr(self, packet): # https://tools.ietf.org/html/rfc6282#section-3.1.1 try: tmp_ip = inet_pton(socket.AF_INET6, self.dst) except socket.error: tmp_ip = b"\x00" * 16 if self.m == 0 and self.dac == 0: if self.dam == 0: # Address fully carried pass elif self.dam == 1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[-8:] elif self.dam == 2: tmp_ip = LINK_LOCAL_PREFIX[ 0:8] + b"\x00\x00\x00\xff\xfe\x00" + tmp_ip[ -2:] # noqa: E501 elif self.dam == 3: tmp_ip = _extract_upperaddress(self, source=False) elif self.m == 0 and self.dac == 1: if self.dam == 0: # reserved pass elif self.dam == 0x3: # should use context IID + encapsulating header tmp_ip = _extract_upperaddress(self, source=False) elif self.dam not in [0x1, 0x2]: # https://tools.ietf.org/html/rfc6282#page-9 # Should use context information: unimplemented pass elif self.m == 1 and self.dac == 0: if self.dam == 0: # Address fully carried pass elif self.dam == 1: tmp = b"\xff" + chb(tmp_ip[16 - dest_addr_size(self)]) tmp_ip = tmp + b"\x00" * 9 + tmp_ip[-5:] elif self.dam == 2: tmp = b"\xff" + chb(tmp_ip[16 - dest_addr_size(self)]) tmp_ip = tmp + b"\x00" * 11 + tmp_ip[-3:] else: # self.dam == 3: tmp_ip = b"\xff\x02" + b"\x00" * 13 + tmp_ip[-1:] elif self.m == 1 and self.dac == 1: if self.dam == 0x0: # https://tools.ietf.org/html/rfc6282#page-10 # https://github.com/wireshark/wireshark/blob/f54611d1104d85a425e52c7318c522ed249916b6/epan/dissectors/packet-6lowpan.c#L2149-L2166 # Format: ffXX:XXLL:PPPP:PPPP:PPPP:PPPP:XXXX:XXXX # P and L should be retrieved from context P = b"\x00" * 16 L = b"\x00" X = tmp_ip[-6:] tmp_ip = b"\xff" + X[:2] + L + P[:8] + X[2:6] else: # all the others values: reserved pass self.dst = inet_ntop(socket.AF_INET6, tmp_ip) return self.dst
def in6_getLinkScopedMcastAddr(addr, grpid=None, scope=2): """ Generate a Link-Scoped Multicast Address as described in RFC 4489. Returned value is in printable notation. 'addr' parameter specifies the link-local address to use for generating Link-scoped multicast address IID. By default, the function returns a ::/96 prefix (aka last 32 bits of returned address are null). If a group id is provided through 'grpid' parameter, last 32 bits of the address are set to that value (accepted formats : b'\x12\x34\x56\x78' or '12345678' or 0x12345678 or 305419896). By default, generated address scope is Link-Local (2). That value can be modified by passing a specific 'scope' value as an argument of the function. RFC 4489 only authorizes scope values <= 2. Enforcement is performed by the function (None will be returned). If no link-local address can be used to generate the Link-Scoped IPv6 Multicast address, or if another error occurs, None is returned. """ if scope not in [0, 1, 2]: return None try: if not in6_islladdr(addr): return None addr = inet_pton(socket.AF_INET6, addr) except Exception: warning("in6_getLinkScopedMcastPrefix(): Invalid address provided") return None iid = addr[8:] if grpid is None: grpid = b'\x00\x00\x00\x00' else: if isinstance(grpid, (bytes, str)): if len(grpid) == 8: try: grpid = int(grpid, 16) & 0xffffffff except Exception: warning("in6_getLinkScopedMcastPrefix(): Invalid group id provided") # noqa: E501 return None elif len(grpid) == 4: try: grpid = struct.unpack("!I", grpid)[0] except Exception: warning("in6_getLinkScopedMcastPrefix(): Invalid group id provided") # noqa: E501 return None grpid = struct.pack("!I", grpid) flgscope = struct.pack("B", 0xff & ((0x3 << 4) | scope)) plen = b'\xff' res = b'\x00' a = b'\xff' + flgscope + res + plen + iid + grpid return inet_ntop(socket.AF_INET6, a)
def in6_addrtomac(addr): """ Extract the mac address from provided address. None is returned on error. """ mask = inet_pton(socket.AF_INET6, "::ffff:ffff:ffff:ffff") x = in6_and(mask, inet_pton(socket.AF_INET6, addr)) ifaceid = inet_ntop(socket.AF_INET6, x)[2:] return in6_ifaceidtomac(ifaceid)
def load_winpcapy(): """This functions calls Winpcap/Npcap pcap_findalldevs function, and extracts and parse all the data scapy will need to use it: - the Interface List - the IPv4 addresses - the IPv6 addresses This data is stored in their respective conf.cache_* subfields: conf.cache_iflist conf.cache_ipaddrs conf.cache_in6_getifaddr """ err = create_string_buffer(PCAP_ERRBUF_SIZE) devs = POINTER(pcap_if_t)() if_list = [] ip_addresses = {} ip6_addresses = [] if pcap_findalldevs(byref(devs), err) < 0: return try: p = devs # Iterate through the different interfaces while p: if_list.append(plain_str(p.contents.name)) a = p.contents.addresses while a: # IPv4 address if a.contents.addr.contents.sa_family == socket.AF_INET: # noqa: E501 ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in)) if_raw_addr = b"".join( chb(x) for x in val.contents.sin_addr[:4]) # noqa: E501 if if_raw_addr != b'\x00\x00\x00\x00': ip_addresses[plain_str( p.contents.name )] = if_raw_addr # noqa: E501 # IPv6 address if a.contents.addr.contents.sa_family == socket.AF_INET6: # noqa: E501 ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in6)) addr = inet_ntop(socket.AF_INET6, b"".join( chb(x) for x in val.contents.sin6_addr[:])) # noqa: E501 scope = scapy.utils6.in6_getscope(addr) ip6_addresses.append( (addr, scope, plain_str(p.contents.name))) # noqa: E501 a = a.contents.next p = p.contents.next conf.cache_iflist = if_list conf.cache_ipaddrs = ip_addresses conf.cache_in6_getifaddr = ip6_addresses except Exception: raise finally: pcap_freealldevs(devs)
def m2i(self, pkt, x): tmp_len = self.length_from(pkt) prefixlen = self.prefixlen_to_bytelen(tmp_len) if tmp_len > 128: warning("EigrpIP6Field: Prefix length is > 128. Dissection of this packet will fail") # noqa: E501 else: pad = b"\x00" * (16 - prefixlen) x += pad return inet_ntop(socket.AF_INET6, x)
def in6_6to4ExtractAddr(addr): """ Extract IPv4 address embedded in 6to4 address. Passed address must be a 6to4 address. None is returned on error. """ try: addr = inet_pton(socket.AF_INET6, addr) except Exception: return None if addr[:2] != b" \x02": return None return inet_ntop(socket.AF_INET, addr[2:6])
def in6_get6to4Prefix(addr): """ Returns the /48 6to4 prefix associated with provided IPv4 address On error, None is returned. No check is performed on public/private status of the address """ try: addr = inet_pton(socket.AF_INET, addr) addr = inet_ntop(socket.AF_INET6, b'\x20\x02' + addr + b'\x00' * 10) except Exception: return None return addr
def in6_get6to4Prefix(addr): # type: (str) -> Optional[str] """ Returns the /48 6to4 prefix associated with provided IPv4 address On error, None is returned. No check is performed on public/private status of the address """ try: baddr = inet_pton(socket.AF_INET, addr) return inet_ntop(socket.AF_INET6, b'\x20\x02' + baddr + b'\x00' * 10) except Exception: return None
def decompressDestAddr(self): if not self.dp and not self.di: # Prefix & Interface return self.dst elif not self.di: # Only interface addr = inet_pton(socket.AF_INET6, self.dst)[-8:] addr = LINK_LOCAL_PREFIX[:8] + addr else: # Interface not provided addr = _extract_upperaddress(self, source=False) self.dst = inet_ntop(socket.AF_INET6, addr) return self.dst
def decompressDestinyAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.destinyAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.m == 0 and self.dac == 0: if self.dam == 0: pass elif self.dam == 1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[-8:] elif self.dam == 2: tmp_ip = LINK_LOCAL_PREFIX[ 0:8] + b"\x00\x00\x00\xff\xfe\x00" + tmp_ip[ -2:] # noqa: E501 elif self.dam == 3: # TODO May need some extra changes, we are copying # (self.m == 0 and self.dac == 1) tmp_ip = _extract_upperaddress(self, source=False) elif self.m == 0 and self.dac == 1: if self.dam == 0: raise Exception('Reserved') elif self.dam == 0x3: tmp_ip = _extract_upperaddress(self, source=False) elif self.dam not in [0x1, 0x2]: warning("Unknown destiny address compression mode !") elif self.m == 1 and self.dac == 0: if self.dam == 0: raise Exception("unimplemented") elif self.dam == 1: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 9 + tmp_ip[-5:] elif self.dam == 2: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 11 + tmp_ip[-3:] else: # self.dam == 3: tmp_ip = b"\xff\x02" + b"\x00" * 13 + tmp_ip[-1:] elif self.m == 1 and self.dac == 1: if self.dam == 0x0: # See https://tools.ietf.org/html/rfc6282#page-9 raise Exception( "Unimplemented: I didn't understand the 6lowpan specification" ) # noqa: E501 else: # all the others values raise Exception("Reserved value by specification.") self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.destinyAddr
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 load_winpcapy(): """This functions calls Winpcap/Npcap pcap_findalldevs function, and extracts and parse all the data scapy will need to use it: - the Interface List This data is stored in their respective conf.cache_* subfields: conf.cache_iflist """ 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 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[description] = (name, ips) p = p.contents.next conf.cache_iflist = if_list except Exception: raise finally: pcap_freealldevs(devs)
def ifchange(self, iff, addr): the_addr, the_plen = (addr.split("/") + ["128"])[:2] the_plen = int(the_plen) naddr = inet_pton(socket.AF_INET6, the_addr) nmask = in6_cidr2mask(the_plen) the_net = inet_ntop(socket.AF_INET6, in6_and(nmask, naddr)) for i, route in enumerate(self.routes): net, plen, gw, iface, addr, metric = route if iface != iff: continue if gw == '::': self.routes[i] = (the_net, the_plen, gw, iface, [the_addr], metric) # noqa: E501 else: self.routes[i] = (net, plen, gw, iface, [the_addr], metric) self.invalidate_cache() conf.netcache.in6_neighbor.flush()
def decompressDestinyAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.destinyAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.m == 0 and self.dac == 0: if self.dam == 0: pass elif self.dam == 1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[-8:] elif self.dam == 2: tmp_ip = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" + tmp_ip[-2:] # noqa: E501 elif self.dam == 3: # TODO May need some extra changes, we are copying # (self.m == 0 and self.dac == 1) tmp_ip = _extract_dot15d4address(self, source=False) elif self.m == 0 and self.dac == 1: if self.dam == 0: raise Exception('Reserved') elif self.dam == 0x3: tmp_ip = _extract_dot15d4address(self, source=False) elif self.dam not in [0x1, 0x2]: warning("Unknown destiny address compression mode !") elif self.m == 1 and self.dac == 0: if self.dam == 0: raise Exception("unimplemented") elif self.dam == 1: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 9 + tmp_ip[-5:] elif self.dam == 2: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 11 + tmp_ip[-3:] else: # self.dam == 3: tmp_ip = b"\xff\x02" + b"\x00" * 13 + tmp_ip[-1:] elif self.m == 1 and self.dac == 1: if self.dam == 0x0: raise Exception("Unimplemented: I didn't understand the 6lowpan specification") # noqa: E501 else: # all the others values raise Exception("Reserved value by specification.") self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.destinyAddr
def in6_ctop(addr): """ Convert an IPv6 address in Compact Representation Notation (RFC 1924) to printable representation ;-) Returns None on error. """ if len(addr) != 20 or not reduce(lambda x, y: x and y, [x in _rfc1924map for x in addr]): return None i = 0 for c in addr: j = _rfc1924map.index(c) i = 85 * i + j res = [] for j in range(4): res.append(struct.pack("!I", i % 2**32)) i = i // (2**32) res.reverse() return inet_ntop(socket.AF_INET6, b"".join(res))
def ifadd(self, iff, addr): """ Add an interface 'iff' with provided address into routing table. Ex: ifadd('eth0', '2001:bd8:cafe:1::1/64') will add following entry into # noqa: E501 Scapy6 internal routing table: Destination Next Hop iface Def src @ Metric 2001:bd8:cafe:1::/64 :: eth0 2001:bd8:cafe:1::1 1 prefix length value can be omitted. In that case, a value of 128 will be used. """ addr, plen = (addr.split("/") + ["128"])[:2] addr = in6_ptop(addr) plen = int(plen) naddr = inet_pton(socket.AF_INET6, addr) nmask = in6_cidr2mask(plen) prefix = inet_ntop(socket.AF_INET6, in6_and(nmask, naddr)) self.invalidate_cache() self.routes.append((prefix, plen, '::', iff, [addr], 1))
def compressSourceAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.src) if self.sac == 0: if self.sam == 0x0: tmp_ip = tmp_ip elif self.sam == 0x1: tmp_ip = tmp_ip[8:16] elif self.sam == 0x2: tmp_ip = tmp_ip[14:16] else: # self.sam == 0x3: pass else: # self.sac == 1 if self.sam == 0x0: tmp_ip = b"\x00" * 16 elif self.sam == 0x1: tmp_ip = tmp_ip[8:16] elif self.sam == 0x2: tmp_ip = tmp_ip[14:16] self.sourceAddr = inet_ntop(socket.AF_INET6, b"\x00" * (16 - len(tmp_ip)) + tmp_ip) # noqa: E501 return self.sourceAddr
def load_winpcapy(): err = create_string_buffer(PCAP_ERRBUF_SIZE) devs = POINTER(pcap_if_t)() if_list = [] ip_addresses = {} ip6_addresses = [] if pcap_findalldevs(byref(devs), err) < 0: return try: p = devs # Iterate through the different interfaces while p: if_list.append(plain_str(p.contents.name)) a = p.contents.addresses while a: # IPv4 address if a.contents.addr.contents.sa_family == socket.AF_INET: # noqa: E501 ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in)) if_raw_addr = b"".join(chb(x) for x in val.contents.sin_addr[:4]) # noqa: E501 if if_raw_addr != b'\x00\x00\x00\x00': ip_addresses[plain_str(p.contents.name)] = if_raw_addr # noqa: E501 # IPv6 address if a.contents.addr.contents.sa_family == socket.AF_INET6: # noqa: E501 ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in6)) addr = inet_ntop(socket.AF_INET6, b"".join(chb(x) for x in val.contents.sin6_addr[:])) # noqa: E501 scope = scapy.utils6.in6_getscope(addr) ip6_addresses.append((addr, scope, plain_str(p.contents.name))) # noqa: E501 a = a.contents.next p = p.contents.next conf.cache_iflist = if_list conf.cache_ipaddrs = ip_addresses conf.cache_in6_getifaddr = ip6_addresses except Exception: raise finally: pcap_freealldevs(devs)
def in6_getifaddr_raw(): """Returns all available IPv6 on the computer, read from winpcap.""" err = create_string_buffer(PCAP_ERRBUF_SIZE) devs = POINTER(pcap_if_t)() ret = [] if pcap_findalldevs(byref(devs), err) < 0: return ret try: p = devs ret = [] while p: a = p.contents.addresses while a: if a.contents.addr.contents.sa_family == socket.AF_INET6: ap = a.contents.addr val = cast(ap, POINTER(sockaddr_in6)) addr = inet_ntop(socket.AF_INET6, b"".join(chb(x) for x in val.contents.sin6_addr[:])) scope = scapy.utils6.in6_getscope(addr) ret.append((addr, scope, plain_str(p.contents.name))) a = a.contents.next p = p.contents.next return ret finally: pcap_freealldevs(devs)
def in6_ptop(str): """ Normalizes IPv6 addresses provided in printable format, returning the same address in printable format. (2001:0db8:0:0::1 -> 2001:db8::1) """ return inet_ntop(socket.AF_INET6, inet_pton(socket.AF_INET6, str))
def get_if_addr(iff): return inet_ntop(socket.AF_INET, get_if_raw_addr(iff))