[toc]

用C语言在linux中使用Socks5协议开发代理服务器

1.写一个使用socks5协议的代理服务器程序支持域名与ipv4

socks5s.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//socks5s.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>

#define SOCKS5_PORT 1080
#define BACKLOG 10
#define BUFFER_SIZE 4096

void fatal_error(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}

// 代理数据转发
void proxy_data(int client_sock, int remote_sock) {
fd_set read_fds;
char buffer[BUFFER_SIZE];
int max_fd = (client_sock > remote_sock) ? client_sock : remote_sock;

while (1) {
FD_ZERO(&read_fds);
FD_SET(client_sock, &read_fds);
FD_SET(remote_sock, &read_fds);

if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0) {
perror("Select error");
break;
}

if (FD_ISSET(client_sock, &read_fds)) {
int len = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (len <= 0) break;
send(remote_sock, buffer, len, 0);
}

if (FD_ISSET(remote_sock, &read_fds)) {
int len = recv(remote_sock, buffer, BUFFER_SIZE, 0);
if (len <= 0) break;
send(client_sock, buffer, len, 0);
}
}

close(client_sock);
close(remote_sock);
}

// 处理 SOCKS5 代理请求
void handle_client(int client_sock) {
unsigned char buffer[BUFFER_SIZE];

// 读取 SOCKS5 握手请求
recv(client_sock, buffer, 2, 0);
if (buffer[0] != 0x05) {
printf("Unsupported SOCKS version: %d\n", buffer[0]);
close(client_sock);
return;
}

// 读取可用认证方法
int nmethods = buffer[1];
recv(client_sock, buffer, nmethods, 0);

// 发送认证响应 (0x05 0x00 -> 无需认证)
unsigned char response[2] = {0x05, 0x00};
send(client_sock, response, 2, 0);

// 读取 SOCKS5 请求
recv(client_sock, buffer, 4, 0);
if (buffer[1] != 0x01) { // 只支持 CONNECT
printf("Unsupported command: %d\n", buffer[1]);
close(client_sock);
return;
}

// 解析目标地址
char remote_ip[INET_ADDRSTRLEN];
int remote_port;
struct sockaddr_in remote_addr;
int remote_sock;

if (buffer[3] == 0x01) { // IPv4
recv(client_sock, buffer + 4, 4, 0);
recv(client_sock, buffer + 8, 2, 0);
inet_ntop(AF_INET, buffer + 4, remote_ip, INET_ADDRSTRLEN);
remote_port = ntohs(*(uint16_t *)(buffer + 8));
} else if (buffer[3] == 0x03) { // 域名
uint8_t domain_len;
recv(client_sock, &domain_len, 1, 0);
recv(client_sock, buffer + 5, domain_len + 2, 0); // 读取域名和端口

char domain[256];
memcpy(domain, buffer + 5, domain_len);
domain[domain_len] = '\0'; // 确保是 C 字符串
remote_port = ntohs(*(uint16_t *)(buffer + 5 + domain_len));

printf("Resolving domain: %s:%d\n", domain, remote_port);

struct hostent *host = gethostbyname(domain);
if (!host) {
perror("Domain resolution failed");
close(client_sock);
return;
}
strcpy(remote_ip, inet_ntoa(*(struct in_addr *)host->h_addr));
} else {
printf("Unsupported address type: %d\n", buffer[3]);
close(client_sock);
return;
}

printf("Connecting to %s:%d\n", remote_ip, remote_port);

// 连接目标服务器
if ((remote_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation failed");
close(client_sock);
return;
}

remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(remote_port);
inet_pton(AF_INET, remote_ip, &remote_addr.sin_addr);

if (connect(remote_sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) < 0) {
perror("Connection failed");
close(client_sock);
close(remote_sock);
return;
}

printf("Connected to target server!\n");

// 发送连接成功响应
unsigned char reply[10] = {0x05, 0x00, 0x00, 0x01};
memcpy(reply + 4, buffer + 4, 6); // 复制目标地址信息
send(client_sock, reply, 10, 0);

// 开始数据转发
proxy_data(client_sock, remote_sock);
}

int main() {
int server_sock;
struct sockaddr_in server_addr;
int optval = 1;

// 创建 TCP 套接字
if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fatal_error("Socket creation failed");
}

// 设置 SO_REUSEADDR
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
fatal_error("setsockopt SO_REUSEADDR failed");
}

// 初始化服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SOCKS5_PORT);

// 绑定地址和端口
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
fatal_error("Bind failed");
}

printf("Server bound to port %d successfully.\n", SOCKS5_PORT);

// 监听连接
if (listen(server_sock, BACKLOG) < 0) {
fatal_error("Listen failed");
}

printf("SOCKS5 Proxy Server running on port %d, waiting for connections...\n", SOCKS5_PORT);

// 处理客户端连接
while (1) {
int client_sock = accept(server_sock, NULL, NULL);
if (client_sock < 0) {
perror("Accept failed");
continue;
}
printf("New client connected!\n");

if (!fork()) {
close(server_sock);
handle_client(client_sock);
exit(0);
}
close(client_sock);
}

close(server_sock);
return 0;
}