Statistics
| Branch: | Tag: | Revision:

root / lib / netutils.py @ 912b2278

History | View | Annotate | Download (19.7 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 069a4bcf Guido Trotter
# Workaround a bug in some linux distributions that don't define SO_PEERCRED
56 069a4bcf Guido Trotter
try:
57 a3e964cf Klaus Aehlig
  # pylint: disable=E1101
58 069a4bcf Guido Trotter
  _SO_PEERCRED = IN.SO_PEERCRED
59 069a4bcf Guido Trotter
except AttributeError:
60 069a4bcf Guido Trotter
  _SO_PEERCRED = 17
61 069a4bcf Guido Trotter
62 37531236 Andrea Spadaccini
# Regexes used to find IP addresses in the output of ip.
63 37531236 Andrea Spadaccini
_IP_RE_TEXT = r"[.:a-z0-9]+"      # separate for testing purposes
64 37531236 Andrea Spadaccini
_IP_FAMILY_RE = re.compile(r"(?P<family>inet6?)\s+(?P<ip>%s)/" % _IP_RE_TEXT,
65 37531236 Andrea Spadaccini
                           re.IGNORECASE)
66 37531236 Andrea Spadaccini
67 37531236 Andrea Spadaccini
# Dict used to convert from a string representing an IP family to an IP
68 37531236 Andrea Spadaccini
# version
69 e687ec01 Michael Hanselmann
_NAME_TO_IP_VER = {
70 37531236 Andrea Spadaccini
  "inet": constants.IP4_VERSION,
71 37531236 Andrea Spadaccini
  "inet6": constants.IP6_VERSION,
72 37531236 Andrea Spadaccini
  }
73 37531236 Andrea Spadaccini
74 37531236 Andrea Spadaccini
75 37531236 Andrea Spadaccini
def _GetIpAddressesFromIpOutput(ip_output):
76 37531236 Andrea Spadaccini
  """Parses the output of the ip command and retrieves the IP addresses and
77 37531236 Andrea Spadaccini
  version.
78 37531236 Andrea Spadaccini

79 37531236 Andrea Spadaccini
  @param ip_output: string containing the output of the ip command;
80 37531236 Andrea Spadaccini
  @rtype: dict; (int, list)
81 37531236 Andrea Spadaccini
  @return: a dict having as keys the IP versions and as values the
82 37531236 Andrea Spadaccini
           corresponding list of addresses found in the IP output.
83 37531236 Andrea Spadaccini

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

98 a744b676 Manuel Franceschini
  @param sock: Unix socket
99 a744b676 Manuel Franceschini
  @rtype: tuple; (number, number, number)
100 a744b676 Manuel Franceschini
  @return: The PID, UID and GID of the connected foreign process.
101 a744b676 Manuel Franceschini

102 a744b676 Manuel Franceschini
  """
103 069a4bcf Guido Trotter
  peercred = sock.getsockopt(socket.SOL_SOCKET, _SO_PEERCRED,
104 a744b676 Manuel Franceschini
                             _STRUCT_UCRED_SIZE)
105 a744b676 Manuel Franceschini
  return struct.unpack(_STRUCT_UCRED, peercred)
106 a744b676 Manuel Franceschini
107 a744b676 Manuel Franceschini
108 37531236 Andrea Spadaccini
def IsValidInterface(ifname):
109 37531236 Andrea Spadaccini
  """Validate an interface name.
110 37531236 Andrea Spadaccini

111 37531236 Andrea Spadaccini
  @type ifname: string
112 37531236 Andrea Spadaccini
  @param ifname: Name of the network interface
113 37531236 Andrea Spadaccini
  @return: boolean indicating whether the interface name is valid or not.
114 37531236 Andrea Spadaccini

115 37531236 Andrea Spadaccini
  """
116 37531236 Andrea Spadaccini
  return os.path.exists(utils.PathJoin("/sys/class/net", ifname))
117 37531236 Andrea Spadaccini
118 37531236 Andrea Spadaccini
119 37531236 Andrea Spadaccini
def GetInterfaceIpAddresses(ifname):
120 37531236 Andrea Spadaccini
  """Returns the IP addresses associated to the interface.
121 37531236 Andrea Spadaccini

122 37531236 Andrea Spadaccini
  @type ifname: string
123 37531236 Andrea Spadaccini
  @param ifname: Name of the network interface
124 37531236 Andrea Spadaccini
  @return: A dict having for keys the IP version (either
125 37531236 Andrea Spadaccini
           L{constants.IP4_VERSION} or L{constants.IP6_VERSION}) and for
126 37531236 Andrea Spadaccini
           values the lists of IP addresses of the respective version
127 37531236 Andrea Spadaccini
           associated to the interface
128 37531236 Andrea Spadaccini

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

144 b705c7a6 Manuel Franceschini
  @type name: str
145 b705c7a6 Manuel Franceschini
  @param name: hostname or None
146 b705c7a6 Manuel Franceschini
  @type family: int
147 b705c7a6 Manuel Franceschini
  @param family: AF_INET | AF_INET6 | None
148 b705c7a6 Manuel Franceschini
  @rtype: L{Hostname}
149 b705c7a6 Manuel Franceschini
  @return: Hostname object
150 17f7fd27 Manuel Franceschini
  @raise errors.OpPrereqError: in case of errors in resolving
151 b705c7a6 Manuel Franceschini

152 b705c7a6 Manuel Franceschini
  """
153 a744b676 Manuel Franceschini
  try:
154 b705c7a6 Manuel Franceschini
    return Hostname(name=name, family=family)
155 a744b676 Manuel Franceschini
  except errors.ResolverError, err:
156 a744b676 Manuel Franceschini
    raise errors.OpPrereqError("The given name (%s) does not resolve: %s" %
157 a744b676 Manuel Franceschini
                               (err[0], err[2]), errors.ECODE_RESOLVER)
158 a744b676 Manuel Franceschini
159 a744b676 Manuel Franceschini
160 b705c7a6 Manuel Franceschini
class Hostname:
161 b705c7a6 Manuel Franceschini
  """Class implementing resolver and hostname functionality.
162 a744b676 Manuel Franceschini

163 a744b676 Manuel Franceschini
  """
164 e7b3ad26 Manuel Franceschini
  _VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$")
165 e7b3ad26 Manuel Franceschini
166 b705c7a6 Manuel Franceschini
  def __init__(self, name=None, family=None):
167 a744b676 Manuel Franceschini
    """Initialize the host name object.
168 a744b676 Manuel Franceschini

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

171 b705c7a6 Manuel Franceschini
    @type family: int
172 b705c7a6 Manuel Franceschini
    @param family: AF_INET | AF_INET6 | None
173 b705c7a6 Manuel Franceschini
    @type name: str
174 b705c7a6 Manuel Franceschini
    @param name: hostname or None
175 a744b676 Manuel Franceschini

176 a744b676 Manuel Franceschini
    """
177 5f30ea3f Michael Hanselmann
    self.name = self.GetFqdn(name)
178 b705c7a6 Manuel Franceschini
    self.ip = self.GetIP(self.name, family=family)
179 a744b676 Manuel Franceschini
180 f3044516 Manuel Franceschini
  @classmethod
181 f3044516 Manuel Franceschini
  def GetSysName(cls):
182 f3044516 Manuel Franceschini
    """Legacy method the get the current system's name.
183 f3044516 Manuel Franceschini

184 f3044516 Manuel Franceschini
    """
185 f3044516 Manuel Franceschini
    return cls.GetFqdn()
186 f3044516 Manuel Franceschini
187 5f30ea3f Michael Hanselmann
  @classmethod
188 5f30ea3f Michael Hanselmann
  def GetFqdn(cls, hostname=None):
189 f3044516 Manuel Franceschini
    """Return fqdn.
190 f3044516 Manuel Franceschini

191 f3044516 Manuel Franceschini
    If hostname is None the system's fqdn is returned.
192 a744b676 Manuel Franceschini

193 f3044516 Manuel Franceschini
    @type hostname: str
194 f3044516 Manuel Franceschini
    @param hostname: name to be fqdn'ed
195 f3044516 Manuel Franceschini
    @rtype: str
196 f3044516 Manuel Franceschini
    @return: fqdn of given name, if it exists, unmodified name otherwise
197 a744b676 Manuel Franceschini

198 a744b676 Manuel Franceschini
    """
199 f3044516 Manuel Franceschini
    if hostname is None:
200 e91b297c Michael Hanselmann
      virtfqdn = vcluster.GetVirtualHostname()
201 e91b297c Michael Hanselmann
      if virtfqdn:
202 5f30ea3f Michael Hanselmann
        result = virtfqdn
203 e91b297c Michael Hanselmann
      else:
204 5f30ea3f Michael Hanselmann
        result = socket.getfqdn()
205 f3044516 Manuel Franceschini
    else:
206 5f30ea3f Michael Hanselmann
      result = socket.getfqdn(hostname)
207 5f30ea3f Michael Hanselmann
208 5f30ea3f Michael Hanselmann
    return cls.GetNormalizedName(result)
209 a744b676 Manuel Franceschini
210 a744b676 Manuel Franceschini
  @staticmethod
211 b705c7a6 Manuel Franceschini
  def GetIP(hostname, family=None):
212 b705c7a6 Manuel Franceschini
    """Return IP address of given hostname.
213 b705c7a6 Manuel Franceschini

214 b705c7a6 Manuel Franceschini
    Supports both IPv4 and IPv6.
215 a744b676 Manuel Franceschini

216 a744b676 Manuel Franceschini
    @type hostname: str
217 a744b676 Manuel Franceschini
    @param hostname: hostname to look up
218 b705c7a6 Manuel Franceschini
    @type family: int
219 b705c7a6 Manuel Franceschini
    @param family: AF_INET | AF_INET6 | None
220 b705c7a6 Manuel Franceschini
    @rtype: str
221 b705c7a6 Manuel Franceschini
    @return: IP address
222 a744b676 Manuel Franceschini
    @raise errors.ResolverError: in case of errors in resolving
223 a744b676 Manuel Franceschini

224 a744b676 Manuel Franceschini
    """
225 a744b676 Manuel Franceschini
    try:
226 b705c7a6 Manuel Franceschini
      if family in (socket.AF_INET, socket.AF_INET6):
227 b705c7a6 Manuel Franceschini
        result = socket.getaddrinfo(hostname, None, family)
228 b705c7a6 Manuel Franceschini
      else:
229 b43dcc5a Manuel Franceschini
        result = socket.getaddrinfo(hostname, None)
230 a744b676 Manuel Franceschini
    except (socket.gaierror, socket.herror, socket.error), err:
231 a744b676 Manuel Franceschini
      # hostname not found in DNS, or other socket exception in the
232 a744b676 Manuel Franceschini
      # (code, description format)
233 a744b676 Manuel Franceschini
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
234 a744b676 Manuel Franceschini
235 b705c7a6 Manuel Franceschini
    # getaddrinfo() returns a list of 5-tupes (family, socktype, proto,
236 b705c7a6 Manuel Franceschini
    # canonname, sockaddr). We return the first tuple's first address in
237 b705c7a6 Manuel Franceschini
    # sockaddr
238 e7b3ad26 Manuel Franceschini
    try:
239 e7b3ad26 Manuel Franceschini
      return result[0][4][0]
240 e7b3ad26 Manuel Franceschini
    except IndexError, err:
241 39d1744a Iustin Pop
      # we don't have here an actual error code, it's just that the
242 39d1744a Iustin Pop
      # data type returned by getaddrinfo is not what we expected;
243 39d1744a Iustin Pop
      # let's keep the same format in the exception arguments with a
244 39d1744a Iustin Pop
      # dummy error code
245 39d1744a Iustin Pop
      raise errors.ResolverError(hostname, 0,
246 39d1744a Iustin Pop
                                 "Unknown error in getaddrinfo(): %s" % err)
247 a744b676 Manuel Franceschini
248 e7b3ad26 Manuel Franceschini
  @classmethod
249 e7b3ad26 Manuel Franceschini
  def GetNormalizedName(cls, hostname):
250 a744b676 Manuel Franceschini
    """Validate and normalize the given hostname.
251 a744b676 Manuel Franceschini

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

256 a744b676 Manuel Franceschini
    """
257 a744b676 Manuel Franceschini
    hostname = hostname.lower()
258 e7b3ad26 Manuel Franceschini
    if (not cls._VALID_NAME_RE.match(hostname) or
259 a744b676 Manuel Franceschini
        # double-dots, meaning empty label
260 a744b676 Manuel Franceschini
        ".." in hostname or
261 a744b676 Manuel Franceschini
        # empty initial label
262 a744b676 Manuel Franceschini
        hostname.startswith(".")):
263 a744b676 Manuel Franceschini
      raise errors.OpPrereqError("Invalid hostname '%s'" % hostname,
264 a744b676 Manuel Franceschini
                                 errors.ECODE_INVAL)
265 a744b676 Manuel Franceschini
    if hostname.endswith("."):
266 a744b676 Manuel Franceschini
      hostname = hostname.rstrip(".")
267 a744b676 Manuel Franceschini
    return hostname
268 a744b676 Manuel Franceschini
269 a744b676 Manuel Franceschini
270 05edafd3 Santi Raffa
def ValidatePortNumber(port):
271 05edafd3 Santi Raffa
  """Returns the validated integer port number if it is valid.
272 05edafd3 Santi Raffa

273 05edafd3 Santi Raffa
  @param port: the port number to be validated
274 05edafd3 Santi Raffa

275 05edafd3 Santi Raffa
  @raise ValueError: if the port is not valid
276 05edafd3 Santi Raffa
  @rtype: int
277 05edafd3 Santi Raffa
  @return: the validated value.
278 05edafd3 Santi Raffa

279 05edafd3 Santi Raffa
  """
280 05edafd3 Santi Raffa
281 05edafd3 Santi Raffa
  try:
282 05edafd3 Santi Raffa
    port = int(port)
283 05edafd3 Santi Raffa
  except TypeError:
284 05edafd3 Santi Raffa
    raise errors.ProgrammerError("ValidatePortNumber called with non-numeric"
285 05edafd3 Santi Raffa
                                 " type %s." % port.__class__.__name__)
286 05edafd3 Santi Raffa
  except ValueError:
287 05edafd3 Santi Raffa
    raise ValueError("Invalid port value: '%s'" % port)
288 05edafd3 Santi Raffa
289 05edafd3 Santi Raffa
  if not 0 < port < 2 ** 16:
290 05edafd3 Santi Raffa
    raise ValueError("Invalid port value: '%d'" % port)
291 05edafd3 Santi Raffa
292 05edafd3 Santi Raffa
  return port
293 05edafd3 Santi Raffa
294 05edafd3 Santi Raffa
295 a744b676 Manuel Franceschini
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
296 a744b676 Manuel Franceschini
  """Simple ping implementation using TCP connect(2).
297 a744b676 Manuel Franceschini

298 a744b676 Manuel Franceschini
  Check if the given IP is reachable by doing attempting a TCP connect
299 a744b676 Manuel Franceschini
  to it.
300 a744b676 Manuel Franceschini

301 a744b676 Manuel Franceschini
  @type target: str
302 77b02a99 Renรฉ Nussbaumer
  @param target: the IP to ping
303 a744b676 Manuel Franceschini
  @type port: int
304 a744b676 Manuel Franceschini
  @param port: the port to connect to
305 a744b676 Manuel Franceschini
  @type timeout: int
306 a744b676 Manuel Franceschini
  @param timeout: the timeout on the connection attempt
307 a744b676 Manuel Franceschini
  @type live_port_needed: boolean
308 a744b676 Manuel Franceschini
  @param live_port_needed: whether a closed port will cause the
309 a744b676 Manuel Franceschini
      function to return failure, as if there was a timeout
310 a744b676 Manuel Franceschini
  @type source: str or None
311 a744b676 Manuel Franceschini
  @param source: if specified, will cause the connect to be made
312 a744b676 Manuel Franceschini
      from this specific source address; failures to bind other
313 a744b676 Manuel Franceschini
      than C{EADDRNOTAVAIL} will be ignored
314 a744b676 Manuel Franceschini

315 a744b676 Manuel Franceschini
  """
316 25ba209e Michael Hanselmann
  logging.debug("Attempting to reach TCP port %s on target %s with a timeout"
317 25ba209e Michael Hanselmann
                " of %s seconds", port, target, timeout)
318 25ba209e Michael Hanselmann
319 a744b676 Manuel Franceschini
  try:
320 8b312c1d Manuel Franceschini
    family = IPAddress.GetAddressFamily(target)
321 25ba209e Michael Hanselmann
  except errors.IPAddressError, err:
322 25ba209e Michael Hanselmann
    raise errors.ProgrammerError("Family of IP address given in parameter"
323 25ba209e Michael Hanselmann
                                 " 'target' can't be determined: %s" % err)
324 a744b676 Manuel Franceschini
325 a744b676 Manuel Franceschini
  sock = socket.socket(family, socket.SOCK_STREAM)
326 a744b676 Manuel Franceschini
  success = False
327 a744b676 Manuel Franceschini
328 a744b676 Manuel Franceschini
  if source is not None:
329 a744b676 Manuel Franceschini
    try:
330 a744b676 Manuel Franceschini
      sock.bind((source, 0))
331 8ad0da1e Iustin Pop
    except socket.error, err:
332 8ad0da1e Iustin Pop
      if err[0] == errno.EADDRNOTAVAIL:
333 a744b676 Manuel Franceschini
        success = False
334 a744b676 Manuel Franceschini
335 a744b676 Manuel Franceschini
  sock.settimeout(timeout)
336 a744b676 Manuel Franceschini
337 a744b676 Manuel Franceschini
  try:
338 a744b676 Manuel Franceschini
    sock.connect((target, port))
339 a744b676 Manuel Franceschini
    sock.close()
340 a744b676 Manuel Franceschini
    success = True
341 a744b676 Manuel Franceschini
  except socket.timeout:
342 a744b676 Manuel Franceschini
    success = False
343 8ad0da1e Iustin Pop
  except socket.error, err:
344 8ad0da1e Iustin Pop
    success = (not live_port_needed) and (err[0] == errno.ECONNREFUSED)
345 a744b676 Manuel Franceschini
346 a744b676 Manuel Franceschini
  return success
347 a744b676 Manuel Franceschini
348 a744b676 Manuel Franceschini
349 a744b676 Manuel Franceschini
def GetDaemonPort(daemon_name):
350 a744b676 Manuel Franceschini
  """Get the daemon port for this cluster.
351 a744b676 Manuel Franceschini

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

356 a744b676 Manuel Franceschini
  @type daemon_name: string
357 a744b676 Manuel Franceschini
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
358 a744b676 Manuel Franceschini
  @rtype: int
359 a744b676 Manuel Franceschini

360 a744b676 Manuel Franceschini
  """
361 a744b676 Manuel Franceschini
  if daemon_name not in constants.DAEMONS_PORTS:
362 a744b676 Manuel Franceschini
    raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name)
