From 71f1defc221ee97277b8a2f1480ae8f4f2194c68 Mon Sep 17 00:00:00 2001 From: Jindong Zhang Date: Tue, 10 May 2022 19:12:39 +0800 Subject: [PATCH] some workaround, use threadsafe function for muslc, fix socks5 remote address resolve mode. fix lwip be limited to 200 fd sometime. --- src/agent.c | 2 +- src/agentcall.c | 2 +- src/fileexchange.c | 8 +-- src/lwipopts.h | 1 + src/pipe.c | 2 +- src/portforward.c | 79 ++++++++++++++++++-------- src/socksproxy.c | 137 ++++++++++++++++++--------------------------- src/utils.c | 36 +++++++++++- src/utils.h | 3 +- src/vnet.c | 12 ++-- src/vnet.h | 2 +- 11 files changed, 165 insertions(+), 119 deletions(-) diff --git a/src/agent.c b/src/agent.c index 1e43de8..543b32f 100644 --- a/src/agent.c +++ b/src/agent.c @@ -187,7 +187,7 @@ int agent_process_frame(char *str_data, int data_size) { log_error("empty packet"); return 0; } - log_trace("process_frame %*s\n", data_size, str_data); + // log_trace("process_frame %*s\n", data_size, str_data); // simple command if (data_size == strlen("EXIT") && strcmp(str_data, "EXIT") == 0) { agent_restore_stdin(); diff --git a/src/agentcall.c b/src/agentcall.c index 96a1539..d4daa64 100644 --- a/src/agentcall.c +++ b/src/agentcall.c @@ -35,7 +35,7 @@ typedef struct thread_arg_pass_t { static void agentcall_server_request(void *p) { int sd = (int)p; - set_vnet_socket_nodelay(sd); + vnet_setsocketdefaultopt(sd); char recv_buf[READ_CHUNK_SIZE]; int n, nwrote; log_info("sd: %d", sd); diff --git a/src/fileexchange.c b/src/fileexchange.c index bb2a1fb..2d2bbd2 100644 --- a/src/fileexchange.c +++ b/src/fileexchange.c @@ -37,12 +37,12 @@ typedef struct path_exchange { static int file_receiver_request(void *p) { int sd = (int)p; - set_vnet_socket_nodelay(sd); + vnet_setsocketdefaultopt(sd); char recv_buf[READ_CHUNK_SIZE]; int n, nwrote; log_info("sd: %d", sd); if (vnet_readstring(sd, recv_buf, READ_CHUNK_SIZE) == 0) { - close(sd); + lwip_close(sd); return 0; } char *target_file_path = recv_buf; @@ -77,12 +77,12 @@ int file_receiver_start() { static int file_sender_request(void *p) { int sd = (int)p; - set_vnet_socket_nodelay(sd); + vnet_setsocketdefaultopt(sd); char recv_buf[READ_CHUNK_SIZE]; int n, nwrote; log_info("sd: %d", sd); if (vnet_readstring(sd, recv_buf, READ_CHUNK_SIZE) == 0) { - close(sd); + lwip_close(sd); return 0; } char *target_file_path = recv_buf; diff --git a/src/lwipopts.h b/src/lwipopts.h index a6aef93..0b5854c 100644 --- a/src/lwipopts.h +++ b/src/lwipopts.h @@ -135,6 +135,7 @@ a lot of data that needs to be copied, this should be set high. */ #define LWIP_TCP 1 #define TCP_TTL 255 +#define LWIP_TCP_KEEPALIVE 1 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 diff --git a/src/pipe.c b/src/pipe.c index bd97cec..9af0adb 100644 --- a/src/pipe.c +++ b/src/pipe.c @@ -136,7 +136,7 @@ int vnet_notify_to_libuv(char *buf, size_t size) { f->buf = memdup(buf, size); f->len = size; queue_put(q, f); - log_info("add queue"); + // log_info("add queue"); data_income_notify.data = 1; // set dry int r = uv_async_send(&data_income_notify); return 0; diff --git a/src/portforward.c b/src/portforward.c index 7a0c9fe..467e4f8 100644 --- a/src/portforward.c +++ b/src/portforward.c @@ -37,6 +37,9 @@ struct lwip_sockaddr_in { char sin_zero[SIN_ZERO_LEN]; }; + + + static int port_forward_static_service_port = 7000; typedef struct port_listen { @@ -47,12 +50,12 @@ typedef struct port_listen { static void portforward_static_server_request(void *p) { int sd = (int)p; - set_vnet_socket_nodelay(sd); + vnet_setsocketdefaultopt(sd); char recv_buf[READ_CHUNK_SIZE]; int n, nwrote; CHECK(sd >= 0, "sd: %d", sd); int readbytes = 0; - + //TODO (jdz) readn do { n = lwip_read(sd, recv_buf + readbytes, 1); if (n <= 0) { @@ -63,7 +66,7 @@ static void portforward_static_server_request(void *p) { readbytes += 1; } while (*(recv_buf + readbytes - 1) != '\0'); char *host = strdup(recv_buf); - log_info("target %s", host); + readbytes = 0; do { n = lwip_read(sd, recv_buf + readbytes, sizeof(uint16_t)); @@ -76,9 +79,7 @@ static void portforward_static_server_request(void *p) { uint16_t port = ntohs(*((uint16_t *)(recv_buf))); log_info("target %s %hu", host, port); - // TODO(jdz) real connect the ip port or listen ip port - // -L -R 30 80 - // connect first + int sock; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { lwip_close(sd); @@ -89,31 +90,29 @@ static void portforward_static_server_request(void *p) { struct addrinfo *res; snprintf(portaddr, sizeof(portaddr), "%d", port); - - struct hostent *shes = gethostbyname(host); - if (!shes) { + char* ip = safe_gethostbyname(host, port); + if (ip == NULL) { close(sock); lwip_close(sd); return; } - free(host); - // TODO(jdz) thread safe - host = inet_ntoa(*(struct in_addr*)shes->h_addr); - log_info("use ip %s:%hu for domain", host, port); - struct sockaddr_in addr; + log_info("use ip %s:%hu for domain", ip, port); + struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); #ifdef __APPLE__ addr.sin_len = sizeof(addr); #endif addr.sin_family = AF_INET; addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(host); - /* connect */ - log_info("start connect %s:%hu", host, port); + addr.sin_addr.s_addr = inet_addr(ip); + + log_info("start connect %s:%hu", ip, port); + free(ip); int ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr)); if (ret != 0) { lwip_close(sd); + close(sock); log_info("connect error return %d errno:%d %s", ret, errno, strerror(errno)); return; @@ -156,7 +155,7 @@ static void loop_lwipsocket_to_socket(int *arg) { } log_info("select ret %d", ret); if (!FD_ISSET(lwip_fd, &fdset)) { - // return; + // pass } int r = lwip_recv(lwip_fd, buf, READ_CHUNK_SIZE, MSG_DONTWAIT); @@ -171,11 +170,13 @@ static void loop_lwipsocket_to_socket(int *arg) { } log_info("write expect %d %d", fd, r); int writebytes = write(fd, buf, r); - log_info("writeed %d", writebytes); + log_info("written %d", writebytes); if (writebytes < 0) { + lwip_shutdown(lwip_fd, SHUT_RDWR); return; } if (writebytes == 0) { + lwip_shutdown(lwip_fd, SHUT_RDWR); return; } } @@ -187,7 +188,31 @@ static void loop_socket_to_lwipsocket(int *arg) { int fd = arg[1]; while (true) { char buf[READ_CHUNK_SIZE]; - int r = read(fd, buf, READ_CHUNK_SIZE); //TODO + + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + struct timeval tv; + tv.tv_usec = 500; + tv.tv_sec = 0; + int ret = select(fd + 1, &fdset, NULL, NULL, &tv); + if (ret < 0) { + if (errno == EINTR) continue; + if (errno == EBADF) { + log_fatal("fd: %d", fd); + return; // TODO(jdz) fix + } + CHECK(ret > 0, "select ret:%d %s", ret, strerror(errno)); + } + if (ret == 0) { + continue; + } + log_info("select ret %d", ret); + if (!FD_ISSET(fd, &fdset)) { + // pass + } + // TODO 这中间可能被close 导致read到 无效的fd + int r = read(fd, buf, READ_CHUNK_SIZE); // TODO if (r < 0) { lwip_shutdown(lwip_fd, SHUT_RDWR); // TODO(jdz) 最好去掉 return; @@ -199,9 +224,13 @@ static void loop_socket_to_lwipsocket(int *arg) { int writebytes = lwip_write(lwip_fd, buf, r); if (writebytes < 0) { + close(fd); + lwip_close(lwip_fd); return; } if (writebytes == 0) { + close(fd); + lwip_close(lwip_fd); return; } log_info("lwip_write %d %d", r, writebytes); @@ -218,6 +247,8 @@ int pipe_lwip_socket_and_socket_pair(int lwip_fd, int fd) { pthread_create(&worker2, NULL, &loop_socket_to_lwipsocket, (void *)array); loop_lwipsocket_to_socket((void *)array); pthread_join(worker2, NULL); + log_info("lwip ip pair %d %d", lwip_fd, fd); + free(array); return 0; } @@ -298,7 +329,7 @@ int portforward_static_start(char *src_host, uint16_t src_port, char *dst_host, comm_write_packet_to_cli(COMMAND_RETURN, strdup("bind local port error\n"), sizeof("bind local port error\n")); } - return 0; + goto fail; } ret = listen(sock, 20); if (ret != 0) { @@ -308,7 +339,7 @@ int portforward_static_start(char *src_host, uint16_t src_port, char *dst_host, comm_write_packet_to_cli(COMMAND_RETURN, strdup("listen error\n"), sizeof("listen error\n")); } - return 0; + goto fail; } port_listen_t *pe = (port_listen_t *)malloc(sizeof(port_listen_t)); @@ -325,4 +356,8 @@ int portforward_static_start(char *src_host, uint16_t src_port, char *dst_host, sys_thread_new("portforward_static", portforward_service_handler, (void *)pe, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); return 0; + + fail: + close(sock); + return 0; } diff --git a/src/socksproxy.c b/src/socksproxy.c index 662a94d..4cb68b2 100644 --- a/src/socksproxy.c +++ b/src/socksproxy.c @@ -25,7 +25,7 @@ #include #include #include - +#include "utils.h" #include "log.h" #include "portforward.h" #include "vclient.h" @@ -75,7 +75,8 @@ int readn(int fd, void *buf, int n) { return n; } -static int writen(int fd, void *buf, int n) { + +static int lwip_writen(int fd, void *buf, int n) { int nwrite, left = n; while (left > 0) { if ((nwrite = lwip_write(fd, buf, left)) == -1) { @@ -113,9 +114,12 @@ int readtocharR(int fd, char *buf, int bufsize) { } int report_error_to_client(int fd, char *message) { + if (message == NULL) { + message = "(null)"; + } char buffer[512]; - snprintf(buffer, sizeof(buffer), "HTTP/1.1 500 %s\r\n\r\n", message); - writen(fd, buffer, strlen(buffer)); + snprintf(buffer, sizeof(buffer), "HTTP/1.1 500 Internal Server Error %s\r\n\r\n", message); + lwip_writen(fd, buffer, strlen(buffer)); } int http_proxy(int fd, char *prefetch_data, int prefetch_data_size) { @@ -158,7 +162,7 @@ int http_proxy(int fd, char *prefetch_data, int prefetch_data_size) { // printf("cmd:[%s]\n",cmd); if (strcmp(cmd, "GET") && strcmp(cmd, "POST") && strcmp(cmd, "CONNECT")) { report_error_to_client(fd, "This command is not supported"); - close(fd); + lwip_close(fd); // TODO (jdz) 遗留bug return 0; } @@ -204,23 +208,25 @@ int http_proxy(int fd, char *prefetch_data, int prefetch_data_size) { log_info("socket error"); return 0; } - - struct hostent *shes = gethostbyname(host); - if (!shes) { - report_error_to_client(fd, hstrerror(h_errno)); - close(fd); + char* ip = safe_gethostbyname(host, port); + if (ip == NULL) { + log_info("safe_gethostbyname empty ip"); + report_error_to_client(fd, "empty ip"); + lwip_close(fd); + close(rfd); return 0; } struct sockaddr_in sin; sin.sin_family = AF_INET; - bcopy(shes->h_addr, &sin.sin_addr, sizeof(struct in_addr)); + sin.sin_addr.s_addr = inet_addr(ip); + free(ip); sin.sin_port = htons(port); if (connect(rfd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { - report_error_to_client(fd, strerror(buf2)); + report_error_to_client(fd, strerror(errno)); lwip_close(fd); + close(rfd); return 0; } - if (strcmp(cmd, "CONNECT") != 0) { sprintf(buf2, "%s %s\n", cmd, url); if (write(rfd, buf2, strlen(buf2)) < 1) { @@ -230,7 +236,7 @@ int http_proxy(int fd, char *prefetch_data, int prefetch_data_size) { } } else { char *reply = "HTTP/1.1 200 Connection Established\r\n\r\n"; - if (writen(fd, reply, strlen(reply)) < 1) { + if (lwip_writen(fd, reply, strlen(reply)) < 1) { lwip_close(fd); close(rfd); return 0; @@ -283,42 +289,27 @@ int app_connect(int type, void *buf, unsigned short int portnum) { return fd; } else if (type == DOMAIN) { - char portaddr[6]; - struct addrinfo *res; - snprintf(portaddr, ARRAY_SIZE(portaddr), "%d", portnum); - log_info("getaddrinfo: %s %s", (char *)buf, portaddr); - int ret = getaddrinfo((char *)buf, portaddr, NULL, &res); - log_info("getaddrinfo done"); - if (ret == EAI_NODATA) { + + char* ip = safe_gethostbyname(buf, portnum); + if (ip == NULL) { + log_info("safe_gethostbyname empty ip"); + close(fd); return -1; - } else if (ret == 0) { - struct addrinfo *r; - for (r = res; r != NULL; r = r->ai_next) { - fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); - if (fd == -1) { - continue; - } - log_info("connect host"); - struct sockaddr_in *addr; - addr = (struct sockaddr_in *)r->ai_addr; - log_info("port %hu", ntohs(addr->sin_port)); - log_info("inet_ntoa(in_addr)sin = %s\n", - inet_ntoa((struct in_addr)addr->sin_addr)); - - ret = connect(fd, r->ai_addr, r->ai_addrlen); - if (ret == 0) { - log_info("connect host succ %d", fd); - freeaddrinfo(res); - return fd; - } else { - close(fd); - } - } } - freeaddrinfo(res); - return -1; + log_info("connect %s:%hu",ip, portnum); + memset(&remote, 0, sizeof(remote)); + remote.sin_family = AF_INET; + remote.sin_addr.s_addr = inet_addr(ip); + free(ip); + remote.sin_port = htons(portnum); + fd = socket(AF_INET, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&remote, sizeof(struct sockaddr_in)) < 0) { + log_info("connect() in app_connect"); + close(fd); + return -1; + } + return fd; } - return -1; } @@ -358,7 +349,7 @@ char *socks5_auth_get_pass(int fd) { int socks5_auth_userpass(int fd) { char answer[2] = {VERSION5, USERPASS}; - writen(fd, (void *)answer, ARRAY_SIZE(answer)); + lwip_writen(fd, (void *)answer, ARRAY_SIZE(answer)); char resp; readn(fd, (void *)&resp, sizeof(resp)); log_info("auth %hhX", resp); @@ -368,13 +359,13 @@ int socks5_auth_userpass(int fd) { if (strcmp(arg_username, username) == 0 && strcmp(arg_password, password) == 0) { char answer[2] = {AUTH_VERSION, AUTH_OK}; - writen(fd, (void *)answer, ARRAY_SIZE(answer)); + lwip_writen(fd, (void *)answer, ARRAY_SIZE(answer)); free(username); free(password); return 0; } else { char answer[2] = {AUTH_VERSION, AUTH_FAIL}; - writen(fd, (void *)answer, ARRAY_SIZE(answer)); + lwip_writen(fd, (void *)answer, ARRAY_SIZE(answer)); free(username); free(password); return 1; @@ -383,13 +374,13 @@ int socks5_auth_userpass(int fd) { int socks5_auth_noauth(int fd) { char answer[2] = {VERSION5, NOAUTH}; - writen(fd, (void *)answer, ARRAY_SIZE(answer)); + lwip_writen(fd, (void *)answer, ARRAY_SIZE(answer)); return 0; } void socks5_auth_notsupported(int fd) { char answer[2] = {VERSION5, NOMETHOD}; - writen(fd, (void *)answer, ARRAY_SIZE(answer)); + lwip_writen(fd, (void *)answer, ARRAY_SIZE(answer)); } void socks5_auth(int fd, int methods_count) { @@ -447,9 +438,9 @@ char *socks_ip_read(int fd) { void socks5_ip_send_response(int fd, char *ip, unsigned short int port) { char response[4] = {VERSION5, OK, RESERVED, IP}; - writen(fd, (void *)response, ARRAY_SIZE(response)); - writen(fd, (void *)ip, IPSIZE); - writen(fd, (void *)&port, sizeof(port)); + lwip_writen(fd, (void *)response, ARRAY_SIZE(response)); + lwip_writen(fd, (void *)ip, IPSIZE); + lwip_writen(fd, (void *)&port, sizeof(port)); } char *socks5_domain_read(int fd, unsigned char *size) { @@ -472,32 +463,14 @@ void socks5_ip_send_response(int fd, char *ip, unsigned short int port) writen(fd, (void *)&port, sizeof(port)); } */ - void socks5_domain_send_response(int fd, char *domain, unsigned char size, - uint16_t port) { - char response[4] = {VERSION5, OK, RESERVED, IP}; - writen(fd, (void *)response, sizeof(response)); -#if 0 - buf->data[0] = 0x5; - buf->data[1] = 0x0; - buf->data[2] = 0x0; - buf->data[3] = 0x1; - int s_addr = inet_aton("0.0.0.0", NULL); - uint32_t us_addr = htonl(s_addr); - memcpy(&buf->data[4], &us_addr, 4); - buf->data[4] = 0x1; - buf->data[4 + 4] = 0x19; - buf->data[4 + 5] = 0x19; - buf->used = 10; -#endif - char buf[4]; - int s_addr = inet_aton("0.0.0.0", NULL); - uint32_t us_addr = htonl(s_addr); - memcpy(buf, &us_addr, 4); - buf[0] = 0x1; - writen(fd, (void *)buf, sizeof(buf)); - // writen(fd, (void *)domain, size * sizeof(char)); - writen(fd, (void *)&port, sizeof(port)); + unsigned short int port) +{ + char response[4] = { VERSION5, OK, RESERVED, DOMAIN }; + lwip_writen(fd, (void *)response, ARRAY_SIZE(response)); + lwip_writen(fd, (void *)&size, sizeof(size)); + lwip_writen(fd, (void *)domain, size * sizeof(char)); + lwip_writen(fd, (void *)&port, sizeof(port)); } int socks4_is_4a(char *ip) { @@ -529,12 +502,12 @@ int socks4_read_nstring(int fd, char *buf, int size) { void socks4_send_response(int fd, int status) { char resp[8] = {0x00, (char)status, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - writen(fd, (void *)resp, ARRAY_SIZE(resp)); + lwip_writen(fd, (void *)resp, ARRAY_SIZE(resp)); } void *app_thread_process(void *fd) { int net_fd = (int)fd; - set_vnet_socket_nodelay(net_fd); + vnet_setsocketdefaultopt(net_fd); int version = 0; int inet_fd = -1; char header[255]; diff --git a/src/utils.c b/src/utils.c index 00789ad..3a190ce 100644 --- a/src/utils.c +++ b/src/utils.c @@ -9,7 +9,12 @@ #define TERMTUNNEL_UTILS_H #include "utils.h" - +#include "log.h" +#include +#include +#include +#include +#include #include #include #include @@ -94,4 +99,33 @@ void set_stdin_raw() { _stdin_is_raw = true; } + +char* safe_gethostbyname(char *host, uint16_t port) { + log_info("gethostbyname %s:%hu", host, port); + char portaddr[6]; + struct addrinfo *res; + snprintf(portaddr, sizeof(portaddr), "%d", port); + int ret = getaddrinfo((char *)host, portaddr, NULL, &res); + if (ret == EAI_NODATA) { + printf("gethostbyname EAI_NODATA"); + return NULL; + } else if (ret == 0) { + struct addrinfo *r; + for (r = res; r != NULL; r = r->ai_next) { + // TODO(jdz) if == ipv4 + // int fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); + struct sockaddr_in *addr; + addr = (struct sockaddr_in *)r->ai_addr; + char *ret = malloc(INET_ADDRSTRLEN); + inet_ntop(AF_INET, &(addr->sin_addr), ret, INET_ADDRSTRLEN); + // inet_pton(AF_INET, "192.0.2.33", &(sa.sin_addr)); + freeaddrinfo(res); + return ret; + } + freeaddrinfo(res); + } + return NULL; +} + + #endif \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index e56bfec..bc6eb30 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,7 +9,7 @@ #define TERMTUNNEL_UTILS_H #include - +#include #include "log.h" #define CHECK(x, ...) \ if (!(x)) { \ @@ -22,4 +22,5 @@ extern void set_stdin_raw(); extern void restore_stdin(); extern void *memdup(const void *src, size_t n); extern const char *green_encode(const char *buf, int len, int *result_len); +extern char* safe_gethostbyname(char *buf, uint16_t port); #endif \ No newline at end of file diff --git a/src/vnet.c b/src/vnet.c index 7d44cf9..e019d11 100644 --- a/src/vnet.c +++ b/src/vnet.c @@ -42,10 +42,12 @@ char *server_ip = "192.168.1.111"; int16_t listen_port = 700; -void set_vnet_socket_nodelay(int nfd) { - int flags = 1; - size_t flglen = sizeof(flags); - lwip_setsockopt(nfd, SOL_SOCKET, TCP_NODELAY, &flags, &flglen); +void vnet_setsocketdefaultopt(int nfd) { + int flags; + flags = 1; + lwip_setsockopt(nfd, SOL_SOCKET, TCP_NODELAY, &flags, sizeof(flags)); + flags = 1; + lwip_setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags)); } @@ -137,7 +139,7 @@ int vnet_tcp_connect(uint16_t port) { addr.sin_family = AF_INET; addr.sin_port = lwip_htons(port); addr.sin_addr.s_addr = inet_addr(server_ip); - set_vnet_socket_nodelay(s); + vnet_setsocketdefaultopt(s); /* connect */ int ret = lwip_connect(s, (struct sockaddr *)&addr, sizeof(addr)); if (ret == 0) { diff --git a/src/vnet.h b/src/vnet.h index 3a92b11..b76f628 100644 --- a/src/vnet.h +++ b/src/vnet.h @@ -18,7 +18,7 @@ int vnet_send(int s, const void *data, size_t size); int vnet_recv(int s, const void *data, size_t size); int vnet_listen_at(uint16_t port, void *cb,char* thread_desc); int vnet_close(int s); -void set_vnet_socket_nodelay(int nfd); +void vnet_setsocketdefaultopt(int nfd); int vnet_readn(int fd, void *buf, int n); int vnet_readstring(int fd, char *buf, int n); #endif