chiark / gitweb /
Add notion of `ephemeral' associations and a goodbye protocol.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 5 Sep 2017 21:26:51 +0000 (22:26 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 25 Jan 2019 12:07:16 +0000 (12:07 +0000)
When TrIPE kills an ephemeral peer, it sends a `bye' message to the
peer.  When TrIPE receives `bye' from an ephemeral peer, it kills the
peer (without sending `bye' back).

Augment the `connect' service to set appropriate flags when adding
peers, and the Wireshark dissector to understand the new message.

13 files changed:
common/protocol.h
mon/tripemon.in
peerdb/peers.in
peerdb/peers.in.5.in
py/tripe.py.in
server/admin.c
server/peer.c
server/tests.at
server/tripe-admin.5.in
server/tripe.h
svc/connect.8.in
svc/connect.in
wireshark/tripe.lua

index 2416afcff2cd84135dfa4f2f48d34019f0851ebc..e40cf177c142c5fcf22430f0396a0ed3ab1c3a89 100644 (file)
@@ -79,6 +79,7 @@
 #define MISC_EPING 3u                  /* Encrypted ping */
 #define MISC_EPONG 4u                  /* Encrypted ping response */
 #define MISC_GREET 5u                  /* A greeting from a NATed peer */
 #define MISC_EPING 3u                  /* Encrypted ping */
 #define MISC_EPONG 4u                  /* Encrypted ping response */
 #define MISC_GREET 5u                  /* A greeting from a NATed peer */
+#define MISC_BYE 6u                    /* Departure notification */
 
 /* --- Symmetric encryption and keysets --- *
  *
 
 /* --- Symmetric encryption and keysets --- *
  *
index 0d15474ca335d82b8e3001eb586ab09d79dfc606..8666575a1fba5a6c5b182688341cd0638458b1b5 100644 (file)
@@ -1093,6 +1093,9 @@ class AddPeerDialog (MyDialog):
     me.c_mobile = G.CheckButton('Mobile')
     table.pack(me.c_mobile, 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_ephem = G.CheckButton('Ephemeral')
+    table.pack(me.c_ephem, 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 = \
     me.c_peerkey, me.e_peerkey = \
       optional_entry('Peer key tag', r'^[^.:\s]+$', 16)
     me.c_privkey, me.e_privkey = \
@@ -1115,6 +1118,7 @@ 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,
                   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
                   key = (me.c_peerkey.get_active() and
                          me.e_peerkey.get_text() or None),
                   priv = (me.c_privkey.get_active() and
index 3fb23803c8fc0e79b24d39a8d3e9193f04741bdf..75c039d9f5da51c720b0cd7f7af5cc7d27b1552f 100644 (file)
@@ -57,6 +57,10 @@ host = override-me
 ;; the remote peer.
 peer = INET $[$(host)] $(port)
 
 ;; the remote peer.
 peer = INET $[$(host)] $(port)
 
+;; ephemeral: whether to send the peer a disconnection notification, or
+;; react to one from the peer.
+ephemeral = nil
+
 ;;;--------------------------------------------------------------------------
 ;;; Temporary association defaults.
 ;;;
 ;;;--------------------------------------------------------------------------
 ;;; Temporary association defaults.
 ;;;
@@ -81,21 +85,28 @@ retries = 5
 ;;; The parameters here affect peers to whom dynamic connections are made.
 ;;; The user and connect parameters probably need customizing.
 
 ;;; The parameters here affect peers to whom dynamic connections are made.
 ;;; The user and connect parameters probably need customizing.
 
-[@KNOCK]
+[@EPHEMERAL]
 @inherit = @ACTIVE, @WATCH
 
 @inherit = @ACTIVE, @WATCH
 
-;; keepalive: how often to send NOP packets to keep the connection alive, at
-;; least in the minds of intermediate stateful firewalls and NAT routers.
-keepalive = 2m
+;; ephemeral: whether to send the peer a disconnection notification, or
+;; react to one from the peer.
+ephemeral = t
 
 ;; every: interval for checking that this connection is alive.
 every = 30s
 
 
 ;; every: interval for checking that this connection is alive.
 every = 30s
 
+[@KNOCK]
+@inherit = @EPHEMERAL
+
+;; keepalive: how often to send NOP packets to keep the connection alive, at
+;; least in the minds of intermediate stateful firewalls and NAT routers.
+keepalive = 2m
+
 ;; knock: peer-name string to send to the peer.
 knock = $(myhost)
 
 [@DYNAMIC]
 ;; knock: peer-name string to send to the peer.
 knock = $(myhost)
 
 [@DYNAMIC]
-@inherit = @ACTIVE, @WATCH
+@inherit = @EPHEMERAL
 
 ;; cork: whether to wait for a key-exchange packet from the peer before
 ;; sending one of our own.
 
 ;; cork: whether to wait for a key-exchange packet from the peer before
 ;; sending one of our own.
@@ -115,9 +126,6 @@ disconnect = ssh -q $(ssh-user)@$[$(host)] goodbye
 ;; least in the minds of intermediate stateful firewalls and NAT routers.
 keepalive = 2m
 
 ;; least in the minds of intermediate stateful firewalls and NAT routers.
 keepalive = 2m
 
-;; every: interval for checking that this connection is alive.
-every = 30s
-
 ;;;--------------------------------------------------------------------------
 ;;; Passive-peers defaults.
 ;;;
 ;;;--------------------------------------------------------------------------
 ;;; Passive-peers defaults.
 ;;;
index 89eb77769cb325a223b67e9c6227dbef3f228a75..ac27b49cabd5c819363e958d35ff2a037b7f28ce 100644 (file)
@@ -175,6 +175,12 @@ Don't initiate immediate key exchange.  Used by
 Shell command for closing down connection to this peer.  Used by
 .BR connect (8).
 .TP
 Shell command for closing down connection to this peer.  Used by
 .BR connect (8).
 .TP
+.B ephemeral
+Mark the peer as ephemeral: see
+.BR tripe-admin (5)
+for what this means.  Used by
+.BR connect (8).
+.TP
 .B every
 Interval for checking that the peer is still alive and well.  Used by
 .BR connect (8).
 .B every
 Interval for checking that the peer is still alive and well.  Used by
 .BR connect (8).
index 63ae0afc4c72ed0f4be4f828c4fe81bcaa4e4de4..0126dc586991c1357f71e0679b85c3c34cba0b72 100644 (file)
@@ -838,7 +838,8 @@ class TripeCommandDispatcher (TripeConnection):
                               *['ADD'] +
                               _kwopts(kw, ['tunnel', 'keepalive',
                                            'key', 'priv', 'cork',
                               *['ADD'] +
                               _kwopts(kw, ['tunnel', 'keepalive',
                                            'key', 'priv', 'cork',
-                                           'mobile', 'knock']) +
+                                           'mobile', 'knock',
+                                           'ephemeral']) +
                               [peer] +
                               list(addr)))
   def addr(me, peer):
                               [peer] +
                               list(addr)))
   def addr(me, peer):
index 886c672c9c30071b46cce2bb48be8a3f5573ce3b..54883afa448cf15926c78c5e5d0c8748ea0276d1 100644 (file)
@@ -551,7 +551,7 @@ void a_quit(void)
 {
   close(sock.fd);
   unlink(sockname);
 {
   close(sock.fd);
   unlink(sockname);
-  FOREACH_PEER(p, { p_destroy(p); });
+  FOREACH_PEER(p, { p_destroy(p, 1); });
   ps_quit();
   exit(0);
 }
   ps_quit();
   exit(0);
 }
@@ -1285,11 +1285,12 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     })
     OPTTIME("-keepalive", t, { add->peer.t_ka = t; })
     OPT("-cork", { add->peer.f |= KXF_CORK; })
     })
     OPTTIME("-keepalive", t, { add->peer.t_ka = t; })
     OPT("-cork", { add->peer.f |= KXF_CORK; })
+    OPT("-ephemeral", { add->peer.f |= PSF_EPHEM; })
     OPTARG("-key", arg, {
       if (add->peer.tag) xfree(add->peer.tag);
       add->peer.tag = xstrdup(arg);
     })
     OPTARG("-key", arg, {
       if (add->peer.tag) xfree(add->peer.tag);
       add->peer.tag = xstrdup(arg);
     })
-    OPT("-mobile", { add->peer.f |= PSF_MOBILE; })
+    OPT("-mobile", { add->peer.f |= PSF_MOBILE | PSF_EPHEM; })
     OPTARG("-priv", arg, {
       if (add->peer.privtag) xfree(add->peer.privtag);
       add->peer.privtag = xstrdup(arg);
     OPTARG("-priv", arg, {
       if (add->peer.privtag) xfree(add->peer.privtag);
       add->peer.privtag = xstrdup(arg);
@@ -1297,6 +1298,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     OPTARG("-knock", arg, {
       if (add->peer.knock) xfree(add->peer.knock);
       add->peer.knock = xstrdup(arg);
     OPTARG("-knock", arg, {
       if (add->peer.knock) xfree(add->peer.knock);
       add->peer.knock = xstrdup(arg);
+      add->peer.f |= PSF_EPHEM;
     })
   });
 
     })
   });
 
@@ -1860,6 +1862,7 @@ static void acmd_peerinfo(admin *a, unsigned ac, char *av[])
     a_info(a, "keepalive=%lu", ps->t_ka, A_END);
     a_info(a, "corked=%s", BOOL(p->kx.f&KXF_CORK),
           "mobile=%s", BOOL(ps->f&PSF_MOBILE),
     a_info(a, "keepalive=%lu", ps->t_ka, A_END);
     a_info(a, "corked=%s", BOOL(p->kx.f&KXF_CORK),
           "mobile=%s", BOOL(ps->f&PSF_MOBILE),
+          "ephemeral=%s", BOOL(ps->f&PSF_EPHEM),
           A_END);
     a_ok(a);
   }
           A_END);
     a_ok(a);
   }
@@ -1915,7 +1918,7 @@ static void acmd_kill(admin *a, unsigned ac, char *av[])
   peer *p;
 
   if ((p = a_findpeer(a, av[0])) != 0) {
   peer *p;
 
   if ((p = a_findpeer(a, av[0])) != 0) {
-    p_destroy(p);
+    p_destroy(p, 1);
     a_ok(a);
   }
 }
     a_ok(a);
   }
 }
index f600f99e8531794845427c65328a2b49fd0e99bd..606b2038d0c76f93a64af77d539566786de0fe7f 100644 (file)
@@ -454,6 +454,16 @@ static void p_read(int fd, unsigned mode, void *v)
            p_ponged(p, MISC_EPONG, &bb);
          }
          break;
            p_ponged(p, MISC_EPONG, &bb);
          }
          break;
+       case MISC_BYE:
+         buf_init(&bb, buf_t, sizeof(buf_t));
+         if (p_decrypt(&p, &a, n, ch, &b, &bb)) return;
+         if (!(p->spec.f&PSF_EPHEM)) return;
+         if (BOK(&bb)) {
+           buf_flip(&bb);
+           if (BSZ(&bb)) return;
+           p_destroy(p, 0);
+         }
+         break;
       }
       break;
     default:
       }
       break;
     default:
@@ -1044,17 +1054,28 @@ peer *p_find(const char *name)
 /* --- @p_destroy@ --- *
  *
  * Arguments:  @peer *p@ = pointer to a peer
 /* --- @p_destroy@ --- *
  *
  * Arguments:  @peer *p@ = pointer to a peer
+ *             @int bye@ = say goodbye to the peer?
  *
  * Returns:    ---
  *
  * Use:                Destroys a peer.
  */
 
  *
  * Returns:    ---
  *
  * Use:                Destroys a peer.
  */
 
-void p_destroy(peer *p)
+void p_destroy(peer *p, int bye)
 {
   ping *pg, *ppg;
 {
   ping *pg, *ppg;
+  buf *b, bb;
 
   T( trace(T_PEER, "peer: destroying peer `%s'", p->spec.name); )
 
   T( trace(T_PEER, "peer: destroying peer `%s'", p->spec.name); )
