socksd: socks4 and socks4a support
This commit is contained in:
parent
a57252cadb
commit
2fec3c0bc8
1 changed files with 149 additions and 77 deletions
|
@ -2,6 +2,8 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <ip.h>
|
#include <ip.h>
|
||||||
|
|
||||||
|
int socksver;
|
||||||
|
|
||||||
int
|
int
|
||||||
str2addr(char *s, uchar *a)
|
str2addr(char *s, uchar *a)
|
||||||
{
|
{
|
||||||
|
@ -16,18 +18,28 @@ str2addr(char *s, uchar *a)
|
||||||
return 0;
|
return 0;
|
||||||
if(parseip(ip, s) == -1)
|
if(parseip(ip, s) == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
a0 = a;
|
a0 = a;
|
||||||
if(isv4(ip)){
|
if(socksver == 4){
|
||||||
*a++ = 0x01;
|
a += 2;
|
||||||
|
hnputs(a, atoi(p));
|
||||||
|
a += 2;
|
||||||
v6tov4(a, ip);
|
v6tov4(a, ip);
|
||||||
a += 4;
|
a += 4;
|
||||||
} else {
|
} else {
|
||||||
*a++ = 0x04;
|
a += 3;
|
||||||
memmove(a, ip, 16);
|
if(isv4(ip)){
|
||||||
a += 16;
|
*a++ = 0x01;
|
||||||
|
v6tov4(a, ip);
|
||||||
|
a += 4;
|
||||||
|
} else {
|
||||||
|
*a++ = 0x04;
|
||||||
|
memmove(a, ip, 16);
|
||||||
|
a += 16;
|
||||||
|
}
|
||||||
|
hnputs(a, atoi(p));
|
||||||
|
a += 2;
|
||||||
}
|
}
|
||||||
hnputs(a, atoi(p));
|
|
||||||
a += 2;
|
|
||||||
return a - a0;
|
return a - a0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,96 +49,148 @@ addr2str(char *proto, uchar *a){
|
||||||
uchar ip[16];
|
uchar ip[16];
|
||||||
int n, port;
|
int n, port;
|
||||||
|
|
||||||
switch(*a++){
|
if(socksver == 4){
|
||||||
default:
|
a += 2;
|
||||||
abort();
|
port = nhgets(a);
|
||||||
return 0;
|
a += 2;
|
||||||
case 0x01:
|
if((a[0] | a[1] | a[2]) == 0 && a[3]){
|
||||||
|
a += 4;
|
||||||
|
a += strlen((char*)a)+1;
|
||||||
|
snprint(s, sizeof(s), "%s!%s!%d", proto, (char*)a, port);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
v4tov6(ip, a);
|
v4tov6(ip, a);
|
||||||
port = nhgets(a+4);
|
} else {
|
||||||
break;
|
a += 3;
|
||||||
case 0x04:
|
switch(*a++){
|
||||||
memmove(ip, a, 16);
|
default:
|
||||||
port = nhgets(a+16);
|
return nil;
|
||||||
break;
|
case 0x01:
|
||||||
case 0x03:
|
v4tov6(ip, a);
|
||||||
n = *a++;
|
port = nhgets(a+4);
|
||||||
port = nhgets(a+n);
|
break;
|
||||||
snprint(s, sizeof(s), "%s!%.*s!%d", proto, n, (char*)a, port);
|
case 0x04:
|
||||||
return s;
|
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);
|
snprint(s, sizeof(s), "%s!%I!%d", proto, ip, port);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sockerr(void)
|
sockerr(int err)
|
||||||
{
|
{
|
||||||
return 1; /* general error */
|
/* general error */
|
||||||
|
if(socksver == 4)
|
||||||
|
return err ? 0x5b : 0x5a;
|
||||||
|
else
|
||||||
|
return err != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
uchar buf[8*1024];
|
uchar buf[8*1024], *p;
|
||||||
|
char dir[40], *s;
|
||||||
NetConnInfo *nc;
|
NetConnInfo *nc;
|
||||||
int fd, cfd, v, n;
|
int fd, cfd, n;
|
||||||
|
|
||||||
fmtinstall('I', eipfmt);
|
fmtinstall('I', eipfmt);
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
|
||||||
nc = nil;
|
/* ver+cmd or ver+nmethod */
|
||||||
fd = cfd = -1;
|
|
||||||
|
|
||||||
/* negotiation */
|
|
||||||
if(readn(0, buf, 2) != 2)
|
if(readn(0, buf, 2) != 2)
|
||||||
return;
|
return;
|
||||||
v = buf[0];
|
socksver = buf[0];
|
||||||
n = buf[1];
|
if(socksver < 4)
|
||||||
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;
|
return;
|
||||||
Loop:
|
if(socksver > 5)
|
||||||
/* request */
|
socksver = 5;
|
||||||
if(readn(0, buf, 4) != 4)
|
|
||||||
return;
|
if(socksver == 4){
|
||||||
switch(buf[3]){
|
/* port+ip4 */
|
||||||
default:
|
if(readn(0, buf+2, 2+4) != 2+4)
|
||||||
return;
|
|
||||||
case 0x01: /* ipv4 */
|
|
||||||
if(readn(0, buf+4, 4+2) != 4+2)
|
|
||||||
return;
|
return;
|
||||||
break;
|
/* +user\0 */
|
||||||
case 0x03: /* domain name */
|
for(p = buf+2+2+4;; p++){
|
||||||
if(readn(0, buf+4, 1) != 1)
|
if(p >= buf+sizeof(buf))
|
||||||
|
return;
|
||||||
|
if(read(0, p, 1) != 1)
|
||||||
|
return;
|
||||||
|
if(*p == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* socks 4a dom hack */
|
||||||
|
if((buf[4] | buf[5] | buf[6]) == 0 && buf[7]){
|
||||||
|
/* +dom\0 */
|
||||||
|
for(++p;; p++){
|
||||||
|
if(p >= buf+sizeof(buf))
|
||||||
|
return;
|
||||||
|
if(read(0, p, 1) != 1)
|
||||||
|
return;
|
||||||
|
if(*p == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* nmethod */
|
||||||
|
if((n = buf[1]) > 0)
|
||||||
|
if(readn(0, buf+2, n) != n)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* ver+method */
|
||||||
|
buf[0] = socksver;
|
||||||
|
buf[1] = 0x00; /* no authentication required */
|
||||||
|
if(write(1, buf, 2) != 2)
|
||||||
return;
|
return;
|
||||||
if((n = buf[4]) == 0)
|
|
||||||
|
/* ver+cmd+res+atyp */
|
||||||
|
if(readn(0, buf, 4) != 4)
|
||||||
return;
|
return;
|
||||||
if(readn(0, buf+5, n+2) != n+2)
|
switch(buf[3]){
|
||||||
|
default:
|
||||||
return;
|
return;
|
||||||
break;
|
case 0x01: /* +ipv4 */
|
||||||
case 0x04: /* ipv6 */
|
if(readn(0, buf+4, 4+2) != 4+2)
|
||||||
if(readn(0, buf+4, 16+2) != 16+2)
|
return;
|
||||||
|
break;
|
||||||
|
case 0x03: /* +len+dom[len] */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nc = nil;
|
||||||
|
dir[0] = 0;
|
||||||
|
fd = cfd = -1;
|
||||||
|
switch(buf[1]){
|
||||||
|
case 0x01: /* CONNECT */
|
||||||
|
if((s = addr2str("tcp", buf)) == nil)
|
||||||
return;
|
return;
|
||||||
|
fd = dial(s, 0, dir, &cfd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cmd */
|
|
||||||
switch(buf[1]){
|
|
||||||
case 0x01: /* CONNECT */
|
|
||||||
fd = dial(addr2str("tcp", buf+3), 0, 0, &cfd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(fd >= 0){
|
if(fd >= 0){
|
||||||
if((nc = getnetconninfo(nil, fd)) == nil){
|
if((nc = getnetconninfo(dir, -1)) == nil){
|
||||||
if(cfd >= 0)
|
if(cfd >= 0)
|
||||||
close(cfd);
|
close(cfd);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -134,23 +198,31 @@ Loop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* response */
|
/* reply */
|
||||||
buf[0] = v;
|
buf[1] = sockerr(fd < 0); /* status */
|
||||||
buf[1] = (fd < 0) ? sockerr() : 0;
|
if(socksver == 4){
|
||||||
buf[2] = 0x00; /* res */
|
buf[0] = 0x00; /* vc */
|
||||||
if(fd < 0){
|
if(fd < 0){
|
||||||
buf[3] = 0x01; /* atype */
|
memset(buf+2, 0, 2+4);
|
||||||
memset(buf+4, 0, 4+2);
|
write(1, buf, 2+2+4);
|
||||||
if(write(1, buf, 4+4+2) != 4+4+2)
|
|
||||||
return;
|
return;
|
||||||
goto Loop;
|
}
|
||||||
|
} else {
|
||||||
|
buf[0] = socksver; /* ver */
|
||||||
|
buf[2] = 0x00; /* res */
|
||||||
|
if(fd < 0){
|
||||||
|
buf[3] = 0x01; /* atyp */
|
||||||
|
memset(buf+4, 0, 4+2);
|
||||||
|
write(1, buf, 4+4+2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if((n = str2addr(nc->laddr, buf+3)) <= 2)
|
if((n = str2addr(nc->laddr, buf)) <= 0)
|
||||||
return;
|
return;
|
||||||
if(write(1, buf, 3+n) != 3+n)
|
if(write(1, buf, n) != n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* rely data */
|
/* reley data */
|
||||||
switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
|
switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
|
||||||
case -1:
|
case -1:
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue