Update README to make it clear it's a _source_ README.
[u/mdw/putty] / proxy.c
CommitLineData
8eebd221 1/*
2 * Network proxy abstraction in PuTTY
3 *
4 * A proxy layer, if necessary, wedges itself between the network
5 * code and the higher level backend.
6 */
7
8#include <windows.h>
9
10#define DEFINE_PLUG_METHOD_MACROS
11#include "putty.h"
12#include "network.h"
13#include "proxy.h"
14
15/*
16 * Call this when proxy negotiation is complete, so that this
17 * socket can begin working normally.
18 */
19void proxy_activate (Proxy_Socket p)
20{
21 void *data;
22 int len;
23
8eebd221 24 p->state = PROXY_STATE_ACTIVE;
25
26 /* let's try to keep extra receive events from coming through */
27 sk_set_frozen(p->sub_socket, 1);
28
0e8f4cda 29 /* send buffered OOB writes */
8eebd221 30 while (bufchain_size(&p->pending_oob_output_data) > 0) {
31 bufchain_prefix(&p->pending_oob_output_data, &data, &len);
32 sk_write_oob(p->sub_socket, data, len);
33 bufchain_consume(&p->pending_oob_output_data, len);
34 }
35 bufchain_clear(&p->pending_oob_output_data);
36
0e8f4cda 37 /* send buffered normal writes */
8eebd221 38 while (bufchain_size(&p->pending_output_data) > 0) {
39 bufchain_prefix(&p->pending_output_data, &data, &len);
40 sk_write(p->sub_socket, data, len);
41 bufchain_consume(&p->pending_output_data, len);
42 }
43 bufchain_clear(&p->pending_output_data);
44
0e8f4cda 45 /* if we were asked to flush the output during
46 * the proxy negotiation process, do so now.
47 */
8eebd221 48 if (p->pending_flush) sk_flush(p->sub_socket);
8eebd221 49
0e8f4cda 50 /* forward buffered recv data to the backend */
8eebd221 51 while (bufchain_size(&p->pending_input_data) > 0) {
52 bufchain_prefix(&p->pending_input_data, &data, &len);
53 plug_receive(p->plug, 0, data, len);
54 bufchain_consume(&p->pending_input_data, len);
55 }
56 bufchain_clear(&p->pending_input_data);
8eebd221 57
58 /* now set the underlying socket to whatever freeze state they wanted */
59 sk_set_frozen(p->sub_socket, p->freeze);
8eebd221 60}
61
62/* basic proxy socket functions */
63
64static Plug sk_proxy_plug (Socket s, Plug p)
65{
66 Proxy_Socket ps = (Proxy_Socket) s;
67 Plug ret = ps->plug;
68 if (p)
69 ps->plug = p;
70 return ret;
71}
72
73static void sk_proxy_close (Socket s)
74{
75 Proxy_Socket ps = (Proxy_Socket) s;
76
8eebd221 77 sk_close(ps->sub_socket);
78 sfree(ps);
79}
80
81static int sk_proxy_write (Socket s, char *data, int len)
82{
83 Proxy_Socket ps = (Proxy_Socket) s;
84
8eebd221 85 if (ps->state != PROXY_STATE_ACTIVE) {
86 bufchain_add(&ps->pending_output_data, data, len);
87 return bufchain_size(&ps->pending_output_data);
88 }
89 return sk_write(ps->sub_socket, data, len);
90}
91
92static int sk_proxy_write_oob (Socket s, char *data, int len)
93{
94 Proxy_Socket ps = (Proxy_Socket) s;
95
8eebd221 96 if (ps->state != PROXY_STATE_ACTIVE) {
97 bufchain_clear(&ps->pending_output_data);
98 bufchain_clear(&ps->pending_oob_output_data);
99 bufchain_add(&ps->pending_oob_output_data, data, len);
100 return len;
101 }
102 return sk_write_oob(ps->sub_socket, data, len);
103}
104
105static void sk_proxy_flush (Socket s)
106{
107 Proxy_Socket ps = (Proxy_Socket) s;
108
8eebd221 109 if (ps->state != PROXY_STATE_ACTIVE) {
110 ps->pending_flush = 1;
111 return;
112 }
113 sk_flush(ps->sub_socket);
114}
115
116static void sk_proxy_set_private_ptr (Socket s, void *ptr)
117{
118 Proxy_Socket ps = (Proxy_Socket) s;
119 sk_set_private_ptr(ps->sub_socket, ptr);
120}
121
122static void * sk_proxy_get_private_ptr (Socket s)
123{
124 Proxy_Socket ps = (Proxy_Socket) s;
125 return sk_get_private_ptr(ps->sub_socket);
126}
127
128static void sk_proxy_set_frozen (Socket s, int is_frozen)
129{
130 Proxy_Socket ps = (Proxy_Socket) s;
131
8eebd221 132 if (ps->state != PROXY_STATE_ACTIVE) {
133 ps->freeze = is_frozen;
134 return;
135 }
136 sk_set_frozen(ps->sub_socket, is_frozen);
137}
138
139static char * sk_proxy_socket_error (Socket s)
140{
141 Proxy_Socket ps = (Proxy_Socket) s;
142 if (ps->error != NULL || ps->sub_socket == NULL) {
143 return ps->error;
144 }
145 return sk_socket_error(ps->sub_socket);
146}
147
148/* basic proxy plug functions */
149
150static int plug_proxy_closing (Plug p, char *error_msg,
151 int error_code, int calling_back)
152{
153 Proxy_Plug pp = (Proxy_Plug) p;
154 Proxy_Socket ps = pp->proxy_socket;
155
8eebd221 156 if (ps->state != PROXY_STATE_ACTIVE) {
157 ps->closing_error_msg = error_msg;
158 ps->closing_error_code = error_code;
159 ps->closing_calling_back = calling_back;
160 return ps->negotiate(ps, PROXY_CHANGE_CLOSING);
161 }
162 return plug_closing(ps->plug, error_msg,
163 error_code, calling_back);
164}
165
166static int plug_proxy_receive (Plug p, int urgent, char *data, int len)
167{
168 Proxy_Plug pp = (Proxy_Plug) p;
169 Proxy_Socket ps = pp->proxy_socket;
170
8eebd221 171 if (ps->state != PROXY_STATE_ACTIVE) {
172 /* we will lose the urgentness of this data, but since most,
173 * if not all, of this data will be consumed by the negotiation
174 * process, hopefully it won't affect the protocol above us
175 */
176 bufchain_add(&ps->pending_input_data, data, len);
177 ps->receive_urgent = urgent;
178 ps->receive_data = data;
179 ps->receive_len = len;
180 return ps->negotiate(ps, PROXY_CHANGE_RECEIVE);
181 }
182 return plug_receive(ps->plug, urgent, data, len);
183}
184
185static void plug_proxy_sent (Plug p, int bufsize)
186{
187 Proxy_Plug pp = (Proxy_Plug) p;
188 Proxy_Socket ps = pp->proxy_socket;
189
8eebd221 190 if (ps->state != PROXY_STATE_ACTIVE) {
191 ps->sent_bufsize = bufsize;
192 ps->negotiate(ps, PROXY_CHANGE_SENT);
193 return;
194 }
195 plug_sent(ps->plug, bufsize);
196}
197
198static int plug_proxy_accepting (Plug p, void *sock)
199{
200 Proxy_Plug pp = (Proxy_Plug) p;
201 Proxy_Socket ps = pp->proxy_socket;
202
8eebd221 203 if (ps->state != PROXY_STATE_ACTIVE) {
204 ps->accepting_sock = sock;
205 return ps->negotiate(ps, PROXY_CHANGE_ACCEPTING);
206 }
207 return plug_accepting(ps->plug, sock);
208}
209
210static int proxy_for_destination (SockAddr addr, char * hostname, int port)
211{
212 int s = 0, e = 0;
213 char hostip[64];
214 int hostip_len, hostname_len;
215 char * exclude_list;
216
217 /* we want a string representation of the IP address for comparisons */
218 sk_getaddr(addr, hostip, 64);
219
220 hostip_len = strlen(hostip);
221 hostname_len = strlen(hostname);
222
223 exclude_list = cfg.proxy_exclude_list;
224
225 /* now parse the exclude list, and see if either our IP
226 * or hostname matches anything in it.
227 */
228
229 while (exclude_list[s]) {
230 while (exclude_list[s] &&
231 (isspace(exclude_list[s]) ||
232 exclude_list[s] == ',')) s++;
233
234 if (!exclude_list[s]) break;
235
236 e = s;
237
238 while (exclude_list[e] &&
239 (isalnum(exclude_list[e]) ||
240 exclude_list[e] == '-' ||
241 exclude_list[e] == '.' ||
242 exclude_list[e] == '*')) e++;
243
244 if (exclude_list[s] == '*') {
245 /* wildcard at beginning of entry */
246
247 if (strnicmp(hostip + hostip_len - (e - s - 1),
248 exclude_list + s + 1, e - s - 1) == 0 ||
249 strnicmp(hostname + hostname_len - (e - s - 1),
250 exclude_list + s + 1, e - s - 1) == 0)
251 return 0; /* IP/hostname range excluded. do not use proxy. */
252
253 } else if (exclude_list[e-1] == '*') {
254 /* wildcard at end of entry */
255
256 if (strnicmp(hostip, exclude_list + s, e - s - 1) == 0 ||
257 strnicmp(hostname, exclude_list + s, e - s - 1) == 0)
258 return 0; /* IP/hostname range excluded. do not use proxy. */
259
260 } else {
261 /* no wildcard at either end, so let's try an absolute
262 * match (ie. a specific IP)
263 */
264
265 if (stricmp(hostip, exclude_list + s) == 0)
266 return 0; /* IP/hostname excluded. do not use proxy. */
267 if (stricmp(hostname, exclude_list + s) == 0)
268 return 0; /* IP/hostname excluded. do not use proxy. */
269 }
270
271 s = e;
272 }
273
274 /* no matches in the exclude list, so use the proxy */
275 return 1;
276}
277
278Socket new_connection(SockAddr addr, char *hostname,
279 int port, int privport,
280 int oobinline, int nodelay, Plug plug)
281{
282 static struct socket_function_table socket_fn_table = {
283 sk_proxy_plug,
284 sk_proxy_close,
285 sk_proxy_write,
286 sk_proxy_write_oob,
287 sk_proxy_flush,
288 sk_proxy_set_private_ptr,
289 sk_proxy_get_private_ptr,
290 sk_proxy_set_frozen,
291 sk_proxy_socket_error
292 };
293
294 static struct plug_function_table plug_fn_table = {
295 plug_proxy_closing,
296 plug_proxy_receive,
297 plug_proxy_sent,
298 plug_proxy_accepting
299 };
300
301 if (cfg.proxy_type != PROXY_NONE &&
302 proxy_for_destination(addr, hostname, port))
303 {
304 Proxy_Socket ret;
305 Proxy_Plug pplug;
306 SockAddr proxy_addr;
307 char * proxy_canonical_name;
308
309 ret = smalloc(sizeof(struct Socket_proxy_tag));
310 ret->fn = &socket_fn_table;
311 ret->plug = plug;
312 ret->remote_addr = addr;
313 ret->remote_port = port;
314
315 bufchain_init(&ret->pending_input_data);
316 bufchain_init(&ret->pending_output_data);
317 bufchain_init(&ret->pending_oob_output_data);
318
8eebd221 319 ret->sub_socket = NULL;
320 ret->state = PROXY_STATE_NEW;
321
322 if (cfg.proxy_type == PROXY_HTTP) {
323 ret->negotiate = proxy_http_negotiate;
324 } else if (cfg.proxy_type == PROXY_SOCKS) {
6971bbe7 325 if (cfg.proxy_socks_version == 4)
326 ret->negotiate = proxy_socks4_negotiate;
327 else
328 ret->negotiate = proxy_socks5_negotiate;
8eebd221 329 } else if (cfg.proxy_type == PROXY_TELNET) {
330 ret->negotiate = proxy_telnet_negotiate;
331 } else {
332 ret->error = "Network error: Unknown proxy method";
333 return (Socket) ret;
334 }
335
336 /* create the proxy plug to map calls from the actual
337 * socket into our proxy socket layer */
338 pplug = smalloc(sizeof(struct Plug_proxy_tag));
339 pplug->fn = &plug_fn_table;
340 pplug->proxy_socket = ret;
341
342 /* look-up proxy */
343 proxy_addr = sk_namelookup(cfg.proxy_host,
344 &proxy_canonical_name);
345 sfree(proxy_canonical_name);
346
347 /* create the actual socket we will be using,
348 * connected to our proxy server and port.
349 */
350 ret->sub_socket = sk_new(proxy_addr, cfg.proxy_port,
351 privport, oobinline,
352 nodelay, (Plug) pplug);
353 if (sk_socket_error(ret->sub_socket) != NULL)
354 return (Socket) ret;
355
356 sk_addr_free(proxy_addr);
357
358 /* start the proxy negotiation process... */
359 sk_set_frozen(ret->sub_socket, 0);
360 ret->negotiate(ret, PROXY_CHANGE_NEW);
361
362 return (Socket) ret;
363 }
364
365 /* no proxy, so just return the direct socket */
366 return sk_new(addr, port, privport, oobinline, nodelay, plug);
367}
368
369Socket new_listener(int port, Plug plug, int local_host_only)
370{
371 /* TODO: SOCKS (and potentially others) support inbound
372 * TODO: connections via the proxy. support them.
373 */
374
375 return sk_newlistener(port, plug, local_host_only);
376}
377
378/* ----------------------------------------------------------------------
379 * HTTP CONNECT proxy type.
380 */
381
382static int get_line_end (char * data, int len)
383{
384 int off = 0;
385
386 while (off < len)
387 {
388 if (data[off] == '\n') {
389 /* we have a newline */
390 off++;
391
392 /* is that the only thing on this line? */
393 if (off <= 2) return off;
394
395 /* if not, then there is the possibility that this header
396 * continues onto the next line, if it starts with a space
397 * or a tab.
398 */
399
400 if (off + 1 < len &&
401 data[off+1] != ' ' &&
402 data[off+1] != '\t') return off;
403
404 /* the line does continue, so we have to keep going
405 * until we see an the header's "real" end of line.
406 */
407 off++;
408 }
409
410 off++;
411 }
412
413 return -1;
414}
415
416int proxy_http_negotiate (Proxy_Socket p, int change)
417{
418 if (p->state == PROXY_STATE_NEW) {
419 /* we are just beginning the proxy negotiate process,
420 * so we'll send off the initial bits of the request.
421 * for this proxy method, it's just a simple HTTP
422 * request
423 */
0e8f4cda 424 char buf[256], dest[64];
8eebd221 425
0e8f4cda 426 sk_getaddr(p->remote_addr, dest, 64);
8eebd221 427
428 sprintf(buf, "CONNECT %s:%i HTTP/1.1\r\nHost: %s:%i\r\n\r\n",
429 dest, p->remote_port, dest, p->remote_port);
430 sk_write(p->sub_socket, buf, strlen(buf));
431
432 p->state = 1;
8eebd221 433 return 0;
434 }
435
436 if (change == PROXY_CHANGE_CLOSING) {
437 /* if our proxy negotiation process involves closing and opening
438 * new sockets, then we would want to intercept this closing
439 * callback when we were expecting it. if we aren't anticipating
440 * a socket close, then some error must have occurred. we'll
441 * just pass those errors up to the backend.
442 */
443 return plug_closing(p->plug, p->closing_error_msg,
444 p->closing_error_code,
445 p->closing_calling_back);
446 }
447
448 if (change == PROXY_CHANGE_SENT) {
449 /* some (or all) of what we wrote to the proxy was sent.
450 * we don't do anything new, however, until we receive the
451 * proxy's response. we might want to set a timer so we can
452 * timeout the proxy negotiation after a while...
453 */
454 return 0;
455 }
456
457 if (change == PROXY_CHANGE_ACCEPTING) {
458 /* we should _never_ see this, as we are using our socket to
459 * connect to a proxy, not accepting inbound connections.
460 * what should we do? close the socket with an appropriate
461 * error message?
462 */
463 return plug_accepting(p->plug, p->accepting_sock);
464 }
465
466 if (change == PROXY_CHANGE_RECEIVE) {
467 /* we have received data from the underlying socket, which
468 * we'll need to parse, process, and respond to appropriately.
469 */
470
471 void *data;
472 int len;
473 int eol;
474
475 if (p->state == 1) {
476
477 int min_ver, maj_ver, status;
478
479 /* get the status line */
480 bufchain_prefix(&p->pending_input_data, &data, &len);
481 eol = get_line_end(data, len);
482 if (eol < 0) return 1;
483
484 sscanf((char *)data, "HTTP/%i.%i %i", &maj_ver, &min_ver, &status);
485
486 /* remove the status line from the input buffer. */
487 bufchain_consume(&p->pending_input_data, eol);
488
489 /* TODO: we need to support Proxy-Auth headers */
490
491 if (status < 200 || status > 299) {
492 /* error */
493 /* TODO: return a more specific error message,
494 * TODO: based on the status code.
495 */
496 plug_closing(p->plug, "Network error: Error while communicating with proxy",
497 PROXY_ERROR_GENERAL, 0);
498 return 1;
499 }
500
501 p->state = 2;
502 }
503
504 if (p->state == 2) {
505
506 /* get headers. we're done when we get a
507 * header of length 2, (ie. just "\r\n")
508 */
509
510 bufchain_prefix(&p->pending_input_data, &data, &len);
511 eol = get_line_end(data, len);
512 while (eol > 2)
513 {
514 /* TODO: Proxy-Auth stuff. in some cases, we will
515 * TODO: need to extract information from headers.
516 */
517 bufchain_consume(&p->pending_input_data, eol);
518 bufchain_prefix(&p->pending_input_data, &data, &len);
519 eol = get_line_end(data, len);
520 }
521
522 if (eol == 2) {
523 /* we're done */
524 bufchain_consume(&p->pending_input_data, 2);
525 proxy_activate(p);
526 /* proxy activate will have dealt with
527 * whatever is left of the buffer */
528 return 1;
529 }
530
531 return 1;
532 }
533 }
534
535 plug_closing(p->plug, "Network error: Unexpected proxy error",
536 PROXY_ERROR_UNEXPECTED, 0);
6971bbe7 537 return 1;
8eebd221 538}
539
540/* ----------------------------------------------------------------------
6971bbe7 541 * SOCKS proxy type.
8eebd221 542 */
543
6971bbe7 544/* SOCKS version 4 */
545int proxy_socks4_negotiate (Proxy_Socket p, int change)
8eebd221 546{
6971bbe7 547 if (p->state == PROXY_CHANGE_NEW) {
548
549 /* request format:
550 * version number (1 byte) = 4
551 * command code (1 byte)
552 * 1 = CONNECT
553 * 2 = BIND
554 * dest. port (2 bytes) [network order]
555 * dest. address (4 bytes)
556 * user ID (variable length, null terminated string)
557 */
558
559 int length;
560 char * command;
561
562 if (sk_addrtype(p->remote_addr) != AF_INET) {
563 plug_closing(p->plug, "Network error: SOCKS version 4 does not support IPv6",
564 PROXY_ERROR_GENERAL, 0);
565 return 1;
566 }
567
568 length = strlen(cfg.proxy_username) + 9;
569 command = (char*) malloc(length);
570 strcpy(command + 8, cfg.proxy_username);
571
572 command[0] = 4; /* version 4 */
573 command[1] = 1; /* CONNECT command */
574
575 /* port */
576 command[2] = (char) (p->remote_port >> 8) & 0xff;
577 command[3] = (char) p->remote_port & 0xff;
578
579 /* address */
580 sk_addrcopy(p->remote_addr, command + 4);
581
582 sk_write(p->sub_socket, command, length);
583 free(command);
584
585 p->state = 1;
586 return 0;
587 }
588
589 if (change == PROXY_CHANGE_CLOSING) {
590 /* if our proxy negotiation process involves closing and opening
591 * new sockets, then we would want to intercept this closing
592 * callback when we were expecting it. if we aren't anticipating
593 * a socket close, then some error must have occurred. we'll
594 * just pass those errors up to the backend.
595 */
596 return plug_closing(p->plug, p->closing_error_msg,
597 p->closing_error_code,
598 p->closing_calling_back);
599 }
600
601 if (change == PROXY_CHANGE_SENT) {
602 /* some (or all) of what we wrote to the proxy was sent.
603 * we don't do anything new, however, until we receive the
604 * proxy's response. we might want to set a timer so we can
605 * timeout the proxy negotiation after a while...
606 */
607 return 0;
608 }
609
610 if (change == PROXY_CHANGE_ACCEPTING) {
611 /* we should _never_ see this, as we are using our socket to
612 * connect to a proxy, not accepting inbound connections.
613 * what should we do? close the socket with an appropriate
614 * error message?
615 */
616 return plug_accepting(p->plug, p->accepting_sock);
617 }
618
619 if (change == PROXY_CHANGE_RECEIVE) {
620 /* we have received data from the underlying socket, which
621 * we'll need to parse, process, and respond to appropriately.
622 */
623
624 if (p->state == 1) {
625 /* response format:
626 * version number (1 byte) = 4
627 * reply code (1 byte)
628 * 90 = request granted
629 * 91 = request rejected or failed
630 * 92 = request rejected due to lack of IDENTD on client
631 * 93 = request rejected due to difference in user ID
632 * (what we sent vs. what IDENTD said)
633 * dest. port (2 bytes)
634 * dest. address (4 bytes)
635 */
636
637 char *data;
638 int len;
639
640 /* get the response */
641 bufchain_prefix(&p->pending_input_data, &data, &len);
642
643 if (data[0] != 0) {
644 plug_closing(p->plug, "Network error: SOCKS proxy responded with "
645 "unexpected reply code version",
646 PROXY_ERROR_GENERAL, 0);
647 return 1;
648 }
649
650 if (data[1] != 90) {
651
652 switch (data[1]) {
653 case 92:
654 plug_closing(p->plug, "Network error: SOCKS server wanted IDENTD on client",
655 PROXY_ERROR_GENERAL, 0);
656 break;
657 case 93:
658 plug_closing(p->plug, "Network error: Username and IDENTD on client don't agree",
659 PROXY_ERROR_GENERAL, 0);
660 break;
661 case 91:
662 default:
663 plug_closing(p->plug, "Network error: Error while communicating with proxy",
664 PROXY_ERROR_GENERAL, 0);
665 break;
666 }
667
668 return 1;
669 }
670
671 /* we're done */
672 proxy_activate(p);
673 /* proxy activate will have dealt with
674 * whatever is left of the buffer */
675 return 1;
676 }
677 }
678
679 plug_closing(p->plug, "Network error: Unexpected proxy error",
680 PROXY_ERROR_UNEXPECTED, 0);
681 return 1;
682}
683
684/* SOCKS version 5 */
685int proxy_socks5_negotiate (Proxy_Socket p, int change)
686{
687 if (p->state == PROXY_CHANGE_NEW) {
688
689 /* initial command:
690 * version number (1 byte) = 5
691 * number of available authentication methods (1 byte)
692 * available authentication methods (1 byte * previous value)
693 * authentication methods:
694 * 0x00 = no authentication
695 * 0x01 = GSSAPI
696 * 0x02 = username/password
697 * 0x03 = CHAP
698 */
699
700 char command[3];
701
702 command[0] = 5; /* version 5 */
703 command[1] = 1; /* TODO: we don't currently support any auth methods */
704 command[2] = 0x00; /* no authentication */
705
706 sk_write(p->sub_socket, command, 3);
707
708 p->state = 1;
709 return 0;
710 }
711
712 if (change == PROXY_CHANGE_CLOSING) {
713 /* if our proxy negotiation process involves closing and opening
714 * new sockets, then we would want to intercept this closing
715 * callback when we were expecting it. if we aren't anticipating
716 * a socket close, then some error must have occurred. we'll
717 * just pass those errors up to the backend.
718 */
719 return plug_closing(p->plug, p->closing_error_msg,
720 p->closing_error_code,
721 p->closing_calling_back);
722 }
723
724 if (change == PROXY_CHANGE_SENT) {
725 /* some (or all) of what we wrote to the proxy was sent.
726 * we don't do anything new, however, until we receive the
727 * proxy's response. we might want to set a timer so we can
728 * timeout the proxy negotiation after a while...
729 */
730 return 0;
731 }
732
733 if (change == PROXY_CHANGE_ACCEPTING) {
734 /* we should _never_ see this, as we are using our socket to
735 * connect to a proxy, not accepting inbound connections.
736 * what should we do? close the socket with an appropriate
737 * error message?
738 */
739 return plug_accepting(p->plug, p->accepting_sock);
740 }
741
742 if (change == PROXY_CHANGE_RECEIVE) {
743 /* we have received data from the underlying socket, which
744 * we'll need to parse, process, and respond to appropriately.
745 */
746
747 char *data;
748 int len;
749
750 if (p->state == 1) {
751
752 /* initial response:
753 * version number (1 byte) = 5
754 * authentication method (1 byte)
755 * authentication methods:
756 * 0x00 = no authentication
757 * 0x01 = GSSAPI
758 * 0x02 = username/password
759 * 0x03 = CHAP
760 * 0xff = no acceptable methods
761 */
762
763 /* get the response */
764 bufchain_prefix(&p->pending_input_data, &data, &len);
765
766 if (data[0] != 5) {
767 plug_closing(p->plug, "Network error: Error while communicating with proxy",
768 PROXY_ERROR_GENERAL, 0);
769 return 1;
770 }
771
772 if (data[1] == 0x00) p->state = 2; /* no authentication needed */
773 else if (data[1] == 0x01) p->state = 4; /* GSSAPI authentication */
774 else if (data[1] == 0x02) p->state = 5; /* username/password authentication */
775 else if (data[1] == 0x03) p->state = 6; /* CHAP authentication */
776 else {
777 plug_closing(p->plug, "Network error: We don't support any of the SOCKS "
778 "server's authentication methods",
779 PROXY_ERROR_GENERAL, 0);
780 return 1;
781 }
782 }
783
784 if (p->state == 2) {
785
786 /* request format:
787 * version number (1 byte) = 5
788 * command code (1 byte)
789 * 1 = CONNECT
790 * 2 = BIND
791 * 3 = UDP ASSOCIATE
792 * reserved (1 byte) = 0x00
793 * address type (1 byte)
794 * 1 = IPv4
795 * 3 = domainname (first byte has length, no terminating null)
796 * 4 = IPv6
797 * dest. address (variable)
798 * dest. port (2 bytes) [network order]
799 */
800
801 char command[22];
802 int len;
803
804 if (sk_addrtype(p->remote_addr) == AF_INET) {
805 len = 10;
806 command[3] = 1; /* IPv4 */
807 } else {
808 len = 22;
809 command[3] = 4; /* IPv6 */
810 }
811
812 command[0] = 5; /* version 5 */
813 command[1] = 1; /* CONNECT command */
814 command[2] = 0x00;
815
816 /* address */
817 sk_addrcopy(p->remote_addr, command+4);
818
819 /* port */
820 command[len-2] = (char) (p->remote_port >> 8) & 0xff;
821 command[len-1] = (char) p->remote_port & 0xff;
822
823 sk_write(p->sub_socket, command, len);
824
825 p->state = 3;
826 return 1;
827 }
828
829 if (p->state == 3) {
830
831 /* reply format:
832 * version number (1 bytes) = 5
833 * reply code (1 byte)
834 * 0 = succeeded
835 * 1 = general SOCKS server failure
836 * 2 = connection not allowed by ruleset
837 * 3 = network unreachable
838 * 4 = host unreachable
839 * 5 = connection refused
840 * 6 = TTL expired
841 * 7 = command not supported
842 * 8 = address type not supported
843 * reserved (1 byte) = x00
844 * address type (1 byte)
845 * 1 = IPv4
846 * 3 = domainname (first byte has length, no terminating null)
847 * 4 = IPv6
848 * server bound address (variable)
849 * server bound port (2 bytes) [network order]
850 */
851
852 /* get the response */
853 bufchain_prefix(&p->pending_input_data, &data, &len);
854
855 if (data[0] != 5) {
856 plug_closing(p->plug, "Network error: Error while communicating with proxy",
857 PROXY_ERROR_GENERAL, 0);
858 return 1;
859 }
860
861 if (data[1] != 0) {
862
863 switch (data[1]) {
864 case 1:
865 case 2:
866 case 3:
867 case 4:
868 case 5:
869 case 6:
870 case 7:
871 case 8:
872 default:
873 plug_closing(p->plug, "Network error: Error while communicating with proxy",
874 PROXY_ERROR_GENERAL, 0);
875 break;
876 }
877
878 return 1;
879 }
880
881 /* we're done */
882 proxy_activate(p);
883 /* proxy activate will have dealt with
884 * whatever is left of the buffer */
885 return 1;
886 }
887
888 if (p->state == 4) {
889 /* TODO: Handle GSSAPI authentication */
890 plug_closing(p->plug, "Network error: We don't support GSSAPI authentication",
891 PROXY_ERROR_GENERAL, 0);
892 return 1;
893 }
894
895 if (p->state == 5) {
896 /* TODO: Handle username/password authentication */
897 plug_closing(p->plug, "Network error: We don't support username/password "
898 "authentication",
899 PROXY_ERROR_GENERAL, 0);
900 return 1;
901 }
902
903 if (p->state == 6) {
904 /* TODO: Handle CHAP authentication */
905 plug_closing(p->plug, "Network error: We don't support CHAP authentication",
906 PROXY_ERROR_GENERAL, 0);
907 return 1;
908 }
909 }
910
911 plug_closing(p->plug, "Network error: Unexpected proxy error",
912 PROXY_ERROR_UNEXPECTED, 0);
913 return 1;
8eebd221 914}
915
916/* ----------------------------------------------------------------------
0e8f4cda 917 * `Telnet' proxy type.
8eebd221 918 *
919 * (This is for ad-hoc proxies where you connect to the proxy's
920 * telnet port and send a command such as `connect host port'. The
921 * command is configurable, since this proxy type is typically not
922 * standardised or at all well-defined.)
923 */
924
925int proxy_telnet_negotiate (Proxy_Socket p, int change)
926{
0e8f4cda 927 if (p->state == PROXY_CHANGE_NEW) {
928
929 int so = 0, eo = 0;
930
931 /* we need to escape \\, \%, \r, \n, \t, \x??, \0???,
932 * %%, %host, and %port
933 */
934
935 while (cfg.proxy_telnet_command[eo] != 0) {
936
937 /* scan forward until we hit end-of-line,
938 * or an escape character (\ or %) */
939 while (cfg.proxy_telnet_command[eo] != 0 &&
940 cfg.proxy_telnet_command[eo] != '%' &&
941 cfg.proxy_telnet_command[eo] != '\\') eo++;
942
943 /* if we hit eol, break out of our escaping loop */
944 if (cfg.proxy_telnet_command[eo] == 0) break;
945
946 /* if there was any unescaped text before the escape
947 * character, send that now */
948 if (eo != so) {
949 sk_write(p->sub_socket,
950 cfg.proxy_telnet_command + so, eo - so);
951 }
952
953 so = eo++;
954
955 /* if the escape character was the last character of
956 * the line, we'll just stop and send it. */
957 if (cfg.proxy_telnet_command[eo] == 0) break;
958
959 if (cfg.proxy_telnet_command[so] == '\\') {
960
961 /* we recognize \\, \%, \r, \n, \t, \x??.
962 * anything else, we just send unescaped (including the \).
963 */
964
965 switch (cfg.proxy_telnet_command[eo]) {
966
967 case '\\':
968 sk_write(p->sub_socket, "\\", 1);
969 eo++;
970 break;
971
972 case '%':
973 sk_write(p->sub_socket, "%%", 1);
974 eo++;
975 break;
976
977 case 'r':
978 sk_write(p->sub_socket, "\r", 1);
979 eo++;
980 break;
981
982 case 'n':
983 sk_write(p->sub_socket, "\n", 1);
984 eo++;
985 break;
986
987 case 't':
988 sk_write(p->sub_socket, "\t", 1);
989 eo++;
990 break;
991
992 case 'x':
993 case 'X':
994 {
995 /* escaped hexadecimal value (ie. \xff) */
996 unsigned char v = 0;
997 int i = 0;
998
999 for (;;) {
1000 eo++;
1001 if (cfg.proxy_telnet_command[eo] >= '0' &&
1002 cfg.proxy_telnet_command[eo] <= '9')
1003 v += cfg.proxy_telnet_command[eo] - '0';
1004 else if (cfg.proxy_telnet_command[eo] >= 'a' &&
1005 cfg.proxy_telnet_command[eo] <= 'f')
1006 v += cfg.proxy_telnet_command[eo] - 'a' + 10;
1007 else if (cfg.proxy_telnet_command[eo] >= 'A' &&
1008 cfg.proxy_telnet_command[eo] <= 'F')
1009 v += cfg.proxy_telnet_command[eo] - 'A' + 10;
1010 else {
1011 /* non hex character, so we abort and just
1012 * send the whole thing unescaped (including \x)
1013 */
1014 sk_write(p->sub_socket, "\\", 1);
1015 eo = so + 1;
1016 break;
1017 }
1018
1019 /* we only extract two hex characters */
1020 if (i == 1) {
1021 sk_write(p->sub_socket, &v, 1);
1022 eo++;
1023 break;
1024 }
1025
1026 i++;
1027 v <<= 4;
1028 }
1029 }
1030 break;
1031
1032 default:
1033 sk_write(p->sub_socket,
1034 cfg.proxy_telnet_command + so, 2);
1035 eo++;
1036 break;
1037 }
1038 } else {
1039
1040 /* % escape. we recognize %%, %host, %port. anything else,
1041 * we just send unescaped (including the %). */
1042
1043 if (cfg.proxy_telnet_command[eo] == '%') {
1044 sk_write(p->sub_socket, "%", 1);
1045 eo++;
1046 }
1047 else if (strnicmp(cfg.proxy_telnet_command + eo,
1048 "host", 4) == 0) {
1049 char dest[64];
1050 sk_getaddr(p->remote_addr, dest, 64);
1051 sk_write(p->sub_socket, dest, strlen(dest));
1052 eo += 4;
1053 }
1054 else if (strnicmp(cfg.proxy_telnet_command + eo,
1055 "port", 4) == 0) {
1056 char port[8];
1057 sprintf(port, "%i", p->remote_port);
1058 sk_write(p->sub_socket, port, strlen(port));
1059 eo += 4;
1060 }
1061 else {
1062 /* we don't escape this, so send the % now, and
1063 * don't advance eo, so that we'll consider the
1064 * text immediately following the % as unescaped.
1065 */
1066 sk_write(p->sub_socket, "%", 1);
1067 }
1068 }
1069
1070 /* resume scanning for additional escapes after this one. */
1071 so = eo;
1072 }
1073
1074 /* if there is any unescaped text at the end of the line, send it */
1075 if (eo != so) {
1076 sk_write(p->sub_socket, cfg.proxy_telnet_command + so, eo - so);
1077 }
1078
1079 p->state = 1;
0e8f4cda 1080 return 0;
1081 }
1082
1083 if (change == PROXY_CHANGE_CLOSING) {
1084 /* if our proxy negotiation process involves closing and opening
1085 * new sockets, then we would want to intercept this closing
1086 * callback when we were expecting it. if we aren't anticipating
1087 * a socket close, then some error must have occurred. we'll
1088 * just pass those errors up to the backend.
1089 */
1090 return plug_closing(p->plug, p->closing_error_msg,
1091 p->closing_error_code,
1092 p->closing_calling_back);
1093 }
1094
1095 if (change == PROXY_CHANGE_SENT) {
1096 /* some (or all) of what we wrote to the proxy was sent.
1097 * we don't do anything new, however, until we receive the
1098 * proxy's response. we might want to set a timer so we can
1099 * timeout the proxy negotiation after a while...
1100 */
1101 return 0;
1102 }
1103
1104 if (change == PROXY_CHANGE_ACCEPTING) {
1105 /* we should _never_ see this, as we are using our socket to
1106 * connect to a proxy, not accepting inbound connections.
1107 * what should we do? close the socket with an appropriate
1108 * error message?
1109 */
1110 return plug_accepting(p->plug, p->accepting_sock);
1111 }
1112
1113 if (change == PROXY_CHANGE_RECEIVE) {
1114 /* we have received data from the underlying socket, which
1115 * we'll need to parse, process, and respond to appropriately.
1116 */
1117
1118 /* we're done */
1119 proxy_activate(p);
1120 /* proxy activate will have dealt with
1121 * whatever is left of the buffer */
1122 return 1;
1123 }
1124
1125 plug_closing(p->plug, "Network error: Unexpected proxy error",
1126 PROXY_ERROR_UNEXPECTED, 0);
6971bbe7 1127 return 1;
8eebd221 1128}