Browse Source

feat: support udp proxy

master
dnomd343 3 years ago
parent
commit
c2703b9e32
  1. 3
      include/network.h
  2. 2
      include/process.h
  3. 4
      src/CMakeLists.txt
  4. 2
      src/common.c
  5. 2
      src/local.c
  6. 121
      src/network.c
  7. 12
      src/process.c
  8. 4
      src/server.c

3
include/network.h

@ -1,6 +1,9 @@
#ifndef _NETWORK_H_ #ifndef _NETWORK_H_
#define _NETWORK_H_ #define _NETWORK_H_
extern int proxy_exit;
int get_available_port(unsigned short range_start, unsigned short range_end); int get_available_port(unsigned short range_start, unsigned short range_end);
void proxy(char *server_ip, int server_port, char *listen_ip, int listen_port);
#endif #endif

2
include/process.h

@ -9,6 +9,6 @@ extern char *SS_LOCAL_HOST;
extern char *SS_LOCAL_PORT; extern char *SS_LOCAL_PORT;
extern char *SS_PLUGIN_OPTIONS; extern char *SS_PLUGIN_OPTIONS;
void start_bootstrap(); void start_bootstrap(char *ss_type);
#endif #endif

4
src/CMakeLists.txt

@ -13,7 +13,7 @@ list(REMOVE_ITEM SRC ${PROJECT_SOURCE_DIR}/src/local.c)
list(REMOVE_ITEM SRC ${PROJECT_SOURCE_DIR}/src/server.c) list(REMOVE_ITEM SRC ${PROJECT_SOURCE_DIR}/src/server.c)
add_executable(ss-bootstrap-local local.c ${SRC}) add_executable(ss-bootstrap-local local.c ${SRC})
target_link_libraries(ss-bootstrap-local glib-2.0) target_link_libraries(ss-bootstrap-local glib-2.0 pthread)
add_executable(ss-bootstrap-server server.c ${SRC}) add_executable(ss-bootstrap-server server.c ${SRC})
target_link_libraries(ss-bootstrap-server glib-2.0) target_link_libraries(ss-bootstrap-server glib-2.0 pthread)

2
src/common.c

@ -39,7 +39,7 @@ char* int_to_string(int num) { // int -> string
} }
int count = 0; int count = 0;
int temp = num; int temp = num;
while(temp != 0) { // check the number of digits while (temp != 0) { // check the number of digits
temp /= 10; temp /= 10;
++count; ++count;
} }

2
src/local.c

@ -39,6 +39,6 @@ int main(int argc, char *argv[]) {
} }
args_decode(argc, argv); args_decode(argc, argv);
params_load(SHADOWSOCKS_DEFAULT); // default file name params_load(SHADOWSOCKS_DEFAULT); // default file name
start_bootstrap(); start_bootstrap(SHADOWSOCKS_DEFAULT); // local or server mode
return 0; return 0;
} }

121
src/network.c

