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