8 str2addr(char *s, uchar *a)
13 if((s = strchr(s, '!')) == nil)
15 if((p = strchr(++s, '!')) == nil)
17 if(strchr(++p, '!') != nil)
19 if(parseip(ip, s) == -1)
47 addr2str(char *proto, uchar *a){
56 if((a[0] | a[1] | a[2]) == 0 && a[3]){
58 a += strlen((char*)a)+1;
59 snprint(s, sizeof(s), "%s!%s!%d", proto, (char*)a, port);
79 snprint(s, sizeof(s), "%s!%.*s!%d", proto, n, (char*)a, port);
83 snprint(s, sizeof(s), "%s!%I!%d", proto, ip, port);
92 return err ? 0x5b : 0x5a;
98 main(int argc, char *argv[])
100 uchar buf[8*1024], *p;
105 fmtinstall('I', eipfmt);
110 /* ver+cmd or ver+nmethod */
111 if(readn(0, buf, 2) != 2)
121 if(readn(0, buf+2, 2+4) != 2+4)
124 for(p = buf+2+2+4;; p++){
125 if(p >= buf+sizeof(buf))
127 if(read(0, p, 1) != 1)
132 /* socks 4a dom hack */
133 if((buf[4] | buf[5] | buf[6]) == 0 && buf[7]){
136 if(p >= buf+sizeof(buf))
138 if(read(0, p, 1) != 1)
147 if(readn(0, buf+2, n) != n)
152 buf[1] = 0x00; /* no authentication required */
153 if(write(1, buf, 2) != 2)
156 /* ver+cmd+res+atyp */
157 if(readn(0, buf, 4) != 4)
162 case 0x01: /* +ipv4 */
163 if(readn(0, buf+4, 4+2) != 4+2)
166 case 0x03: /* +len+dom[len] */
167 if(readn(0, buf+4, 1) != 1)
169 if((n = buf[4]) == 0)
171 if(readn(0, buf+5, n+2) != n+2)
174 case 0x04: /* +ipv6 */
175 if(readn(0, buf+4, 16+2) != 16+2)
185 case 0x01: /* CONNECT */
186 if((s = addr2str("tcp", buf)) == nil)
188 fd = dial(s, 0, dir, &cfd);
193 if((nc = getnetconninfo(dir, -1)) == nil){
202 buf[1] = sockerr(fd < 0); /* status */
204 buf[0] = 0x00; /* vc */
206 memset(buf+2, 0, 2+4);
207 write(1, buf, 2+2+4);
211 buf[0] = socksver; /* ver */
212 buf[2] = 0x00; /* res */
214 buf[3] = 0x01; /* atyp */
215 memset(buf+4, 0, 4+2);
216 write(1, buf, 4+4+2);
220 if((n = str2addr(nc->laddr, buf)) <= 0)
222 if(write(1, buf, n) != n)
226 switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
236 while((n = read(0, buf, sizeof(buf))) > 0)
237 if(write(1, buf, n) != n)