Statistics
| Branch: | Tag: | Revision:

root / lib / netutils.py @ 3a6a89d7

History | View | Annotate | Download (18.3 kB)

1 a744b676 Manuel Franceschini
#
2 a744b676 Manuel Franceschini
#
3 a744b676 Manuel Franceschini
4 8ad0da1e Iustin Pop
# Copyright (C) 2010, 2011, 2012 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 37531236 Andrea Spadaccini
import os
32 a744b676 Manuel Franceschini
import re
33 a744b676 Manuel Franceschini
import socket
34 a744b676 Manuel Franceschini
import struct
35 a744b676 Manuel Franceschini
import IN
36 37531236 Andrea Spadaccini
import logging
37 a744b676 Manuel Franceschini
38 a744b676 Manuel Franceschini
from ganeti import constants
39 a744b676 Manuel Franceschini
from ganeti import errors
40 37531236 Andrea Spadaccini
from ganeti import utils
41 e91b297c Michael Hanselmann
from ganeti import vcluster
42 a744b676 Manuel Franceschini
43 a744b676 Manuel Franceschini
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...):
44 a744b676 Manuel Franceschini
# struct ucred { pid_t pid; uid_t uid; gid_t gid; };
45 a744b676 Manuel Franceschini
#
46 a744b676 Manuel Franceschini
# The GNU C Library defines gid_t and uid_t to be "unsigned int" and
47 a744b676 Manuel Franceschini
# pid_t to "int".
48 a744b676 Manuel Franceschini
#
49 a744b676 Manuel Franceschini
# IEEE Std 1003.1-2008:
50 a744b676 Manuel Franceschini
# "nlink_t, uid_t, gid_t, and id_t shall be integer types"
51 a744b676 Manuel Franceschini
# "blksize_t, pid_t, and ssize_t shall be signed integer types"
52 a744b676 Manuel Franceschini
_STRUCT_UCRED = "iII"
53 a744b676 Manuel Franceschini
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED)
54 a744b676 Manuel Franceschini
55 37531236 Andrea Spadaccini
# Regexes used to find IP addresses in the output of ip.
56 37531236 Andrea Spadaccini
_IP_RE_TEXT = r"[.:a-z0-9]+"      # separate for testing purposes
57 37531236 Andrea Spadaccini
_IP_FAMILY_RE = re.compile(r"(?P<family>inet6?)\s+(?P<ip>%s)/" % _IP_RE_TEXT,
58 37531236 Andrea Spadaccini
                           re.IGNORECASE)
59 37531236 Andrea Spadaccini
60 37531236 Andrea Spadaccini
# Dict used to convert from a string representing an IP family to an IP
61 37531236 Andrea Spadaccini
# version
62 e687ec01 Michael Hanselmann
_NAME_TO_IP_VER = {
63 37531236 Andrea Spadaccini
  "inet": constants.IP4_VERSION,
64 37531236 Andrea Spadaccini
  "inet6": constants.IP6_VERSION,
65 37531236 Andrea Spadaccini
  }
66 37531236 Andrea Spadaccini
67 37531236 Andrea Spadaccini
68 37531236 Andrea Spadaccini
def _GetIpAddressesFromIpOutput(ip_output):
69 37531236 Andrea Spadaccini
  """Parses the output of the ip command and retrieves the IP addresses and
70 37531236 Andrea Spadaccini
  version.
71 37531236 Andrea Spadaccini

72 37531236 Andrea Spadaccini
  @param ip_output: string containing the output of the ip command;
73 37531236 Andrea Spadaccini
  @rtype: dict; (int, list)
74 37531236 Andrea Spadaccini
  @return: a dict having as keys the IP versions and as values the
75 37531236 Andrea Spadaccini
           corresponding list of addresses found in the IP output.
76 37531236 Andrea Spadaccini

77 37531236 Andrea Spadaccini
  """
78 37531236 Andrea Spadaccini
  addr = dict((i, []) for i in _NAME_TO_IP_VER.values())
79 37531236 Andrea Spadaccini
80 37531236 Andrea Spadaccini
  for row in ip_output.splitlines():
81 37531236 Andrea Spadaccini
    match = _IP_FAMILY_RE.search(row)
82 37531236 Andrea Spadaccini
    if match and IPAddress.IsValid(match.group("ip")):
83 37531236 Andrea Spadaccini
      addr[_NAME_TO_IP_VER[match.group("family")]].append(match.group("ip"))
84 37531236 Andrea Spadaccini
85 37531236 Andrea Spadaccini
  return addr
86 37531236 Andrea Spadaccini
87 a744b676 Manuel Franceschini
88 a744b676 Manuel Franceschini
def GetSocketCredentials(sock):
89 a744b676 Manuel Franceschini
  """Returns the credentials of the foreign process connected to a socket.
90 a744b676 Manuel Franceschini

91 a744b676 Manuel Franceschini
  @param sock: Unix socket
92 a744b676 Manuel Franceschini
  @rtype: tuple; (number, number, number)
93 a744b676 Manuel Franceschini
  @return: The PID, UID and GID of the connected foreign process.
94 a744b676 Manuel Franceschini

95 a744b676 Manuel Franceschini
  """
96 a744b676 Manuel Franceschini
  peercred = sock.getsockopt(socket.SOL_SOCKET, IN.SO_PEERCRED,
97 a744b676 Manuel Franceschini
                             _STRUCT_UCRED_SIZE)