@ -1,10 +1,27 @@
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h>
#include <sys/time.h> #include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include "network.h" #include "network.h"
#define TIMEOUT 15
#define BUFFER_SIZE 4096
int proxy_exit;
typedef struct ipv4_proxy_info {
char *server_ip;
int server_port;
struct sockaddr_in ipv4_client_addr;
int ipv4_client_fd;
char *buffer;
long len;
} ipv4_proxy_info;
int get_random_num(int range_start, int range_end) { // create a random number in range int get_random_num(int range_start, int range_end) { // create a random number in range
struct timeval tp; struct timeval tp;
gettimeofday(&tp, NULL); gettimeofday(&tp, NULL);
@ -78,3 +95,107 @@ int get_available_port(unsigned short range_start, unsigned short range_end) { /
} }
} }
} }
int create_ipv4_udp_sock(char *address, int port) { // 创建并绑定IPv4 UDP端口
struct sockaddr_in ipv4_udp_addr;
int ipv4_udp_sock = socket(AF_INET, SOCK_DGRAM, 0); // IPv4 UDP模式
bzero(&ipv4_udp_addr, sizeof(ipv4_udp_addr)); // 清空为0x00
ipv4_udp_addr.sin_family = AF_INET;
ipv4_udp_addr.sin_port = htons(port); // 监听端口
if (address == NULL) {
ipv4_udp_addr.sin_addr.s_addr = INADDR_ANY; // 监听0.0.0.0
} else {
ipv4_udp_addr.sin_addr.s_addr = inet_addr(address); // 监听地址
}
if (bind(ipv4_udp_sock, (struct sockaddr*)&ipv4_udp_addr, sizeof(ipv4_udp_addr)) < 0) { // 绑定接口
perror("[Shadowsocks Bootstrap] IPv4 UDP Sock bind error");
return -1; // 端口被占用
}
return ipv4_udp_sock;
}
long ipv4_receive(int fd, char *buffer, int buffer_size, int timeout, struct sockaddr_in sa) { // IPv4接收 超时处理
socklen_t sa_len = sizeof(sa);
if (timeout == 0) { // 永久等待
return recvfrom(fd, buffer, buffer_size, 0, (struct sockaddr*)&sa, &sa_len);
}
fd_set rfds;
struct timeval tv;
tv.tv_sec = timeout; // 超时时间 单位s
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
select(fd + 1, &rfds, (fd_set*)0, (fd_set*)0, &tv);
if (FD_ISSET(fd, &rfds)) {
return recvfrom(fd, buffer, buffer_size, 0, (struct sockaddr*)&sa, &sa_len);
}
return -1; // 接收超时
}
long ipv4_send_and_receive(char *ipv4_server_ip, int ipv4_server_port, char *send_buffer, long send_len, char *recv_buffer) { // IPv4下发送并接收
struct sockaddr_in ipv4_server_addr;
int ipv4_server_fd = socket(AF_INET, SOCK_DGRAM, 0); // 通讯描述符
bzero(&ipv4_server_addr, sizeof(ipv4_server_addr)); // 清空为0x00
ipv4_server_addr.sin_family = AF_INET;
ipv4_server_addr.sin_port = htons(ipv4_server_port); // 目标IP
ipv4_server_addr.sin_addr.s_addr = inet_addr(ipv4_server_ip); // 目标端口
if (sendto(ipv4_server_fd, send_buffer, send_len, 0, (struct sockaddr*)&ipv4_server_addr, sizeof(ipv4_server_addr)) < 0) { // 发送缓冲区数据
perror("[Shadowsocks Bootstrap] IPv4 UDP send failed");
}
long recv_len = ipv4_receive(ipv4_server_fd, recv_buffer, BUFFER_SIZE, TIMEOUT, ipv4_server_addr); // 接收数据到缓冲区
close(ipv4_server_fd); // 关闭描述符
return recv_len; // 返回接收长度
}
void ipv4_proxy(void *ipv4_info) { // 代理IPv4客户端
ipv4_proxy_info *info = (ipv4_proxy_info*)ipv4_info;
char *recv_buffer = (char*)malloc(BUFFER_SIZE); // 申请接收缓冲区内存
long recv_len = ipv4_send_and_receive(info->server_ip, info->server_port, info->buffer, info->len, recv_buffer); // 服务端交互
if (recv_len < 0) { // 服务端超时
printf("[Shadowsocks Bootstrap] Server return timeout\n");
} else {
if (sendto(info->ipv4_client_fd, recv_buffer, recv_len, 0, (struct sockaddr*)&(info->ipv4_client_addr), sizeof(info->ipv4_client_addr)) < 0) { // 服务端数据返回给客户端
perror("[Shadowsocks Bootstrap] IPv4 UDP return failed");
} else {
printf("[Shadowsocks Bootstrap] UDP Proxy: ↑ %ld bytes ↓ %ld bytes\n", info->len, recv_len);
}
}
free(recv_buffer); // 释放接收缓冲区内存
free(info->buffer); // 释放发送缓冲区内存
free(ipv4_info); // 释放线程传参结构体
}
void proxy(char *server_ip, int server_port, char *listen_ip, int listen_port) { // 代理UDP请求
pthread_t tid;
long recv_len;
char recv_buffer[BUFFER_SIZE]; // 接收缓冲区
struct sockaddr_in ipv4_client_addr;
socklen_t ipv4_client_addr_len = sizeof(ipv4_client_addr);
int ipv4_client_fd = create_ipv4_udp_sock(listen_ip, listen_port); // 监听端口描述符
if (ipv4_client_fd == -1) { // 端口被占用
printf("[Shadowsocks Bootstrap] The UDP port seems to be occupied by the SIP003 plugin\n");
printf("[Shadowsocks Bootstrap] WARNING: UDP communication of the agent will not work properly\n");
return;
}
proxy_exit = 0; // 重置退出标识
printf("[Shadowsocks Bootstrap] UDP Proxy: %s:%d -> %s:%d\n", listen_ip, listen_port, server_ip, server_port);
for (;;) {
recv_len = recvfrom(ipv4_client_fd, recv_buffer, BUFFER_SIZE, 0, (struct sockaddr*)&ipv4_client_addr, &ipv4_client_addr_len);
char *proxy_buffer = (char*)malloc(recv_len);
memcpy(proxy_buffer, recv_buffer, recv_len); // 复制缓冲区数据
ipv4_proxy_info *info = (ipv4_proxy_info*)malloc(sizeof(ipv4_proxy_info));
info->server_ip = server_ip;
info->server_port = server_port;
info->ipv4_client_addr = ipv4_client_addr;
info->ipv4_client_fd = ipv4_client_fd;
info->buffer = proxy_buffer;
info->len = recv_len;
pthread_create(&tid, NULL, (void*)ipv4_proxy, (void*)info); // 新线程代理请求
if (proxy_exit) {
break; // 退出代理
}
}
sleep(TIMEOUT); // 等待线程结束
close(ipv4_client_fd); // 关闭监听
}

