Statistics
| Branch: | Tag: | Revision:

root / lib / netutils.py @ 8062638d

History | View | Annotate | Download (13.6 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 17f7fd27 Manuel Franceschini
  @raise errors.OpPrereqError: in case of errors in resolving
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 f3044516 Manuel Franceschini
    self.name = self.GetNormalizedName(self.GetFqdn(name))
102 b705c7a6 Manuel Franceschini
    self.ip = self.GetIP(self.name, family=family)
103 a744b676 Manuel Franceschini
104 f3044516 Manuel Franceschini
  @classmethod
105 f3044516 Manuel Franceschini
  def GetSysName(cls):
106 f3044516 Manuel Franceschini
    """Legacy method the get the current system's name.
107 f3044516 Manuel Franceschini

108 f3044516 Manuel Franceschini
    """
109 f3044516 Manuel Franceschini
    return cls.GetFqdn()
110 f3044516 Manuel Franceschini
111 a744b676 Manuel Franceschini
  @staticmethod
112 f3044516 Manuel Franceschini
  def GetFqdn(hostname=None):
113 f3044516 Manuel Franceschini
    """Return fqdn.
114 f3044516 Manuel Franceschini

115 f3044516 Manuel Franceschini
    If hostname is None the system's fqdn is returned.
116 a744b676 Manuel Franceschini

117 f3044516 Manuel Franceschini
    @type hostname: str
118 f3044516 Manuel Franceschini
    @param hostname: name to be fqdn'ed
119 f3044516 Manuel Franceschini
    @rtype: str
120 f3044516 Manuel Franceschini
    @return: fqdn of given name, if it exists, unmodified name otherwise
121 a744b676 Manuel Franceschini

122 a744b676 Manuel Franceschini
    """
123 f3044516 Manuel Franceschini
    if hostname is None:
124 f3044516 Manuel Franceschini
      return socket.getfqdn()
125 f3044516 Manuel Franceschini
    else:
126 f3044516 Manuel Franceschini
      return socket.getfqdn(hostname)
127 a744b676 Manuel Franceschini
128 a744b676 Manuel Franceschini
  @staticmethod
129 b705c7a6 Manuel Franceschini
  def GetIP(hostname, family=None):
130 b705c7a6 Manuel Franceschini
    """Return IP address of given hostname.
131 b705c7a6 Manuel Franceschini

132 b705c7a6 Manuel Franceschini
    Supports both IPv4 and IPv6.
133 a744b676 Manuel Franceschini

134 a744b676 Manuel Franceschini
    @type hostname: str
135 a744b676 Manuel Franceschini
    @param hostname: hostname to look up
136 b705c7a6 Manuel Franceschini
    @type family: int
137 b705c7a6 Manuel Franceschini
    @param family: AF_INET | AF_INET6 | None
138 b705c7a6 Manuel Franceschini
    @rtype: str
139 b705c7a6 Manuel Franceschini
    @return: IP address
140 a744b676 Manuel Franceschini
    @raise errors.ResolverError: in case of errors in resolving
141 a744b676 Manuel Franceschini

142 a744b676 Manuel Franceschini
    """
143 a744b676 Manuel Franceschini
    try:
144 b705c7a6 Manuel Franceschini
      if family in (socket.AF_INET, socket.AF_INET6):
145 b705c7a6 Manuel Franceschini
        result = socket.getaddrinfo(hostname, None, family)
146 b705c7a6 Manuel Franceschini
      else:
147 b43dcc5a Manuel Franceschini
        result = socket.getaddrinfo(hostname, None)
148 a744b676 Manuel Franceschini
    except (socket.gaierror, socket.herror, socket.error), err:
149 a744b676 Manuel Franceschini
      # hostname not found in DNS, or other socket exception in the
150 a744b676 Manuel Franceschini
      # (code, description format)
151 a744b676 Manuel Franceschini
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
152 a744b676 Manuel Franceschini
153 b705c7a6 Manuel Franceschini
    # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
154 b705c7a6 Manuel Franceschini
    # canonname, sockaddr). We return the first tuple's first address in
155 b705c7a6 Manuel Franceschini
    # sockaddr
156 e7b3ad26 Manuel Franceschini
    try:
157 e7b3ad26 Manuel Franceschini
      return result[0][4][0]
158 e7b3ad26 Manuel Franceschini
    except IndexError, err:
159 e7b3ad26 Manuel Franceschini
      raise errors.ResolverError("Unknown error in getaddrinfo(): %s" % err)
160 a744b676 Manuel Franceschini
161 e7b3ad26 Manuel Franceschini
  @classmethod
162 e7b3ad26 Manuel Franceschini
  def GetNormalizedName(cls, hostname):
163 a744b676 Manuel Franceschini
    """Validate and normalize the given hostname.
164 a744b676 Manuel Franceschini

165 a744b676 Manuel Franceschini
    @attention: the validation is a bit more relaxed than the standards
166 a744b676 Manuel Franceschini
        require; most importantly, we allow underscores in names
167 a744b676 Manuel Franceschini
    @raise errors.OpPrereqError: when the name is not valid
168 a744b676 Manuel Franceschini

169 a744b676 Manuel Franceschini
    """
170 a744b676 Manuel Franceschini
    hostname = hostname.lower()
171 e7b3ad26 Manuel Franceschini
    if (not cls._VALID_NAME_RE.match(hostname) or
172 a744b676 Manuel Franceschini
        # double-dots, meaning empty label
173 a744b676 Manuel Franceschini
        ".." in hostname or
174 a744b676 Manuel Franceschini
        # empty initial label
175 a744b676 Manuel Franceschini
        hostname.startswith(".")):
176 a744b676 Manuel Franceschini
      raise errors.OpPrereqError("Invalid hostname '%s'" % hostname,
177 a744b676 Manuel Franceschini
                                 errors.ECODE_INVAL)
178 a744b676 Manuel Franceschini
    if hostname.endswith("."):
179 a744b676 Manuel Franceschini
      hostname = hostname.rstrip(".")
180 a744b676 Manuel Franceschini
    return hostname
181 a744b676 Manuel Franceschini
182 a744b676 Manuel Franceschini
183 a744b676 Manuel Franceschini
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
184 a744b676 Manuel Franceschini
  """Simple ping implementation using TCP connect(2).
185 a744b676 Manuel Franceschini

186 a744b676 Manuel Franceschini
  Check if the given IP is reachable by doing attempting a TCP connect
187 a744b676 Manuel Franceschini
  to it.
188 a744b676 Manuel Franceschini

189 a744b676 Manuel Franceschini
  @type target: str
190 a744b676 Manuel Franceschini
  @param target: the IP or hostname to ping
191 a744b676 Manuel Franceschini
  @type port: int
192 a744b676 Manuel Franceschini
  @param port: the port to connect to
193 a744b676 Manuel Franceschini
  @type timeout: int
194 a744b676 Manuel Franceschini
  @param timeout: the timeout on the connection attempt
195 a744b676 Manuel Franceschini
  @type live_port_needed: boolean
196 a744b676 Manuel Franceschini
  @param live_port_needed: whether a closed port will cause the
197 a744b676 Manuel Franceschini
      function to return failure, as if there was a timeout
198 a744b676 Manuel Franceschini
  @type source: str or None
199 a744b676 Manuel Franceschini
  @param source: if specified, will cause the connect to be made
200 a744b676 Manuel Franceschini
      from this specific source address; failures to bind other
201 a744b676 Manuel Franceschini
      than C{EADDRNOTAVAIL} will be ignored
202 a744b676 Manuel Franceschini

203 a744b676 Manuel Franceschini
  """
204 a744b676 Manuel Franceschini
  try:
205 8b312c1d Manuel Franceschini
    family = IPAddress.GetAddressFamily(target)
206 a744b676 Manuel Franceschini
  except errors.GenericError:
207 a744b676 Manuel Franceschini
    return False
208 a744b676 Manuel Franceschini
209 a744b676 Manuel Franceschini
  sock = socket.socket(family, socket.SOCK_STREAM)
210 a744b676 Manuel Franceschini
  success = False
211 a744b676 Manuel Franceschini
212 a744b676 Manuel Franceschini
  if source is not None:
213 a744b676 Manuel Franceschini
    try:
214 a744b676 Manuel Franceschini
      sock.bind((source, 0))
215 a744b676 Manuel Franceschini
    except socket.error, (errcode, _):
216 a744b676 Manuel Franceschini
      if errcode == errno.EADDRNOTAVAIL:
217 a744b676 Manuel Franceschini
        success = False
218 a744b676 Manuel Franceschini
219 a744b676 Manuel Franceschini
  sock.settimeout(timeout)
220 a744b676 Manuel Franceschini
221 a744b676 Manuel Franceschini
  try:
222 a744b676 Manuel Franceschini
    sock.connect((target, port))
223 a744b676 Manuel Franceschini
    sock.close()
224 a744b676 Manuel Franceschini
    success = True
225 a744b676 Manuel Franceschini
  except socket.timeout:
226 a744b676 Manuel Franceschini
    success = False
227 a744b676 Manuel Franceschini
  except socket.error, (errcode, _):
228 a744b676 Manuel Franceschini
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
229 a744b676 Manuel Franceschini
230 a744b676 Manuel Franceschini
  return success
231 a744b676 Manuel Franceschini
232 a744b676 Manuel Franceschini
233 a744b676 Manuel Franceschini
def GetDaemonPort(daemon_name):
234 a744b676 Manuel Franceschini
  """Get the daemon port for this cluster.
235 a744b676 Manuel Franceschini

236 a744b676 Manuel Franceschini
  Note that this routine does not read a ganeti-specific file, but
237 a744b676 Manuel Franceschini
  instead uses C{socket.getservbyname} to allow pre-customization of
238 a744b676 Manuel Franceschini
  this parameter outside of Ganeti.
239 a744b676 Manuel Franceschini

240 a744b676 Manuel Franceschini
  @type daemon_name: string
241 a744b676 Manuel Franceschini
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
242 a744b676 Manuel Franceschini
  @rtype: int
243 a744b676 Manuel Franceschini

244 a744b676 Manuel Franceschini
  """
245 a744b676 Manuel Franceschini
  if daemon_name not in constants.DAEMONS_PORTS:
246 a744b676 Manuel Franceschini
    raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name)