98 a744b676 Manuel Franceschini
  return struct.unpack(_STRUCT_UCRED, peercred)
99 a744b676 Manuel Franceschini
100 a744b676 Manuel Franceschini
101 37531236 Andrea Spadaccini
def IsValidInterface(ifname):
102 37531236 Andrea Spadaccini
  """Validate an interface name.
103 37531236 Andrea Spadaccini

104 37531236 Andrea Spadaccini
  @type ifname: string
105 37531236 Andrea Spadaccini
  @param ifname: Name of the network interface
106 37531236 Andrea Spadaccini
  @return: boolean indicating whether the interface name is valid or not.
107 37531236 Andrea Spadaccini

108 37531236 Andrea Spadaccini
  """
109 37531236 Andrea Spadaccini
  return os.path.exists(utils.PathJoin("/sys/class/net", ifname))
110 37531236 Andrea Spadaccini
111 37531236 Andrea Spadaccini
112 37531236 Andrea Spadaccini
def GetInterfaceIpAddresses(ifname):
113 37531236 Andrea Spadaccini
  """Returns the IP addresses associated to the interface.
114 37531236 Andrea Spadaccini

115 37531236 Andrea Spadaccini
  @type ifname: string
116 37531236 Andrea Spadaccini
  @param ifname: Name of the network interface
117 37531236 Andrea Spadaccini
  @return: A dict having for keys the IP version (either
118 37531236 Andrea Spadaccini
           L{constants.IP4_VERSION} or L{constants.IP6_VERSION}) and for
119 37531236 Andrea Spadaccini
           values the lists of IP addresses of the respective version
120 37531236 Andrea Spadaccini
           associated to the interface
121 37531236 Andrea Spadaccini

122 37531236 Andrea Spadaccini
  """
123 37531236 Andrea Spadaccini
  result = utils.RunCmd([constants.IP_COMMAND_PATH, "-o", "addr", "show",
124 37531236 Andrea Spadaccini
                         ifname])
125 37531236 Andrea Spadaccini
126 37531236 Andrea Spadaccini
  if result.failed:
127 37531236 Andrea Spadaccini
    logging.error("Error running the ip command while getting the IP"
128 37531236 Andrea Spadaccini
                  " addresses of %s", ifname)
129 37531236 Andrea Spadaccini
    return None
130 37531236 Andrea Spadaccini
131 37531236 Andrea Spadaccini
  return _GetIpAddressesFromIpOutput(result.output)
132 37531236 Andrea Spadaccini
133 37531236 Andrea Spadaccini
134 b705c7a6 Manuel Franceschini
def GetHostname(name=None, family=None):
135 b705c7a6 Manuel Franceschini
  """Returns a Hostname object.
136 a744b676 Manuel Franceschini

137 b705c7a6 Manuel Franceschini
  @type name: str
138 b705c7a6 Manuel Franceschini
  @param name: hostname or None
139 b705c7a6 Manuel Franceschini
  @type family: int
140 b705c7a6 Manuel Franceschini
  @param family: AF_INET | AF_INET6 | None
141 b705c7a6 Manuel Franceschini
  @rtype: L{Hostname}
142 b705c7a6 Manuel Franceschini
  @return: Hostname object
143 17f7fd27 Manuel Franceschini
  @raise errors.OpPrereqError: in case of errors in resolving
144 b705c7a6 Manuel Franceschini

145 b705c7a6 Manuel Franceschini
  """
146 a744b676 Manuel Franceschini
  try:
147 b705c7a6 Manuel Franceschini
    return Hostname(name=name, family=family)
148 a744b676 Manuel Franceschini
  except errors.ResolverError, err:
149 a744b676 Manuel Franceschini
    raise errors.OpPrereqError("The given name (%s) does not resolve: %s" %
150 a744b676 Manuel Franceschini
                               (err[0], err[2]), errors.ECODE_RESOLVER)
151 a744b676 Manuel Franceschini
152 a744b676 Manuel Franceschini
153 b705c7a6 Manuel Franceschini
class Hostname:
154 b705c7a6 Manuel Franceschini
  """Class implementing resolver and hostname functionality.
155 a744b676 Manuel Franceschini

156 a744b676 Manuel Franceschini
  """
157 e7b3ad26 Manuel Franceschini
  _VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$")
158 e7b3ad26 Manuel Franceschini
159 b705c7a6 Manuel Franceschini
  def __init__(self, name=None, family=None):
160 a744b676 Manuel Franceschini
    """Initialize the host name object.
161 a744b676 Manuel Franceschini

162 b705c7a6 Manuel Franceschini
    If the name argument is None, it will use this system's name.
163 b705c7a6 Manuel Franceschini

164 b705c7a6 Manuel Franceschini
    @type family: int
165 b705c7a6 Manuel Franceschini
    @param family: AF_INET | AF_INET6 | None
166 b705c7a6 Manuel Franceschini
    @type name: str
167 b705c7a6 Manuel Franceschini
    @param name: hostname or None
168 a744b676 Manuel Franceschini

169 a744b676 Manuel Franceschini
    """
170 f3044516 Manuel Franceschini
    self.name = self.GetNormalizedName(self.GetFqdn(name))
171 b705c7a6 Manuel Franceschini
    self.ip = self.GetIP(self.name, family=family)
172 a744b676 Manuel Franceschini
173 f3044516 Manuel Franceschini
  @classmethod