12
src/process.c

@ -4,6 +4,7 @@
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include "network.h"
#include "process.h" #include "process.h"
char **shadowsocks_args; char **shadowsocks_args;
@ -156,6 +157,7 @@ void exit_with_child() { // exit and kill his child process
sleep(1); // block sleep(1); // block
} }
exiting = 1; exiting = 1;
proxy_exit = 1;
if (ss_pid != 0) { if (ss_pid != 0) {
kill(ss_pid, SIGKILL); kill(ss_pid, SIGKILL);
printf("[Shadowsocks Bootstrap] kill shadowsocks process.\n"); printf("[Shadowsocks Bootstrap] kill shadowsocks process.\n");
@ -190,13 +192,21 @@ void show_params() { // show shadowsocks and plugin params
printf("[Shadowsocks Bootstrap] SS_PLUGIN_OPTIONS -> %s\n", SS_PLUGIN_OPTIONS); printf("[Shadowsocks Bootstrap] SS_PLUGIN_OPTIONS -> %s\n", SS_PLUGIN_OPTIONS);
} }
void start_bootstrap() { // start shadowsocks and plugin (optional) void start_bootstrap(char *ss_type) { // start shadowsocks and plugin (optional)
show_params(); show_params();
main_loop = g_main_loop_new(NULL, FALSE); main_loop = g_main_loop_new(NULL, FALSE);
signal(SIGINT, exit_with_child); // catch Ctrl + C (2) signal(SIGINT, exit_with_child); // catch Ctrl + C (2)
signal(SIGTERM, exit_with_child); // catch exit signal (15) signal(SIGTERM, exit_with_child); // catch exit signal (15)
signal(SIGCHLD, get_sub_exit); // callback when child process die signal(SIGCHLD, get_sub_exit); // callback when child process die
process_exec(); // exec child process process_exec(); // exec child process
usleep(500 * 1000); // wait 500ms for plugin start
if (plugin_file != NULL) { // start udp proxy when using plugin
if (!strcmp(ss_type, "sslocal")) { // local mode
proxy(SS_REMOTE_HOST, atoi(SS_REMOTE_PORT), SS_LOCAL_HOST, atoi(SS_LOCAL_PORT));
} else { // server mode
proxy(SS_LOCAL_HOST, atoi(SS_LOCAL_PORT), SS_REMOTE_HOST, atoi(SS_REMOTE_PORT));
}
}
g_main_loop_run(main_loop); // into main loop for wait g_main_loop_run(main_loop); // into main loop for wait
exit_with_child(); exit_with_child();
} }

4
src/server.c

@ -3,6 +3,8 @@
#include "common.h" #include "common.h"
#include "process.h" #include "process.h"
#include "network.h"
#define SHADOWSOCKS_DEFAULT "ssserver" #define SHADOWSOCKS_DEFAULT "ssserver"
char *help_msg = char *help_msg =
@ -39,6 +41,6 @@ int main(int argc, char *argv[]) {
} }
args_decode(argc, argv); args_decode(argc, argv);
params_load(SHADOWSOCKS_DEFAULT); // default file name params_load(SHADOWSOCKS_DEFAULT); // default file name
start_bootstrap(); start_bootstrap(SHADOWSOCKS_DEFAULT); // local or server mode
return 0; return 0;
} }

Loading…
Cancel
Save