+
+  if (bye && (p->spec.f&PSF_EPHEM)) {
+    b = p_txstart(p, MSG_MISC | MISC_BYE);
+    buf_init(&bb, buf_t, sizeof(buf_t));
+    assert(BOK(&bb)); buf_flip(&bb);
+    p_encrypt(p, MSG_MISC | MISC_BYE, &bb, b);
+    p_txend(p);
+  }
+
   a_notify("KILL", "%s", p->spec.name, A_END);
   ksl_free(&p->ks);
   kx_free(&p->kx);
   a_notify("KILL", "%s", p->spec.name, A_END);
   ksl_free(&p->ks);
   kx_free(&p->kx);
index 8bceb147703d697dfe8ce0f269d6234955e0a1e1..08bfb135cd3219fb5bf2faebd2b9ce04c735aadd 100644 (file)
@@ -752,7 +752,7 @@ WITH_TRIPE(, [
 AT_CLEANUP
 
 ###--------------------------------------------------------------------------
 AT_CLEANUP
 
 ###--------------------------------------------------------------------------
-### Knock.
+### Knock and bye.
 
 AT_SETUP([server knock])
 AT_KEYWORDS([knock])
 
 AT_SETUP([server knock])
 AT_KEYWORDS([knock])
@@ -786,7 +786,7 @@ WITH_2TRIPES([alice], [bob], [-nslip], [-talice], [-tbob], [
     AT_CHECK([cat knock-addr],, [INET 127.0.0.1 5311[]nl])
 
     AWAIT_KXDONE([alice], [alice], [bob], [bob], [
     AT_CHECK([cat knock-addr],, [INET 127.0.0.1 5311[]nl])
 
     AWAIT_KXDONE([alice], [alice], [bob], [bob], [
-      AT_CHECK([TRIPECTL -dalice ADD bob INET 127.0.0.1 5311])
+      AT_CHECK([TRIPECTL -dalice ADD -ephemeral bob INET 127.0.0.1 5311])
     ])
 
     COMMS_EPING([alice], [alice], [bob], [bob])
     ])
 
     COMMS_EPING([alice], [alice], [bob], [bob])
@@ -798,6 +798,7 @@ WITH_2TRIPES([alice], [bob], [-nslip], [-talice], [-tbob], [
       AT_CHECK([TRIPECTL -dalice FORCEKX bob])
       AT_CHECK([TRIPECTL -dbob FORCEKX alice])
     ])
       AT_CHECK([TRIPECTL -dalice FORCEKX bob])
       AT_CHECK([TRIPECTL -dbob FORCEKX alice])
     ])
+
     AT_CHECK([TRIPECTL -dbob KILL alice])
     AT_CHECK([TRIPECTL -dalice LIST],, [])
   ])
     AT_CHECK([TRIPECTL -dbob KILL alice])
     AT_CHECK([TRIPECTL -dalice LIST],, [])
   ])
