X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/blobdiff_plain/47828bd9813b146e8569355b3083847299dd8729..b50ba1bda8722c66c40005f43707ebc63515732b:/server/peer.c diff --git a/server/peer.c b/server/peer.c index 94629213..f723cccb 100644 --- a/server/peer.c +++ b/server/peer.c @@ -29,7 +29,7 @@ /*----- Global state ------------------------------------------------------*/ -sel_file udpsock[NADDRFAM]; +udpsocket udpsock[NADDRFAM]; /*----- Static variables --------------------------------------------------*/ @@ -366,7 +366,7 @@ static void p_read(int fd, unsigned mode, void *v) }) buf_init(&b, buf_i, n); buf_getbyte(&b); - if (c_check(&b) || BLEFT(&b)) { + if (c_check(0, 0, &b) || BLEFT(&b)) { a_warn("PEER", "-", "invalid-greeting", A_END); return; } @@ -427,9 +427,8 @@ static void p_read(int fd, unsigned mode, void *v) } break; case MSG_KEYEXCH: - if (!p) goto unexp; - p_rxupdstats(p, n); - kx_message(&p->kx, ch & MSG_TYPEMASK, &b); + if (p) p_rxupdstats(p, n); + if (kx_message(p ? &p->kx : 0, &a, ch & MSG_TYPEMASK, &b)) goto unexp; break; case MSG_MISC: switch (ch & MSG_TYPEMASK) { @@ -469,6 +468,16 @@ static void p_read(int fd, unsigned mode, void *v) 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: @@ -503,6 +512,35 @@ buf *p_txstart(peer *p, unsigned msg) return (&p->b); } +/* --- @p_txaddr@ --- * + * + * Arguments: @const addr *a@ = recipient address + * @const void *p@ = pointer to packet to send + * @size_t sz@ = length of packet + * + * Returns: Zero if successful, nonzero on error. + * + * Use: Sends a packet to an address which (possibly) isn't a current + * peer. + */ + +int p_txaddr(const addr *a, const void *p, size_t sz) +{ + socklen_t sasz = addrsz(a); + int i; + + if ((i = afix(a->sa.sa_family)) < 0) { + a_warn("PEER", "?ADDR", a, "disabled-address-family", A_END); + return (-1); + } + IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", p, sz); ) + if (sendto(udpsock[i].sf.fd, p, sz, 0, &a->sa, sasz) < 0) { + a_warn("PEER", "?ADDR", a, "socket-write-error", "?ERRNO", A_END); + return (-1); + } + return (0); +} + /* --- @p_txend@ --- * * * Arguments: @peer *p@ = pointer to peer block @@ -524,7 +562,7 @@ static int p_dotxend(peer *p) } IF_TRACING(T_PEER, trace_block(T_PACKET, "peer: sending packet", BBASE(&p->b), BLEN(&p->b)); ) - if (sendto(udpsock[p->afix].fd, BBASE(&p->b), BLEN(&p->b), + if (sendto(udpsock[p->afix].sf.fd, BBASE(&p->b), BLEN(&p->b), 0, &p->spec.sa.sa, sasz) < 0) { a_warn("PEER", "?PEER", p, "socket-write-error", "?ERRNO", A_END); return (0); @@ -778,7 +816,7 @@ void p_setifname(peer *p, const char *name) const addr *p_addr(peer *p) { return (&p->spec.sa); } -/* --- @p_init@ --- * +/* --- @p_bind@ --- * * * Arguments: @struct addrinfo *ailist@ = addresses to bind to * @@ -787,7 +825,7 @@ const addr *p_addr(peer *p) { return (&p->spec.sa); } * Use: Initializes the peer system; creates the socket. */ -void p_init(struct addrinfo *ailist) +void p_bind(struct addrinfo *ailist) { int fd; int len = PKBUFSZ; @@ -798,11 +836,11 @@ void p_init(struct addrinfo *ailist) addr a; socklen_t sz; - for (i = 0; i < NADDRFAM; i++) udpsock[i].fd = -1; + for (i = 0; i < NADDRFAM; i++) udpsock[i].sf.fd = -1; for (ai = ailist; ai; ai = ai->ai_next) { if ((i = afix(ai->ai_family)) < 0) continue; - if (udpsock[i].fd != -1) continue; + if (udpsock[i].sf.fd != -1) continue; /* --- Note on socket buffer sizes --- * * @@ -812,56 +850,89 @@ void p_init(struct addrinfo *ailist) * than second-guessing me. */ - if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0) - die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); + if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0) { + a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, + "create-failed", "?ERRNO", A_END); + exit(EXIT_FAILURE); + } if (i == AFIX_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) { - die(EXIT_FAILURE, "failed to set IPv6-only state: %s", - strerror(errno)); + a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, + "set-v6only-failed", "?ERRNO", A_END); + exit(EXIT_FAILURE); } assert(ai->ai_addrlen <= sizeof(a)); memcpy(&a, ai->ai_addr, ai->ai_addrlen); if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport); - if (bind(fd, &a.sa, addrsz(&a))) - die(EXIT_FAILURE, "bind failed: %s", strerror(errno)); + if (bind(fd, &a.sa, addrsz(&a))) { + a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, + "bind-failed", "?ERRNO", A_END); + exit(EXIT_FAILURE); + } 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)); + a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, + "set-buffers-failed", "?ERRNO", A_END); + exit(EXIT_FAILURE); } fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); - sel_initfile(&sel, &udpsock[i], fd, SEL_READ, p_read, 0); - sel_addfile(&udpsock[i]); - T( trace(T_PEER, "peer: created %s socket", aftab[i].name); ) - if (!port) { + if (port) + udpsock[i].port = port; + else { sz = sizeof(a); if (getsockname(fd, &a.sa, &sz)) { - die(EXIT_FAILURE, "failed to read local socket address: %s", - strerror(errno)); + a_warn("PEER", "-", "udp-socket", "%s", aftab[i].name, + "read-local-address-failed", "?ERRNO", A_END); + exit(EXIT_FAILURE); } - lastport = getport(&a); + udpsock[i].port = lastport = getport(&a); } + T( trace(T_PEER, "peer: created %s socket", aftab[i].name); ) + sel_initfile(&sel, &udpsock[i].sf, fd, SEL_READ, p_read, 0); + sel_addfile(&udpsock[i].sf); } - sym_create(&byname); - am_create(&byaddr); } -/* --- @p_port@ --- * +/* --- @p_unbind@ --- * * - * Arguments: @int i@ = address family index to retrieve + * Arguments: --- + * + * Returns: --- * - * Returns: Port number used for socket. + * Use: Unbinds the UDP sockets. There must not be any active peers, + * and none can be created until the sockets are rebound. */ -unsigned p_port(int i) +void p_unbind(void) { - addr a; - socklen_t sz = sizeof(addr); + int i; + +#ifndef NDEBUG + { peer_iter it; p_mkiter(&it); assert(!p_next(&it)); } +#endif - if (getsockname(udpsock[i].fd, &a.sa, &sz)) - die(EXIT_FAILURE, "couldn't read port number: %s", strerror(errno)); - return (getport(&a)); + for (i = 0; i < NADDRFAM; i++) { + if (udpsock[i].sf.fd == -1) continue; + sel_rmfile(&udpsock[i].sf); + close(udpsock[i].sf.fd); + udpsock[i].sf.fd = -1; + } +} + +/* --- @p_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Initializes the peer system. + */ + +void p_init(void) +{ + sym_create(&byname); + am_create(&byaddr); } /* --- @p_keepalive@ --- * @@ -931,6 +1002,7 @@ peer *p_create(peerspec *spec) p->spec.name = (/*unconst*/ char *)SYM_NAME(p->byname); if (spec->tag) p->spec.tag = xstrdup(spec->tag); if (spec->privtag) p->spec.privtag = xstrdup(spec->privtag); + if (spec->knock) p->spec.knock = xstrdup(spec->knock); p->ks = 0; p->pings = 0; p->ifname = 0; @@ -946,7 +1018,8 @@ peer *p_create(peerspec *spec) 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.f & PSF_KXMASK)) + iv_addreason(); + if (kx_setup(&p->kx, p, &p->ks, p->spec.f & PSF_KXMASK)) goto tidy_4; a_notify("ADD", "?PEER", p, @@ -964,6 +1037,7 @@ tidy_4: if (spec->t_ka) sel_rmtimer(&p->tka); xfree(p->ifname); p->t->ops->destroy(p->t); + iv_rmreason(); tidy_3: if (fd >= 0) close(fd); tidy_2: @@ -1057,17 +1131,28 @@ peer *p_find(const char *name) /* --- @p_destroy@ --- * * * Arguments: @peer *p@ = pointer to a peer + * @int bye@ = say goodbye to the peer? * * Returns: --- * * Use: Destroys a peer. */ -void p_destroy(peer *p) +void p_destroy(peer *p, int bye) { ping *pg, *ppg; + buf *b, bb; 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); @@ -1075,6 +1160,7 @@ void p_destroy(peer *p) if (p->ifname) xfree(p->ifname); if (p->spec.tag) xfree(p->spec.tag); if (p->spec.privtag) xfree(p->spec.privtag); + if (p->spec.knock) xfree(p->spec.knock); p->t->ops->destroy(p->t); if (p->spec.t_ka) sel_rmtimer(&p->tka); for (pg = p->pings; pg; pg = ppg) { @@ -1083,9 +1169,21 @@ void p_destroy(peer *p) } sym_remove(&byname, p->byname); am_remove(&byaddr, p->byaddr); + iv_rmreason(); DESTROY(p); } +/* --- @p_destroyall@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Destroys all of the peers, saying goodbye. + */ + +void p_destroyall(void) { FOREACH_PEER(p, { p_destroy(p, 1); }); } + /* --- @p_mkiter@ --- * * * Arguments: @peer_iter *i@ = pointer to an iterator