1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """miscellaneous network functions.
23 """
24
25 import array
26 import errno
27 import fcntl
28 import re
29 import socket
30 import struct
31
32 from twisted.internet import address
33
34 from flumotion.common import avltree
35
36 __version__ = "$Rev: 7056 $"
37
38
39
40
41
42
43
45 """
46 Find the names of all available network interfaces
47 """
48 ptr_size = len(struct.pack('P', 0))
49 size = 24 + 2 * (ptr_size)
50 max_possible = 128
51 bytes = max_possible * size
52 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
53 names = array.array('B', '\0' * bytes)
54 outbytes = struct.unpack('iP', fcntl.ioctl(
55 s.fileno(),
56 0x8912,
57 struct.pack('iP', bytes, names.buffer_info()[0])
58 ))[0]
59 namestr = names.tostring()
60 return [namestr[i:i+size].split('\0', 1)[0] for i in range(0, outbytes, size)]
61
63 """
64 Get the IP address for an interface
65 """
66 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
67 return socket.inet_ntoa(fcntl.ioctl(
68 s.fileno(),
69 0x8915,
70 struct.pack('256s', ifname[:15])
71 )[20:24])
72
88
90 """
91 Attempt to guess a public hostname for this system.
92 """
93 ip = guess_public_ip()
94
95 try:
96 return socket.gethostbyaddr(ip)[0]
97 except socket.error:
98 return ip
99
101 try:
102 b1, b2, b3, b4 = map(int, s.split('.'))
103 except TypeError:
104 raise ValueError(s)
105
106 ret = 0
107 for n in b1, b2, b3, b4:
108 ret <<= 8
109 if n < 0 or n > 255:
110 raise ValueError(s)
111 ret += n
112 return ret
113
115 l = []
116 for i in range(4):
117 l.append((n>>(i*8)) & 0xff)
118 l.reverse()
119 return '.'.join(map(str, l))
120
122 tz = 0
123 if n == 0:
124
125 tz = 32
126 else:
127 while not (n & (1<<tz)):
128 tz += 1
129 return tz
130
132 - def fromFile(klass, f, requireNames=True, defaultRouteName='*default*'):
133 """
134 Make a new routing table, populated from entries in an open
135 file object.
136
137 The entries are expected to have the form:
138 IP-ADDRESS/MASK-BITS ROUTE-NAME
139
140 The `#' character denotes a comment. Empty lines are allowed.
141
142 @param f: file from whence to read a routing table
143 @type f: open file object
144 @param requireNames: whether to require route names in the file
145 @type requireNames: boolean, default to True
146 @param defaultRouteName: default name to give to a route if it
147 does not have a name in the file; only
148 used if requireNames is False
149 @type defaultRouteName: anything, defaults to '*default*'
150 """
151 comment = re.compile(r'^\s*#')
152 empty = re.compile(r'^\s*$')
153 entry = re.compile(r'^\s*'
154 r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
155 r'/'
156 r'(\d{1,2})'
157 r'(\s+([^\s](.*[^\s])?))?\s*$')
158 ret = klass()
159 n = 0
160 for line in f:
161 n += 1
162 if comment.match(line) or empty.match(line):
163 continue
164 m = entry.match(line)
165 if not m:
166 raise ValueError('While loading routing table from file'
167 ' %s: line %d: invalid syntax: %r'
168 % (f, n, line))
169 route = m.group(4)
170 if route is None:
171 if requireNames:
172 raise ValueError('%s:%d: Missing required route name: %r'
173 % (f, n, line))
174 else:
175 route = defaultRouteName
176 ret.addSubnet(route, m.group(1), int(m.group(2)))
177 if route not in ret.routeNames:
178 ret.routeNames.append(route)
179
180 return ret
181 fromFile = classmethod(fromFile)
182
186
188 return self.routeNames
189
191 return (ipv4StringToInt(ipv4String),
192 ~((1 << (32 - maskBits)) - 1))
193
194 - def addSubnet(self, route, ipv4String, maskBits=32):
195 ipv4Int, mask = self._parseSubnet(ipv4String, maskBits)
196 if not ipv4Int & mask == ipv4Int:
197 raise ValueError('Net %s too specific for mask with %d bits'
198 % (ipv4String, maskBits))
199 self.avltree.insert((mask, ipv4Int, route))
200
204
207
211
214
216 """
217 Return the preferred route for this IP.
218
219 @param ip: The IP to use for routing decisions.
220 @type ip: An integer or string representing an IPv4 address
221 """
222 if isinstance(ip, str):
223 ip = ipv4StringToInt(ip)
224
225 for netmask, net, route in self:
226 if ip & netmask == net:
227 return route
228
229 return None
230
232 """
233 Return an iterator yielding routes in order of preference.
234
235 @param ip: The IP to use for routing decisions.
236 @type ip: An integer or string representing an IPv4 address
237 """
238 if isinstance(ip, str):
239 ip = ipv4StringToInt(ip)
240 for mask, net, route in self:
241 if ip & mask == net:
242 yield route
243
244 yield None
245
247 """
248 Get the host name of an IPv4 address.
249
250 @type a: L{twisted.internet.address.IPv4Address}
251 """
252 if not isinstance(a, address.IPv4Address) and not isinstance(a,
253 address.UNIXAddress):
254 raise TypeError("object %r is not an IPv4Address or UNIXAddress" % a)
255 if isinstance(a, address.UNIXAddress):
256 return 'localhost'
257
258 try:
259 host = a.host
260 except AttributeError:
261 host = a[1]
262 return host
263
265 """
266 Get the port number of an IPv4 address.
267
268 @type a: L{twisted.internet.address.IPv4Address}
269 """
270 assert(isinstance(a, address.IPv4Address))
271 try:
272 port = a.port
273 except AttributeError:
274 port = a[2]
275 return port
276
278 """Checks if the given port is unused
279 @param port: the port number or 0 for a random port
280 @type port: integer
281 @returns: port number or None if in use
282 @rtype: integer or None
283 """
284
285 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
286
287 try:
288 try:
289 s.bind(('', port))
290 port = s.getsockname()[1]
291 except socket.error, e:
292 if e.args[0] != errno.EADDRINUSE:
293 raise
294 port = None
295 finally:
296 s.close()
297
298 return port
299