X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/650a6624cf72fe28e52a29a78de0f1cbfab44d7b..7d6ec3708e83ad0f9fe52360512df995cda06007:/peer.c diff --git a/peer.c b/peer.c index 937d29f2..402d08b5 100644 --- a/peer.c +++ b/peer.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: peer.c,v 1.3 2001/02/04 17:10:58 mdw Exp $ + * $Id$ * * Communication with the peer * @@ -26,21 +26,6 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: peer.c,v $ - * Revision 1.3 2001/02/04 17:10:58 mdw - * Make file descriptors be nonblocking and close-on-exec. - * - * Revision 1.2 2001/02/03 22:40:29 mdw - * Put timer information into the entropy pool when packets are received - * and on similar events. Reseed the generator on the interval timer. - * - * Revision 1.1 2001/02/03 20:26:37 mdw - * Initial checkin. - * - */ - /*----- Header files ------------------------------------------------------*/ #include "tripe.h" @@ -50,6 +35,22 @@ static peer *peers = 0; static sel_file sock; +/*----- Tunnel table ------------------------------------------------------*/ + +const tunnel_ops *tunnels[] = { +#ifdef TUN_LINUX + &tun_linux, +#endif +#ifdef TUN_BSD + &tun_bsd, +#endif +#ifdef TUN_UNET + &tun_unet, +#endif + &tun_slip, + 0 +}, *tun_default; + /*----- Main code ---------------------------------------------------------*/ /* --- @p_read@ --- * @@ -78,7 +79,7 @@ static void p_read(int fd, unsigned mode, void *v) sz = sizeof(addr); n = recvfrom(fd, buf_i, sizeof(buf_i), 0, &a.sa, &sz); if (n < 0) { - a_warn("error reading socket: %s", strerror(errno)); + a_warn("PEER - socket-read-error -- %s", strerror(errno)); return; } @@ -90,44 +91,54 @@ static void p_read(int fd, unsigned mode, void *v) p->peer.sin.sin_port == a.sin.sin_port) goto found; } - a_warn("packet from unexpected peer: %s:%u", - inet_ntoa(a.sin.sin_addr), (unsigned)ntohs(a.sin.sin_port)); + a_warn("PEER - unexpected-source INET %s %u", + inet_ntoa(a.sin.sin_addr), (unsigned)ntohs(a.sin.sin_port)); return; found: - T( trace(T_PEER, "peer: packet received from `%s'", p->name); - trace_block(T_PACKET, "peer: packet contents", buf_i, n); ) + IF_TRACING(T_PEER, { + trace(T_PEER, "peer: packet received from `%s'", p->name); + trace_block(T_PACKET, "peer: packet contents", buf_i, n); + }) /* --- Pick the packet apart --- */ + p->st.t_last = time(0); + p->st.n_in++; + p->st.sz_in += n; buf_init(&b, buf_i, n); if ((ch = buf_getbyte(&b)) < 0) { - a_warn("bad packet from `%s': no type byte", p->name); + a_warn("PEER %s bad-packet no-type", p->name); return; } - switch (ch) { + switch (ch & MSG_CATMASK) { case MSG_PACKET: + if (ch & MSG_TYPEMASK) { + a_warn("PEER %s bad-packet unknown-type 0x%02x", p->name, ch); + p->st.n_reject++; + return; + } buf_init(&bb, buf_o, sizeof(buf_o)); - if (ks_decrypt(&p->ks, &b, &bb)) { - a_warn("couldn't decrypt inbound packet"); + if (ksl_decrypt(&p->ks, MSG_PACKET, &b, &bb)) { + p->st.n_reject++; + a_warn("PEER %s decrypt-failed", p->name); return; } - if (BOK(&bb)) - tun_inject(&p->t, &bb); - else - a_warn("packet build failed"); - break; - case MSG_PRECHALLENGE: - kx_prechallenge(&p->kx, &b); - break; - case MSG_CHALLENGE: - kx_challenge(&p->kx, &b); + if (BOK(&bb)) { + p->st.n_ipin++; + p->st.sz_ipin += BSZ(&b); + p->t->ops->inject(p->t, &bb); + } else { + p->st.n_reject++; + a_warn("PEER %s packet-build-failed", p->name); + } break; - case MSG_RESPONSE: - kx_response(&p->kx, &b); + case MSG_KEYEXCH: + kx_message(&p->kx, ch & MSG_TYPEMASK, &b); break; default: - a_warn("bad packet from `%s': unknown packet type", p->name); + p->st.n_reject++; + a_warn("PEER %s bad-packet unknown-category 0x%02x", p->name, ch); break; } } @@ -162,14 +173,18 @@ buf *p_txstart(peer *p, unsigned msg) void p_txend(peer *p) { if (!BOK(&p->b)) { - a_warn("packet build failed"); + a_warn("PEER %s packet-build-failed", p->name); return; } IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", BBASE(&p->b), BLEN(&p->b)); ) if (sendto(sock.fd, BBASE(&p->b), BLEN(&p->b), 0, &p->peer.sa, p->sasz) < 0) - a_warn("packet send to `%s' failed: %s", p->name, strerror(errno)); + a_warn("PEER %s socket-write-error -- %s", p->name, strerror(errno)); + else { + p->st.n_out++; + p->st.sz_out += BLEN(&p->b); + } } /* --- @p_tun@ --- * @@ -185,11 +200,15 @@ void p_txend(peer *p) void p_tun(peer *p, buf *b) { buf *bb = p_txstart(p, MSG_PACKET); + TIMER; - if (ks_encrypt(&p->ks, b, bb)) + if (ksl_encrypt(&p->ks, MSG_PACKET, b, bb)) kx_start(&p->kx); - if (BCUR(bb) > BBASE(bb)) + if (BOK(bb) && BLEN(bb)) { + p->st.n_ipout++; + p->st.sz_ipout += BLEN(bb); p_txend(p); + } } /* --- @p_interval@ --- * @@ -211,10 +230,19 @@ void p_interval(void) pp = p->next; if (reload) kx_newkeys(&p->kx); - ks_prune(&p->ks); + ksl_prune(&p->ks); } } +/* --- @p_stats@ --- * + * + * Arguments: @peer *p@ = pointer to a peer block + * + * Returns: A pointer to the peer's statistics. + */ + +stats *p_stats(peer *p) { return (&p->st); } + /* --- @p_ifname@ --- * * * Arguments: @peer *p@ = pointer to a peer block @@ -222,7 +250,7 @@ void p_interval(void) * Returns: A pointer to the peer's interface name. */ -const char *p_ifname(peer *p) { return (tun_ifname(&p->t)); } +const char *p_ifname(peer *p) { return (p->t->ops->ifname(p->t)); } /* --- @p_addr@ --- * * @@ -235,26 +263,41 @@ const addr *p_addr(peer *p) { return (&p->peer); } /* --- @p_init@ --- * * - * Arguments: @unsigned port@ = port number to listen to + * Arguments: @struct in_addr addr@ = address to bind to + * @unsigned port@ = port number to listen to * * Returns: --- * * Use: Initializes the peer system; creates the socket. */ -void p_init(unsigned port) +void p_init(struct in_addr addr, unsigned port) { int fd; struct sockaddr_in sin; + int len = PKBUFSZ; + + /* --- Note on socket buffer sizes --- * + * + * For some bizarre reason, Linux 2.2 (at least) doubles the socket buffer + * sizes I pass to @setsockopt@. I'm not putting special-case code here + * for Linux: BSD (at least TCPv2) does what I tell it rather than second- + * guessing me. + */ if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); BURN(sin); sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_addr = addr; sin.sin_port = htons(port); if (bind(fd, (struct sockaddr *)&sin, sizeof(sin))) die(EXIT_FAILURE, "bind failed: %s", strerror(errno)); + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) || + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len))) { + die(EXIT_FAILURE, "failed to set socket buffer sizes: %s", + strerror(errno)); + } fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); sel_initfile(&sel, &sock, fd, SEL_READ, p_read, 0); sel_addfile(&sock); @@ -282,6 +325,7 @@ unsigned p_port(void) /* --- @p_create@ --- * * * Arguments: @const char *name@ = name for this peer + * @const tunnel_ops *tops@ = tunnel to use * @struct sockaddr *sa@ = socket address of peer * @size_t sz@ = size of socket address * @@ -291,23 +335,40 @@ unsigned p_port(void) * by this point. */ -peer *p_create(const char *name, struct sockaddr *sa, size_t sz) +peer *p_create(const char *name, const tunnel_ops *tops, + struct sockaddr *sa, size_t sz) { peer *p = CREATE(peer); + T( trace(T_PEER, "peer: creating new peer `%s'", name); ) p->name = xstrdup(name); p->ks = 0; p->prev = 0; memcpy(&p->peer.sa, sa, sz); p->sasz = sz; + memset(&p->st, 0, sizeof(stats)); + p->st.t_start = time(0); if (kx_init(&p->kx, p, &p->ks)) goto tidy_0; - if (tun_create(&p->t, p)) + if ((p->t = tops->create(p)) == 0) goto tidy_1; p->next = peers; if (peers) peers->prev = p; peers = p; + switch (p->peer.sa.sa_family) { + case AF_INET: + a_notify("ADD %s %s INET %s %u", + name, + p->t->ops->ifname(p->t), + inet_ntoa(p->peer.sin.sin_addr), + (unsigned)ntohs(p->peer.sin.sin_port)); + break; + default: + a_notify("ADD %s %s UNKNOWN", name, p->t->ops->ifname(p->t)); + break; + } + a_notify("KXSTART %s", name); /* Couldn't tell anyone before */ return (p); tidy_1: @@ -358,9 +419,10 @@ peer *p_find(const char *name) void p_destroy(peer *p) { T( trace(T_PEER, "peer: destroying peer `%s'", p->name); ) - ks_free(&p->ks); + a_notify("KILL %s", p->name); + ksl_free(&p->ks); kx_free(&p->kx); - tun_destroy(&p->t); + p->t->ops->destroy(p->t); xfree(p->name); if (p->next) p->next->prev = p->prev;