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 """Make a new routing table, populated from entries in an open
129 file object.
130
131 The entries are expected to have the form:
132 IP-ADDRESS/MASK-BITS ROUTE-NAME
133
134 The `#' character denotes a comment. Empty lines are allowed.
135
136 @param f: file from whence to read a routing table
137 @type f: open file object
138 @param requireNames: whether to require route names in the file
139 @type requireNames: boolean, default to True
140 @param defaultRouteName: default name to give to a route if it
141 does not have a name in the file; only
142 used if requireNames is False
143 @type defaultRouteName: anything, defaults to '*default*'
144 """
145 comment = re.compile(r'^\s*#')
146 empty = re.compile(r'^\s*$')
147 entry = re.compile(r'^\s*'
148 r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
149 r'/'
150 r'(\d{1,2})'
151 r'(\s+([^\s](.*[^\s])?))?\s*$')
152 ret = klass()
153 n = 0
154 for line in f:
155 n += 1
156 if comment.match(line) or empty.match(line):
157 continue
158 m = entry.match(line)
159 if not m:
160 raise ValueError('While loading routing table from file'
161 ' %s: line %d: invalid syntax: %r'
162 % (f, n, line))
163 route = m.group(4)
164 if route is None:
165 if requireNames:
166 raise ValueError('%s:%d: Missing required route name: %r'
167 % (f, n, line))
168 else:
169 route = defaultRouteName
170 ret.addSubnet(route, m.group(1), int(m.group(2)))
171 if route not in ret.routeNames:
172 ret.routeNames.append(route)
173
174 return ret
175 fromFile = classmethod(fromFile)
176
180
182 return self.routeNames
183
185 return (ipv4StringToInt(ipv4String),
186 ~((1 << (32 - maskBits)) - 1))
187
188 - def addSubnet(self, route, ipv4String, maskBits=32):
189 ipv4Int, mask = self._parseSubnet(ipv4String, maskBits)
190 if not ipv4Int & mask == ipv4Int:
191 raise ValueError('Net %s too specific for mask with %d bits'
192 % (ipv4String, maskBits))
193 self.avltree.insert((mask, ipv4Int, route))
194
198
201
205
208
210 if isinstance(ip, str):
211 ip = ipv4StringToInt(ip)
212
213 for netmask, net, route in self:
214 if ip & netmask == net:
215 return route
216
217 return None
218
220 if isinstance(ip, str):
221 ip = ipv4StringToInt(ip)
222 for mask, net, route in self:
223 if ip & mask == net:
224 yield route
225
226 yield None
227