index a340f57f75997064f3ccdcc02c303e9efc24525a..c81dc111b84e1d4677e8633da27e7f26596a89aa 100644 (file)
@@ -332,6 +332,21 @@ Run the command in the background, using the given
 Don't send an immediate challenge to the peer; instead, wait until it
 sends us something before responding.
 .TP
 Don't send an immediate challenge to the peer; instead, wait until it
 sends us something before responding.
 .TP
+.B "\-ephemeral"
+The association with the peer is not intended to persist indefinitely.
+If a peer marked as ephemeral is killed, or the
+.BR tripe (8)
+daemon is shut down, send a
+.B bye
+packet to the peer so that it forgets about us; if a peer marked as
+ephemeral sends us a
+.B bye
+packet then it is killed (but in this case no further
+.B bye
+packet is sent).  Peers not marked as ephemeral exhibit neither of these
+behaviours; each peer must have the other marked as ephemeral for the
+association to be fully torn down if either end kills the other.
+.TP
 .BI "\-keepalive " time
 Send a no-op packet if we've not sent a packet to the peer in the last
 .I time
 .BI "\-keepalive " time
 Send a no-op packet if we've not sent a packet to the peer in the last
 .I time
@@ -370,7 +385,8 @@ emits a
 .B KNOCK
 notification stating the peer's (claimed) name and address.  The server
 will already have verified that the sender is using the peer's private
 .B KNOCK
 notification stating the peer's (claimed) name and address.  The server
 will already have verified that the sender is using the peer's private