247 a744b676 Manuel Franceschini
248 a744b676 Manuel Franceschini
  (proto, default_port) = constants.DAEMONS_PORTS[daemon_name]
249 a744b676 Manuel Franceschini
  try:
250 a744b676 Manuel Franceschini
    port = socket.getservbyname(daemon_name, proto)
251 a744b676 Manuel Franceschini
  except socket.error:
252 a744b676 Manuel Franceschini
    port = default_port
253 a744b676 Manuel Franceschini
254 a744b676 Manuel Franceschini
  return port
255 8b312c1d Manuel Franceschini
256 8b312c1d Manuel Franceschini
257 8b312c1d Manuel Franceschini
class IPAddress(object):
258 8b312c1d Manuel Franceschini
  """Class that represents an IP address.
259 8b312c1d Manuel Franceschini

260 8b312c1d Manuel Franceschini
  """
261 8b312c1d Manuel Franceschini
  iplen = 0
262 8b312c1d Manuel Franceschini
  family = None
263 8b312c1d Manuel Franceschini
  loopback_cidr = None
264 8b312c1d Manuel Franceschini
265 8b312c1d Manuel Franceschini
  @staticmethod
266 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
267 8b312c1d Manuel Franceschini
    """Abstract method to please pylint.
268 8b312c1d Manuel Franceschini

269 8b312c1d Manuel Franceschini
    """
