Greetings and challenges.
authormdw <mdw>
Fri, 7 Oct 2005 14:41:54 +0000 (14:41 +0000)
committermdw <mdw>
Fri, 7 Oct 2005 14:41:54 +0000 (14:41 +0000)
12 files changed:
Makefile.am
admin.c
chal.c [new file with mode: 0644]
debian/control
doc/tripe-admin.5
ethereal/packet-tripe.c
keyset.c
peer.c
servutil.c
tripe-protocol.h
tripe.h
tripemon.in

index 8fbec70..144671d 100644 (file)
@@ -44,7 +44,7 @@ EXTRA_SCRIPTS = ${PYTHONSCRIPTS} ${PYGTKSCRIPTS}
 tripe_SOURCES = \
        tripe.c tripe.h tripe-protocol.h \
        admin.c peer.c \
 tripe_SOURCES = \
        tripe.c tripe.h tripe-protocol.h \
        admin.c peer.c \
-       keymgmt.c keyexch.c keyset.c \
+       keymgmt.c keyexch.c keyset.c chal.c \
        servutil.c util.c util.h \
        tun-unet.c tun-bsd.c tun-linux.c tun-slip.c
 tripe_LDADD = $(CATACOMB_LIBS)
        servutil.c util.c util.h \
        tun-unet.c tun-bsd.c tun-linux.c tun-slip.c
 tripe_LDADD = $(CATACOMB_LIBS)
diff --git a/admin.c b/admin.c
index 987de7a..da7ccad 100644 (file)
--- a/admin.c
+++ b/admin.c
@@ -38,11 +38,12 @@ const trace_opt tr_opts[] = {
   { 't',       T_TUNNEL,       "tunnel events" },
   { 'r',       T_PEER,         "peer events" },
   { 'a',       T_ADMIN,        "admin interface" },
   { 't',       T_TUNNEL,       "tunnel events" },
   { 'r',       T_PEER,         "peer events" },
   { 'a',       T_ADMIN,        "admin interface" },
-  { 'p',       T_PACKET,       "packet contents" },
-  { 'c',       T_CRYPTO,       "crypto details" },
   { 's',       T_KEYSET,       "symmetric keyset management" },
   { 'x',       T_KEYEXCH,      "key exchange" },
   { 'm',       T_KEYMGMT,      "key management" },
   { 's',       T_KEYSET,       "symmetric keyset management" },
   { 'x',       T_KEYEXCH,      "key exchange" },
   { 'm',       T_KEYMGMT,      "key management" },
+  { 'l',       T_CHAL,         "challenge management" },
+  { 'p',       T_PACKET,       "packet contents" },
+  { 'c',       T_CRYPTO,       "crypto details" },
   { 'A',       T_ALL,          "all of the above" },
   { 0,         0,              0 }
 };
   { 'A',       T_ALL,          "all of the above" },
   { 0,         0,              0 }
 };
@@ -512,6 +513,25 @@ static long a_parsetime(const char *p)
   return (t);    
 }
 
   return (t);    
 }
 
+/* --- @a_findpeer@ --- *
+ *
+ * Arguments:  @admin *a@ = admin connection
+ *             @const char *pn@ = peer name
+ *
+ * Returns:    The peer, or null if not there.
+ *
+ * Use:                Finds a peer, reporting an error if it failed.
+ */
+
+static peer *a_findpeer(admin *a, const char *pn)
+{
+  peer *p;
+
+  if ((p = p_find(pn)) == 0)
+    a_fail(a, "unknown-peer %s", pn);
+  return (p);
+}
+
 /*----- Backgrounded operations -------------------------------------------*/
 
 #define BGTAG(bg)                                                      \
 /*----- Backgrounded operations -------------------------------------------*/
 
 #define BGTAG(bg)                                                      \
@@ -604,108 +624,192 @@ static void a_bgadd(admin *a, admin_bgop *bg, const char *tag,
   if (tag) a_write(a, "DETACH", tag, 0);
 }
 
   if (tag) a_write(a, "DETACH", tag, 0);
 }
 
-/*----- Adding peers ------------------------------------------------------*/
+/*----- Name resolution operations ----------------------------------------*/
 
 
-/* --- @a_addfree@ --- *
+/* --- @a_resolved@ --- *
  *
  *
- * Arguments:  @admin_addop *add@ = operation block
+ * Arguments:  @struct hostent *h@ = pointer to resolved hostname
+ *             @void *v@ = pointer to resolver operation
  *
  * Returns:    ---
  *
  *
  * Returns:    ---
  *
- * Use:                Frees an add operation.
+ * Use:                Handles a completed name resolution.
  */
 
  */
 
