Statistics
| Branch: | Tag: | Revision:

root / lib / netutils.py @ e7b3ad26

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 b705c7a6 Manuel Franceschini
        result = socket.getaddrinfo(hostname, None, socket.AF_INET)
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)