270 8b312c1d Manuel Franceschini
    raise NotImplementedError
271 8b312c1d Manuel Franceschini
272 8b312c1d Manuel Franceschini
  @classmethod
273 8b312c1d Manuel Franceschini
  def IsValid(cls, address):
274 8b312c1d Manuel Franceschini
    """Validate a IP address.
275 8b312c1d Manuel Franceschini

276 8b312c1d Manuel Franceschini
    @type address: str
277 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
278 8b312c1d Manuel Franceschini
    @rtype: bool
279 8b312c1d Manuel Franceschini
    @return: True if valid, False otherwise
280 8b312c1d Manuel Franceschini

281 8b312c1d Manuel Franceschini
    """
282 8b312c1d Manuel Franceschini
    if cls.family is None:
283 8b312c1d Manuel Franceschini
      try:
284 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
285 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
286 8b312c1d Manuel Franceschini
        return False
287 8b312c1d Manuel Franceschini
    else:
288 8b312c1d Manuel Franceschini
      family = cls.family
289 8b312c1d Manuel Franceschini
290 8b312c1d Manuel Franceschini
    try:
291 8b312c1d Manuel Franceschini
      socket.inet_pton(family, address)
292 8b312c1d Manuel Franceschini
      return True
293 8b312c1d Manuel Franceschini
    except socket.error:
