X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=gui%2Ftinc-gui;h=6facb7cb5caf96904aa7d8b60adc4c49a741b9ec;hp=e5c9f76647549dea371359ef09ecec1a844ef3c8;hb=27e6a89b155b171b0b026d5e24ee0cc68f43d010;hpb=103543aa2c15d9f1e2aa313a2e593a7524cce484 diff --git a/gui/tinc-gui b/gui/tinc-gui index e5c9f766..6facb7cb 100755 --- a/gui/tinc-gui +++ b/gui/tinc-gui @@ -1,28 +1,257 @@ #!/usr/bin/python +import string +import socket import wx import sys -import Tinc from wx.lib.mixins.listctrl import ColumnSorterMixin from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin +# Classes to interface with a running tinc daemon + +REQ_STOP = 0 +REQ_RELOAD = 1 +REQ_RESTART = 2 +REQ_DUMP_NODES = 3 +REQ_DUMP_EDGES = 4 +REQ_DUMP_SUBNETS = 5 +REQ_DUMP_CONNECTIONS = 6 +REQ_DUMP_GRAPH = 7 +REQ_PURGE = 8 +REQ_SET_DEBUG = 9 +REQ_RETRY = 10 +REQ_CONNECT = 11 +REQ_DISCONNECT = 12 + +ID = 0 +ACK = 4 +CONTROL = 18 + +class Node: + def __init__(self): + print('New node') + + def __exit__(self): + print('Deleting node ' + self.name) + + def parse(self, args): + self.name = args[0] + self.address = args[2] + if args[3] != 'port': + args.insert(3, 'port') + args.insert(4, '') + self.port = args[4] + self.cipher = int(args[6]) + self.digest = int(args[8]) + self.maclength = int(args[10]) + self.compression = int(args[12]) + self.options = int(args[14], 0x10) + self.status = int(args[16], 0x10) + self.nexthop = args[18] + self.via = args[20] + self.distance = int(args[22]) + self.pmtu = int(args[24]) + self.minmtu = int(args[26]) + self.maxmtu = int(args[28][:-1]) + + self.subnets = {} + +class Edge: + def parse(self, args): + self.fr = args[0] + self.to = args[2] + self.address = args[4] + self.port = args[6] + self.options = int(args[8], 16) + self.weight = int(args[10]) + +class Subnet: + def parse(self, args): + if args[0].find('#') >= 0: + (address, self.weight) = args[0].split('#', 1) + else: + self.weight = 10 + address = args[0] + + if address.find('/') >= 0: + (self.address, self.prefixlen) = address.split('/', 1) + else: + self.address = address + self.prefixlen = '48' + + self.owner = args[2] + +class Connection: + def parse(self, args): + self.name = args[0] + self.address = args[2] + if args[3] != 'port': + args.insert(3, 'port') + args.insert(4, '') + self.port = args[4] + self.options = int(args[6], 0x10) + self.socket = int(args[8]) + self.status = int(args[10], 0x10) + self.weight = 123 + +class VPN: + confdir = '/etc/tinc' + piddir = '/var/run/' + + def connect(self): + f = open(self.pidfile) + info = string.split(f.readline()) + f.close() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((info[2], int(info[4]))) + self.sf = s.makefile() + s.close() + hello = string.split(self.sf.readline()) + self.name = hello[1] + self.sf.write('0 ^' + info[1] + ' 17\r\n') + self.sf.flush() + resp = string.split(self.sf.readline()) + self.port = info[4] + self.nodes = {} + self.edges = {} + self.subnets = {} + self.connections = {} + self.refresh() + + def refresh(self): + self.sf.write('18 3\r\n18 4\r\n18 5\r\n18 6\r\n') + self.sf.flush() + + for node in self.nodes.values(): + node.visited = False + for edge in self.edges.values(): + edge.visited = False + for subnet in self.subnets.values(): + subnet.visited = False + for connections in self.connections.values(): + connections.visited = False + + while True: + resp = string.split(self.sf.readline()) + if len(resp) < 2: + break + if resp[0] != '18': + break + if resp[1] == '3': + if len(resp) < 3: + continue + node = self.nodes.get(resp[2]) or Node() + node.parse(resp[2:]) + node.visited = True + self.nodes[resp[2]] = node + elif resp[1] == '4': + if len(resp) < 5: + continue + edge = self.nodes.get((resp[2], resp[4])) or Edge() + edge.parse(resp[2:]) + edge.visited = True + self.edges[(resp[2], resp[4])] = edge + elif resp[1] == '5': + if len(resp) < 5: + continue + subnet = self.subnets.get((resp[2], resp[4])) or Subnet() + subnet.parse(resp[2:]) + subnet.visited = True + self.subnets[(resp[2], resp[4])] = subnet + self.nodes[subnet.owner].subnets[resp[2]] = subnet + elif resp[1] == '6': + if len(resp) < 5: + break + connection = self.connections.get((resp[2], resp[4])) or Connection() + connection.parse(resp[2:]) + connection.visited = True + self.connections[(resp[2], resp[4])] = connection + else: + break + + for key, subnet in self.subnets.items(): + if not subnet.visited: + del self.subnets[key] + + for key, edge in self.edges.items(): + if not edge.visited: + del self.edges[key] + + for key, node in self.nodes.items(): + if not node.visited: + del self.nodes[key] + else: + for key, subnet in node.subnets.items(): + if not subnet.visited: + del node.subnets[key] + + for key, connection in self.connections.items(): + if not connection.visited: + del self.connections[key] + + def close(self): + self.sf.close() + + def disconnect(self, name): + self.sf.write('18 12 ' + name + '\r\n') + self.sf.flush() + resp = string.split(self.sf.readline()) + + def debug(self, level = -1): + self.sf.write('18 9 ' + str(level) + '\r\n') + self.sf.flush() + resp = string.split(self.sf.readline()) + return int(resp[2]) + + def __init__(self, netname = None, pidfile = None): + self.tincconf = VPN.confdir + '/' + + if netname: + self.netname = netname + self.tincconf += netname + '/' + + self.tincconf += 'tinc.conf' + + if pidfile is not None: + self.pidfile = pidfile + else: + self.pidfile = VPN.piddir + 'tinc.' + if netname: + self.pidfile += netname + '.' + self.pidfile += 'pid' + +# GUI starts here + +argv0 = sys.argv[0] del sys.argv[0] net = None -controlcookie = None - -while len(sys.argv) >= 2: +pidfile = None + +def usage(exitcode = 0): + print('Usage: ' + argv0 + ' [options]') + print('\nValid options are:') + print(' -n, --net=NETNAME Connect to net NETNAME.') + print(' --pidfile=FILENAME Read control cookie from FILENAME.') + print(' --help Display this help and exit.') + print('\nReport bugs to tinc@tinc-vpn.org.') + sys.exit(exitcode) + +while len(sys.argv): if sys.argv[0] in ('-n', '--net'): - net = sys.argv[1] - elif sys.argv[0] in ('--controlcookie'): - controlcookie = sys.argv[1] + del sys.argv[0] + net = sys.argv[0] + elif sys.argv[0] in ('--pidfile'): + del sys.argv[0] + pidfile = sys.argv[0] + elif sys.argv[0] in ('--help'): + usage(0) else: - print('Unknown option ' + sys.argv[0]) - sys.exit(1) + print(argv0 + ': unrecognized option \'' + sys.argv[0] + '\'') + usage(1) del sys.argv[0] - del sys.argv[0] -vpn = Tinc.VPN(net, controlcookie) +vpn = VPN(net, pidfile) vpn.connect() class SuperListCtrl(wx.ListCtrl, ColumnSorterMixin, ListCtrlAutoWidthMixin): @@ -107,7 +336,7 @@ class ConnectionsPage(wx.Panel): i = 0 for key, connection in vpn.connections.items(): - if self.list.ItemCount <= i: + if self.list.GetItemCount() <= i: self.list.InsertStringItem(i, connection.name) else: self.list.SetStringItem(i, 0, connection.name) @@ -119,8 +348,8 @@ class ConnectionsPage(wx.Panel): self.list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnContext) i += 1 - while self.list.ItemCount > i: - self.list.DeleteItem(self.list.ItemCount - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) class NodesPage(wx.Panel): @@ -153,7 +382,7 @@ class NodesPage(wx.Panel): i = 0 for key, node in vpn.nodes.items(): - if self.list.ItemCount <= i: + if self.list.GetItemCount() <= i: self.list.InsertStringItem(i, node.name) else: self.list.SetStringItem(i, 0, node.name) @@ -175,8 +404,8 @@ class NodesPage(wx.Panel): self.list.SetItemData(i, i) i += 1 - while self.list.ItemCount > i: - self.list.DeleteItem(self.list.ItemCount - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) class EdgesPage(wx.Panel): def __init__(self, parent, id): @@ -199,7 +428,7 @@ class EdgesPage(wx.Panel): i = 0 for key, edge in vpn.edges.items(): - if self.list.ItemCount <= i: + if self.list.GetItemCount() <= i: self.list.InsertStringItem(i, edge.fr) else: self.list.SetStringItem(i, 0, edge.fr) @@ -211,8 +440,8 @@ class EdgesPage(wx.Panel): self.list.itemDataMap[i] = (edge.fr, edge.to, edge.address, edge.port, edge.options, edge.weight) i += 1 - while self.list.ItemCount > i: - self.list.DeleteItem(self.list.ItemCount - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) class SubnetsPage(wx.Panel): def __init__(self, parent, id): @@ -231,7 +460,7 @@ class SubnetsPage(wx.Panel): i = 0 for key, subnet in vpn.subnets.items(): - if self.list.ItemCount <= i: + if self.list.GetItemCount() <= i: self.list.InsertStringItem(i, subnet.address + '/' + subnet.prefixlen) else: self.list.SetStringItem(i, 0, subnet.address + '/' + subnet.prefixlen) @@ -240,8 +469,8 @@ class SubnetsPage(wx.Panel): self.list.itemDataMap[i] = (subnet.address + '/' + subnet.prefixlen, subnet.weight, subnet.owner) i = i + 1 - while self.list.ItemCount > i: - self.list.DeleteItem(self.list.ItemCount - 1) + while self.list.GetItemCount() > i: + self.list.DeleteItem(self.list.GetItemCount() - 1) class StatusPage(wx.Panel): def __init__(self, parent, id):