363 a744b676 Manuel Franceschini
364 a744b676 Manuel Franceschini
  (proto, default_port) = constants.DAEMONS_PORTS[daemon_name]
365 a744b676 Manuel Franceschini
  try:
366 a744b676 Manuel Franceschini
    port = socket.getservbyname(daemon_name, proto)
367 a744b676 Manuel Franceschini
  except socket.error:
368 a744b676 Manuel Franceschini
    port = default_port
369 a744b676 Manuel Franceschini
370 a744b676 Manuel Franceschini
  return port
371 8b312c1d Manuel Franceschini
372 8b312c1d Manuel Franceschini
373 8b312c1d Manuel Franceschini
class IPAddress(object):
374 8b312c1d Manuel Franceschini
  """Class that represents an IP address.
375 8b312c1d Manuel Franceschini

376 8b312c1d Manuel Franceschini
  """
377 8b312c1d Manuel Franceschini
  iplen = 0
378 8b312c1d Manuel Franceschini
  family = None
379 8b312c1d Manuel Franceschini
  loopback_cidr = None
380 8b312c1d Manuel Franceschini
381 8b312c1d Manuel Franceschini
  @staticmethod
382 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
383 8b312c1d Manuel Franceschini
    """Abstract method to please pylint.
384 8b312c1d Manuel Franceschini

385 8b312c1d Manuel Franceschini
    """
