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