X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/a69f441795eff547976f0556f45814942cd35bbe..171206b508a85f9e9fd5cdba18145b18285bc7ef:/mon/tripemon.in diff --git a/mon/tripemon.in b/mon/tripemon.in index b7c50243..24709344 100644 --- a/mon/tripemon.in +++ b/mon/tripemon.in @@ -10,19 +10,18 @@ ### ### This file is part of Trivial IP Encryption (TrIPE). ### -### TrIPE is free software; you can redistribute it and/or modify -### it under the terms of the GNU General Public License as published by -### the Free Software Foundation; either version 2 of the License, or -### (at your option) any later version. +### TrIPE is free software: you can redistribute it and/or modify it under +### the terms of the GNU General Public License as published by the Free +### Software Foundation; either version 3 of the License, or (at your +### option) any later version. ### -### TrIPE is distributed in the hope that it will be useful, -### but WITHOUT ANY WARRANTY; without even the implied warranty of -### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -### GNU General Public License for more details. +### TrIPE is distributed in the hope that it will be useful, but WITHOUT +### ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +### FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +### for more details. ### ### You should have received a copy of the GNU General Public License -### along with TrIPE; if not, write to the Free Software Foundation, -### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +### along with TrIPE. If not, see . ###-------------------------------------------------------------------------- ### Dependencies. @@ -41,13 +40,14 @@ import re as RX from cStringIO import StringIO try: - if OS.getenv('TRIPEMON_FORCE_GI'): raise ImportError + if OS.getenv('TRIPEMON_FORCE_GI'): raise ImportError() import pygtk pygtk.require('2.0') import gtk as G import gobject as GO import gtk.gdk as GDK GL = GO + GDK.KEY_Escape = G.keysyms.Escape def raise_window(w): w.window.raise_() combo_box_text = G.combo_box_new_text def set_entry_bg(e, c): e.modify_base(G.STATE_NORMAL, c) @@ -311,6 +311,7 @@ class Peer (MonitorObject): """Initialize the object with the given name.""" MonitorObject.__init__(me, name) me.pinghook = HookList() + me.__dict__.update(conn.algs(name)) me.update() def update(me, hunoz = None): @@ -556,6 +557,17 @@ class MyWindow (MyWindowMixin): G.Window.__init__(me, kind) me.mywininit() +class TrivialWindowMixin (MyWindowMixin): + """A simple window which you can close with Escape.""" + def mywininit(me): + super(TrivialWindowMixin, me).mywininit() + me.connect('key-press-event', me._keypress) + def _keypress(me, _, ev): + if ev.keyval == GDK.KEY_Escape: me.destroy() + +class TrivialWindow (MyWindow, TrivialWindowMixin): + pass + class MyDialog (G.Dialog, MyWindowMixin, HookClient): """A dialogue box with a closehook and sensible button binding.""" @@ -761,7 +773,7 @@ class ValidatingEntry (G.Entry): ValidationError. """ if not me.validp: - raise ValidationError + raise ValidationError() return G.Entry.get_text(me) def numericvalidate(min = None, max = None): @@ -778,21 +790,21 @@ def numericvalidate(min = None, max = None): ###-------------------------------------------------------------------------- ### Various minor dialog boxen. -GPL = """This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. +GPL = """\ +TrIPE is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3 of the License, or (at your +option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +TrIPE is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.""" +along with TrIPE. If not, see .""" -class AboutBox (G.AboutDialog, MyWindowMixin): +class AboutBox (G.AboutDialog, TrivialWindowMixin): """The program `About' box.""" def __init__(me): G.AboutDialog.__init__(me) @@ -873,7 +885,7 @@ class WarningLogModel (LogModel): """Call with a new warning message.""" me.add(tag, ' '.join([T.quotify(w) for w in rest])) -class LogViewer (MyWindow): +class LogViewer (TrivialWindow): """ A log viewer window. @@ -889,7 +901,7 @@ class LogViewer (MyWindow): """ Create a log viewer showing the LogModel MODEL. """ - MyWindow.__init__(me) + TrivialWindow.__init__(me) me.model = model scr = MyScrolledWindow() me.list = MyTreeView(me.model) @@ -1052,53 +1064,72 @@ class AddPeerDialog (MyDialog): ValidatingEntry(numericvalidate(0, 65535), '4070', 5)) - me.c_keepalive = G.CheckButton('Keepalives') me.l_tunnel = table.labelled('Tunnel', combo_box_text(), newlinep = True, width = 3) - me.tuns = conn.tunnels() + me.tuns = ['(Default)'] + conn.tunnels() for t in me.tuns: me.l_tunnel.append_text(t) me.l_tunnel.set_active(0) - table.pack(me.c_keepalive, newlinep = True, xopt = G.FILL) - me.c_keepalive.connect('toggled', - lambda t: me.e_keepalive.set_sensitive\ - (t.get_active())) - me.e_keepalive = ValidatingEntry(r'^\d+[hms]?$', '', 5) - me.e_keepalive.set_sensitive(False) - table.pack(me.e_keepalive, width = 3) + + def tickybox_sensitivity(tickybox, target): + tickybox.connect('toggled', + lambda t: target.set_sensitive (t.get_active())) + + def optional_entry(label, rx_valid, width): + c = G.CheckButton(label) + table.pack(c, newlinep = True, xopt = G.FILL) + e = ValidatingEntry(rx_valid, '', width) + e.set_sensitive(False) + tickybox_sensitivity(c, e) + table.pack(e, width = 3) + return c, e + + me.c_keepalive, me.e_keepalive = \ + optional_entry('Keepalives', r'^\d+[hms]?$', 5) + + me.c_cork = G.CheckButton('Cork') + table.pack(me.c_cork, newlinep = True, width = 4, xopt = G.FILL) + + me.c_mobile = G.CheckButton('Mobile') + table.pack(me.c_mobile, newlinep = True, width = 4, xopt = G.FILL) + + me.c_peerkey, me.e_peerkey = \ + optional_entry('Peer key tag', r'^[^.:\s]+$', 16) + me.c_privkey, me.e_privkey = \ + optional_entry('Private key tag', r'^[^.:\s]+$', 16) + me.show_all() def ok(me): """Handle an OK press: create the peer.""" try: - if me.c_keepalive.get_active(): - ka = me.e_keepalive.get_text() - else: - ka = None t = me.l_tunnel.get_active() - if t == 0: - tun = None - else: - tun = me.tuns[t] - me._addpeer(me.e_name.get_text(), - me.e_addr.get_text(), - me.e_port.get_text(), - ka, - tun) + me._addpeer(me.e_name.get_text(), + me.e_addr.get_text(), + me.e_port.get_text(), + keepalive = (me.c_keepalive.get_active() and + me.e_keepalive.get_text() or None), + tunnel = t and me.tuns[t] or None, + cork = me.c_cork.get_active() or None, + mobile = me.c_mobile.get_active() or None, + key = (me.c_peerkey.get_active() and + me.e_peerkey.get_text() or None), + priv = (me.c_privkey.get_active() and + me.e_privkey.get_text() or None)) except ValidationError: GDK.beep() return @incr - def _addpeer(me, name, addr, port, keepalive, tunnel): + def _addpeer(me, *args, **kw): """Coroutine function: actually do the ADD command.""" try: - conn.add(name, addr, port, keepalive = keepalive, tunnel = tunnel) + conn.add(*args, **kw) me.destroy() except T.TripeError, exc: T.defer(moanbox, ' '.join(exc)) -class ServInfo (MyWindow): +class ServInfo (TrivialWindow): """ Show information about the server and available services. @@ -1109,7 +1140,7 @@ class ServInfo (MyWindow): """ def __init__(me): - MyWindow.__init__(me) + TrivialWindow.__init__(me) me.set_title('TrIPE server info') table = GridPacker() me.add(table) @@ -1199,7 +1230,7 @@ def xlate_time(t): return '%04d:%02d:%02d %02d:%02d:%02d (%.1f %s ago)' % \ (YY, MM, DD, hh, mm, ss, ago, unit) def xlate_bytes(b): - """Translate a number of bytes into something a human might want to read.""" + """Translate a raw byte count into something a human might want to read.""" suff = 'B' b = int(b) for s in 'KMG': @@ -1221,12 +1252,40 @@ statsxlate = \ ('ip-bytes-in', xlate_bytes), ('ip-bytes-out', xlate_bytes)] +def format_stat(format, dict): + if callable(format): return format(dict) + else: return format % dict + ## How to lay out the stats dialog. Format is (LABEL, FORMAT): LABEL is ## the label to give the entry box; FORMAT is the format string to write into ## the entry. +cryptolayout = \ + [('Diffie-Hellman group', + '%(kx-group)s ' + '(%(kx-group-order-bits)s-bit order, ' + '%(kx-group-elt-bits)s-bit elements)'), + ('Bulk crypto transform', + '%(bulk-transform)s (%(bulk-overhead)s byte overhead)'), + ('Data encryption', lambda d: '%s (%s; %s)' % ( + d['cipher'], + '%d-bit key' % (8*int(d['cipher-keysz'])), + d.get('cipher-blksz', '0') == '0' + and 'stream cipher' + or '%d-bit block' % (8*int(d['cipher-blksz'])))), + ('Message authentication', lambda d: '%s (%s; %s)' % ( + d['mac'], + d.get('mac-keysz') is None + and 'one-time MAC' + or '%d-bit key' % (8*int(d['mac-keysz'])), + '%d-bit tag' % (8*int(d['mac-tagsz'])))), + ('Hash', lambda d: '%s (%d-bit output)' % + (d['hash'], 8*int(d['hash-sz'])))] + statslayout = \ [('Start time', '%(start-time)s'), - ('Last key-exchange', '%(last-keyexch-time)s'), + ('Private key', '%(current-key)s')] + \ + cryptolayout + \ + [('Last key-exchange', '%(last-keyexch-time)s'), ('Last packet', '%(last-packet-time)s'), ('Packets in/out', '%(packets-in)s (%(bytes-in)s) / %(packets-out)s (%(bytes-out)s)'), @@ -1236,7 +1295,7 @@ statslayout = \ '%(ip-packets-in)s (%(ip-bytes-in)s) / %(ip-packets-out)s (%(ip-bytes-out)s)'), ('Rejected packets', '%(rejected-packets)s')] -class PeerWindow (MyWindow): +class PeerWindow (TrivialWindow): """ Show information about a peer. @@ -1254,7 +1313,7 @@ class PeerWindow (MyWindow): def __init__(me, peer): """Construct a PeerWindow, showing information about PEER.""" - MyWindow.__init__(me) + TrivialWindow.__init__(me) me.set_title('TrIPE statistics: %s' % peer.name) me.peer = peer @@ -1301,6 +1360,7 @@ class PeerWindow (MyWindow): def change(me): """Update the display in response to a notification.""" me.e['Interface'].set_text(me.peer.ifname) + me.e['Address'].set_text(me.peer.addr) def _update(me): """ @@ -1313,8 +1373,9 @@ class PeerWindow (MyWindow): stat = conn.stats(me.peer.name) for s, trans in statsxlate: stat[s] = trans(stat[s]) + stat.update(me.peer.__dict__) for label, format in statslayout: - me.e[label].set_text(format % stat) + me.e[label].set_text(format_stat(format, stat)) GL.timeout_add(1000, lambda: me.cr.switch() and False) me.cr.parent.switch() me.cr = None @@ -1348,10 +1409,10 @@ class PeerWindow (MyWindow): ###-------------------------------------------------------------------------- ### Cryptographic status. -class CryptoInfo (MyWindow): +class CryptoInfo (TrivialWindow): """Simple display of cryptographic algorithms in use.""" def __init__(me): - MyWindow.__init__(me) + TrivialWindow.__init__(me) me.set_title('Cryptographic algorithms') T.aside(me.populate) def populate(me): @@ -1359,31 +1420,11 @@ class CryptoInfo (MyWindow): me.add(table) crypto = conn.algs() - table.info('Diffie-Hellman group', - '%s (%d-bit order, %d-bit elements)' % - (crypto['kx-group'], - int(crypto['kx-group-order-bits']), - int(crypto['kx-group-elt-bits'])), - len = 32) - table.info('Data encryption', - '%s (%d-bit key; %s)' % - (crypto['cipher'], - int(crypto['cipher-keysz']) * 8, - crypto['cipher-blksz'] == '0' - and 'stream cipher' - or '%d-bit block' % (int(crypto['cipher-blksz']) * 8)), - newlinep = True) - table.info('Message authentication', - '%s (%d-bit key; %d-bit tag)' % - (crypto['mac'], - int(crypto['mac-keysz']) * 8, - int(crypto['mac-tagsz']) * 8), - newlinep = True) - table.info('Hash function', - '%s (%d-bit output)' % - (crypto['hash'], - int(crypto['hash-sz']) * 8), - newlinep = True) + firstp = True + for label, format in cryptolayout: + table.info(label, format_stat(format, crypto), + len = 42, newlinep = not firstp) + firstp = False me.show_all() @@ -1571,6 +1612,7 @@ class MonitorWindow (MyWindow): '???', 'green', '???', 'green']) peer.win = WindowSlot(lambda: PeerWindow(peer)) me.hook(peer.pinghook, me._ping) + me.hook(peer.changehook, lambda: me._change(peer)) me.apchange() def delpeer(me, peer): @@ -1711,6 +1753,10 @@ class MonitorWindow (MyWindow): me.listmodel[p.i][textcol] = '%.1f ms' % ps.tlast me.listmodel[p.i][colourcol] = 'black' + def _change(me, p): + """Hook: notified when the peer changes state.""" + me.listmodel[p.i][1] = p.addr + def setstatus(me, status): """Update the message in the status bar.""" me.status.pop(0)