]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/socksd.c
merge
[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, 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 = -1;
184         switch(buf[1]){
185         case 0x01:      /* CONNECT */
186                 if((s = addr2str("tcp", buf)) == nil)
187                         return;
188                 fd = dial(s, 0, dir, 0);
189                 break;
190         }
191
192         if(fd >= 0){
193                 if((nc = getnetconninfo(dir, -1)) == nil){
194                         close(fd);
195                         fd = -1;
196                 }
197         }
198
199         /* reply */
200         buf[1] = sockerr(fd < 0);                       /* status */
201         if(socksver == 4){
202                 buf[0] = 0x00;                          /* vc */
203                 if(fd < 0){
204                         memset(buf+2, 0, 2+4);
205                         write(1, buf, 2+2+4);
206                         return;
207                 }
208         } else {
209                 buf[0] = socksver;                      /* ver */
210                 buf[2] = 0x00;                          /* res */
211                 if(fd < 0){
212                         buf[3] = 0x01;                  /* atyp */
213                         memset(buf+4, 0, 4+2);
214                         write(1, buf, 4+4+2);
215                         return;
216                 }
217         }
218         if((n = str2addr(nc->laddr, buf)) <= 0)
219                 return;
220         if(write(1, buf, n) != n)
221                 return;
222
223         /* relay data */
224         switch(rfork(RFMEM|RFPROC|RFFDG|RFNOWAIT)){
225         case -1:
226                 return;
227         case 0:
228                 dup(fd, 0);
229                 break;
230         default:
231                 dup(fd, 1);
232         }
233         while((n = read(0, buf, sizeof(buf))) > 0)
234                 if(write(1, buf, n) != n)
235                         break;
236         postnote(PNGROUP, getpid(), "kill");
237         exits(0);
238 }
239