root / lib / netutils.py @ b43dcc5a
History | View | Annotate | Download (13.1 kB)
1 | a744b676 | Manuel Franceschini | #
|
---|---|---|---|
2 | a744b676 | Manuel Franceschini | #
|
3 | a744b676 | Manuel Franceschini | |
4 | a744b676 | Manuel Franceschini | # Copyright (C) 2010 Google Inc.
|
5 | a744b676 | Manuel Franceschini | #
|
6 | a744b676 | Manuel Franceschini | # This program is free software; you can redistribute it and/or modify
|
7 | a744b676 | Manuel Franceschini | # it under the terms of the GNU General Public License as published by
|
8 | a744b676 | Manuel Franceschini | # the Free Software Foundation; either version 2 of the License, or
|
9 | a744b676 | Manuel Franceschini | # (at your option) any later version.
|
10 | a744b676 | Manuel Franceschini | #
|
11 | a744b676 | Manuel Franceschini | # This program is distributed in the hope that it will be useful, but
|
12 | a744b676 | Manuel Franceschini | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | a744b676 | Manuel Franceschini | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | a744b676 | Manuel Franceschini | # General Public License for more details.
|
15 | a744b676 | Manuel Franceschini | #
|
16 | a744b676 | Manuel Franceschini | # You should have received a copy of the GNU General Public License
|
17 | a744b676 | Manuel Franceschini | # along with this program; if not, write to the Free Software
|
18 | a744b676 | Manuel Franceschini | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | a744b676 | Manuel Franceschini | # 02110-1301, USA.
|
20 | a744b676 | Manuel Franceschini | |
21 | a744b676 | Manuel Franceschini | |
22 | a744b676 | Manuel Franceschini | """Ganeti network utility module.
|
23 | a744b676 | Manuel Franceschini |
|
24 | a744b676 | Manuel Franceschini | This module holds functions that can be used in both daemons (all) and
|
25 | a744b676 | Manuel Franceschini | the command line scripts.
|
26 | a744b676 | Manuel Franceschini |
|
27 | a744b676 | Manuel Franceschini | """
|
28 | a744b676 | Manuel Franceschini | |
29 | a744b676 | Manuel Franceschini | |
30 | a744b676 | Manuel Franceschini | import errno |
31 | a744b676 | Manuel Franceschini | import re |
32 | a744b676 | Manuel Franceschini | import socket |
33 | a744b676 | Manuel Franceschini | import struct |
34 | a744b676 | Manuel Franceschini | import IN |
35 | a744b676 | Manuel Franceschini | |
36 | a744b676 | Manuel Franceschini | from ganeti import constants |
37 | a744b676 | Manuel Franceschini | from ganeti import errors |
38 | a744b676 | Manuel Franceschini | |
39 | a744b676 | Manuel Franceschini | # Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...):
|
40 | a744b676 | Manuel Franceschini | # struct ucred { pid_t pid; uid_t uid; gid_t gid; };
|
41 | a744b676 | Manuel Franceschini | #
|
42 | a744b676 | Manuel Franceschini | # The GNU C Library defines gid_t and uid_t to be "unsigned int" and
|
43 | a744b676 | Manuel Franceschini | # pid_t to "int".
|
44 | a744b676 | Manuel Franceschini | #
|
45 | a744b676 | Manuel Franceschini | # IEEE Std 1003.1-2008:
|
46 | a744b676 | Manuel Franceschini | # "nlink_t, uid_t, gid_t, and id_t shall be integer types"
|
47 | a744b676 | Manuel Franceschini | # "blksize_t, pid_t, and ssize_t shall be signed integer types"
|
48 | a744b676 | Manuel Franceschini | _STRUCT_UCRED = "iII"
|
49 | a744b676 | Manuel Franceschini | _STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED) |
50 | a744b676 | Manuel Franceschini | |
51 | a744b676 | Manuel Franceschini | |
52 | a744b676 | Manuel Franceschini | def GetSocketCredentials(sock): |
53 | a744b676 | Manuel Franceschini | """Returns the credentials of the foreign process connected to a socket.
|
54 | a744b676 | Manuel Franceschini |
|
55 | a744b676 | Manuel Franceschini | @param sock: Unix socket
|
56 | a744b676 | Manuel Franceschini | @rtype: tuple; (number, number, number)
|
57 | a744b676 | Manuel Franceschini | @return: The PID, UID and GID of the connected foreign process.
|
58 | a744b676 | Manuel Franceschini |
|
59 | a744b676 | Manuel Franceschini | """
|
60 | a744b676 | Manuel Franceschini | peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED, |
61 | a744b676 | Manuel Franceschini | _STRUCT_UCRED_SIZE) |
62 | a744b676 | Manuel Franceschini | return struct.unpack(_STRUCT_UCRED, peercred)
|
63 | a744b676 | Manuel Franceschini | |
64 | a744b676 | Manuel Franceschini | |
65 | b705c7a6 | Manuel Franceschini | def GetHostname(name=None, family=None): |
66 | b705c7a6 | Manuel Franceschini | """Returns a Hostname object.
|
67 | a744b676 | Manuel Franceschini |
|
68 | b705c7a6 | Manuel Franceschini | @type name: str
|
69 | b705c7a6 | Manuel Franceschini | @param name: hostname or None
|
70 | b705c7a6 | Manuel Franceschini | @type family: int
|
71 | b705c7a6 | Manuel Franceschini | @param family: AF_INET | AF_INET6 | None
|
72 | b705c7a6 | Manuel Franceschini | @rtype: L{Hostname}
|
73 | b705c7a6 | Manuel Franceschini | @return: Hostname object
|
74 | b705c7a6 | Manuel Franceschini | @raise: errors.OpPrereqError
|
75 | b705c7a6 | Manuel Franceschini |
|
76 | b705c7a6 | Manuel Franceschini | """
|
77 | a744b676 | Manuel Franceschini | try:
|
78 | b705c7a6 | Manuel Franceschini | return Hostname(name=name, family=family)
|
79 | a744b676 | Manuel Franceschini | except errors.ResolverError, err:
|
80 | a744b676 | Manuel Franceschini | raise errors.OpPrereqError("The given name (%s) does not resolve: %s" % |
81 | a744b676 | Manuel Franceschini | (err[0], err[2]), errors.ECODE_RESOLVER) |
82 | a744b676 | Manuel Franceschini | |
83 | a744b676 | Manuel Franceschini | |
84 | b705c7a6 | Manuel Franceschini | class Hostname: |
85 | b705c7a6 | Manuel Franceschini | """Class implementing resolver and hostname functionality.
|
86 | a744b676 | Manuel Franceschini |
|
87 | a744b676 | Manuel Franceschini | """
|
88 | e7b3ad26 | Manuel Franceschini | _VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$")
|
89 | e7b3ad26 | Manuel Franceschini | |
90 | b705c7a6 | Manuel Franceschini | def __init__(self, name=None, family=None): |
91 | a744b676 | Manuel Franceschini | """Initialize the host name object.
|
92 | a744b676 | Manuel Franceschini |
|
93 | b705c7a6 | Manuel Franceschini | If the name argument is None, it will use this system's name.
|
94 | b705c7a6 | Manuel Franceschini |
|
95 | b705c7a6 | Manuel Franceschini | @type family: int
|
96 | b705c7a6 | Manuel Franceschini | @param family: AF_INET | AF_INET6 | None
|
97 | b705c7a6 | Manuel Franceschini | @type name: str
|
98 | b705c7a6 | Manuel Franceschini | @param name: hostname or None
|
99 | a744b676 | Manuel Franceschini |
|
100 | a744b676 | Manuel Franceschini | """
|
101 | a744b676 | Manuel Franceschini | if name is None: |
102 | b705c7a6 | Manuel Franceschini | name = self.GetSysName()
|
103 | a744b676 | Manuel Franceschini | |
104 | b705c7a6 | Manuel Franceschini | self.name = self.GetNormalizedName(name) |
105 | b705c7a6 | Manuel Franceschini | self.ip = self.GetIP(self.name, family=family) |
106 | a744b676 | Manuel Franceschini | |
107 | a744b676 | Manuel Franceschini | @staticmethod
|
108 | b705c7a6 | Manuel Franceschini | def GetSysName(): |
109 | a744b676 | Manuel Franceschini | """Return the current system's name.
|
110 | a744b676 | Manuel Franceschini |
|
111 | a744b676 | Manuel Franceschini | This is simply a wrapper over C{socket.gethostname()}.
|
112 | a744b676 | Manuel Franceschini |
|
113 | a744b676 | Manuel Franceschini | """
|
114 | a744b676 | Manuel Franceschini | return socket.gethostname()
|
115 | a744b676 | Manuel Franceschini | |
116 | a744b676 | Manuel Franceschini | @staticmethod
|
117 | b705c7a6 | Manuel Franceschini | def GetIP(hostname, family=None): |
118 | b705c7a6 | Manuel Franceschini | """Return IP address of given hostname.
|
119 | b705c7a6 | Manuel Franceschini |
|
120 | b705c7a6 | Manuel Franceschini | Supports both IPv4 and IPv6.
|
121 | a744b676 | Manuel Franceschini |
|
122 | a744b676 | Manuel Franceschini | @type hostname: str
|
123 | a744b676 | Manuel Franceschini | @param hostname: hostname to look up
|
124 | b705c7a6 | Manuel Franceschini | @type family: int
|
125 | b705c7a6 | Manuel Franceschini | @param family: AF_INET | AF_INET6 | None
|
126 | b705c7a6 | Manuel Franceschini | @rtype: str
|
127 | b705c7a6 | Manuel Franceschini | @return: IP address
|
128 | a744b676 | Manuel Franceschini | @raise errors.ResolverError: in case of errors in resolving
|
129 | a744b676 | Manuel Franceschini |
|
130 | a744b676 | Manuel Franceschini | """
|
131 | a744b676 | Manuel Franceschini | try:
|
132 | b705c7a6 | Manuel Franceschini | if family in (socket.AF_INET, socket.AF_INET6): |
133 | b705c7a6 | Manuel Franceschini | result = socket.getaddrinfo(hostname, None, family)
|
134 | b705c7a6 | Manuel Franceschini | else:
|
135 | b43dcc5a | Manuel Franceschini | result = socket.getaddrinfo(hostname, None)
|
136 | a744b676 | Manuel Franceschini | except (socket.gaierror, socket.herror, socket.error), err:
|
137 | a744b676 | Manuel Franceschini | # hostname not found in DNS, or other socket exception in the
|
138 | a744b676 | Manuel Franceschini | # (code, description format)
|
139 | a744b676 | Manuel Franceschini | raise errors.ResolverError(hostname, err.args[0], err.args[1]) |
140 | a744b676 | Manuel Franceschini | |
141 | b705c7a6 | Manuel Franceschini | # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
|
142 | b705c7a6 | Manuel Franceschini | # canonname, sockaddr). We return the first tuple's first address in
|
143 | b705c7a6 | Manuel Franceschini | # sockaddr
|
144 | e7b3ad26 | Manuel Franceschini | try:
|
145 | e7b3ad26 | Manuel Franceschini | return result[0][4][0] |
146 | e7b3ad26 | Manuel Franceschini | except IndexError, err: |
147 | e7b3ad26 | Manuel Franceschini | raise errors.ResolverError("Unknown error in getaddrinfo(): %s" % err) |
148 | a744b676 | Manuel Franceschini | |
149 | e7b3ad26 | Manuel Franceschini | @classmethod
|
150 | e7b3ad26 | Manuel Franceschini | def GetNormalizedName(cls, hostname): |
151 | a744b676 | Manuel Franceschini | """Validate and normalize the given hostname.
|
152 | a744b676 | Manuel Franceschini |
|
153 | a744b676 | Manuel Franceschini | @attention: the validation is a bit more relaxed than the standards
|
154 | a744b676 | Manuel Franceschini | require; most importantly, we allow underscores in names
|
155 | a744b676 | Manuel Franceschini | @raise errors.OpPrereqError: when the name is not valid
|
156 | a744b676 | Manuel Franceschini |
|
157 | a744b676 | Manuel Franceschini | """
|
158 | a744b676 | Manuel Franceschini | hostname = hostname.lower() |
159 | e7b3ad26 | Manuel Franceschini | if (not cls._VALID_NAME_RE.match(hostname) or |
160 | a744b676 | Manuel Franceschini | # double-dots, meaning empty label
|
161 | a744b676 | Manuel Franceschini | ".." in hostname or |
162 | a744b676 | Manuel Franceschini | # empty initial label
|
163 | a744b676 | Manuel Franceschini | hostname.startswith(".")):
|
164 | a744b676 | Manuel Franceschini | raise errors.OpPrereqError("Invalid hostname '%s'" % hostname, |
165 | a744b676 | Manuel Franceschini | errors.ECODE_INVAL) |
166 | a744b676 | Manuel Franceschini | if hostname.endswith("."): |
167 | a744b676 | Manuel Franceschini | hostname = hostname.rstrip(".")
|
168 | a744b676 | Manuel Franceschini | return hostname
|
169 | a744b676 | Manuel Franceschini | |
170 | a744b676 | Manuel Franceschini | |
171 | a744b676 | Manuel Franceschini | def TcpPing(target, port, timeout=10, live_port_needed=False, source=None): |
172 | a744b676 | Manuel Franceschini | """Simple ping implementation using TCP connect(2).
|
173 | a744b676 | Manuel Franceschini |
|
174 | a744b676 | Manuel Franceschini | Check if the given IP is reachable by doing attempting a TCP connect
|
175 | a744b676 | Manuel Franceschini | to it.
|
176 | a744b676 | Manuel Franceschini |
|
177 | a744b676 | Manuel Franceschini | @type target: str
|
178 | a744b676 | Manuel Franceschini | @param target: the IP or hostname to ping
|
179 | a744b676 | Manuel Franceschini | @type port: int
|
180 | a744b676 | Manuel Franceschini | @param port: the port to connect to
|
181 | a744b676 | Manuel Franceschini | @type timeout: int
|
182 | a744b676 | Manuel Franceschini | @param timeout: the timeout on the connection attempt
|
183 | a744b676 | Manuel Franceschini | @type live_port_needed: boolean
|
184 | a744b676 | Manuel Franceschini | @param live_port_needed: whether a closed port will cause the
|
185 | a744b676 | Manuel Franceschini | function to return failure, as if there was a timeout
|
186 | a744b676 | Manuel Franceschini | @type source: str or None
|
187 | a744b676 | Manuel Franceschini | @param source: if specified, will cause the connect to be made
|
188 | a744b676 | Manuel Franceschini | from this specific source address; failures to bind other
|
189 | a744b676 | Manuel Franceschini | than C{EADDRNOTAVAIL} will be ignored
|
190 | a744b676 | Manuel Franceschini |
|
191 | a744b676 | Manuel Franceschini | """
|
192 | a744b676 | Manuel Franceschini | try:
|
193 | 8b312c1d | Manuel Franceschini | family = IPAddress.GetAddressFamily(target) |
194 | a744b676 | Manuel Franceschini | except errors.GenericError:
|
195 | a744b676 | Manuel Franceschini | return False |
196 | a744b676 | Manuel Franceschini | |
197 | a744b676 | Manuel Franceschini | sock = socket.socket(family, socket.SOCK_STREAM) |
198 | a744b676 | Manuel Franceschini | success = False
|
199 | a744b676 | Manuel Franceschini | |
200 | a744b676 | Manuel Franceschini | if source is not None: |
201 | a744b676 | Manuel Franceschini | try:
|
202 | a744b676 | Manuel Franceschini | sock.bind((source, 0))
|
203 | a744b676 | Manuel Franceschini | except socket.error, (errcode, _):
|
204 | a744b676 | Manuel Franceschini | if errcode == errno.EADDRNOTAVAIL:
|
205 | a744b676 | Manuel Franceschini | success = False
|
206 | a744b676 | Manuel Franceschini | |
207 | a744b676 | Manuel Franceschini | sock.settimeout(timeout) |
208 | a744b676 | Manuel Franceschini | |
209 | a744b676 | Manuel Franceschini | try:
|
210 | a744b676 | Manuel Franceschini | sock.connect((target, port)) |
211 | a744b676 | Manuel Franceschini | sock.close() |
212 | a744b676 | Manuel Franceschini | success = True
|
213 | a744b676 | Manuel Franceschini | except socket.timeout:
|
214 | a744b676 | Manuel Franceschini | success = False
|
215 | a744b676 | Manuel Franceschini | except socket.error, (errcode, _):
|
216 | a744b676 | Manuel Franceschini | success = (not live_port_needed) and (errcode == errno.ECONNREFUSED) |
217 | a744b676 | Manuel Franceschini | |
218 | a744b676 | Manuel Franceschini | return success
|
219 | a744b676 | Manuel Franceschini | |
220 | a744b676 | Manuel Franceschini | |
221 | a744b676 | Manuel Franceschini | def GetDaemonPort(daemon_name): |
222 | a744b676 | Manuel Franceschini | """Get the daemon port for this cluster.
|
223 | a744b676 | Manuel Franceschini |
|
224 | a744b676 | Manuel Franceschini | Note that this routine does not read a ganeti-specific file, but
|
225 | a744b676 | Manuel Franceschini | instead uses C{socket.getservbyname} to allow pre-customization of
|
226 | a744b676 | Manuel Franceschini | this parameter outside of Ganeti.
|
227 | a744b676 | Manuel Franceschini |
|
228 | a744b676 | Manuel Franceschini | @type daemon_name: string
|
229 | a744b676 | Manuel Franceschini | @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
|
230 | a744b676 | Manuel Franceschini | @rtype: int
|
231 | a744b676 | Manuel Franceschini |
|
232 | a744b676 | Manuel Franceschini | """
|
233 | a744b676 | Manuel Franceschini | if daemon_name not in constants.DAEMONS_PORTS: |
234 | a744b676 | Manuel Franceschini | raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name) |
235 | a744b676 | Manuel Franceschini | |
236 | a744b676 | Manuel Franceschini | (proto, default_port) = constants.DAEMONS_PORTS[daemon_name] |
237 | a744b676 | Manuel Franceschini | try:
|
238 | a744b676 | Manuel Franceschini | port = socket.getservbyname(daemon_name, proto) |
239 | a744b676 | Manuel Franceschini | except socket.error:
|
240 | a744b676 | Manuel Franceschini | port = default_port |
241 | a744b676 | Manuel Franceschini | |
242 | a744b676 | Manuel Franceschini | return port
|
243 | 8b312c1d | Manuel Franceschini | |
244 | 8b312c1d | Manuel Franceschini | |
245 | 8b312c1d | Manuel Franceschini | class IPAddress(object): |
246 | 8b312c1d | Manuel Franceschini | """Class that represents an IP address.
|
247 | 8b312c1d | Manuel Franceschini |
|
248 | 8b312c1d | Manuel Franceschini | """
|
249 | 8b312c1d | Manuel Franceschini | iplen = 0
|
250 | 8b312c1d | Manuel Franceschini | family = None
|
251 | 8b312c1d | Manuel Franceschini | loopback_cidr = None
|
252 | 8b312c1d | Manuel Franceschini | |
253 | 8b312c1d | Manuel Franceschini | @staticmethod
|
254 | 8b312c1d | Manuel Franceschini | def _GetIPIntFromString(address): |
255 | 8b312c1d | Manuel Franceschini | """Abstract method to please pylint.
|
256 | 8b312c1d | Manuel Franceschini |
|
257 | 8b312c1d | Manuel Franceschini | """
|
258 | 8b312c1d | Manuel Franceschini | raise NotImplementedError |
259 | 8b312c1d | Manuel Franceschini | |
260 | 8b312c1d | Manuel Franceschini | @classmethod
|
261 | 8b312c1d | Manuel Franceschini | def IsValid(cls, address): |
262 | 8b312c1d | Manuel Franceschini | """Validate a IP address.
|
263 | 8b312c1d | Manuel Franceschini |
|
264 | 8b312c1d | Manuel Franceschini | @type address: str
|
265 | 8b312c1d | Manuel Franceschini | @param address: IP address to be checked
|
266 | 8b312c1d | Manuel Franceschini | @rtype: bool
|
267 | 8b312c1d | Manuel Franceschini | @return: True if valid, False otherwise
|
268 | 8b312c1d | Manuel Franceschini |
|
269 | 8b312c1d | Manuel Franceschini | """
|
270 | 8b312c1d | Manuel Franceschini | if cls.family is None: |
271 | 8b312c1d | Manuel Franceschini | try:
|
272 | 8b312c1d | Manuel Franceschini | family = cls.GetAddressFamily(address) |
273 | 8b312c1d | Manuel Franceschini | except errors.IPAddressError:
|
274 | 8b312c1d | Manuel Franceschini | return False |
275 | 8b312c1d | Manuel Franceschini | else:
|
276 | 8b312c1d | Manuel Franceschini | family = cls.family |
277 | 8b312c1d | Manuel Franceschini | |
278 | 8b312c1d | Manuel Franceschini | try:
|
279 | 8b312c1d | Manuel Franceschini | socket.inet_pton(family, address) |
280 | 8b312c1d | Manuel Franceschini | return True |
281 | 8b312c1d | Manuel Franceschini | except socket.error:
|
282 | 8b312c1d | Manuel Franceschini | return False |
283 | 8b312c1d | Manuel Franceschini | |
284 | 8b312c1d | Manuel Franceschini | @classmethod
|
285 | 8b312c1d | Manuel Franceschini | def Own(cls, address): |
286 | 8b312c1d | Manuel Franceschini | """Check if the current host has the the given IP address.
|
287 | 8b312c1d | Manuel Franceschini |
|
288 | 8b312c1d | Manuel Franceschini | This is done by trying to bind the given address. We return True if we
|
289 | 8b312c1d | Manuel Franceschini | succeed or false if a socket.error is raised.
|
290 | 8b312c1d | Manuel Franceschini |
|
291 | 8b312c1d | Manuel Franceschini | @type address: str
|
292 | 8b312c1d | Manuel Franceschini | @param address: IP address to be checked
|
293 | 8b312c1d | Manuel Franceschini | @rtype: bool
|
294 | 8b312c1d | Manuel Franceschini | @return: True if we own the address, False otherwise
|
295 | 8b312c1d | Manuel Franceschini |
|
296 | 8b312c1d | Manuel Franceschini | """
|
297 | 8b312c1d | Manuel Franceschini | if cls.family is None: |
298 | 8b312c1d | Manuel Franceschini | try:
|
299 | 8b312c1d | Manuel Franceschini | family = cls.GetAddressFamily(address) |
300 | 8b312c1d | Manuel Franceschini | except errors.IPAddressError:
|
301 | 8b312c1d | Manuel Franceschini | return False |
302 | 8b312c1d | Manuel Franceschini | else:
|
303 | 8b312c1d | Manuel Franceschini | family = cls.family |
304 | 8b312c1d | Manuel Franceschini | |
305 | 8b312c1d | Manuel Franceschini | s = socket.socket(family, socket.SOCK_DGRAM) |
306 | 8b312c1d | Manuel Franceschini | success = False
|
307 | 8b312c1d | Manuel Franceschini | try:
|
308 | 8b312c1d | Manuel Franceschini | try:
|
309 | 8b312c1d | Manuel Franceschini | s.bind((address, 0))
|
310 | 8b312c1d | Manuel Franceschini | success = True
|
311 | 8b312c1d | Manuel Franceschini | except socket.error:
|
312 | 8b312c1d | Manuel Franceschini | success = False
|
313 | 8b312c1d | Manuel Franceschini | finally:
|
314 | 8b312c1d | Manuel Franceschini | s.close() |
315 | 8b312c1d | Manuel Franceschini | return success
|
316 | 8b312c1d | Manuel Franceschini | |
317 | 8b312c1d | Manuel Franceschini | @classmethod
|
318 | 8b312c1d | Manuel Franceschini | def InNetwork(cls, cidr, address): |
319 | 8b312c1d | Manuel Franceschini | """Determine whether an address is within a network.
|
320 | 8b312c1d | Manuel Franceschini |
|
321 | 8b312c1d | Manuel Franceschini | @type cidr: string
|
322 | 8b312c1d | Manuel Franceschini | @param cidr: Network in CIDR notation, e.g. '192.0.2.0/24', '2001:db8::/64'
|
323 | 8b312c1d | Manuel Franceschini | @type address: str
|
324 | 8b312c1d | Manuel Franceschini | @param address: IP address
|
325 | 8b312c1d | Manuel Franceschini | @rtype: bool
|
326 | 8b312c1d | Manuel Franceschini | @return: True if address is in cidr, False otherwise
|
327 | 8b312c1d | Manuel Franceschini |
|
328 | 8b312c1d | Manuel Franceschini | """
|
329 | 8b312c1d | Manuel Franceschini | address_int = cls._GetIPIntFromString(address) |
330 | 8b312c1d | Manuel Franceschini | subnet = cidr.split("/")
|
331 | 8b312c1d | Manuel Franceschini | assert len(subnet) == 2 |
332 | 8b312c1d | Manuel Franceschini | try:
|
333 | 8b312c1d | Manuel Franceschini | prefix = int(subnet[1]) |
334 | 8b312c1d | Manuel Franceschini | except ValueError: |
335 | 8b312c1d | Manuel Franceschini | return False |
336 | 8b312c1d | Manuel Franceschini | |
337 | 8b312c1d | Manuel Franceschini | assert 0 <= prefix <= cls.iplen |
338 | 8b312c1d | Manuel Franceschini | target_int = cls._GetIPIntFromString(subnet[0])
|
339 | 8b312c1d | Manuel Franceschini | # Convert prefix netmask to integer value of netmask
|
340 | 8b312c1d | Manuel Franceschini | netmask_int = (2**cls.iplen)-1 ^ ((2**cls.iplen)-1 >> prefix) |
341 | 8b312c1d | Manuel Franceschini | # Calculate hostmask
|
342 | 8b312c1d | Manuel Franceschini | hostmask_int = netmask_int ^ (2**cls.iplen)-1 |
343 | 8b312c1d | Manuel Franceschini | # Calculate network address by and'ing netmask
|
344 | 8b312c1d | Manuel Franceschini | network_int = target_int & netmask_int |
345 | 8b312c1d | Manuel Franceschini | # Calculate broadcast address by or'ing hostmask
|
346 | 8b312c1d | Manuel Franceschini | broadcast_int = target_int | hostmask_int |
347 | 8b312c1d | Manuel Franceschini | |
348 | 8b312c1d | Manuel Franceschini | return network_int <= address_int <= broadcast_int
|
349 | 8b312c1d | Manuel Franceschini | |
350 | 8b312c1d | Manuel Franceschini | @staticmethod
|
351 | 8b312c1d | Manuel Franceschini | def GetAddressFamily(address): |
352 | 8b312c1d | Manuel Franceschini | """Get the address family of the given address.
|
353 | 8b312c1d | Manuel Franceschini |
|
354 | 8b312c1d | Manuel Franceschini | @type address: str
|
355 | 8b312c1d | Manuel Franceschini | @param address: ip address whose family will be returned
|
356 | 8b312c1d | Manuel Franceschini | @rtype: int
|
357 | 8b312c1d | Manuel Franceschini | @return: socket.AF_INET or socket.AF_INET6
|
358 | 8b312c1d | Manuel Franceschini | @raise errors.GenericError: for invalid addresses
|
359 | 8b312c1d | Manuel Franceschini |
|
360 | 8b312c1d | Manuel Franceschini | """
|
361 | 8b312c1d | Manuel Franceschini | try:
|
362 | 8b312c1d | Manuel Franceschini | return IP4Address(address).family
|
363 | 8b312c1d | Manuel Franceschini | except errors.IPAddressError:
|
364 | 8b312c1d | Manuel Franceschini | pass
|
365 | 8b312c1d | Manuel Franceschini | |
366 | 8b312c1d | Manuel Franceschini | try:
|
367 | 8b312c1d | Manuel Franceschini | return IP6Address(address).family
|
368 | 8b312c1d | Manuel Franceschini | except errors.IPAddressError:
|
369 | 8b312c1d | Manuel Franceschini | pass
|
370 | 8b312c1d | Manuel Franceschini | |
371 | 8b312c1d | Manuel Franceschini | raise errors.IPAddressError("Invalid address '%s'" % address) |
372 | 8b312c1d | Manuel Franceschini | |
373 | 8b312c1d | Manuel Franceschini | @classmethod
|
374 | 8b312c1d | Manuel Franceschini | def IsLoopback(cls, address): |
375 | 8b312c1d | Manuel Franceschini | """Determine whether it is a loopback address.
|
376 | 8b312c1d | Manuel Franceschini |
|
377 | 8b312c1d | Manuel Franceschini | @type address: str
|
378 | 8b312c1d | Manuel Franceschini | @param address: IP address to be checked
|
379 | 8b312c1d | Manuel Franceschini | @rtype: bool
|
380 | 8b312c1d | Manuel Franceschini | @return: True if loopback, False otherwise
|
381 | 8b312c1d | Manuel Franceschini |
|
382 | 8b312c1d | Manuel Franceschini | """
|
383 | 8b312c1d | Manuel Franceschini | try:
|
384 | 8b312c1d | Manuel Franceschini | return cls.InNetwork(cls.loopback_cidr, address)
|
385 | 8b312c1d | Manuel Franceschini | except errors.IPAddressError:
|
386 | 8b312c1d | Manuel Franceschini | return False |
387 | 8b312c1d | Manuel Franceschini | |
388 | 8b312c1d | Manuel Franceschini | |
389 | 8b312c1d | Manuel Franceschini | class IP4Address(IPAddress): |
390 | 8b312c1d | Manuel Franceschini | """IPv4 address class.
|
391 | 8b312c1d | Manuel Franceschini |
|
392 | 8b312c1d | Manuel Franceschini | """
|
393 | 8b312c1d | Manuel Franceschini | iplen = 32
|
394 | 8b312c1d | Manuel Franceschini | family = socket.AF_INET |
395 | 8b312c1d | Manuel Franceschini | loopback_cidr = "127.0.0.0/8"
|
396 | 8b312c1d | Manuel Franceschini | |
397 | 8b312c1d | Manuel Franceschini | def __init__(self, address): |
398 | 8b312c1d | Manuel Franceschini | """Constructor for IPv4 address.
|
399 | 8b312c1d | Manuel Franceschini |
|
400 | 8b312c1d | Manuel Franceschini | @type address: str
|
401 | 8b312c1d | Manuel Franceschini | @param address: IP address
|
402 | 8b312c1d | Manuel Franceschini | @raises errors.IPAddressError: if address invalid
|
403 | 8b312c1d | Manuel Franceschini |
|
404 | 8b312c1d | Manuel Franceschini | """
|
405 | 8b312c1d | Manuel Franceschini | IPAddress.__init__(self)
|
406 | 8b312c1d | Manuel Franceschini | if not self.IsValid(address): |
407 | 8b312c1d | Manuel Franceschini | raise errors.IPAddressError("IPv4 Address %s invalid" % address) |
408 | 8b312c1d | Manuel Franceschini | |
409 | 8b312c1d | Manuel Franceschini | self.address = address
|
410 | 8b312c1d | Manuel Franceschini | |
411 | 8b312c1d | Manuel Franceschini | @staticmethod
|
412 | 8b312c1d | Manuel Franceschini | def _GetIPIntFromString(address): |
413 | 8b312c1d | Manuel Franceschini | """Get integer value of IPv4 address.
|
414 | 8b312c1d | Manuel Franceschini |
|
415 | 8b312c1d | Manuel Franceschini | @type address: str
|
416 | 8b312c1d | Manuel Franceschini | @param: IPv6 address
|
417 | 8b312c1d | Manuel Franceschini | @rtype: int
|
418 | 8b312c1d | Manuel Franceschini | @return: integer value of given IP address
|
419 | 8b312c1d | Manuel Franceschini |
|
420 | 8b312c1d | Manuel Franceschini | """
|
421 | 8b312c1d | Manuel Franceschini | address_int = 0
|
422 | 8b312c1d | Manuel Franceschini | parts = address.split(".")
|
423 | 8b312c1d | Manuel Franceschini | assert len(parts) == 4 |
424 | 8b312c1d | Manuel Franceschini | for part in parts: |
425 | 8b312c1d | Manuel Franceschini | address_int = (address_int << 8) | int(part) |
426 | 8b312c1d | Manuel Franceschini | |
427 | 8b312c1d | Manuel Franceschini | return address_int
|
428 | 8b312c1d | Manuel Franceschini | |
429 | 8b312c1d | Manuel Franceschini | |
430 | 8b312c1d | Manuel Franceschini | class IP6Address(IPAddress): |
431 | 8b312c1d | Manuel Franceschini | """IPv6 address class.
|
432 | 8b312c1d | Manuel Franceschini |
|
433 | 8b312c1d | Manuel Franceschini | """
|
434 | 8b312c1d | Manuel Franceschini | iplen = 128
|
435 | 8b312c1d | Manuel Franceschini | family = socket.AF_INET6 |
436 | 8b312c1d | Manuel Franceschini | loopback_cidr = "::1/128"
|
437 | 8b312c1d | Manuel Franceschini | |
438 | 8b312c1d | Manuel Franceschini | def __init__(self, address): |
439 | 8b312c1d | Manuel Franceschini | """Constructor for IPv6 address.
|
440 | 8b312c1d | Manuel Franceschini |
|
441 | 8b312c1d | Manuel Franceschini | @type address: str
|
442 | 8b312c1d | Manuel Franceschini | @param address: IP address
|
443 | 8b312c1d | Manuel Franceschini | @raises errors.IPAddressError: if address invalid
|
444 | 8b312c1d | Manuel Franceschini |
|
445 | 8b312c1d | Manuel Franceschini | """
|
446 | 8b312c1d | Manuel Franceschini | IPAddress.__init__(self)
|
447 | 8b312c1d | Manuel Franceschini | if not self.IsValid(address): |
448 | 8b312c1d | Manuel Franceschini | raise errors.IPAddressError("IPv6 Address [%s] invalid" % address) |
449 | 8b312c1d | Manuel Franceschini | self.address = address
|
450 | 8b312c1d | Manuel Franceschini | |
451 | 8b312c1d | Manuel Franceschini | @staticmethod
|
452 | 8b312c1d | Manuel Franceschini | def _GetIPIntFromString(address): |
453 | 8b312c1d | Manuel Franceschini | """Get integer value of IPv6 address.
|
454 | 8b312c1d | Manuel Franceschini |
|
455 | 8b312c1d | Manuel Franceschini | @type address: str
|
456 | 8b312c1d | Manuel Franceschini | @param: IPv6 address
|
457 | 8b312c1d | Manuel Franceschini | @rtype: int
|
458 | 8b312c1d | Manuel Franceschini | @return: integer value of given IP address
|
459 | 8b312c1d | Manuel Franceschini |
|
460 | 8b312c1d | Manuel Franceschini | """
|
461 | 8b312c1d | Manuel Franceschini | doublecolons = address.count("::")
|
462 | 8b312c1d | Manuel Franceschini | assert not doublecolons > 1 |
463 | 8b312c1d | Manuel Franceschini | if doublecolons == 1: |
464 | 8b312c1d | Manuel Franceschini | # We have a shorthand address, expand it
|
465 | 8b312c1d | Manuel Franceschini | parts = [] |
466 | 8b312c1d | Manuel Franceschini | twoparts = address.split("::")
|
467 | 8b312c1d | Manuel Franceschini | sep = len(twoparts[0].split(':')) + len(twoparts[1].split(':')) |
468 | 8b312c1d | Manuel Franceschini | parts = twoparts[0].split(':') |
469 | 8b312c1d | Manuel Franceschini | [parts.append("0") for _ in range(8 - sep)] |
470 | 8b312c1d | Manuel Franceschini | parts += twoparts[1].split(':') |
471 | 8b312c1d | Manuel Franceschini | else:
|
472 | 8b312c1d | Manuel Franceschini | parts = address.split(":")
|
473 | 8b312c1d | Manuel Franceschini | |
474 | 8b312c1d | Manuel Franceschini | address_int = 0
|
475 | 8b312c1d | Manuel Franceschini | for part in parts: |
476 | 8b312c1d | Manuel Franceschini | address_int = (address_int << 16) + int(part or '0', 16) |
477 | 8b312c1d | Manuel Franceschini | |
478 | 8b312c1d | Manuel Franceschini | return address_int
|
479 | 1a8337f2 | Manuel Franceschini | |
480 | 7845b8c8 | Manuel Franceschini | |
481 | 1a8337f2 | Manuel Franceschini | def FormatAddress(family, address): |
482 | 1a8337f2 | Manuel Franceschini | """Format a socket address
|
483 | 1a8337f2 | Manuel Franceschini |
|
484 | 1a8337f2 | Manuel Franceschini | @type family: integer
|
485 | 1a8337f2 | Manuel Franceschini | @param family: socket family (one of socket.AF_*)
|
486 | 1a8337f2 | Manuel Franceschini | @type address: family specific (usually tuple)
|
487 | 1a8337f2 | Manuel Franceschini | @param address: address, as reported by this class
|
488 | 1a8337f2 | Manuel Franceschini |
|
489 | 1a8337f2 | Manuel Franceschini | """
|
490 | 1a8337f2 | Manuel Franceschini | if family == socket.AF_UNIX and len(address) == 3: |
491 | 1a8337f2 | Manuel Franceschini | return "pid=%s, uid=%s, gid=%s" % address |
492 | 1a8337f2 | Manuel Franceschini | |
493 | 1a8337f2 | Manuel Franceschini | if family in (socket.AF_INET, socket.AF_INET6) and len(address) == 2: |
494 | 1a8337f2 | Manuel Franceschini | host, port = address |
495 | 1a8337f2 | Manuel Franceschini | if family == socket.AF_INET6:
|
496 | 1a8337f2 | Manuel Franceschini | res = "[%s]" % host
|
497 | 1a8337f2 | Manuel Franceschini | else:
|
498 | 1a8337f2 | Manuel Franceschini | res = host |
499 | 1a8337f2 | Manuel Franceschini | |
500 | 1a8337f2 | Manuel Franceschini | if port is not None: |
501 | 1a8337f2 | Manuel Franceschini | res += ":%s" % port
|
502 | 1a8337f2 | Manuel Franceschini | |
503 | 1a8337f2 | Manuel Franceschini | return res
|
504 | 1a8337f2 | Manuel Franceschini | |
505 | 1a8337f2 | Manuel Franceschini | raise errors.ParameterError(family, address) |