source: filezilla/trunk/fuentes/src/putty/proxy.c @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

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