1 /*
2  * Stuff pertaining to bouncing through socks proxies.
3  *
4  * written by Joshua J. Drake
5  * on Nov. 4, 1998
6  *
7  * fixed bugs, nov 14 99
8  * added passwd auth, sep 26 00
9  */
10 
11 #include "irc.h"
12 #include "output.h"
13 #include "socks.h"
14 #include "vars.h"
15 
16 
17 #define SOCKS_DEBUG
18 
19 u_char *
socks4_error(int cd)20 socks4_error(int cd)
21 {
22    switch (cd)
23      {
24         case 91:
25            return "rejected or failed";
26            break;
27         case 92:
28            return "no identd";
29            break;
30         case 93:
31            return "identd response != username";
32            break;
33         default:
34            return "Unknown error";
35      }
36 }
37 
38 u_char *
socks5_error(int cd)39 socks5_error(int cd)
40 {
41    switch (cd)
42      {
43         case SOCKS5_FAIL:
44            return "Rejected or failed";
45            break;
46         case SOCKS5_AUTHORIZE:
47            return "Connection not allowed by ruleset";
48            break;
49         case SOCKS5_NETUNREACH:
50            return "Network unreachable";
51            break;
52         case SOCKS5_HOSTUNREACH:
53            return "Host unreachable";
54            break;
55         case SOCKS5_CONNREF:
56            return "Connection refused";
57            break;
58         case SOCKS5_TTLEXP:
59            return "Time to live expired";
60            break;
61         case SOCKS5_BADCMND:
62            return "Bad command";
63            break;
64         case SOCKS5_BADADDR:
65            return "Bad address";
66            break;
67         default:
68            return "Unknown error";
69      }
70 }
71 
72 /*
73  * try to negotiate a SOCKS4 connection.
74  *
75  */
76 int
socks4_connect(s,server)77 socks4_connect(s, server)
78    int s;
79    struct sockaddr_in server;
80 {
81    u_char socksreq[512], *ptr;
82    int red;
83 
84    ptr = socksreq;
85    *(ptr++) = SOCKS4_VERSION;
86    *(ptr++) = SOCKS_CONNECT;
87    memcpy(ptr, &server.sin_port, 2);
88    ptr += 2;
89    memcpy(ptr, &server.sin_addr.s_addr, 4);
90    ptr += 4;
91    strcpy(ptr, username);
92    ptr += strlen(username);
93    *ptr = '\0';
94    red = write(s, socksreq, 9 + strlen(username));
95    if (red == -1)
96      {
97 	put_error("Cannot write to socks proxy: %s", strerror(errno));
98 	return 0;
99      }
100    red = read(s, socksreq, 8);
101    if (red == -1)
102      {
103 	put_error("Cannot read from socks proxy: %s", strerror(errno));
104 	return 0;
105      }
106    if (socksreq[1] != 90)
107      {
108         put_error("Cannot connect to SOCKS4 proxy: %s", socks4_error(socksreq[1]));
109         return 0;
110      }
111    return 1;
112 }
113 
114 
115 
116 
117 
118 
119 /*
120  * send a socks auth request
121  */
122 int
socks5_send_auth_req(s)123 socks5_send_auth_req(s)
124    int s;
125 {
126    u_char req[8], *p;
127    int rl, wl;
128 
129 #ifdef SOCKS_DEBUG
130    put_info("SOCKS5: sending supported auth type request");
131 #endif
132    p = req;
133    *p++ = SOCKS5_VERSION;
134    *p++ = 2;
135    *p++ = AUTH_NONE;
136    *p++ = AUTH_PASSWD;
137 
138    rl = (int)(p - req);
139    if ((wl = write(s, req, rl)) != rl)
140      {
141 	put_error("SOCKS5: short write %d on authentication request: %s",
142 		  wl, strerror(errno));
143 	return 0;
144      }
145    return 1;
146 }
147 
148 /*
149  * read/analyze a socks response
150  */
151 int
socks5_recv_auth_rep(s)152 socks5_recv_auth_rep(s)
153    int s;
154 {
155    char rep[128];
156    int rl;
157 
158 #ifdef SOCKS_DEBUG
159    put_info("SOCKS5: reading supported auth type response");
160 #endif
161    memset(rep, 0, sizeof(rep));
162    if ((rl = read(s, rep, sizeof(rep))) < 1)
163      {
164 	put_error("SOCKS5: read failed during auth: %s", strerror(errno));
165         return 0;
166      }
167 #ifdef SOCKS_DEBUG
168    put_info("SOCKS5: selected auth type: %x", rep[1]);
169 #endif
170 
171    /* report server desired authentication (if not none) */
172    switch (rep[1])
173      {
174       case AUTH_NONE:
175 	return 1;
176 	/* all done heheh */
177       case AUTH_PASSWD:
178 	return 2;
179 	/* :) */
180       default:
181 	put_error("Cannot use SOCKS proxy, server wants type %x authentication.", rep[1]);
182 	return 0;
183 	/* :( */
184      }
185    /* not reached... */
186    return 0;
187 }
188 
189 /*
190  * send the username/password
191  */
192 int
socks5_send_userpass_req(s)193 socks5_send_userpass_req(s)
194    int s;
195 {
196    char req[512], *p;
197    char *user, *pass;
198    int rl, wl;
199 
200    /* try username and password */
201    user = get_string_var(SOCKS_USERNAME_VAR);
202    pass = get_string_var(SOCKS_PASSWORD_VAR);
203    if (!user || !*user
204        || !pass || !*pass)
205      {
206 	put_error("SOCKS5: no username/passsword specified.");
207 	return 0;
208      }
209 #ifdef SOCKS_DEBUG
210    put_info("SOCKS5: sending user/pass request: %s/%s", user,pass);
211 #endif
212 
213    memset(req, 0, sizeof(req));
214    p = req;
215    *(p++) = 0x01;
216    *(p++) = (char)strlen(user);
217    strncpy(p, user, sizeof(req) - 1 - (p - req));
218    p += strlen(user);
219    *(p++) = strlen(pass);
220    strncpy(p, pass, sizeof(req) - 1 - (p - req));
221    p += strlen(pass);
222    rl = (int)(p - req);
223 
224    if ((wl = write(s, req, rl)) != rl)
225      {
226 	put_error("SOCKS5: short write %d during USER/PASS negotiation: %s",
227 		  wl, strerror(errno));
228 	return 0;
229      }
230    return 1;
231 }
232 
233 /*
234  * read the user/pass response
235  */
236 int
socks5_recv_userpass_rep(s)237 socks5_recv_userpass_rep(s)
238    int s;
239 {
240    char rep[128];
241    int rl;
242 
243 #ifdef SOCKS_DEBUG
244    put_info("SOCKS5: reading user/pass response");
245 #endif
246    memset(rep, 0, sizeof(rep));
247    if ((rl = read(s, rep, sizeof(rep))) == -1)
248      {
249 	put_error("SOCKS5: read failed during USER/PASS auth: %s", strerror(errno));
250 	return 0;
251      }
252    if (rep[1] != 0)
253      {
254 	put_error("SOCKS5: USER or PASS incorrect.");
255 	return 0;
256      }
257 #ifdef SOCKS_DEBUG
258    put_info("SOCKS5: user/pass accepted");
259 #endif
260    return 1;
261 }
262 
263 
264 /*
265  * send a socks5 connect request...
266  */
267 int
socks5_send_connect_req(s,server)268 socks5_send_connect_req(s, server)
269    int s;
270    struct sockaddr_in server;
271 {
272    char req[128], *p;
273    int wl, rl;
274 
275    p = req;
276    *p++ = SOCKS5_VERSION;
277    *p++ = SOCKS_CONNECT;
278    *p++ = 0;
279    *p++ = SOCKS5_IPV4ADDR;
280    memcpy(p, &(server.sin_addr.s_addr), 4);
281    p += 4;
282    memcpy(p, &(server.sin_port), 2);
283    p += 2;
284 
285    put_info("SOCKS5: Connecting through proxy to: %s:%u...",
286 	    inet_ntoa(server.sin_addr), ntohs(server.sin_port));
287 
288    rl = (int)(p - req);
289    if ((wl = write(s, req, rl)) != 10)
290      {
291 	put_error("SOCKS5: short write %d on connect: %s", wl, strerror(errno));
292 	return 0;
293      }
294    return 1;
295 }
296 
297 
298 /*
299  * receive a socks5 connect response
300  */
301 int
socks5_recv_connect_rep(s)302 socks5_recv_connect_rep(s)
303    int s;
304 {
305    char req[128], tb[256];
306    int rl;
307    struct sockaddr_in sin;
308    unsigned short ts;
309 
310 #ifdef SOCKS_DEBUG
311    put_info("SOCKS5: reading connect response");
312 #endif
313    if ((rl = read(s, req, sizeof(req))) < 1)
314      {
315 	put_error("SOCKS5: read failed during bounce: %s", strerror(errno));
316 	return 0;
317      }
318    if (req[0] != SOCKS5_VERSION)
319      {
320 	put_error("SOCKS5: This is not a SOCKS version 5 proxy.");
321 	return 0;
322      }
323    if (req[1] != SOCKS5_NOERR)
324      {
325 	put_error("SOCKS5: server failed: %s", socks5_error(req[1]));
326 	return 0;
327      }
328    /*
329     * parse the rest of the response..
330     */
331    switch (req[3])
332      {
333       case 1:
334 	memcpy(&(sin.sin_addr.s_addr), req+4, sizeof(sin.sin_addr.s_addr));
335 	memcpy(&(sin.sin_port), req+8, sizeof(sin.sin_port));
336 	put_info("SOCKS5: bounce successful, your address will be: %s:%d",
337 		 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
338 	break;
339       case 3:
340 	ts = (u_short)req[4];
341 	memcpy(tb, req+5, MIN(ts, sizeof(tb)-1));
342 	tb[MIN(ts, sizeof(tb)-1)] = '\0';
343 	memcpy(&(sin.sin_port), req + ts + 5, sizeof(sin.sin_port));
344 	put_info("SOCKS5: bounce successful, your address will be: %s:%d",
345 		 tb, ntohs(sin.sin_port));
346 	break;
347       case 4:
348 	/* don't report address of ipv6 addresses. */
349 	put_info("SOCKS bounce successful.");
350 	break;
351       default:
352 	put_error("SOCKS5: Unknown address type: %x", req[3]);
353 	return 0;
354      }
355    return 1;
356 }
357 
358 
359 /*
360  * try to negotiate a SOCKS5 connection. (with the socket/username, to the server)
361  */
362 int
socks5_connect(s,server)363 socks5_connect(s, server)
364    int s;
365    struct sockaddr_in server;
366 {
367    /* propose desired authentication */
368    if (!socks5_send_auth_req(s))
369      return 0;
370 
371    /* get response */
372    switch (socks5_recv_auth_rep(s))
373      {
374       case 1:
375 	/* no-auth */
376 	break;
377       case 2:
378 	if (!socks5_send_userpass_req(s))
379 	  return 0;
380 	if (!socks5_recv_userpass_rep(s))
381 	  return 0;
382 	break;
383       default:
384 	return 0;
385      }
386 
387    /* try to bounce to target */
388    if (!socks5_send_connect_req(s, server))
389      return 0;
390 
391    /* read the response... */
392    if (!socks5_recv_connect_rep(s))
393      return 0;
394    return 1;
395 }
396