174 f3044516 Manuel Franceschini
  def GetSysName(cls):
175 f3044516 Manuel Franceschini
    """Legacy method the get the current system's name.
176 f3044516 Manuel Franceschini

177 f3044516 Manuel Franceschini
    """
178 f3044516 Manuel Franceschini
    return cls.GetFqdn()
179 f3044516 Manuel Franceschini
180 a744b676 Manuel Franceschini
  @staticmethod
181 f3044516 Manuel Franceschini
  def GetFqdn(hostname=None):
182 f3044516 Manuel Franceschini
    """Return fqdn.
183 f3044516 Manuel Franceschini

184 f3044516 Manuel Franceschini
    If hostname is None the system's fqdn is returned.
185 a744b676 Manuel Franceschini

186 f3044516 Manuel Franceschini
    @type hostname: str
187 f3044516 Manuel Franceschini
    @param hostname: name to be fqdn'ed
188 f3044516 Manuel Franceschini
    @rtype: str
189 f3044516 Manuel Franceschini
    @return: fqdn of given name, if it exists, unmodified name otherwise
190 a744b676 Manuel Franceschini

191 a744b676 Manuel Franceschini
    """
192 f3044516 Manuel Franceschini
    if hostname is None:
193 e91b297c Michael Hanselmann
      virtfqdn = vcluster.GetVirtualHostname()
194 e91b297c Michael Hanselmann
      if virtfqdn:
195 e91b297c Michael Hanselmann
        return virtfqdn
196 e91b297c Michael Hanselmann
      else:
197 e91b297c Michael Hanselmann
        return socket.getfqdn()
198 f3044516 Manuel Franceschini
    else:
199 f3044516 Manuel Franceschini
      return socket.getfqdn(hostname)
200 a744b676 Manuel Franceschini
201 a744b676 Manuel Franceschini
  @staticmethod
202 b705c7a6 Manuel Franceschini
  def GetIP(hostname, family=None):
203 b705c7a6 Manuel Franceschini
    """Return IP address of given hostname.
204 b705c7a6 Manuel Franceschini

205 b705c7a6 Manuel Franceschini
    Supports both IPv4 and IPv6.
206 a744b676 Manuel Franceschini

207 a744b676 Manuel Franceschini
    @type hostname: str
208 a744b676 Manuel Franceschini
    @param hostname: hostname to look up
209 b705c7a6 Manuel Franceschini
    @type family: int
210 b705c7a6 Manuel Franceschini
    @param family: AF_INET | AF_INET6 | None
211 b705c7a6 Manuel Franceschini
    @rtype: str
212 b705c7a6 Manuel Franceschini
    @return: IP address
213 a744b676 Manuel Franceschini
    @raise errors.ResolverError: in case of errors in resolving
214 a744b676 Manuel Franceschini

215 a744b676 Manuel Franceschini
    """
216 a744b676 Manuel Franceschini
    try:
217 b705c7a6 Manuel Franceschini
      if family in (socket.AF_INET, socket.AF_INET6):
218 b705c7a6 Manuel Franceschini
        result = socket.getaddrinfo(hostname, None, family)
219 b705c7a6 Manuel Franceschini
      else:
220 b43dcc5a Manuel Franceschini
        result = socket.getaddrinfo(hostname, None)
221 a744b676 Manuel Franceschini
    except (socket.gaierror, socket.herror, socket.error), err:
222 a744b676 Manuel Franceschini
      # hostname not found in DNS, or other socket exception in the
223 a744b676 Manuel Franceschini
      # (code, description format)
224 a744b676 Manuel Franceschini
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
225 a744b676 Manuel Franceschini
226 b705c7a6 Manuel Franceschini
    # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
227 b705c7a6 Manuel Franceschini
    # canonname, sockaddr). We return the first tuple's first address in
228 b705c7a6 Manuel Franceschini
    # sockaddr
229 e7b3ad26 Manuel Franceschini
    try:
230 e7b3ad26 Manuel Franceschini
      return result[0][4][0]
231 e7b3ad26 Manuel Franceschini
    except IndexError, err:
232 e7b3ad26 Manuel Franceschini
      raise errors.ResolverError("Unknown error in getaddrinfo(): %s" % err)
233 a744b676 Manuel Franceschini
234 e7b3ad26 Manuel Franceschini
  @classmethod
235 e7b3ad26 Manuel Franceschini
  def GetNormalizedName(cls, hostname):
236 a744b676 Manuel Franceschini
    """Validate and normalize the given hostname.
237 a744b676 Manuel Franceschini

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

242 a744b676 Manuel Franceschini
    """
243 a744b676 Manuel Franceschini
    hostname = hostname.lower()
244 e7b3ad26 Manuel Franceschini
    if (not cls._VALID_NAME_RE.match(hostname) or
245 a744b676 Manuel Franceschini
        # double-dots, meaning empty label
246 a744b676 Manuel Franceschini
        ".." in hostname or
247 a744b676 Manuel Franceschini
        # empty initial label
248 a744b676 Manuel Franceschini
        hostname.startswith(".")):
249 a744b676 Manuel Franceschini
      raise errors.OpPrereqError("Invalid hostname '%s'" % hostname,
250 a744b676 Manuel Franceschini
                                 errors.ECODE_INVAL)
251 a744b676 Manuel Franceschini
    if hostname.endswith("."):
