1 #define _POSIX_C_SOURCE 200809L
11 #include <bsd/string.h>
12 #include <sys/types.h>
14 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
25 static __thread
char* log_context
= "";
27 #define log_error(fmt, ...) \
28 fprintf(stderr, "ERROR [%s] " fmt "\n", log_context , ##__VA_ARGS__);
30 #define log_warn(fmt, ...) \
31 fprintf(stderr, "WARN [%s] " fmt "\n", log_context , ##__VA_ARGS__);
33 #define log_info(fmt, ...) \
34 fprintf(stderr, "INFO [%s] " fmt "\n", log_context , ##__VA_ARGS__);
37 #define log_debug(fmt, ...) \
38 fprintf(stderr, "DEBUG [%s] " fmt "\n", log_context , ##__VA_ARGS__);
40 #define log_debug(fmt, ...)
43 void log_context_set(char* new_context
) {
44 log_context
= new_context
;
45 log_debug("Thread started");
48 void log_context_clear() {
49 log_debug("Thread finished");
59 bool itoa(char* buf
, int buflen
, int64_t val
) {
60 int result
= snprintf(buf
, buflen
, "%ld", val
);
61 return result
> 0 && result
< buflen
;
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
);
70 strlcpy(dest
, "Unknown socket family", dest_length
);
74 char* sockaddr_tostring(struct sockaddr_storage
* addr
) {
75 static char buf
[INET6_ADDRSTRLEN
];
76 sockaddr_stringify(buf
, sizeof(buf
), addr
);
80 static __thread
char* errno_string
= NULL
;
81 static __thread
size_t errno_string_len
= 0;
83 void realloc_errno_string() {
84 if (errno_string_len
== 0) {
87 errno_string_len
*= 2;
89 errno_string
= realloc(errno_string
, errno_string_len
);
93 int original_errno
= errno
;
94 while (strerror_r(original_errno
, errno_string
, errno_string_len
) != 0) {
95 realloc_errno_string();
100 void* smalloc(size_t sz
) {
101 void* ptr
= calloc(1, sz
);
103 log_error("Memory allocation failed: %s", sstrerrno());
114 extern char** environ
;
116 int getenv_int(char* key
) {
117 char* value
= getenv(key
);
119 log_error("Missing environment variable: %s", key
);
126 char* extract_env_value(char* str
) {
128 while ((ch
= *str
++)) {
136 bool getenv_list_matcher(char* key
, bool (*matches
)(char*, void*), void* data
) {
137 size_t key_length
= strlen(key
);
139 char** ptr
= environ
;
142 if (strncmp(*ptr
, key
, key_length
) == 0) {
143 char* value
= extract_env_value(*ptr
);
144 if (matches(value
, data
)) {
161 bool ssend(int fd
, void* buf
, size_t len
) {
163 ssize_t sz
= send(fd
, buf
, len
, MSG_NOSIGNAL
);
165 log_warn("Failed to write, closing connection: %s", sstrerrno());
174 ssize_t
srecv(int fd
, void* buf
, size_t len
) {
175 return recv(fd
, buf
, len
, 0);
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());
183 for (ssize_t i
= 0; i
< sz
; ++i
) {
184 log_debug("got byte: %x", value
[i
]);
189 bool read_byte_check(int fd
, uint8_t expected
, char* msg
) {
191 if (!read_bytes(fd
, &actual
, 1)) {
194 if (actual
!= expected
) {
207 void proxy_copy_fd(int wfd
, int rfd
) {
208 log_debug("proxy_copy_fd %d %d", wfd
, rfd
);
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
);
217 log_warn("Failed to read, closing connection: %s", sstrerrno());
221 log_debug("proxy_copy_fd end of file %d %d", wfd
, rfd
);
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());
230 log_debug("proxy_copy_fd unblocked from write %d", wfd
);
233 shutdown(wfd
, SHUT_WR
);
234 shutdown(rfd
, SHUT_RD
);
238 struct proxy_copy_from_dest_data
{
242 char log_context
[INET6_ADDRSTRLEN
];
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
);
249 proxy_copy_fd(data
->dst_fd
, data
->src_fd
);
257 bool proxy_create_copy_from_dest_thread(
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());
272 bool proxy_negotiate_auth(int fd
) {
273 if (!read_byte_check(fd
, 5, "Client sent invalid version!")) {
278 if (!read_bytes(fd
, &nmethods
, 1)) {
282 log_warn("Client sent invalid authentication method count!");
286 uint8_t methods
[nmethods
];
287 if (!read_bytes(fd
, methods
, nmethods
)) {
290 bool found_noauth
= false;
291 for (int i
= 0; i
< nmethods
; ++i
) {
292 if (methods
[i
] == 0) {
298 ssend(fd
, "\x05\xff", 2);
299 log_warn("Client does not support no-authentication SOCKS5!");
303 if (!ssend(fd
, "\x05\x00", 2)) {
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
)) {
320 bool proxy_dns_handle_request(int* dst_fd
, int fd
) {
322 if (!read_bytes(fd
, (uint8_t*)&name_length
, 1)) {
325 if (name_length
< 1) {
326 log_warn("Client sent invalid name length!");
330 char name
[name_length
+1];
331 if (!read_bytes(fd
, (uint8_t*)name
, name_length
)) {
334 name
[name_length
] = '\0';
337 if (!read_bytes(fd
, (uint8_t*)&port_int
, 2)) {
340 port_int
= ntohs(port_int
);
342 if (!itoa(port
, sizeof(port
), port_int
)) {
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;
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);
361 log_debug("proxy_dns_handle_request getaddrinfo success");
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
);
369 if (connect(*dst_fd
, rp
->ai_addr
, rp
->ai_addrlen
) == 0) {
370 proxy_write_error_response(fd
, 0);
371 freeaddrinfo(result
);
378 proxy_write_error_response(fd
, 4);
379 freeaddrinfo(result
);
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
;
388 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin6_addr
, 16)) {
392 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin6_port
, 2)) {
396 log_debug("got addr: %s", sockaddr_tostring((struct sockaddr_storage
*)&dst_addr
));
398 *dst_fd
= socket(AF_INET6
, SOCK_STREAM
, 0);
400 log_error("Failed to create socket: %s", sstrerrno());
404 if (connect(*dst_fd
, (struct sockaddr
*)&dst_addr
, sizeof(dst_addr
)) != 0) {
405 proxy_write_error_response(fd
, 4);
409 proxy_write_error_response(fd
, 0);
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
;
418 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin_addr
, 4)) {
422 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin_port
, 2)) {
426 log_debug("got addr: %s", sockaddr_tostring((struct sockaddr_storage
*)&dst_addr
));
428 *dst_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
430 log_error("Failed to create socket: %s", sstrerrno());
434 if (connect(*dst_fd
, (struct sockaddr
*)&dst_addr
, sizeof(dst_addr
)) != 0) {
435 proxy_write_error_response(fd
, 4);
439 proxy_write_error_response(fd
, 0);
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);
449 if (!read_byte_check(fd
, 1, "Client sent invalid command!")) {
450 proxy_write_error_response(fd
, 7);
454 if (!read_byte_check(fd
, 0, "Client sent invalid reserved section!")) {
455 proxy_write_error_response(fd
, 1);
460 if (!read_bytes(fd
, &addr_type
, 1)) {
465 return proxy_ipv4_handle_request(dst_fd
, fd
);
467 return proxy_dns_handle_request(dst_fd
, fd
);
469 return proxy_ipv6_handle_request(dst_fd
, fd
);
472 proxy_write_error_response(fd
, 8);
476 struct proxy_handle_accept_data
{
479 char log_context
[INET6_ADDRSTRLEN
];
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
);
488 log_debug("proxy_negotiate_auth before %d", data
->fd
);
489 if (!proxy_negotiate_auth(data
->fd
)) {
490 log_debug("negotiate_auth fail");
494 log_debug("proxy_handle_request before");
495 if (!proxy_handle_request(&dst_fd
, data
->fd
)) {
496 log_debug("proxy_handle_request fail");
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");
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");
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;
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
);
541 return memcmp(addr1_ptr
, addr2_ptr
, length
) == 0;
544 bool sockaddr_matches_string(char* str
, void* _addr
) {
545 struct sockaddr_storage
* addr
= (struct sockaddr_storage
*)_addr
;
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;
555 if (getaddrinfo(str
, NULL
, &hints
, &result
) != 0) {
556 log_warn("sockaddr_matches_string getaddrinfo failed: %s", str
);
561 for (struct addrinfo
* rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
562 if (sockaddr_equals_addrinfo(addr
, rp
)) {
568 freeaddrinfo(result
);
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");
578 if (getenv_list_matcher("ALLOW_HOST", sockaddr_matches_string
, addr
)) {
579 log_debug("Accepting connection because it matches ALLOW_HOST entry");
583 log_info("Rejecting connection: %s", sockaddr_tostring(addr
));
588 void rewrite_ipv4_mapped_address(struct sockaddr_storage
* addr
) {
589 if (addr
->ss_family
!= AF_INET6
) {
593 struct in6_addr
* addr_data
= &((struct sockaddr_in6
*)addr
)->sin6_addr
;
595 ((uint32_t*)(addr_data
))[0] == 0 &&
596 ((uint32_t*)(addr_data
))[1] == 0 &&
597 ((uint32_t*)(addr_data
))[2] == htonl(0xffff)
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
));
609 void server_accept_connection(int listen_fd
) {
610 struct sockaddr_storage client_addr
;
611 socklen_t client_addr_length
= sizeof(client_addr
);
613 int fd
= accept(listen_fd
, (struct sockaddr
*)&client_addr
, &client_addr_length
);
615 log_error("Failed to accept connection: %s", sstrerrno());
619 rewrite_ipv4_mapped_address(&client_addr
);
621 if (!server_has_permission(&client_addr
)) {
626 log_info("Accepting connection: %s", sockaddr_tostring(&client_addr
));
628 struct proxy_handle_accept_data
* data
= smalloc(sizeof(struct proxy_handle_accept_data
));
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());
637 int server_create_socket(int listen_port
) {
638 int listen_fd
= socket(AF_INET6
, SOCK_STREAM
, 0);
640 log_error("Failed to create socket: %s", sstrerrno());
645 if (setsockopt(listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) != 0) {
646 log_error("Failed to set SO_REUSEADDR: %s", sstrerrno());
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
);
657 if (bind(listen_fd
, (struct sockaddr
*)&server_addr
, sizeof(server_addr
)) < 0) {
658 log_error("Failed to bind to port: %s", sstrerrno());
662 if (listen(listen_fd
, 5) < 0) {
663 log_error("Failed to listen on socket: %s", sstrerrno());
673 printf("socks5server " VERSION
"\n");
674 log_context
= "acceptor";
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
);
681 server_accept_connection(listen_fd
);