git: 9front

Download patch

ref: 25c833cdd5193cc655ea4869dfff766a7a9b8346
parent: a3f3d5a3caf3168127b16825bb003e26852c9d37
author: cinap_lenrek <cinap_lenrek@rei2.9hal>
date: Thu Mar 1 19:34:41 EST 2012

socksd: simple socks server (no manpage yet)

--- a/sys/src/cmd/ip/mkfile
+++ b/sys/src/cmd/ip/mkfile
@@ -22,6 +22,7 @@
 	traceroute\
 	torrent\
 	udpecho\
+	socksd\
 	wol\
 
 DIRS=ftpfs cifsd dhcpd httpd ipconfig ppp imap4d snoopy
--- /dev/null
+++ b/sys/src/cmd/ip/socksd.c
@@ -1,0 +1,171 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+
+int
+str2addr(char *s, uchar *a)
+{
+	uchar *a0, ip[16];
+	char *p;
+
+	if((s = strchr(s, '!')) == nil)
+		return 0;
+	if((p = strchr(++s, '!')) == nil)
+		return 0;
+	if(strchr(++p, '!') != nil)
+		return 0;
+	if(parseip(ip, s) == -1)
+		return 0;
+	a0 = a;
+	if(isv4(ip)){
+		*a++ = 0x01;
+		v6tov4(a, ip);
+		a += 4;
+	} else {
+		*a++ = 0x04;
+		memmove(a, ip, 16);
+		a += 16;
+	}
+	hnputs(a, atoi(p));
+	a += 2;
+	return a - a0;
+}
+
+char*
+addr2str(char *proto, uchar *a){
+	static char s[128];
+	uchar ip[16];
+	int n, port;
+
+	switch(*a++){
+	default:
+		abort();
+		return 0;
+	case 0x01:
+		v4tov6(ip, a);
+		port = nhgets(a+4);
+		break;
+	case 0x04:
+		memmove(ip, a, 16);
+		port = nhgets(a+16);
+		break;
+	case 0x03:
+		n = *a++;
+		port = nhgets(a+n);
+		snprint(s, sizeof(s), "%s!%.*s!%d", proto, n, (char*)a, port);
+		return s;
+	}
+	snprint(s, sizeof(s), "%s!%I!%d", proto, ip, port);
+	return s;
+}
+
+int
+sockerr(void)
+{
+	return 1;	/* general error */
+}
+
+void
+main(int argc, char *argv[])
+{
+	uchar buf[8*1024];
+	NetConnInfo *nc;
+	int fd, cfd, v, n;
+
+	fmtinstall('I', eipfmt);
+
+	ARGBEGIN {
+	} ARGEND;
+
+	nc = nil;
+	fd = cfd = -1;
+
+	/* negotiation */
+	if(readn(0, buf, 2) != 2)
+		return;
+	v = buf[0];
+	n = buf[1];
+	if(n > 0)
+		if(readn(0, buf, n) != n)
+			return;
+	if(v > 5)
+		v = 5;
+	buf[0] = v;
+	buf[1] = 0x00;	/* no authentication required */
+	if(write(1, buf, 2) != 2)
+		return;
+Loop:
+	/* request */
+	if(readn(0, buf, 4) != 4)
+		return;
+	switch(buf[3]){
+	default:
+		return;
+	case 0x01:	/* ipv4 */
+		if(readn(0, buf+4, 4+2) != 4+2)
+			return;
+		break;
+	case 0x03:	/* domain name */
+		if(readn(0, buf+4, 1) != 1)
+			return;
+		if((n = buf[4]) == 0)
+			return;
+		if(readn(0, buf+5, n+2) != n+2)
+			return;
+		break;
+	case 0x04:	/* ipv6 */
+		if(readn(0, buf+4, 16+2) != 16+2)
+			return;
+		break;
+	}
+
+	/* cmd */
+	switch(buf[1]){
+	case 0x01:	/* CONNECT */
+		fd = dial(addr2str("tcp", buf+3), 0, 0, &cfd);
+		break;
+	}
+	if(fd >= 0){
+		if((nc = getnetconninfo(nil, fd)) == nil){
+			if(cfd >= 0)
+				close(cfd);
+			close(fd);
+			fd = cfd = -1;
+		}
+	}
+
+	/* response */
+	buf[0] = v;
+	buf[1] = (fd < 0) ? sockerr() : 0;
+	buf[2] = 0x00;				/* res */
+	if(fd < 0){
+		buf[3] = 0x01;			/* atype */
+		memset(buf+4, 0, 4+2);
+		if(write(1, buf, 4+4+2) != 4+4+2)
+			return;
+		goto Loop;
+	}
+	if((n = str2addr(nc->laddr, buf+3)) <= 2)
+		return;
+	if(write(1, buf, 3+n) != 3+n)
+		return;
+
+	/* rely data */
+	switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
+	case -1:
+		return;
+	case 0:
+		dup(fd, 0);
+		break;
+	default:
+		dup(fd, 1);
+	}
+	close(fd);
+	while((n = read(0, buf, sizeof(buf))) > 0)
+		if(write(1, buf, n) != n)
+			break;
+	if(cfd >= 0)
+		hangup(cfd);
+	exits(0);
+}
+
--