252 a744b676 Manuel Franceschini
      hostname = hostname.rstrip(".")
253 a744b676 Manuel Franceschini
    return hostname
254 a744b676 Manuel Franceschini
255 a744b676 Manuel Franceschini
256 a744b676 Manuel Franceschini
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
257 a744b676 Manuel Franceschini
  """Simple ping implementation using TCP connect(2).
258 a744b676 Manuel Franceschini

259 a744b676 Manuel Franceschini
  Check if the given IP is reachable by doing attempting a TCP connect
260 a744b676 Manuel Franceschini
  to it.
261 a744b676 Manuel Franceschini

262 a744b676 Manuel Franceschini
  @type target: str
263 77b02a99 René Nussbaumer
  @param target: the IP to ping
264 a744b676 Manuel Franceschini
  @type port: int
265 a744b676 Manuel Franceschini
  @param port: the port to connect to
266 a744b676 Manuel Franceschini
  @type timeout: int
267 a744b676 Manuel Franceschini
  @param timeout: the timeout on the connection attempt
268 a744b676 Manuel Franceschini
  @type live_port_needed: boolean
269 a744b676 Manuel Franceschini
  @param live_port_needed: whether a closed port will cause the
270 a744b676 Manuel Franceschini
      function to return failure, as if there was a timeout
271 a744b676 Manuel Franceschini
  @type source: str or None
272 a744b676 Manuel Franceschini
  @param source: if specified, will cause the connect to be made
273 a744b676 Manuel Franceschini
      from this specific source address; failures to bind other
274 a744b676 Manuel Franceschini
      than C{EADDRNOTAVAIL} will be ignored
275 a744b676 Manuel Franceschini

276 a744b676 Manuel Franceschini
  """
277 a744b676 Manuel Franceschini
  try:
278 8b312c1d Manuel Franceschini
    family = IPAddress.GetAddressFamily(target)
279 a744b676 Manuel Franceschini
  except errors.GenericError:
280 a744b676 Manuel Franceschini
    return False
281 a744b676 Manuel Franceschini
282 a744b676 Manuel Franceschini
  sock = socket.socket(family, socket.SOCK_STREAM)
283 a744b676 Manuel Franceschini
  success = False
284 a744b676 Manuel Franceschini
285 a744b676 Manuel Franceschini
  if source is not None:
286 a744b676 Manuel Franceschini
    try:
287 a744b676 Manuel Franceschini
      sock.bind((source, 0))
288 8ad0da1e Iustin Pop
    except socket.error, err:
289 8ad0da1e Iustin Pop
      if err[0] == errno.EADDRNOTAVAIL:
290 a744b676 Manuel Franceschini
        success = False
291 a744b676 Manuel Franceschini
292 a744b676 Manuel Franceschini
  sock.settimeout(timeout)
293 a744b676 Manuel Franceschini
294 a744b676 Manuel Franceschini
  try:
295 a744b676 Manuel Franceschini
    sock.connect((target, port))
296 a744b676 Manuel Franceschini
    sock.close()
297 a744b676 Manuel Franceschini
    success = True
298 a744b676 Manuel Franceschini
  except socket.timeout:
299 a744b676 Manuel Franceschini
    success = False
300 8ad0da1e Iustin Pop
  except socket.error, err:
301 8ad0da1e Iustin Pop
    success = (not live_port_needed) and (err[0] == errno.ECONNREFUSED)
302 a744b676 Manuel Franceschini
303 a744b676 Manuel Franceschini
  return success
304 a744b676 Manuel Franceschini
305 a744b676 Manuel Franceschini
306 a744b676 Manuel Franceschini
def GetDaemonPort(daemon_name):
307 a744b676 Manuel Franceschini
  """Get the daemon port for this cluster.
308 a744b676 Manuel Franceschini

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

313 a744b676 Manuel Franceschini
  @type daemon_name: string
314 a744b676 Manuel Franceschini
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
315 a744b676 Manuel Franceschini
  @rtype: int
316 a744b676 Manuel Franceschini

317 a744b676 Manuel Franceschini
  """
318 a744b676 Manuel Franceschini
  if daemon_name not in constants.DAEMONS_PORTS:
319 a744b676 Manuel Franceschini
    raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name)
320 a744b676 Manuel Franceschini
321 a744b676 Manuel Franceschini
  (proto, default_port) = constants.DAEMONS_PORTS[daemon_name]
322 a744b676 Manuel Franceschini
  try:
323 a744b676 Manuel Franceschini
    port = socket.getservbyname(daemon_name, proto)
324 a744b676 Manuel Franceschini
  except socket.error:
325 a744b676 Manuel Franceschini
    port = default_port
326 a744b676 Manuel Franceschini
327 a744b676 Manuel Franceschini
  return port
328 8b312c1d Manuel Franceschini
329 8b312c1d Manuel Franceschini
330 8b312c1d Manuel Franceschini
class IPAddress(object):
331 8b312c1d Manuel Franceschini
  """Class that represents an IP address.
332 8b312c1d Manuel Franceschini

333 8b312c1d Manuel Franceschini
  """
334 8b312c1d Manuel Franceschini
  iplen = 0
335 8b312c1d Manuel Franceschini
  family = None
336 8b312c1d Manuel Franceschini
  loopback_cidr = None
337 8b312c1d Manuel Franceschini
338 8b312c1d Manuel Franceschini
  @staticmethod
