static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws, char *buff, size_t len) { int dfd, keep = 1; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; struct sockaddr_storage naddr; socklen_t nlen; size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes; if (!buff || len <= off) return 0; memset(buff, 0, len); while ((rlen = read(fd, buff + off, len - off)) > 0) { dfd = -1; nlen = 0; p = NULL; memset(&naddr, 0, sizeof(naddr)); hdr = (struct ct_proto *) buff; memset(hdr, 0, sizeof(*hdr)); hdr->flags = 0; trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr, (size_t *) &nlen); if (unlikely(dfd < 0 || nlen == 0)) { memset(buff, 0, len); continue; } err = get_user_by_sockaddr(&naddr, nlen, &p); if (unlikely(err || !p)) { memset(buff, 0, len); continue; } clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off - crypto_box_zerobytes), (rlen + crypto_box_zerobytes), (unsigned char **) &cbuff); if (unlikely(clen <= 0)) { memset(buff, 0, len); continue; } hdr->payload = htons((uint16_t) clen); set_udp_cork(dfd); sendto(dfd, hdr, sizeof(struct ct_proto), 0, (struct sockaddr *) &naddr, nlen); sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr, nlen); set_udp_uncork(dfd); memset(buff, 0, len); } return keep; }
static int handler_udp_tun_to_net(int fd, const struct worker_struct *ws, char *buff, size_t len) { int dfd, state, keep = 1; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; struct sockaddr_storage naddr; socklen_t nlen; size_t off = sizeof(struct ct_proto) + crypto_box_zerobytes; if (!buff || len <= off) { errno = EINVAL; return 0; } errno = 0; memset(buff, 0, len); while ((rlen = read(fd, buff + off, len - off)) > 0) { dfd = -1; nlen = 0; p = NULL; memset(&naddr, 0, sizeof(naddr)); hdr = (struct ct_proto *) buff; memset(hdr, 0, sizeof(*hdr)); hdr->flags = 0; trie_addr_lookup(buff + off, rlen, ws->parent.ipv4, &dfd, &naddr, (size_t *) &nlen); if (unlikely(dfd < 0 || nlen == 0)) { syslog(LOG_INFO, "CPU%u: UDP tunnel lookup failed: " "unknown destination\n", ws->cpu); memset(buff, 0, len); continue; } err = get_user_by_sockaddr(&naddr, nlen, &p); if (unlikely(err || !p)) { syslog(LOG_ERR, "CPU%u: User protocol not in cache! " "Dropping connection!\n", ws->cpu); memset(buff, 0, len); continue; } clen = curve25519_encode(ws->c, p, (unsigned char *) (buff + off - crypto_box_zerobytes), (rlen + crypto_box_zerobytes), (unsigned char **) &cbuff); if (unlikely(clen <= 0)) { syslog(LOG_ERR, "CPU%u: UDP tunnel encrypt error: %zd\n", ws->cpu, clen); memset(buff, 0, len); continue; } hdr->payload = htons((uint16_t) clen); state = 1; setsockopt(dfd, IPPROTO_UDP, UDP_CORK, &state, sizeof(state)); err = sendto(dfd, hdr, sizeof(struct ct_proto), 0, (struct sockaddr *) &naddr, nlen); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: UDP tunnel write error: %s\n", ws->cpu, strerror(errno)); err = sendto(dfd, cbuff, clen, 0, (struct sockaddr *) &naddr, nlen); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: UDP tunnel write error: %s\n", ws->cpu, strerror(errno)); state = 0; setsockopt(dfd, IPPROTO_UDP, UDP_CORK, &state, sizeof(state)); errno = 0; memset(buff, 0, len); } if (unlikely(rlen < 0 && errno != EAGAIN)) syslog(LOG_ERR, "CPU%u: UDP tunnel read error: %s\n", ws->cpu, strerror(errno)); return keep; }
static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws, char *buff, size_t len) { int keep = 1; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; struct sockaddr_storage naddr; socklen_t nlen = sizeof(naddr); if (!buff || !len) return 0; memset(&naddr, 0, sizeof(naddr)); while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr, &nlen)) > 0) { p = NULL; hdr = (struct ct_proto *) buff; if (unlikely(rlen < sizeof(struct ct_proto))) goto close; if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload))) goto close; if (unlikely(ntohs(hdr->payload) == 0)) goto close; if (hdr->flags & PROTO_FLAG_EXIT) { close: remove_user_by_sockaddr(&naddr, nlen); trie_addr_remove_addr(&naddr, nlen); handler_udp_notify_close(fd, &naddr); return keep; } if (hdr->flags & PROTO_FLAG_INIT) { syslog_maybe(auth_log, LOG_INFO, "Got initial userhash " "from remote end!\n"); if (unlikely(rlen - sizeof(*hdr) < sizeof(struct username_struct))) goto close; err = try_register_user_by_sockaddr(ws->c, buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), &naddr, nlen, auth_log); if (unlikely(err)) goto close; goto next; } err = get_user_by_sockaddr(&naddr, nlen, &p); if (unlikely(err || !p)) goto close; clen = curve25519_decode(ws->c, p, (unsigned char *) buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), (unsigned char **) &cbuff, NULL); if (unlikely(clen <= 0)) goto close; cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4, fd, &naddr, nlen); if (unlikely(err)) goto next; err = write(ws->parent.tunfd, cbuff, clen); next: nlen = sizeof(naddr); memset(&naddr, 0, sizeof(naddr)); } return keep; }
static int handler_udp_net_to_tun(int fd, const struct worker_struct *ws, char *buff, size_t len) { int keep = 1; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; struct sockaddr_storage naddr; socklen_t nlen = sizeof(naddr); if (!buff || !len) { errno = EINVAL; return 0; } memset(&naddr, 0, sizeof(naddr)); errno = 0; while ((rlen = recvfrom(fd, buff, len, 0, (struct sockaddr *) &naddr, &nlen)) > 0) { p = NULL; hdr = (struct ct_proto *) buff; if (unlikely(rlen < sizeof(struct ct_proto))) goto close; if (unlikely(rlen - sizeof(*hdr) != ntohs(hdr->payload))) goto close; if (unlikely(ntohs(hdr->payload) == 0)) goto close; if (hdr->flags & PROTO_FLAG_EXIT) { close: remove_user_by_sockaddr(&naddr, nlen); trie_addr_remove_addr(&naddr, nlen); handler_udp_notify_close(fd, &naddr); return keep; } if (hdr->flags & PROTO_FLAG_INIT) { if (auth_log) syslog(LOG_INFO, "Got initial userhash from remote end!\n"); if (unlikely(rlen - sizeof(*hdr) < sizeof(struct username_struct))) goto close; err = try_register_user_by_sockaddr(ws->c, buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), &naddr, nlen, auth_log); if (unlikely(err)) goto close; goto next; } err = get_user_by_sockaddr(&naddr, nlen, &p); if (unlikely(err || !p)) { syslog(LOG_ERR, "CPU%u: User protocol not in cache! " "Dropping connection!\n", ws->cpu); goto close; } clen = curve25519_decode(ws->c, p, (unsigned char *) buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), (unsigned char **) &cbuff, NULL); if (unlikely(clen <= 0)) { syslog(LOG_ERR, "CPU%u: UDP net decryption error: %zd\n", ws->cpu, clen); goto close; } cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4, fd, &naddr, nlen); if (unlikely(err)) { syslog(LOG_INFO, "CPU%u: Malicious packet dropped " "from id %d\n", ws->cpu, fd); goto next; } err = write(ws->parent.tunfd, cbuff, clen); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: UDP net write error: %s\n", ws->cpu, strerror(errno)); next: nlen = sizeof(naddr); memset(&naddr, 0, sizeof(naddr)); errno = 0; } if (unlikely(rlen < 0 && errno != EAGAIN)) syslog(LOG_ERR, "CPU%u: UDP net read error: %s\n", ws->cpu, strerror(errno)); return keep; }