static void client_send_cb(uv_write_t *req, int status) { struct client_context *client = req->data; struct remote_context *remote = client->remote; if (status == 0) { if (client->stage == XSTAGE_REQUEST) { receive_from_client(client); } else if (client->stage == XSTAGE_FORWARD) { receive_from_remote(remote); } else if (client->stage == XSTAGE_TERMINATE) { close_client(client); close_remote(remote); } } else { char addrbuf[INET6_ADDRSTRLEN + 1] = {0}; int port = ip_name(&client->addr, addrbuf, sizeof addrbuf); if (client->stage == XSTAGE_FORWARD) { logger_log(LOG_ERR, "%s:%d <- %s failed: %s", addrbuf, port, client->target_addr, uv_strerror(status)); } else { logger_log(LOG_ERR, "forward to %s:%d failed: %s", addrbuf, port, uv_strerror(status)); } } free(req); }
static void client_recv_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { struct client_context *client = stream->data; struct remote_context *remote = client->remote; int clen; if (nread > 0) { reset_timer(remote); uv_read_stop(&client->handle.stream); switch (client->stage) { case XSTAGE_HANDSHAKE: if (verify_methods(buf->base, nread)) { handshake(client); } else { logger_log(LOG_ERR, "invalid method packet"); close_client(client); close_remote(remote); } break; case XSTAGE_REQUEST: if (verify_request(buf->base, nread)) { request_start(client, buf->base); } else { logger_log(LOG_ERR, "invalid request packet"); close_client(client); close_remote(remote); } break; case XSTAGE_FORWARD: clen = nread + PRIMITIVE_BYTES; uint8_t *c = client->buf + HEADER_BYTES; int rc = crypto_encrypt(c, (uint8_t*)buf->base, nread); if (rc) { logger_log(LOG_ERR, "encrypt failed"); close_client(client); close_remote(remote); } forward_to_remote(remote, c, clen); break; default: break; } } else if (nread < 0) { if (nread != UV_EOF) { char addrbuf[INET6_ADDRSTRLEN + 1] = {0}; uint16_t port = ip_name(&client->addr, addrbuf, sizeof addrbuf); logger_log(LOG_ERR, "receive from %s:%d failed: %s", addrbuf, port, uv_strerror(nread)); } close_client(client); close_remote(remote); } }
static void remote_timer_expire(uv_timer_t *handle) { struct remote_context *remote = handle->data; struct client_context *client = remote->client; if (verbose) { struct sockaddr peername; int namelen = sizeof peername; uv_tcp_getpeername(&client->handle.tcp, &peername, &namelen); char addr1[INET6_ADDRSTRLEN + 1]; char addr2[INET6_ADDRSTRLEN + 1]; int p1 = ip_name(&peername, addr1, sizeof addr2); int p2 = ip_name(&client->target_addr, addr2, sizeof(addr2)); logger_log(LOG_WARNING, "%s:%d <-> %s:%d connection timeout", addr1, p1, addr2, p2); } close_client(client); close_remote(remote); }
void cache_log(uint8_t atyp, const struct sockaddr *src_addr, const struct sockaddr *dst_addr, const char *host, uint16_t port, int hit) { char src[INET6_ADDRSTRLEN + 1] = {0}; char dst[INET6_ADDRSTRLEN + 1] = {0}; uint16_t src_port = 0, dst_port = 0; char *hint = hit ? "hit" : "miss"; src_port = ip_name(src_addr, src, sizeof src); if (atyp == ATYP_HOST) { logger_log(hit ? LOG_INFO : LOG_WARNING, "[udp] cache %s: %s:%d -> %s:%d", hint, src, src_port, host, ntohs(port)); } else { dst_port = ip_name(dst_addr, dst, sizeof dst); logger_log(hit ? LOG_INFO : LOG_WARNING, "[udp] cache %s: %s:%d -> %s:%d", hint, src, src_port, dst, dst_port); } }
static void forward_to_server(struct sockaddr *server_addr, struct client_context *client, uint8_t *data, ssize_t datalen) { if (verbose) { char src[INET6_ADDRSTRLEN + 1] = {0}; char dst[INET6_ADDRSTRLEN + 1] = {0}; uint16_t dst_port = 0, src_port = 0; src_port = ip_name(&client->addr, src, sizeof src); dst_port = ip_name(&client->dest_addr, dst, sizeof dst); logger_log(LOG_INFO, "%s:%d -> %s:%d", src, src_port, dst, dst_port); } uv_udp_send_t *write_req = malloc(sizeof(*write_req) + sizeof(uv_buf_t)); uv_buf_t *buf = (uv_buf_t *)(write_req + 1); buf->base = (char *)data; buf->len = datalen; write_req->data = client;; uv_udp_send(write_req, &client->server_handle, buf, 1, server_addr, server_send_cb); }
static void handle_invalid_packet(struct client_context *client) { int port = 0; char remote[INET_ADDRSTRLEN + 1]; port = ip_name(&client->addr, remote, sizeof(remote)); logger_log(LOG_ERR, "Invalid tcp packet from %s:%d", remote, port); packet_reset(&client->packet); close_client(client); }
static void remote_timer_expire(uv_timer_t *handle) { struct remote_context *remote = handle->data; struct client_context *client = remote->client; if (verbose) { char addrbuf[INET6_ADDRSTRLEN + 1] = {0}; uint16_t port = ip_name(&client->addr, addrbuf, sizeof addrbuf); logger_log(LOG_WARNING, "%s:%d <-> %s connection timeout", addrbuf, port, client->target_addr); } close_client(remote->client); close_remote(remote); }
static void inet_recv_cb(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { struct tundev_context *ctx = container_of(handle, struct tundev_context, inet_udp); if (nread > 0) { uint8_t *m = (uint8_t *)buf->base; ssize_t mlen = nread - PRIMITIVE_BYTES; int rc = crypto_decrypt(m, (uint8_t *)buf->base, nread); if (rc) { int port = 0; char remote[INET_ADDRSTRLEN + 1]; port = ip_name(addr, remote, sizeof(remote)); logger_log(LOG_ERR, "Invalid udp packet from %s:%d", remote, port); return; } if (mode == xTUN_SERVER) { struct iphdr *iphdr = (struct iphdr *) m; in_addr_t client_network = iphdr->saddr & htonl(ctx->tun->netmask); if (client_network != ctx->tun->network) { char *a = inet_ntoa(*(struct in_addr *) &iphdr->saddr); logger_log(LOG_ERR, "Invalid client: %s", a); return; } // TODO: Compare source address uv_rwlock_rdlock(&rwlock); struct peer *peer = lookup_peer(iphdr->saddr, peers); uv_rwlock_rdunlock(&rwlock); if (peer == NULL) { char saddr[24] = {0}, daddr[24] = {0}; parse_addr(iphdr, saddr, daddr); logger_log(LOG_WARNING, "[UDP] Cache miss: %s -> %s", saddr, daddr); uv_rwlock_wrlock(&rwlock); peer = save_peer(iphdr->saddr, (struct sockaddr *) addr, peers); uv_rwlock_wrunlock(&rwlock); } else { if (memcmp(&peer->remote_addr, addr, sizeof(*addr))) { peer->remote_addr = *addr; } } peer->protocol = xTUN_UDP; } network_to_tun(ctx->tunfd, m, mlen); } }
void connect_to_remote(struct remote_context *remote) { remote->stage = XSTAGE_CONNECT; remote->connect_req.data = remote; int rc = uv_tcp_connect(&remote->connect_req, &remote->handle.tcp, &server_addr, remote_connect_cb); if (rc) { char addrbuf[INET6_ADDRSTRLEN + 1]; ip_name(&server_addr, addrbuf, sizeof(addrbuf)); logger_log(LOG_ERR, "connect to %s error: %s", addrbuf, uv_strerror(rc)); close_client(remote->client); close_remote(remote); } }
static void remote_recv_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { struct remote_context *remote; struct client_context *client; remote = stream->data; client = remote->client; if (nread > 0) { reset_timer(remote); struct packet *packet = &remote->packet; int rc = packet_filter(packet, buf->base, nread); if (rc == PACKET_COMPLETED) { int clen = packet->size; int mlen = packet->size - PRIMITIVE_BYTES; uint8_t *c = packet->buf, *m = packet->buf; assert(mlen > 0 && mlen <= MAX_PACKET_SIZE - PRIMITIVE_BYTES); int err = crypto_decrypt(m, c, clen); if (err) { goto error; } uv_read_stop(&remote->handle.stream); forward_to_client(client, m, mlen); } else if (rc == PACKET_INVALID) { goto error; } } else if (nread < 0){ if (nread != UV_EOF && verbose) { char addrbuf[INET6_ADDRSTRLEN + 1]; int port = ip_name(&client->target_addr, addrbuf, sizeof(addrbuf)); logger_log(LOG_ERR, "receive from %s:%d failed: %s", addrbuf, port, uv_strerror(nread)); } close_client(client); close_remote(remote); } return; error: logger_log(LOG_ERR, "invalid tcp packet"); if (verbose) { dump_hex(buf->base, nread, "invalid tcp Packet"); } close_client(client); close_remote(remote); }
static void remote_send_cb(uv_write_t *req, int status) { struct remote_context *remote = (struct remote_context *)req->data; struct client_context *client = remote->client; if (status == 0) { receive_from_client(client); } else { char addrbuf[INET6_ADDRSTRLEN + 1] = {0}; uint16_t port = ip_name(&client->addr, addrbuf, sizeof addrbuf); logger_log(LOG_ERR, "%s:%d -> failed: %s", addrbuf, port, client->target_addr, uv_strerror(status)); } free(req); }
static void remote_timer_expire(uv_timer_t *handle) { struct remote_context *remote = handle->data; struct client_context *client = remote->client; if (verbose) { char addrbuf[INET6_ADDRSTRLEN + 1] = {0}; uint16_t port = ip_name(&client->addr, addrbuf, sizeof addrbuf); if (client->stage < XSTAGE_FORWARD) { logger_log(LOG_WARNING, "%s:%d connection timeout", addrbuf, port); } else { logger_log(LOG_WARNING, "%s:%d <-> %s connection timeout", addrbuf, port, client->target_addr); } } assert(client->stage != XSTAGE_TERMINATE); request_ack(client, S5_REP_TTL_EXPIRED); }
static void remote_connect_cb(uv_connect_t *req, int status) { struct remote_context *remote = (struct remote_context *)req->data; struct client_context *client = remote->client; if (status == 0) { reset_timer(remote); client->stage = XSTAGE_FORWARD; remote->stage = XSTAGE_FORWARD; request_to_server(remote); receive_from_remote(remote); } else { if (status != UV_ECANCELED) { char addrbuf[INET6_ADDRSTRLEN + 1]; ip_name(&server_addr, addrbuf, sizeof(addrbuf)); logger_log(LOG_ERR, "connect to %s failed: %s", addrbuf, uv_strerror(status)); close_client(client); close_remote(remote); } } }