Revision b705c7a6 lib/netutils.py
b/lib/netutils.py | ||
---|---|---|
62 | 62 |
return struct.unpack(_STRUCT_UCRED, peercred) |
63 | 63 |
|
64 | 64 |
|
65 |
def GetHostInfo(name=None):
|
|
66 |
"""Lookup host name and raise an OpPrereqError for failures"""
|
|
65 |
def GetHostname(name=None, family=None):
|
|
66 |
"""Returns a Hostname object.
|
|
67 | 67 |
|
68 |
@type name: str |
|
69 |
@param name: hostname or None |
|
70 |
@type family: int |
|
71 |
@param family: AF_INET | AF_INET6 | None |
|
72 |
@rtype: L{Hostname} |
|
73 |
@return: Hostname object |
|
74 |
@raise: errors.OpPrereqError |
|
75 |
|
|
76 |
""" |
|
68 | 77 |
try: |
69 |
return HostInfo(name)
|
|
78 |
return Hostname(name=name, family=family)
|
|
70 | 79 |
except errors.ResolverError, err: |
71 | 80 |
raise errors.OpPrereqError("The given name (%s) does not resolve: %s" % |
72 | 81 |
(err[0], err[2]), errors.ECODE_RESOLVER) |
73 | 82 |
|
74 | 83 |
|
75 |
class HostInfo:
|
|
76 |
"""Class implementing resolver and hostname functionality |
|
84 |
class Hostname:
|
|
85 |
"""Class implementing resolver and hostname functionality.
|
|
77 | 86 |
|
78 | 87 |
""" |
79 |
_VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$") |
|
80 |
|
|
81 |
def __init__(self, name=None): |
|
88 |
def __init__(self, name=None, family=None): |
|
82 | 89 |
"""Initialize the host name object. |
83 | 90 |
|
84 |
If the name argument is not passed, it will use this system's |
|
85 |
name. |
|
91 |
If the name argument is None, it will use this system's name. |
|
92 |
|
|
93 |
@type family: int |
|
94 |
@param family: AF_INET | AF_INET6 | None |
|
95 |
@type name: str |
|
96 |
@param name: hostname or None |
|
86 | 97 |
|
87 | 98 |
""" |
88 | 99 |
if name is None: |
89 |
name = self.SysName() |
|
90 |
|
|
91 |
self.query = name |
|
92 |
self.name, self.aliases, self.ipaddrs = self.LookupHostname(name) |
|
93 |
self.ip = self.ipaddrs[0] |
|
100 |
name = self.GetSysName() |
|
94 | 101 |
|
95 |
def ShortName(self): |
|
96 |
"""Returns the hostname without domain. |
|
97 |
|
|
98 |
""" |
|
99 |
return self.name.split('.')[0] |
|
102 |
self.name = self.GetNormalizedName(name) |
|
103 |
self.ip = self.GetIP(self.name, family=family) |
|
100 | 104 |
|
101 | 105 |
@staticmethod |
102 |
def SysName(): |
|
106 |
def GetSysName():
|
|
103 | 107 |
"""Return the current system's name. |
104 | 108 |
|
105 | 109 |
This is simply a wrapper over C{socket.gethostname()}. |
... | ... | |
108 | 112 |
return socket.gethostname() |
109 | 113 |
|
110 | 114 |
@staticmethod |
111 |
def LookupHostname(hostname): |
|
112 |
"""Look up hostname |
|
115 |
def GetIP(hostname, family=None): |
|
116 |
"""Return IP address of given hostname. |
|
117 |
|
|
118 |
Supports both IPv4 and IPv6. |
|
113 | 119 |
|
114 | 120 |
@type hostname: str |
115 | 121 |
@param hostname: hostname to look up |
116 |
|
|
117 |
@rtype: tuple
|
|
118 |
@return: a tuple (name, aliases, ipaddrs) as returned by
|
|
119 |
C{socket.gethostbyname_ex}
|
|
122 |
@type family: int |
|
123 |
@param family: AF_INET | AF_INET6 | None
|
|
124 |
@rtype: str
|
|
125 |
@return: IP address
|
|
120 | 126 |
@raise errors.ResolverError: in case of errors in resolving |
121 | 127 |
|
122 | 128 |
""" |
123 | 129 |
try: |
124 |
result = socket.gethostbyname_ex(hostname) |
|
130 |
if family in (socket.AF_INET, socket.AF_INET6): |
|
131 |
result = socket.getaddrinfo(hostname, None, family) |
|
132 |
else: |
|
133 |
result = socket.getaddrinfo(hostname, None, socket.AF_INET) |
|
125 | 134 |
except (socket.gaierror, socket.herror, socket.error), err: |
126 | 135 |
# hostname not found in DNS, or other socket exception in the |
127 | 136 |
# (code, description format) |
128 | 137 |
raise errors.ResolverError(hostname, err.args[0], err.args[1]) |
129 | 138 |
|
130 |
return result |
|
139 |
# getaddrinfo() returns a list of 5-tupes (family, socktype, proto, |
|
140 |
# canonname, sockaddr). We return the first tuple's first address in |
|
141 |
# sockaddr |
|
142 |
return result[0][4][0] |
|
131 | 143 |
|
132 |
@classmethod
|
|
133 |
def NormalizeName(cls, hostname):
|
|
144 |
@staticmethod
|
|
145 |
def GetNormalizedName(hostname):
|
|
134 | 146 |
"""Validate and normalize the given hostname. |
135 | 147 |
|
136 | 148 |
@attention: the validation is a bit more relaxed than the standards |
... | ... | |
138 | 150 |
@raise errors.OpPrereqError: when the name is not valid |
139 | 151 |
|
140 | 152 |
""" |
153 |
valid_name_re = re.compile("^[a-z0-9._-]{1,255}$") |
|
141 | 154 |
hostname = hostname.lower() |
142 |
if (not cls._VALID_NAME_RE.match(hostname) or
|
|
155 |
if (not valid_name_re.match(hostname) or
|
|
143 | 156 |
# double-dots, meaning empty label |
144 | 157 |
".." in hostname or |
145 | 158 |
# empty initial label |
Also available in: Unified diff