-key by this point.
+key by this point.  This option implies
+.BR \-ephemeral .
 .TP
 .B "\-mobile"
 The peer is a mobile device, and is likely to change address rapidly.
 .TP
 .B "\-mobile"
 The peer is a mobile device, and is likely to change address rapidly.
@@ -380,7 +396,8 @@ peers, however, it will attempt to decrypt the packet using their keys,
 and if one succeeds, the server will update its idea of the peer's
 address and emit an
 .B NEWADDR
 and if one succeeds, the server will update its idea of the peer's
 address and emit an
 .B NEWADDR
-notification.
+notification.  This option implies
+.BR \-ephemeral .
 .TP
 .BI "\-priv " tag
 Use the private key
 .TP
 .BI "\-priv " tag
 Use the private key
@@ -639,6 +656,14 @@ or
 .B nil
 depending on whether or not (respectively) the peer is expected to
 change its address unpredictably.
 .B nil
 depending on whether or not (respectively) the peer is expected to
 change its address unpredictably.
+.TP
+.B ephemeral
+Either
+.B t
+or
+.B nil
+depending on whether the association with the peer is expected to be
+temporary or persistent (respectively).
 .RE
 .SP
 .BI "PING \fR[" options "\fR] " peer
 .RE
 .SP
 .BI "PING \fR[" options "\fR] " peer
