diff options
Diffstat (limited to 'src/lib/util/socks.c')
-rw-r--r-- | src/lib/util/socks.c | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/src/lib/util/socks.c b/src/lib/util/socks.c new file mode 100644 index 000000000..ffde8a667 --- /dev/null +++ b/src/lib/util/socks.c | |||
@@ -0,0 +1,690 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/socks.c | ||
23 | * @brief SOCKS5 connection support | ||
24 | * @author Jeffrey Burdges | ||
25 | * | ||
26 | * These routines should be called only on newly active connections. | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | |||
32 | |||
33 | #define LOG(kind, ...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__) | ||
34 | |||
35 | #define LOG_STRERROR(kind, syscall) \ | ||
36 | GNUNET_log_from_strerror (kind, "util-socks", syscall) | ||
37 | |||
38 | |||
39 | /* SOCKS5 authentication methods */ | ||
40 | #define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */ | ||
41 | #define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */ | ||
42 | #define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */ | ||
43 | #define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */ | ||
44 | #define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */ | ||
45 | #define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */ | ||
46 | #define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */ | ||
47 | |||
48 | |||
49 | /* SOCKS5 connection responses */ | ||
50 | #define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */ | ||
51 | #define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */ | ||
52 | #define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */ | ||
53 | #define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */ | ||
54 | #define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */ | ||
55 | #define SOCKS5_REP_REFUSED 0x05 /* connection refused */ | ||
56 | #define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */ | ||
57 | #define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */ | ||
58 | #define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */ | ||
59 | #define SOCKS5_REP_INVADDR 0x09 /* Invalid address */ | ||
60 | |||
61 | const char * | ||
62 | SOCKS5_REP_names (int rep) | ||
63 | { | ||
64 | switch (rep) | ||
65 | { | ||
66 | case SOCKS5_REP_SUCCEEDED: | ||
67 | return "succeeded"; | ||
68 | |||
69 | case SOCKS5_REP_FAIL: | ||
70 | return "general SOCKS server failure"; | ||
71 | |||
72 | case SOCKS5_REP_NALLOWED: | ||
73 | return "connection not allowed by ruleset"; | ||
74 | |||
75 | case SOCKS5_REP_NUNREACH: | ||
76 | return "Network unreachable"; | ||
77 | |||
78 | case SOCKS5_REP_HUNREACH: | ||
79 | return "Host unreachable"; | ||
80 | |||
81 | case SOCKS5_REP_REFUSED: | ||
82 | return "connection refused"; | ||
83 | |||
84 | case SOCKS5_REP_EXPIRED: | ||
85 | return "TTL expired"; | ||
86 | |||
87 | case SOCKS5_REP_CNOTSUP: | ||
88 | return "Command not supported"; | ||
89 | |||
90 | case SOCKS5_REP_ANOTSUP: | ||
91 | return "Address not supported"; | ||
92 | |||
93 | case SOCKS5_REP_INVADDR: | ||
94 | return "Invalid address"; | ||
95 | |||
96 | default: | ||
97 | return NULL; | ||
98 | } | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Encode a string for the SOCKS5 protocol by prefixing it a byte stating its | ||
104 | * length and stripping the trailing zero byte. Truncates any string longer | ||
105 | * than 255 bytes. | ||
106 | * | ||
107 | * @param b buffer to contain the encoded string | ||
108 | * @param s string to encode | ||
109 | * @return pointer to the end of the encoded string in the buffer | ||
110 | */ | ||
111 | unsigned char * | ||
112 | SOCK5_proto_string (unsigned char *b, const char *s) | ||
113 | { | ||
114 | size_t l = strlen (s); | ||
115 | |||
116 | if (l > 255) | ||
117 | { | ||
118 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
119 | "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n"); | ||
120 | l = 255; | ||
121 | } | ||
122 | *(b++) = (unsigned char) l; | ||
123 | memcpy (b, s, l); | ||
124 | return b + l; | ||
125 | } | ||
126 | |||
127 | |||
128 | #define SOCKS5_step_greet 0 | ||
129 | #define SOCKS5_step_auth 1 | ||
130 | #define SOCKS5_step_cmd 2 | ||
131 | #define SOCKS5_step_done 3 | ||
132 | |||
133 | /** | ||
134 | * State of the SOCKS5 handshake. | ||
135 | */ | ||
136 | struct GNUNET_SOCKS_Handshake | ||
137 | { | ||
138 | /** | ||
139 | * Connection handle used for SOCKS5 | ||
140 | */ | ||
141 | struct GNUNET_CONNECTION_Handle *socks5_connection; | ||
142 | |||
143 | /** | ||
144 | * Connection handle initially returned to client | ||
145 | */ | ||
146 | struct GNUNET_CONNECTION_Handle *target_connection; | ||
147 | |||
148 | /** | ||
149 | * Transmission handle on socks5_connection. | ||
150 | */ | ||
151 | struct GNUNET_CONNECTION_TransmitHandle *th; | ||
152 | |||
153 | /** | ||
154 | * Our stage in the SOCKS5 handshake | ||
155 | */ | ||
156 | int step; | ||
157 | |||
158 | /** | ||
159 | * Precomputed SOCKS5 handshake output buffer | ||
160 | */ | ||
161 | unsigned char outbuf[1024]; | ||
162 | |||
163 | /** | ||
164 | * Pointers delineating protoocol steps in the output buffer | ||
165 | */ | ||
166 | unsigned char *(outstep[4]); | ||
167 | |||
168 | /** | ||
169 | * SOCKS5 handshake input buffer | ||
170 | */ | ||
171 | unsigned char inbuf[1024]; | ||
172 | |||
173 | /** | ||
174 | * Pointers delimiting the current step in the input buffer | ||
175 | */ | ||
176 | unsigned char *instart; | ||
177 | unsigned char *inend; | ||
178 | }; | ||
179 | |||
180 | |||
181 | /* Registering prototypes */ | ||
182 | |||
183 | void | ||
184 | register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want); | ||
185 | |||
186 | /* In fact, the client sends first rule in GNUnet suggests one could take | ||
187 | * large mac read sizes without fear of screwing up the proxied protocol, | ||
188 | * but we make a proper SOCKS5 client. */ | ||
189 | #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2) | ||
190 | |||
191 | |||
192 | struct GNUNET_CONNECTION_TransmitHandle * | ||
193 | register_sender (struct GNUNET_SOCKS_Handshake *ih); | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Conclude the SOCKS5 handshake successfully. | ||
198 | * | ||
199 | * @param ih SOCKS5 handshake, consumed here. | ||
200 | * @param c open unused connection, consumed here. | ||
201 | * @return Connection handle that becomes usable when the handshake completes. | ||
202 | */ | ||
203 | void | ||
204 | SOCKS5_handshake_done (struct GNUNET_SOCKS_Handshake *ih) | ||
205 | { | ||
206 | GNUNET_CONNECTION_acivate_proxied (ih->target_connection); | ||
207 | } | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Read one step in the SOCKS5 handshake. | ||
212 | * | ||
213 | * @param ih SOCKS5 Handshake | ||
214 | */ | ||
215 | void | ||
216 | SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih) | ||
217 | { | ||
218 | unsigned char *b = ih->instart; | ||
219 | size_t available = ih->inend - b; | ||
220 | |||
221 | int want = register_reciever_wants (ih); | ||
222 | |||
223 | if (available < want) | ||
224 | { | ||
225 | register_reciever (ih, want - available); | ||
226 | return; | ||
227 | } | ||
228 | GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0); | ||
229 | switch (ih->step) | ||
230 | { | ||
231 | case SOCKS5_step_greet: /* SOCKS5 server's greeting */ | ||
232 | if (b[0] != 5) | ||
233 | { | ||
234 | LOG (GNUNET_ERROR_TYPE_ERROR, "Not a SOCKS5 server\n"); | ||
235 | GNUNET_assert (0); | ||
236 | } | ||
237 | switch (b[1]) | ||
238 | { | ||
239 | case SOCKS5_AUTH_NOAUTH: | ||
240 | ih->step = SOCKS5_step_cmd; /* no authentication to do */ | ||
241 | break; | ||
242 | |||
243 | case SOCKS5_AUTH_USERPASS: | ||
244 | ih->step = SOCKS5_step_auth; | ||
245 | break; | ||
246 | |||
247 | case SOCKS5_AUTH_REJECT: | ||
248 | LOG (GNUNET_ERROR_TYPE_ERROR, "No authentication method accepted\n"); | ||
249 | return; | ||
250 | |||
251 | default: | ||
252 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
253 | "Not a SOCKS5 server / Nonsensical authentication\n"); | ||
254 | return; | ||
255 | } | ||
256 | b += 2; | ||
257 | break; | ||
258 | |||
259 | case SOCKS5_step_auth: /* SOCKS5 server's response to authentication */ | ||
260 | if (b[1] != 0) | ||
261 | { | ||
262 | LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 authentication failed\n"); | ||
263 | GNUNET_assert (0); | ||
264 | } | ||
265 | ih->step = SOCKS5_step_cmd; | ||
266 | b += 2; | ||
267 | break; | ||
268 | |||
269 | case SOCKS5_step_cmd: /* SOCKS5 server's response to command */ | ||
270 | if (b[0] != 5) | ||
271 | { | ||
272 | LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 protocol error\n"); | ||
273 | GNUNET_assert (0); | ||
274 | } | ||
275 | if (0 != b[1]) | ||
276 | { | ||
277 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
278 | "SOCKS5 connection error : %s\n", | ||
279 | SOCKS5_REP_names (b[1])); | ||
280 | return; | ||
281 | } | ||
282 | b += 3; | ||
283 | /* There is no reason to verify host and port afaik. */ | ||
284 | switch (*(b++)) | ||
285 | { | ||
286 | case 1: /* IPv4 */ | ||
287 | b += sizeof(struct in_addr); /* 4 */ | ||
288 | break; | ||
289 | |||
290 | case 4: /* IPv6 */ | ||
291 | b += sizeof(struct in6_addr); /* 16 */ | ||
292 | break; | ||
293 | |||
294 | case 3: /* hostname */ | ||
295 | b += *b; | ||
296 | break; | ||
297 | } | ||
298 | b += 2; /* port */ | ||
299 | if (b > ih->inend) | ||
300 | { | ||
301 | register_reciever (ih, b - ih->inend); | ||
302 | return; | ||
303 | } | ||
304 | ih->step = SOCKS5_step_done; | ||
305 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
306 | "SOCKS5 server : %s\n", | ||
307 | SOCKS5_REP_names (b[1])); | ||
308 | ih->instart = b; | ||
309 | SOCKS5_handshake_done (ih); | ||
310 | return; | ||
311 | |||
312 | case SOCKS5_step_done: | ||
313 | GNUNET_assert (0); | ||
314 | } | ||
315 | ih->instart = b; | ||
316 | /* Do not reschedule the sender unless we're done reading. | ||
317 | * I imagine this lets us avoid ever cancelling the transmit handle. */ | ||
318 | register_sender (ih); | ||
319 | } | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Callback to read from the SOCKS5 proxy. | ||
324 | * | ||
325 | * @param client the service | ||
326 | * @param handler function to call with the message | ||
327 | * @param handler_cls closure for @a handler | ||
328 | */ | ||
329 | void | ||
330 | receiver (void *cls, | ||
331 | const void *buf, | ||
332 | size_t available, | ||
333 | const struct sockaddr *addr, | ||
334 | socklen_t addrlen, | ||
335 | int errCode) | ||
336 | { | ||
337 | struct GNUNET_SOCKS_Handshake *ih = cls; | ||
338 | |||
339 | GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]); | ||
340 | GNUNET_memcpy (ih->inend, buf, available); | ||
341 | ih->inend += available; | ||
342 | SOCKS5_handshake_step (ih); | ||
343 | } | ||
344 | |||
345 | |||
346 | /** | ||
347 | * Register callback to read from the SOCKS5 proxy. | ||
348 | * | ||
349 | * @param client the service | ||
350 | * @param handler function to call with the message | ||
351 | * @param handler_cls closure for @a handler | ||
352 | */ | ||
353 | void | ||
354 | register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want) | ||
355 | { | ||
356 | GNUNET_CONNECTION_receive (ih->socks5_connection, | ||
357 | want, | ||
358 | GNUNET_TIME_relative_get_minute_ (), | ||
359 | &receiver, | ||
360 | ih); | ||
361 | } | ||
362 | |||
363 | |||
364 | /** | ||
365 | * Register SOCKS5 handshake sender | ||
366 | * | ||
367 | * @param cls closure (SOCKS handshake) | ||
368 | * @param size number of bytes available in @a buf | ||
369 | * @param buf where the callee should write the message | ||
370 | * @return number of bytes written to @a buf | ||
371 | */ | ||
372 | size_t | ||
373 | transmit_ready (void *cls, size_t size, void *buf) | ||
374 | { | ||
375 | struct GNUNET_SOCKS_Handshake *ih = cls; | ||
376 | |||
377 | /* connection.c has many routines that call us with buf == NULL : | ||
378 | * signal_transmit_error() - DNS, etc. active | ||
379 | * connect_fail_continuation() | ||
380 | * connect_probe_continuation() - timeout | ||
381 | * try_connect_using_address() - DNS failure/timeout | ||
382 | * transmit_timeout() - retry failed? | ||
383 | * GNUNET_CONNECTION_notify_transmit_ready() can schedule : | ||
384 | * transmit_timeout() - DNS still working | ||
385 | * connect_error() - DNS done but no socket? | ||
386 | * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error() | ||
387 | * We'd need to dig into the scheduler to guess at the reason, as | ||
388 | * connection.c tells us nothing itself, but mostly its timouts. | ||
389 | * Initially, we'll simply ignore this and leave massive timeouts, but | ||
390 | * maybe that should change for error handling pruposes. It appears that | ||
391 | * successful operations, including DNS resolution, do not use this. */if (NULL == buf) | ||
392 | { | ||
393 | if (0 == ih->step) | ||
394 | { | ||
395 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
396 | "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n"); | ||
397 | register_sender (ih); | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
402 | "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n", | ||
403 | ih->step); | ||
404 | GNUNET_break (0); | ||
405 | } | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | GNUNET_assert ((1024 >= size) && (size > 0)); | ||
410 | GNUNET_assert ((SOCKS5_step_done > ih->step) && (ih->step >= 0)); | ||
411 | unsigned char *b = ih->outstep[ih->step]; | ||
412 | unsigned char *e = ih->outstep[ih->step + 1]; | ||
413 | GNUNET_assert (e <= &ih->outbuf[1024]); | ||
414 | unsigned int l = e - b; | ||
415 | GNUNET_assert (size >= l); | ||
416 | GNUNET_memcpy (buf, b, l); | ||
417 | register_reciever (ih, register_reciever_wants (ih)); | ||
418 | return l; | ||
419 | } | ||
420 | |||
421 | |||
422 | /** | ||
423 | * Register SOCKS5 handshake sender | ||
424 | * | ||
425 | * @param ih handshake | ||
426 | * @return non-NULL if the notify callback was queued, | ||
427 | * NULL if we are already going to notify someone else (busy) | ||
428 | */ | ||
429 | struct GNUNET_CONNECTION_TransmitHandle * | ||
430 | register_sender (struct GNUNET_SOCKS_Handshake *ih) | ||
431 | { | ||
432 | struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES; | ||
433 | |||
434 | GNUNET_assert (SOCKS5_step_done > ih->step); | ||
435 | GNUNET_assert (ih->step >= 0); | ||
436 | if (0 == ih->step) | ||
437 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3); | ||
438 | unsigned char *b = ih->outstep[ih->step]; | ||
439 | unsigned char *e = ih->outstep[ih->step + 1]; | ||
440 | GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]); | ||
441 | ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection, | ||
442 | e - b, | ||
443 | timeout, | ||
444 | &transmit_ready, | ||
445 | ih); | ||
446 | return ih->th; | ||
447 | } | ||
448 | |||
449 | |||
450 | /** | ||
451 | * Initialize a SOCKS5 handshake for authentication via username and | ||
452 | * password. Tor uses SOCKS username and password authentication to assign | ||
453 | * programs unique circuits. | ||
454 | * | ||
455 | * @param user username for the proxy | ||
456 | * @param pass password for the proxy | ||
457 | * @return Valid SOCKS5 hanbdshake handle | ||
458 | */ | ||
459 | struct GNUNET_SOCKS_Handshake * | ||
460 | GNUNET_SOCKS_init_handshake (const char *user, const char *pass) | ||
461 | { | ||
462 | struct GNUNET_SOCKS_Handshake *ih = | ||
463 | GNUNET_new (struct GNUNET_SOCKS_Handshake); | ||
464 | unsigned char *b = ih->outbuf; | ||
465 | |||
466 | ih->outstep[SOCKS5_step_greet] = b; | ||
467 | *(b++) = 5; /* SOCKS5 */ | ||
468 | unsigned char *n = b++; | ||
469 | *n = 1; /* Number of authentication methods */ | ||
470 | /* We support no authentication even when requesting authentication, | ||
471 | * but this appears harmless, given the way that Tor uses authentication. | ||
472 | * And some SOCKS5 servers might require this. */ | ||
473 | *(b++) = SOCKS5_AUTH_NOAUTH; | ||
474 | if (NULL != user) | ||
475 | { | ||
476 | *(b++) = SOCKS5_AUTH_USERPASS; | ||
477 | (*n)++; | ||
478 | } | ||
479 | /* There is no apparent reason to support authentication methods beyond | ||
480 | * username and password since afaik Tor does not support them. */ | ||
481 | |||
482 | /* We authenticate with an empty username and password if the server demands | ||
483 | * them but we do not have any. */ | ||
484 | if (user == NULL) | ||
485 | user = ""; | ||
486 | if (pass == NULL) | ||
487 | pass = ""; | ||
488 | |||
489 | ih->outstep[SOCKS5_step_auth] = b; | ||
490 | *(b++) = 1; /* subnegotiation ver.: 1 */ | ||
491 | b = SOCK5_proto_string (b, user); | ||
492 | b = SOCK5_proto_string (b, pass); | ||
493 | |||
494 | ih->outstep[SOCKS5_step_cmd] = b; | ||
495 | |||
496 | ih->inend = ih->instart = ih->inbuf; | ||
497 | |||
498 | return ih; | ||
499 | } | ||
500 | |||
501 | |||
502 | /** | ||
503 | * Initialize a SOCKS5 handshake without authentication, thereby possibly | ||
504 | * sharing a Tor circuit with another process. | ||
505 | * | ||
506 | * @return Valid SOCKS5 hanbdshake handle | ||
507 | */ | ||
508 | struct GNUNET_SOCKS_Handshake * | ||
509 | GNUNET_SOCKS_init_handshake_noauth () | ||
510 | { | ||
511 | return GNUNET_SOCKS_init_handshake (NULL, NULL); | ||
512 | } | ||
513 | |||
514 | |||
515 | /** | ||
516 | * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host | ||
517 | * and port. | ||
518 | * | ||
519 | * @param ih SOCKS5 handshake | ||
520 | * @param host | ||
521 | * @param port | ||
522 | */ | ||
523 | void | ||
524 | GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih, | ||
525 | const char *host, | ||
526 | uint16_t port) | ||
527 | { | ||
528 | union | ||
529 | { | ||
530 | struct in_addr in4; | ||
531 | struct in6_addr in6; | ||
532 | } ia; | ||
533 | unsigned char *b = ih->outstep[SOCKS5_step_cmd]; | ||
534 | |||
535 | *(b++) = 5; /* SOCKS5 */ | ||
536 | *(b++) = 1; /* Establish a TCP/IP stream */ | ||
537 | *(b++) = 0; /* reserved */ | ||
538 | |||
539 | /* Specify destination */ | ||
540 | if (1 == inet_pton (AF_INET, host, &ia.in4)) | ||
541 | { | ||
542 | *(b++) = 1; /* IPv4 */ | ||
543 | GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr)); | ||
544 | b += sizeof(struct in_addr); /* 4 */ | ||
545 | } | ||
546 | else if (1 == inet_pton (AF_INET6, host, &ia.in6)) | ||
547 | { | ||
548 | *(b++) = 4; /* IPv6 */ | ||
549 | GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr)); | ||
550 | b += sizeof(struct in6_addr); /* 16 */ | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | *(b++) = 3; /* hostname */ | ||
555 | b = SOCK5_proto_string (b, host); | ||
556 | } | ||
557 | |||
558 | /* Specify port */ | ||
559 | *(uint16_t *) b = htons (port); | ||
560 | b += 2; | ||
561 | |||
562 | ih->outstep[SOCKS5_step_done] = b; | ||
563 | } | ||
564 | |||
565 | |||
566 | /** | ||
567 | * Run a SOCKS5 handshake on an open but unused TCP connection. | ||
568 | * | ||
569 | * @param ih SOCKS5 handshake, consumed here. | ||
570 | * @param c open unused connection, consumed here. | ||
571 | * @return Connection handle that becomes usable when the SOCKS5 handshake completes. | ||
572 | */ | ||
573 | struct GNUNET_CONNECTION_Handle * | ||
574 | GNUNET_SOCKS_run_handshake (struct GNUNET_SOCKS_Handshake *ih, | ||
575 | struct GNUNET_CONNECTION_Handle *c) | ||
576 | { | ||
577 | ih->socks5_connection = c; | ||
578 | ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c); | ||
579 | register_sender (ih); | ||
580 | |||
581 | return ih->target_connection; | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
586 | * Check if a SOCKS proxy is required by a service. Do not use local service | ||
587 | * if a SOCKS proxy port is configured as this could deanonymize a user. | ||
588 | * | ||
589 | * @param service_name name of service to connect to | ||
590 | * @param cfg configuration to use | ||
591 | * @return GNUNET_YES if so, GNUNET_NO if not | ||
592 | */ | ||
593 | int | ||
594 | GNUNET_SOCKS_check_service (const char *service_name, | ||
595 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
596 | { | ||
597 | return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") || | ||
598 | GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST"); | ||
599 | } | ||
600 | |||
601 | |||
602 | /** | ||
603 | * Try to connect to a service configured to use a SOCKS5 proxy. | ||
604 | * | ||
605 | * @param service_name name of service to connect to | ||
606 | * @param cfg configuration to use | ||
607 | * @return Connection handle that becomes usable when the handshake completes. | ||
608 | * NULL if SOCKS not configured or not configured properly | ||
609 | */ | ||
610 | struct GNUNET_CONNECTION_Handle * | ||
611 | GNUNET_SOCKS_do_connect (const char *service_name, | ||
612 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
613 | { | ||
614 | struct GNUNET_SOCKS_Handshake *ih; | ||
615 | struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */ | ||
616 | char *host0; | ||
617 | char *host1; | ||
618 | char *user; | ||
619 | char *pass; | ||
620 | unsigned long long port0; | ||
621 | unsigned long long port1; | ||
622 | |||
623 | if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg)) | ||
624 | return NULL; | ||
625 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, | ||
626 | service_name, | ||
627 | "SOCKSPORT", | ||
628 | &port0)) | ||
629 | port0 = 9050; | ||
630 | /* A typical Tor client should usually try port 9150 for the TBB too, but | ||
631 | * GNUnet can probably assume a system Tor installation. */ | ||
632 | if ((port0 > 65535) || (port0 <= 0)) | ||
633 | { | ||
634 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
635 | _ ( | ||
636 | "Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"), | ||
637 | port0, | ||
638 | service_name); | ||
639 | return NULL; | ||
640 | } | ||
641 | if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, | ||
642 | service_name, | ||
643 | "PORT", | ||
644 | &port1)) || | ||
645 | (port1 > 65535) || (port1 <= 0) || | ||
646 | (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, | ||
647 | service_name, | ||
648 | "HOSTNAME", | ||
649 | &host1))) | ||
650 | { | ||
651 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
652 | _ ( | ||
653 | "Attempting to proxy service `%s' to invalid port %d or hostname.\n"), | ||
654 | service_name, | ||
655 | port1); | ||
656 | return NULL; | ||
657 | } | ||
658 | /* Appeared to still work after host0 corrupted, so either test case is broken, or | ||
659 | this whole routine is not being called. */ | ||
660 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, | ||
661 | service_name, | ||
662 | "SOCKSHOST", | ||
663 | &host0)) | ||
664 | host0 = NULL; | ||
665 | socks5 = GNUNET_CONNECTION_create_from_connect (cfg, | ||
666 | (host0 != NULL) ? host0 | ||
667 | : "127.0.0.1", | ||
668 | port0); | ||
669 | GNUNET_free (host0); | ||
670 | |||
671 | /* Sets to NULL if they do not exist */ | ||
672 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, | ||
673 | service_name, | ||
674 | "SOCKSUSER", | ||
675 | &user); | ||
676 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, | ||
677 | service_name, | ||
678 | "SOCKSPASS", | ||
679 | &pass); | ||
680 | ih = GNUNET_SOCKS_init_handshake (user, pass); | ||
681 | GNUNET_free (user); | ||
682 | GNUNET_free (pass); | ||
683 | |||
684 | GNUNET_SOCKS_set_handshake_destination (ih, host1, port1); | ||
685 | GNUNET_free (host1); | ||
686 | return GNUNET_SOCKS_run_handshake (ih, socks5); | ||
687 | } | ||
688 | |||
689 | |||
690 | /* socks.c */ | ||