339 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
340 8b312c1d Manuel Franceschini
    """Abstract method to please pylint.
341 8b312c1d Manuel Franceschini

342 8b312c1d Manuel Franceschini
    """
343 8b312c1d Manuel Franceschini
    raise NotImplementedError
344 8b312c1d Manuel Franceschini
345 8b312c1d Manuel Franceschini
  @classmethod
346 8b312c1d Manuel Franceschini
  def IsValid(cls, address):
347 8b312c1d Manuel Franceschini
    """Validate a IP address.
348 8b312c1d Manuel Franceschini

349 8b312c1d Manuel Franceschini
    @type address: str
350 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
351 8b312c1d Manuel Franceschini
    @rtype: bool
352 8b312c1d Manuel Franceschini
    @return: True if valid, False otherwise
353 8b312c1d Manuel Franceschini

354 8b312c1d Manuel Franceschini
    """
355 8b312c1d Manuel Franceschini
    if cls.family is None:
356 8b312c1d Manuel Franceschini
      try:
357 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
358 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
359 8b312c1d Manuel Franceschini
        return False
360 8b312c1d Manuel Franceschini
    else:
361 8b312c1d Manuel Franceschini
      family = cls.family
362 8b312c1d Manuel Franceschini
363 8b312c1d Manuel Franceschini
    try:
364 8b312c1d Manuel Franceschini
      socket.inet_pton(family, address)
365 8b312c1d Manuel Franceschini
      return True
366 8b312c1d Manuel Franceschini
    except socket.error:
367 8b312c1d Manuel Franceschini
      return False
368 8b312c1d Manuel Franceschini
369 8b312c1d Manuel Franceschini
  @classmethod
370 7df2c4f0 Andrea Spadaccini
  def ValidateNetmask(cls, netmask):
371 7df2c4f0 Andrea Spadaccini
    """Validate a netmask suffix in CIDR notation.
372 7df2c4f0 Andrea Spadaccini

373 7df2c4f0 Andrea Spadaccini
    @type netmask: int
374 7df2c4f0 Andrea Spadaccini
    @param netmask: netmask suffix to validate
375 7df2c4f0 Andrea Spadaccini
    @rtype: bool
376 7df2c4f0 Andrea Spadaccini
    @return: True if valid, False otherwise
377 7df2c4f0 Andrea Spadaccini

378 7df2c4f0 Andrea Spadaccini
    """
379 7df2c4f0 Andrea Spadaccini
    assert (isinstance(netmask, (int, long)))
380 7df2c4f0 Andrea Spadaccini
381 7df2c4f0 Andrea Spadaccini
    return 0 < netmask <= cls.iplen
382 7df2c4f0 Andrea Spadaccini
383 7df2c4f0 Andrea Spadaccini
  @classmethod
384 8b312c1d Manuel Franceschini
  def Own(cls, address):
385 8b312c1d Manuel Franceschini
    """Check if the current host has the the given IP address.
386 8b312c1d Manuel Franceschini

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

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

395 8b312c1d Manuel Franceschini
    """
396 8b312c1d Manuel Franceschini
    if cls.family is None:
397 8b312c1d Manuel Franceschini
      try:
398 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
399 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
400 8b312c1d Manuel Franceschini
        return False
401 8b312c1d Manuel Franceschini
    else:
402 8b312c1d Manuel Franceschini
      family = cls.family
403 8b312c1d Manuel Franceschini
404 8b312c1d Manuel Franceschini
    s = socket.socket(family, socket.SOCK_DGRAM)
405 8b312c1d Manuel Franceschini
    success = False
406 8b312c1d Manuel Franceschini
    try:
407 8b312c1d Manuel Franceschini
      try:
408 8b312c1d Manuel Franceschini
        s.bind((address, 0))
409 8b312c1d Manuel Franceschini
        success = True
410 8b312c1d Manuel Franceschini
      except socket.error:
411 8b312c1d Manuel Franceschini
        success = False
412 8b312c1d Manuel Franceschini
    finally:
413 8b312c1d Manuel Franceschini
      s.close()
414 8b312c1d Manuel Franceschini
    return success
415 8b312c1d Manuel Franceschini
416 8b312c1d Manuel Franceschini
  @classmethod
417 8b312c1d Manuel Franceschini
  def InNetwork(cls, cidr, address):
418 8b312c1d Manuel Franceschini
    """Determine whether an address is within a network.
419 8b312c1d Manuel Franceschini

420 8b312c1d Manuel Franceschini
    @type cidr: string
421 8b312c1d Manuel Franceschini
    @param cidr: Network in CIDR notation, e.g. '192.0.2.0/24', '2001:db8::/64'
422 8b312c1d Manuel Franceschini
    @type address: str
423 8b312c1d Manuel Franceschini
    @param address: IP address
424 8b312c1d Manuel Franceschini
    @rtype: bool
425 8b312c1d Manuel Franceschini
    @return: True if address is in cidr, False otherwise
426 8b312c1d Manuel Franceschini

427 8b312c1d Manuel Franceschini
    """
428 8b312c1d Manuel Franceschini
    address_int = cls._GetIPIntFromString(address)
429 8b312c1d Manuel Franceschini
    subnet = cidr.split("/")
430 8b312c1d Manuel Franceschini
    assert len(subnet) == 2
431 8b312c1d Manuel Franceschini
    try:
