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