Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/pton_ntop.py: 31%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
6"""
7Convert IPv6 addresses between textual representation and binary.
9These functions are missing when python is compiled
10without IPv6 support, on Windows for instance.
11"""
13import socket
14import re
15import binascii
16from scapy.compat import plain_str, hex_bytes, bytes_encode, bytes_hex
18# Typing imports
19from typing import Union
21_IP6_ZEROS = re.compile('(?::|^)(0(?::0)+)(?::|$)')
22_INET6_PTON_EXC = socket.error("illegal IP address string passed to inet_pton")
25def _inet6_pton(addr):
26 # type: (str) -> bytes
27 """Convert an IPv6 address from text representation into binary form,
28used when socket.inet_pton is not available.
30 """
31 joker_pos = None
32 result = b""
33 addr = plain_str(addr)
34 if addr == '::':
35 return b'\x00' * 16
36 if addr.startswith('::'):
37 addr = addr[1:]
38 if addr.endswith('::'):
39 addr = addr[:-1]
40 parts = addr.split(":")
41 nparts = len(parts)
42 for i, part in enumerate(parts):
43 if not part:
44 # "::" indicates one or more groups of 2 null bytes
45 if joker_pos is None:
46 joker_pos = len(result)
47 else:
48 # Wildcard is only allowed once
49 raise _INET6_PTON_EXC
50 elif i + 1 == nparts and '.' in part:
51 # The last part of an IPv6 address can be an IPv4 address
52 if part.count('.') != 3:
53 # we have to do this since socket.inet_aton('1.2') ==
54 # b'\x01\x00\x00\x02'
55 raise _INET6_PTON_EXC
56 try:
57 result += socket.inet_aton(part)
58 except socket.error:
59 raise _INET6_PTON_EXC
60 else:
61 # Each part must be 16bit. Add missing zeroes before decoding.
62 try:
63 result += hex_bytes(part.rjust(4, "0"))
64 except (binascii.Error, TypeError):
65 raise _INET6_PTON_EXC
66 # If there's a wildcard, fill up with zeros to reach 128bit (16 bytes)
67 if joker_pos is not None:
68 if len(result) == 16:
69 raise _INET6_PTON_EXC
70 result = (result[:joker_pos] + b"\x00" * (16 - len(result)) +
71 result[joker_pos:])
72 if len(result) != 16:
73 raise _INET6_PTON_EXC
74 return result
77_INET_PTON = {
78 socket.AF_INET: socket.inet_aton,
79 socket.AF_INET6: _inet6_pton,
80}
83def inet_pton(af, addr):
84 # type: (socket.AddressFamily, Union[bytes, str]) -> bytes
85 """Convert an IP address from text representation into binary form."""
86 # Will replace Net/Net6 objects
87 addr = plain_str(addr)
88 # Use inet_pton if available
89 try:
90 if not socket.has_ipv6:
91 raise AttributeError
92 return socket.inet_pton(af, addr)
93 except AttributeError:
94 try:
95 return _INET_PTON[af](addr)
96 except KeyError:
97 raise socket.error("Address family not supported by protocol")
100def _inet6_ntop(addr):
101 # type: (bytes) -> str
102 """Convert an IPv6 address from binary form into text representation,
103used when socket.inet_pton is not available.
105 """
106 # IPv6 addresses have 128bits (16 bytes)
107 if len(addr) != 16:
108 raise ValueError("invalid length of packed IP address string")
110 # Decode to hex representation
111 address = ":".join(plain_str(bytes_hex(addr[idx:idx + 2])).lstrip('0') or '0' # noqa: E501
112 for idx in range(0, 16, 2))
114 try:
115 # Get the longest set of zero blocks. We need to take a look
116 # at group 1 regarding the length, as 0:0:1:0:0:2:3:4 would
117 # have two matches: 0:0: and :0:0: where the latter is longer,
118 # though the first one should be taken. Group 1 is in both
119 # cases 0:0.
120 match = max(_IP6_ZEROS.finditer(address),
121 key=lambda m: m.end(1) - m.start(1))
122 return '{}::{}'.format(address[:match.start()], address[match.end():])
123 except ValueError:
124 return address
127_INET_NTOP = {
128 socket.AF_INET: socket.inet_ntoa,
129 socket.AF_INET6: _inet6_ntop,
130}
133def inet_ntop(af, addr):
134 # type: (socket.AddressFamily, bytes) -> str
135 """Convert an IP address from binary form into text representation."""
136 # Use inet_ntop if available
137 addr = bytes_encode(addr)
138 try:
139 if not socket.has_ipv6:
140 raise AttributeError
141 return socket.inet_ntop(af, addr)
142 except AttributeError:
143 try:
144 return _INET_NTOP[af](addr)
145 except KeyError:
146 raise ValueError("unknown address family %d" % af)