432 8b312c1d Manuel Franceschini
      prefix = int(subnet[1])
433 8b312c1d Manuel Franceschini
    except ValueError:
434 8b312c1d Manuel Franceschini
      return False
435 8b312c1d Manuel Franceschini
436 8b312c1d Manuel Franceschini
    assert 0 <= prefix <= cls.iplen
437 8b312c1d Manuel Franceschini
    target_int = cls._GetIPIntFromString(subnet[0])
438 8b312c1d Manuel Franceschini
    # Convert prefix netmask to integer value of netmask
439 e687ec01 Michael Hanselmann
    netmask_int = (2 ** cls.iplen) - 1 ^ ((2 ** cls.iplen) - 1 >> prefix)
440 8b312c1d Manuel Franceschini
    # Calculate hostmask
441 e687ec01 Michael Hanselmann
    hostmask_int = netmask_int ^ (2 ** cls.iplen) - 1
442 8b312c1d Manuel Franceschini
    # Calculate network address by and'ing netmask
443 8b312c1d Manuel Franceschini
    network_int = target_int & netmask_int
444 8b312c1d Manuel Franceschini
    # Calculate broadcast address by or'ing hostmask
445 8b312c1d Manuel Franceschini
    broadcast_int = target_int | hostmask_int
446 8b312c1d Manuel Franceschini
447 8b312c1d Manuel Franceschini
    return network_int <= address_int <= broadcast_int
448 8b312c1d Manuel Franceschini
449 8b312c1d Manuel Franceschini
  @staticmethod
450 8b312c1d Manuel Franceschini
  def GetAddressFamily(address):
451 8b312c1d Manuel Franceschini
    """Get the address family of the given address.
452 8b312c1d Manuel Franceschini

453 8b312c1d Manuel Franceschini
    @type address: str
454 8b312c1d Manuel Franceschini
    @param address: ip address whose family will be returned
455 8b312c1d Manuel Franceschini
    @rtype: int
456 37531236 Andrea Spadaccini
    @return: C{socket.AF_INET} or C{socket.AF_INET6}
457 8b312c1d Manuel Franceschini
    @raise errors.GenericError: for invalid addresses
458 8b312c1d Manuel Franceschini

459 8b312c1d Manuel Franceschini
    """
460 8b312c1d Manuel Franceschini
    try:
461 8b312c1d Manuel Franceschini
      return IP4Address(address).family
462 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
463 8b312c1d Manuel Franceschini
      pass
464 8b312c1d Manuel Franceschini
465 8b312c1d Manuel Franceschini
    try:
466 8b312c1d Manuel Franceschini
      return IP6Address(address).family
467 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
468 8b312c1d Manuel Franceschini
      pass
469 8b312c1d Manuel Franceschini
470 8b312c1d Manuel Franceschini
    raise errors.IPAddressError("Invalid address '%s'" % address)
471 8b312c1d Manuel Franceschini
472 37531236 Andrea Spadaccini
  @staticmethod
473 37531236 Andrea Spadaccini
  def GetVersionFromAddressFamily(family):
474 37531236 Andrea Spadaccini
    """Convert an IP address family to the corresponding IP version.
475 37531236 Andrea Spadaccini

476 37531236 Andrea Spadaccini
    @type family: int
477 37531236 Andrea Spadaccini
    @param family: IP address family, one of socket.AF_INET or socket.AF_INET6
478 37531236 Andrea Spadaccini
    @return: an int containing the IP version, one of L{constants.IP4_VERSION}
479 37531236 Andrea Spadaccini
             or L{constants.IP6_VERSION}
480 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown families
481 37531236 Andrea Spadaccini

482 37531236 Andrea Spadaccini
    """
483 37531236 Andrea Spadaccini
    if family == socket.AF_INET:
484 37531236 Andrea Spadaccini
      return constants.IP4_VERSION
485 37531236 Andrea Spadaccini
    elif family == socket.AF_INET6:
486 37531236 Andrea Spadaccini
      return constants.IP6_VERSION
487 37531236 Andrea Spadaccini
488 37531236 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP address family" % family)
489 37531236 Andrea Spadaccini
490 37531236 Andrea Spadaccini
  @staticmethod
491 37531236 Andrea Spadaccini
  def GetAddressFamilyFromVersion(version):
492 37531236 Andrea Spadaccini
    """Convert an IP version to the corresponding IP address family.
493 37531236 Andrea Spadaccini

494 37531236 Andrea Spadaccini
    @type version: int
495 37531236 Andrea Spadaccini
    @param version: IP version, one of L{constants.IP4_VERSION} or
496 37531236 Andrea Spadaccini
                    L{constants.IP6_VERSION}
497 37531236 Andrea Spadaccini
    @return: an int containing the IP address family, one of C{socket.AF_INET}
498 37531236 Andrea Spadaccini
             or C{socket.AF_INET6}
499 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown IP versions
500 37531236 Andrea Spadaccini

501 37531236 Andrea Spadaccini
    """
502 37531236 Andrea Spadaccini
    if version == constants.IP4_VERSION:
503 37531236 Andrea Spadaccini
      return socket.AF_INET
504 37531236 Andrea Spadaccini
    elif version == constants.IP6_VERSION:
505 37531236 Andrea Spadaccini
      return socket.AF_INET6
506 37531236 Andrea Spadaccini
507 37531236 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP version" % version)
508 37531236 Andrea Spadaccini
509 7df2c4f0 Andrea Spadaccini
  @staticmethod
