2 Copyright (C) 2011-4ever rofl0r
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 // possible defines: (nothing) -> uses getaddrinfo,
20 // thus pulling in dependencies to malloc, free, gai_strerror et al, and even printf
21 // this increases the binary size by around 50 KB. supports all methods.
22 // NO_DNS_SUPPORT -> supports only method 0 (client submits ipv4). binary size is only ~25KB
23 // IPV4_ONLY -> uses gethostbyname for dns lookup.
24 // unfortunately most modern libcs just call getaddrinfo internally.
25 // IPV4_ONLY + USE_FIREDNS supports DNS via firedns. pulls dependecies to firedns.
26 // should still be much smaller than gethostbyname/getaddrinfo.
27 // NO_LOG - no output at all
28 // NO_IDSWITCH - do not compile possibility to switch uid/gid
29 // NO_DAEMONIZE - disable daemonize, which pulls in fork and other deps.
36 #include <arpa/inet.h>
40 #include "../rocksock/rocksockserver.h"
42 #include "../rocksock/endianness.h"
44 #include "../lib/include/stringptr.h"
45 #include "../lib/include/strlib.h"
46 #include "../lib/include/optparser.h"
47 #include "../lib/include/proclib.h"
51 #include "../lib/include/logger.h"
52 #define LOGP(X) log_perror(X)
53 #define LOGPUTS(F, X) log_puts(F, X)
54 #define LOGPUTD(F, X, Y) log_putd(F, X, Y)
55 #define LOGTS(X) log_timestamp(X)
56 #define LOGPUT(F, ...) log_put(F, __VA_ARGS__)
59 #define LOGP(X) do {} while(0)
60 #define LOGPUTS(F, X) do {} while(0)
61 #define LOGPUTD(F, X, Y) do {} while(0)
62 #define LOGTS(X) do {} while(0)
63 #define LOGPUT(F, ...) do {} while(0)
67 #define CONFIG_DAEMONIZE 1
69 #define CONFIG_DAEMONIZE 0
73 #define CONFIG_IDSWITCH 1
75 #define CONFIG_IDSWITCH 0
81 #error USE_FIREDNS requires IPV4_ONLY too
89 #define CONFIG_FIREDNS 1
90 #include "../firedns/include/firedns.h"
91 static firedns_state fire
;
92 static void init_firedns(void) {
94 firedns_add_server(&fire
, "8.8.4.4");
95 firedns_add_server(&fire
, "8.8.8.8");
98 #define CONFIG_FIREDNS 0
99 #define init_firedns() do {} while(0)
100 #define firedns_resolveip4(...) 0
103 #ifndef NO_DNS_SUPPORT
109 #ifndef USER_BUFSIZE_KB
110 #define USER_BUFSIZE_KB 4
113 #ifndef USER_MAX_CONN
114 #define USER_MAX_CONN 32
117 #define CLIENT_BUFSIZE (USER_BUFSIZE_KB * 1024)
120 #define MSG_NOSIGNAL 0
126 struct addrinfo
* hostaddr
;
127 struct addrinfo hostaddr_buf
;
135 } rfc1928_authmethod
;
139 EC_GENERAL_FAILURE
= 1,
141 EC_NET_UNREACHABLE
= 3,
142 EC_HOST_UNREACHABLE
= 4,
145 EC_COMMAND_NOT_SUPPORTED
= 7,
146 EC_ADDRESSTYPE_NOT_SUPPORTED
= 8,
166 SS_AWAITING_AUTH_PACKET
,
167 SS_AWAITING_DISCONNECT
,
176 unsigned char buf
[CLIENT_BUFSIZE
];
187 rocksockserver serva
;
192 socksbuffer clientbuffers
[USER_MAX_CONN
];
193 fdinfo clients
[USER_MAX_CONN
* 2];
194 rfc1928_authmethod accepted_authmethod
;
198 // dont waste buffers for stdin, out, err
199 #define MAX_FD (3 + (USER_MAX_CONN * 2))
200 #define fdindex(a) (a - 3)
202 static void logstart(void) {
203 LOGPUTS(1, SPL("["));
205 LOGPUTS(1, SPL("] "));
208 static void printfd(int fd
) {
209 LOGPUTS(1, SPLITERAL("("));
211 LOGPUTS(1, SPLITERAL(")"));
214 static inline socksbuffer
* find_free_buffer(socksserver
* srv
) {
216 for(i
= 0; i
< USER_MAX_CONN
; i
++) {
217 if(srv
->clientbuffers
[i
].state
== BS_UNUSED
) return &srv
->clientbuffers
[i
];
222 static int socksserver_write(socksserver
* srv
, int fd
);
225 static void socksserver_disconnect_client(socksserver
* srv
, int fd
, int forced
) {
226 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
228 if(CONFIG_LOG
&& srv
->log
) {
231 LOGPUT(1, VARISL(" disconnect, forced: "), VARII(forced
), NULL
);
234 if(forced
) rocksockserver_disconnect_client(&srv
->serva
, fd
);
235 client
->state
= SS_DISCONNECTED
;
237 client
->data
->state
= BS_UNUSED
;
238 client
->data
->start
= 0;
239 client
->data
->used
= 0;
242 if(client
->target_fd
!= -1) fdflag
= 1;
243 fd
= client
->target_fd
;
244 client
->target_fd
= -1;
247 srv
->clients
[fdindex(fd
)].target_fd
= -1;
248 socksserver_disconnect_client(srv
, fd
, 1);
252 static int socksserver_on_clientdisconnect (void* userdata
, int fd
) {
253 socksserver
* srv
= (socksserver
*) userdata
;
254 // fdinfo* client = &srv->clients[fdindex(fd)];
255 //if(client->target_fd != -1) socksserver_disconnect_client(srv, client->target_fd, 0);
256 socksserver_disconnect_client(srv
, fd
, 0);
260 static char* get_client_ip(struct sockaddr_storage
* ip
, char* buffer
, size_t bufsize
) {
262 if(ip
->ss_family
== PF_INET
)
263 return (char*) inet_ntop(PF_INET
, &((struct sockaddr_in
*) ip
)->sin_addr
, buffer
, bufsize
);
264 else return (char*) inet_ntop(PF_INET6
, &((struct sockaddr_in6
*) ip
)->sin6_addr
, buffer
, bufsize
);
267 stringfromipv4(((unsigned char*)(&((struct sockaddr_in
*)ip
)->sin_addr
)), buffer
);
274 static int socksserver_on_clientconnect (void* userdata
, struct sockaddr_storage
* clientaddr
, int fd
) {
275 socksserver
* srv
= (socksserver
*) userdata
;
278 if(CONFIG_LOG
&& srv
->log
&& clientaddr
) {
281 LOGPUT(1, VARISL(" connect from: "), VARIC(get_client_ip(clientaddr
, buffer
, sizeof(buffer
))), NULL
);
284 if(fd
< 3 || fd
>= MAX_FD
) {
285 rocksockserver_disconnect_client(&srv
->serva
, fd
);
289 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
291 // put into nonblocking mode, so that writes will not block the server
292 int flags
= fcntl(fd
, F_GETFL
);
293 if(flags
== -1) return -1;
294 if(fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1) return -2;
296 client
->data
= find_free_buffer(srv
);
298 if(CONFIG_LOG
&& srv
->log
) {
300 LOGPUTS(1, SPL("warning: couldnt find free buffer\n"));
302 rocksockserver_disconnect_client(&srv
->serva
, fd
);
306 client
->state
= SS_CONNECTED
;
307 client
->data
->state
= BS_IDLE
;
308 client
->data
->start
= 0;
309 client
->target_fd
= -1;
314 static int socksserver_on_clientwantsdata (void* userdata
, int fd
) {
315 socksserver
* srv
= (socksserver
*) userdata
;
317 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
319 if(client
->target_fd
>= 0 && srv
->clients
[fdindex(client
->target_fd
)].state
== SS_AWAITING_PIPE
)
320 srv
->clients
[fdindex(client
->target_fd
)].state
= SS_WIRED
;
322 if(client
->data
->state
== BS_WRITING
)
323 socksserver_write(srv
, fd
);
328 // returns either the one authmethod supported by the server or AM_INVALID.
329 static rfc1928_authmethod
socksserver_parse_authpacket(socksserver
* srv
, int fd
) {
330 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
331 unsigned char numMethods
;
334 if(client
->data
->start
< 3) return AM_INVALID
;
335 if(client
->data
->buf
[0] != 5) return AM_INVALID
;
336 numMethods
= client
->data
->buf
[1];
337 for(i
= 0; i
< numMethods
&& (2U + i
) < client
->data
->start
; i
++) {
338 if(client
->data
->buf
[2 + i
] == (unsigned char) srv
->accepted_authmethod
)
339 return srv
->accepted_authmethod
;
344 static int socksserver_read_client(socksserver
* srv
, int fd
) {
345 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
348 if ((nbytes
= recv(fd
, client
->data
->buf
+ client
->data
->start
, CLIENT_BUFSIZE
- client
->data
->start
, 0)) <= 0) {
349 socksserver_on_clientdisconnect(srv
, fd
);
350 rocksockserver_disconnect_client(&srv
->serva
, fd
);
353 client
->data
->start
+= nbytes
;
354 client
->data
->used
+= nbytes
;
358 static int socksserver_write(socksserver
* srv
, int fd
) {
359 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
360 client
->data
->state
= BS_WRITING
;
361 ssize_t written
= send(fd
, client
->data
->buf
+ client
->data
->start
, client
->data
->used
- client
->data
->start
, MSG_NOSIGNAL
);
366 if(err
== EAGAIN
|| err
== EWOULDBLOCK
) return 0;
370 socksserver_disconnect_client(srv
, fd
, 1);
371 rocksockserver_disconnect_client(&srv
->serva
, fd
);
374 } else if ((size_t) written
== client
->data
->used
- client
->data
->start
)
375 client
->data
->state
= BS_IDLE
;
380 +----+-----+-------+------+----------+----------+
381 |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
382 +----+-----+-------+------+----------+----------+
383 | 1 | 1 | X'00' | 1 | Variable | 2 |
384 +----+-----+-------+------+----------+----------+
386 static int socksserver_send_error(socksserver
* srv
, int fd
, rfc1928_errorcode ec
) {
387 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
389 client
->data
->buf
[i
++] = 5;
390 client
->data
->buf
[i
++] = ec
;
391 client
->data
->buf
[i
++] = 0;
393 client
->data
->buf
[i
++] = AT_IPV4
;
394 client
->data
->buf
[i
++] = 0;
395 client
->data
->buf
[i
++] = 0;
396 client
->data
->buf
[i
++] = 0;
397 client
->data
->buf
[i
++] = 0;
399 client
->data
->buf
[i
++] = 0;
400 client
->data
->buf
[i
++] = 0;
402 client
->data
->used
= i
;
403 client
->data
->start
= 0;
404 client
->data
->state
= BS_WRITING
;
405 return socksserver_write(srv
, fd
);
408 static int socksserver_send_auth_response_i(socksserver
* srv
, int fd
, int version
, rfc1928_authmethod meth
) {
409 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
410 client
->data
->buf
[0] = version
;
411 client
->data
->buf
[1] = meth
;
412 client
->data
->state
= BS_WRITING
;
413 client
->data
->start
= 0;
414 client
->data
->used
= 2;
415 return socksserver_write(srv
, fd
);
418 #define socksserver_send_auth_response(SRV, FD, METH) socksserver_send_auth_response_i(SRV, FD, 5, METH)
422 Once the SOCKS V5 server has started, and the client has selected the
423 Username/Password Authentication protocol, the Username/Password
424 subnegotiation begins. This begins with the client producing a
425 Username/Password request:
427 +----+------+----------+------+----------+
428 |VER | ULEN | UNAME | PLEN | PASSWD |
429 +----+------+----------+------+----------+
430 | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
431 +----+------+----------+------+----------+
433 The VER field contains the current version of the subnegotiation,
434 which is X'01'. The ULEN field contains the length of the UNAME field
435 that follows. The UNAME field contains the username as known to the
436 source operating system. The PLEN field contains the length of the
437 PASSWD field that follows. The PASSWD field contains the password
438 association with the given UNAME.
440 The server verifies the supplied UNAME and PASSWD, and sends the
449 A STATUS field of X'00' indicates success. If the server returns a
450 `failure' (STATUS value other than X'00') status, it MUST close the
454 // return 0 when packet is not complete, 1 if successfull, -1 if not
455 static int socksserver_check_credentials(socksserver
* srv
, int fd
) {
456 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
458 unsigned char ulen
, plen
;
459 unsigned char* buf
= client
->data
->buf
;
460 if(client
->data
->start
< 5) return 0;
461 if(buf
[i
++] != 1) return -1;
463 if(client
->data
->start
< i
+ ulen
+ 2) return 0; // passwd must be at least 1 char long
464 if(ulen
!= srv
->username
.size
|| memcmp(buf
+ i
, srv
->username
.ptr
, ulen
)) return -1;
467 if(client
->data
->start
< i
+ plen
) return 0;
468 if(plen
!= srv
->password
.size
|| memcmp(buf
+ i
, srv
->password
.ptr
, plen
)) return -1;
472 static inline uint16_t my_ntohs (unsigned char* port
) {
473 #ifdef IS_LITTLE_ENDIAN
474 return (port
[0] * 256) + port
[1];
476 return port
[0] + (port
[1] * 256);
480 static int resolve_host(host_info
* hostinfo
) {
481 if (!hostinfo
|| !hostinfo
->host
|| !hostinfo
->port
) return -1;
484 struct addrinfo hints
;
485 memset(&hints
, 0, sizeof(hints
));
486 hints
.ai_family
= PF_UNSPEC
;
487 hints
.ai_socktype
= SOCK_STREAM
;
488 ret
= getaddrinfo(hostinfo
->host
, NULL
, &hints
, &hostinfo
->hostaddr
);
490 if(hostinfo
->hostaddr
->ai_addr
->sa_family
== PF_INET
)
491 ((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_port
= htons(hostinfo
->port
);
493 ((struct sockaddr_in6
*) hostinfo
->hostaddr
->ai_addr
)->sin6_port
= htons(hostinfo
->port
);
498 struct in_addr
*result
;
501 result
= firedns_resolveip4(&fire
, hostinfo
->host
);
502 if(!result
) return 1;
504 if (!(he
= gethostbyname(hostinfo
->host
)) || !he
->h_addr_list
[0] || he
->h_addrtype
!= AF_INET
) return -2;
506 hostinfo
->hostaddr
->ai_family
= AF_INET
;
507 hostinfo
->hostaddr
->ai_addr
->sa_family
= AF_INET
;
508 hostinfo
->hostaddr
->ai_addrlen
= sizeof(struct sockaddr_in
);
510 memcpy(&((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_addr
, result
, 4);
512 memcpy(&((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_addr
, he
->h_addr_list
[0], 4);
513 ((struct sockaddr_in
*) hostinfo
->hostaddr
->ai_addr
)->sin_port
= htons(hostinfo
->port
);
519 The SOCKS request is formed as follows:
521 +----+-----+-------+------+----------+----------+
522 |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
523 +----+-----+-------+------+----------+----------+
524 | 1 | 1 | X'00' | 1 | Variable | 2 |
525 +----+-----+-------+------+----------+----------+
529 o VER protocol version: X'05'
533 o UDP ASSOCIATE X'03'
535 o ATYP address type of following address
536 o IP V4 address: X'01'
538 o IP V6 address: X'04'
539 o DST.ADDR desired destination address
540 o DST.PORT desired destination port in network octet
543 The SOCKS server will typically evaluate the request based on source
544 and destination addresses, and return one or more reply messages, as
545 appropriate for the request type.
547 In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies
548 the type of address contained within the field:
552 the address is a version-4 IP address, with a length of 4 octets
556 the address field contains a fully-qualified domain name. The first
557 octet of the address field contains the number of octets of name that
558 follow, there is no terminating NUL octet.
562 the address is a version-6 IP address, with a length of 16 octets.
567 // parses the connect request and tries to establish the requested connection.
568 // returns -1 if packet is not complete
570 static int socksserver_connect_request(socksserver
* srv
, int fd
) {
571 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
573 unsigned char dlen
= 0;
574 unsigned char* buf
= client
->data
->buf
;
578 struct addrinfo addrbuf
;
579 struct sockaddr sockbuf
;
581 memset(&addr
, 0, sizeof(addr
));
582 memset(&addrbuf
, 0, sizeof(addrbuf
));
583 memset(&sockbuf
, 0, sizeof(sockbuf
));
585 addrbuf
.ai_addr
= &sockbuf
;
586 addr
.hostaddr
= &addrbuf
;
589 if(!client
->data
->start
) return -1;
590 if(buf
[i
++] != 5) return EC_NOT_ALLOWED
; // check first byte whenever the message length is > 0 to not waste resources on maldoers
591 if(client
->data
->start
< 1+1+1+1+4+2) return -1;
593 if(buf
[i
++] != 1) return EC_COMMAND_NOT_SUPPORTED
; // we support only the connect method.
594 if(buf
[i
++] != 0) return EC_GENERAL_FAILURE
;
598 memcpy(&((struct sockaddr_in
*) addr
.hostaddr
->ai_addr
)->sin_addr
, buf
+ 4, 4);
599 memcpy(&((struct sockaddr_in
*) addr
.hostaddr
->ai_addr
)->sin_port
, buf
+ 8, 2);
600 ((struct sockaddr_in
*) addr
.hostaddr
->ai_addr
)->sin_family
= PF_INET
;
601 addr
.hostaddr
->ai_addr
->sa_family
= PF_INET
;
602 addr
.hostaddr
->ai_addrlen
= sizeof(struct sockaddr_in
);
608 if(client
->data
->start
< 1U+1U+1U+1U+1U+dlen
+2U) return -1;
609 addr
.port
= my_ntohs(buf
+ i
+ dlen
);
611 addr
.host
= (char*) (buf
+ i
);
612 if(CONFIG_IPV6
) addr
.hostaddr
= NULL
;
613 if(!resolve_host(&addr
)) {
615 memcpy(&addrbuf
, addr
.hostaddr
, sizeof(struct addrinfo
));
616 freeaddrinfo(addr
.hostaddr
);
617 addr
.hostaddr
= &addrbuf
;
619 } else goto notsupported
;
621 } else goto notsupported
;
624 if(client
->data
->start
< 1+1+1+1+16+2) return -1;
625 memcpy(&((struct sockaddr_in6
*) addr
.hostaddr
->ai_addr
)->sin6_addr
, buf
+ 4, 16);
626 memcpy(&((struct sockaddr_in6
*) addr
.hostaddr
->ai_addr
)->sin6_port
, buf
+ 20, 2);
627 ((struct sockaddr_in6
*) addr
.hostaddr
->ai_addr
)->sin6_family
= PF_INET6
;
628 addr
.hostaddr
->ai_addr
->sa_family
= PF_INET6
;
629 addr
.hostaddr
->ai_addrlen
= sizeof(struct sockaddr_in6
);
634 return EC_ADDRESSTYPE_NOT_SUPPORTED
;
636 client
->target_fd
= socket(addr
.hostaddr
->ai_addr
->sa_family
, SOCK_STREAM
, 0);
637 if(client
->target_fd
== -1) {
640 case ENETDOWN
: case ENETUNREACH
: case ENETRESET
:
641 return EC_NET_UNREACHABLE
;
642 case EHOSTUNREACH
: case EHOSTDOWN
:
643 return EC_HOST_UNREACHABLE
;
645 return EC_CONN_REFUSED
;
647 return EC_GENERAL_FAILURE
;
651 if(client
->target_fd
>= MAX_FD
) {
652 close(client
->target_fd
);
653 return EC_GENERAL_FAILURE
;
656 flags
= fcntl(client
->target_fd
, F_GETFL
);
657 if(flags
== -1) return EC_GENERAL_FAILURE
;
659 if(fcntl(client
->target_fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1) return EC_GENERAL_FAILURE
;
661 ret
= connect(client
->target_fd
, addr
.hostaddr
->ai_addr
, addr
.hostaddr
->ai_addrlen
);
664 if (!(ret
== EINPROGRESS
|| ret
== EWOULDBLOCK
))
668 srv
->clients
[fdindex(client
->target_fd
)].state
= SS_SOCKSTARGET
;
669 srv
->clients
[fdindex(client
->target_fd
)].data
= client
->data
;
670 srv
->clients
[fdindex(client
->target_fd
)].target_fd
= fd
;
671 rocksockserver_watch_fd(&srv
->serva
, client
->target_fd
);
673 if(CONFIG_LOG
&& srv
->log
) {
674 if(get_client_ip((struct sockaddr_storage
*) addr
.hostaddr
->ai_addr
, (char*) buf
, CLIENT_BUFSIZE
)) {
677 LOGPUTS(1, SPLITERAL(" -> "));
678 printfd(client
->target_fd
);
679 LOGPUT(1, VARISL(" <"), VARIC((char*)buf
), VARISL(">"), NULL
);
687 The client connects to the server, and sends a version
688 identifier/method selection message:
690 +----+----------+----------+
691 |VER | NMETHODS | METHODS |
692 +----+----------+----------+
694 +----+----------+----------+
696 The VER field is set to X'05' for this version of the protocol. The
697 NMETHODS field contains the number of method identifier octets that
698 appear in the METHODS field.
700 The server selects from one of the methods given in METHODS, and
701 sends a METHOD selection message:
709 If the selected METHOD is X'FF', none of the methods listed by the
710 client are acceptable, and the client MUST close the connection.
712 static int socksserver_on_clientread (void* userdata
, int fd
, size_t dummy
) {
713 socksserver
* srv
= (socksserver
*) userdata
;
714 fdinfo
* client
= &srv
->clients
[fdindex(fd
)];
715 rfc1928_authmethod authmethod
;
722 if(client
->state
== SS_AWAITING_PIPE
|| (client
->data
->state
!= BS_IDLE
&& client
->data
->state
!= BS_READING
)) {
723 if((readv
= recvfrom(fd
, buf
, 4, MSG_PEEK
, NULL
, NULL
)) <= 0) {
725 socksserver_on_clientdisconnect(userdata
, fd
);
728 rocksockserver_disconnect_client(&srv
->serva
, fd
);
733 if(client
->state
== SS_WIRED
|| client
->state
== SS_SOCKSTARGET
) {
734 client
->data
->start
= 0;
735 client
->data
->used
= 0;
738 if(socksserver_read_client(srv
, fd
))
741 switch(client
->state
) {
742 case SS_AWAITING_DISCONNECT
:
743 socksserver_disconnect_client(srv
, fd
, 1);
746 if((authmethod
= socksserver_parse_authpacket(srv
, fd
)) != AM_INVALID
) {
747 if(authmethod
== AM_USERNAME
)
748 client
->state
= SS_AWAITING_AUTH_PACKET
;
750 client
->state
= SS_AUTHED
;
752 client
->state
= SS_AWAITING_DISCONNECT
;
754 socksserver_send_auth_response(srv
, fd
, authmethod
);
756 case SS_AWAITING_AUTH_PACKET
:
757 ret
= socksserver_check_credentials(srv
, fd
);
760 client
->state
= SS_AWAITING_DISCONNECT
;
761 socksserver_send_auth_response_i(srv
, fd
, 1, AM_INVALID
);
763 client
->state
= SS_AUTHED
;
764 socksserver_send_auth_response_i(srv
, fd
, 1, 0);
768 ret
= socksserver_connect_request(srv
, fd
);
769 if(ret
== -1) return 4;
771 client
->state
= SS_AWAITING_DISCONNECT
;
773 client
->state
= SS_AWAITING_PIPE
;
775 socksserver_send_error(srv
, fd
, ret
);
778 if(srv
->clients
[fdindex(client
->target_fd
)].state
== SS_AWAITING_PIPE
)
779 srv
->clients
[fdindex(client
->target_fd
)].state
= SS_WIRED
;
780 client
->data
->start
= 0;
781 socksserver_write(srv
, client
->target_fd
);
784 client
->data
->start
= 0;
785 socksserver_write(srv
, client
->target_fd
);
793 static int socksserver_init(socksserver
* srv
, char* listenip
, int port
, int log
, stringptr
* username
, stringptr
* pass
, int uid
, int gid
) {
794 memset(srv
, 0, sizeof(socksserver
));
796 if(rocksockserver_init(&srv
->serva
, listenip
, port
, (void*) srv
)) return -1;
798 if(CONFIG_IDSWITCH
) {
799 //dropping privs after bind()
800 if(gid
!= -1 && setgid(gid
) == -1) LOGP("setgid");
801 if(gid
!= -1 && setgroups(0, NULL
) == -1) LOGP("setgroups");
802 if(uid
!= -1 && setuid(uid
) == -1) LOGP("setuid");
806 memcpy(srv
->_username
, username
->ptr
, username
->size
);
807 srv
->username
.ptr
= srv
->_username
;
808 srv
->username
.size
= username
->size
;
809 memset(username
->ptr
, 0, username
->size
);
813 memcpy(srv
->_password
, pass
->ptr
, pass
->size
);
814 srv
->password
.ptr
= srv
->_password
;
815 srv
->password
.size
= pass
->size
;
816 memset(pass
->ptr
, 0, pass
->size
);
819 srv
->accepted_authmethod
= username
->size
? AM_USERNAME
: AM_NO_AUTH
;
822 if(rocksockserver_loop(&srv
->serva
, NULL
, 0, &socksserver_on_clientconnect
, &socksserver_on_clientread
, &socksserver_on_clientwantsdata
, &socksserver_on_clientdisconnect
)) return -2;
826 __attribute__ ((noreturn
))
827 static void syntax(op_state
* opt
) {
828 LOGPUTS(1, SPL("progname -listenip=0.0.0.0 -port=1080 -log=0 -uid=0 -gid=0 -user=foo -pass=bar -d\n"));
829 LOGPUTS(1, SPL("user and pass are regarding socks authentication\n"));
830 LOGPUTS(1, SPL("passed options were:\n"));
831 if(CONFIG_LOG
) op_printall(opt
);
835 int main(int argc
, char** argv
) {
837 static const char defaultip
[] = "127.0.0.1";
838 op_state opt_storage
, *opt
= &opt_storage
;
839 op_init(opt
, argc
, argv
);
840 SPDECLAREC(o_port
, op_get(opt
, SPL("port")));
841 SPDECLAREC(o_listenip
, op_get(opt
, SPL("listenip")));
845 SPDECLAREC(o_log
, op_get(opt
, SPL("log")));
846 log
= o_log
->size
? strtoint(o_log
->ptr
, o_log
->size
) : 1;
850 if(CONFIG_IDSWITCH
) {
851 SPDECLAREC(o_uid
, op_get(opt
, SPL("uid")));
852 SPDECLAREC(o_gid
, op_get(opt
, SPL("gid")));
853 uid
= o_uid
->size
? strtoint(o_uid
->ptr
, o_uid
->size
) : -1;
854 gid
= o_gid
->size
? strtoint(o_gid
->ptr
, o_gid
->size
) : -1;
859 SPDECLAREC(o_user
, op_get(opt
, SPL("user")));
860 SPDECLAREC(o_pass
, op_get(opt
, SPL("pass")));
862 char* ip
= o_listenip
->size
? o_listenip
->ptr
: (char*) defaultip
;
863 int port
= o_port
->size
? strtoint(o_port
->ptr
, o_port
->size
) : 1080;
865 if(CONFIG_LOG
&& op_hasflag(opt
, SPLITERAL("-help"))) syntax(opt
);
867 if((o_user
->size
&& (!o_pass
->size
|| o_user
->size
> 255)) || (o_pass
->size
&& (!o_user
->size
|| o_pass
->size
> 255))) {
868 LOGPUTS(1, SPL("fatal: username or password exceeding 255 chars, or only one of both set\n"));
871 if(CONFIG_DAEMONIZE
&& op_hasflag(opt
, SPL("d"))) daemonize();
872 socksserver_init(&srv
, ip
, port
, log
, o_user
, o_pass
, uid
, gid
);