index 2024627a10abde931bc1dabc15137fb89875ae35..a2907be1a6bff9a030d9dd4879c8eed1e96e14e6 100644 (file)
@@ -617,6 +617,7 @@ typedef struct peerspec {
   unsigned f;                          /* Flags for the peer */
 #define PSF_KXMASK 255u                        /*   Key-exchange flags to set */
 #define PSF_MOBILE 256u                        /*   Address may change rapidly */
   unsigned f;                          /* Flags for the peer */
 #define PSF_KXMASK 255u                        /*   Key-exchange flags to set */
 #define PSF_MOBILE 256u                        /*   Address may change rapidly */
+#define PSF_EPHEM 512u                 /*   Association is ephemeral */
 } peerspec;
 
 typedef struct peer_byname {
 } peerspec;
 
 typedef struct peer_byname {
@@ -1693,13 +1694,14 @@ extern peer *p_find(const char */*name*/);
 /* --- @p_destroy@ --- *
  *
  * Arguments:  @peer *p@ = pointer to a peer
 /* --- @p_destroy@ --- *
  *
  * Arguments:  @peer *p@ = pointer to a peer
+ *             @int bye@ = say goodbye to the peer?
  *
  * Returns:    ---
  *
  * Use:                Destroys a peer.
  */
 
  *
  * Returns:    ---
  *
  * Use:                Destroys a peer.
  */
 
-extern void p_destroy(peer */*p*/);
+extern void p_destroy(peer */*p*/, int /*bye*/);
 
 /* --- @FOREACH_PEER@ --- *
  *
 
 /* --- @FOREACH_PEER@ --- *
  *
index 5a11164763eda16df987c994775121f24e0ea2d8..1e4e2d25e7d3315a9cdc8512dadcf1b8b82a7f5f 100644 (file)
@@ -467,6 +467,7 @@ The service will submit the command
 .RB [ \-priv
 .IR tag ]
 .RB [ \-mobile ]
 .RB [ \-priv
 .IR tag ]
 .RB [ \-mobile ]
+.RB [ \-ephemeral ]
 .RB [ \-tunnel
 .IR driver ]
 .I address
 .RB [ \-tunnel
 .IR driver ]
 .I address
@@ -533,6 +534,19 @@ to the
 .B tunnel
 key.
 .hP \*o
 .B tunnel
 key.
 .hP \*o
+The option
+.B \-ephemeral
+is provided if the peer's database record assigns the
+.B ephemeral
+key one of the values
+.BR t ,
+.BR true ,
+.BR y ,
+.BR yes,
+or
+.BR on ;
+or if it is absent.
+.hP \*o
 The
 .I address
 is the value assigned to the
 The
 .I address
 is the value assigned to the
index fe8d73b98e592862cabe2f8ee31b4722d871a126..99dbd8af1ca8340e943999b7bdafa9f5ac5a3685 100644 (file)
@@ -717,11 +717,12 @@ def disownpeer(peer):
     T.Coroutine(run_ifupdown, name = 'ifdown %s' % peer.name) \
         .switch('ifdown', peer)
 
     T.Coroutine(run_ifupdown, name = 'ifdown %s' % peer.name) \
         .switch('ifdown', peer)
 
-def addpeer(peer, addr):
+def addpeer(peer, addr, ephemp):
   """
   Process a connect request from a new peer PEER on address ADDR.
 
   """
   Process a connect request from a new peer PEER on address ADDR.
 
-  Any existing peer with this name is disconnected from the server.
+  Any existing peer with this name is disconnected from the server.  EPHEMP
+  is the default ephemeral-ness state for the new peer.
   """
   if peer.name in S.list():
     S.kill(peer.name)
   """
   if peer.name in S.list():
     S.kill(peer.name)
@@ -734,6 +735,8 @@ def addpeer(peer, addr):
           mobile = peer.get('mobile', filter = boolean, default = False),
           knock = peer.get('knock', default = None),
           cork = peer.get('cork', filter = boolean, default = False),
           mobile = peer.get('mobile', filter = boolean, default = False),
           knock = peer.get('knock', default = None),
           cork = peer.get('cork', filter = boolean, default = False),
+          ephemeral = peer.get('ephemeral', filter = boolean,
+                               default = ephemp),
           *addr)
   except T.TripeError, exc:
     raise T.TripeJobError(*exc.args)
           *addr)
   except T.TripeError, exc:
     raise T.TripeJobError(*exc.args)
@@ -778,7 +781,7 @@ def notify(_, code, *rest):
       S.warn(['connect', 'knock-tag-mismatch',
               'peer', pname, 'public-key-tag', ktag])
       return
       S.warn(['connect', 'knock-tag-mismatch',
               'peer', pname, 'public-key-tag', ktag])
       return
-    T.spawn(addpeer, p, rest[1:])
+    T.spawn(addpeer, p, rest[1:], True)
 
 ###--------------------------------------------------------------------------
 ### Command implementation.
 
 ###--------------------------------------------------------------------------
 ### Command implementation.
@@ -813,7 +816,7 @@ def cmd_active(name):
   addr = peer.get('peer')
   if addr == 'PASSIVE':
     raise T.TripeJobError('passive-peer', name)
   addr = peer.get('peer')
   if addr == 'PASSIVE':
     raise T.TripeJobError('passive-peer', name)
-  addpeer(peer, M.split(addr, quotep = True)[0])
+  addpeer(peer, M.split(addr, quotep = True)[0], True)
 
 def cmd_listactive():
   """
 
 def cmd_listactive():
   """
@@ -875,7 +878,7 @@ def cmd_passive(*args):
     addr = cr.parent.switch()
     if addr is None:
       raise T.TripeJobError('connect-timeout')
     addr = cr.parent.switch()
     if addr is None:
       raise T.TripeJobError('connect-timeout')
-    addpeer(peer, addr)
+    addpeer(peer, addr, True)
   finally:
     del chalmap[chal]
 
   finally:
     del chalmap[chal]
 
@@ -911,7 +914,7 @@ def setup():
     for name in M.split(autos)[0]:
       try:
         peer = Peer(name, cdb)
     for name in M.split(autos)[0]:
       try:
         peer = Peer(name, cdb)
-        addpeer(peer, M.split(peer.get('peer'), quotep = True)[0])
+        addpeer(peer, M.split(peer.get('peer'), quotep = True)[0], False)
       except T.TripeJobError, err:
         S.warn('connect', 'auto-add-failed', name, *err.args)
 
       except T.TripeJobError, err:
         S.warn('connect', 'auto-add-failed', name, *err.args)
 
index aab8e7983832b8dfc56dc2397228d0072f3e9e48..5c6d7ba94ee54ce02a073b7fca49a68f41541359 100644 (file)
@@ -408,6 +408,8 @@ local PKTINFO = {
              dissect = { dissect_misc_ciphertext } },
       [5] = { label = "MISC_GREET", info = "greeting",
              dissect = { dissect_misc_payload } },
              dissect = { dissect_misc_ciphertext } },
       [5] = { label = "MISC_GREET", info = "greeting",
              dissect = { dissect_misc_payload } },
+      [6] = { label = "MISC_BYE", info = "disconnect notification",
+             dissect = { dissect_misc_ciphertext } },
     }
   }
 }
     }
   }
 }