294 8b312c1d Manuel Franceschini
      return False
295 8b312c1d Manuel Franceschini
296 8b312c1d Manuel Franceschini
  @classmethod
297 8b312c1d Manuel Franceschini
  def Own(cls, address):
298 8b312c1d Manuel Franceschini
    """Check if the current host has the the given IP address.
299 8b312c1d Manuel Franceschini

300 8b312c1d Manuel Franceschini
    This is done by trying to bind the given address. We return True if we
301 8b312c1d Manuel Franceschini
    succeed or false if a socket.error is raised.
302 8b312c1d Manuel Franceschini

303 8b312c1d Manuel Franceschini
    @type address: str
304 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
305 8b312c1d Manuel Franceschini
    @rtype: bool
306 8b312c1d Manuel Franceschini
    @return: True if we own the address, False otherwise
307 8b312c1d Manuel Franceschini

308 8b312c1d Manuel Franceschini
    """
309 8b312c1d Manuel Franceschini
    if cls.family is None:
310 8b312c1d Manuel Franceschini
      try:
311 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
312 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
313 8b312c1d Manuel Franceschini
        return False
314 8b312c1d Manuel Franceschini
    else:
315 8b312c1d Manuel Franceschini
      family = cls.family
316 8b312c1d Manuel Franceschini
317 8b312c1d Manuel Franceschini
    s = socket.socket(family, socket.SOCK_DGRAM)
318 8b312c1d Manuel Franceschini
    success = False
319 8b312c1d Manuel Franceschini
    try:
320 8b312c1d Manuel Franceschini
      try:
321 8b312c1d Manuel Franceschini
        s.bind((address, 0))
322 8b312c1d Manuel Franceschini
        success = True
323 8b312c1d Manuel Franceschini
      except socket.error:
324 8b312c1d Manuel Franceschini
        success = False
325 8b312c1d Manuel Franceschini
    finally:
326 8b312c1d Manuel Franceschini
      s.close()
327 8b312c1d Manuel Franceschini
    return success
328 8b312c1d Manuel Franceschini
329 8b312c1d Manuel Franceschini
  @classmethod
330 8b312c1d Manuel Franceschini
  def InNetwork(cls, cidr, address):
331 8b312c1d Manuel Franceschini
    """Determine whether an address is within a network.
332 8b312c1d Manuel Franceschini

333 8b312c1d Manuel Franceschini
    @type cidr: string
334 8b312c1d Manuel Franceschini
    @param cidr: Network in CIDR notation, e.g. '192.0.2.0/24', '2001:db8::/64'
335 8b312c1d Manuel Franceschini
    @type address: str
336 8b312c1d Manuel Franceschini
    @param address: IP address
337 8b312c1d Manuel Franceschini
    @rtype: bool
338 8b312c1d Manuel Franceschini
    @return: True if address is in cidr, False otherwise
339 8b312c1d Manuel Franceschini

340 8b312c1d Manuel Franceschini
    """