386 8b312c1d Manuel Franceschini
    raise NotImplementedError
387 8b312c1d Manuel Franceschini
388 8b312c1d Manuel Franceschini
  @classmethod
389 8b312c1d Manuel Franceschini
  def IsValid(cls, address):
390 8b312c1d Manuel Franceschini
    """Validate a IP address.
391 8b312c1d Manuel Franceschini

392 8b312c1d Manuel Franceschini
    @type address: str
393 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
394 8b312c1d Manuel Franceschini
    @rtype: bool
395 8b312c1d Manuel Franceschini
    @return: True if valid, False otherwise
396 8b312c1d Manuel Franceschini

397 8b312c1d Manuel Franceschini
    """
398 8b312c1d Manuel Franceschini
    if cls.family is None:
399 8b312c1d Manuel Franceschini
      try:
400 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
401 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
402 8b312c1d Manuel Franceschini
        return False
403 8b312c1d Manuel Franceschini
    else:
404 8b312c1d Manuel Franceschini
      family = cls.family
405 8b312c1d Manuel Franceschini
406 8b312c1d Manuel Franceschini
    try:
407 8b312c1d Manuel Franceschini
      socket.inet_pton(family, address)
408 8b312c1d Manuel Franceschini
      return True
409 8b312c1d Manuel Franceschini
    except socket.error:
