Fix experimental GUI when reading hexadecimal values.
[tinc] / gui / Tinc.py
1 #!/usr/bin/python
2
3 import string
4 import socket
5
6 REQ_STOP = 0
7 REQ_RELOAD = 1
8 REQ_RESTART = 2
9 REQ_DUMP_NODES = 3
10 REQ_DUMP_EDGES = 4
11 REQ_DUMP_SUBNETS = 5
12 REQ_DUMP_CONNECTIONS = 6
13 REQ_DUMP_GRAPH = 7
14 REQ_PURGE = 8
15 REQ_SET_DEBUG = 9
16 REQ_RETRY = 10
17 REQ_CONNECT = 11
18 REQ_DISCONNECT = 12
19
20 ID = 0
21 ACK = 4
22 CONTROL = 18
23
24 class Node:
25         def __init__(self):
26                 print('New node')
27
28         def __exit__(self):
29                 print('Deleting node ' + self.name)
30
31         def parse(self, args):
32                 self.name = args[0]
33                 self.address = args[2]
34                 if args[3] != 'port':
35                         args.insert(3, 'port')
36                         args.insert(4, '')
37                 self.port = args[4]
38                 self.cipher = int(args[6])
39                 self.digest = int(args[8])
40                 self.maclength = int(args[10])
41                 self.compression = int(args[12])
42                 self.options = int(args[14], 0x10)
43                 self.status = int(args[16], 0x10)
44                 self.nexthop = args[18]
45                 self.via = args[20]
46                 self.distance = int(args[22])
47                 self.pmtu = int(args[24])
48                 self.minmtu = int(args[26])
49                 self.maxmtu = int(args[28][:-1])
50
51                 self.subnets = {}
52
53 class Edge:
54         def parse(self, args):
55                 self.fr = args[0]
56                 self.to = args[2]
57                 self.address = args[4]
58                 self.port = args[6]
59                 self.options = int(args[8], 16)
60                 self.weight = int(args[10])
61
62 class Subnet:
63         def parse(self, args):
64                 if args[0].find('#') >= 0:
65                         (address, self.weight) = args[0].split('#', 1)
66                 else:
67                         self.weight = 10
68                         address = args[0]
69
70                 if address.find('/') >= 0:
71                         (self.address, self.prefixlen) = address.split('/', 1)
72                 else:
73                         self.address = address
74                         self.prefixlen = '48'
75
76                 self.owner = args[2]    
77
78 class Connection:
79         def parse(self, args):
80                 self.name = args[0]
81                 self.address = args[2]
82                 if args[3] != 'port':
83                         args.insert(3, 'port')
84                         args.insert(4, '')
85                 self.port = args[4]
86                 self.options = int(args[6], 0x10)
87                 self.socket = int(args[8])
88                 self.status = int(args[10], 0x10)
89                 self.weight = 123
90
91 class VPN:
92         confdir = '/etc/tinc'
93         cookiedir = '/var/run/'
94
95         def connect(self):
96                 f = open(self.cookiefile)
97                 cookie = string.split(f.readline())
98                 f.close()
99                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
100                 s.connect(('127.0.0.1', int(cookie[1])))
101                 self.sf = s.makefile()
102                 s.close()
103                 hello = string.split(self.sf.readline())
104                 self.name = hello[1]
105                 self.sf.write('0 ^' + cookie[0] + ' 17\r\n')
106                 self.sf.flush()
107                 resp = string.split(self.sf.readline())
108                 self.port = cookie[1]
109                 self.nodes = {}
110                 self.edges = {}
111                 self.subnets = {}
112                 self.connections = {}
113                 self.refresh()
114
115         def refresh(self):
116                 self.sf.write('18 3\r\n18 4\r\n18 5\r\n18 6\r\n')
117                 self.sf.flush()
118
119                 for node in self.nodes.values():
120                         node.visited = False
121                 for edge in self.edges.values():
122                         edge.visited = False
123                 for subnet in self.subnets.values():
124                         subnet.visited = False
125                 for connections in self.connections.values():
126                         connections.visited = False
127
128                 while True:
129                         resp = string.split(self.sf.readline())
130                         if len(resp) < 2:
131                                 break
132                         if resp[0] != '18':
133                                 break
134                         if resp[1] == '3':
135                                 if len(resp) < 3:
136                                         continue
137                                 node = self.nodes.get(resp[2]) or Node()
138                                 node.parse(resp[2:])
139                                 node.visited = True
140                                 self.nodes[resp[2]] = node
141                         elif resp[1] == '4':
142                                 if len(resp) < 5:
143                                         continue
144                                 edge = self.nodes.get((resp[2], resp[4])) or Edge()
145                                 edge.parse(resp[2:])
146                                 edge.visited = True
147                                 self.edges[(resp[2], resp[4])] = edge
148                         elif resp[1] == '5':
149                                 if len(resp) < 5:
150                                         continue
151                                 subnet = self.subnets.get((resp[2], resp[4])) or Subnet()
152                                 subnet.parse(resp[2:])
153                                 subnet.visited = True
154                                 self.subnets[(resp[2], resp[4])] = subnet
155                                 self.nodes[subnet.owner].subnets[resp[2]] = subnet
156                         elif resp[1] == '6':
157                                 if len(resp) < 5:
158                                         break
159                                 connection = self.connections.get((resp[2], resp[4])) or Connection()
160                                 connection.parse(resp[2:])
161                                 connection.visited = True
162                                 self.connections[(resp[2], resp[4])] = connection
163                         else:
164                                 break
165
166                 for key, subnet in self.subnets.items():
167                         if not subnet.visited:
168                                 del self.subnets[key]
169
170                 for key, edge in self.edges.items():
171                         if not edge.visited:
172                                 del self.edges[key]
173
174                 for key, node in self.nodes.items():
175                         if not node.visited:
176                                 del self.nodes[key]
177                         else:
178                                 for key, subnet in node.subnets.items():
179                                         if not subnet.visited:
180                                                 del node.subnets[key]
181
182                 for key, connection in self.connections.items():
183                         if not connection.visited:
184                                 del self.connections[key]
185
186         def close(self):
187                 self.sf.close()
188
189         def disconnect(self, name):
190                 self.sf.write('18 12 ' + name + '\r\n')
191                 self.sf.flush()
192                 resp = string.split(self.sf.readline())
193
194         def debug(self, level = -1):
195                 self.sf.write('18 9 ' + str(level) + '\r\n')
196                 self.sf.flush()
197                 resp = string.split(self.sf.readline())
198                 return int(resp[2])
199
200         def __init__(self, netname = None, controlcookie = None):
201                 self.tincconf = VPN.confdir + '/'
202
203                 if netname:
204                         self.netname = netname
205                         self.tincconf += netname + '/'
206
207                 self.tincconf += 'tinc.conf'
208
209                 if controlcookie is not None:
210                         self.cookiefile = controlcookie
211                 else:
212                         self.cookiefile = VPN.cookiedir + 'tinc.'
213                         if netname:
214                                 self.cookiefile += netname + '.'
215                         self.cookiefile += 'cookie'