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