410 8b312c1d Manuel Franceschini
      return False
411 8b312c1d Manuel Franceschini
412 8b312c1d Manuel Franceschini
  @classmethod
413 7df2c4f0 Andrea Spadaccini
  def ValidateNetmask(cls, netmask):
414 7df2c4f0 Andrea Spadaccini
    """Validate a netmask suffix in CIDR notation.
415 7df2c4f0 Andrea Spadaccini

416 7df2c4f0 Andrea Spadaccini
    @type netmask: int
417 7df2c4f0 Andrea Spadaccini
    @param netmask: netmask suffix to validate
418 7df2c4f0 Andrea Spadaccini
    @rtype: bool
419 7df2c4f0 Andrea Spadaccini
    @return: True if valid, False otherwise
420 7df2c4f0 Andrea Spadaccini

421 7df2c4f0 Andrea Spadaccini
    """
422 7df2c4f0 Andrea Spadaccini
    assert (isinstance(netmask, (int, long)))
423 7df2c4f0 Andrea Spadaccini
424 7df2c4f0 Andrea Spadaccini
    return 0 < netmask <= cls.iplen
425 7df2c4f0 Andrea Spadaccini
426 7df2c4f0 Andrea Spadaccini
  @classmethod
427 8b312c1d Manuel Franceschini
  def Own(cls, address):