510 7df2c4f0 Andrea Spadaccini
  def GetClassFromIpVersion(version):
511 7df2c4f0 Andrea Spadaccini
    """Return the IPAddress subclass for the given IP version.
512 7df2c4f0 Andrea Spadaccini

513 7df2c4f0 Andrea Spadaccini
    @type version: int
514 7df2c4f0 Andrea Spadaccini
    @param version: IP version, one of L{constants.IP4_VERSION} or
515 7df2c4f0 Andrea Spadaccini
                    L{constants.IP6_VERSION}
516 7df2c4f0 Andrea Spadaccini
    @return: a subclass of L{netutils.IPAddress}
517 7df2c4f0 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknowo IP versions
518 7df2c4f0 Andrea Spadaccini

519 7df2c4f0 Andrea Spadaccini
    """
520 7df2c4f0 Andrea Spadaccini
    if version == constants.IP4_VERSION:
521 7df2c4f0 Andrea Spadaccini
      return IP4Address
522 7df2c4f0 Andrea Spadaccini
    elif version == constants.IP6_VERSION:
523 7df2c4f0 Andrea Spadaccini
      return IP6Address
524 7df2c4f0 Andrea Spadaccini
525 7df2c4f0 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP version" % version)
526 7df2c4f0 Andrea Spadaccini
527 7df2c4f0 Andrea Spadaccini
  @staticmethod
528 7df2c4f0 Andrea Spadaccini
  def GetClassFromIpFamily(family):
529 7df2c4f0 Andrea Spadaccini
    """Return the IPAddress subclass for the given IP family.
530 7df2c4f0 Andrea Spadaccini

531 7df2c4f0 Andrea Spadaccini
    @param family: IP family (one of C{socket.AF_INET} or C{socket.AF_INET6}
532 7df2c4f0 Andrea Spadaccini
    @return: a subclass of L{netutils.IPAddress}
533 7df2c4f0 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknowo IP versions
534 7df2c4f0 Andrea Spadaccini

535 7df2c4f0 Andrea Spadaccini
    """
536 7df2c4f0 Andrea Spadaccini
    return IPAddress.GetClassFromIpVersion(
537 7df2c4f0 Andrea Spadaccini
              IPAddress.GetVersionFromAddressFamily(family))
538 7df2c4f0 Andrea Spadaccini
539 8b312c1d Manuel Franceschini
  @classmethod
540 8b312c1d Manuel Franceschini
  def IsLoopback(cls, address):
541 8b312c1d Manuel Franceschini
    """Determine whether it is a loopback address.
542 8b312c1d Manuel Franceschini

543 8b312c1d Manuel Franceschini
    @type address: str
544 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
545 8b312c1d Manuel Franceschini
    @rtype: bool
546 8b312c1d Manuel Franceschini
    @return: True if loopback, False otherwise
547 8b312c1d Manuel Franceschini

548 8b312c1d Manuel Franceschini
    """
549 8b312c1d Manuel Franceschini
    try:
550 8b312c1d Manuel Franceschini
      return cls.InNetwork(cls.loopback_cidr, address)
551 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
552 8b312c1d Manuel Franceschini
      return False
553 8b312c1d Manuel Franceschini
554 8b312c1d Manuel Franceschini
555 8b312c1d Manuel Franceschini
class IP4Address(IPAddress):
556 8b312c1d Manuel Franceschini
  """IPv4 address class.
557 8b312c1d Manuel Franceschini

558 8b312c1d Manuel Franceschini
  """
559 8b312c1d Manuel Franceschini
  iplen = 32
560 8b312c1d Manuel Franceschini
  family = socket.AF_INET
561 8b312c1d Manuel Franceschini
  loopback_cidr = "127.0.0.0/8"
562 8b312c1d Manuel Franceschini
563 8b312c1d Manuel Franceschini
  def __init__(self, address):
564 8b312c1d Manuel Franceschini
    """Constructor for IPv4 address.
565 8b312c1d Manuel Franceschini

566 8b312c1d Manuel Franceschini
    @type address: str
567 8b312c1d Manuel Franceschini
    @param address: IP address
568 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
569 8b312c1d Manuel Franceschini

570 8b312c1d Manuel Franceschini
    """
571 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
572 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
573 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv4 Address %s invalid" % address)
574 8b312c1d Manuel Franceschini
575 8b312c1d Manuel Franceschini
    self.address = address
576 8b312c1d Manuel Franceschini
577 8b312c1d Manuel Franceschini
  @staticmethod
578 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
579 8b312c1d Manuel Franceschini
    """Get integer value of IPv4 address.
580 8b312c1d Manuel Franceschini

581 8b312c1d Manuel Franceschini
    @type address: str
582 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
583 8b312c1d Manuel Franceschini
    @rtype: int
584 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
585 8b312c1d Manuel Franceschini

586 8b312c1d Manuel Franceschini
    """
587 8b312c1d Manuel Franceschini
    address_int = 0
588 8b312c1d Manuel Franceschini
    parts = address.split(".")
589 8b312c1d Manuel Franceschini
    assert len(parts) == 4
590 8b312c1d Manuel Franceschini
    for part in parts:
591 8b312c1d Manuel Franceschini
      address_int = (address_int << 8) | int(part)
592 8b312c1d Manuel Franceschini
593 8b312c1d Manuel Franceschini
    return address_int
