chiark / gitweb /
Explicit close-down notifications. 1.0.0pre12
authorMark Wooding <mdw@distorted.org.uk>
Sat, 5 Jan 2013 07:52:43 +0000 (07:52 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 5 Jan 2013 08:54:42 +0000 (08:54 +0000)
Suppose I have a mobile device, and I roam from one peer to another in
the same organization.  The old peer will continue to believe that I'm
connected through it until it notices, some time later, that pings
aren't getting through to me; it will therefore be sending packets to me
through its broken tunnel.  Suppose further that the organization is
using some dynamic routing protocol in order to propagate information
about how packets to me ought to be routed: then, this old peer will be
continuing to advertise its broken route to me, and all hosts closer to
the old peer than the new one will use the wrong route, until the
connection gets pinged out.

We can fix this by having the mobile peer send some explicit
notification.  It doesn't have to be completely reliable, fortunately.
This change touches a fair few pieces of the code, but in simple ways.

  * `connect' grows a new command to map a user name to a peer name.

  * `watch' grows the ability to issue a `disconnect' command.

  * The default `peers.in' file passes an explicit argument in its
    `connect' SSH rune, and adds a `disconnect' rune with a different
    action argument.

  * The contributed `knock' script knows about these new actions, and
    how to pass them about.  This is pretty much a rewrite, but it was a
    very simple program before.

contrib/knock.in
debian/changelog
peerdb/peers.in
peerdb/peers.in.5.in
svc/connect.8.in
svc/connect.in
svc/watch.8.in
svc/watch.in

index be55f2b95a0496b312842a6637c001fcf52cd162..28d8e532d2d80a1557bbfad7ec72a10fbf2b3e1c 100755 (executable)
@@ -25,23 +25,50 @@ set -e
 : ${tripectl=$bindir/tripectl}
 export TRIPEDIR TRIPESOCK
 
-case "$#,$1,$2" in
-
-  2,-c,*:*)
-    ## Proxy through to another server.
-    server=${2%:*} user=${2##*:}
-    exec ssh "$server" "$user"
+## Make sure we're being called properly, and figure out the peer identity.
+case "$#,$1" in
+  2,-c) ;;
+  *)
+    echo >&2 "usage: $0 -c '[SERVER:]PEER [hello|goodbye]'"
+    exit 1
     ;;
+esac
 
-  2,-c,*)
-    ## Connect to the local tripe server.
-    exec $tripectl SVCSUBMIT connect passive "$2"
-    ;;
+## SSH has smushed all of our arguments together, so let's split them apart
+## again.
+set -- $2
+
+## Examine the peer identifier and work out how to proceed.
+case "$#,$1" in
+  0,*) echo >&2 "$0: missing peer identifier"; exit 1 ;;
+  *:*) mode=proxy server=${1%:*} user=${1##*:} ;;
+  *) mode=local user=$1 ;;
+esac
+shift
 
+## If there's no action then check to see whether SSH has hidden one
+## somewhere.  Make sure the command looks sensible.
+case "$#" in 0) set -- $SSH_ORIGINAL_COMMAND ;; esac
+case "$#,$1" in
+  0, | 1,hello) act=hello ;;
+  1,goodbye) act=goodbye ;;
+  *) echo >&2 "$0: unknown action spec \`$*'"; exit 1 ;;
+esac
+
+## Now actually do something.
+case "$mode,$act" in
+  proxy,*)
+    exec ssh "$server" "$user" "$act"
+    ;;
+  local,hello)
+    exec $tripectl SVCSUBMIT connect passive "$user"
+    ;;
+  local,goodbye)
+    peer=$($tripectl SVCSUBMIT connect userpeer "$user")
+    exec $tripectl KILL "$peer"
+    ;;
   *)
-    ## Anything else is an error.
-    echo >&2 "usage: $0 -c [SERVER:]PEER"
+    echo >&2 "$0: unknown mode/action $mode/$act"
     exit 1
     ;;
-
 esac
index ccbcf58fdc4589ea80569c58fb2c9a93c39290c5..ce929b62e200ffbc2a461f9d72a12413debc8cc1 100644 (file)
@@ -1,3 +1,10 @@
+tripe (1.0.0pre12) experimental; urgency=low
+
+  * tripe-peer-services: Add machinery for notifying a peer that we no
+    longer require its services.
+ -- Mark Wooding <mdw@distorted.org.uk>  Sat, 05 Jan 2013 07:50:33 +0000
+
 tripe (1.0.0pre11.1) experimental; urgency=low
 
   * tripe: Fix segfault from PEERINFO command.
index 5e381bdd012e80f2eb5a2a124d1059621fed28c8..53eef5b23d69098e9bf4c3ae5303648de151112f 100644 (file)
@@ -85,7 +85,10 @@ ssh-user = tripe
 
 ;; connect: shell command to use to wake up the remote peer and establish the
 ;; connection.
-connect = ssh -q $(ssh-user)@$[$(host)]
+connect = ssh -q $(ssh-user)@$[$(host)] hello
+
+;; disconnect: shell command to use to shut the remote peer down.
+disconnect = ssh -q $(ssh-user)@$[$(host)] goodbye
 
 ;; keepalive: how often to send NOP packets to keep the connection alive, at
 ;; least in the minds of intermediate stateful firewalls and NAT routers.
index 48f69b3b359f098c7d862ef34f419d1bc04029f8..e31d0e37973a28b884b8da4245ae7a2a385ad292 100644 (file)
@@ -138,6 +138,10 @@ Shell command for initiating connection to this peer.  Used by
 Don't initiate immediate key exchange.  Used by
 .BR connect (8).
 .TP
+.B disconnect
+Shell command for closing down connection to this peer.  Used by
+.BR watch (8).
+.TP
 .B every
 Interval for checking that the peer is still alive and well.  Used by
 .BR watch (8).
index d529918d887958d90df9e9bda9e781ff476a16fe..2cc3c5cea6b51255440f3cd45baec4ef71651d14 100644 (file)
@@ -302,6 +302,13 @@ for days, hours, minutes or seconds respectively; if no suffix is given,
 seconds are assumed.
 .\"-opts
 .RE
+.SP
+.BI "userpeer " user
+Output a single
+.B INFO
+line identifying the peer corresponding to the
+.I user
+name.
 .
 .\"--------------------------------------------------------------------------
 .SH "ERROR MESSAGES"
@@ -341,7 +348,9 @@ has no record in the database.
 .SP
 .BI "unknown-user " user
 (For
-.BR passive .)
+.B passive
+and
+.BR userinfo .)
 There is no record of
 .I user
 in the database.
index 5f8940e34ddc5b527e50275fe2bd85b243203940..0031d36fcee85b72aa226a79f747742c11af2352 100644 (file)
@@ -130,6 +130,16 @@ def cmd_info(name):
   for i in items:
     T.svcinfo('%s=%s' % (i, peer.get(i)))
 
+def cmd_userpeer(user):
+  """
+  userpeer USER: Report the peer name for the named user.
+  """
+  try:
+    peer = CDB.init(opts.cdb)['U' + user]
+  except KeyError:
+    raise T.TripeJobError('unknown-user', user)
+  T.svcinfo(peer)
+
 ## Dictionary mapping challenges to waiting passive-connection coroutines.
 chalmap = {}
 
@@ -241,7 +251,8 @@ service_info = [('connect', VERSION, {
   'passive': (1, None, '[OPTIONS] USER', cmd_passive),
   'active': (1, 1, 'PEER', cmd_active),
   'info': (1, 1, 'PEER', cmd_info),
-  'list': (0, 0, '', cmd_list)
+  'list': (0, 0, '', cmd_list),
+  'userpeer': (1, 1, 'USER', cmd_userpeer)
 })]
 
 if __name__ == '__main__':
index 3e40251015a2d45ee2ec6bf6d4de74b0b8639c43..79ddbef9387a26ccff53146f3a52b6080c5b4d7b 100644 (file)
@@ -248,6 +248,17 @@ command will issue a command such as
 where
 .I our-name
 is the remote peer's name for this host.
+.PP
+Similarly, if the database record has a
+.B disconnect
+entry, then
+.B watch
+will use this to give the peer explicit notification that its services
+are no longer needed.  The value f the
+.B disconnect
+key is invoked as a Bourne shell command.  This ought to result in a
+.B KILL
+command being issued to the peer's server.
 .SS "Operation"
 On startup,
 .B watch
@@ -451,6 +462,10 @@ under various circumstances.  The process identifiers are as follows.
 A child spawned in order to establish a dynamic connection with
 .IR peer .
 .SP
+.BI "disconnect " peer
+A child spawned in order to shut down a dynamic connection with
+.IR peer .
+.SP
 .BI "ifdown " peer
 A child spawned to deconfigure the network interface for
 .IR peer .
index 5917c79eb9c5405c610979472529519c1af3abf7..4aaf20be713f1198c62ce10366b1bf8542d3870d 100644 (file)
@@ -329,6 +329,22 @@ def connect(peer, conn = None):
       q.get()
   potwatch('connect', peer, q)
 
+def disconnect(peer, disconn = None):
+  """
+  Start the job of disconnecting from a passive PEER.
+
+  The DISCONN string is a shell command which will disconnect from the peer.
+  """
+  if disconn is None:
+    try:
+      conn = peerinfo(peer)['disconnect']
+    except KeyError:
+      return
+  q = T.Queue()
+  cmd = Command(['disconnect', peer], q, 'disconnect',
+                ['/bin/sh', '-c', disconn], None)
+  potwatch('disconnect', peer, q)
+
 _pingseq = 0
 class PingPeer (object):
   """
@@ -641,6 +657,9 @@ def delpeer(peer):
     pinger.kill(peer)
   except KeyError:
     pass
+  if 'disconnect' in info:
+    T.Coroutine(disconnect, name = 'disconnect %s' % peer) \
+                            .switch(peer, info['disconnect'])
   if 'ifdown' in info:
     T.Coroutine(ifupdown, name = 'ifdown %s' % peer) \
                           .switch('ifdown', peer, info)