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