594 8b312c1d Manuel Franceschini
595 8b312c1d Manuel Franceschini
596 8b312c1d Manuel Franceschini
class IP6Address(IPAddress):
597 8b312c1d Manuel Franceschini
  """IPv6 address class.
598 8b312c1d Manuel Franceschini

599 8b312c1d Manuel Franceschini
  """
600 8b312c1d Manuel Franceschini
  iplen = 128
601 8b312c1d Manuel Franceschini
  family = socket.AF_INET6
602 8b312c1d Manuel Franceschini
  loopback_cidr = "::1/128"
603 8b312c1d Manuel Franceschini
604 8b312c1d Manuel Franceschini
  def __init__(self, address):
605 8b312c1d Manuel Franceschini
    """Constructor for IPv6 address.
606 8b312c1d Manuel Franceschini

607 8b312c1d Manuel Franceschini
    @type address: str
608 8b312c1d Manuel Franceschini
    @param address: IP address
609 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
610 8b312c1d Manuel Franceschini

611 8b312c1d Manuel Franceschini
    """
612 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
613 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
614 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv6 Address [%s] invalid" % address)
615 8b312c1d Manuel Franceschini
    self.address = address
616 8b312c1d Manuel Franceschini
617 8b312c1d Manuel Franceschini
  @staticmethod
618 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
619 8b312c1d Manuel Franceschini
    """Get integer value of IPv6 address.
620 8b312c1d Manuel Franceschini

621 8b312c1d Manuel Franceschini
    @type address: str
622 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
623 8b312c1d Manuel Franceschini
    @rtype: int
624 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
625 8b312c1d Manuel Franceschini

626 8b312c1d Manuel Franceschini
    """
627 8b312c1d Manuel Franceschini
    doublecolons = address.count("::")
628 8b312c1d Manuel Franceschini
    assert not doublecolons > 1
629 8b312c1d Manuel Franceschini
    if doublecolons == 1:
630 8b312c1d Manuel Franceschini
      # We have a shorthand address, expand it
631 8b312c1d Manuel Franceschini
      parts = []
632 8b312c1d Manuel Franceschini
      twoparts = address.split("::")
633 d0c8c01d Iustin Pop
      sep = len(twoparts[0].split(":")) + len(twoparts[1].split(":"))
634 d0c8c01d Iustin Pop
      parts = twoparts[0].split(":")
635 17385bd2 Andrea Spadaccini
      parts.extend(["0"] * (8 - sep))
636 d0c8c01d Iustin Pop
      parts += twoparts[1].split(":")
637 8b312c1d Manuel Franceschini
    else:
638 8b312c1d Manuel Franceschini
      parts = address.split(":")
639 8b312c1d Manuel Franceschini
640 8b312c1d Manuel Franceschini
    address_int = 0
641 8b312c1d Manuel Franceschini
    for part in parts:
642 d0c8c01d Iustin Pop
      address_int = (address_int << 16) + int(part or "0", 16)
643 8b312c1d Manuel Franceschini
644 8b312c1d Manuel Franceschini
    return address_int
645 1a8337f2 Manuel Franceschini
646 7845b8c8 Manuel Franceschini
647 981732fb Manuel Franceschini
def FormatAddress(address, family=None):
648 1a8337f2 Manuel Franceschini
  """Format a socket address
649 1a8337f2 Manuel Franceschini

650 1a8337f2 Manuel Franceschini
  @type address: family specific (usually tuple)
651 1a8337f2 Manuel Franceschini
  @param address: address, as reported by this class
652 981732fb Manuel Franceschini
  @type family: integer
653 981732fb Manuel Franceschini
  @param family: socket family (one of socket.AF_*) or None
654 1a8337f2 Manuel Franceschini

655 1a8337f2 Manuel Franceschini
  """
656 981732fb Manuel Franceschini
  if family is None:
657 981732fb Manuel Franceschini
    try:
658 981732fb Manuel Franceschini
      family = IPAddress.GetAddressFamily(address[0])
659 981732fb Manuel Franceschini
    except errors.IPAddressError:
660 981732fb Manuel Franceschini
      raise errors.ParameterError(address)
661 981732fb Manuel Franceschini
662 1a8337f2 Manuel Franceschini
  if family == socket.AF_UNIX and len(address) == 3:
663 1a8337f2 Manuel Franceschini
    return "pid=%s, uid=%s, gid=%s" % address
664 1a8337f2 Manuel Franceschini
665 1a8337f2 Manuel Franceschini
  if family in (socket.AF_INET, socket.AF_INET6) and len(address) == 2:
666 1a8337f2 Manuel Franceschini
    host, port = address
667 1a8337f2 Manuel Franceschini
    if family == socket.AF_INET6:
668 1a8337f2 Manuel Franceschini
      res = "[%s]" % host
669 1a8337f2 Manuel Franceschini
    else:
670 1a8337f2 Manuel Franceschini
      res = host
671 1a8337f2 Manuel Franceschini
672 1a8337f2 Manuel Franceschini
    if port is not None:
673 1a8337f2 Manuel Franceschini
      res += ":%s" % port
674 1a8337f2 Manuel Franceschini
675 1a8337f2 Manuel Franceschini
    return res
676 1a8337f2 Manuel Franceschini
677 1a8337f2 Manuel Franceschini
  raise errors.ParameterError(family, address)