static void remote_recv_cb(EV_P_ ev_io *w, int revents) { ssize_t r; remote_ctx_t *remote_ctx = (remote_ctx_t *)w; server_ctx_t *server_ctx = remote_ctx->server_ctx; // server has been closed if (server_ctx == NULL) { LOGE("[udp] invalid server"); close_and_free_remote(EV_A_ remote_ctx); return; } if (verbose) { LOGI("[udp] remote receive a packet"); } struct sockaddr_storage src_addr; socklen_t src_addr_len = sizeof(struct sockaddr_storage); memset(&src_addr, 0, src_addr_len); buffer_t *buf = ss_malloc(sizeof(buffer_t)); balloc(buf, buf_size); // recv r = recvfrom(remote_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet ERROR("[udp] remote_recv_recvfrom"); goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { LOGI("[udp] remote_recv_recvfrom fragmentation"); } } buf->len = r; #ifdef MODULE_LOCAL int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #ifdef MODULE_REDIR struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, &dst_addr); if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { LOGI("[udp] ss-redir does not support domain name"); goto CLEAN_UP; } #else int len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, NULL); #endif if (len == 0) { LOGI("[udp] error in parse header"); // error in parse header goto CLEAN_UP; } // server may return using a different address type other than the type we // have used during sending #if defined(MODULE_TUNNEL) || defined(MODULE_REDIR) // Construct packet buf->len -= len; memmove(buf->data, buf->data + len, buf->len); #else #ifdef __ANDROID__ rx += buf->len; stat_update_cb(); #endif // Construct packet brealloc(buf, buf->len + 3, buf_size); memmove(buf->data + 3, buf->data, buf->len); memset(buf->data, 0, 3); buf->len += 3; #endif #endif #ifdef MODULE_REMOTE rx += buf->len; char addr_header_buf[512]; char *addr_header = remote_ctx->addr_header; int addr_header_len = remote_ctx->addr_header_len; if (remote_ctx->af == AF_INET || remote_ctx->af == AF_INET6) { addr_header_len = construct_udprelay_header(&src_addr, addr_header_buf); addr_header = addr_header_buf; } // Construct packet brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #endif if (buf->len > packet_size) { if (verbose) { LOGI("[udp] remote_recv_sendto fragmentation"); } } size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr); #ifdef MODULE_REDIR size_t remote_dst_addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int src_fd = socket(remote_ctx->src_addr.ss_family, SOCK_DGRAM, 0); if (src_fd < 0) { ERROR("[udp] remote_recv_socket"); goto CLEAN_UP; } int opt = 1; if (setsockopt(src_fd, SOL_IP, IP_TRANSPARENT, &opt, sizeof(opt))) { ERROR("[udp] remote_recv_setsockopt"); close(src_fd); goto CLEAN_UP; } if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { ERROR("[udp] remote_recv_setsockopt"); close(src_fd); goto CLEAN_UP; } #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(src_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif if (bind(src_fd, (struct sockaddr *)&dst_addr, remote_dst_addr_len) != 0) { ERROR("[udp] remote_recv_bind"); close(src_fd); goto CLEAN_UP; } int s = sendto(src_fd, buf->data, buf->len, 0, (struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len); if (s == -1) { ERROR("[udp] remote_recv_sendto"); close(src_fd); goto CLEAN_UP; } close(src_fd); #else int s = sendto(server_ctx->fd, buf->data, buf->len, 0, (struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len); if (s == -1) { ERROR("[udp] remote_recv_sendto"); goto CLEAN_UP; } #endif // handle the UDP packet successfully, // triger the timer ev_timer_again(EV_A_ & remote_ctx->watcher); CLEAN_UP: bfree(buf); ss_free(buf); }
static void remote_recv_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w; remote_t *remote = remote_recv_ctx->remote; server_t *server = remote->server; ev_timer_again(EV_A_ & remote->recv_ctx->watcher); #ifdef ANDROID stat_update_cb(loop); #endif ssize_t r = recv(remote->fd, server->buf->array, BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("remote_recv_cb_recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } server->buf->len = r; if (!remote->direct) { #ifdef ANDROID rx += server->buf->len; #endif if ( r == 0 ) return; // SSR beg if (server->obfs_plugin) { obfs_class *obfs_plugin = server->obfs_plugin; if (obfs_plugin->client_decode) { int needsendback; server->buf->len = obfs_plugin->client_decode(server->obfs, &server->buf->array, server->buf->len, &server->buf->capacity, &needsendback); if (server->buf->len < 0) { LOGE("client_decode"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } int err = ss_decrypt(server->buf, server->d_ctx); if (err) { LOGE("remote invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if (server->protocol_plugin) { obfs_class *protocol_plugin = server->protocol_plugin; if (protocol_plugin->client_post_decrypt) { server->buf->len = protocol_plugin->client_post_decrypt(server->protocol, &server->buf->array, server->buf->len, &server->buf->capacity); if (server->buf->len < 0) { LOGE("client_post_decrypt"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } if ( server->buf->len == 0 ) return; } } // SSR end } int s = send(server->fd, server->buf->array, server->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send server->buf->idx = 0; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); return; } else { ERROR("remote_recv_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < server->buf->len) { server->buf->len -= s; server->buf->idx = s; ev_io_stop(EV_A_ & remote_recv_ctx->io); ev_io_start(EV_A_ & server->send_ctx->io); return; } }