1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 Miscellaneous network functions for use in flumotion.
24 """
25
26 import socket
27 import fcntl
28 import struct
29 import array
30 import re
31
32 from flumotion.common import avltree
33
34
35
36
37
38
40 """
41 Find the names of all available network interfaces
42 """
43 ptr_size = len(struct.pack('P', 0))
44 size = 24 + 2 * (ptr_size)
45 max_possible = 128
46 bytes = max_possible * size
47 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
48 names = array.array('B', '\0' * bytes)
49 outbytes = struct.unpack('iP', fcntl.ioctl(
50 s.fileno(),
51 0x8912,
52 struct.pack('iP', bytes, names.buffer_info()[0])
53 ))[0]
54 namestr = names.tostring()
55 return [namestr[i:i+size].split('\0', 1)[0] for i in range(0, outbytes, size)]
56
58 """
59 Get the IP address for an interface
60 """
61 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
62 return socket.inet_ntoa(fcntl.ioctl(
63 s.fileno(),
64 0x8915,
65 struct.pack('256s', ifname[:15])
66 )[20:24])
67
83
85 """
86 Attempt to guess a public hostname for this system.
87 """
88 ip = guess_public_ip()
89
90 try:
91 return socket.gethostbyaddr(ip)[0]
92 except:
93 return ip
94
96 try:
97 b1, b2, b3, b4 = map(int, s.split('.'))
98 except TypeError:
99 raise ValueError(s)
100
101 ret = 0
102 for n in b1, b2, b3, b4:
103 ret <<= 8
104 if n < 0 or n > 255:
105 raise ValueError(s)
106 ret += n
107 return ret
108
110 l = []
111 for i in range(4):
112 l.append((n>>(i*8)) & 0xff)
113 l.reverse()
114 return '.'.join(map(str, l))
115
117 tz = 0
118 if n == 0:
119
120 tz = 32
121 else:
122 while not (n & (1<<tz)):
123 tz += 1
124 return tz
125
127 - def fromFile(klass, f, requireNames=True, defaultRouteName='*default*'):
128 """
129 Make a new routing table, populated from entries in an open
130 file object.
131
132 The entries are expected to have the form:
133 IP-ADDRESS/MASK-BITS ROUTE-NAME
134
135 The `#' character denotes a comment. Empty lines are allowed.
136
137 @param f: file from whence to read a routing table
138 @type f: open file object
139 @param requireNames: whether to require route names in the file
140 @type requireNames: boolean, default to True
141 @param defaultRouteName: default name to give to a route if it
142 does not have a name in the file; only
143 used if requireNames is False
144 @type defaultRouteName: anything, defaults to '*default*'
145 """
146 comment = re.compile(r'^\s*#')
147 empty = re.compile(r'^\s*$')
148 entry = re.compile(r'^\s*'
149 r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
150 r'/'
151 r'(\d{1,2})'
152 r'(\s+([^\s](.*[^\s])?))?\s*$')
153 ret = klass()
154 n = 0
155 for line in f:
156 n += 1
157 if comment.match(line) or empty.match(line):
158 continue
159 m = entry.match(line)
160 if not m:
161 raise ValueError('While loading routing table from file'
162 ' %s: line %d: invalid syntax: %r'
163 % (f, n, line))
164 route = m.group(4)
165 if route is None:
166 if requireNames:
167 raise ValueError('%s:%d: Missing required route name: %r'
168 % (f, n, line))
169 else:
170 route = defaultRouteName
171 ret.addSubnet(route, m.group(1), int(m.group(2)))
172 if route not in ret.routeNames:
173 ret.routeNames.append(route)
174
175 return ret
176 fromFile = classmethod(fromFile)
177
181
183 return self.routeNames
184
186 return (ipv4StringToInt(ipv4String),
187 ~((1 << (32 - maskBits)) - 1))
188
189 - def addSubnet(self, route, ipv4String, maskBits=32):
190 ipv4Int, mask = self._parseSubnet(ipv4String, maskBits)
191 if not ipv4Int & mask == ipv4Int:
192 raise ValueError('Net %s too specific for mask with %d bits'
193 % (ipv4String, maskBits))
194 self.avltree.insert((mask, ipv4Int, route))
195
199
202
206
209
211 """
212 Return the preferred route for this IP.
213
214 @param ip: The IP to use for routing decisions.
215 @type ip: An integer or string representing an IPv4 address
216 """
217 if isinstance(ip, str):
218 ip = ipv4StringToInt(ip)
219
220 for netmask, net, route in self:
221 if ip & netmask == net:
222 return route
223
224 return None
225
227 """
228 Return an iterator yielding routes in order of preference.
229
230 @param ip: The IP to use for routing decisions.
231 @type ip: An integer or string representing an IPv4 address
232 """
233 if isinstance(ip, str):
234 ip = ipv4StringToInt(ip)
235 for mask, net, route in self:
236 if ip & mask == net:
237 yield route
238
239 yield None
240