chiark / gitweb /
svc: Peer management services.
[tripe] / server / peer.c
index e57c6ba4cfe3342b03734b15f6c0d5c647302985..4bb2c82c6b0f80b07da5f42ab928d7d61532270d 100644 (file)
@@ -122,6 +122,57 @@ found:
   p_pingdone(pg, PING_OK);
 }
 
+/* --- @p_encrypt@ --- *
+ *
+ * Arguments:  @peer *p@ = peer to encrypt message to
+ *             @int ty@ message type to send
+ *             @buf *bin, *bout@ = input and output buffers
+ *
+ * Returns:    ---
+ *
+ * Use:                Convenience function for packet encryption.  Forces
+ *             renegotiation when necessary.  Check for the output buffer
+ *             being broken to find out whether the encryption was
+ *             successful.
+ */
+
+static int p_encrypt(peer *p, int ty, buf *bin, buf *bout)
+{
+  int err = ksl_encrypt(&p->ks, ty, bin, bout);
+
+  if (err == KSERR_REGEN) {
+    kx_start(&p->kx, 1);
+    err = 0;
+  }
+  if (!BOK(bout))
+    err = -1;
+  return (err);
+}
+
+/* --- @p_decrypt@ --- *
+ *
+ * Arguments:  @peer *p@ = peer to decrypt message from
+ *             @int ty@ = message type to expect
+ *             @buf *bin, *bout@ = input and output buffers
+ *
+ * Returns:    Zero on success; nonzero on error.
+ *
+ * Use:                Convenience function for packet decryption.  Reports errors
+ *             and updates statistics appropriately.
+ */
+
+static int p_decrypt(peer *p, int ty, buf *bin, buf *bout)
+{
+  if (ksl_decrypt(&p->ks, ty, bin, bout)) {
+    p->st.n_reject++;
+    a_warn("PEER", "?PEER", p, "decrypt-failed", A_END);
+    return (-1);
+  }
+  if (!BOK(bout))
+    return (-1);
+  return (0);
+}
+
 /* --- @p_read@ --- *
  *
  * Arguments:  @int fd@ = file descriptor to read from
@@ -208,11 +259,8 @@ static void p_read(int fd, unsigned mode, void *v)
        return;
       }
       buf_init(&bb, buf_o, sizeof(buf_o));
-      if (ksl_decrypt(&p->ks, MSG_PACKET, &b, &bb)) {
-       p->st.n_reject++;
-       a_warn("PEER", "?PEER", p, "decrypt-failed", A_END);
+      if (p_decrypt(p, MSG_PACKET, &b, &bb))
        return;
-      }
       if (BOK(&bb)) {
        p->st.n_ipin++;
        p->st.sz_ipin += BSZ(&b);
@@ -239,26 +287,19 @@ static void p_read(int fd, unsigned mode, void *v)
          break;
        case MISC_EPING:
          buf_init(&bb, buf_t, sizeof(buf_t));
-         if (ksl_decrypt(&p->ks, ch, &b, &bb)) {
-           p->st.n_reject++;
-           a_warn("PEER", "?PEER", p, "decrypt-failed", A_END);
+         if (p_decrypt(p, ch, &b, &bb))
            return;
-         }
          if (BOK(&bb)) {
            buf_flip(&bb);
-           if (ksl_encrypt(&p->ks, MSG_MISC | MISC_EPONG, &bb,
-                           p_txstart(p, MSG_MISC | MISC_EPONG)))
-             kx_start(&p->kx, 0);
+           p_encrypt(p, MSG_MISC | MISC_EPONG, &bb,
+                     p_txstart(p, MSG_MISC | MISC_EPONG));
            p_txend(p);
          }
          break;
        case MISC_EPONG:
          buf_init(&bb, buf_t, sizeof(buf_t));
-         if (ksl_decrypt(&p->ks, ch, &b, &bb)) {
-           p->st.n_reject++;
-           a_warn("PEER", "?PEER", p, "decrypt-failed", A_END);
+         if (p_decrypt(p, ch, &b, &bb))
            return;
-         }
          if (BOK(&bb)) {
            buf_flip(&bb);
            p_ponged(p, MISC_EPONG, &bb);
@@ -427,8 +468,7 @@ int p_pingsend(peer *p, ping *pg, unsigned type,
       buf_init(&bb, buf_t, sizeof(buf_t));
       p_pingwrite(pg, &bb);
       buf_flip(&bb);
-      if (ksl_encrypt(&p->ks, MSG_MISC | MISC_EPING, &bb, b))
-       kx_start(&p->kx, 0);
+      p_encrypt(p, MSG_MISC | MISC_EPING, &bb, b);
       if (!BOK(b))
        return (-1);
       p_txend(p);
@@ -486,8 +526,7 @@ void p_tun(peer *p, buf *b)
   buf *bb = p_txstart(p, MSG_PACKET);
 
   TIMER;
-  if (ksl_encrypt(&p->ks, MSG_PACKET, b, bb))
-    kx_start(&p->kx, 0);
+  p_encrypt(p, MSG_PACKET, b, bb);
   if (BOK(bb) && BLEN(bb)) {
     p->st.n_ipout++;
     p->st.sz_ipout += BLEN(bb);
@@ -685,6 +724,8 @@ static void p_setkatimer(peer *p)
 peer *p_create(peerspec *spec)
 {
   peer *p = CREATE(peer);
+  const tunnel_ops *tops = spec->tops;
+  int fd;
   unsigned f;
 
   p->byname = sym_find(&byname, spec->name, -1, sizeof(peer_byname), &f);
@@ -701,27 +742,35 @@ peer *p_create(peerspec *spec)
   p->ifname = 0;
   memset(&p->st, 0, sizeof(stats));
   p->st.t_start = time(0);
-  if ((p->t = spec->tops->create(p, &p->ifname)) == 0)
+  if (!(tops->flags & TUNF_PRIVOPEN))
+    fd = -1;
+  else if ((fd = ps_tunfd(tops, &p->ifname)) < 0)
     goto tidy_2;
+  if ((p->t = tops->create(p, fd, &p->ifname)) == 0)
+    goto tidy_3;
+  T( trace(T_TUNNEL, "peer: attached interface %s to peer `%s'",
+          p->ifname, p_name(p)); )
   p_setkatimer(p);
   if (kx_init(&p->kx, p, &p->ks, p->spec.kxf))
-    goto tidy_3;
+    goto tidy_4;
   a_notify("ADD",
-           "?PEER", p,
-           "%s", p->ifname,
-           "?ADDR", &p->spec.sa,
-           A_END);
+          "?PEER", p,
+          "%s", p->ifname,
+          "?ADDR", &p->spec.sa,
+          A_END);
   if (!(p->spec.kxf & KXF_CORK)) {
     a_notify("KXSTART", "?PEER", p, A_END);
     /* Couldn't tell anyone before */
   }
   return (p);
 
-tidy_3:
+tidy_4:
   if (spec->t_ka)
     sel_rmtimer(&p->tka);
   xfree(p->ifname);
   p->t->ops->destroy(p->t);
+tidy_3:
+  if (fd >= 0) close(fd);
 tidy_2:
   am_remove(&byaddr, p->byaddr);
 tidy_1: