static void handler_udp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p, struct curve25519_struct *c, char *buff, size_t len) { char *cbuff; ssize_t rlen, clen; struct ct_proto *hdr; struct sockaddr_storage naddr; socklen_t nlen = sizeof(naddr); if (!buff || !len) return; memset(&naddr, 0, sizeof(naddr)); while ((rlen = recvfrom(sfd, buff, len, 0, (struct sockaddr *) &naddr, &nlen)) > 0) { 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) goto close; clen = curve25519_decode(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; if (write(dfd, cbuff, clen)) { ; } } return; close: closed_by_server = 1; }
static void handler_tcp_net_to_tun(int sfd, int dfd, struct curve25519_proto *p, struct curve25519_struct *c, char *buff, size_t len) { char *cbuff; ssize_t rlen, clen; struct ct_proto *hdr; if (!buff || !len) return; while ((rlen = handler_tcp_read(sfd, buff, len)) > 0) { 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) goto close; clen = curve25519_decode(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; if (write(dfd, cbuff, clen)); } return; close: closed_by_server = 1; }
static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws, char *buff, size_t len) { int keep = 1, count = 0; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; if (!buff || !len) return 0; while ((rlen = handler_tcp_read(fd, buff, len)) > 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_socket(fd); trie_addr_remove(fd); handler_tcp_notify_close(fd); rlen = write(ws->parent.efd, &fd, sizeof(fd)); keep = 0; 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_socket(ws->c, buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), fd, auth_log); if (unlikely(err)) goto close; continue; } err = get_user_by_socket(fd, &p); if (unlikely(err || !p)) continue; 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)) continue; cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; err = trie_addr_maybe_update(cbuff, clen, ws->parent.ipv4, fd, NULL, 0); if (unlikely(err)) continue; err = write(ws->parent.tunfd, cbuff, clen); count++; if (count == 10) { write_exact(ws->efd[1], &fd, sizeof(fd), 1); /* Read later next data and let others process */ return keep; } } 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; }
int try_register_user_by_sockaddr(struct curve25519_struct *c, char *src, size_t slen, struct sockaddr_storage *sa, size_t sa_len, int log) { int ret = -1; char *cbuff = NULL; struct user_store *elem; ssize_t clen; size_t real_len = 132; enum is_user_enum err; unsigned char auth[crypto_auth_hmacsha512256_BYTES]; struct taia arrival_taia; /* assert(132 == clen + sizeof(auth)); */ /* * Check hmac first, if malicious, drop immediately before we * investigate more efforts. */ if (slen < real_len) return -1; taia_now(&arrival_taia); memcpy(auth, src, sizeof(auth)); src += sizeof(auth); real_len -= sizeof(auth); if (crypto_auth_hmacsha512256_verify(auth, (unsigned char *) src, real_len, token)) { syslog(LOG_ERR, "Got bad packet hmac! Dropping!\n"); return -1; } else { if (log) syslog(LOG_INFO, "Got good packet hmac!\n"); } rwlock_rd_lock(&store_lock); elem = store; while (elem) { clen = curve25519_decode(c, &elem->proto_inf, (unsigned char *) src, real_len, (unsigned char **) &cbuff, &arrival_taia); if (clen <= 0) { elem = elem->next; continue; } cbuff += crypto_box_zerobytes; clen -= crypto_box_zerobytes; if (log) syslog(LOG_INFO, "Packet decoded successfully!\n"); err = username_msg_is_user(cbuff, clen, elem->username, strlen(elem->username) + 1); if (err == USERNAMES_OK) { if (log) syslog(LOG_INFO, "Found user %s! Registering ...\n", elem->username); ret = register_user_by_sockaddr(sa, sa_len, &elem->proto_inf); break; } elem = elem->next; } rwlock_unlock(&store_lock); if (ret == -1) syslog(LOG_ERR, "User not found! Dropping connection!\n"); return ret; }
static int handler_tcp_net_to_tun(int fd, const struct worker_struct *ws, char *buff, size_t len) { int keep = 1, count = 0; char *cbuff; ssize_t rlen, err, clen; struct ct_proto *hdr; struct curve25519_proto *p; if (!buff || !len) { errno = EINVAL; return 0; } errno = 0; while ((rlen = handler_tcp_read(fd, buff, len)) > 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_socket(fd); trie_addr_remove(fd); handler_tcp_notify_close(fd); rlen = write(ws->parent.efd, &fd, sizeof(fd)); if (rlen != sizeof(fd)) syslog(LOG_ERR, "CPU%u: TCP event write error: %s\n", ws->cpu, strerror(errno)); keep = 0; 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_socket(ws->c, buff + sizeof(struct ct_proto), rlen - sizeof(struct ct_proto), fd, auth_log); if (unlikely(err)) goto close; continue; } err = get_user_by_socket(fd, &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: TCP 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, NULL, 0); if (unlikely(err)) { syslog(LOG_INFO, "CPU%u: Malicious packet dropped " "from id %d\n", ws->cpu, fd); continue; } err = write(ws->parent.tunfd, cbuff, clen); if (unlikely(err < 0)) syslog(LOG_ERR, "CPU%u: TCP net write error: %s\n", ws->cpu, strerror(errno)); count++; if (count == 10) { err = write_exact(ws->efd[1], &fd, sizeof(fd), 1); if (unlikely(err != sizeof(fd))) syslog(LOG_ERR, "CPU%u: TCP net put fd back in " "pipe error: %s\n", ws->cpu, strerror(errno)); return keep; } errno = 0; } if (unlikely(rlen < 0 && errno != EAGAIN && errno != EBADF)) syslog(LOG_ERR, "CPU%u: TCP net 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) { 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; }