-static void a_addfree(admin_addop *add)
+static void a_resolved(struct hostent *h, void *v)
 {
 {
-  T( trace(T_ADMIN, "admin: free add op %s", BGTAG(add)); )
-  if (add->peer.name) xfree(add->peer.name);
-  if (add->paddr) xfree(add->paddr);
-}
+  admin_resop *r = v;
+
+  T( trace(T_ADMIN, "admin: resop %s resolved", BGTAG(r)); )
+  TIMER;
+  if (!h) {
+    a_bgfail(&r->bg, "resolve-error %s", r->addr);
+    r->func(r, ARES_FAIL);
+  } else {
+    memcpy(&r->sa.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
+    r->func(r, ARES_OK);
+  }
+  sel_rmtimer(&r->t);
+  xfree(r->addr);
+  a_bgrelease(&r->bg);
+} 
 
 
-/* --- @a_addcancel@ --- *
+/* --- @a_restimer@ --- *
  *
  *
- * Arguments:  @admin_bgop *bg@ = background operation
+ * Arguments:  @struct timeval *tv@ = timer
+ *             @void *v@ = pointer to resolver operation
  *
  * Returns:    ---
  *
  *
  * Returns:    ---
  *
- * Use:                Cancels an add operation.
+ * Use:                Times out a resolver.
  */
 
  */
 
-static void a_addcancel(admin_bgop *bg)
+static void a_restimer(struct timeval *tv, void *v)
 {
 {
-  admin_addop *add = (admin_addop *)bg;
-
-  T( trace(T_ADMIN, "admin: cancel add op %s", BGTAG(add)); )
-  sel_rmtimer(&add->t);
-  bres_abort(&add->r);
-  a_addfree(add);
+  admin_resop *r = v;
+
+  T( trace(T_ADMIN, "admin: resop %s timeout", BGTAG(r)); )
+  a_bgfail(&r->bg, "resolver-timeout %s\n", r->addr);
+  r->func(r, ARES_FAIL);
+  bres_abort(&r->r);
+  xfree(r->addr);
+  a_bgrelease(&r->bg);
 }
 
 }
 
-/* --- @a_doadd@ --- *
+/* --- @a_rescancel@ --- *
  *
  *
- * Arguments:  @admin_addop *add@ = operation block
+ * Arguments:  @admin_bgop *bg@ = background operation
  *
  * Returns:    ---
  *
  *
  * Returns:    ---
  *
- * Use:                Does the peer add thing.
+ * Use:                Cancels an add operation.
  */
 
  */
 
-static void a_doadd(admin_addop *add)
+static void a_rescancel(admin_bgop *bg)
 {
 {
-  if (p_find(add->peer.name))
-    a_bgfail(&add->bg, "peer-exists %s", add->peer.name);
-  else if (!p_create(&add->peer))
-    a_bgfail(&add->bg, "peer-create-fail %s", add->peer.name);
-  else
-    a_bgok(&add->bg);
+  admin_resop *r = (admin_resop *)bg;
+
+  T( trace(T_ADMIN, "admin: cancel resop %s", BGTAG(r)); )
+  r->func(r, ARES_FAIL);
+  sel_rmtimer(&r->t);
+  xfree(r->addr);
+  bres_abort(&r->r);
 }
 }
-/* --- @a_addresolve@ --- *
+
+/* --- @a_resolve@ --- *
  *
  *
- * Arguments:  @struct hostent *h@ = pointer to resolved hostname
- *             @void *v@ = pointer to add operation
+ * Arguments:  @admin *a@ = administration connection
+ *             @admin_resop *r@ = resolver operation to run
+ *             @const char *tag@ = background operation tag
+ *             @void (*func)(struct admin_resop *, int@ = handler function
+ *             @unsigned ac@ = number of remaining arguments
+ *             @char *av[]@ = pointer to remaining arguments
  *
  * Returns:    ---
  *
  *
  * Returns:    ---
  *
- * Use:                Handles a completed name resolution.
+ * Use:                Cranks up a resolver job.
  */
 
  */
 
-static void a_addresolve(struct hostent *h, void *v)
+static void a_resolve(admin *a, admin_resop *r, const char *tag,
+                     void (*func)(struct admin_resop *, int),
+                     unsigned ac, char *av[])
 {
 {
-  admin_addop *add = v;
+  struct timeval tv;
+  unsigned long pt;
+  char *p;
+  int i = 0;
 
 
-  T( trace(T_ADMIN, "admin: add op %s resolved", BGTAG(add)); )
-  TIMER;
-  if (!h)
-    a_bgfail(&add->bg, "resolve-error %s", add->paddr);
-  else {
-    memcpy(&add->peer.sa.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
-    a_doadd(add);
+  /* --- Fill in the easy bits of address --- */
+
+  r->addr = 0;
+  r->func = func;
+  if (mystrieq(av[i], "inet")) i++;
+  if (ac - i != 2) {
+    a_fail(a, "bad-addr-syntax [inet] ADDRESS PORT");
+    goto fail;
+  }
+  r->sa.sin.sin_family = AF_INET;
+  r->sasz = sizeof(r->sa.sin);
+  r->addr = xstrdup(av[i]);
+  pt = strtoul(av[i + 1], &p, 0);
+  if (*p) {
+    struct servent *s = getservbyname(av[i + 1], "udp");
+    if (!s) {
+      a_fail(a, "unknown-service %s", av[i + 1]);
+      goto fail;
+    }
+    pt = ntohs(s->s_port);
   }
   }
-  sel_rmtimer(&add->t);
-  a_addfree(add);
-  a_bgrelease(&add->bg);
+  if (pt == 0 || pt >= 65536) {
+    a_fail(a, "invalid-port %lu", pt);
+    goto fail;
+  }
+  r->sa.sin.sin_port = htons(pt);
+
+  /* --- Report backgrounding --- *
+   *
+   * Do this for consistency of interface, even if we're going to get the
+   * answer straight away.
+   */
+
+  a_bgadd(a, &r->bg, tag, a_rescancel);
+  T( trace(T_ADMIN, "admin: %u, resop %s, hostname `%s'",
+          a->seq, BGTAG(r), r->addr); )
+
+  /* --- If the name is numeric, do it the easy way --- */
+  
+  if (inet_aton(av[i], &r->sa.sin.sin_addr)) {
+    T( trace(T_ADMIN, "admin: resop %s done the easy way", BGTAG(r)); )
+    func(r, ARES_OK);
+    xfree(r->addr);
+    a_bgrelease(&r->bg);
+    return;
+  }
+
+  /* --- Store everything for later and crank up the resolver --- */
+
+  gettimeofday(&tv, 0);
+  tv.tv_sec += T_RESOLVE;
+  sel_addtimer(&sel, &r->t, &tv, a_restimer, r);
+  bres_byname(&r->r, r->addr, a_resolved, r);
+  return;
+
+fail:
+  func(r, ARES_FAIL);
+  if (r->addr) xfree(r->addr);
+  xfree(r);
 }
 
 }
 
-/* --- @a_addtimer@ --- *
+/*----- Adding peers ------------------------------------------------------*/
+
+/* --- @a_doadd@ --- *
  *
  *
- * Arguments:  @struct timeval *tv@ = timer
- *             @void *v@ = pointer to add operation
+ * Arguments:  @admin_resop *r@ = resolver operation
+ *             @int rc@ = how it worked
  *
  * Returns:    ---
  *
  *
  * Returns:    ---
  *
- * Use:                Times out a resolver.
+ * Use:                Handles a completed resolution.
  */
 
  */
 
-static void a_addtimer(struct timeval *tv, void *v)
+static void a_doadd(admin_resop *r, int rc)
 {
 {
-  admin_addop *add = v;
+  admin_addop *add = (admin_addop *)r;
+
+  T( trace(T_ADMIN, "admin: done add op %s", BGTAG(add)); )
+
+  if (rc == ARES_OK) {
+    add->peer.sasz = add->r.sasz;
+    add->peer.sa = add->r.sa;
+    if (p_find(add->peer.name))
+      a_bgfail(&add->r.bg, "peer-exists %s", add->peer.name);
+    else if (!p_create(&add->peer))
+      a_bgfail(&add->r.bg, "peer-create-fail %s", add->peer.name);
+    else
+      a_bgok(&add->r.bg);
+  }
 
 
-  T( trace(T_ADMIN, "admin: add op %s timeout", BGTAG(add)); )
-  a_bgfail(&add->bg, "resolver-timeout %s\n", add->paddr);
-  bres_abort(&add->r);
-  a_addfree(add);
-  a_bgrelease(&add->bg);
+  xfree(add->peer.name);
 }
 
 /* --- @acmd_add@ --- *
 }
 
 /* --- @acmd_add@ --- *
@@ -721,27 +825,23 @@ static void a_addtimer(struct timeval *tv, void *v)
 
 static void acmd_add(admin *a, unsigned ac, char *av[])
 {
 
 static void acmd_add(admin *a, unsigned ac, char *av[])
 {
-  unsigned long pt;
-  struct timeval tv;
   unsigned i, j;
   unsigned i, j;
-  char *p;
   const char *tag = 0;
   admin_addop *add = 0;
 
   const char *tag = 0;
   admin_addop *add = 0;
 
-  /* --- Make sure someone's not got there already --- */
-
-  if (p_find(av[0])) {
-    a_fail(a, "peer-exists %s", av[0]);
-    goto fail;
-  }
-
   /* --- Set stuff up --- */
 
   add = xmalloc(sizeof(*add));
   add->peer.name = xstrdup(av[0]);
   add->peer.t_ka = 0;
   add->peer.tops = tun_default;
   /* --- Set stuff up --- */
 
   add = xmalloc(sizeof(*add));
   add->peer.name = xstrdup(av[0]);
   add->peer.t_ka = 0;
   add->peer.tops = tun_default;
-  add->paddr = 0;
+
+  /* --- Make sure someone's not got there already --- */
+
+  if (p_find(av[0])) {
+    a_fail(a, "peer-exists %s", av[0]);
+    goto fail;
+  }
 
   /* --- Parse options --- */
 
 
   /* --- Parse options --- */
 
@@ -757,7 +857,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
       for (j = 0;; j++) {
        if (!tunnels[j]) {
          a_fail(a, "unknown-tunnel %s", av[i]);
       for (j = 0;; j++) {
        if (!tunnels[j]) {
          a_fail(a, "unknown-tunnel %s", av[i]);
-         return;
+         goto fail;
        }
        if (mystrieq(av[i], tunnels[j]->name)) {
          add->peer.tops = tunnels[j];
        }
        if (mystrieq(av[i], tunnels[j]->name)) {
          add->peer.tops = tunnels[j];
@@ -769,7 +869,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
       if (!av[++i]) goto bad_syntax;
       if ((t = a_parsetime(av[i])) < 0) {
        a_fail(a, "bad-time-spec %s", av[i]);
       if (!av[++i]) goto bad_syntax;
       if ((t = a_parsetime(av[i])) < 0) {
        a_fail(a, "bad-time-spec %s", av[i]);
-       return;
+       goto fail;
       }
       add->peer.t_ka = t;
     } else if (mystrieq(av[i], "--")) {
       }
       add->peer.t_ka = t;
     } else if (mystrieq(av[i], "--")) {
@@ -780,66 +880,18 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     i++;
   }
 
     i++;
   }
 
-  /* --- Fill in the easy bits of address --- */
-
-  if (mystrieq(av[i], "inet")) i++;
-  if (ac - i != 2) {
-    a_fail(a, "bad-syntax -- add PEER [OPTIONS] [inet] ADDRESS PORT");
-    goto fail;
-  }
-  add->peer.sa.sin.sin_family = AF_INET;
-  add->peer.sasz = sizeof(add->peer.sa.sin);
-  add->paddr = xstrdup(av[i]);
-  pt = strtoul(av[i + 1], &p, 0);
-  if (*p) {
-    struct servent *s = getservbyname(av[i + 1], "udp");
-    if (!s) {
-      a_fail(a, "unknown-service %s", av[i + 1]);
-      goto fail;
-    }
-    pt = ntohs(s->s_port);
-  }
-  if (pt == 0 || pt >= 65536) {
-    a_fail(a, "invalid-port %lu", pt);
-    goto fail;
-  }
-  add->peer.sa.sin.sin_port = htons(pt);
-
-  /* --- Report backgrounding --- *
-   *
-   * Do this for consistency of interface, even if we're going to get the
-   * answer straight away.
-   */
+  /* --- Crank up the resolver --- */
 
 
-  a_bgadd(a, &add->bg, tag, a_addcancel);
-  T( trace(T_ADMIN, "admin: %u, add op %s resolving hostname `%s'",
-          a->seq, BGTAG(add), add->paddr); )
-
-  /* --- If the name is numeric, do it the easy way --- */
-  
-  if (inet_aton(av[i], &add->peer.sa.sin.sin_addr)) {
-    T( trace(T_ADMIN, "admin: add op %s done the easy way", BGTAG(add)); )
-    a_doadd(add);
-    a_addfree(add);
-    a_bgrelease(&add->bg);
-    return;
-  }
-
-  /* --- Store everything for later and crank up the resolver --- */
-
-  gettimeofday(&tv, 0);
-  tv.tv_sec += T_RESOLVE;
-  sel_addtimer(&sel, &add->t, &tv, a_addtimer, add);
-  bres_byname(&add->r, add->paddr, a_addresolve, add);
+  a_resolve(a, &add->r, tag, a_doadd, ac - i, av + i);
   return;
 
   return;
 
+  /* --- Clearing up --- */
+
 bad_syntax:
   a_fail(a, "bad-syntax -- add PEER [OPTIONS] ADDR ...");
 fail:
 bad_syntax:
   a_fail(a, "bad-syntax -- add PEER [OPTIONS] ADDR ...");
 fail:
-  if (add) {
-    a_addfree(add);
-    xfree(add);
-  }
+  xfree(add->peer.name);
+  xfree(add);
   return;
 }
 
   return;
 }
 
@@ -942,10 +994,8 @@ static void a_ping(admin *a, unsigned ac, char *av[],
   }
 
   if (!av[i]) goto bad_syntax;
   }
 
   if (!av[i]) goto bad_syntax;
-  if ((p = p_find(av[i])) == 0) {
-    a_fail(a, "unknown-peer %s", av[i]);
+  if ((p = a_findpeer(a, av[i])) == 0)
     return;
     return;
-  }
   pg = xmalloc(sizeof(*pg));
   gettimeofday(&pg->pingtime, 0);
   a_bgadd(a, &pg->bg, tag, a_pingcancel);
   pg = xmalloc(sizeof(*pg));
   gettimeofday(&pg->pingtime, 0);
   a_bgadd(a, &pg->bg, tag, a_pingcancel);
@@ -1115,22 +1165,61 @@ static void acmd_ifname(admin *a, unsigned ac, char *av[])
 {
   peer *p;
 
 {
   peer *p;
 
-  if ((p = p_find(av[0])) == 0)
-    a_fail(a, "unknown-peer %s", av[0]);
-  else {
+  if ((p = a_findpeer(a, av[0])) != 0) {
     a_info(a, "%s", p_ifname(p));
     a_ok(a);
   }
 }
 
     a_info(a, "%s", p_ifname(p));
     a_ok(a);
   }
 }
 
+static void acmd_getchal(admin *a, unsigned ac, char *av[])
+{
+  buf b;
+
+  buf_init(&b, buf_i, PKBUFSZ);
+  c_new(&b);
+  a_info(a, "%s", b64_encode(BBASE(&b), BLEN(&b)));
+  a_ok(a);
+}
+
+static void acmd_checkchal(admin *a, unsigned ac, char *av[])
+{
+  base64_ctx b64;
+  buf b;
+  dstr d = DSTR_INIT;
+
+  base64_init(&b64);
+  base64_decode(&b64, av[0], strlen(av[0]), &d);
+  base64_decode(&b64, 0, 0, &d);
+  buf_init(&b, d.buf, d.len);
+  if (c_check(&b) || BBAD(&b) || BLEFT(&b))
+    a_fail(a, "invalid-challenge");
+  else
+    a_ok(a);
+  dstr_destroy(&d);
+}
+
+static void acmd_greet(admin *a, unsigned ac, char *av[])
+{
+  peer *p;
+  base64_ctx b64;
+  dstr d = DSTR_INIT;
+
+  if ((p = a_findpeer(a, av[0])) != 0) {
+    base64_init(&b64);
+    base64_decode(&b64, av[1], strlen(av[1]), &d);
+    base64_decode(&b64, 0, 0, &d);
+    p_greet(p, d.buf, d.len);
+    dstr_destroy(&d);
+    a_ok(a);
+  }
+}
+
 static void acmd_addr(admin *a, unsigned ac, char *av[])
 {
   peer *p;
   const addr *ad;
 
 static void acmd_addr(admin *a, unsigned ac, char *av[])
 {
   peer *p;
   const addr *ad;
 
-  if ((p = p_find(av[0])) == 0)
-    a_fail(a, "unknown-peer %s", av[0]);
-  else {
+  if ((p = a_findpeer(a, av[0])) != 0) {
     ad = p_addr(p);
     assert(ad->sa.sa_family == AF_INET);
     a_info(a, "INET %s %u",
     ad = p_addr(p);
     assert(ad->sa.sa_family == AF_INET);
     a_info(a, "INET %s %u",
@@ -1145,15 +1234,12 @@ static void acmd_peerinfo(admin *a, unsigned ac, char *av[])
   peer *p;
   const peerspec *ps;
 
   peer *p;
   const peerspec *ps;
 
-  if ((p = p_find(av[0])) == 0) {
-    a_fail(a, "unknown-peer %s", av[0]);
-    return;
+  if ((p = a_findpeer(a, av[0])) != 0) {
+    ps = p_spec(p);
+    a_info(a, "tunnel=%s", ps->tops->name);
+    a_info(a, "keepalive=%lu", ps->t_ka);
+    a_ok(a);
   }
   }
-
-  ps = p_spec(p);
-  a_info(a, "tunnel=%s", ps->tops->name);
-  a_info(a, "keepalive=%lu", ps->t_ka);
-  a_ok(a);
 }
 
 static void acmd_servinfo(admin *a, unsigned ac, char *av[])
 }
 
 static void acmd_servinfo(admin *a, unsigned ac, char *av[])
@@ -1169,10 +1255,8 @@ static void acmd_stats(admin *a, unsigned ac, char *av[])
   peer *p;
   stats *st;
 
   peer *p;
   stats *st;
 
-  if ((p = p_find(av[0])) == 0) {
-    a_fail(a, "unknown-peer %s", av[0]);
+  if ((p = a_findpeer(a, av[0])) == 0)
     return;
     return;
-  }
 
   st = p_stats(p);
   a_info(a, "start-time=%s", timestr(st->t_start));
 
   st = p_stats(p);
   a_info(a, "start-time=%s", timestr(st->t_start));
@@ -1196,9 +1280,7 @@ static void acmd_stats(admin *a, unsigned ac, char *av[])
 static void acmd_kill(admin *a, unsigned ac, char *av[])
 {
   peer *p;
 static void acmd_kill(admin *a, unsigned ac, char *av[])
 {
   peer *p;
-  if ((p = p_find(av[0])) == 0)
-    a_fail(a, "unknown-peer %s", av[0]);
-  else {
+  if ((p = a_findpeer(a, av[0])) != 0) {
     p_destroy(p);
     a_ok(a);
   }
     p_destroy(p);
     a_ok(a);
   }
@@ -1207,9 +1289,7 @@ static void acmd_kill(admin *a, unsigned ac, char *av[])
 static void acmd_forcekx(admin *a, unsigned ac, char *av[])
 {
   peer *p;
 static void acmd_forcekx(admin *a, unsigned ac, char *av[])
 {
   peer *p;
-  if ((p = p_find(av[0])) == 0)
-    a_fail(a, "unknown-peer %s", av[0]);
-  else {
+  if ((p = a_findpeer(a, av[0])) != 0) {
     kx_start(&p->kx, 1);
     a_ok(a);
   }
     kx_start(&p->kx, 1);
     a_ok(a);
   }
@@ -1255,9 +1335,12 @@ static const acmd acmdtab[] = {
   { "add",     "add PEER [OPTIONS] ADDR ...",
                                        2,      0xffff, acmd_add },
   { "addr",    "addr PEER",            1,      1,      acmd_addr },
   { "add",     "add PEER [OPTIONS] ADDR ...",
                                        2,      0xffff, acmd_add },
   { "addr",    "addr PEER",            1,      1,      acmd_addr },
+  { "checkchal", "checkchal CHAL",     1,      1,      acmd_checkchal },
   { "daemon",  "daemon",               0,      0,      acmd_daemon },
   { "eping",   "eping [OPTIONS] PEER", 1,      0xffff, acmd_eping },
   { "forcekx", "forcekx PEER",         1,      1,      acmd_forcekx },
   { "daemon",  "daemon",               0,      0,      acmd_daemon },
   { "eping",   "eping [OPTIONS] PEER", 1,      0xffff, acmd_eping },
   { "forcekx", "forcekx PEER",         1,      1,      acmd_forcekx },
+  { "getchal", "getchal",              0,      0,      acmd_getchal },
+  { "greet",   "greet PEER CHAL",      2,      2,      acmd_greet },
   { "help",    "help",                 0,      0,      acmd_help },
   { "ifname",  "ifname PEER",          1,      1,      acmd_ifname },
   { "kill",    "kill PEER",            1,      1,      acmd_kill },
   { "help",    "help",                 0,      0,      acmd_help },
   { "ifname",  "ifname PEER",          1,      1,      acmd_ifname },
   { "kill",    "kill PEER",            1,      1,      acmd_kill },
diff --git a/chal.c b/chal.c
new file mode 100644 (file)
index 0000000..a8cd4a4
--- /dev/null
+++ b/chal.c
@@ -0,0 +1,143 @@
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Cryptographic challenges
+ *
+ * (c) 2005 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * 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 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.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "tripe.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static gmac *mac;
+static uint32 oseq;
+static seqwin iseq;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @c_genkey@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Generates a new challenge key.
+ */
+
+static void c_genkey(void)
+{
+  if (mac && GM_CLASS(mac) == algs.m && oseq < 0x07ffffff) return;
+  if (mac) GM_DESTROY(mac);
+  assert(algs.mksz < sizeof(buf_t));
+  rand_get(RAND_GLOBAL, buf_t, algs.mksz);
+  mac = GM_KEY(algs.m, buf_t, algs.mksz);
+  oseq = 0;
+  seq_reset(&iseq);
+  IF_TRACING(T_CHAL, {
+    trace(T_CHAL, "chal: generated new challenge key");
+    trace_block(T_CRYPTO, "chal: new key", buf_t, algs.mksz);
+  })
+}
+
+/* --- @c_new@ --- *
+ *
+ * Arguments:  @buf *b@ = where to put the challenge
+ *
+ * Returns:    Zero if OK, nonzero on error.
+ *
+ * Use:                Issues a new challenge.
+ */
+
+int c_new(buf *b)
+{
+  octet *p;
+  ghash *h;
+
+  c_genkey();
+  p = BCUR(b);
+  if (buf_putu32(b, oseq++)) return (-1);
+  h = GM_INIT(mac);
+  GH_HASH(h, p, BCUR(b) - p);
+  buf_put(b, GH_DONE(h, 0), algs.tagsz);
+  GH_DESTROY(h);
+  if (BBAD(b)) return (-1);
+  IF_TRACING(T_CHAL, {
+    trace(T_CHAL, "chal: issuing challenge %lu", (unsigned long)(oseq - 1));
+    trace_block(T_CRYPTO, "chal: challenge block", p, BCUR(b) - p);
+  })
+  return (0);
+}
+
+/* --- @c_check@ --- *
+ *
+ * Arguments:  @buf *b@ = where to find the challenge
+ *
+ * Returns:    Zero if OK, nonzero if it didn't work.
+ *
+ * Use:                Checks a challenge.  On failure, the buffer is broken.
+ */
+
+int c_check(buf *b)
+{
+  const octet *p;
+  size_t sz = 4 + algs.tagsz;
+  uint32 seq;
+  ghash *h;
+  int ok;
+
+  if ((p = buf_get(b, sz)) == 0) {
+    a_warn("CHAL invalid-challenge");
+    goto fail;
+  }
+  IF_TRACING(T_CHAL, trace_block(T_CRYPTO, "chal: check challenge", p, sz); )
+  if (!mac) {
+    a_warn("CHAL impossible-challenge");
+    goto fail;
+  }
+  h = GM_INIT(mac);
+  GH_HASH(h, p, 4);
+  ok = (memcmp(GH_DONE(h, 0), p + 4, algs.tagsz) == 0);
+  GH_DESTROY(h);
+  if (!ok) {
+    a_warn("CHAL incorrect-tag");
+    goto fail;
+  }
+  seq = LOAD32(p);
+  switch (seq_check(&iseq, LOAD32(p))) {
+    case SEQ_OK: break;
+    case SEQ_OLD: a_warn("CHAL replay old-sequence"); goto fail;
+    case SEQ_REPLAY: a_warn("CHAL replay duplicated-sequence"); goto fail;
+    default: abort();
+  }
+  T( trace(T_CHAL, "chal: checked challenge %lu", (unsigned long)seq); )
+  return (0);
+
+fail:
+  buf_break(b);
+  return (-1);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
index ef4865c..60caf64 100644 (file)
@@ -1,7 +1,7 @@
 Source: tripe
 Section: net
 Priority: extra
 Source: tripe
 Section: net
 Priority: extra
-Maintainer: Mark Wooding <mdw@nsict.org>
+Maintainer: Mark Wooding <mdw@distorted.org.uk>
 Build-Depends: catacomb-dev (>= 2.1.0), mlib-dev (>= 2.0.3),
  tethereal, ethereal-dev (>= 0.10.10), debhelper (>= 4.0.2)
 Standards-Version: 3.1.1
 Build-Depends: catacomb-dev (>= 2.1.0), mlib-dev (>= 2.0.3),
  tethereal, ethereal-dev (>= 0.10.10), debhelper (>= 4.0.2)
 Standards-Version: 3.1.1
index b6bcdfc..4afa6a9 100644 (file)
@@ -24,10 +24,9 @@ with little difficulty.
 By default, the server listens for admin connections on the Unix-domain
 socket
 .BR /var/lib/tripe/tripesock .
 By default, the server listens for admin connections on the Unix-domain
 socket
 .BR /var/lib/tripe/tripesock .
-Administration commands use a simple textual protocol.  Each client
-command or server response consists of a line of ASCII text terminated
-by a single linefeed character.  No command may be longer than 255
-characters.
+Administration commands use a textual protocol.  Each client command or
+server response consists of a line of ASCII text terminated by a single
+linefeed character.  No command may be longer than 255 characters.
 .SS "General structure"
 Each command or response line consists of a sequence of
 whitespace-separated words.  The number and nature of whitespace
 .SS "General structure"
 Each command or response line consists of a sequence of
 whitespace-separated words.  The number and nature of whitespace
@@ -251,6 +250,13 @@ Emits an
 line reporting the IP address and port number stored for
 .IR peer .
 .TP
 line reporting the IP address and port number stored for
 .IR peer .
 .TP
+.BI "CHECKCHAL " challenge
+Verifies a challenge as being one earlier issued by
+.B GETCHAL
+and not previously either passed to
+.B CHECKCHAL
+or in a greeting message.
+.TP
 .B "DAEMON"
 Causes the server to disassociate itself from its terminal and become a
 background task.  This only works once.  A warning is issued.
 .B "DAEMON"
 Causes the server to disassociate itself from its terminal and become a
 background task.  This only works once.  A warning is issued.
@@ -268,6 +274,20 @@ Requests the server to begin a new key exchange with
 .I peer
 immediately.
 .TP
 .I peer
 immediately.
 .TP
+.B "GETCHAL"
+Requests a challenge.  The challenge is returned in an
+.B INFO
+line, as a base64-encoded string.  See
+.BR CHECKCHAL .
+.TP
+.BI "GREET " peer " " challenge
+Sends a greeting packet containing the
+.I challenge
+(base-64 encoded) to the named
+.IR peer .
+The expectation is that this will cause the peer to recognize us and
+begin a key-exchange.
+.TP
 .B "HELP"
 Causes the server to emit an
 .B INFO
 .B "HELP"
 Causes the server to emit an
 .B INFO
@@ -425,15 +445,6 @@ the backgroud name-resolution required by the
 .B ADD
 command.
 .TP
 .B ADD
 command.
 .TP
-.B p
-Display contents of packets sent and received by the tunnel and/or peer
-modules.
-.TP
-.B c
-Display inputs, outputs and intermediate results of cryptographic
-operations.  This includes plaintext and key material.  Use with
-caution.
-.TP
 .B s
 Handling of symmetric keysets: creation and expiry of keysets, and
 encryption and decryption of messages.
 .B s
 Handling of symmetric keysets: creation and expiry of keysets, and
 encryption and decryption of messages.
@@ -443,6 +454,21 @@ Key exchange: reception, parsing and emission of key exchange messages.
 .TP
 .B m
 Key management: loading keys and checking for file modifications.
 .TP
 .B m
 Key management: loading keys and checking for file modifications.
+.TP
+.B l
+Display information about challenge issuing and verification.
+.TP
+.B p
+Display contents of packets sent and received by the tunnel and/or peer
+modules.
+.TP
+.B c
+Display inputs, outputs and intermediate results of cryptographic
+operations.  This includes plaintext and key material.  Use with
+caution.
+.TP
+.B A
+All of the above.
 .PP
 Note that the
 .B p
 .PP
 Note that the
 .B p
@@ -453,19 +479,17 @@ and
 outputs provide extra detail for other outputs.  Specifying
 .B p
 without
 outputs provide extra detail for other outputs.  Specifying
 .B p
 without
-.B r
+.BR r
 or
 .B t
 isn't useful; neither is specifying
 .B c
 without one of
 .BR s ,
 or
 .B t
 isn't useful; neither is specifying
 .B c
 without one of
 .BR s ,
+.BR l ,
 .B x
 or
 .BR m .
 .B x
 or
 .BR m .
-.TP
-.B A
-All of the above.
 .RE
 .TP
 .B "TUNNELS"
 .RE
 .TP
 .B "TUNNELS"
@@ -507,7 +531,7 @@ messages.
 .B WARN
 messages.
 .TP
 .B WARN
 messages.
 .TP
-.B a
+.B A
 All of the above.
 .RE
 .TP
 All of the above.
 .RE
 .TP
@@ -530,6 +554,10 @@ The
 .B tripe
 server is already running as a daemon.
 .TP
 .B tripe
 server is already running as a daemon.
 .TP
+.BI "bad-addr-syntax \-\- " message
+(For commands accepting socket addresses.)  The address couldn't be
+understood.
+.TP
 .BI "bad-syntax \-\- " message
 (For any command.)  The command couldn't be understood: e.g., the number
 of arguments was wrong.
 .BI "bad-syntax \-\- " message
 (For any command.)  The command couldn't be understood: e.g., the number
 of arguments was wrong.
@@ -635,6 +663,12 @@ and its network address is
 .BI "DAEMON"
 The server has forked off into the sunset and become a daemon.
 .TP
 .BI "DAEMON"
 The server has forked off into the sunset and become a daemon.
 .TP
+.BI "GREET " challenge " " address \fR...
+A valid greeting was received, with the given challenge (exactly as it
+was returned by
+.B GETCHAL
+earlier).
+.TP
 .BI "KILL " peer
 The peer
 .I peer
 .BI "KILL " peer
 The peer
 .I peer
@@ -677,6 +711,29 @@ client.
 .BI "ADMIN client-read-error \-\- " message
 There was an error sending data to a client.  The connection to the
 client has been closed.
 .BI "ADMIN client-read-error \-\- " message
 There was an error sending data to a client.  The connection to the
 client has been closed.
+.SS "CHAL warnings"
+These indicate errors in challenges, either in the
+.B CHECKCHAL
+command or in greeting packets.
+.TP
+.B "CHAL impossible-challenge"
+The server hasn't issued any challenges yet.  Quite how anyone else
+thought he could make one up is hard to imagine.
+.TP
+.B "CHAL incorrect-tag"
+Challenge received contained the wrong authentication data.  It might be
+very stale, or a forgery.
+.TP
+.B "CHAL invalid-challenge"
+Challenge received was the wrong length.  We might have changed MAC
+algorithms since the challenge was issued, or it might just be rubbish.
+.TP
+.B "CHAL replay duplicated-sequence"
+Challenge received was a definite replay of an old challenge.  Someone's
+up to something!
+.TP
+.B "CHAL replay old-sequence"
+Challenge received was old, but maybe not actually a replay.  Try again.
 .SS "KEYMGMT warnings"
 These indicate a problem with the keyring files, or the keys stored in
 them.
 .SS "KEYMGMT warnings"
 These indicate a problem with the keyring files, or the keys stored in
 them.
index b3f2190..4fa8402 100644 (file)
@@ -199,6 +199,10 @@ static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t)
            col_set_str(p->cinfo, COL_INFO,
                        "Miscellaneous, encrypted ping reply");
            break;
            col_set_str(p->cinfo, COL_INFO,
                        "Miscellaneous, encrypted ping reply");
            break;
+         case MISC_GREET:
+           col_set_str(p->cinfo, COL_INFO,
+                       "Miscellaneous, greeting");
+           break;
          default:
            col_add_fstr(p->cinfo, COL_INFO,
                         "Miscellaneous, unknown type code %u",
          default:
            col_add_fstr(p->cinfo, COL_INFO,
                         "Miscellaneous, unknown type code %u",
@@ -269,6 +273,7 @@ static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t)
          case MISC_NOP:
          case MISC_PING:
          case MISC_PONG:
          case MISC_NOP:
          case MISC_PING:
          case MISC_PONG:
+         case MISC_GREET:
            proto_tree_add_item(tt, hf_tripe_misc_payload,
                                b, off, -1, FALSE);
            goto done;
            proto_tree_add_item(tt, hf_tripe_misc_payload,
                                b, off, -1, FALSE);
            goto done;
@@ -366,7 +371,7 @@ void proto_register_tripe(void)
       "This is the TrIPE miscellaneous message type subcode."
     } },
     { &hf_tripe_misc_payload, {
       "This is the TrIPE miscellaneous message type subcode."
     } },
     { &hf_tripe_misc_payload, {
-      "Miscellaneous message type", "tripe.misc.payload",
+      "Miscellaneous message payload", "tripe.misc.payload",
       FT_BYTES, BASE_NONE, 0, 0,
       "This is the miscellaneous message payload."
     } },
       FT_BYTES, BASE_NONE, 0, 0,
       "This is the miscellaneous message payload."
     } },
index cdd0c99..9b804ea 100644 (file)
--- a/keyset.c
+++ b/keyset.c
@@ -265,27 +265,12 @@ static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
 
 static int dosequence(keyset *ks, uint32 seq)
 {
 
 static int dosequence(keyset *ks, uint32 seq)
 {
-  uint32 seqbit;
-  uint32 n;
-
-  if (seq < ks->iseq) {
-    a_warn("SYMM replay old-sequence");
-    return (-1);
-  }
-  if (seq >= ks->iseq + KS_SEQWINSZ) {
-    n = seq - (ks->iseq + KS_SEQWINSZ - 1);
-    if (n < KS_SEQWINSZ)
-      ks->iwin >>= n;
-    else
-      ks->iwin = 0;
-    ks->iseq += n;
-  }
-  seqbit = 1 << (seq - ks->iseq);
-  if (ks->iwin & seqbit) {
-    a_warn("SYMM replay duplicated-sequence");
-    return (-1);
+  switch (seq_check(&ks->iseq, seq)) {
+    case SEQ_OK: break;
+    case SEQ_OLD: a_warn("SYMM replay old-sequence"); return (-1);
+    case SEQ_REPLAY: a_warn("SYMM replay duplicated-sequence"); return (-1);
+    default: abort();
   }
   }
-  ks->iwin |= seqbit;
   return (0);
 }
 
   return (0);
 }
 
@@ -397,8 +382,8 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
   ks->ref = 1;
   ks->t_exp = now + T_EXP;
   ks->sz_exp = SZ_EXP;
   ks->ref = 1;
   ks->t_exp = now + T_EXP;
   ks->sz_exp = SZ_EXP;
-  ks->oseq = ks->iseq = 0;
-  ks->iwin = 0;
+  ks->oseq = 0;
+  seq_reset(&ks->iseq);
   ks->next = 0;
   ks->p = p;
   ks->f = KSF_LISTEN;
   ks->next = 0;
   ks->p = p;
   ks->f = KSF_LISTEN;
diff --git a/peer.c b/peer.c
index 5e4c4f9..6b746dd 100644 (file)
--- a/peer.c
+++ b/peer.c
@@ -53,17 +53,6 @@ const tunnel_ops *tunnels[] = {
 
 /*----- Main code ---------------------------------------------------------*/
 
 
 /*----- Main code ---------------------------------------------------------*/
 
-static void checktimers(void)
-{
-  sel_timer *t, **tt;
-
-  tt = &sel.timers;
-  while (*tt) {
-    assert((*tt)->prev == tt);
-    tt = &(*tt)->next;
-  }
-}
-
 /* --- @p_pingtype@ --- *
  *
  * Arguments:  @unsigned msg@ = message type
 /* --- @p_pingtype@ --- *
  *
  * Arguments:  @unsigned msg@ = message type
@@ -144,7 +133,7 @@ found:
 
 static void p_read(int fd, unsigned mode, void *v)
 {
 
 static void p_read(int fd, unsigned mode, void *v)
 {
-  peer *p;
+  peer *p = 0;
   addr a;
   size_t sz;
   ssize_t n;
   addr a;
   size_t sz;
   ssize_t n;
@@ -161,6 +150,28 @@ static void p_read(int fd, unsigned mode, void *v)
     return;
   }
 
     return;
   }
 
+  /* --- If the packet is a greeting, don't check peers --- */
+
+  if (n && buf_i[0] == (MSG_MISC | MISC_GREET)) {
+    IF_TRACING(T_PEER, {
+      trace(T_PEER, "peer: greeting received from INET %s %u",
+           inet_ntoa(a.sin.sin_addr),
+           (unsigned)ntohs(a.sin.sin_port));
+      trace_block(T_PACKET, "peer: greeting contents", buf_i, n);
+    })
+    buf_init(&b, buf_i, n);
+    buf_getbyte(&b);
+    if (c_check(&b) || BLEFT(&b)) {
+      a_warn("PEER - invalid-greeting");
+      return;
+    }
+    a_notify("GREET %s INET %s %u",
+            b64_encode(buf_i + 1, n - 1),
+            inet_ntoa(a.sin.sin_addr),
+            (unsigned)ntohs(a.sin.sin_port));
+    return;
+  }
+
   /* --- Find the appropriate peer --- */
 
   assert(a.sa.sa_family == AF_INET);
   /* --- Find the appropriate peer --- */
 
   assert(a.sa.sa_family == AF_INET);
@@ -357,7 +368,6 @@ void p_pingdone(ping *p, int rc)
   if (rc != PING_TIMEOUT) sel_rmtimer(&p->t);
   T( trace(T_PEER, "peer: ping 0x%08lx done (rc = %d)",
           (unsigned long)p->id, rc); )
   if (rc != PING_TIMEOUT) sel_rmtimer(&p->t);
   T( trace(T_PEER, "peer: ping 0x%08lx done (rc = %d)",
           (unsigned long)p->id, rc); )
-checktimers();
   if (rc >= 0) p->func(rc, p->arg);
 }
 
   if (rc >= 0) p->func(rc, p->arg);
 }
 
@@ -435,12 +445,29 @@ int p_pingsend(peer *p, ping *pg, unsigned type,
   gettimeofday(&tv, 0);
   tv.tv_sec += timeout;
   sel_addtimer(&sel, &pg->t, &tv, p_pingtimeout, pg);
   gettimeofday(&tv, 0);
   tv.tv_sec += timeout;
   sel_addtimer(&sel, &pg->t, &tv, p_pingtimeout, pg);
-checktimers();
   T( trace(T_PEER, "peer: send %s 0x%08lx to %s",
           p_pingtype(type), (unsigned long)pg->id, p->spec.name); )
   return (0);
 }
 
   T( trace(T_PEER, "peer: send %s 0x%08lx to %s",
           p_pingtype(type), (unsigned long)pg->id, p->spec.name); )
   return (0);
 }
 
+/* --- @p_greet@ --- *
+ *
+ * Arguments:  @peer *p@ = peer to send to
+ *             @const void *c@ = pointer to challenge
+ *             @size_t sz@ = size of challenge
+ *
+ * Returns:    ---
+ *
+ * Use:                Sends a greeting packet.
+ */
+
+void p_greet(peer *p, const void *c, size_t sz)
+{
+  buf *b = p_txstart(p, MSG_MISC | MISC_GREET);
+  buf_put(b, c, sz);
+  p_txend(p);
+}
+
 /* --- @p_tun@ --- *
  *
  * Arguments:  @peer *p@ = pointer to peer block
 /* --- @p_tun@ --- *
  *
  * Arguments:  @peer *p@ = pointer to peer block
index 590327d..f4ab92e 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: servutil.c,v 1.5 2004/04/08 01:36:17 mdw Exp $
+ * $Id$
  *
  * Various handy server-only utilities
  *
  *
  * Various handy server-only utilities
  *
@@ -91,4 +91,74 @@ const char *timestr(time_t t)
   return ((const char *)buf_t);
 }
 
   return ((const char *)buf_t);
 }
 
+/* --- @b64_encode@ --- *
+ *
+ * Arguments:  @const void *p@ = pointer to some gorp
+ *             @size_t sz@ = size of the gorp
+ *
+ * Returns:    Pointer to base64-encoded version in @buf_t@.
+ */
+
+const char *b64_encode(const void *p, size_t sz)
+{
+  base64_ctx b64;
+  dstr d = DSTR_INIT;
+
+  base64_init(&b64);
+  b64.indent = "";
+  b64.maxline = 0;
+  base64_encode(&b64, p, sz, &d);
+  base64_encode(&b64, 0, 0, &d);
+  while (d.len && d.buf[d.len - 1] == '=') d.len--;
+  assert(d.len < sizeof(buf_t));
+  memcpy(buf_t, d.buf, d.len);
+  buf_t[d.len] = 0;
+  dstr_destroy(&d);
+  return ((const char *)buf_t);
+}
+
+/* --- @seq_reset@ --- *
+ *
+ * Arguments:  @seqwin *s@ = sequence-checking window
+ *
+ * Returns:    ---
+ *
+ * Use:                Resets a sequence number window.
+ */
+
+void seq_reset(seqwin *s) { s->seq = 0; s->win = 0; }
+
+/* --- @seq_check@ --- *
+ *
+ * Arguments:  @seqwin *s@ = sequence-checking window
+ *             @uint32 q@ = sequence number to check
+ *
+ * Returns:    A @SEQ_@ code.
+ *
+ * Use:                Checks a sequence number against the window, updating things
+ *             as necessary.
+ */
+
+int seq_check(seqwin *s, uint32 q)
+{
+  uint32 qbit;
+  uint32 n;
+
+  if (q < s->seq)
+    return (SEQ_OLD);
+  if (q >= s->seq + SEQ_WINSZ) {
+    n = q - (s->seq + SEQ_WINSZ - 1);
+    if (n < SEQ_WINSZ)
+      s->win >>= n;
+    else
+      s->win = 0;
+    s->seq += n;
+  }
+  qbit = 1 << (q - s->seq);
+  if (s->win & qbit)
+    return (SEQ_REPLAY);
+  s->win |= qbit;
+  return (0);
+}
+
 /*----- That's all, folks -------------------------------------------------*/
 /*----- That's all, folks -------------------------------------------------*/
index ebf7a71..bfa9748 100644 (file)
@@ -77,6 +77,7 @@
 #define MISC_PONG 2u                   /* Transport-level ping response */
 #define MISC_EPING 3u                  /* Encrypted ping */
 #define MISC_EPONG 4u                  /* Encrypted ping response */
 #define MISC_PONG 2u                   /* Transport-level ping response */
 #define MISC_EPING 3u                  /* Encrypted ping */
 #define MISC_EPONG 4u                  /* Encrypted ping response */
+#define MISC_GREET 5u                  /* A greeting from a NATed peer */
 
 /* --- Symmetric encryption and keysets --- *
  *
 
 /* --- Symmetric encryption and keysets --- *
  *
diff --git a/tripe.h b/tripe.h
index 47719fe..eec4093 100644 (file)
--- a/tripe.h
+++ b/tripe.h
@@ -66,6 +66,7 @@
 
 #include <mLib/alloc.h>
 #include <mLib/arena.h>
 
 #include <mLib/alloc.h>
 #include <mLib/arena.h>
+#include <mLib/base64.h>
 #include <mLib/bres.h>
 #include <mLib/dstr.h>
 #include <mLib/env.h>
 #include <mLib/bres.h>
 #include <mLib/dstr.h>
 #include <mLib/env.h>
 #define T_KEYSET 32u
 #define T_KEYEXCH 64u
 #define T_KEYMGMT 128u
 #define T_KEYSET 32u
 #define T_KEYEXCH 64u
 #define T_KEYMGMT 128u
+#define T_CHAL 256u
 
 
-#define T_ALL 255u
+#define T_ALL 511u
 
 /* --- Units --- */
 
 
 /* --- Units --- */
 
@@ -160,6 +162,21 @@ typedef union addr {
   struct sockaddr_in sin;
 } addr;
 
   struct sockaddr_in sin;
 } addr;
 
+/* --- Sequence number checking --- */
+
+typedef struct seqwin {
+  uint32 seq;                          /* First acceptable input sequence */
+  uint32 win;                          /* Window of acceptable numbers */
+} seqwin;
+
+#define SEQ_WINSZ 32                   /* Bits in sequence number window */
+
+#define SEQ_RESET(iseq) { 
+
+#define SEQ_OK 0                       /* Sequence number valid */
+#define SEQ_OLD -1                     /* Sequence number too old */
+#define SEQ_REPLAY -2                  /* Definitely replayed */
+
 /* --- A symmetric keyset --- *
  *
  * A keyset contains a set of symmetric keys for encrypting and decrypting
 /* --- A symmetric keyset --- *
  *
  * A keyset contains a set of symmetric keys for encrypting and decrypting
@@ -185,11 +202,9 @@ typedef struct keyset {
   size_t tagsz;                                /* Length to truncate MAC tags */
   gmac *min, *mout;                    /* Keyset MACs for integrity */
   uint32 oseq;                         /* Outbound sequence number */
   size_t tagsz;                                /* Length to truncate MAC tags */
   gmac *min, *mout;                    /* Keyset MACs for integrity */
   uint32 oseq;                         /* Outbound sequence number */
-  uint32 iseq, iwin;                   /* Inbound sequence number */
+  seqwin iseq;                         /* Inbound sequence number */
 } keyset;
 
 } keyset;
 
-#define KS_SEQWINSZ 32                 /* Bits in sequence number window */
-
 #define KSF_LISTEN 1u                  /* Don't encrypt packets yet */
 #define KSF_LINK 2u                    /* Key is in a linked list */
 
 #define KSF_LISTEN 1u                  /* Don't encrypt packets yet */
 #define KSF_LINK 2u                    /* Key is in a linked list */
 
@@ -355,14 +370,29 @@ typedef struct admin_bgop {
   void (*cancel)(struct admin_bgop *); /* Destructor function */
 } admin_bgop;
 
   void (*cancel)(struct admin_bgop *); /* Destructor function */
 } admin_bgop;
 
-typedef struct admin_addop {
+typedef struct admin_resop {
   admin_bgop bg;                       /* Background operation header */
   admin_bgop bg;                       /* Background operation header */
-  peerspec peer;                       /* Peer pending creation */
-  char *paddr;                         /* Hostname to be resolved */
+  char *addr;                          /* Hostname to be resolved */
   bres_client r;                       /* Background resolver task */
   sel_timer t;                         /* Timer for resolver */
   bres_client r;                       /* Background resolver task */
   sel_timer t;                         /* Timer for resolver */
+  addr sa;                             /* Socket address */
+  size_t sasz;                         /* Socket address size */
+  void (*func)(struct admin_resop *, int); /* Handler */
+} admin_resop;
+
+enum { ARES_OK, ARES_FAIL };
+
+typedef struct admin_addop {
+  admin_resop r;                       /* Name resolution header */
+  peerspec peer;                       /* Peer pending creation */
 } admin_addop;
 
 } admin_addop;
 
+typedef struct admin_greetop {
+  admin_resop r;                       /* Name resolution header */
+  void *c;                             /* Challenge block */
+  size_t sz;                           /* Length of challenge */
+} admin_greetop;
+
 typedef struct admin_pingop {
   admin_bgop bg;                       /* Background operation header */
   ping ping;                           /* Ping pending response */
 typedef struct admin_pingop {
   admin_bgop bg;                       /* Background operation header */
   ping ping;                           /* Ping pending response */
@@ -691,6 +721,30 @@ extern int ksl_encrypt(keyset **/*ksroot*/, unsigned /*ty*/,
 extern int ksl_decrypt(keyset **/*ksroot*/, unsigned /*ty*/,
                       buf */*b*/, buf */*bb*/);
 
 extern int ksl_decrypt(keyset **/*ksroot*/, unsigned /*ty*/,
                       buf */*b*/, buf */*bb*/);
 
+/*----- Challenges --------------------------------------------------------*/
+
+/* --- @c_new@ --- *
+ *
+ * Arguments:  @buf *b@ = where to put the challenge
+ *
+ * Returns:    Zero if OK, nonzero on error.
+ *
+ * Use:                Issues a new challenge.
+ */
+
+extern int c_new(buf */*b*/);
+
+/* --- @c_check@ --- *
+ *
+ * Arguments:  @buf *b@ = where to find the challenge
+ *
+ * Returns:    Zero if OK, nonzero if it didn't work.
+ *
+ * Use:                Checks a challenge.  On failure, the buffer is broken.
+ */
+
+extern int c_check(buf */*b*/);
+
 /*----- Administration interface ------------------------------------------*/
 
 /* --- @a_warn@ --- *
 /*----- Administration interface ------------------------------------------*/
 
 /* --- @a_warn@ --- *
@@ -819,6 +873,19 @@ extern int p_pingsend(peer */*p*/, ping */*pg*/, unsigned /*type*/,
 
 extern void p_pingdone(ping */*p*/, int /*rc*/);
 
 
 extern void p_pingdone(ping */*p*/, int /*rc*/);
 
+/* --- @p_greet@ --- *
+ *
+ * Arguments:  @peer *p@ = peer to send to
+ *             @const void *c@ = pointer to challenge
+ *             @size_t sz@ = size of challenge
+ *
+ * Returns:    ---
+ *
+ * Use:                Sends a greeting packet.
+ */
+
+extern void p_greet(peer */*p*/, const void */*c*/, size_t /*sz*/);
+
 /* --- @p_tun@ --- *
  *
  * Arguments:  @peer *p@ = pointer to peer block
 /* --- @p_tun@ --- *
  *
  * Arguments:  @peer *p@ = pointer to peer block
@@ -1031,6 +1098,40 @@ extern const char *timestr(time_t /*t*/);
 
 extern int mystrieq(const char */*x*/, const char */*y*/);
 
 
 extern int mystrieq(const char */*x*/, const char */*y*/);
 
+/* --- @b64_encode@ --- *
+ *
+ * Arguments:  @const void *p@ = pointer to some gorp
+ *             @size_t sz@ = size of the gorp
+ *
+ * Returns:    Pointer to base64-encoded version in @buf_t@.
+ */
+
+extern const char *b64_encode(const void */*p*/, size_t /*sz*/);
+
+/* --- @seq_reset@ --- *
+ *
+ * Arguments:  @seqwin *s@ = sequence-checking window
+ *
+ * Returns:    ---
+ *
+ * Use:                Resets a sequence number window.
+ */
+
+extern void seq_reset(seqwin */*s*/);
+
+/* --- @seq_check@ --- *
+ *
+ * Arguments:  @seqwin *s@ = sequence-checking window
+ *             @uint32 q@ = sequence number to check
+ *
+ * Returns:    A @SEQ_@ code.
+ *
+ * Use:                Checks a sequence number against the window, updating things
+ *             as necessary.
+ */
+
+extern int seq_check(seqwin */*s*/, uint32 /*q*/);
+
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus
index a5fe71d..0db0775 100644 (file)
@@ -7,6 +7,7 @@ import socket as S
 from sys import argv, exit, stdin, stdout, stderr
 import os as OS
 from os import environ
 from sys import argv, exit, stdin, stdout, stderr
 import os as OS
 from os import environ
+import math as M
 import sets as SET
 import getopt as O
 import time as T
 import sets as SET
 import getopt as O
 import time as T
@@ -815,8 +816,15 @@ def xlate_time(t):
   """Translate a time in tripe's stats format to something a human might
   actually want to read."""
   if t == 'NEVER': return '(never)'
   """Translate a time in tripe's stats format to something a human might
   actually want to read."""
   if t == 'NEVER': return '(never)'
-  Y, M, D, h, m, s = map(int, rx_time.match(t).group(1, 2, 3, 4, 5, 6))
-  return '%04d:%02d:%02d %02d:%02d:%02d' % (Y, M, D, h, m, s)
+  YY, MM, DD, hh, mm, ss = map(int, rx_time.match(t).group(1, 2, 3, 4, 5, 6))
+  ago = T.time() - T.mktime((YY, MM, DD, hh, mm, ss, 0, 0, -1))
+  ago = M.floor(ago); unit = 's'
+  for n, u in [(60, 'min'), (60, 'hrs'), (24, 'days')]:
+    if ago < 2*n: break
+    ago /= n
+    unit = u
+  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."""
   suff = 'B'
 def xlate_bytes(b):
   """Translate a number of bytes into something a human might want to read."""
   suff = 'B'