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_errno(fmt, ...) \
28 fprintf(stderr, "ERROR [%s] " fmt ": %s\n", log_context , ##__VA_ARGS__ , strerror(errno));
30 #define log_error(fmt, ...) \
31 fprintf(stderr, "ERROR [%s] " fmt "\n", log_context , ##__VA_ARGS__);
33 #define log_warn(fmt, ...) \
34 fprintf(stderr, "WARN [%s] " fmt "\n", log_context , ##__VA_ARGS__);
36 #define log_info(fmt, ...) \
37 fprintf(stderr, "INFO [%s] " fmt "\n", log_context , ##__VA_ARGS__);
40 #define log_debug(fmt, ...) \
41 fprintf(stderr, "DEBUG [%s] " fmt "\n", log_context , ##__VA_ARGS__);
43 #define log_debug(fmt, ...)
46 void log_context_set(char* new_context
) {
47 log_context
= new_context
;
48 log_debug("Thread started");
51 void log_context_clear() {
52 log_debug("Thread finished");
62 bool itoa(char* buf
, int buflen
, int64_t val
) {
63 int result
= snprintf(buf
, buflen
, "%ld", val
);
64 return result
> 0 && result
< buflen
;
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
);
73 strlcpy(dest
, "Unknown socket family", dest_length
);
77 char* sockaddr_tostring(struct sockaddr_storage
* addr
) {
78 static char buf
[INET6_ADDRSTRLEN
];
79 sockaddr_stringify(buf
, sizeof(buf
), addr
);
83 void* smalloc(size_t sz
) {
84 void* ptr
= calloc(1, sz
);
86 log_errno("Memory allocation failed");
98 extern char** environ
;
100 int getenv_int(char* key
) {
101 char* value
= getenv(key
);
103 log_error("Missing environment variable: %s", key
);
110 char* extract_env_value(char* str
) {
112 while ((ch
= *str
++)) {
120 bool getenv_list_matcher(char* key
, bool (*matches
)(char*, void*), void* data
) {
121 size_t key_length
= strlen(key
);
123 char** ptr
= environ
;
126 if (strncmp(*ptr
, key
, key_length
) == 0) {
127 char* value
= extract_env_value(*ptr
);
128 if (matches(value
, data
)) {
145 bool ssend(int fd
, void* buf
, size_t len
) {
147 ssize_t sz
= send(fd
, buf
, len
, MSG_NOSIGNAL
);
149 log_errno("Failed to write, closing connection");
158 ssize_t
srecv(int fd
, void* buf
, size_t len
) {
159 return recv(fd
, buf
, len
, 0);
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");
167 for (ssize_t i
= 0; i
< sz
; ++i
) {
168 log_debug("got byte: %x", value
[i
]);
173 bool read_byte_check(int fd
, uint8_t expected
, char* msg
) {
175 if (!read_bytes(fd
, &actual
, 1)) {
178 if (actual
!= expected
) {
191 void proxy_copy_fd(int wfd
, int rfd
) {
192 log_debug("proxy_copy_fd %d %d", wfd
, rfd
);
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
);
201 log_errno("Failed to read, closing connection");
205 log_debug("proxy_copy_fd end of file %d %d", wfd
, rfd
);
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");
214 log_debug("proxy_copy_fd unblocked from write %d", wfd
);
217 shutdown(wfd
, SHUT_WR
);
218 shutdown(rfd
, SHUT_RD
);
222 struct proxy_copy_from_dest_data
{
226 char log_context
[INET6_ADDRSTRLEN
];
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
);
233 proxy_copy_fd(data
->dst_fd
, data
->src_fd
);
241 bool proxy_create_copy_from_dest_thread(
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");
256 bool proxy_negotiate_auth(int fd
) {
257 if (!read_byte_check(fd
, 5, "Client sent invalid version!")) {
262 if (!read_bytes(fd
, &nmethods
, 1)) {
266 log_warn("Client sent invalid authentication method count!");
270 uint8_t methods
[nmethods
];
271 if (!read_bytes(fd
, methods
, nmethods
)) {
274 bool found_noauth
= false;
275 for (int i
= 0; i
< nmethods
; ++i
) {
276 if (methods
[i
] == 0) {
282 ssend(fd
, "\x05\xff", 2);
283 log_warn("Client does not support no-authentication SOCKS5!");
287 if (!ssend(fd
, "\x05\x00", 2)) {
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
)) {
304 bool proxy_dns_handle_request(int* dst_fd
, int fd
) {
306 if (!read_bytes(fd
, (uint8_t*)&name_length
, 1)) {
309 if (name_length
< 1) {
310 log_warn("Client sent invalid name length!");
314 char name
[name_length
+1];
315 if (!read_bytes(fd
, (uint8_t*)name
, name_length
)) {
318 name
[name_length
] = '\0';
321 if (!read_bytes(fd
, (uint8_t*)&port_int
, 2)) {
324 port_int
= ntohs(port_int
);
326 if (!itoa(port
, sizeof(port
), port_int
)) {
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;
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);
345 log_debug("proxy_dns_handle_request getaddrinfo success");
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
);
353 if (connect(*dst_fd
, rp
->ai_addr
, rp
->ai_addrlen
) == 0) {
354 proxy_write_error_response(fd
, 0);
355 freeaddrinfo(result
);
362 proxy_write_error_response(fd
, 4);
363 freeaddrinfo(result
);
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
;
372 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin6_addr
, 16)) {
376 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin6_port
, 2)) {
380 log_debug("got addr: %s", sockaddr_tostring((struct sockaddr_storage
*)&dst_addr
));
382 *dst_fd
= socket(AF_INET6
, SOCK_STREAM
, 0);
384 log_errno("Failed to create socket");
388 if (connect(*dst_fd
, (struct sockaddr
*)&dst_addr
, sizeof(dst_addr
)) != 0) {
389 proxy_write_error_response(fd
, 4);
393 proxy_write_error_response(fd
, 0);
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
;
402 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin_addr
, 4)) {
406 if (!read_bytes(fd
, (uint8_t*)&dst_addr
.sin_port
, 2)) {
410 log_debug("got addr: %s", sockaddr_tostring((struct sockaddr_storage
*)&dst_addr
));
412 *dst_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
414 log_errno("Failed to create socket");
418 if (connect(*dst_fd
, (struct sockaddr
*)&dst_addr
, sizeof(dst_addr
)) != 0) {
419 proxy_write_error_response(fd
, 4);
423 proxy_write_error_response(fd
, 0);
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);
433 if (!read_byte_check(fd
, 1, "Client sent invalid command!")) {
434 proxy_write_error_response(fd
, 7);
438 if (!read_byte_check(fd
, 0, "Client sent invalid reserved section!")) {
439 proxy_write_error_response(fd
, 1);
444 if (!read_bytes(fd
, &addr_type
, 1)) {
449 return proxy_ipv4_handle_request(dst_fd
, fd
);
451 return proxy_dns_handle_request(dst_fd
, fd
);
453 return proxy_ipv6_handle_request(dst_fd
, fd
);
456 proxy_write_error_response(fd
, 8);
460 struct proxy_handle_accept_data
{
463 char log_context
[INET6_ADDRSTRLEN
];
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
);
472 log_debug("proxy_negotiate_auth before %d", data
->fd
);
473 if (!proxy_negotiate_auth(data
->fd
)) {
474 log_debug("negotiate_auth fail");
478 log_debug("proxy_handle_request before");
479 if (!proxy_handle_request(&dst_fd
, data
->fd
)) {
480 log_debug("proxy_handle_request fail");
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");
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");
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;
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
);
525 return memcmp(addr1_ptr
, addr2_ptr
, length
) == 0;
528 bool sockaddr_matches_string(char* str
, void* _addr
) {
529 struct sockaddr_storage
* addr
= (struct sockaddr_storage
*)_addr
;
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;
539 if (getaddrinfo(str
, NULL
, &hints
, &result
) != 0) {
540 log_warn("sockaddr_matches_string getaddrinfo failed: %s", str
);
545 for (struct addrinfo
* rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
546 if (sockaddr_equals_addrinfo(addr
, rp
)) {
552 freeaddrinfo(result
);
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");
562 if (getenv_list_matcher("ALLOW_HOST", sockaddr_matches_string
, addr
)) {
563 log_debug("Accepting connection because it matches ALLOW_HOST entry");
567 log_info("Rejecting connection: %s", sockaddr_tostring(addr
));
572 void rewrite_ipv4_mapped_address(struct sockaddr_storage
* addr
) {
573 if (addr
->ss_family
!= AF_INET6
) {
577 struct in6_addr
* addr_data
= &((struct sockaddr_in6
*)addr
)->sin6_addr
;
579 ((uint32_t*)(addr_data
))[0] == 0 &&
580 ((uint32_t*)(addr_data
))[1] == 0 &&
581 ((uint32_t*)(addr_data
))[2] == htonl(0xffff)
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
));
593 void server_accept_connection(int listen_fd
) {
594 struct sockaddr_storage client_addr
;
595 socklen_t client_addr_length
= sizeof(client_addr
);
597 int fd
= accept(listen_fd
, (struct sockaddr
*)&client_addr
, &client_addr_length
);
599 log_errno("Failed to accept connection");
603 rewrite_ipv4_mapped_address(&client_addr
);
605 if (!server_has_permission(&client_addr
)) {
610 log_info("Accepting connection: %s", sockaddr_tostring(&client_addr
));
612 struct proxy_handle_accept_data
* data
= smalloc(sizeof(struct proxy_handle_accept_data
));
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");
621 int server_create_socket(int listen_port
) {
622 int listen_fd
= socket(AF_INET6
, SOCK_STREAM
, 0);
624 log_errno("Failed to create socket");
629 if (setsockopt(listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) != 0) {
630 log_errno("Failed to set SO_REUSEADDR");
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
);
641 if (bind(listen_fd
, (struct sockaddr
*)&server_addr
, sizeof(server_addr
)) < 0) {
642 log_errno("Failed to bind to port");
646 if (listen(listen_fd
, 5) < 0) {
647 log_errno("Failed to listen on socket");
657 printf("socks5server " VERSION
"\n");
658 log_context
= "acceptor";
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
);
665 server_accept_connection(listen_fd
);