341 8b312c1d Manuel Franceschini
    address_int = cls._GetIPIntFromString(address)
342 8b312c1d Manuel Franceschini
    subnet = cidr.split("/")
343 8b312c1d Manuel Franceschini
    assert len(subnet) == 2
344 8b312c1d Manuel Franceschini
    try:
345 8b312c1d Manuel Franceschini
      prefix = int(subnet[1])
346 8b312c1d Manuel Franceschini
    except ValueError:
347 8b312c1d Manuel Franceschini
      return False
348 8b312c1d Manuel Franceschini
349 8b312c1d Manuel Franceschini
    assert 0 <= prefix <= cls.iplen
350 8b312c1d Manuel Franceschini
    target_int = cls._GetIPIntFromString(subnet[0])
351 8b312c1d Manuel Franceschini
    # Convert prefix netmask to integer value of netmask
352 8b312c1d Manuel Franceschini
    netmask_int = (2**cls.iplen)-1 ^ ((2**cls.iplen)-1 >> prefix)
353 8b312c1d Manuel Franceschini
    # Calculate hostmask
354 8b312c1d Manuel Franceschini
    hostmask_int = netmask_int ^ (2**cls.iplen)-1
355 8b312c1d Manuel Franceschini
    # Calculate network address by and'ing netmask
356 8b312c1d Manuel Franceschini
    network_int = target_int & netmask_int
357 8b312c1d Manuel Franceschini
    # Calculate broadcast address by or'ing hostmask
358 8b312c1d Manuel Franceschini
    broadcast_int = target_int | hostmask_int
359 8b312c1d Manuel Franceschini
360 8b312c1d Manuel Franceschini
    return network_int <= address_int <= broadcast_int
361 8b312c1d Manuel Franceschini
362 8b312c1d Manuel Franceschini
  @staticmethod
363 8b312c1d Manuel Franceschini
  def GetAddressFamily(address):
364 8b312c1d Manuel Franceschini
    """Get the address family of the given address.
365 8b312c1d Manuel Franceschini

366 8b312c1d Manuel Franceschini
    @type address: str
367 8b312c1d Manuel Franceschini
    @param address: ip address whose family will be returned
368 8b312c1d Manuel Franceschini
    @rtype: int
369 8b312c1d Manuel Franceschini
    @return: socket.AF_INET or socket.AF_INET6
370 8b312c1d Manuel Franceschini
    @raise errors.GenericError: for invalid addresses
371 8b312c1d Manuel Franceschini

372 8b312c1d Manuel Franceschini
    """
373 8b312c1d Manuel Franceschini
    try:
374 8b312c1d Manuel Franceschini
      return IP4Address(address).family
375 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
376 8b312c1d Manuel Franceschini
      pass
377 8b312c1d Manuel Franceschini
378 8b312c1d Manuel Franceschini
    try:
379 8b312c1d Manuel Franceschini
      return IP6Address(address).family
380 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
381 8b312c1d Manuel Franceschini
      pass
382 8b312c1d Manuel Franceschini
383 8b312c1d Manuel Franceschini
    raise errors.IPAddressError("Invalid address '%s'" % address)
384 8b312c1d Manuel Franceschini
385 8b312c1d Manuel Franceschini
  @classmethod
386 8b312c1d Manuel Franceschini
  def IsLoopback(cls, address):
387 8b312c1d Manuel Franceschini
    """Determine whether it is a loopback address.
388 8b312c1d Manuel Franceschini

389 8b312c1d Manuel Franceschini
    @type address: str
390 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
391 8b312c1d Manuel Franceschini
    @rtype: bool
392 8b312c1d Manuel Franceschini
    @return: True if loopback, False otherwise
393 8b312c1d Manuel Franceschini

394 8b312c1d Manuel Franceschini
    """
