]> code.delx.au - proxy/blob - socks5server.c
Initial commit v0.1
[proxy] / socks5server.c
1 #define _POSIX_C_SOURCE 200809L
2
3 #include <stdio.h>
4 #include <stdbool.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <pthread.h>
8 #include <errno.h>
9
10 #include <string.h>
11 #include <bsd/string.h>
12 #include <sys/types.h>
13
14 #include <sys/socket.h>
15 #include <netdb.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18
19
20
21 /***********
22 * Logging *
23 ***********/
24
25 static __thread char* log_context = "";
26
27 #define log_errno(fmt, ...) \
28 fprintf(stderr, "ERROR [%s] " fmt ": %s\n", log_context , ##__VA_ARGS__ , strerror(errno));
29
30 #define log_error(fmt, ...) \
31 fprintf(stderr, "ERROR [%s] " fmt "\n", log_context , ##__VA_ARGS__);
32
33 #define log_warn(fmt, ...) \
34 fprintf(stderr, "WARN [%s] " fmt "\n", log_context , ##__VA_ARGS__);
35
36 #define log_info(fmt, ...) \
37 fprintf(stderr, "INFO [%s] " fmt "\n", log_context , ##__VA_ARGS__);
38
39 #ifdef DEBUG
40 #define log_debug(fmt, ...) \
41 fprintf(stderr, "DEBUG [%s] " fmt "\n", log_context , ##__VA_ARGS__);
42 #else
43 #define log_debug(fmt, ...)
44 #endif
45
46 void log_context_set(char* new_context) {
47 log_context = new_context;
48 log_debug("Thread started");
49 }
50
51 void log_context_clear() {
52 log_debug("Thread finished");
53 log_context = "";
54 }
55
56
57
58 /*************
59 * Utilities *
60 *************/
61
62 bool itoa(char* buf, int buflen, int64_t val) {
63 int result = snprintf(buf, buflen, "%ld", val);
64 return result > 0 && result < buflen;
65 }
66
67 void sockaddr_stringify(char* dest, size_t dest_length, struct sockaddr_storage* addr) {
68 if (addr->ss_family == AF_INET) {
69 inet_ntop(AF_INET, &((struct sockaddr_in*)addr)->sin_addr, dest, dest_length);
70 } else if (addr->ss_family == AF_INET6) {
71 inet_ntop(AF_INET6, &((struct sockaddr_in6*)addr)->sin6_addr, dest, dest_length);
72 } else {
73 strlcpy(dest, "Unknown socket family", dest_length);
74 }
75 }
76
77 char* sockaddr_tostring(struct sockaddr_storage* addr) {
78 static char buf[INET6_ADDRSTRLEN];
79 sockaddr_stringify(buf, sizeof(buf), addr);
80 return buf;
81 }
82
83 void* smalloc(size_t sz) {
84 void* ptr = calloc(1, sz);
85 if (ptr == NULL) {
86 log_errno("Memory allocation failed");
87 exit(1);
88 }
89 return ptr;
90 }
91
92
93
94 /**********
95 * Config *
96 **********/
97
98 extern char** environ;
99
100 int getenv_int(char* key) {
101 char* value = getenv(key);
102 if (value == NULL) {
103 log_error("Missing environment variable: %s", key);
104 exit(1);
105 }
106
107 return atoi(value);
108 }
109
110 char* extract_env_value(char* str) {
111 char ch;
112 while ((ch = *str++)) {
113 if (ch == '=') {
114 return str;
115 }
116 }
117 return "";
118 }
119
120 bool getenv_list_matcher(char* key, bool (*matches)(char*, void*), void* data) {
121 size_t key_length = strlen(key);
122
123 char** ptr = environ;
124
125 while (*ptr) {
126 if (strncmp(*ptr, key, key_length) == 0) {
127 char* value = extract_env_value(*ptr);
128 if (matches(value, data)) {
129 return true;
130 }
131 }
132 ++ptr;
133 }
134
135 return false;
136 }
137
138
139
140
141 /**************
142 * Network IO *
143 **************/
144
145 bool ssend(int fd, void* buf, size_t len) {
146 while (len > 0) {
147 ssize_t sz = send(fd, buf, len, MSG_NOSIGNAL);
148 if (sz < 0) {
149 log_errno("Failed to write, closing connection");
150 return false;
151 }
152 buf += sz;
153 len -= sz;
154 }
155 return true;
156 }
157
158 ssize_t srecv(int fd, void* buf, size_t len) {
159 return recv(fd, buf, len, 0);
160 }
161
162 bool read_bytes(int fd, uint8_t* value, ssize_t sz) {
163 if (srecv(fd, value, sz) != sz) {
164 log_errno("Failed to read from client socket");
165 return false;
166 }
167 for (ssize_t i = 0; i < sz; ++i) {
168 log_debug("got byte: %x", value[i]);
169 }
170 return true;
171 }
172
173 bool read_byte_check(int fd, uint8_t expected, char* msg) {
174 uint8_t actual;
175 if (!read_bytes(fd, &actual, 1)) {
176 return false;
177 }
178 if (actual != expected) {
179 log_warn("%s", msg);
180 return false;
181 }
182 return true;
183 }
184
185
186
187 /**********
188 * Server *
189 **********/
190
191 void proxy_copy_fd(int wfd, int rfd) {
192 log_debug("proxy_copy_fd %d %d", wfd, rfd);
193
194 char buf[32768];
195
196 for (;;) {
197 log_debug("proxy_copy_fd blocking on read %d", rfd);
198 int bufsz = srecv(rfd, buf, sizeof(buf));
199 log_debug("proxy_copy_fd unblocked from read %d", rfd);
200 if (bufsz < 0) {
201 log_errno("Failed to read, closing connection");
202 break;
203 }
204 if (bufsz == 0) {
205 log_debug("proxy_copy_fd end of file %d %d", wfd, rfd);
206 break;
207 }
208
209 log_debug("proxy_copy_fd blocking on write %d", wfd);
210 if (!ssend(wfd, buf, bufsz)) {
211 log_errno("Failed to write, closing connection");
212 break;
213 }
214 log_debug("proxy_copy_fd unblocked from write %d", wfd);
215 }
216
217 shutdown(wfd, SHUT_WR);
218 shutdown(rfd, SHUT_RD);
219 }
220
221
222 struct proxy_copy_from_dest_data {
223 pthread_t tid;
224 int src_fd;
225 int dst_fd;
226 char log_context[INET6_ADDRSTRLEN];
227 };
228
229 void* proxy_copy_from_dest(void* _data) {
230 struct proxy_copy_from_dest_data* data = (struct proxy_copy_from_dest_data*)_data;
231 log_context_set(data->log_context);
232
233 proxy_copy_fd(data->dst_fd, data->src_fd);
234
235 log_context_clear();
236 free(data);
237
238 return NULL;
239 }
240
241 bool proxy_create_copy_from_dest_thread(
242 int dst_fd,
243 int src_fd
244 ) {
245 struct proxy_copy_from_dest_data* data = smalloc(sizeof(struct proxy_copy_from_dest_data));
246 data->dst_fd = dst_fd;
247 data->src_fd = src_fd;
248 strlcpy(data->log_context, log_context, sizeof(data->log_context));
249 if (pthread_create(&data->tid, NULL, &proxy_copy_from_dest, data) != 0) {
250 log_errno("Failed to spawn thread");
251 exit(1);
252 }
253 return true;
254 }
255
256 bool proxy_negotiate_auth(int fd) {
257 if (!read_byte_check(fd, 5, "Client sent invalid version!")) {
258 return false;
259 }
260
261 uint8_t nmethods;
262 if (!read_bytes(fd, &nmethods, 1)) {
263 return false;
264 }
265 if (nmethods < 1) {
266 log_warn("Client sent invalid authentication method count!");
267 return false;
268 }
269
270 uint8_t methods[nmethods];
271 if (!read_bytes(fd, methods, nmethods)) {
272 return false;
273 }
274 bool found_noauth = false;
275 for (int i = 0; i < nmethods; ++i) {
276 if (methods[i] == 0) {
277 found_noauth = true;
278 break;
279 }
280 }
281 if (!found_noauth) {
282 ssend(fd, "\x05\xff", 2);
283 log_warn("Client does not support no-authentication SOCKS5!");
284 return false;
285 }
286
287 if (!ssend(fd, "\x05\x00", 2)) {
288 return false;
289 }
290
291 return true;
292 }
293
294 bool proxy_write_error_response(int fd, uint8_t errcode) {
295 char response[] = "\x05\xff\x00\x01\x00\x00\x00\x00\x00\x00";
296 int length = sizeof(response) - 1; // remove trailing null
297 response[1] = errcode;
298 if (!ssend(fd, response, length)) {
299 return false;
300 }
301 return true;
302 }
303
304 bool proxy_dns_handle_request(int* dst_fd, int fd) {
305 uint8_t name_length;
306 if (!read_bytes(fd, (uint8_t*)&name_length, 1)) {
307 return false;
308 }
309 if (name_length < 1) {
310 log_warn("Client sent invalid name length!");
311 return false;
312 }
313
314 char name[name_length+1];
315 if (!read_bytes(fd, (uint8_t*)name, name_length)) {
316 return false;
317 }
318 name[name_length] = '\0';
319
320 uint16_t port_int;
321 if (!read_bytes(fd, (uint8_t*)&port_int, 2)) {
322 return false;
323 }
324 port_int = ntohs(port_int);
325 char port[8];
326 if (!itoa(port, sizeof(port), port_int)) {
327 return false;
328 }
329
330
331 struct addrinfo hints;
332 struct addrinfo* result;
333 memset(&hints, 0, sizeof(hints));
334 hints.ai_family = AF_UNSPEC;
335 hints.ai_socktype = SOCK_STREAM;
336 hints.ai_flags = AI_NUMERICSERV;
337 hints.ai_protocol = 0;
338
339 log_debug("proxy_dns_handle_request getaddrinfo before '%s' '%s'", name, port);
340 if (getaddrinfo(name, port, &hints, &result) != 0) {
341 log_warn("proxy_dns_handle_request getaddrinfo failed");
342 proxy_write_error_response(fd, 4);
343 return false;
344 }
345 log_debug("proxy_dns_handle_request getaddrinfo success");
346
347 for (struct addrinfo* rp = result; rp != NULL; rp = rp->ai_next) {
348 *dst_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
349 if (*dst_fd < 0) {
350 continue;
351 }
352
353 if (connect(*dst_fd, rp->ai_addr, rp->ai_addrlen) == 0) {
354 proxy_write_error_response(fd, 0);
355 freeaddrinfo(result);
356 return true;
357 }
358
359 close(*dst_fd);
360 }
361
362 proxy_write_error_response(fd, 4);
363 freeaddrinfo(result);
364 return false;
365 }
366
367 bool proxy_ipv6_handle_request(int* dst_fd, int fd) {
368 struct sockaddr_in6 dst_addr;
369 memset(&dst_addr, 0, sizeof(dst_addr));
370 dst_addr.sin6_family = AF_INET6;
371
372 if (!read_bytes(fd, (uint8_t*)&dst_addr.sin6_addr, 16)) {
373 return false;
374 }
375
376 if (!read_bytes(fd, (uint8_t*)&dst_addr.sin6_port, 2)) {
377 return false;
378 }
379
380 log_debug("got addr: %s", sockaddr_tostring((struct sockaddr_storage*)&dst_addr));
381
382 *dst_fd = socket(AF_INET6, SOCK_STREAM, 0);
383 if (*dst_fd < 0) {
384 log_errno("Failed to create socket");
385 exit(1);
386 }
387
388 if (connect(*dst_fd, (struct sockaddr*)&dst_addr, sizeof(dst_addr)) != 0) {
389 proxy_write_error_response(fd, 4);
390 return false;
391 }
392
393 proxy_write_error_response(fd, 0);
394 return true;
395 }
396
397 bool proxy_ipv4_handle_request(int* dst_fd, int fd) {
398 struct sockaddr_in dst_addr;
399 memset(&dst_addr, 0, sizeof(dst_addr));
400 dst_addr.sin_family = AF_INET;
401
402 if (!read_bytes(fd, (uint8_t*)&dst_addr.sin_addr, 4)) {
403 return false;
404 }
405
406 if (!read_bytes(fd, (uint8_t*)&dst_addr.sin_port, 2)) {
407 return false;
408 }
409
410 log_debug("got addr: %s", sockaddr_tostring((struct sockaddr_storage*)&dst_addr));
411
412 *dst_fd = socket(AF_INET, SOCK_STREAM, 0);
413 if (*dst_fd < 0) {
414 log_errno("Failed to create socket");
415 exit(1);
416 }
417
418 if (connect(*dst_fd, (struct sockaddr*)&dst_addr, sizeof(dst_addr)) != 0) {
419 proxy_write_error_response(fd, 4);
420 return false;
421 }
422
423 proxy_write_error_response(fd, 0);
424 return true;
425 }
426
427 bool proxy_handle_request(int* dst_fd, int fd) {
428 if (!read_byte_check(fd, 5, "Client sent invalid version!")) {
429 proxy_write_error_response(fd, 1);
430 return false;
431 }
432
433 if (!read_byte_check(fd, 1, "Client sent invalid command!")) {
434 proxy_write_error_response(fd, 7);
435 return false;
436 }
437
438 if (!read_byte_check(fd, 0, "Client sent invalid reserved section!")) {
439 proxy_write_error_response(fd, 1);
440 return false;
441 }
442
443 uint8_t addr_type;
444 if (!read_bytes(fd, &addr_type, 1)) {
445 return false;
446 }
447 switch (addr_type) {
448 case 1:
449 return proxy_ipv4_handle_request(dst_fd, fd);
450 case 3:
451 return proxy_dns_handle_request(dst_fd, fd);
452 case 4:
453 return proxy_ipv6_handle_request(dst_fd, fd);
454 }
455
456 proxy_write_error_response(fd, 8);
457 return false;
458 }
459
460 struct proxy_handle_accept_data {
461 pthread_t tid;
462 int fd;
463 char log_context[INET6_ADDRSTRLEN];
464 };
465
466 void* proxy_handle_accept(void* _data) {
467 struct proxy_handle_accept_data* data = (struct proxy_handle_accept_data*)_data;
468 log_context_set(data->log_context);
469
470 int dst_fd = -1;
471
472 log_debug("proxy_negotiate_auth before %d", data->fd);
473 if (!proxy_negotiate_auth(data->fd)) {
474 log_debug("negotiate_auth fail");
475 goto finish;
476 }
477
478 log_debug("proxy_handle_request before");
479 if (!proxy_handle_request(&dst_fd, data->fd)) {
480 log_debug("proxy_handle_request fail");
481 goto finish;
482 }
483
484 log_debug("proxy_create_copy_from_dest_thread before %d %d", dst_fd, data->fd);
485 if (!proxy_create_copy_from_dest_thread(dst_fd, data->fd)) {
486 log_debug("proxy_create_copy_from_dest_thread fail");
487 goto finish;
488 }
489
490 // opposite direction to the thread we just created
491 log_debug("proxy_copy_fd before %d %d", data->fd, dst_fd);
492 proxy_copy_fd(data->fd, dst_fd);
493 log_debug("proxy_copy_fd after");
494
495 finish:
496 if (dst_fd >= 0) {
497 close(dst_fd);
498 }
499 close(data->fd);
500
501 log_context_clear();
502
503 free(data);
504
505 return NULL;
506 }
507
508 bool sockaddr_equals_addrinfo(struct sockaddr_storage* addr1, struct addrinfo* addr2) {
509 void* addr1_ptr = NULL;
510 void* addr2_ptr = NULL;
511 socklen_t length = 0;
512
513 if (addr1->ss_family == AF_INET && addr2->ai_family == AF_INET) {
514 addr1_ptr = &(((struct sockaddr_in*)addr1)->sin_addr);
515 addr2_ptr = &((struct sockaddr_in*)addr2->ai_addr)->sin_addr;
516 length = sizeof(struct in_addr);
517 } else if (addr1->ss_family == AF_INET6 && addr2->ai_family == AF_INET6) {
518 addr1_ptr = &(((struct sockaddr_in6*)addr1)->sin6_addr);
519 addr2_ptr = &((struct sockaddr_in6*)addr2->ai_addr)->sin6_addr;
520 length = sizeof(struct in6_addr);
521 } else {
522 return false;
523 }
524
525 return memcmp(addr1_ptr, addr2_ptr, length) == 0;
526 }
527
528 bool sockaddr_matches_string(char* str, void* _addr) {
529 struct sockaddr_storage* addr = (struct sockaddr_storage*)_addr;
530
531 struct addrinfo hints;
532 struct addrinfo* result;
533 memset(&hints, 0, sizeof(hints));
534 hints.ai_family = AF_UNSPEC;
535 hints.ai_socktype = SOCK_STREAM;
536 hints.ai_flags = AI_NUMERICSERV;
537 hints.ai_protocol = 0;
538
539 if (getaddrinfo(str, NULL, &hints, &result) != 0) {
540 log_warn("sockaddr_matches_string getaddrinfo failed: %s", str);
541 return false;
542 }
543
544 bool found = false;
545 for (struct addrinfo* rp = result; rp != NULL; rp = rp->ai_next) {
546 if (sockaddr_equals_addrinfo(addr, rp)) {
547 found = true;
548 break;
549 }
550 }
551
552 freeaddrinfo(result);
553 return found;
554 }
555
556 bool server_has_permission(struct sockaddr_storage* addr) {
557 if (getenv("ALLOW_ALL") != NULL) {
558 log_debug("Accepting connection because ALLOW_ALL is set");
559 return true;
560 }
561
562 if (getenv_list_matcher("ALLOW_HOST", sockaddr_matches_string, addr)) {
563 log_debug("Accepting connection because it matches ALLOW_HOST entry");
564 return true;
565 }
566
567 log_info("Rejecting connection: %s", sockaddr_tostring(addr));
568
569 return false;
570 }
571
572 void rewrite_ipv4_mapped_address(struct sockaddr_storage* addr) {
573 if (addr->ss_family != AF_INET6) {
574 return;
575 }
576
577 struct in6_addr* addr_data = &((struct sockaddr_in6*)addr)->sin6_addr;
578 if (!(
579 ((uint32_t*)(addr_data))[0] == 0 &&
580 ((uint32_t*)(addr_data))[1] == 0 &&
581 ((uint32_t*)(addr_data))[2] == htonl(0xffff)
582 )) {
583 return;
584 }
585
586 struct sockaddr_in new_addr;
587 memset(&new_addr, 0, sizeof(struct sockaddr));
588 new_addr.sin_family = AF_INET;
589 memcpy(&new_addr.sin_addr.s_addr, &((struct sockaddr_in6*)addr)->sin6_addr.s6_addr[12], 4);
590 memcpy(addr, &new_addr, sizeof(struct sockaddr_in));
591 }
592
593 void server_accept_connection(int listen_fd) {
594 struct sockaddr_storage client_addr;
595 socklen_t client_addr_length = sizeof(client_addr);
596
597 int fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_length);
598 if (fd < 0) {
599 log_errno("Failed to accept connection");
600 exit(1);
601 }
602
603 rewrite_ipv4_mapped_address(&client_addr);
604
605 if (!server_has_permission(&client_addr)) {
606 close(fd);
607 return;
608 }
609
610 log_info("Accepting connection: %s", sockaddr_tostring(&client_addr));
611
612 struct proxy_handle_accept_data* data = smalloc(sizeof(struct proxy_handle_accept_data));
613 data->fd = fd;
614 sockaddr_stringify(data->log_context, sizeof(data->log_context), &client_addr);
615 if (pthread_create(&data->tid, NULL, &proxy_handle_accept, data) != 0) {
616 log_errno("Failed to spawn thread");
617 exit(1);
618 }
619 }
620
621 int server_create_socket(int listen_port) {
622 int listen_fd = socket(AF_INET6, SOCK_STREAM, 0);
623 if (listen_fd < 0) {
624 log_errno("Failed to create socket");
625 exit(1);
626 }
627
628 int yes = 1;
629 if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) != 0) {
630 log_errno("Failed to set SO_REUSEADDR");
631 exit(1);
632 }
633
634
635 struct sockaddr_in6 server_addr;
636 memset(&server_addr, 0, sizeof(server_addr));
637 server_addr.sin6_family = AF_INET6;
638 server_addr.sin6_addr = in6addr_any;
639 server_addr.sin6_port = htons(listen_port);
640
641 if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
642 log_errno("Failed to bind to port");
643 exit(1);
644 }
645
646 if (listen(listen_fd, 5) < 0) {
647 log_errno("Failed to listen on socket");
648 exit(1);
649 }
650
651 return listen_fd;
652 }
653
654
655
656 int main() {
657 printf("socks5server " VERSION "\n");
658 log_context = "acceptor";
659
660 int listen_port = getenv_int("LISTEN_PORT");
661 int listen_fd = server_create_socket(listen_port);
662 log_info("Listening on port %d", listen_port);
663
664 for (;;) {
665 server_accept_connection(listen_fd);
666 }
667
668 return 0;
669 }