static void client_recv_cb(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { struct server_context *server = container_of(handle, struct server_context, udp); if (nread > 0) { char key[KEY_BYTES + 1] = {0}; crypto_generickey((uint8_t *)key, sizeof(key) -1, (uint8_t*)addr, sizeof(*addr), NULL, 0); struct client_context *client = NULL; uv_mutex_lock(&mutex); cache_lookup(cache, key, (void *)&client); uv_mutex_unlock(&mutex); if (client == NULL) { client = new_client(); client->addr = *addr; client->local_handle = handle; memcpy(client->key, key, sizeof(key)); uv_timer_init(handle->loop, client->timer); uv_udp_init(handle->loop, &client->server_handle); client->server_handle.data = client; uv_udp_recv_start(&client->server_handle, server_alloc_cb, server_recv_cb); uv_mutex_lock(&mutex); cache_insert(cache, client->key, (void *)client); uv_mutex_unlock(&mutex); } int clen = nread + PRIMITIVE_BYTES + addrlen; int mlen = nread + addrlen; uint8_t *c = (uint8_t *)buf->base - PRIMITIVE_BYTES - addrlen; uint8_t *m = (uint8_t *)buf->base - addrlen; if (server->dest_addr->sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)server->dest_addr; m[0] = 1; memcpy(m + 1, &addr->sin_addr, 4); memcpy(m + 1 + 4, &addr->sin_port, 2); } else { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)server->dest_addr; m[0] = 4; memcpy(m + 1, &addr->sin6_addr, 16); memcpy(m + 1 + 16, &addr->sin6_port, 2); } int rc = crypto_encrypt(c, m, mlen); if (!rc) { reset_timer(client); forward_to_server(server->server_addr, client, c, clen); } } else { goto error; } return; error: free(buf->base - addrlen - PRIMITIVE_BYTES); }
/* * * SOCKS5 UDP Request * +----+------+------+----------+----------+----------+ * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | * +----+------+------+----------+----------+----------+ * | 2 | 1 | 1 | Variable | 2 | Variable | * +----+------+------+----------+----------+----------+ * */ static void client_recv_cb(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { struct server_context *server = container_of(handle, struct server_context, udp); if (nread > 0) { uint8_t frag = buf->base[2]; if (frag) { logger_log(LOG_ERR, "don't support udp dgram frag"); goto err; } char key[KEY_BYTES + 1] = {0}; crypto_generickey((uint8_t *)key, sizeof(key) -1, (uint8_t*)addr, sizeof(*addr), NULL, 0); struct client_context *client = NULL; uv_mutex_lock(&mutex); cache_lookup(cache, key, (void *)&client); uv_mutex_unlock(&mutex); if (client == NULL) { client = new_client(); client->addr = *addr; client->local_handle = handle; memcpy(client->key, key, sizeof(key)); uv_timer_init(handle->loop, client->timer); uv_udp_init(handle->loop, &client->server_handle); client->server_handle.data = client; uv_udp_recv_start(&client->server_handle, server_alloc_cb, server_recv_cb); uv_mutex_lock(&mutex); cache_insert(cache, client->key, (void *)client); uv_mutex_unlock(&mutex); } int clen = nread - 3 + PRIMITIVE_BYTES; uint8_t *c = (uint8_t *)buf->base - PRIMITIVE_BYTES; int rc = crypto_encrypt(c, (uint8_t*)buf->base + 3, nread - 3); if (!rc) { reset_timer(client); forward_to_server(server->server_addr, client, c, clen); } } else { goto err; } return; err: free(buf->base - PRIMITIVE_BYTES); }
static void poll_cb(uv_poll_t *watcher, int status, int events) { char buffer[1024] = {0}; char control_buffer[64] = {0}; struct iovec iov[1]; struct msghdr msg; struct sockaddr client_addr; struct server_context *server = container_of(watcher, struct server_context, watcher); if (status >= 0) { msg.msg_name = &client_addr; msg.msg_namelen = sizeof(client_addr); msg.msg_control = control_buffer; msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buffer; iov[0].iov_len = sizeof(buffer); msg.msg_iov = iov; msg.msg_iovlen = 1; int msglen = recvmsg(watcher->io_watcher.fd, &msg, 0); if (msglen <= 0) { logger_stderr("receive from client error: %s", strerror(errno)); } struct sockaddr dest_addr; if (getdestaddr(&msg, &dest_addr)) { logger_stderr("can not get destination address"); } int addrlen = dest_addr.sa_family == AF_INET ? IPV4_HEADER_LEN : IPV6_HEADER_LEN; int mlen = addrlen + msglen; int clen = PRIMITIVE_BYTES + mlen; uint8_t *c = malloc(clen); uint8_t *m = c + PRIMITIVE_BYTES; /* * * xsocks UDP Request * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * */ if (dest_addr.sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)&dest_addr; m[0] = ATYP_IPV4; memcpy(m + 1, &addr->sin_addr, 4); memcpy(m + 1 + 4, &addr->sin_port, 2); } else { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&dest_addr; m[0] = ATYP_IPV6; memcpy(m + 1, &addr->sin6_addr, 16); memcpy(m + 1 + 16, &addr->sin6_port, 2); } memcpy(m + addrlen, buffer, msglen); int rc = crypto_encrypt(c, m, mlen); if (!rc) { char key[KEY_BYTES + 1] = {0}; crypto_generickey((uint8_t *)key, sizeof(key) -1, (uint8_t *)&client_addr, sizeof(client_addr), NULL, 0); struct client_context *client = NULL; uv_mutex_lock(&mutex); cache_lookup(cache, key, (void *)&client); uv_mutex_unlock(&mutex); if (client == NULL) { client = new_client(); client->addr = client_addr; memcpy(client->key, key, sizeof(key)); uv_timer_init(watcher->loop, client->timer); uv_udp_init(watcher->loop, &client->server_handle); client->server_handle.data = client; uv_udp_recv_start(&client->server_handle, server_alloc_cb, server_recv_cb); uv_mutex_lock(&mutex); cache_insert(cache, client->key, (void *)client); uv_mutex_unlock(&mutex); } reset_timer(client); forward_to_server(server->server_addr, client, c, clen); } } }