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