123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- /** SOCKSv5 proxy that listens on port 1080.
- *
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdint.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <netdb.h>
- int proxy_data(int sockfd);
- int main(void){
- int listen_socket;
-
- struct sockaddr_in address;
- struct sockaddr_in remote_addr;
- socklen_t addr_size;
- if (!(listen_socket = socket(AF_INET, SOCK_STREAM, 0))){
- printf("Error creating socket\n");
- return 1;
- }
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = INADDR_ANY;
- address.sin_port = htons(1080);
- if(bind(listen_socket, (struct sockaddr *) &address, sizeof(address))){
- printf("Error binding socket\n");
- return 1;
- }
- if(listen(listen_socket, 10) < 0){
- printf("Error listening\n");
- close(listen_socket);
- exit(1);
- }
- for(;;){
- addr_size = sizeof(remote_addr);
- int new_socket;
- new_socket = accept(listen_socket, (struct sockaddr *) &remote_addr,
- &addr_size);
- if(new_socket < 0){
- perror("accept");
- exit(1);
- }
- int pid = fork();
- if(pid > 0){ //child
- close(listen_socket);
- proxy_data(new_socket);
- exit(0);
- }
- close(new_socket);
-
- }
- return 0;
- }
- struct socks_method_req {
- uint8_t version;
- uint8_t num_methods;
- };
- struct socks_req {
- uint8_t version;
- uint8_t cmd;
- uint8_t rsvd;
- uint8_t addr_type;
- };
- //continuously read from the socket and look for a CONNECT message
- int proxy_data(int sockfd){
- uint8_t *buffer = calloc(1, BUFSIZ);
- uint8_t *response = calloc(1, BUFSIZ);
-
- int bytes_read = recv(sockfd, buffer, BUFSIZ-1, 0);
- if (bytes_read < 0){
- printf("Error reading from socket\n");
- goto err;
- }
- printf("Received %d bytes:\n", bytes_read);
- for(int i=0; i< bytes_read; i++){
- printf("%02x ", buffer[i]);
- }
- printf("\n");
- //Respond to methods negotiation
- struct socks_method_req *clnt_meth = (struct socks_method_req *) buffer;
- uint8_t *p = buffer + 2;
- if(clnt_meth->version != 0x05){
- printf("Client supplied invalid version: %02x\n", clnt_meth->version);
- }
- int responded = 0;
- int bytes_sent;
- for(int i=0; i< clnt_meth->num_methods; i++){
- if(p[0] == 0x00){//send response with METH= 0x00
- response[0] = 0x05;
- response[1] = 0x00;
- send(sockfd, response, 2, 0);
- responded = 1;
- }
- p++;
- }
- if(!responded){//respond with METH= 0xFF
- response[0] = 0x05;
- response[1] = 0xFF;
- send(sockfd, response, 2, 0);
- goto err;
- }
- //Now wait for a connect request
- bytes_read = recv(sockfd, buffer, BUFSIZ-1, 0);
- if (bytes_read < 0){
- printf("Error reading from socket\n");
- goto err;
- }
- printf("Received %d bytes:\n", bytes_read);
- for(int i=0; i< bytes_read; i++){
- printf("%02x ", buffer[i]);
- }
- printf("\n");
- struct socks_req *clnt_req = (struct socks_req *) buffer;
- p = buffer+4;
- //see if it's a connect request
- if(clnt_req->cmd != 0x01){
- printf("Error: issued a non-connect command\n");
- goto err;
- }
- //from this point on, this code will live on slitheen relay
- struct sockaddr_in dest;
- dest.sin_family = AF_INET;
- uint8_t domain_len;
- switch(clnt_req->addr_type){
- case 0x01:
- //IPv4
- dest.sin_addr.s_addr = *((uint32_t*) p);
- printf("destination addr: %d\n", ntohl(dest.sin_addr.s_addr));
- p += 4;
- break;
-
- case 0x03:
- //domain name
- domain_len = p[0];
- p++;
- uint8_t *domain_name = calloc(1, domain_len+1);
- memcpy(domain_name, p, domain_len);
- domain_name[domain_len] = '\0';
- struct hostent *host;
- host = gethostbyname((const char *) domain_name);
- dest.sin_addr = *((struct in_addr *) host->h_addr);
- printf("destination addr: %d\n", ntohl(dest.sin_addr.s_addr));
- p += domain_len;
- free(domain_name);
- break;
- case 0x04:
- //IPv6
- goto err;//TODO: fix this
- break;
- }
- //now set the port
- dest.sin_port = *((uint16_t *) p);
- printf("destination port: %d\n", ntohs(dest.sin_port));
- int32_t handle = socket(AF_INET, SOCK_STREAM, 0);
- if(handle < 0){
- printf("error: constructing socket failed\n");
- goto err;
- }
- struct sockaddr_in my_addr;
- socklen_t my_addr_len = sizeof(my_addr);
- int32_t error = connect (handle, (struct sockaddr *) &dest, sizeof (struct sockaddr));
- if(error <0){
- printf("error connecting\n");
- goto err;
- }
- getsockname(handle, (struct sockaddr *) &my_addr, &my_addr_len);
- //now send the reply to the client
- response[0] = 0x05;
- response[1] = 0x00;//TODO: make this accurate
- response[2] = 0x00;
- response[3] = 0x01;
- *((uint32_t *) (response + 4)) = my_addr.sin_addr.s_addr;
- *((uint16_t *) (response + 8)) = my_addr.sin_port;
- printf("Bound to %x:%d\n", my_addr.sin_addr.s_addr, ntohs(my_addr.sin_port));
- bytes_sent = send(sockfd, response, 10,0);
- printf("Sent response (%d bytes):\n", bytes_sent);
- for(int i=0; i< bytes_sent; i++){
- printf("%02x ", response[i]);
- }
- printf("\n");
- //now shuffle data
- for(;;){
- fd_set readfds;
- fd_set writefds;
- int32_t nfds = (sockfd > handle) ? sockfd +1 : handle + 1;
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_SET(sockfd, &readfds);
- FD_SET(handle, &readfds);
- FD_SET(sockfd, &writefds);
- FD_SET(handle, &writefds);
- if(select(nfds, &readfds, &writefds, NULL, NULL) <0){
- printf("Select error\n");
- continue;
- }
- if(FD_ISSET(sockfd, &readfds) && FD_ISSET(handle, &writefds)){
- bytes_read = recv(sockfd, buffer, BUFSIZ-1, 0);
- if (bytes_read < 0){
- printf("Error reading from socket\n");
- goto err;
- }
- if(bytes_read > 0){
- printf("Received %d bytes:\n", bytes_read);
- for(int i=0; i< bytes_read; i++){
- printf("%02x ", buffer[i]);
- }
- printf("\n");
- bytes_sent = send(handle, buffer, bytes_read, 0);
- printf("Sent to website (%d bytes):\n", bytes_sent);
- for(int i=0; i< bytes_sent; i++){
- printf("%02x ", buffer[i]);
- }
- printf("\n");
- }
- } else if(FD_ISSET(handle, &readfds) && FD_ISSET(sockfd, &writefds)){
- bytes_read = recv(handle, buffer, BUFSIZ-1, 0);
- if (bytes_read < 0){
- printf("Error reading from socket\n");
- goto err;
- }
- if(bytes_read > 0){
- printf("Received %d bytes:\n", bytes_read);
- for(int i=0; i< bytes_read; i++){
- printf("%02x ", buffer[i]);
- }
- printf("\n");
- bytes_sent = send(sockfd, buffer, bytes_read, 0);
- printf("Sent to website (%d bytes):\n", bytes_sent);
- for(int i=0; i< bytes_sent; i++){
- printf("%02x ", buffer[i]);
- }
- printf("\n");
- }
- }
- }
- err:
- close(sockfd);
- free(buffer);
- free(response);
- exit(0);
- }
|