summaryrefslogtreecommitdiff
path: root/usocks/usocks.c
blob: f9b85c6ff1850ae488864d9f7418fc26c3555ac7 (plain)
    1 /* This is https://fenua.org/gaetan/src/usocks-0.7.c */
    2 /*
    3  * Copyright (C) 2013-2018, Gaetan Bisson <bisson@archlinux.org>.
    4  *
    5  * Permission to use, copy, modify, and/or distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   12  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
   14  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   15  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 /*
   19  * USocks. Minimalistic SOCKS5 proxying library.
   20  *
   21  * USocks implements a connect() function over the system one in order to
   22  * forward connections through a prescribed SOCKS5 proxy; its design focuses
   23  * are code clarity and conciseness.
   24  *
   25  * Compile with:
   26  *
   27  *   cc -O2 -fPIC -ldl -shared -o usocks.so usocks.c
   28  *
   29  * Use by exporting:
   30  *
   31  *   USOCKS_PORT=7772
   32  *   USOCKS_ADDR=127.0.0.1
   33  *   LD_PRELOAD=`pwd`/usocks.so
   34  */
   35 
   36 
   37 /* ****************************************************************************
   38  *
   39  * HEADERS
   40  *
   41  */
   42 
   43 
   44 #define _GNU_SOURCE
   45 
   46 #include <stdio.h>
   47 #include <stdlib.h>
   48 #include <string.h>
   49 #include <unistd.h>
   50 #include <fcntl.h>
   51 #include <dlfcn.h>
   52 #include <sys/socket.h>
   53 #include <netinet/in.h>
   54 #include <arpa/inet.h>
   55 
   56 
   57 /* ****************************************************************************
   58  *
   59  * INITIALIZE PROXY DATA AND LOCATE SYSTEM FUNCTIONS
   60  *
   61  */
   62 
   63 
   64 struct sockaddr_in us_proxy;
   65 
   66 typedef int (*connect_t)(int, const struct sockaddr *, socklen_t);
   67 connect_t sys_connect;
   68 
   69 int us_init (void) {
   70 	char *port = getenv("USOCKS_PORT");
   71 	char *addr = getenv("USOCKS_ADDR");
   72 	if (!port) return -1;
   73 	if (!addr) return -1;
   74 
   75 	memset(&us_proxy, 0, sizeof(us_proxy));
   76 	us_proxy.sin_family = AF_INET;
   77 	us_proxy.sin_port = htons(atoi(port));
   78 	us_proxy.sin_addr.s_addr = inet_addr(addr);
   79 
   80 	sys_connect = (connect_t)(intptr_t)dlsym(RTLD_NEXT, "connect");
   81 	return 0;
   82 }
   83 
   84 
   85 /* ****************************************************************************
   86  *
   87  * LEAVE NO BYTES BEHIND
   88  *
   89  */
   90 
   91 
   92 int us_sendall (int socket, const char *buffer, size_t length, int flags) {
   93 	int r, off=0;
   94 	while(off<length) {
   95 		r = send(socket, buffer+off, length-off, flags);
   96 		if (r<0) return -1;
   97 		off += r;
   98 	}
   99 	return off;
  100 }
  101 
  102 int us_recvall (int socket, char *buffer, size_t length, int flags) {
  103 	int r, off=0;
  104 	while (off<length) {
  105 		r = recv(socket, buffer+off, length-off, flags);
  106 		if (r<0) return -1;
  107 		off += r;
  108 	}
  109 	return off;
  110 }
  111 
  112 
  113 /* ****************************************************************************
  114  *
  115  * REDEFINE CONNECT()
  116  *
  117  */
  118 
  119 
  120 const unsigned char l4[] = { 0x7f };                                            /* matches loopback IPv4 addresses    */
  121 const unsigned char l6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };  /* matches loopback IPv6 address      */
  122 const unsigned char l64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f }; /* matches loopback IPv6to4 addresses */
  123 
  124 int connect (int sock, const struct sockaddr *addr, socklen_t len) {
  125 	int p, t, v, f=sizeof(t);
  126 	char b[256];
  127 
  128 	if (!sys_connect) if (us_init()) return -1;
  129 
  130 	/* let unix domain sockets and loopback traffic through */
  131 	switch (addr->sa_family) {
  132 		case AF_UNIX:
  133 			return sys_connect(sock,addr,len);
  134 		case AF_INET6:
  135 #if 0
  136 			if (!memcmp(&(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr), l64, 13) ||
  137 			    !memcmp(&(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr), l6, 16))
  138 				return sys_connect(sock,addr,len);
  139 #endif
  140 			v=16;
  141 			break;
  142 		case AF_INET:
  143 #if 0
  144 			/*if (!memcmp(&(((struct sockaddr_in *)addr)->sin_addr.s_addr), l4, 1))
  145 				return sys_connect(sock,addr,len);*/
  146 #endif
  147 			v=4;
  148 			break;
  149 		default:
  150 			return -1;
  151 	}
  152 
  153 	/* let non-TCP through */
  154 	getsockopt(sock, SOL_SOCKET, SO_TYPE, &t, (socklen_t *)&f);
  155 	if (t!=SOCK_STREAM) return sys_connect(sock,addr,len);
  156 
  157 	/* open blocking connection to proxy */
  158 	f = fcntl(sock, F_GETFL);
  159 	p = socket(AF_INET, SOCK_STREAM, 0);
  160 	fcntl(p, F_SETFL, f & ~O_NONBLOCK);
  161 	if (sys_connect(p,(struct sockaddr*)&us_proxy,sizeof(us_proxy))) return -1;
  162 
  163 	/* protocol version and authentication method */
  164 	memcpy(b, "\x05\x01\x00", 3);
  165 	if (us_sendall(p,b,3,0)!=3) goto err;
  166 	if (us_recvall(p,b,2,0)!=2) goto err;
  167 	if (memcmp(b,"\x05\x00",2)) goto err;
  168 
  169 	/* connection request */
  170 	memcpy(b, "\x05\x01\x00", 3);
  171 	if (v==4) {
  172 		b[3] = '\x01';
  173 		memcpy(b+4, &(((struct sockaddr_in *)addr)->sin_addr.s_addr), 4);
  174 		memcpy(b+8, &(((struct sockaddr_in *)addr)->sin_port), 2);
  175 	} else {
  176 		b[3] = '\x04';
  177 		memcpy(b+4, &(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr), 16);
  178 		memcpy(b+20, &(((struct sockaddr_in6 *)addr)->sin6_port), 2);
  179 	}
  180 	if (us_sendall(p,b,v+6,0)!=v+6) goto err;
  181 	if (us_recvall(p,b,4,0)!=4) goto err;
  182 	if (memcmp(b,"\x05\x00\x00",3)) goto err;
  183 	if (us_recvall(p,b,v+2,0)!=v+2) goto err;
  184 
  185 	/* return proxy socket */
  186 	close(sock);
  187 	fcntl(p, F_SETFL, f);
  188 	fcntl(p, F_DUPFD, sock);
  189 
  190 	return 0;
  191 
  192 err:
  193 	close(p);
  194 	return -1;
  195 }

Generated by cgit