Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/dns/inet.py: 19%

80 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-02 06:07 +0000

1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 

2 

3# Copyright (C) 2003-2017 Nominum, Inc. 

4# 

5# Permission to use, copy, modify, and distribute this software and its 

6# documentation for any purpose with or without fee is hereby granted, 

7# provided that the above copyright notice and this permission notice 

8# appear in all copies. 

9# 

10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 

11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 

12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 

13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 

14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 

15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 

16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

17 

18"""Generic Internet address helper functions.""" 

19 

20import socket 

21from typing import Any, Optional, Tuple 

22 

23import dns.ipv4 

24import dns.ipv6 

25 

26# We assume that AF_INET and AF_INET6 are always defined. We keep 

27# these here for the benefit of any old code (unlikely though that 

28# is!). 

29AF_INET = socket.AF_INET 

30AF_INET6 = socket.AF_INET6 

31 

32 

33def inet_pton(family: int, text: str) -> bytes: 

34 """Convert the textual form of a network address into its binary form. 

35 

36 *family* is an ``int``, the address family. 

37 

38 *text* is a ``str``, the textual address. 

39 

40 Raises ``NotImplementedError`` if the address family specified is not 

41 implemented. 

42 

43 Returns a ``bytes``. 

44 """ 

45 

46 if family == AF_INET: 

47 return dns.ipv4.inet_aton(text) 

48 elif family == AF_INET6: 

49 return dns.ipv6.inet_aton(text, True) 

50 else: 

51 raise NotImplementedError 

52 

53 

54def inet_ntop(family: int, address: bytes) -> str: 

55 """Convert the binary form of a network address into its textual form. 

56 

57 *family* is an ``int``, the address family. 

58 

59 *address* is a ``bytes``, the network address in binary form. 

60 

61 Raises ``NotImplementedError`` if the address family specified is not 

62 implemented. 

63 

64 Returns a ``str``. 

65 """ 

66 

67 if family == AF_INET: 

68 return dns.ipv4.inet_ntoa(address) 

69 elif family == AF_INET6: 

70 return dns.ipv6.inet_ntoa(address) 

71 else: 

72 raise NotImplementedError 

73 

74 

75def af_for_address(text: str) -> int: 

76 """Determine the address family of a textual-form network address. 

77 

78 *text*, a ``str``, the textual address. 

79 

80 Raises ``ValueError`` if the address family cannot be determined 

81 from the input. 

82 

83 Returns an ``int``. 

84 """ 

85 

86 try: 

87 dns.ipv4.inet_aton(text) 

88 return AF_INET 

89 except Exception: 

90 try: 

91 dns.ipv6.inet_aton(text, True) 

92 return AF_INET6 

93 except Exception: 

94 raise ValueError 

95 

96 

97def is_multicast(text: str) -> bool: 

98 """Is the textual-form network address a multicast address? 

99 

100 *text*, a ``str``, the textual address. 

101 

102 Raises ``ValueError`` if the address family cannot be determined 

103 from the input. 

104 

105 Returns a ``bool``. 

106 """ 

107 

108 try: 

109 first = dns.ipv4.inet_aton(text)[0] 

110 return first >= 224 and first <= 239 

111 except Exception: 

112 try: 

113 first = dns.ipv6.inet_aton(text, True)[0] 

114 return first == 255 

115 except Exception: 

116 raise ValueError 

117 

118 

119def is_address(text: str) -> bool: 

120 """Is the specified string an IPv4 or IPv6 address? 

121 

122 *text*, a ``str``, the textual address. 

123 

124 Returns a ``bool``. 

125 """ 

126 

127 try: 

128 dns.ipv4.inet_aton(text) 

129 return True 

130 except Exception: 

131 try: 

132 dns.ipv6.inet_aton(text, True) 

133 return True 

134 except Exception: 

135 return False 

136 

137 

138def low_level_address_tuple( 

139 high_tuple: Tuple[str, int], af: Optional[int] = None 

140) -> Any: 

141 """Given a "high-level" address tuple, i.e. 

142 an (address, port) return the appropriate "low-level" address tuple 

143 suitable for use in socket calls. 

144 

145 If an *af* other than ``None`` is provided, it is assumed the 

146 address in the high-level tuple is valid and has that af. If af 

147 is ``None``, then af_for_address will be called. 

148 """ 

149 address, port = high_tuple 

150 if af is None: 

151 af = af_for_address(address) 

152 if af == AF_INET: 

153 return (address, port) 

154 elif af == AF_INET6: 

155 i = address.find("%") 

156 if i < 0: 

157 # no scope, shortcut! 

158 return (address, port, 0, 0) 

159 # try to avoid getaddrinfo() 

160 addrpart = address[:i] 

161 scope = address[i + 1 :] 

162 if scope.isdigit(): 

163 return (addrpart, port, 0, int(scope)) 

164 try: 

165 return (addrpart, port, 0, socket.if_nametoindex(scope)) 

166 except AttributeError: # pragma: no cover (we can't really test this) 

167 ai_flags = socket.AI_NUMERICHOST 

168 ((*_, tup), *_) = socket.getaddrinfo(address, port, flags=ai_flags) 

169 return tup 

170 else: 

171 raise NotImplementedError(f"unknown address family {af}") 

172 

173 

174def any_for_af(af): 

175 """Return the 'any' address for the specified address family.""" 

176 if af == socket.AF_INET: 

177 return "0.0.0.0" 

178 elif af == socket.AF_INET6: 

179 return "::" 

180 raise NotImplementedError(f"unknown address family {af}") 

181 

182 

183def canonicalize(text: str) -> str: 

184 """Verify that *address* is a valid text form IPv4 or IPv6 address and return its 

185 canonical text form. IPv6 addresses with scopes are rejected. 

186 

187 *text*, a ``str``, the address in textual form. 

188 

189 Raises ``ValueError`` if the text is not valid. 

190 """ 

191 try: 

192 return dns.ipv6.canonicalize(text) 

193 except Exception: 

194 try: 

195 return dns.ipv4.canonicalize(text) 

196 except Exception: 

197 raise ValueError