Statistics
| Branch: | Tag: | Revision:

root / lib / netutils.py @ 98dfcaff

History | View | Annotate | Download (16.9 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 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 a744b676 Manuel Franceschini
42 a744b676 Manuel Franceschini
# Structure definition for getsockopt(SOL_SOCKET, SO_PEERCRED, ...):
43 a744b676 Manuel Franceschini
# struct ucred { pid_t pid; uid_t uid; gid_t gid; };
44 a744b676 Manuel Franceschini
#
45 a744b676 Manuel Franceschini
# The GNU C Library defines gid_t and uid_t to be "unsigned int" and
46 a744b676 Manuel Franceschini
# pid_t to "int".
47 a744b676 Manuel Franceschini
#
48 a744b676 Manuel Franceschini
# IEEE Std 1003.1-2008:
49 a744b676 Manuel Franceschini
# "nlink_t, uid_t, gid_t, and id_t shall be integer types"
50 a744b676 Manuel Franceschini
# "blksize_t, pid_t, and ssize_t shall be signed integer types"
51 a744b676 Manuel Franceschini
_STRUCT_UCRED = "iII"
52 a744b676 Manuel Franceschini
_STRUCT_UCRED_SIZE = struct.calcsize(_STRUCT_UCRED)
53 a744b676 Manuel Franceschini
54 37531236 Andrea Spadaccini
# Regexes used to find IP addresses in the output of ip.
55 37531236 Andrea Spadaccini
_IP_RE_TEXT = r"[.:a-z0-9]+"      # separate for testing purposes
56 37531236 Andrea Spadaccini
_IP_FAMILY_RE = re.compile(r"(?P<family>inet6?)\s+(?P<ip>%s)/" % _IP_RE_TEXT,
57 37531236 Andrea Spadaccini
                           re.IGNORECASE)
58 37531236 Andrea Spadaccini
59 37531236 Andrea Spadaccini
# Dict used to convert from a string representing an IP family to an IP
60 37531236 Andrea Spadaccini
# version
61 e687ec01 Michael Hanselmann
_NAME_TO_IP_VER = {
62 37531236 Andrea Spadaccini
  "inet": constants.IP4_VERSION,
63 37531236 Andrea Spadaccini
  "inet6": constants.IP6_VERSION,
64 37531236 Andrea Spadaccini
  }
65 37531236 Andrea Spadaccini
66 37531236 Andrea Spadaccini
67 37531236 Andrea Spadaccini
def _GetIpAddressesFromIpOutput(ip_output):
68 37531236 Andrea Spadaccini
  """Parses the output of the ip command and retrieves the IP addresses and
69 37531236 Andrea Spadaccini
  version.
70 37531236 Andrea Spadaccini

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

190 a744b676 Manuel Franceschini
    """
191 f3044516 Manuel Franceschini
    if hostname is None:
192 f3044516 Manuel Franceschini
      return socket.getfqdn()
193 f3044516 Manuel Franceschini
    else:
194 f3044516 Manuel Franceschini
      return socket.getfqdn(hostname)
195 a744b676 Manuel Franceschini
196 a744b676 Manuel Franceschini
  @staticmethod
197 b705c7a6 Manuel Franceschini
  def GetIP(hostname, family=None):
198 b705c7a6 Manuel Franceschini
    """Return IP address of given hostname.
199 b705c7a6 Manuel Franceschini

200 b705c7a6 Manuel Franceschini
    Supports both IPv4 and IPv6.
201 a744b676 Manuel Franceschini

202 a744b676 Manuel Franceschini
    @type hostname: str
203 a744b676 Manuel Franceschini
    @param hostname: hostname to look up
204 b705c7a6 Manuel Franceschini
    @type family: int
205 b705c7a6 Manuel Franceschini
    @param family: AF_INET | AF_INET6 | None
206 b705c7a6 Manuel Franceschini
    @rtype: str
207 b705c7a6 Manuel Franceschini
    @return: IP address
208 a744b676 Manuel Franceschini
    @raise errors.ResolverError: in case of errors in resolving
209 a744b676 Manuel Franceschini

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

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

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

254 a744b676 Manuel Franceschini
  Check if the given IP is reachable by doing attempting a TCP connect
255 a744b676 Manuel Franceschini
  to it.
256 a744b676 Manuel Franceschini

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

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

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

308 a744b676 Manuel Franceschini
  @type daemon_name: string
309 a744b676 Manuel Franceschini
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
310 a744b676 Manuel Franceschini
  @rtype: int
311 a744b676 Manuel Franceschini

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

328 8b312c1d Manuel Franceschini
  """
329 8b312c1d Manuel Franceschini
  iplen = 0
330 8b312c1d Manuel Franceschini
  family = None
331 8b312c1d Manuel Franceschini
  loopback_cidr = None
332 8b312c1d Manuel Franceschini
333 8b312c1d Manuel Franceschini
  @staticmethod
334 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
335 8b312c1d Manuel Franceschini
    """Abstract method to please pylint.
336 8b312c1d Manuel Franceschini

337 8b312c1d Manuel Franceschini
    """
338 8b312c1d Manuel Franceschini
    raise NotImplementedError
339 8b312c1d Manuel Franceschini
340 8b312c1d Manuel Franceschini
  @classmethod
341 8b312c1d Manuel Franceschini
  def IsValid(cls, address):
342 8b312c1d Manuel Franceschini
    """Validate a IP address.
343 8b312c1d Manuel Franceschini

344 8b312c1d Manuel Franceschini
    @type address: str
345 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
346 8b312c1d Manuel Franceschini
    @rtype: bool
347 8b312c1d Manuel Franceschini
    @return: True if valid, False otherwise
348 8b312c1d Manuel Franceschini

349 8b312c1d Manuel Franceschini
    """
350 8b312c1d Manuel Franceschini
    if cls.family is None:
351 8b312c1d Manuel Franceschini
      try:
352 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
353 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
354 8b312c1d Manuel Franceschini
        return False
355 8b312c1d Manuel Franceschini
    else:
356 8b312c1d Manuel Franceschini
      family = cls.family
357 8b312c1d Manuel Franceschini
358 8b312c1d Manuel Franceschini
    try:
359 8b312c1d Manuel Franceschini
      socket.inet_pton(family, address)
360 8b312c1d Manuel Franceschini
      return True
361 8b312c1d Manuel Franceschini
    except socket.error:
362 8b312c1d Manuel Franceschini
      return False
363 8b312c1d Manuel Franceschini
364 8b312c1d Manuel Franceschini
  @classmethod
365 8b312c1d Manuel Franceschini
  def Own(cls, address):
366 8b312c1d Manuel Franceschini
    """Check if the current host has the the given IP address.
367 8b312c1d Manuel Franceschini

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

371 8b312c1d Manuel Franceschini
    @type address: str
372 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
373 8b312c1d Manuel Franceschini
    @rtype: bool
374 8b312c1d Manuel Franceschini
    @return: True if we own the address, False otherwise
375 8b312c1d Manuel Franceschini

376 8b312c1d Manuel Franceschini
    """
377 8b312c1d Manuel Franceschini
    if cls.family is None:
378 8b312c1d Manuel Franceschini
      try:
379 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
380 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
381 8b312c1d Manuel Franceschini
        return False
382 8b312c1d Manuel Franceschini
    else:
383 8b312c1d Manuel Franceschini
      family = cls.family
384 8b312c1d Manuel Franceschini
385 8b312c1d Manuel Franceschini
    s = socket.socket(family, socket.SOCK_DGRAM)
386 8b312c1d Manuel Franceschini
    success = False
387 8b312c1d Manuel Franceschini
    try:
388 8b312c1d Manuel Franceschini
      try:
389 8b312c1d Manuel Franceschini
        s.bind((address, 0))
390 8b312c1d Manuel Franceschini
        success = True
391 8b312c1d Manuel Franceschini
      except socket.error:
392 8b312c1d Manuel Franceschini
        success = False
393 8b312c1d Manuel Franceschini
    finally:
394 8b312c1d Manuel Franceschini
      s.close()
395 8b312c1d Manuel Franceschini
    return success
396 8b312c1d Manuel Franceschini
397 8b312c1d Manuel Franceschini
  @classmethod
398 8b312c1d Manuel Franceschini
  def InNetwork(cls, cidr, address):
399 8b312c1d Manuel Franceschini
    """Determine whether an address is within a network.
400 8b312c1d Manuel Franceschini

401 8b312c1d Manuel Franceschini
    @type cidr: string
402 8b312c1d Manuel Franceschini
    @param cidr: Network in CIDR notation, e.g. '192.0.2.0/24', '2001:db8::/64'
403 8b312c1d Manuel Franceschini
    @type address: str
404 8b312c1d Manuel Franceschini
    @param address: IP address
405 8b312c1d Manuel Franceschini
    @rtype: bool
406 8b312c1d Manuel Franceschini
    @return: True if address is in cidr, False otherwise
407 8b312c1d Manuel Franceschini

408 8b312c1d Manuel Franceschini
    """
409 8b312c1d Manuel Franceschini
    address_int = cls._GetIPIntFromString(address)
410 8b312c1d Manuel Franceschini
    subnet = cidr.split("/")
411 8b312c1d Manuel Franceschini
    assert len(subnet) == 2
412 8b312c1d Manuel Franceschini
    try:
413 8b312c1d Manuel Franceschini
      prefix = int(subnet[1])
414 8b312c1d Manuel Franceschini
    except ValueError:
415 8b312c1d Manuel Franceschini
      return False
416 8b312c1d Manuel Franceschini
417 8b312c1d Manuel Franceschini
    assert 0 <= prefix <= cls.iplen
418 8b312c1d Manuel Franceschini
    target_int = cls._GetIPIntFromString(subnet[0])
419 8b312c1d Manuel Franceschini
    # Convert prefix netmask to integer value of netmask
420 e687ec01 Michael Hanselmann
    netmask_int = (2 ** cls.iplen) - 1 ^ ((2 ** cls.iplen) - 1 >> prefix)
421 8b312c1d Manuel Franceschini
    # Calculate hostmask
422 e687ec01 Michael Hanselmann
    hostmask_int = netmask_int ^ (2 ** cls.iplen) - 1
423 8b312c1d Manuel Franceschini
    # Calculate network address by and'ing netmask
424 8b312c1d Manuel Franceschini
    network_int = target_int & netmask_int
425 8b312c1d Manuel Franceschini
    # Calculate broadcast address by or'ing hostmask
426 8b312c1d Manuel Franceschini
    broadcast_int = target_int | hostmask_int
427 8b312c1d Manuel Franceschini
428 8b312c1d Manuel Franceschini
    return network_int <= address_int <= broadcast_int
429 8b312c1d Manuel Franceschini
430 8b312c1d Manuel Franceschini
  @staticmethod
431 8b312c1d Manuel Franceschini
  def GetAddressFamily(address):
432 8b312c1d Manuel Franceschini
    """Get the address family of the given address.
433 8b312c1d Manuel Franceschini

434 8b312c1d Manuel Franceschini
    @type address: str
435 8b312c1d Manuel Franceschini
    @param address: ip address whose family will be returned
436 8b312c1d Manuel Franceschini
    @rtype: int
437 37531236 Andrea Spadaccini
    @return: C{socket.AF_INET} or C{socket.AF_INET6}
438 8b312c1d Manuel Franceschini
    @raise errors.GenericError: for invalid addresses
439 8b312c1d Manuel Franceschini

440 8b312c1d Manuel Franceschini
    """
441 8b312c1d Manuel Franceschini
    try:
442 8b312c1d Manuel Franceschini
      return IP4Address(address).family
443 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
444 8b312c1d Manuel Franceschini
      pass
445 8b312c1d Manuel Franceschini
446 8b312c1d Manuel Franceschini
    try:
447 8b312c1d Manuel Franceschini
      return IP6Address(address).family
448 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
449 8b312c1d Manuel Franceschini
      pass
450 8b312c1d Manuel Franceschini
451 8b312c1d Manuel Franceschini
    raise errors.IPAddressError("Invalid address '%s'" % address)
452 8b312c1d Manuel Franceschini
453 37531236 Andrea Spadaccini
  @staticmethod
454 37531236 Andrea Spadaccini
  def GetVersionFromAddressFamily(family):
455 37531236 Andrea Spadaccini
    """Convert an IP address family to the corresponding IP version.
456 37531236 Andrea Spadaccini

457 37531236 Andrea Spadaccini
    @type family: int
458 37531236 Andrea Spadaccini
    @param family: IP address family, one of socket.AF_INET or socket.AF_INET6
459 37531236 Andrea Spadaccini
    @return: an int containing the IP version, one of L{constants.IP4_VERSION}
460 37531236 Andrea Spadaccini
             or L{constants.IP6_VERSION}
461 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown families
462 37531236 Andrea Spadaccini

463 37531236 Andrea Spadaccini
    """
464 37531236 Andrea Spadaccini
    if family == socket.AF_INET:
465 37531236 Andrea Spadaccini
      return constants.IP4_VERSION
466 37531236 Andrea Spadaccini
    elif family == socket.AF_INET6:
467 37531236 Andrea Spadaccini
      return constants.IP6_VERSION
468 37531236 Andrea Spadaccini
469 37531236 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP address family" % family)
470 37531236 Andrea Spadaccini
471 37531236 Andrea Spadaccini
  @staticmethod
472 37531236 Andrea Spadaccini
  def GetAddressFamilyFromVersion(version):
473 37531236 Andrea Spadaccini
    """Convert an IP version to the corresponding IP address family.
474 37531236 Andrea Spadaccini

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

482 37531236 Andrea Spadaccini
    """
483 37531236 Andrea Spadaccini
    if version == constants.IP4_VERSION:
484 37531236 Andrea Spadaccini
      return socket.AF_INET
485 37531236 Andrea Spadaccini
    elif version == constants.IP6_VERSION:
486 37531236 Andrea Spadaccini
      return socket.AF_INET6
487 37531236 Andrea Spadaccini
488 37531236 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP version" % version)
489 37531236 Andrea Spadaccini
490 8b312c1d Manuel Franceschini
  @classmethod
491 8b312c1d Manuel Franceschini
  def IsLoopback(cls, address):
492 8b312c1d Manuel Franceschini
    """Determine whether it is a loopback address.
493 8b312c1d Manuel Franceschini

494 8b312c1d Manuel Franceschini
    @type address: str
495 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
496 8b312c1d Manuel Franceschini
    @rtype: bool
497 8b312c1d Manuel Franceschini
    @return: True if loopback, False otherwise
498 8b312c1d Manuel Franceschini

499 8b312c1d Manuel Franceschini
    """
500 8b312c1d Manuel Franceschini
    try:
501 8b312c1d Manuel Franceschini
      return cls.InNetwork(cls.loopback_cidr, address)
502 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
503 8b312c1d Manuel Franceschini
      return False
504 8b312c1d Manuel Franceschini
505 8b312c1d Manuel Franceschini
506 8b312c1d Manuel Franceschini
class IP4Address(IPAddress):
507 8b312c1d Manuel Franceschini
  """IPv4 address class.
508 8b312c1d Manuel Franceschini

509 8b312c1d Manuel Franceschini
  """
510 8b312c1d Manuel Franceschini
  iplen = 32
511 8b312c1d Manuel Franceschini
  family = socket.AF_INET
512 8b312c1d Manuel Franceschini
  loopback_cidr = "127.0.0.0/8"
513 8b312c1d Manuel Franceschini
514 8b312c1d Manuel Franceschini
  def __init__(self, address):
515 8b312c1d Manuel Franceschini
    """Constructor for IPv4 address.
516 8b312c1d Manuel Franceschini

517 8b312c1d Manuel Franceschini
    @type address: str
518 8b312c1d Manuel Franceschini
    @param address: IP address
519 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
520 8b312c1d Manuel Franceschini

521 8b312c1d Manuel Franceschini
    """
522 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
523 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
524 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv4 Address %s invalid" % address)
525 8b312c1d Manuel Franceschini
526 8b312c1d Manuel Franceschini
    self.address = address
527 8b312c1d Manuel Franceschini
528 8b312c1d Manuel Franceschini
  @staticmethod
529 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
530 8b312c1d Manuel Franceschini
    """Get integer value of IPv4 address.
531 8b312c1d Manuel Franceschini

532 8b312c1d Manuel Franceschini
    @type address: str
533 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
534 8b312c1d Manuel Franceschini
    @rtype: int
535 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
536 8b312c1d Manuel Franceschini

537 8b312c1d Manuel Franceschini
    """
538 8b312c1d Manuel Franceschini
    address_int = 0
539 8b312c1d Manuel Franceschini
    parts = address.split(".")
540 8b312c1d Manuel Franceschini
    assert len(parts) == 4
541 8b312c1d Manuel Franceschini
    for part in parts:
542 8b312c1d Manuel Franceschini
      address_int = (address_int << 8) | int(part)
543 8b312c1d Manuel Franceschini
544 8b312c1d Manuel Franceschini
    return address_int
545 8b312c1d Manuel Franceschini
546 8b312c1d Manuel Franceschini
547 8b312c1d Manuel Franceschini
class IP6Address(IPAddress):
548 8b312c1d Manuel Franceschini
  """IPv6 address class.
549 8b312c1d Manuel Franceschini

550 8b312c1d Manuel Franceschini
  """
551 8b312c1d Manuel Franceschini
  iplen = 128
552 8b312c1d Manuel Franceschini
  family = socket.AF_INET6
553 8b312c1d Manuel Franceschini
  loopback_cidr = "::1/128"
554 8b312c1d Manuel Franceschini
555 8b312c1d Manuel Franceschini
  def __init__(self, address):
556 8b312c1d Manuel Franceschini
    """Constructor for IPv6 address.
557 8b312c1d Manuel Franceschini

558 8b312c1d Manuel Franceschini
    @type address: str
559 8b312c1d Manuel Franceschini
    @param address: IP address
560 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
561 8b312c1d Manuel Franceschini

562 8b312c1d Manuel Franceschini
    """
563 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
564 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
565 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv6 Address [%s] invalid" % address)
566 8b312c1d Manuel Franceschini
    self.address = address
567 8b312c1d Manuel Franceschini
568 8b312c1d Manuel Franceschini
  @staticmethod
569 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
570 8b312c1d Manuel Franceschini
    """Get integer value of IPv6 address.
571 8b312c1d Manuel Franceschini

572 8b312c1d Manuel Franceschini
    @type address: str
573 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
574 8b312c1d Manuel Franceschini
    @rtype: int
575 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
576 8b312c1d Manuel Franceschini

577 8b312c1d Manuel Franceschini
    """
578 8b312c1d Manuel Franceschini
    doublecolons = address.count("::")
579 8b312c1d Manuel Franceschini
    assert not doublecolons > 1
580 8b312c1d Manuel Franceschini
    if doublecolons == 1:
581 8b312c1d Manuel Franceschini
      # We have a shorthand address, expand it
582 8b312c1d Manuel Franceschini
      parts = []
583 8b312c1d Manuel Franceschini
      twoparts = address.split("::")
584 d0c8c01d Iustin Pop
      sep = len(twoparts[0].split(":")) + len(twoparts[1].split(":"))
585 d0c8c01d Iustin Pop
      parts = twoparts[0].split(":")
586 17385bd2 Andrea Spadaccini
      parts.extend(["0"] * (8 - sep))
587 d0c8c01d Iustin Pop
      parts += twoparts[1].split(":")
588 8b312c1d Manuel Franceschini
    else:
589 8b312c1d Manuel Franceschini
      parts = address.split(":")
590 8b312c1d Manuel Franceschini
591 8b312c1d Manuel Franceschini
    address_int = 0
592 8b312c1d Manuel Franceschini
    for part in parts:
593 d0c8c01d Iustin Pop
      address_int = (address_int << 16) + int(part or "0", 16)
594 8b312c1d Manuel Franceschini
595 8b312c1d Manuel Franceschini
    return address_int
596 1a8337f2 Manuel Franceschini
597 7845b8c8 Manuel Franceschini
598 981732fb Manuel Franceschini
def FormatAddress(address, family=None):
599 1a8337f2 Manuel Franceschini
  """Format a socket address
600 1a8337f2 Manuel Franceschini

601 1a8337f2 Manuel Franceschini
  @type address: family specific (usually tuple)
602 1a8337f2 Manuel Franceschini
  @param address: address, as reported by this class
603 981732fb Manuel Franceschini
  @type family: integer
604 981732fb Manuel Franceschini
  @param family: socket family (one of socket.AF_*) or None
605 1a8337f2 Manuel Franceschini

606 1a8337f2 Manuel Franceschini
  """
607 981732fb Manuel Franceschini
  if family is None:
608 981732fb Manuel Franceschini
    try:
609 981732fb Manuel Franceschini
      family = IPAddress.GetAddressFamily(address[0])
610 981732fb Manuel Franceschini
    except errors.IPAddressError:
611 981732fb Manuel Franceschini
      raise errors.ParameterError(address)
612 981732fb Manuel Franceschini
613 1a8337f2 Manuel Franceschini
  if family == socket.AF_UNIX and len(address) == 3:
614 1a8337f2 Manuel Franceschini
    return "pid=%s, uid=%s, gid=%s" % address
615 1a8337f2 Manuel Franceschini
616 1a8337f2 Manuel Franceschini
  if family in (socket.AF_INET, socket.AF_INET6) and len(address) == 2:
617 1a8337f2 Manuel Franceschini
    host, port = address
618 1a8337f2 Manuel Franceschini
    if family == socket.AF_INET6:
619 1a8337f2 Manuel Franceschini
      res = "[%s]" % host
620 1a8337f2 Manuel Franceschini
    else:
621 1a8337f2 Manuel Franceschini
      res = host
622 1a8337f2 Manuel Franceschini
623 1a8337f2 Manuel Franceschini
    if port is not None:
624 1a8337f2 Manuel Franceschini
      res += ":%s" % port
625 1a8337f2 Manuel Franceschini
626 1a8337f2 Manuel Franceschini
    return res
627 1a8337f2 Manuel Franceschini
628 1a8337f2 Manuel Franceschini
  raise errors.ParameterError(family, address)