428 8b312c1d Manuel Franceschini
    """Check if the current host has the the given IP address.
429 8b312c1d Manuel Franceschini

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

433 8b312c1d Manuel Franceschini
    @type address: str
434 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
435 8b312c1d Manuel Franceschini
    @rtype: bool
436 8b312c1d Manuel Franceschini
    @return: True if we own the address, False otherwise
437 8b312c1d Manuel Franceschini

438 8b312c1d Manuel Franceschini
    """
439 8b312c1d Manuel Franceschini
    if cls.family is None:
440 8b312c1d Manuel Franceschini
      try:
441 8b312c1d Manuel Franceschini
        family = cls.GetAddressFamily(address)
442 8b312c1d Manuel Franceschini
      except errors.IPAddressError:
443 8b312c1d Manuel Franceschini
        return False
444 8b312c1d Manuel Franceschini
    else:
445 8b312c1d Manuel Franceschini
      family = cls.family
446 8b312c1d Manuel Franceschini
447 8b312c1d Manuel Franceschini
    s = socket.socket(family, socket.SOCK_DGRAM)
448 8b312c1d Manuel Franceschini
    success = False
449 8b312c1d Manuel Franceschini
    try:
450 8b312c1d Manuel Franceschini
      try:
451 8b312c1d Manuel Franceschini
        s.bind((address, 0))
452 8b312c1d Manuel Franceschini
        success = True
453 8b312c1d Manuel Franceschini
      except socket.error:
454 8b312c1d Manuel Franceschini
        success = False
455 8b312c1d Manuel Franceschini
    finally:
456 8b312c1d Manuel Franceschini
      s.close()
457 8b312c1d Manuel Franceschini
    return success
458 8b312c1d Manuel Franceschini
459 8b312c1d Manuel Franceschini
  @classmethod
460 8b312c1d Manuel Franceschini
  def InNetwork(cls, cidr, address):
461 8b312c1d Manuel Franceschini
    """Determine whether an address is within a network.
462 8b312c1d Manuel Franceschini

463 8b312c1d Manuel Franceschini
    @type cidr: string
464 8b312c1d Manuel Franceschini
    @param cidr: Network in CIDR notation, e.g. '192.0.2.0/24', '2001:db8::/64'
465 8b312c1d Manuel Franceschini
    @type address: str
466 8b312c1d Manuel Franceschini
    @param address: IP address
467 8b312c1d Manuel Franceschini
    @rtype: bool
468 8b312c1d Manuel Franceschini
    @return: True if address is in cidr, False otherwise
469 8b312c1d Manuel Franceschini

470 8b312c1d Manuel Franceschini
    """
471 8b312c1d Manuel Franceschini
    address_int = cls._GetIPIntFromString(address)
472 8b312c1d Manuel Franceschini
    subnet = cidr.split("/")
473 8b312c1d Manuel Franceschini
    assert len(subnet) == 2
