7 from wx.lib.mixins.listctrl import ColumnSorterMixin
8 from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
10 # Classes to interface with a running tinc daemon
18 REQ_DUMP_CONNECTIONS = 6
35 print('Deleting node ' + self.name)
37 def parse(self, args):
39 self.address = args[2]
41 args.insert(3, 'port')
44 self.cipher = int(args[6])
45 self.digest = int(args[8])
46 self.maclength = int(args[10])
47 self.compression = int(args[12])
48 self.options = int(args[14], 0x10)
49 self.status = int(args[16], 0x10)
50 self.nexthop = args[18]
52 self.distance = int(args[22])
53 self.pmtu = int(args[24])
54 self.minmtu = int(args[26])
55 self.maxmtu = int(args[28][:-1])
60 def parse(self, args):
63 self.address = args[4]
65 self.options = int(args[8], 16)
66 self.weight = int(args[10])
69 def parse(self, args):
70 if args[0].find('#') >= 0:
71 (address, self.weight) = args[0].split('#', 1)
76 if address.find('/') >= 0:
77 (self.address, self.prefixlen) = address.split('/', 1)
79 self.address = address
85 def parse(self, args):
87 self.address = args[2]
89 args.insert(3, 'port')
92 self.options = int(args[6], 0x10)
93 self.socket = int(args[8])
94 self.status = int(args[10], 0x10)
99 cookiedir = '/var/run/'
102 f = open(self.cookiefile)
103 cookie = string.split(f.readline())
105 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
106 s.connect(('127.0.0.1', int(cookie[1])))
107 self.sf = s.makefile()
109 hello = string.split(self.sf.readline())
111 self.sf.write('0 ^' + cookie[0] + ' 17\r\n')
113 resp = string.split(self.sf.readline())
114 self.port = cookie[1]
118 self.connections = {}
122 self.sf.write('18 3\r\n18 4\r\n18 5\r\n18 6\r\n')
125 for node in self.nodes.values():
127 for edge in self.edges.values():
129 for subnet in self.subnets.values():
130 subnet.visited = False
131 for connections in self.connections.values():
132 connections.visited = False
135 resp = string.split(self.sf.readline())
143 node = self.nodes.get(resp[2]) or Node()
146 self.nodes[resp[2]] = node
150 edge = self.nodes.get((resp[2], resp[4])) or Edge()
153 self.edges[(resp[2], resp[4])] = edge
157 subnet = self.subnets.get((resp[2], resp[4])) or Subnet()
158 subnet.parse(resp[2:])
159 subnet.visited = True
160 self.subnets[(resp[2], resp[4])] = subnet
161 self.nodes[subnet.owner].subnets[resp[2]] = subnet
165 connection = self.connections.get((resp[2], resp[4])) or Connection()
166 connection.parse(resp[2:])
167 connection.visited = True
168 self.connections[(resp[2], resp[4])] = connection
172 for key, subnet in self.subnets.items():
173 if not subnet.visited:
174 del self.subnets[key]
176 for key, edge in self.edges.items():
180 for key, node in self.nodes.items():
184 for key, subnet in node.subnets.items():
185 if not subnet.visited:
186 del node.subnets[key]
188 for key, connection in self.connections.items():
189 if not connection.visited:
190 del self.connections[key]
195 def disconnect(self, name):
196 self.sf.write('18 12 ' + name + '\r\n')
198 resp = string.split(self.sf.readline())
200 def debug(self, level = -1):
201 self.sf.write('18 9 ' + str(level) + '\r\n')
203 resp = string.split(self.sf.readline())
206 def __init__(self, netname = None, controlcookie = None):
207 self.tincconf = VPN.confdir + '/'
210 self.netname = netname
211 self.tincconf += netname + '/'
213 self.tincconf += 'tinc.conf'
215 if controlcookie is not None:
216 self.cookiefile = controlcookie
218 self.cookiefile = VPN.cookiedir + 'tinc.'
220 self.cookiefile += netname + '.'
221 self.cookiefile += 'cookie'
229 while len(sys.argv) >= 2:
230 if sys.argv[0] in ('-n', '--net'):
232 elif sys.argv[0] in ('--controlcookie'):
233 controlcookie = sys.argv[1]
235 print('Unknown option ' + sys.argv[0])
241 vpn = VPN(net, controlcookie)
244 class SuperListCtrl(wx.ListCtrl, ColumnSorterMixin, ListCtrlAutoWidthMixin):
245 def __init__(self, parent, style):
246 wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
247 ListCtrlAutoWidthMixin.__init__(self)
248 ColumnSorterMixin.__init__(self, 14)
250 def GetListCtrl(self):
254 class SettingsPage(wx.Panel):
255 def OnDebugLevel(self, event):
256 vpn.debug(self.debug.GetValue())
258 def __init__(self, parent, id):
259 wx.Panel.__init__(self, parent, id)
260 grid = wx.FlexGridSizer(cols = 2)
261 grid.AddGrowableCol(0, 1)
263 namelabel = wx.StaticText(self, -1, 'Name:')
264 self.name = wx.TextCtrl(self, -1, vpn.name)
268 portlabel = wx.StaticText(self, -1, 'Port:')
269 self.port = wx.TextCtrl(self, -1, vpn.port)
273 debuglabel = wx.StaticText(self, -1, 'Debug level:')
274 self.debug = wx.SpinCtrl(self, min = 0, max = 5, initial = vpn.debug())
275 self.debug.Bind(wx.EVT_SPINCTRL, self.OnDebugLevel)
279 modelabel = wx.StaticText(self, -1, 'Mode:')
280 self.mode = wx.ComboBox(self, -1, style = wx.CB_READONLY, value = 'Router', choices = ['Router', 'Switch', 'Hub'])
286 class ConnectionsPage(wx.Panel):
287 def __init__(self, parent, id):
288 wx.Panel.__init__(self, parent, id)
289 self.list = wx.ListCtrl(self, id, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
290 self.list.InsertColumn(0, 'Name')
291 self.list.InsertColumn(1, 'Address')
292 self.list.InsertColumn(2, 'Port')
293 self.list.InsertColumn(3, 'Options')
294 self.list.InsertColumn(4, 'Weight')
296 hbox = wx.BoxSizer(wx.HORIZONTAL)
297 hbox.Add(self.list, 1, wx.EXPAND)
301 class ContextMenu(wx.Menu):
302 def __init__(self, item):
303 wx.Menu.__init__(self)
307 disconnect = wx.MenuItem(self, -1, 'Disconnect')
308 self.AppendItem(disconnect)
309 self.Bind(wx.EVT_MENU, self.OnDisconnect, id=disconnect.GetId())
311 def OnDisconnect(self, event):
312 print('Disconnecting ' + self.item[0])
313 vpn.disconnect(self.item[0])
315 def OnContext(self, event):
316 print('Context menu!')
319 self.PopupMenu(self.ContextMenu(self.list.itemDataMap[event.GetIndex()]), event.GetPosition())
322 self.list.itemDataMap = {}
325 for key, connection in vpn.connections.items():
326 if self.list.GetItemCount() <= i:
327 self.list.InsertStringItem(i, connection.name)
329 self.list.SetStringItem(i, 0, connection.name)
330 self.list.SetStringItem(i, 1, connection.address)
331 self.list.SetStringItem(i, 2, connection.port)
332 self.list.SetStringItem(i, 3, str(connection.options))
333 self.list.SetStringItem(i, 4, str(connection.weight))
334 self.list.itemDataMap[i] = (connection.name, connection.address, connection.port, connection.options, connection.weight)
335 self.list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnContext)
338 while self.list.GetItemCount() > i:
339 self.list.DeleteItem(self.list.GetItemCount() - 1)
342 class NodesPage(wx.Panel):
343 def __init__(self, parent, id):
344 wx.Panel.__init__(self, parent, id)
345 self.list = SuperListCtrl(self, id)
346 self.list.InsertColumn( 0, 'Name')
347 self.list.InsertColumn( 1, 'Address')
348 self.list.InsertColumn( 2, 'Port')
349 self.list.InsertColumn( 3, 'Cipher')
350 self.list.InsertColumn( 4, 'Digest')
351 self.list.InsertColumn( 5, 'MACLength')
352 self.list.InsertColumn( 6, 'Compression')
353 self.list.InsertColumn( 7, 'Options')
354 self.list.InsertColumn( 8, 'Status')
355 self.list.InsertColumn( 9, 'Nexthop')
356 self.list.InsertColumn(10, 'Via')
357 self.list.InsertColumn(11, 'Distance')
358 self.list.InsertColumn(12, 'PMTU')
359 self.list.InsertColumn(13, 'Min MTU')
360 self.list.InsertColumn(14, 'Max MTU')
362 hbox = wx.BoxSizer(wx.HORIZONTAL)
363 hbox.Add(self.list, 1, wx.EXPAND)
368 self.list.itemDataMap = {}
371 for key, node in vpn.nodes.items():
372 if self.list.GetItemCount() <= i:
373 self.list.InsertStringItem(i, node.name)
375 self.list.SetStringItem(i, 0, node.name)
376 self.list.SetStringItem(i, 1, node.address)
377 self.list.SetStringItem(i, 2, node.port)
378 self.list.SetStringItem(i, 3, str(node.cipher))
379 self.list.SetStringItem(i, 4, str(node.digest))
380 self.list.SetStringItem(i, 5, str(node.maclength))
381 self.list.SetStringItem(i, 6, str(node.compression))
382 self.list.SetStringItem(i, 7, str(node.options))
383 self.list.SetStringItem(i, 8, str(node.status))
384 self.list.SetStringItem(i, 9, node.nexthop)
385 self.list.SetStringItem(i, 10, node.via)
386 self.list.SetStringItem(i, 11, str(node.distance))
387 self.list.SetStringItem(i, 12, str(node.pmtu))
388 self.list.SetStringItem(i, 13, str(node.minmtu))
389 self.list.SetStringItem(i, 14, str(node.maxmtu))
390 self.list.itemDataMap[i] = (node.name, node.address, node.port, node.cipher, node.digest, node.maclength, node.compression, node.options, node.status, node.nexthop, node.via, node.distance, node.pmtu, node.minmtu, node.maxmtu)
391 self.list.SetItemData(i, i)
394 while self.list.GetItemCount() > i:
395 self.list.DeleteItem(self.list.GetItemCount() - 1)
397 class EdgesPage(wx.Panel):
398 def __init__(self, parent, id):
399 wx.Panel.__init__(self, parent, id)
400 self.list = wx.ListCtrl(self, id, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
401 self.list.InsertColumn(0, 'From')
402 self.list.InsertColumn(1, 'To')
403 self.list.InsertColumn(2, 'Address')
404 self.list.InsertColumn(3, 'Port')
405 self.list.InsertColumn(4, 'Options')
406 self.list.InsertColumn(5, 'Weight')
408 hbox = wx.BoxSizer(wx.HORIZONTAL)
409 hbox.Add(self.list, 1, wx.EXPAND)
414 self.list.itemDataMap = {}
417 for key, edge in vpn.edges.items():
418 if self.list.GetItemCount() <= i:
419 self.list.InsertStringItem(i, edge.fr)
421 self.list.SetStringItem(i, 0, edge.fr)
422 self.list.SetStringItem(i, 1, edge.to)
423 self.list.SetStringItem(i, 2, edge.address)
424 self.list.SetStringItem(i, 3, edge.port)
425 self.list.SetStringItem(i, 4, str(edge.options))
426 self.list.SetStringItem(i, 5, str(edge.weight))
427 self.list.itemDataMap[i] = (edge.fr, edge.to, edge.address, edge.port, edge.options, edge.weight)
430 while self.list.GetItemCount() > i:
431 self.list.DeleteItem(self.list.GetItemCount() - 1)
433 class SubnetsPage(wx.Panel):
434 def __init__(self, parent, id):
435 wx.Panel.__init__(self, parent, id)
436 self.list = SuperListCtrl(self, id)
437 self.list.InsertColumn(0, 'Subnet', wx.LIST_FORMAT_RIGHT)
438 self.list.InsertColumn(1, 'Weight', wx.LIST_FORMAT_RIGHT)
439 self.list.InsertColumn(2, 'Owner')
440 hbox = wx.BoxSizer(wx.HORIZONTAL)
441 hbox.Add(self.list, 1, wx.EXPAND)
446 self.list.itemDataMap = {}
449 for key, subnet in vpn.subnets.items():
450 if self.list.GetItemCount() <= i:
451 self.list.InsertStringItem(i, subnet.address + '/' + subnet.prefixlen)
453 self.list.SetStringItem(i, 0, subnet.address + '/' + subnet.prefixlen)
454 self.list.SetStringItem(i, 1, subnet.weight)
455 self.list.SetStringItem(i, 2, subnet.owner)
456 self.list.itemDataMap[i] = (subnet.address + '/' + subnet.prefixlen, subnet.weight, subnet.owner)
459 while self.list.GetItemCount() > i:
460 self.list.DeleteItem(self.list.GetItemCount() - 1)
462 class StatusPage(wx.Panel):
463 def __init__(self, parent, id):
464 wx.Panel.__init__(self, parent, id)
466 class GraphPage(wx.Window):
467 def __init__(self, parent, id):
468 wx.Window.__init__(self, parent, id)
470 class NetPage(wx.Notebook):
471 def __init__(self, parent, id):
472 wx.Notebook.__init__(self, parent)
473 self.settings = SettingsPage(self, id)
474 self.connections = ConnectionsPage(self, id)
475 self.nodes = NodesPage(self, id)
476 self.edges = EdgesPage(self, id)
477 self.subnets = SubnetsPage(self, id)
478 self.graph = GraphPage(self, id)
479 self.status = StatusPage(self, id)
481 self.AddPage(self.settings, 'Settings')
482 #self.AddPage(self.status, 'Status')
483 self.AddPage(self.connections, 'Connections')
484 self.AddPage(self.nodes, 'Nodes')
485 self.AddPage(self.edges, 'Edges')
486 self.AddPage(self.subnets, 'Subnets')
487 #self.AddPage(self.graph, 'Graph')
490 class MainWindow(wx.Frame):
491 def OnQuit(self, event):
494 def OnTimer(self, event):
496 self.np.nodes.refresh()
497 self.np.subnets.refresh()
498 self.np.edges.refresh()
499 self.np.connections.refresh()
501 def __init__(self, parent, id, title):
502 wx.Frame.__init__(self, parent, id, title)
504 menubar = wx.MenuBar()
506 file.Append(1, '&Quit\tCtrl-X', 'Quit tinc GUI')
507 menubar.Append(file, '&File')
509 #nb = wx.Notebook(self, -1)
510 #nb.SetPadding((0, 0))
511 self.np = NetPage(self, -1)
512 #nb.AddPage(np, 'VPN')
514 self.timer = wx.Timer(self, -1)
515 self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
516 self.timer.Start(1000)
517 self.Bind(wx.EVT_MENU, self.OnQuit, id=1)
518 self.SetMenuBar(menubar)
522 mw = MainWindow(None, -1, 'Tinc GUI')
524 #def OnTaskBarIcon(event):
527 #icon = wx.Icon("tincgui.ico", wx.BITMAP_TYPE_PNG)
528 #taskbaricon = wx.TaskBarIcon()
529 #taskbaricon.SetIcon(icon, 'Tinc GUI')
530 #wx.EVT_TASKBAR_RIGHT_UP(taskbaricon, OnTaskBarIcon)