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

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.""" 

7 

8import sys as _sys 

9import struct as _struct 

10 

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 

20 

21from netaddr.core import AddrFormatError, ZEROFILL, INET_PTON 

22 

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) 

28 

29from netaddr.compat import _str_type 

30 

31#: The width (in bits) of this address type. 

32width = 32 

33 

34#: The individual word size (in bits) of this address type. 

35word_size = 8 

36 

37#: The format string to be used when converting words to string values. 

38word_fmt = '%d' 

39 

40#: The separator character used between each word. 

41word_sep = '.' 

42 

43#: The AF_* constant value of this address type. 

44family = AF_INET 

45 

46#: A friendly string name address type. 

47family_name = 'IPv4' 

48 

49#: The version of this address type. 

50version = 4 

51 

52#: The number base to be used when interpreting word values as integers. 

53word_base = 10 

54 

55#: The maximum integer value that can be represented by this address type. 

56max_int = 2 ** width - 1 

57 

58#: The number of words in this address type. 

59num_words = width // word_size 

60 

61#: The maximum integer value for an individual word in this address type. 

62max_word = 2 ** word_size - 1 

63 

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)]) 

67 

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)]) 

71 

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)]) 

75 

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)]) 

79 

80 

81def valid_str(addr, flags=0): 

82 """ 

83 :param addr: An IPv4 address in presentation (string) format. 

84 

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. 

88 

89 :return: ``True`` if IPv4 address is valid, ``False`` otherwise. 

90 """ 

91 if addr == '': 

92 raise AddrFormatError('Empty strings are not supported!') 

93 

94 validity = True 

95 

96 if flags & ZEROFILL: 

97 addr = '.'.join(['%d' % int(i) for i in addr.split('.')]) 

98 

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 

106 

107 return validity 

108 

109 

110def str_to_int(addr, flags=0): 

111 """ 

112 :param addr: An IPv4 dotted decimal address in string form. 

113 

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. 

117 

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('.')]) 

122 

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,)) 

130 

131 

132def int_to_str(int_val, dialect=None): 

133 """ 

134 :param int_val: An unsigned integer. 

135 

136 :param dialect: (unused) Any value passed in is ignored. 

137 

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,)) 

149 

150 

151def int_to_arpa(int_val): 

152 """ 

153 :param int_val: An unsigned integer. 

154 

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) 

162 

163 

164def int_to_packed(int_val): 

165 """ 

166 :param int_val: the integer to be packed. 

167 

168 :return: a packed string that is equivalent to value represented by an 

169 unsigned integer. 

170 """ 

171 return _struct.pack('>I', int_val) 

172 

173 

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. 

178 

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] 

183 

184 

185def valid_words(words): 

186 return _valid_words(words, word_size, num_words) 

187 

188 

189def int_to_words(int_val): 

190 """ 

191 :param int_val: An unsigned integer. 

192 

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) 

203 

204 

205def words_to_int(words): 

206 """ 

207 :param words: A list or tuple containing integer octets. 

208 

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] 

215 

216 

217def valid_bits(bits): 

218 return _valid_bits(bits, width, word_sep) 

219 

220 

221def bits_to_int(bits): 

222 return _bits_to_int(bits, width, word_sep) 

223 

224 

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) 

229 

230 

231def valid_bin(bin_val): 

232 return _valid_bin(bin_val, width) 

233 

234 

235def int_to_bin(int_val): 

236 return _int_to_bin(int_val, width) 

237 

238 

239def bin_to_int(bin_val): 

240 return _bin_to_int(bin_val, width) 

241 

242 

243def expand_partial_address(addr): 

244 """ 

245 Expands a partial IPv4 address into a full 4-octet version. 

246 

247 :param addr: an partial or abbreviated IPv4 address 

248 

249 :return: an expanded IP address in presentation format (x.x.x.x) 

250 

251 """ 

252 tokens = [] 

253 

254 error = AddrFormatError('invalid partial IPv4 address: %r!' % addr) 

255 

256 if isinstance(addr, _str_type): 

257 if ':' in addr: 

258 # Ignore IPv6 ... 

259 raise error 

260 

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 

268 

269 if 1 <= len(tokens) <= 4: 

270 for i in range(4 - len(tokens)): 

271 tokens.append('0') 

272 else: 

273 raise error 

274 

275 if not tokens: 

276 raise error 

277 

278 return '%s.%s.%s.%s' % tuple(tokens) 

279