474 8b312c1d Manuel Franceschini
    try:
475 8b312c1d Manuel Franceschini
      prefix = int(subnet[1])
476 8b312c1d Manuel Franceschini
    except ValueError:
477 8b312c1d Manuel Franceschini
      return False
478 8b312c1d Manuel Franceschini
479 8b312c1d Manuel Franceschini
    assert 0 <= prefix <= cls.iplen
480 8b312c1d Manuel Franceschini
    target_int = cls._GetIPIntFromString(subnet[0])
481 8b312c1d Manuel Franceschini
    # Convert prefix netmask to integer value of netmask
482 e687ec01 Michael Hanselmann
    netmask_int = (2 ** cls.iplen) - 1 ^ ((2 ** cls.iplen) - 1 >> prefix)
483 8b312c1d Manuel Franceschini
    # Calculate hostmask
484 e687ec01 Michael Hanselmann
    hostmask_int = netmask_int ^ (2 ** cls.iplen) - 1
485 8b312c1d Manuel Franceschini
    # Calculate network address by and'ing netmask
486 8b312c1d Manuel Franceschini
    network_int = target_int & netmask_int
487 8b312c1d Manuel Franceschini
    # Calculate broadcast address by or'ing hostmask
488 8b312c1d Manuel Franceschini
    broadcast_int = target_int | hostmask_int
489 8b312c1d Manuel Franceschini
490 8b312c1d Manuel Franceschini
    return network_int <= address_int <= broadcast_int
491 8b312c1d Manuel Franceschini
492 8b312c1d Manuel Franceschini
  @staticmethod
493 8b312c1d Manuel Franceschini
  def GetAddressFamily(address):
494 8b312c1d Manuel Franceschini
    """Get the address family of the given address.
495 8b312c1d Manuel Franceschini

496 8b312c1d Manuel Franceschini
    @type address: str
497 8b312c1d Manuel Franceschini
    @param address: ip address whose family will be returned
498 8b312c1d Manuel Franceschini
    @rtype: int
499 37531236 Andrea Spadaccini
    @return: C{socket.AF_INET} or C{socket.AF_INET6}
500 8b312c1d Manuel Franceschini
    @raise errors.GenericError: for invalid addresses
501 8b312c1d Manuel Franceschini

502 8b312c1d Manuel Franceschini
    """
503 8b312c1d Manuel Franceschini
    try:
504 8b312c1d Manuel Franceschini
      return IP4Address(address).family
505 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
506 8b312c1d Manuel Franceschini
      pass
507 8b312c1d Manuel Franceschini
508 8b312c1d Manuel Franceschini
    try:
509 8b312c1d Manuel Franceschini
      return IP6Address(address).family
510 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
511 8b312c1d Manuel Franceschini
      pass
512 8b312c1d Manuel Franceschini
513 8b312c1d Manuel Franceschini
    raise errors.IPAddressError("Invalid address '%s'" % address)
514 8b312c1d Manuel Franceschini
515 37531236 Andrea Spadaccini
  @staticmethod
516 37531236 Andrea Spadaccini
  def GetVersionFromAddressFamily(family):
517 37531236 Andrea Spadaccini
    """Convert an IP address family to the corresponding IP version.
518 37531236 Andrea Spadaccini

519 37531236 Andrea Spadaccini
    @type family: int
520 37531236 Andrea Spadaccini
    @param family: IP address family, one of socket.AF_INET or socket.AF_INET6
521 37531236 Andrea Spadaccini
    @return: an int containing the IP version, one of L{constants.IP4_VERSION}
522 37531236 Andrea Spadaccini
             or L{constants.IP6_VERSION}
523 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown families
524 37531236 Andrea Spadaccini

525 37531236 Andrea Spadaccini
    """
526 37531236 Andrea Spadaccini
    if family == socket.AF_INET:
527 37531236 Andrea Spadaccini
      return constants.IP4_VERSION
528 37531236 Andrea Spadaccini
    elif family == socket.AF_INET6:
529 37531236 Andrea Spadaccini
      return constants.IP6_VERSION
530 37531236 Andrea Spadaccini
531 37531236 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP address family" % family)
532 37531236 Andrea Spadaccini
533 37531236 Andrea Spadaccini
  @staticmethod
534 37531236 Andrea Spadaccini
  def GetAddressFamilyFromVersion(version):
535 37531236 Andrea Spadaccini
    """Convert an IP version to the corresponding IP address family.
536 37531236 Andrea Spadaccini

537 37531236 Andrea Spadaccini
    @type version: int
538 37531236 Andrea Spadaccini
    @param version: IP version, one of L{constants.IP4_VERSION} or
539 37531236 Andrea Spadaccini
                    L{constants.IP6_VERSION}
540 37531236 Andrea Spadaccini
    @return: an int containing the IP address family, one of C{socket.AF_INET}
541 37531236 Andrea Spadaccini
             or C{socket.AF_INET6}
542 37531236 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknown IP versions
543 37531236 Andrea Spadaccini

544 37531236 Andrea Spadaccini
    """
545 37531236 Andrea Spadaccini
    if version == constants.IP4_VERSION:
546 37531236 Andrea Spadaccini
      return socket.AF_INET
547 37531236 Andrea Spadaccini
    elif version == constants.IP6_VERSION:
