server/peer.c, etc.: Introduce who-goes-there protocol.
[tripe] / server / peer.c
index 0b5a6c2..b20f2fd 100644 (file)
@@ -40,6 +40,7 @@ static struct tunnel_node {
   struct tunnel_node *next;
   const tunnel_ops *tops;
 } *tunnels, **tunnels_tail = &tunnels;
+static ratelim wgt_limit;
 const tunnel_ops *dflttun;
 
 /*----- Main code ---------------------------------------------------------*/
@@ -229,6 +230,7 @@ static int p_decrypt(peer **pp, addr *a, size_t n,
 {
   peer *p, *q;
   int err = KSERR_DECRYPT;
+  buf b;
 
   /* --- If we have a match on the source address then try that first --- */
 
@@ -276,9 +278,17 @@ static int p_decrypt(peer **pp, addr *a, size_t n,
 
 searched:
   if (!p) {
-    if (!q)
+    if (!q) {
       a_warn("PEER", "-", "unexpected-source", "?ADDR", a, A_END);
-    else {
+      if (!ratelim_withdraw(&wgt_limit, 1)) {
+       buf_init(&b, buf_t, sizeof(buf_t));
+       buf_putbyte(&b, MSG_MISC | MISC_WGT);
+       if (n > WGTLEN) n = WGTLEN;
+       buf_put(&b, buf_i, n);
+       T( trace(T_PEER, "peer: sending who-goes-there message"); )
+       assert(BOK(&b)); p_txaddr(a, BBASE(&b), BLEN(&b));
+      }
+    } else {
       a_warn("PEER", "?PEER", p, "decrypt-failed",
             "error-code", "%d", err, A_END);
       p_rxupdstats(q, n);
@@ -325,6 +335,9 @@ static void p_read(int fd, unsigned mode, void *v)
   ssize_t n;
   int ch;
   buf b, bb;
+  const octet *q;
+  unsigned i;
+  time_t now;
 #ifndef NTRACE
   int ix = -1;
   char name[NI_MAXHOST], svc[NI_MAXSERV];
@@ -445,7 +458,7 @@ static void p_read(int fd, unsigned mode, void *v)
            buf_flip(&bb);
            p_encrypt(p, MSG_MISC | MISC_EPONG, &bb,
                      p_txstart(p, MSG_MISC | MISC_EPONG));
-           p_txend(p, 0);
+           p_txend(p, TXF_WGT);
          }
          break;
        case MISC_EPONG:
@@ -467,6 +480,31 @@ static void p_read(int fd, unsigned mode, void *v)
            p_destroy(p, 0);
          }
          break;
+       case MISC_WGT:
+         if (!p) goto unexp;
+         if (!(p->spec.f&PSF_EPHEM))
+           { a_warn("PEER", "?PEER", p, "unexpected-wgt", A_END); break; }
+         n = BLEFT(&b); if (n > WGTLEN) n = WGTLEN;
+         now = time(0);
+         q = buf_get(&b, n); assert(q);
+         for (i = 0; i < NWGT; i++) {
+           if (p->wgt[i].when != (time_t)-1 &&
+               now - p->wgt[i].when <= T_WGT &&
+               p->wgt[i].sz == n &&
+               MEMCMP(p->wgt[i].msg, ==, q, n))
+             goto found_wgt;
+         }
+         a_warn("PEER", "?PEER", p, "unrecognized-wgt", A_END);
+         break;
+       found_wgt:
+         if (p->spec.knock) {
+           T( trace(T_PEER, "peer: who-goes-there from peer: knocking"); )
+           kx_start(&p->kx, 0);
+         } else {
+           T( trace(T_PEER, "peer: who-goes-there from peer: notifying"); )
+           a_notify("WGT", "?PEER", p, A_END);
+         }
+         break;
       }
       break;
     default:
@@ -565,7 +603,16 @@ static int p_dotxend(peer *p)
 
 void p_txend(peer *p, unsigned f)
 {
+  size_t n;
+
   if (p_dotxend(p)) {
+    if ((f&TXF_WGT) && (p->spec.f&PSF_EPHEM)) {
+      n = BLEN(&p->b); if (n > WGTLEN) n = WGTLEN;
+      memcpy(p->wgt[p->wgtix].msg, BBASE(&p->b), n);
+      p->wgt[p->wgtix].sz = n;
+      p->wgt[p->wgtix].when = time(0);
+      p->wgtix++; if (p->wgtix >= NWGT) p->wgtix = 0;
+    }
     if (p->spec.t_ka) {
       sel_rmtimer(&p->tka);
       p_setkatimer(p);
@@ -670,7 +717,7 @@ int p_pingsend(peer *p, ping *pg, unsigned type,
       p_encrypt(p, MSG_MISC | MISC_EPING, &bb, b);
       if (!BOK(b))
        return (-1);
-      p_txend(p, 0);
+      p_txend(p, TXF_WGT);
       break;
     default:
       abort();
@@ -729,7 +776,7 @@ void p_tun(peer *p, buf *b)
   if (BOK(bb) && BLEN(bb)) {
     p->st.n_ipout++;
     p->st.sz_ipout += BLEN(bb);
-    p_txend(p, 0);
+    p_txend(p, TXF_WGT);
   }
 }
 
@@ -932,6 +979,7 @@ void p_init(void)
 {
   sym_create(&byname);
   am_create(&byaddr);
+  ratelim_init(&wgt_limit, 5, 100);
 }
 
 /* --- @p_addtun@ --- *
@@ -1084,7 +1132,7 @@ peer *p_create(peerspec *spec)
   peer *p = CREATE(peer);
   const tunnel_ops *tops = spec->tops;
   int fd;
-  unsigned f;
+  unsigned f, i;
 
   p->byname = sym_find(&byname, spec->name, -1, sizeof(peer_byname), &f);
   if (f) goto tidy_0;
@@ -1126,6 +1174,11 @@ peer *p_create(peerspec *spec)
     /* Couldn't tell anyone before */
   }
   if (p->spec.f & PSF_MOBILE) nmobile++;
+  for (i = 0; i < NWGT; i++) {
+    p->wgt[i].sz = 0;
+    p->wgt[i].when = (time_t)-1;
+  }
+  p->wgtix = 0;
   return (p);
 
 tidy_4: