]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/socksd.c
2128a5ff68847713c8af23791ef01acceb47e04c
[plan9front.git] / sys / src / cmd / ip / socksd.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4
5 int socksver;
6
7 int
8 str2addr(char *s, uchar *a)
9 {
10         uchar *a0, ip[16];
11         char *p;
12
13         if((s = strchr(s, '!')) == nil)
14                 return 0;
15         if((p = strchr(++s, '!')) == nil)
16                 return 0;
17         if(strchr(++p, '!') != nil)
18                 return 0;
19         if(parseip(ip, s) == -1)
20                 return 0;
21
22         a0 = a;
23         if(socksver == 4){
24                 a += 2;
25                 hnputs(a, atoi(p));
26                 a += 2;
27                 v6tov4(a, ip);
28                 a += 4;
29         } else {
30                 a += 3;
31                 if(isv4(ip)){
32                         *a++ = 0x01;
33                         v6tov4(a, ip);
34                         a += 4;
35                 } else {
36                         *a++ = 0x04;
37                         memmove(a, ip, 16);
38                         a += 16;
39                 }
40                 hnputs(a, atoi(p));
41                 a += 2;
42         }
43         return a - a0;
44 }
45
46 char*
47 addr2str(char *proto, uchar *a){
48         static char s[128];
49         uchar ip[16];
50         int n, port;
51
52         if(socksver == 4){
53                 a += 2;
54                 port = nhgets(a);
55                 a += 2;
56                 if((a[0] | a[1] | a[2]) == 0 && a[3]){
57                         a += 4;
58                         a += strlen((char*)a)+1;
59                         snprint(s, sizeof(s), "%s!%s!%d", proto, (char*)a, port);
60                         return s;
61                 }
62                 v4tov6(ip, a);
63         } else {
64                 a += 3;
65                 switch(*a++){
66                 default:
67                         return nil;
68                 case 0x01:
69                         v4tov6(ip, a);
70                         port = nhgets(a+4);
71                         break;
72                 case 0x04:
73                         memmove(ip, a, 16);
74                         port = nhgets(a+16);
75                         break;
76                 case 0x03:
77                         n = *a++;
78                         port = nhgets(a+n);
79                         snprint(s, sizeof(s), "%s!%.*s!%d", proto, n, (char*)a, port);
80                         return s;
81                 }
82         }
83         snprint(s, sizeof(s), "%s!%I!%d", proto, ip, port);
84         return s;
85 }
86
87 int
88 sockerr(int err)
89 {
90         /* general error */
91         if(socksver == 4)
92                 return err ? 0x5b : 0x5a;
93         else
94                 return err != 0;
95 }
96
97 void
98 main(int argc, char *argv[])
99 {
100         uchar buf[8*1024], *p;
101         char dir[40], *s;
102         NetConnInfo *nc;
103         int fd, cfd, n;
104
105         fmtinstall('I', eipfmt);
106
107         ARGBEGIN {
108         } ARGEND;
109
110         /* ver+cmd or ver+nmethod */
111         if(readn(0, buf, 2) != 2)
112                 return;
113         socksver = buf[0];
114         if(socksver < 4)
115                 return;
116         if(socksver > 5)
117                 socksver = 5;
118
119         if(socksver == 4){
120                 /* port+ip4 */
121                 if(readn(0, buf+2, 2+4) != 2+4)
122                         return;
123                 /* +user\0 */
124                 for(p = buf+2+2+4;; p++){
125                         if(p >= buf+sizeof(buf))
126                                 return;
127                         if(read(0, p, 1) != 1)
128                                 return;
129                         if(*p == 0)
130                                 break;
131                 }
132                 /* socks 4a dom hack */
133                 if((buf[4] | buf[5] | buf[6]) == 0 && buf[7]){
134                         /* +dom\0 */
135                         for(++p;; p++){
136                                 if(p >= buf+sizeof(buf))
137                                         return;
138                                 if(read(0, p, 1) != 1)
139                                         return;
140                                 if(*p == 0)
141                                         break;
142                         }
143                 }
144         } else {
145                 /* nmethod */
146                 if((n = buf[1]) > 0)
147                         if(readn(0, buf+2, n) != n)
148                                 return;
149
150                 /* ver+method */
151                 buf[0] = socksver;
152                 buf[1] = 0x00;  /* no authentication required */
153                 if(write(1, buf, 2) != 2)
154                         return;
155
156                 /* ver+cmd+res+atyp */
157                 if(readn(0, buf, 4) != 4)
158                         return;
159                 switch(buf[3]){
160                 default:
161                         return;
162                 case 0x01:      /* +ipv4 */
163                         if(readn(0, buf+4, 4+2) != 4+2)
164                                 return;
165                         break;
166                 case 0x03:      /* +len+dom[len] */
167                         if(readn(0, buf+4, 1) != 1)
168                                 return;
169                         if((n = buf[4]) == 0)
170                                 return;
171                         if(readn(0, buf+5, n+2) != n+2)
172                                 return;
173                         break;
174                 case 0x04:      /* +ipv6 */
175                         if(readn(0, buf+4, 16+2) != 16+2)
176                                 return;
177                         break;
178                 }
179         }
180
181         nc = nil;
182         dir[0] = 0;
183         fd = cfd = -1;
184         switch(buf[1]){
185         case 0x01:      /* CONNECT */
186                 if((s = addr2str("tcp", buf)) == nil)
187                         return;
188                 fd = dial(s, 0, dir, &cfd);
189                 break;
190         }
191
192         if(fd >= 0){
193                 if((nc = getnetconninfo(dir, -1)) == nil){
194                         if(cfd >= 0)
195                                 close(cfd);
196                         close(fd);
197                         fd = cfd = -1;
198                 }
199         }
200
201         /* reply */
202         buf[1] = sockerr(fd < 0);                       /* status */
203         if(socksver == 4){
204                 buf[0] = 0x00;                          /* vc */
205                 if(fd < 0){
206                         memset(buf+2, 0, 2+4);
207                         write(1, buf, 2+2+4);
208                         return;
209                 }
210         } else {
211                 buf[0] = socksver;                      /* ver */
212                 buf[2] = 0x00;                          /* res */
213                 if(fd < 0){
214                         buf[3] = 0x01;                  /* atyp */
215                         memset(buf+4, 0, 4+2);
216                         write(1, buf, 4+4+2);
217                         return;
218                 }
219         }
220         if((n = str2addr(nc->laddr, buf)) <= 0)
221                 return;
222         if(write(1, buf, n) != n)
223                 return;
224
225         /* reley data */
226         switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
227         case -1:
228                 return;
229         case 0:
230                 dup(fd, 0);
231                 break;
232         default:
233                 dup(fd, 1);
234         }
235         close(fd);
236         while((n = read(0, buf, sizeof(buf))) > 0)
237                 if(write(1, buf, n) != n)
238                         break;
239         if(cfd >= 0)
240                 hangup(cfd);
241         exits(0);
242 }
243