548 37531236 Andrea Spadaccini
      return socket.AF_INET6
549 37531236 Andrea Spadaccini
550 37531236 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP version" % version)
551 37531236 Andrea Spadaccini
552 7df2c4f0 Andrea Spadaccini
  @staticmethod
553 7df2c4f0 Andrea Spadaccini
  def GetClassFromIpVersion(version):
554 7df2c4f0 Andrea Spadaccini
    """Return the IPAddress subclass for the given IP version.
555 7df2c4f0 Andrea Spadaccini

556 7df2c4f0 Andrea Spadaccini
    @type version: int
557 7df2c4f0 Andrea Spadaccini
    @param version: IP version, one of L{constants.IP4_VERSION} or
558 7df2c4f0 Andrea Spadaccini
                    L{constants.IP6_VERSION}
559 7df2c4f0 Andrea Spadaccini
    @return: a subclass of L{netutils.IPAddress}
560 7df2c4f0 Andrea Spadaccini
    @raise errors.ProgrammerError: for unknowo IP versions
561 7df2c4f0 Andrea Spadaccini

562 7df2c4f0 Andrea Spadaccini
    """
563 7df2c4f0 Andrea Spadaccini
    if version == constants.IP4_VERSION:
564 7df2c4f0 Andrea Spadaccini
      return IP4Address
565 7df2c4f0 Andrea Spadaccini
    elif version == constants.IP6_VERSION:
566 7df2c4f0 Andrea Spadaccini
      return IP6Address
567 7df2c4f0 Andrea Spadaccini
568 7df2c4f0 Andrea Spadaccini
    raise errors.ProgrammerError("%s is not a valid IP version" % version)
569 7df2c4f0 Andrea Spadaccini
570 7df2c4f0 Andrea Spadaccini
  @staticmethod
571 7df2c4f0 Andrea Spadaccini
  def GetClassFromIpFamily(family):
572 7df2c4f0 Andrea Spadaccini
    """Return the IPAddress subclass for the given IP family.
573 7df2c4f0 Andrea Spadaccini

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

578 7df2c4f0 Andrea Spadaccini
    """
579 7df2c4f0 Andrea Spadaccini
    return IPAddress.GetClassFromIpVersion(
580 7df2c4f0 Andrea Spadaccini
              IPAddress.GetVersionFromAddressFamily(family))
581 7df2c4f0 Andrea Spadaccini
582 8b312c1d Manuel Franceschini
  @classmethod
583 8b312c1d Manuel Franceschini
  def IsLoopback(cls, address):
584 8b312c1d Manuel Franceschini
    """Determine whether it is a loopback address.
585 8b312c1d Manuel Franceschini

586 8b312c1d Manuel Franceschini
    @type address: str
587 8b312c1d Manuel Franceschini
    @param address: IP address to be checked
588 8b312c1d Manuel Franceschini
    @rtype: bool
589 8b312c1d Manuel Franceschini
    @return: True if loopback, False otherwise
590 8b312c1d Manuel Franceschini

591 8b312c1d Manuel Franceschini
    """
592 8b312c1d Manuel Franceschini
    try:
593 8b312c1d Manuel Franceschini
      return cls.InNetwork(cls.loopback_cidr, address)
594 8b312c1d Manuel Franceschini
    except errors.IPAddressError:
595 8b312c1d Manuel Franceschini
      return False
596 8b312c1d Manuel Franceschini
597 8b312c1d Manuel Franceschini
598 8b312c1d Manuel Franceschini
class IP4Address(IPAddress):
599 8b312c1d Manuel Franceschini
  """IPv4 address class.
600 8b312c1d Manuel Franceschini

601 8b312c1d Manuel Franceschini
  """
602 8b312c1d Manuel Franceschini
  iplen = 32
603 8b312c1d Manuel Franceschini
  family = socket.AF_INET
604 8b312c1d Manuel Franceschini
  loopback_cidr = "127.0.0.0/8"
605 8b312c1d Manuel Franceschini
606 8b312c1d Manuel Franceschini
  def __init__(self, address):
607 8b312c1d Manuel Franceschini
    """Constructor for IPv4 address.
608 8b312c1d Manuel Franceschini

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

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

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

629 8b312c1d Manuel Franceschini
    """
630 8b312c1d Manuel Franceschini
    address_int = 0
631 8b312c1d Manuel Franceschini
    parts = address.split(".")
632 8b312c1d Manuel Franceschini
    assert len(parts) == 4
633 8b312c1d Manuel Franceschini
    for part in parts:
634 8b312c1d Manuel Franceschini
      address_int = (address_int << 8) | int(part)
635 8b312c1d Manuel Franceschini
636 8b312c1d Manuel Franceschini
    return address_int
637 8b312c1d Manuel Franceschini
638 8b312c1d Manuel Franceschini
639 8b312c1d Manuel Franceschini
class IP6Address(IPAddress):
640 8b312c1d Manuel Franceschini
  """IPv6 address class.
641 8b312c1d Manuel Franceschini

642 8b312c1d Manuel Franceschini
  """
643 8b312c1d Manuel Franceschini
  iplen = 128
644 8b312c1d Manuel Franceschini
  family = socket.AF_INET6
645 8b312c1d Manuel Franceschini
  loopback_cidr = "::1/128"
