10 str2addr(char *s, uchar *a)
15 if((s = strchr(s, '!')) == nil)
17 if((p = strchr(++s, '!')) == nil)
19 if(strchr(++p, '!') != nil)
21 if(parseip(ip, s) == -1)
49 addr2str(char *proto, uchar *a){
58 if((a[0] | a[1] | a[2]) == 0 && a[3]){
60 a += strlen((char*)a)+1;
61 snprint(s, sizeof(s), "%s!%s!%d", proto, (char*)a, port);
81 n = utfnlen((char*)a, n);
82 snprint(s, sizeof(s), "%s!%.*s!%d", proto, n, (char*)a, port);
86 snprint(s, sizeof(s), "%s!%I!%d", proto, ip, port);
91 udprelay(int fd, char *dir)
97 char addr[128], ldir[40];
101 snprint(addr, sizeof(addr), "%s/udp!*!0", outside);
102 if((cfd = announce(addr, ldir)) < 0)
104 if(write(cfd, "headers", 7) != 7)
106 strcat(ldir, "/data");
107 if((rfd = open(ldir, ORDWR)) < 0)
111 if((r = rfork(RFMEM|RFPROC|RFNOWAIT)) <= 0)
114 if((cfd = listen(dir, ldir)) < 0)
116 close(fd); /* close inside udp server */
117 if((fd = accept(cfd, ldir)) < 0)
120 switch(rfork(RFMEM|RFPROC|RFNOWAIT)){
124 while((r = read(fd, msg.data, sizeof(msg.data))) > 0){
128 if(p[0] | p[1] | p[2])
138 v4tov6(msg.raddr, p);
145 memmove(msg.raddr, p, 16);
149 memmove(msg.rport, p, 2);
151 memmove(msg.data, p, r);
152 write(rfd, &msg, sizeof(Udphdr)+r);
156 while((r = read(rfd, &msg, sizeof(msg))) > 0){
165 if(r+n > sizeof(msg.data))
166 r = sizeof(msg.data)-n;
173 v6tov4(p, msg.raddr);
177 memmove(p, msg.raddr, 16);
180 memmove(p, msg.rport, 2);
182 write(fd, msg.data, r);
193 return err ? 0x5b : 0x5a;
199 main(int argc, char *argv[])
201 uchar buf[8*1024], *p;
202 char addr[128], dir[40], ldir[40], *s;
206 fmtinstall('I', eipfmt);
208 setnetmtpt(inside, sizeof(inside), 0);
209 setnetmtpt(outside, sizeof(outside), 0);
212 setnetmtpt(inside, sizeof(inside), ARGF());
215 setnetmtpt(outside, sizeof(outside), ARGF());
219 /* ver+cmd or ver+nmethod */
220 if(readn(0, buf, 2) != 2)
230 if(readn(0, buf+2, 2+4) != 2+4)
233 for(p = buf+2+2+4;; p++){
234 if(p >= buf+sizeof(buf))
236 if(read(0, p, 1) != 1)
241 /* socks 4a dom hack */
242 if((buf[4] | buf[5] | buf[6]) == 0 && buf[7]){
245 if(p >= buf+sizeof(buf))
247 if(read(0, p, 1) != 1)
256 if(readn(0, buf+2, n) != n)
261 buf[1] = 0x00; /* no authentication required */
262 if(write(1, buf, 2) != 2)
265 /* ver+cmd+res+atyp */
266 if(readn(0, buf, 4) != 4)
271 case 0x01: /* +ipv4 */
272 if(readn(0, buf+4, 4+2) != 4+2)
275 case 0x03: /* +len+dom[len] */
276 if(readn(0, buf+4, 1) != 1)
278 if((n = buf[4]) == 0)
280 if(readn(0, buf+5, n+2) != n+2)
283 case 0x04: /* +ipv6 */
284 if(readn(0, buf+4, 16+2) != 16+2)
294 case 0x01: /* CONNECT */
295 snprint(addr, sizeof(addr), "%s/tcp", outside);
296 if((s = addr2str(addr, buf)) == nil)
299 fd = dial(s, 0, dir, &cfd);
302 case 0x02: /* BIND */
303 if(myipaddr(buf, outside) < 0)
305 snprint(addr, sizeof(addr), "%s/tcp!%I!0", outside, buf);
306 fd = announce(addr, dir);
309 if(myipaddr(buf, inside) < 0)
311 snprint(addr, sizeof(addr), "%s/udp!%I!0", inside, buf);
312 fd = announce(addr, dir);
318 buf[1] = sockerr(fd < 0); /* status */
320 buf[0] = 0x00; /* vc */
322 memset(buf+2, 0, 2+4);
323 write(1, buf, 2+2+4);
327 buf[0] = socksver; /* ver */
328 buf[2] = 0x00; /* res */
330 buf[3] = 0x01; /* atyp */
331 memset(buf+4, 0, 4+2);
332 write(1, buf, 4+4+2);
336 if((nc = getnetconninfo(dir, cfd)) == nil)
338 if((n = str2addr((cmd & 0x100) ? nc->raddr : nc->laddr, buf)) <= 0)
340 if(write(1, buf, n) != n)
346 case 0x01: /* CONNECT */
348 case 0x02: /* BIND */
349 cfd = listen(dir, ldir);
354 fd = accept(cfd, dir);
361 if(udprelay(fd, dir) == 0)
362 while(read(0, buf, sizeof(buf)) > 0)
368 switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
377 while((n = read(0, buf, sizeof(buf))) > 0)
378 if(write(1, buf, n) != n)
383 postnote(PNGROUP, getpid(), "kill");