Statistics
| Branch: | Tag: | Revision:

root / lib / netutils.py @ 1a2eb2dc

History | View | Annotate | Download (18.6 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 39d1744a Iustin Pop
      # we don't have here an actual error code, it's just that the
233 39d1744a Iustin Pop
      # data type returned by getaddrinfo is not what we expected;
234 39d1744a Iustin Pop
      # let's keep the same format in the exception arguments with a
235 39d1744a Iustin Pop
      # dummy error code
236 39d1744a Iustin Pop
      raise errors.ResolverError(hostname, 0,
237 39d1744a Iustin Pop
                                 "Unknown error in getaddrinfo(): %s" % err)
238 a744b676 Manuel Franceschini
239 e7b3ad26 Manuel Franceschini
  @classmethod
240 e7b3ad26 Manuel Franceschini
  def GetNormalizedName(cls, hostname):
241 a744b676 Manuel Franceschini
    """Validate and normalize the given hostname.
242 a744b676 Manuel Franceschini

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

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

264 a744b676 Manuel Franceschini
  Check if the given IP is reachable by doing attempting a TCP connect
265 a744b676 Manuel Franceschini
  to it.
266 a744b676 Manuel Franceschini

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

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

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

318 a744b676 Manuel Franceschini
  @type daemon_name: string
319 a744b676 Manuel Franceschini
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
320 a744b676 Manuel Franceschini
  @rtype: int
321 a744b676 Manuel Franceschini

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

338 8b312c1d Manuel Franceschini
  """
339 8b312c1d Manuel Franceschini
  iplen = 0
340 8b312c1d Manuel Franceschini
  family = None
341 8b312c1d Manuel Franceschini
  loopback_cidr = None
342 8b312c1d Manuel Franceschini
343 8b312c1d Manuel Franceschini
  @staticmethod
344 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
345 8b312c1d Manuel Franceschini
    """Abstract method to please pylint.
346 8b312c1d Manuel Franceschini

347 8b312c1d Manuel Franceschini
    """
348 8b312c1d Manuel Franceschini
    raise NotImplementedError
349 8b312c1d Manuel Franceschini
350 8b312c1d Manuel Franceschini
  @classmethod
351 8b312c1d Manuel Franceschini
  def IsValid(cls, address):
352 8b312c1d Manuel Franceschini
    """Validate a IP address.
353 8b312c1d Manuel Franceschini

354 8b312c1d Manuel Franceschini
    @type address: str
355 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
356 8b312c1d Manuel Franceschini
    @rtype: bool
357 8b312c1d Manuel Franceschini
    @return: True if valid, False otherwise
358 8b312c1d Manuel Franceschini

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

378 7df2c4f0 Andrea Spadaccini
    @type netmask: int
379 7df2c4f0 Andrea Spadaccini
    @param netmask: netmask suffix to validate
380 7df2c4f0 Andrea Spadaccini
    @rtype: bool
381 7df2c4f0 Andrea Spadaccini
    @return: True if valid, False otherwise
382 7df2c4f0 Andrea Spadaccini

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

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

395 8b312c1d Manuel Franceschini
    @type address: str
396 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
397 8b312c1d Manuel Franceschini
    @rtype: bool
398 8b312c1d Manuel Franceschini
    @return: True if we own the address, False otherwise
399 8b312c1d Manuel Franceschini

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

425 8b312c1d Manuel Franceschini
    @type cidr: string
426 8b312c1d Manuel Franceschini
    @param cidr: Network in CIDR notation, e.g. '192.0.2.0/24', '2001:db8::/64'
427 8b312c1d Manuel Franceschini
    @type address: str
428 8b312c1d Manuel Franceschini
    @param address: IP address
429 8b312c1d Manuel Franceschini
    @rtype: bool
430 8b312c1d Manuel Franceschini
    @return: True if address is in cidr, False otherwise
431 8b312c1d Manuel Franceschini

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

458 8b312c1d Manuel Franceschini
    @type address: str
459 8b312c1d Manuel Franceschini
    @param address: ip address whose family will be returned
460 8b312c1d Manuel Franceschini
    @rtype: int
461 37531236 Andrea Spadaccini
    @return: C{socket.AF_INET} or C{socket.AF_INET6}
462 8b312c1d Manuel Franceschini
    @raise errors.GenericError: for invalid addresses
463 8b312c1d Manuel Franceschini

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

481 37531236 Andrea Spadaccini
    @type family: int
482 37531236 Andrea Spadaccini
    @param family: IP address family, one of socket.AF_INET or socket.AF_INET6
483 37531236 Andrea Spadaccini
    @return: an int containing the IP version, one of L{constants.IP4_VERSION}
484 37531236 Andrea Spadaccini
             or L{constants.IP6_VERSION}
485 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown families
486 37531236 Andrea Spadaccini

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

499 37531236 Andrea Spadaccini
    @type version: int
500 37531236 Andrea Spadaccini
    @param version: IP version, one of L{constants.IP4_VERSION} or
501 37531236 Andrea Spadaccini
                    L{constants.IP6_VERSION}
502 37531236 Andrea Spadaccini
    @return: an int containing the IP address family, one of C{socket.AF_INET}
503 37531236 Andrea Spadaccini
             or C{socket.AF_INET6}
504 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown IP versions
505 37531236 Andrea Spadaccini

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

518 7df2c4f0 Andrea Spadaccini
    @type version: int
519 7df2c4f0 Andrea Spadaccini
    @param version: IP version, one of L{constants.IP4_VERSION} or
520 7df2c4f0 Andrea Spadaccini
                    L{constants.IP6_VERSION}
521 7df2c4f0 Andrea Spadaccini
    @return: a subclass of L{netutils.IPAddress}
522 7df2c4f0 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknowo IP versions
523 7df2c4f0 Andrea Spadaccini

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

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

540 7df2c4f0 Andrea Spadaccini
    """
541 7df2c4f0 Andrea Spadaccini
    return IPAddress.GetClassFromIpVersion(
542 7df2c4f0 Andrea Spadaccini
              IPAddress.GetVersionFromAddressFamily(family))
543 7df2c4f0 Andrea Spadaccini
544 8b312c1d Manuel Franceschini
  @classmethod
545 8b312c1d Manuel Franceschini
  def IsLoopback(cls, address):
546 8b312c1d Manuel Franceschini
    """Determine whether it is a loopback address.
547 8b312c1d Manuel Franceschini

548 8b312c1d Manuel Franceschini
    @type address: str
549 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
550 8b312c1d Manuel Franceschini
    @rtype: bool
551 8b312c1d Manuel Franceschini
    @return: True if loopback, False otherwise
552 8b312c1d Manuel Franceschini

553 8b312c1d Manuel Franceschini
    """
554 8b312c1d Manuel Franceschini
    try:
555 8b312c1d Manuel Franceschini
      return cls.InNetwork(cls.loopback_cidr, address)
556 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
557 8b312c1d Manuel Franceschini
      return False
558 8b312c1d Manuel Franceschini
559 8b312c1d Manuel Franceschini
560 8b312c1d Manuel Franceschini
class IP4Address(IPAddress):
561 8b312c1d Manuel Franceschini
  """IPv4 address class.
562 8b312c1d Manuel Franceschini

563 8b312c1d Manuel Franceschini
  """
564 8b312c1d Manuel Franceschini
  iplen = 32
565 8b312c1d Manuel Franceschini
  family = socket.AF_INET
566 8b312c1d Manuel Franceschini
  loopback_cidr = "127.0.0.0/8"
567 8b312c1d Manuel Franceschini
568 8b312c1d Manuel Franceschini
  def __init__(self, address):
569 8b312c1d Manuel Franceschini
    """Constructor for IPv4 address.
570 8b312c1d Manuel Franceschini

571 8b312c1d Manuel Franceschini
    @type address: str
572 8b312c1d Manuel Franceschini
    @param address: IP address
573 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
574 8b312c1d Manuel Franceschini

575 8b312c1d Manuel Franceschini
    """
576 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
577 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
578 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv4 Address %s invalid" % address)
579 8b312c1d Manuel Franceschini
580 8b312c1d Manuel Franceschini
    self.address = address
581 8b312c1d Manuel Franceschini
582 8b312c1d Manuel Franceschini
  @staticmethod
583 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
584 8b312c1d Manuel Franceschini
    """Get integer value of IPv4 address.
585 8b312c1d Manuel Franceschini

586 8b312c1d Manuel Franceschini
    @type address: str
587 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
588 8b312c1d Manuel Franceschini
    @rtype: int
589 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
590 8b312c1d Manuel Franceschini

591 8b312c1d Manuel Franceschini
    """
592 8b312c1d Manuel Franceschini
    address_int = 0
593 8b312c1d Manuel Franceschini
    parts = address.split(".")
594 8b312c1d Manuel Franceschini
    assert len(parts) == 4
595 8b312c1d Manuel Franceschini
    for part in parts:
596 8b312c1d Manuel Franceschini
      address_int = (address_int << 8) | int(part)
597 8b312c1d Manuel Franceschini
598 8b312c1d Manuel Franceschini
    return address_int
599 8b312c1d Manuel Franceschini
600 8b312c1d Manuel Franceschini
601 8b312c1d Manuel Franceschini
class IP6Address(IPAddress):
602 8b312c1d Manuel Franceschini
  """IPv6 address class.
603 8b312c1d Manuel Franceschini

604 8b312c1d Manuel Franceschini
  """
605 8b312c1d Manuel Franceschini
  iplen = 128
606 8b312c1d Manuel Franceschini
  family = socket.AF_INET6
607 8b312c1d Manuel Franceschini
  loopback_cidr = "::1/128"
608 8b312c1d Manuel Franceschini
609 8b312c1d Manuel Franceschini
  def __init__(self, address):
610 8b312c1d Manuel Franceschini
    """Constructor for IPv6 address.
611 8b312c1d Manuel Franceschini

612 8b312c1d Manuel Franceschini
    @type address: str
613 8b312c1d Manuel Franceschini
    @param address: IP address
614 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
615 8b312c1d Manuel Franceschini

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

626 8b312c1d Manuel Franceschini
    @type address: str
627 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
628 8b312c1d Manuel Franceschini
    @rtype: int
629 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
630 8b312c1d Manuel Franceschini

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

655 1a8337f2 Manuel Franceschini
  @type address: family specific (usually tuple)
656 1a8337f2 Manuel Franceschini
  @param address: address, as reported by this class
657 981732fb Manuel Franceschini
  @type family: integer
658 981732fb Manuel Franceschini
  @param family: socket family (one of socket.AF_*) or None
659 1a8337f2 Manuel Franceschini

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