Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/netaddr/strategy/ipv4.py: 62%
103 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:45 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:45 +0000
1#-----------------------------------------------------------------------------
2# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
3#
4# Released under the BSD license. See the LICENSE file for details.
5#-----------------------------------------------------------------------------
6"""IPv4 address logic."""
8import sys as _sys
9import struct as _struct
11from socket import inet_aton as _inet_aton
12# Check whether we need to use fallback code or not.
13if _sys.platform in ('win32', 'cygwin'):
14 # inet_pton() not available on Windows. inet_pton() under cygwin
15 # behaves exactly like inet_aton() and is therefore highly unreliable.
16 from netaddr.fbsocket import inet_pton as _inet_pton, AF_INET
17else:
18 # All other cases, use all functions from the socket module.
19 from socket import inet_pton as _inet_pton, AF_INET
21from netaddr.core import AddrFormatError, ZEROFILL, INET_PTON
23from netaddr.strategy import (
24 valid_words as _valid_words, valid_bits as _valid_bits,
25 bits_to_int as _bits_to_int, int_to_bits as _int_to_bits,
26 valid_bin as _valid_bin, int_to_bin as _int_to_bin,
27 bin_to_int as _bin_to_int)
29from netaddr.compat import _str_type
31#: The width (in bits) of this address type.
32width = 32
34#: The individual word size (in bits) of this address type.
35word_size = 8
37#: The format string to be used when converting words to string values.
38word_fmt = '%d'
40#: The separator character used between each word.
41word_sep = '.'
43#: The AF_* constant value of this address type.
44family = AF_INET
46#: A friendly string name address type.
47family_name = 'IPv4'
49#: The version of this address type.
50version = 4
52#: The number base to be used when interpreting word values as integers.
53word_base = 10
55#: The maximum integer value that can be represented by this address type.
56max_int = 2 ** width - 1
58#: The number of words in this address type.
59num_words = width // word_size
61#: The maximum integer value for an individual word in this address type.
62max_word = 2 ** word_size - 1
64#: A dictionary mapping IPv4 CIDR prefixes to the equivalent netmasks.
65prefix_to_netmask = dict(
66 [(i, max_int ^ (2 ** (width - i) - 1)) for i in range(0, width + 1)])
68#: A dictionary mapping IPv4 netmasks to their equivalent CIDR prefixes.
69netmask_to_prefix = dict(
70 [(max_int ^ (2 ** (width - i) - 1), i) for i in range(0, width + 1)])
72#: A dictionary mapping IPv4 CIDR prefixes to the equivalent hostmasks.
73prefix_to_hostmask = dict(
74 [(i, (2 ** (width - i) - 1)) for i in range(0, width + 1)])
76#: A dictionary mapping IPv4 hostmasks to their equivalent CIDR prefixes.
77hostmask_to_prefix = dict(
78 [((2 ** (width - i) - 1), i) for i in range(0, width + 1)])
81def valid_str(addr, flags=0):
82 """
83 :param addr: An IPv4 address in presentation (string) format.
85 :param flags: decides which rules are applied to the interpretation of the
86 addr value. Supported constants are INET_PTON and ZEROFILL. See the
87 netaddr.core docs for details.
89 :return: ``True`` if IPv4 address is valid, ``False`` otherwise.
90 """
91 if addr == '':
92 raise AddrFormatError('Empty strings are not supported!')
94 validity = True
96 if flags & ZEROFILL:
97 addr = '.'.join(['%d' % int(i) for i in addr.split('.')])
99 try:
100 if flags & INET_PTON:
101 _inet_pton(AF_INET, addr)
102 else:
103 _inet_aton(addr)
104 except Exception:
105 validity = False
107 return validity
110def str_to_int(addr, flags=0):
111 """
112 :param addr: An IPv4 dotted decimal address in string form.
114 :param flags: decides which rules are applied to the interpretation of the
115 addr value. Supported constants are INET_PTON and ZEROFILL. See the
116 netaddr.core docs for details.
118 :return: The equivalent unsigned integer for a given IPv4 address.
119 """
120 if flags & ZEROFILL:
121 addr = '.'.join(['%d' % int(i) for i in addr.split('.')])
123 try:
124 if flags & INET_PTON:
125 return _struct.unpack('>I', _inet_pton(AF_INET, addr))[0]
126 else:
127 return _struct.unpack('>I', _inet_aton(addr))[0]
128 except Exception:
129 raise AddrFormatError('%r is not a valid IPv4 address string!' % (addr,))
132def int_to_str(int_val, dialect=None):
133 """
134 :param int_val: An unsigned integer.
136 :param dialect: (unused) Any value passed in is ignored.
138 :return: The IPv4 presentation (string) format address equivalent to the
139 unsigned integer provided.
140 """
141 if 0 <= int_val <= max_int:
142 return '%d.%d.%d.%d' % (
143 int_val >> 24,
144 (int_val >> 16) & 0xff,
145 (int_val >> 8) & 0xff,
146 int_val & 0xff)
147 else:
148 raise ValueError('%r is not a valid 32-bit unsigned integer!' % (int_val,))
151def int_to_arpa(int_val):
152 """
153 :param int_val: An unsigned integer.
155 :return: The reverse DNS lookup for an IPv4 address in network byte
156 order integer form.
157 """
158 words = ["%d" % i for i in int_to_words(int_val)]
159 words.reverse()
160 words.extend(['in-addr', 'arpa', ''])
161 return '.'.join(words)
164def int_to_packed(int_val):
165 """
166 :param int_val: the integer to be packed.
168 :return: a packed string that is equivalent to value represented by an
169 unsigned integer.
170 """
171 return _struct.pack('>I', int_val)
174def packed_to_int(packed_int):
175 """
176 :param packed_int: a packed string containing an unsigned integer.
177 It is assumed that string is packed in network byte order.
179 :return: An unsigned integer equivalent to value of network address
180 represented by packed binary string.
181 """
182 return _struct.unpack('>I', packed_int)[0]
185def valid_words(words):
186 return _valid_words(words, word_size, num_words)
189def int_to_words(int_val):
190 """
191 :param int_val: An unsigned integer.
193 :return: An integer word (octet) sequence that is equivalent to value
194 represented by an unsigned integer.
195 """
196 if not 0 <= int_val <= max_int:
197 raise ValueError('%r is not a valid integer value supported by'
198 'this address type!' % (int_val,))
199 return ( int_val >> 24,
200 (int_val >> 16) & 0xff,
201 (int_val >> 8) & 0xff,
202 int_val & 0xff)
205def words_to_int(words):
206 """
207 :param words: A list or tuple containing integer octets.
209 :return: An unsigned integer that is equivalent to value represented
210 by word (octet) sequence.
211 """
212 if not valid_words(words):
213 raise ValueError('%r is not a valid octet list for an IPv4 address!' % (words,))
214 return _struct.unpack('>I', _struct.pack('4B', *words))[0]
217def valid_bits(bits):
218 return _valid_bits(bits, width, word_sep)
221def bits_to_int(bits):
222 return _bits_to_int(bits, width, word_sep)
225def int_to_bits(int_val, word_sep=None):
226 if word_sep is None:
227 word_sep = globals()['word_sep']
228 return _int_to_bits(int_val, word_size, num_words, word_sep)
231def valid_bin(bin_val):
232 return _valid_bin(bin_val, width)
235def int_to_bin(int_val):
236 return _int_to_bin(int_val, width)
239def bin_to_int(bin_val):
240 return _bin_to_int(bin_val, width)
243def expand_partial_address(addr):
244 """
245 Expands a partial IPv4 address into a full 4-octet version.
247 :param addr: an partial or abbreviated IPv4 address
249 :return: an expanded IP address in presentation format (x.x.x.x)
251 """
252 tokens = []
254 error = AddrFormatError('invalid partial IPv4 address: %r!' % addr)
256 if isinstance(addr, _str_type):
257 if ':' in addr:
258 # Ignore IPv6 ...
259 raise error
261 try:
262 if '.' in addr:
263 tokens = ['%d' % int(o) for o in addr.split('.')]
264 else:
265 tokens = ['%d' % int(addr)]
266 except ValueError:
267 raise error
269 if 1 <= len(tokens) <= 4:
270 for i in range(4 - len(tokens)):
271 tokens.append('0')
272 else:
273 raise error
275 if not tokens:
276 raise error
278 return '%s.%s.%s.%s' % tuple(tokens)