395 8b312c1d Manuel Franceschini
    try:
396 8b312c1d Manuel Franceschini
      return cls.InNetwork(cls.loopback_cidr, address)
397 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
398 8b312c1d Manuel Franceschini
      return False
399 8b312c1d Manuel Franceschini
400 8b312c1d Manuel Franceschini
401 8b312c1d Manuel Franceschini
class IP4Address(IPAddress):
402 8b312c1d Manuel Franceschini
  """IPv4 address class.
403 8b312c1d Manuel Franceschini

404 8b312c1d Manuel Franceschini
  """
405 8b312c1d Manuel Franceschini
  iplen = 32
406 8b312c1d Manuel Franceschini
  family = socket.AF_INET
407 8b312c1d Manuel Franceschini
  loopback_cidr = "127.0.0.0/8"
408 8b312c1d Manuel Franceschini
409 8b312c1d Manuel Franceschini
  def __init__(self, address):
410 8b312c1d Manuel Franceschini
    """Constructor for IPv4 address.
411 8b312c1d Manuel Franceschini

412 8b312c1d Manuel Franceschini
    @type address: str
413 8b312c1d Manuel Franceschini
    @param address: IP address
414 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
415 8b312c1d Manuel Franceschini

416 8b312c1d Manuel Franceschini
    """
417 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
418 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
419 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv4 Address %s invalid" % address)
420 8b312c1d Manuel Franceschini
421 8b312c1d Manuel Franceschini
    self.address = address
422 8b312c1d Manuel Franceschini
423 8b312c1d Manuel Franceschini
  @staticmethod
424 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
425 8b312c1d Manuel Franceschini
    """Get integer value of IPv4 address.
426 8b312c1d Manuel Franceschini

427 8b312c1d Manuel Franceschini
    @type address: str
428 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
429 8b312c1d Manuel Franceschini
    @rtype: int
430 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
431 8b312c1d Manuel Franceschini

432 8b312c1d Manuel Franceschini
    """
433 8b312c1d Manuel Franceschini
    address_int = 0
434 8b312c1d Manuel Franceschini
    parts = address.split(".")
435 8b312c1d Manuel Franceschini
    assert len(parts) == 4
436 8b312c1d Manuel Franceschini
    for part in parts:
437 8b312c1d Manuel Franceschini
      address_int = (address_int << 8) | int(part)
438 8b312c1d Manuel Franceschini
439 8b312c1d Manuel Franceschini
    return address_int
440 8b312c1d Manuel Franceschini
441 8b312c1d Manuel Franceschini
442 8b312c1d Manuel Franceschini
class IP6Address(IPAddress):
443 8b312c1d Manuel Franceschini
  """IPv6 address class.
444 8b312c1d Manuel Franceschini

445 8b312c1d Manuel Franceschini
  """
446 8b312c1d Manuel Franceschini
  iplen = 128
447 8b312c1d Manuel Franceschini
  family = socket.AF_INET6
448 8b312c1d Manuel Franceschini
  loopback_cidr = "::1/128"
449 8b312c1d Manuel Franceschini
450 8b312c1d Manuel Franceschini
  def __init__(self, address):
451 8b312c1d Manuel Franceschini
    """Constructor for IPv6 address.
452 8b312c1d Manuel Franceschini

453 8b312c1d Manuel Franceschini
    @type address: str
454 8b312c1d Manuel Franceschini
    @param address: IP address
455 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
456 8b312c1d Manuel Franceschini

457 8b312c1d Manuel Franceschini
    """
458 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
459 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
460 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv6 Address [%s] invalid" % address)
461 8b312c1d Manuel Franceschini
    self.address = address
462 8b312c1d Manuel Franceschini
463 8b312c1d Manuel Franceschini
  @staticmethod
