server/admin.c: Remove spurious `ping' in usage message.
[tripe] / mon / tripemon.in
index 1e62f03..11ee6dc 100644 (file)
@@ -40,7 +40,7 @@ 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
@@ -323,13 +323,19 @@ class Peer (MonitorObject):
 
   def _setaddr(me, addr):
     """Set the peer's address."""
-    if addr[0] == 'INET':
-      ipaddr, port = addr[1:]
+    if addr[0] in ['INET', 'INET6']:
+      af, ipaddr, port = addr
       try:
-        name = S.gethostbyaddr(ipaddr)[0]
-        me.addr = 'INET %s:%s [%s]' % (name, port, ipaddr)
-      except S.herror:
-        me.addr = 'INET %s:%s' % (ipaddr, port)
+        name, _ = S.getnameinfo((ipaddr, int(port)),
+                                S.NI_NUMERICSERV | S.NI_NAMEREQD)
+      except S.gaierror:
+        me.addr = '%s %s%s%s:%s' % (af,
+                                    af == 'INET6' and '[' or '',
+                                    ipaddr,
+                                    af == 'INET6' and ']' or '',
+                                    port)
+      else:
+        me.addr = '%s %s:%s [%s]' % (af, name, port, ipaddr)
     else:
       me.addr = ' '.join(addr)
 
@@ -773,7 +779,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):
@@ -1042,6 +1048,8 @@ class AddPeerDialog (MyDialog):
     * e_name, e_addr, e_port, c_keepalive, l_tunnel: widgets in the dialog
   """
 
+  AFS = ['ANY', 'INET', 'INET6']
+
   def __init__(me):
     """Initialize the dialogue."""
     MyDialog.__init__(me, 'Add peer',
@@ -1055,10 +1063,15 @@ class AddPeerDialog (MyDialog):
     table = GridPacker()
     me.vbox.pack_start(table, True, True, 0)
     me.e_name = table.labelled('Name',
-                               ValidatingEntry(r'^[^\s.:]+$', '', 16),
+                               ValidatingEntry(r'^[^\s:]+$', '', 16),
                                width = 3)
+    me.l_af = table.labelled('Family', combo_box_text(),
+                             newlinep = True, width = 3)
+    for af in me.AFS:
+      me.l_af.append_text(af)
+    me.l_af.set_active(0)
     me.e_addr = table.labelled('Address',
-                               ValidatingEntry(r'^[a-zA-Z0-9.-]+$', '', 24),
+                               ValidatingEntry(r'^[a-zA-Z0-9.-:]+$', '', 24),
                                newlinep = True)
     me.e_port = table.labelled('Port',
                                ValidatingEntry(numericvalidate(0, 65535),
@@ -1075,12 +1088,17 @@ class AddPeerDialog (MyDialog):
       tickybox.connect('toggled',
                        lambda t: target.set_sensitive (t.get_active()))
 
-    me.c_keepalive = G.CheckButton('Keepalives')
-    table.pack(me.c_keepalive, newlinep = True, xopt = G.FILL)
-    me.e_keepalive = ValidatingEntry(r'^\d+[hms]?$', '', 5)
-    me.e_keepalive.set_sensitive(False)
-    tickybox_sensitivity(me.c_keepalive, me.e_keepalive)
-    table.pack(me.e_keepalive, width = 3)
+    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)
@@ -1088,19 +1106,16 @@ class AddPeerDialog (MyDialog):
     me.c_mobile = G.CheckButton('Mobile')
     table.pack(me.c_mobile, newlinep = True, width = 4, xopt = G.FILL)
 
-    me.c_peerkey = G.CheckButton('Peer key tag')
-    table.pack(me.c_peerkey, newlinep = True, xopt = G.FILL)
-    me.e_peerkey = ValidatingEntry(r'^[^.:\s]+$', '', 16)
-    me.e_peerkey.set_sensitive(False)
-    tickybox_sensitivity(me.c_peerkey, me.e_peerkey)
-    table.pack(me.e_peerkey, width = 3)
+    me.c_ephem = G.CheckButton('Ephemeral')
+    table.pack(me.c_ephem, newlinep = True, width = 4, xopt = G.FILL)
 
-    me.c_privkey = G.CheckButton('Private key tag')
-    table.pack(me.c_privkey, newlinep = True, xopt = G.FILL)
-    me.e_privkey = ValidatingEntry(r'^[^.:\s]+$', '', 16)
-    me.e_privkey.set_sensitive(False)
-    tickybox_sensitivity(me.c_privkey, me.e_privkey)
-    table.pack(me.e_privkey, width = 3)
+    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.c_knock, me.e_knock = \
+      optional_entry('Knock string', r'^[^:\s]+$', 16)
 
     me.show_all()
 
@@ -1108,7 +1123,9 @@ class AddPeerDialog (MyDialog):
     """Handle an OK press: create the peer."""
     try:
       t = me.l_tunnel.get_active()
+      afix = me.l_af.get_active()
       me._addpeer(me.e_name.get_text(),
+                  me.AFS[afix],
                   me.e_addr.get_text(),
                   me.e_port.get_text(),
                   keepalive = (me.c_keepalive.get_active() and
@@ -1116,10 +1133,13 @@ class AddPeerDialog (MyDialog):
                   tunnel = t and me.tuns[t] or None,
                   cork = me.c_cork.get_active() or None,
                   mobile = me.c_mobile.get_active() or None,
+                  ephemeral = me.c_ephem.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))
+                          me.e_privkey.get_text() or None),
+                  knock = (me.c_knock.get_active() and
+                           me.e_knock.get_text() or None))
     except ValidationError:
       GDK.beep()
       return
@@ -1256,6 +1276,10 @@ 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.
@@ -1264,10 +1288,22 @@ cryptolayout = \
     '%(kx-group)s '
     '(%(kx-group-order-bits)s-bit order, '
     '%(kx-group-elt-bits)s-bit elements)'),
-   ('Cipher',
-    '%(cipher)s (%(cipher-keysz)s-bit key, %(cipher-blksz)s-bit block)'),
-   ('Mac', '%(mac)s (%(mac-keysz)s-bit key, %(mac-tagsz)s-bit tag)'),
-   ('Hash', '%(hash)s (%(hash-sz)s-bit output)')]
+   ('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'),
@@ -1348,6 +1384,7 @@ class PeerWindow (TrivialWindow):
   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):
     """
@@ -1362,7 +1399,7 @@ class PeerWindow (TrivialWindow):
         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
@@ -1407,31 +1444,11 @@ class CryptoInfo (TrivialWindow):
     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()
 
@@ -1619,6 +1636,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):
@@ -1759,6 +1777,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)