646 8b312c1d Manuel Franceschini
647 8b312c1d Manuel Franceschini
  def __init__(self, address):
648 8b312c1d Manuel Franceschini
    """Constructor for IPv6 address.
649 8b312c1d Manuel Franceschini

650 8b312c1d Manuel Franceschini
    @type address: str
651 8b312c1d Manuel Franceschini
    @param address: IP address
652 8b312c1d Manuel Franceschini
    @raises errors.IPAddressError: if address invalid
653 8b312c1d Manuel Franceschini

654 8b312c1d Manuel Franceschini
    """
655 8b312c1d Manuel Franceschini
    IPAddress.__init__(self)
656 8b312c1d Manuel Franceschini
    if not self.IsValid(address):
657 8b312c1d Manuel Franceschini
      raise errors.IPAddressError("IPv6 Address [%s] invalid" % address)
658 8b312c1d Manuel Franceschini
    self.address = address
659 8b312c1d Manuel Franceschini
660 8b312c1d Manuel Franceschini
  @staticmethod
661 8b312c1d Manuel Franceschini
  def _GetIPIntFromString(address):
662 8b312c1d Manuel Franceschini
    """Get integer value of IPv6 address.
663 8b312c1d Manuel Franceschini

664 8b312c1d Manuel Franceschini
    @type address: str
665 17f7fd27 Manuel Franceschini
    @param address: IPv6 address
666 8b312c1d Manuel Franceschini
    @rtype: int
667 8b312c1d Manuel Franceschini
    @return: integer value of given IP address
668 8b312c1d Manuel Franceschini

669 8b312c1d Manuel Franceschini
    """
670 8b312c1d Manuel Franceschini
    doublecolons = address.count("::")
671 8b312c1d Manuel Franceschini
    assert not doublecolons > 1
672 8b312c1d Manuel Franceschini
    if doublecolons == 1:
673 8b312c1d Manuel Franceschini
      # We have a shorthand address, expand it
674 8b312c1d Manuel Franceschini
      parts = []
675 8b312c1d Manuel Franceschini
      twoparts = address.split("::")
676 d0c8c01d Iustin Pop
      sep = len(twoparts[0].split(":")) + len(twoparts[1].split(":"))
677 d0c8c01d Iustin Pop
      parts = twoparts[0].split(":")
678 17385bd2 Andrea Spadaccini
      parts.extend(["0"] * (8 - sep))
679 d0c8c01d Iustin Pop
      parts += twoparts[1].split(":")
680 8b312c1d Manuel Franceschini
    else:
681 8b312c1d Manuel Franceschini
      parts = address.split(":")
682 8b312c1d Manuel Franceschini
683 8b312c1d Manuel Franceschini
    address_int = 0
684 8b312c1d Manuel Franceschini
    for part in parts:
685 d0c8c01d Iustin Pop
      address_int = (address_int << 16) + int(part or "0", 16)
686 8b312c1d Manuel Franceschini
687 8b312c1d Manuel Franceschini
    return address_int
688 1a8337f2 Manuel Franceschini
689 7845b8c8 Manuel Franceschini
690 981732fb Manuel Franceschini
def FormatAddress(address, family=None):
691 1a8337f2 Manuel Franceschini
  """Format a socket address
692 1a8337f2 Manuel Franceschini

693 1a8337f2 Manuel Franceschini
  @type address: family specific (usually tuple)
694 1a8337f2 Manuel Franceschini
  @param address: address, as reported by this class
695 981732fb Manuel Franceschini
  @type family: integer
696 981732fb Manuel Franceschini
  @param family: socket family (one of socket.AF_*) or None
697 1a8337f2 Manuel Franceschini

698 1a8337f2 Manuel Franceschini
  """
699 981732fb Manuel Franceschini
  if family is None:
700 981732fb Manuel Franceschini
    try:
701 981732fb Manuel Franceschini
      family = IPAddress.GetAddressFamily(address[0])
702 981732fb Manuel Franceschini
    except errors.IPAddressError:
703 981732fb Manuel Franceschini
      raise errors.ParameterError(address)
704 981732fb Manuel Franceschini
705 1a8337f2 Manuel Franceschini
  if family == socket.AF_UNIX and len(address) == 3:
706 1a8337f2 Manuel Franceschini
    return "pid=%s, uid=%s, gid=%s" % address
707 1a8337f2 Manuel Franceschini
708 1a8337f2 Manuel Franceschini
  if family in (socket.AF_INET, socket.AF_INET6) and len(address) == 2:
709 1a8337f2 Manuel Franceschini
    host, port = address
710 1a8337f2 Manuel Franceschini
    if family == socket.AF_INET6:
711 1a8337f2 Manuel Franceschini
      res = "[%s]" % host
712 1a8337f2 Manuel Franceschini
    else:
713 1a8337f2 Manuel Franceschini
      res = host
714 1a8337f2 Manuel Franceschini
715 1a8337f2 Manuel Franceschini
    if port is not None:
716 1a8337f2 Manuel Franceschini
      res += ":%s" % port
717 1a8337f2 Manuel Franceschini
718 1a8337f2 Manuel Franceschini
    return res
719 1a8337f2 Manuel Franceschini
720 1a8337f2 Manuel Franceschini
  raise errors.ParameterError(family, address)