464 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
465 8b312c1d Manuel Franceschini
    """Get integer value of IPv6 address.
466 8b312c1d Manuel Franceschini

467 8b312c1d Manuel Franceschini
    @type address: str
468 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
469 8b312c1d Manuel Franceschini
    @rtype: int
470 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
471 8b312c1d Manuel Franceschini

472 8b312c1d Manuel Franceschini
    """
473 8b312c1d Manuel Franceschini
    doublecolons = address.count("::")
474 8b312c1d Manuel Franceschini
    assert not doublecolons > 1
475 8b312c1d Manuel Franceschini
    if doublecolons == 1:
476 8b312c1d Manuel Franceschini
      # We have a shorthand address, expand it
477 8b312c1d Manuel Franceschini
      parts = []
478 8b312c1d Manuel Franceschini
      twoparts = address.split("::")
479 8b312c1d Manuel Franceschini
      sep = len(twoparts[0].split(':')) + len(twoparts[1].split(':'))
480 8b312c1d Manuel Franceschini
      parts = twoparts[0].split(':')
481 8b312c1d Manuel Franceschini
      [parts.append("0") for _ in range(8 - sep)]
482 8b312c1d Manuel Franceschini
      parts += twoparts[1].split(':')
483 8b312c1d Manuel Franceschini
    else:
484 8b312c1d Manuel Franceschini
      parts = address.split(":")
485 8b312c1d Manuel Franceschini
486 8b312c1d Manuel Franceschini
    address_int = 0
487 8b312c1d Manuel Franceschini
    for part in parts:
488 8b312c1d Manuel Franceschini
      address_int = (address_int << 16) + int(part or '0', 16)
489 8b312c1d Manuel Franceschini
490 8b312c1d Manuel Franceschini
    return address_int
491 1a8337f2 Manuel Franceschini
492 7845b8c8 Manuel Franceschini
493 981732fb Manuel Franceschini
def FormatAddress(address, family=None):
494 1a8337f2 Manuel Franceschini
  """Format a socket address
495 1a8337f2 Manuel Franceschini

496 1a8337f2 Manuel Franceschini
  @type address: family specific (usually tuple)
497 1a8337f2 Manuel Franceschini
  @param address: address, as reported by this class
498 981732fb Manuel Franceschini
  @type family: integer
499 981732fb Manuel Franceschini
  @param family: socket family (one of socket.AF_*) or None
500 1a8337f2 Manuel Franceschini

501 1a8337f2 Manuel Franceschini
  """
502 981732fb Manuel Franceschini
  if family is None:
503 981732fb Manuel Franceschini
    try:
504 981732fb Manuel Franceschini
      family = IPAddress.GetAddressFamily(address[0])
505 981732fb Manuel Franceschini
    except errors.IPAddressError:
506 981732fb Manuel Franceschini
      raise errors.ParameterError(address)
507 981732fb Manuel Franceschini
508 1a8337f2 Manuel Franceschini
  if family == socket.AF_UNIX and len(address) == 3:
509 1a8337f2 Manuel Franceschini
    return "pid=%s, uid=%s, gid=%s" % address
510 1a8337f2 Manuel Franceschini
511 1a8337f2 Manuel Franceschini
  if family in (socket.AF_INET, socket.AF_INET6) and len(address) == 2:
512 1a8337f2 Manuel Franceschini
    host, port = address
513 1a8337f2 Manuel Franceschini
    if family == socket.AF_INET6:
514 1a8337f2 Manuel Franceschini
      res = "[%s]" % host
515 1a8337f2 Manuel Franceschini
    else:
516 1a8337f2 Manuel Franceschini
      res = host
517 1a8337f2 Manuel Franceschini
518 1a8337f2 Manuel Franceschini
    if port is not None:
519 1a8337f2 Manuel Franceschini
      res += ":%s" % port
520 1a8337f2 Manuel Franceschini
521 1a8337f2 Manuel Franceschini
    return res
522 1a8337f2 Manuel Franceschini
523 1a8337f2 Manuel Franceschini
  raise errors.ParameterError(family, address)