]> code.delx.au - proxy/blob - socks5server.c
Makefile cleanups
[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 #ifndef VERSION
20 #define VERSION "dev"
21 #endif
22
23
24 /***********
25 * Logging *
26 ***********/
27
28 static __thread char* log_context = "";
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 static __thread char* errno_string = NULL;
84 static __thread size_t errno_string_len = 0;
85
86 void realloc_errno_string() {
87 if (errno_string_len == 0) {
88 errno_string_len = 1;
89 } else {
90 errno_string_len *= 2;
91 }
92 errno_string = realloc(errno_string, errno_string_len);
93 }
94
95 char* sstrerrno() {
96 int original_errno = errno;
97 while (strerror_r(original_errno, errno_string, errno_string_len) != 0) {
98 realloc_errno_string();
99 }
100 return errno_string;
101 }
102
103 void* smalloc(size_t sz) {
104 void* ptr = calloc(1, sz);
105 if (ptr == NULL) {
106 log_error("Memory allocation failed: %s", sstrerrno());
107 exit(1);
108 }
109 return ptr;
110 }
111
112
113 /**********
114 * Config *
115 **********/
116
117 extern char** environ;
118
119 int getenv_int(char* key) {
120 char* value = getenv(key);
121 if (value == NULL) {
122 log_error("Missing environment variable: %s", key);
123 exit(1);
124 }
125
126 return atoi(value);
127 }
128
129 char* extract_env_value(char* str) {
130 char ch;
131 while ((ch = *str++)) {
132 if (ch == '=') {
133 return str;
134 }
135 }
136 return "";
137 }
138
139 bool getenv_list_matcher(char* key, bool (*matches)(char*, void*), void* data) {
140 size_t key_length = strlen(key);
141
142 char** ptr = environ;
143
144 while (*ptr) {
145 if (strncmp(*ptr, key, key_length) == 0) {
146 char* value = extract_env_value(*ptr);
147 if (matches(value, data)) {
148 return true;
149 }
150 }
151 ++ptr;
152 }
153
154 return false;
155 }
156
157
158
159
160 /**************
161 * Network IO *
162 **************/
163
164 bool ssend(int fd, void* buf, size_t len) {
165 while (len > 0) {
166 ssize_t sz = send(fd, buf, len, MSG_NOSIGNAL);
167 if (sz < 0) {
168 log_warn("Failed to write, closing connection: %s", sstrerrno());
169 return false;
170 }
171 buf += sz;
172 len -= sz;
173 }
174 return true;
175 }
176
177 ssize_t srecv(int fd, void* buf, size_t len) {
178 return recv(fd, buf, len, 0);
179 }
180
181 bool read_bytes(int fd, uint8_t* value, ssize_t sz) {
182 if (srecv(fd, value, sz) != sz) {
183 log_warn("Failed to read from client socket: %s", sstrerrno());
184 return false;
185 }
186 for (ssize_t i = 0; i < sz; ++i) {
187 log_debug("got byte: %x", value[i]);
188 }
189 return true;
190 }
191
192 bool read_byte_check(int fd, uint8_t expected, char* msg) {
193 uint8_t actual;
194 if (!read_bytes(fd, &actual, 1)) {
195 return false;
196 }
197 if (actual != expected) {
198 log_warn("%s", msg);
199 return false;
200 }
201 return true;
202 }
203
204
205
206 /**********
207 * Server *
208 **********/
209
210 void proxy_copy_fd(int wfd, int rfd) {
211 log_debug("proxy_copy_fd %d %d", wfd, rfd);
212
213 char buf[32768];
214
215 for (;;) {
216 log_debug("proxy_copy_fd blocking on read %d", rfd);
217 int bufsz = srecv(rfd, buf, sizeof(buf));
218 log_debug("proxy_copy_fd unblocked from read %d", rfd);
219 if (bufsz < 0) {
220 log_warn("Failed to read, closing connection: %s", sstrerrno());
221 break;
222 }
223 if (bufsz == 0) {
224 log_debug("proxy_copy_fd end of file %d %d", wfd, rfd);
225 break;
226 }
227
228 log_debug("proxy_copy_fd blocking on write %d", wfd);
229 if (!ssend(wfd, buf, bufsz)) {
230 log_warn("Failed to write, closing connection: %s", sstrerrno());
231 break;
232 }
233 log_debug("proxy_copy_fd unblocked from write %d", wfd);
234 }
235
236 shutdown(wfd, SHUT_WR);
237 shutdown(rfd, SHUT_RD);
238 }
239
240
241 struct proxy_copy_from_dest_data {
242 pthread_t tid;
243 int src_fd;
244 int dst_fd;
245 char log_context[INET6_ADDRSTRLEN];
246 };
247
248 void* proxy_copy_from_dest(void* _data) {
249 struct proxy_copy_from_dest_data* data = (struct proxy_copy_from_dest_data*)_data;
250 log_context_set(data->log_context);
251
252 proxy_copy_fd(data->dst_fd, data->src_fd);
253
254 log_context_clear();
255 free(data);
256
257 return NULL;
258 }
259
260 bool proxy_create_copy_from_dest_thread(int dst_fd, int src_fd) {
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 (!(((uint32_t*)(addr_data))[0] == 0 &&
595 ((uint32_t*)(addr_data))[1] == 0 &&
596 ((uint32_t*)(addr_data))[2] == htonl(0xffff)))
597 {
598 return;
599 }
600
601 struct sockaddr_in new_addr;
602 memset(&new_addr, 0, sizeof(struct sockaddr));
603 new_addr.sin_family = AF_INET;
604 memcpy(&new_addr.sin_addr.s_addr, &((struct sockaddr_in6*)addr)->sin6_addr.s6_addr[12], 4);
605 memcpy(addr, &new_addr, sizeof(struct sockaddr_in));
606 }
607
608 void server_accept_connection(int listen_fd) {
609 struct sockaddr_storage client_addr;
610 socklen_t client_addr_length = sizeof(client_addr);
611
612 int fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_length);
613 if (fd < 0) {
614 log_error("Failed to accept connection: %s", sstrerrno());
615 exit(1);
616 }
617
618 rewrite_ipv4_mapped_address(&client_addr);
619
620 if (!server_has_permission(&client_addr)) {
621 close(fd);
622 return;
623 }
624
625 log_info("Accepting connection: %s", sockaddr_tostring(&client_addr));
626
627 struct proxy_handle_accept_data* data = smalloc(sizeof(struct proxy_handle_accept_data));
628 data->fd = fd;
629 sockaddr_stringify(data->log_context, sizeof(data->log_context), &client_addr);
630 if (pthread_create(&data->tid, NULL, &proxy_handle_accept, data) != 0) {
631 log_error("Failed to spawn thread: %s", sstrerrno());
632 exit(1);
633 }
634 }
635
636 int server_create_socket(int listen_port) {
637 int listen_fd = socket(AF_INET6, SOCK_STREAM, 0);
638 if (listen_fd < 0) {
639 log_error("Failed to create socket: %s", sstrerrno());
640 exit(1);
641 }
642
643 int yes = 1;
644 if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) != 0) {
645 log_error("Failed to set SO_REUSEADDR: %s", sstrerrno());
646 exit(1);
647 }
648
649
650 struct sockaddr_in6 server_addr;
651 memset(&server_addr, 0, sizeof(server_addr));
652 server_addr.sin6_family = AF_INET6;
653 server_addr.sin6_addr = in6addr_any;
654 server_addr.sin6_port = htons(listen_port);
655
656 if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
657 log_error("Failed to bind to port: %s", sstrerrno());
658 exit(1);
659 }
660
661 if (listen(listen_fd, 5) < 0) {
662 log_error("Failed to listen on socket: %s", sstrerrno());
663 exit(1);
664 }
665
666 return listen_fd;
667 }
668
669
670
671 int main() {
672 printf("socks5server " VERSION "\n");
673 log_context = "acceptor";
674
675 int listen_port = getenv_int("LISTEN_PORT");
676 int listen_fd = server_create_socket(listen_port);
677 log_info("Listening on port %d", listen_port);
678
679 for (;;) {
680 server_accept_connection(listen_fd);
681 }
682
683 return 0;
684 }