OpenSSL generate_key(): Check EVP_RSA_gen()'s return value
[privoxy.git] / gateway.c
1 /*********************************************************************
2  *
3  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
4  *
5  * Purpose     :  Contains functions to connect to a server, possibly
6  *                using a "forwarder" (i.e. HTTP proxy and/or a SOCKS4
7  *                or SOCKS5 proxy).
8  *
9  * Copyright   :  Written by and Copyright (C) 2001-2023 the
10  *                Privoxy team. https://www.privoxy.org/
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  *********************************************************************/
35
36
37 #include "config.h"
38
39 #include <stdio.h>
40 #include <stddef.h>
41 #include <sys/types.h>
42
43 #ifndef _WIN32
44 #include <netinet/in.h>
45 #endif
46
47 #include <errno.h>
48 #include <string.h>
49 #include "assert.h"
50
51 #ifdef _WIN32
52 #include <winsock2.h>
53 #endif /* def _WIN32 */
54
55 #ifdef __BEOS__
56 #include <netdb.h>
57 #endif /* def __BEOS__ */
58
59 #include "project.h"
60 #include "jcc.h"
61 #include "errlog.h"
62 #include "jbsockets.h"
63 #include "gateway.h"
64 #include "miscutil.h"
65 #include "list.h"
66 #include "parsers.h"
67
68 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
69 #ifdef HAVE_POLL
70 #ifdef __GLIBC__
71 #include <sys/poll.h>
72 #else
73 #include <poll.h>
74 #endif /* def __GLIBC__ */
75 #endif /* HAVE_POLL */
76 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
77
78 static jb_socket socks4_connect(const struct forward_spec *fwd,
79                                 const char *target_host,
80                                 int target_port,
81                                 struct client_state *csp);
82
83 static jb_socket socks5_connect(const struct forward_spec *fwd,
84                                 const char *target_host,
85                                 int target_port,
86                                 struct client_state *csp);
87
88 enum {
89    SOCKS4_REQUEST_GRANTED        =  90,
90    SOCKS4_REQUEST_REJECT         =  91,
91    SOCKS4_REQUEST_IDENT_FAILED   =  92,
92    SOCKS4_REQUEST_IDENT_CONFLICT =  93
93 };
94
95 enum {
96    SOCKS5_REQUEST_GRANTED             = 0,
97    SOCKS5_REQUEST_FAILED              = 1,
98    SOCKS5_REQUEST_DENIED              = 2,
99    SOCKS5_REQUEST_NETWORK_UNREACHABLE = 3,
100    SOCKS5_REQUEST_HOST_UNREACHABLE    = 4,
101    SOCKS5_REQUEST_CONNECTION_REFUSED  = 5,
102    SOCKS5_REQUEST_TTL_EXPIRED         = 6,
103    SOCKS5_REQUEST_PROTOCOL_ERROR      = 7,
104    SOCKS5_REQUEST_BAD_ADDRESS_TYPE    = 8
105 };
106
107 /* structure of a socks client operation */
108 struct socks_op {
109    unsigned char vn;          /* socks version number */
110    unsigned char cd;          /* command code */
111    unsigned char dstport[2];  /* destination port */
112    unsigned char dstip[4];    /* destination address */
113    char userid;               /* first byte of userid */
114    char padding[3];           /* make sure sizeof(struct socks_op) is endian-independent. */
115    /* more bytes of the userid follow, terminated by a NULL */
116 };
117
118 /* structure of a socks server reply */
119 struct socks_reply {
120    unsigned char vn;          /* socks version number */
121    unsigned char cd;          /* command code */
122    unsigned char dstport[2];  /* destination port */
123    unsigned char dstip[4];    /* destination address */
124 };
125
126 static const char socks_userid[] = "anonymous";
127
128 #ifdef FEATURE_CONNECTION_SHARING
129 #ifndef FEATURE_CONNECTION_KEEP_ALIVE
130 #error Using FEATURE_CONNECTION_SHARING without FEATURE_CONNECTION_KEEP_ALIVE is impossible
131 #endif
132
133 #define MAX_REUSABLE_CONNECTIONS 100
134
135 static struct reusable_connection reusable_connection[MAX_REUSABLE_CONNECTIONS];
136 static int mark_connection_unused(const struct reusable_connection *connection);
137
138 /*********************************************************************
139  *
140  * Function    :  initialize_reusable_connections
141  *
142  * Description :  Initializes the reusable_connection structures.
143  *                Must be called with connection_reuse_mutex locked.
144  *
145  * Parameters  : N/A
146  *
147  * Returns     : void
148  *
149  *********************************************************************/
150 extern void initialize_reusable_connections(void)
151 {
152    unsigned int slot = 0;
153
154 #if !defined(HAVE_POLL) && !defined(_WIN32)
155    log_error(LOG_LEVEL_INFO,
156       "Detecting already dead connections might not work "
157       "correctly on your platform. In case of problems, "
158       "unset the keep-alive-timeout option.");
159 #endif
160
161    for (slot = 0; slot < SZ(reusable_connection); slot++)
162    {
163       mark_connection_closed(&reusable_connection[slot]);
164    }
165
166    log_error(LOG_LEVEL_CONNECT, "Initialized %d socket slots.", slot);
167 }
168
169
170 /*********************************************************************
171  *
172  * Function    :  remember_connection
173  *
174  * Description :  Remembers a server connection for reuse later on.
175  *
176  * Parameters  :
177  *          1  :  connection = The server connection to remember.
178  *
179  * Returns     : void
180  *
181  *********************************************************************/
182 void remember_connection(const struct reusable_connection *connection)
183 {
184    unsigned int slot = 0;
185    int free_slot_found = FALSE;
186
187    assert(NULL != connection);
188    assert(connection->sfd != JB_INVALID_SOCKET);
189
190    if (mark_connection_unused(connection))
191    {
192       return;
193    }
194
195    privoxy_mutex_lock(&connection_reuse_mutex);
196
197    /* Find free socket slot. */
198    for (slot = 0; slot < SZ(reusable_connection); slot++)
199    {
200       if (reusable_connection[slot].sfd == JB_INVALID_SOCKET)
201       {
202          assert(reusable_connection[slot].in_use == 0);
203          log_error(LOG_LEVEL_CONNECT,
204             "Remembering socket %d for %s:%d in slot %d.",
205             connection->sfd, connection->host, connection->port, slot);
206          free_slot_found = TRUE;
207          break;
208       }
209    }
210
211    if (!free_slot_found)
212    {
213       log_error(LOG_LEVEL_CONNECT,
214         "No free slots found to remember socket for %s:%d. Last slot %d.",
215         connection->host, connection->port, slot);
216       privoxy_mutex_unlock(&connection_reuse_mutex);
217       close_socket(connection->sfd);
218       return;
219    }
220
221    assert(slot < SZ(reusable_connection));
222    assert(NULL != connection->host);
223    reusable_connection[slot].host = strdup_or_die(connection->host);
224    reusable_connection[slot].sfd = connection->sfd;
225    reusable_connection[slot].port = connection->port;
226    reusable_connection[slot].in_use = 0;
227    reusable_connection[slot].timestamp = connection->timestamp;
228    reusable_connection[slot].request_sent = connection->request_sent;
229    reusable_connection[slot].response_received = connection->response_received;
230    reusable_connection[slot].keep_alive_timeout = connection->keep_alive_timeout;
231    reusable_connection[slot].requests_sent_total = connection->requests_sent_total;
232
233    assert(reusable_connection[slot].gateway_host == NULL);
234    assert(reusable_connection[slot].gateway_port == 0);
235    assert(reusable_connection[slot].auth_username == NULL);
236    assert(reusable_connection[slot].auth_password == NULL);
237    assert(reusable_connection[slot].forwarder_type == SOCKS_NONE);
238    assert(reusable_connection[slot].forward_host == NULL);
239    assert(reusable_connection[slot].forward_port == 0);
240
241    reusable_connection[slot].forwarder_type = connection->forwarder_type;
242    if (NULL != connection->gateway_host)
243    {
244       reusable_connection[slot].gateway_host = strdup_or_die(connection->gateway_host);
245    }
246    else
247    {
248       reusable_connection[slot].gateway_host = NULL;
249    }
250    reusable_connection[slot].gateway_port = connection->gateway_port;
251    if (NULL != connection->auth_username)
252    {
253       reusable_connection[slot].auth_username = strdup_or_die(connection->auth_username);
254    }
255    else
256    {
257       reusable_connection[slot].auth_username = NULL;
258    }
259    if (NULL != connection->auth_password)
260    {
261       reusable_connection[slot].auth_password = strdup_or_die(connection->auth_password);
262    }
263    else
264    {
265       reusable_connection[slot].auth_password = NULL;
266    }
267
268    if (NULL != connection->forward_host)
269    {
270       reusable_connection[slot].forward_host = strdup_or_die(connection->forward_host);
271    }
272    else
273    {
274       reusable_connection[slot].forward_host = NULL;
275    }
276    reusable_connection[slot].forward_port = connection->forward_port;
277
278    privoxy_mutex_unlock(&connection_reuse_mutex);
279 }
280 #endif /* def FEATURE_CONNECTION_SHARING */
281
282
283 /*********************************************************************
284  *
285  * Function    :  mark_connection_closed
286  *
287  * Description : Marks a reused connection closed.
288  *
289  * Parameters  :
290  *          1  :  closed_connection = The connection to mark as closed.
291  *
292  * Returns     : void
293  *
294  *********************************************************************/
295 void mark_connection_closed(struct reusable_connection *closed_connection)
296 {
297    closed_connection->in_use = FALSE;
298    closed_connection->sfd = JB_INVALID_SOCKET;
299    freez(closed_connection->host);
300    closed_connection->port = 0;
301    closed_connection->timestamp = 0;
302    closed_connection->request_sent = 0;
303    closed_connection->response_received = 0;
304    closed_connection->keep_alive_timeout = 0;
305    closed_connection->requests_sent_total = 0;
306    closed_connection->forwarder_type = SOCKS_NONE;
307    freez(closed_connection->gateway_host);
308    closed_connection->gateway_port = 0;
309    freez(closed_connection->auth_username);
310    freez(closed_connection->auth_password);
311    freez(closed_connection->forward_host);
312    closed_connection->forward_port = 0;
313 }
314
315
316 #ifdef FEATURE_CONNECTION_SHARING
317 /*********************************************************************
318  *
319  * Function    :  forget_connection
320  *
321  * Description :  Removes a previously remembered connection from
322  *                the list of reusable connections.
323  *
324  * Parameters  :
325  *          1  :  sfd = The socket belonging to the connection in question.
326  *
327  * Returns     : void
328  *
329  *********************************************************************/
330 void forget_connection(jb_socket sfd)
331 {
332    unsigned int slot = 0;
333
334    assert(sfd != JB_INVALID_SOCKET);
335
336    privoxy_mutex_lock(&connection_reuse_mutex);
337
338    for (slot = 0; slot < SZ(reusable_connection); slot++)
339    {
340       if (reusable_connection[slot].sfd == sfd)
341       {
342          assert(reusable_connection[slot].in_use);
343
344          log_error(LOG_LEVEL_CONNECT,
345             "Forgetting socket %d for %s:%d in slot %d.",
346             sfd, reusable_connection[slot].host,
347             reusable_connection[slot].port, slot);
348          mark_connection_closed(&reusable_connection[slot]);
349          break;
350       }
351    }
352
353    privoxy_mutex_unlock(&connection_reuse_mutex);
354
355 }
356 #endif /* def FEATURE_CONNECTION_SHARING */
357
358
359 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
360 /*********************************************************************
361  *
362  * Function    :  string_or_none
363  *
364  * Description :  Returns a given string or "none" if a NULL pointer
365  *                is given.
366  *                Helper function for connection_destination_matches().
367  *
368  * Parameters  :
369  *          1  :  string = The string to check.
370  *
371  * Returns     :  The string if non-NULL, "none" otherwise.
372  *
373  *********************************************************************/
374 static const char *string_or_none(const char *string)
375 {
376    return(string != NULL ? string : "none");
377 }
378
379
380 /*********************************************************************
381  *
382  * Function    :  connection_detail_matches
383  *
384  * Description :  Helper function for connection_destination_matches().
385  *                Compares strings which can be NULL.
386  *
387  * Parameters  :
388  *          1  :  connection_detail = The connection detail to compare.
389  *          2  :  fowarder_detail = The forwarder detail to compare.
390  *
391  * Returns     :  TRUE for yes, FALSE otherwise.
392  *
393  *********************************************************************/
394 static int connection_detail_matches(const char *connection_detail,
395                                      const char *forwarder_detail)
396 {
397    if (connection_detail == NULL && forwarder_detail == NULL)
398    {
399       /* Both details are unset. */
400       return TRUE;
401    }
402
403    if ((connection_detail == NULL && forwarder_detail != NULL)
404     || (connection_detail != NULL && forwarder_detail == NULL))
405    {
406       /* Only one detail isn't set. */
407       return FALSE;
408    }
409
410    /* Both details are set, but do they match? */
411    return(!strcmpic(connection_detail, forwarder_detail));
412
413 }
414
415
416 /*********************************************************************
417  *
418  * Function    :  connection_destination_matches
419  *
420  * Description :  Determines whether a remembered connection can
421  *                be reused. That is, whether the destination and
422  *                the forwarding settings match.
423  *
424  * Parameters  :
425  *          1  :  connection = The connection to check.
426  *          2  :  http = The destination for the connection.
427  *          3  :  fwd  = The forwarder settings.
428  *
429  * Returns     :  TRUE for yes, FALSE otherwise.
430  *
431  *********************************************************************/
432 int connection_destination_matches(const struct reusable_connection *connection,
433                                    const struct http_request *http,
434                                    const struct forward_spec *fwd)
435 {
436    if ((connection->forwarder_type != fwd->type)
437     || (connection->gateway_port   != fwd->gateway_port)
438     || (connection->forward_port   != fwd->forward_port)
439     || (connection->port           != http->port))
440    {
441       return FALSE;
442    }
443
444    if (!connection_detail_matches(connection->gateway_host, fwd->gateway_host))
445    {
446       log_error(LOG_LEVEL_CONNECT,
447          "Gateway mismatch. Previous gateway: %s. Current gateway: %s",
448          string_or_none(connection->gateway_host),
449          string_or_none(fwd->gateway_host));
450       return FALSE;
451    }
452
453    if (!connection_detail_matches(connection->auth_username, fwd->auth_username))
454    {
455       log_error(LOG_LEVEL_CONNECT, "Socks user name mismatch. "
456          "Previous user name: %s. Current user name: %s",
457          string_or_none(connection->auth_username),
458          string_or_none(fwd->auth_username));
459       return FALSE;
460    }
461
462    if (!connection_detail_matches(connection->auth_password, fwd->auth_password))
463    {
464       log_error(LOG_LEVEL_CONNECT, "Socks user name mismatch. "
465          "Previous password: %s. Current password: %s",
466          string_or_none(connection->auth_password),
467          string_or_none(fwd->auth_password));
468       return FALSE;
469    }
470
471    if (!connection_detail_matches(connection->forward_host, fwd->forward_host))
472    {
473       log_error(LOG_LEVEL_CONNECT,
474          "Forwarding proxy mismatch. Previous proxy: %s. Current proxy: %s",
475          string_or_none(connection->forward_host),
476          string_or_none(fwd->forward_host));
477       return FALSE;
478    }
479
480    return (!strcmpic(connection->host, http->host));
481
482 }
483 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
484
485
486 #ifdef FEATURE_CONNECTION_SHARING
487 /*********************************************************************
488  *
489  * Function    :  close_unusable_connections
490  *
491  * Description :  Closes remembered connections that have timed
492  *                out or have been closed on the other side.
493  *
494  * Parameters  :  none
495  *
496  * Returns     :  Number of connections that are still alive.
497  *
498  *********************************************************************/
499 int close_unusable_connections(void)
500 {
501    unsigned int slot = 0;
502    int connections_alive = 0;
503
504    privoxy_mutex_lock(&connection_reuse_mutex);
505
506    for (slot = 0; slot < SZ(reusable_connection); slot++)
507    {
508       if (!reusable_connection[slot].in_use
509          && (JB_INVALID_SOCKET != reusable_connection[slot].sfd))
510       {
511          time_t time_open = time(NULL) - reusable_connection[slot].timestamp;
512          time_t latency = (reusable_connection[slot].response_received -
513             reusable_connection[slot].request_sent) / 2;
514
515          if (reusable_connection[slot].keep_alive_timeout < time_open + latency)
516          {
517             log_error(LOG_LEVEL_CONNECT,
518                "The connection to %s:%d in slot %d timed out. "
519                "Closing socket %d. Timeout is: %d. Assumed latency: %ld.",
520                reusable_connection[slot].host,
521                reusable_connection[slot].port, slot,
522                reusable_connection[slot].sfd,
523                reusable_connection[slot].keep_alive_timeout,
524                latency);
525             close_socket(reusable_connection[slot].sfd);
526             mark_connection_closed(&reusable_connection[slot]);
527          }
528          else if (!socket_is_still_alive(reusable_connection[slot].sfd))
529          {
530             log_error(LOG_LEVEL_CONNECT,
531                "The connection to %s:%d in slot %d is no longer usable. "
532                "Closing socket %d.", reusable_connection[slot].host,
533                reusable_connection[slot].port, slot,
534                reusable_connection[slot].sfd);
535             close_socket(reusable_connection[slot].sfd);
536             mark_connection_closed(&reusable_connection[slot]);
537          }
538          else
539          {
540             connections_alive++;
541          }
542       }
543    }
544
545    privoxy_mutex_unlock(&connection_reuse_mutex);
546
547    return connections_alive;
548
549 }
550
551
552 /*********************************************************************
553  *
554  * Function    :  get_reusable_connection
555  *
556  * Description :  Returns an open socket to a previously remembered
557  *                open connection (if there is one).
558  *
559  * Parameters  :
560  *          1  :  http = The destination for the connection.
561  *          2  :  fwd  = The forwarder settings.
562  *
563  * Returns     :  JB_INVALID_SOCKET => No reusable connection found,
564  *                otherwise a usable socket.
565  *
566  *********************************************************************/
567 static jb_socket get_reusable_connection(const struct http_request *http,
568                                          const struct forward_spec *fwd)
569 {
570    jb_socket sfd = JB_INVALID_SOCKET;
571    unsigned int slot = 0;
572
573    close_unusable_connections();
574
575    privoxy_mutex_lock(&connection_reuse_mutex);
576
577    for (slot = 0; slot < SZ(reusable_connection); slot++)
578    {
579       if (!reusable_connection[slot].in_use
580          && (JB_INVALID_SOCKET != reusable_connection[slot].sfd))
581       {
582          if (connection_destination_matches(&reusable_connection[slot], http, fwd))
583          {
584             reusable_connection[slot].in_use = TRUE;
585             sfd = reusable_connection[slot].sfd;
586             log_error(LOG_LEVEL_CONNECT,
587                "Found reusable socket %d for %s:%d in slot %d. Timestamp made %ld "
588                "seconds ago. Timeout: %d. Latency: %d. Requests served: %d",
589                sfd, reusable_connection[slot].host, reusable_connection[slot].port,
590                slot, time(NULL) - reusable_connection[slot].timestamp,
591                reusable_connection[slot].keep_alive_timeout,
592                (int)(reusable_connection[slot].response_received -
593                reusable_connection[slot].request_sent),
594                reusable_connection[slot].requests_sent_total);
595             break;
596          }
597       }
598    }
599
600    privoxy_mutex_unlock(&connection_reuse_mutex);
601
602    return sfd;
603
604 }
605
606
607 /*********************************************************************
608  *
609  * Function    :  mark_connection_unused
610  *
611  * Description :  Gives a remembered connection free for reuse.
612  *
613  * Parameters  :
614  *          1  :  connection = The connection in question.
615  *
616  * Returns     :  TRUE => Socket found and marked as unused.
617  *                FALSE => Socket not found.
618  *
619  *********************************************************************/
620 static int mark_connection_unused(const struct reusable_connection *connection)
621 {
622    unsigned int slot = 0;
623    int socket_found = FALSE;
624
625    assert(connection->sfd != JB_INVALID_SOCKET);
626
627    privoxy_mutex_lock(&connection_reuse_mutex);
628
629    for (slot = 0; slot < SZ(reusable_connection); slot++)
630    {
631       if (reusable_connection[slot].sfd == connection->sfd)
632       {
633          assert(reusable_connection[slot].in_use);
634          socket_found = TRUE;
635          log_error(LOG_LEVEL_CONNECT,
636             "Marking open socket %d for %s:%d in slot %d as unused.",
637             connection->sfd, reusable_connection[slot].host,
638             reusable_connection[slot].port, slot);
639          reusable_connection[slot].in_use = 0;
640          reusable_connection[slot].timestamp = connection->timestamp;
641          break;
642       }
643    }
644
645    privoxy_mutex_unlock(&connection_reuse_mutex);
646
647    return socket_found;
648
649 }
650 #endif /* def FEATURE_CONNECTION_SHARING */
651
652
653 /*********************************************************************
654  *
655  * Function    :  forwarded_connect
656  *
657  * Description :  Connect to a specified web server, possibly via
658  *                a HTTP proxy and/or a SOCKS proxy.
659  *
660  * Parameters  :
661  *          1  :  fwd = the proxies to use when connecting.
662  *          2  :  http = the http request and apropos headers
663  *          3  :  csp = Current client state (buffers, headers, etc...)
664  *
665  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
666  *
667  *********************************************************************/
668 jb_socket forwarded_connect(const struct forward_spec *fwd,
669                             struct http_request *http,
670                             struct client_state *csp)
671 {
672    const char *dest_host;
673    int dest_port;
674    jb_socket sfd = JB_INVALID_SOCKET;
675
676 #ifdef FEATURE_CONNECTION_SHARING
677    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)
678       && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
679    {
680       sfd = get_reusable_connection(http, fwd);
681       if (JB_INVALID_SOCKET != sfd)
682       {
683          return sfd;
684       }
685    }
686 #endif /* def FEATURE_CONNECTION_SHARING */
687
688    /* Figure out if we need to connect to the web server or a HTTP proxy. */
689    if (fwd->forward_host)
690    {
691       /* HTTP proxy */
692       dest_host = fwd->forward_host;
693       dest_port = fwd->forward_port;
694    }
695    else
696    {
697       /* Web server */
698       dest_host = http->host;
699       dest_port = http->port;
700    }
701
702    /* Connect, maybe using a SOCKS proxy */
703    switch (fwd->type)
704    {
705       case SOCKS_NONE:
706       case FORWARD_WEBSERVER:
707          sfd = connect_to(dest_host, dest_port, csp);
708          break;
709       case SOCKS_4:
710       case SOCKS_4A:
711          sfd = socks4_connect(fwd, dest_host, dest_port, csp);
712          break;
713       case SOCKS_5:
714       case SOCKS_5T:
715          sfd = socks5_connect(fwd, dest_host, dest_port, csp);
716          break;
717       default:
718          /* Should never get here */
719          log_error(LOG_LEVEL_FATAL,
720             "Internal error in forwarded_connect(). Bad proxy type: %d", fwd->type);
721    }
722
723    if (JB_INVALID_SOCKET != sfd)
724    {
725       log_error(LOG_LEVEL_CONNECT,
726          "Created new connection to %s:%d on socket %d.",
727          http->host, http->port, sfd);
728    }
729
730    return sfd;
731
732 }
733
734
735 #ifdef FUZZ
736 /*********************************************************************
737  *
738  * Function    :  socks_fuzz
739  *
740  * Description :  Wrapper around socks[45]_connect() used for fuzzing.
741  *
742  * Parameters  :
743  *          1  :  csp = Current client state (buffers, headers, etc...)
744  *
745  * Returns     :  JB_ERR_OK or JB_ERR_PARSE
746  *
747  *********************************************************************/
748 extern jb_err socks_fuzz(struct client_state *csp)
749 {
750    jb_socket socket;
751    static struct forward_spec fwd;
752    char target_host[] = "fuzz.example.org";
753    int target_port = 12345;
754
755    fwd.gateway_host = strdup_or_die("fuzz.example.org");
756    fwd.gateway_port = 12345;
757
758    fwd.type = SOCKS_4A;
759    socket = socks4_connect(&fwd, target_host, target_port, csp);
760
761    if (JB_INVALID_SOCKET != socket)
762    {
763       fwd.type = SOCKS_5;
764       socket = socks5_connect(&fwd, target_host, target_port, csp);
765    }
766
767    if (JB_INVALID_SOCKET == socket)
768    {
769       log_error(LOG_LEVEL_ERROR, "%s", csp->error_message);
770       return JB_ERR_PARSE;
771    }
772
773    log_error(LOG_LEVEL_INFO, "Input looks like an acceptable socks response");
774
775    return JB_ERR_OK;
776
777 }
778 #endif
779
780 /*********************************************************************
781  *
782  * Function    :  socks4_connect
783  *
784  * Description :  Connect to the SOCKS server, and connect through
785  *                it to the specified server.   This handles
786  *                all the SOCKS negotiation, and returns a file
787  *                descriptor for a socket which can be treated as a
788  *                normal (non-SOCKS) socket.
789  *
790  *                Logged error messages are saved to csp->error_message
791  *                and later reused by error_response() for the CGI
792  *                message. strdup allocation failures are handled there.
793  *
794  * Parameters  :
795  *          1  :  fwd = Specifies the SOCKS proxy to use.
796  *          2  :  target_host = The final server to connect to.
797  *          3  :  target_port = The final port to connect to.
798  *          4  :  csp = Current client state (buffers, headers, etc...)
799  *
800  * Returns     :  JB_INVALID_SOCKET => failure, else a socket file descriptor.
801  *
802  *********************************************************************/
803 static jb_socket socks4_connect(const struct forward_spec *fwd,
804                                 const char *target_host,
805                                 int target_port,
806                                 struct client_state *csp)
807 {
808    unsigned long web_server_addr;
809    char buf[BUFFER_SIZE];
810    struct socks_op    *c = (struct socks_op    *)buf;
811    struct socks_reply *s = (struct socks_reply *)buf;
812    size_t n;
813    size_t csiz;
814    jb_socket sfd;
815    int err = 0;
816    char *errstr = NULL;
817
818    if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
819    {
820       /* XXX: Shouldn't the config file parser prevent this? */
821       errstr = "NULL gateway host specified.";
822       err = 1;
823    }
824
825    if (fwd->gateway_port <= 0)
826    {
827       errstr = "invalid gateway port specified.";
828       err = 1;
829    }
830
831    if (err)
832    {
833       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
834       csp->error_message = strdup(errstr);
835       errno = EINVAL;
836       return(JB_INVALID_SOCKET);
837    }
838
839    /* build a socks request for connection to the web server */
840
841    /*
842     * The more straightforward &(c->userid) destination pointer can
843     * cause some gcc versions to misidentify the size of the destination
844     * buffer, tripping the runtime check of glibc's source fortification.
845     */
846    strlcpy(buf + offsetof(struct socks_op, userid), socks_userid,
847       sizeof(buf) - sizeof(struct socks_op));
848
849    csiz = sizeof(*c) + sizeof(socks_userid) - sizeof(c->userid) - sizeof(c->padding);
850
851    switch (fwd->type)
852    {
853       case SOCKS_4:
854          web_server_addr = resolve_hostname_to_ip(target_host);
855          if (web_server_addr == INADDR_NONE)
856          {
857             errstr = "could not resolve target host";
858             log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s %s", errstr, target_host);
859             err = 1;
860          }
861          else
862          {
863             web_server_addr = htonl(web_server_addr);
864          }
865          break;
866       case SOCKS_4A:
867          web_server_addr = 0x00000001;
868          n = csiz + strlen(target_host) + 1;
869          if (n > sizeof(buf))
870          {
871             errno = EINVAL;
872             errstr = "buffer cbuf too small.";
873             log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
874             err = 1;
875          }
876          else
877          {
878             strlcpy(buf + csiz, target_host, sizeof(buf) - sizeof(struct socks_op) - csiz);
879             /*
880              * What we forward to the socks4a server should have the
881              * size of socks_op, plus the length of the userid plus
882              * its \0 byte (which we don't have to add because the
883              * first byte of the userid is counted twice as it's also
884              * part of sock_op) minus the padding bytes (which are part
885              * of the userid as well), plus the length of the target_host
886              * (which is stored csiz bytes after the beginning of the buffer),
887              * plus another \0 byte.
888              */
889             assert(n == sizeof(struct socks_op) + strlen(&(c->userid)) - sizeof(c->padding) + strlen(buf + csiz) + 1);
890             csiz = n;
891          }
892          break;
893       default:
894          /* Should never get here */
895          log_error(LOG_LEVEL_FATAL,
896             "socks4_connect: SOCKS4 impossible internal error - bad SOCKS type.");
897          /* Not reached */
898          return(JB_INVALID_SOCKET);
899    }
900
901    if (err)
902    {
903       csp->error_message = strdup(errstr);
904       return(JB_INVALID_SOCKET);
905    }
906
907    c->vn          = 4;
908    c->cd          = 1;
909    c->dstport[0]  = (unsigned char)((target_port       >> 8 ) & 0xff);
910    c->dstport[1]  = (unsigned char)((target_port            ) & 0xff);
911    c->dstip[0]    = (unsigned char)((web_server_addr   >> 24) & 0xff);
912    c->dstip[1]    = (unsigned char)((web_server_addr   >> 16) & 0xff);
913    c->dstip[2]    = (unsigned char)((web_server_addr   >>  8) & 0xff);
914    c->dstip[3]    = (unsigned char)((web_server_addr        ) & 0xff);
915
916 #ifdef FUZZ
917    sfd = 0;
918 #else
919    /* pass the request to the socks server */
920    sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
921
922    if (sfd == JB_INVALID_SOCKET)
923    {
924       /* The error an its reason have already been logged by connect_to()  */
925       return(JB_INVALID_SOCKET);
926    }
927    else if (write_socket(sfd, (char *)c, csiz))
928    {
929       errstr = "SOCKS4 negotiation write failed.";
930       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
931       err = 1;
932       close_socket(sfd);
933    }
934    else if (!data_is_available(sfd, csp->config->socket_timeout))
935    {
936       if (socket_is_still_alive(sfd))
937       {
938          errstr = "SOCKS4 negotiation timed out";
939       }
940       else
941       {
942          errstr = "SOCKS4 negotiation got aborted by the server";
943       }
944       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
945       err = 1;
946       close_socket(sfd);
947    }
948    else
949 #endif
950        if (read_socket(sfd, buf, sizeof(buf)) != sizeof(*s))
951    {
952       errstr = "SOCKS4 negotiation read failed.";
953       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
954       err = 1;
955       close_socket(sfd);
956    }
957
958    if (err)
959    {
960       csp->error_message = strdup(errstr);
961       return(JB_INVALID_SOCKET);
962    }
963
964    switch (s->cd)
965    {
966       case SOCKS4_REQUEST_GRANTED:
967          return(sfd);
968       case SOCKS4_REQUEST_REJECT:
969          errstr = "SOCKS request rejected or failed.";
970          errno = EINVAL;
971          break;
972       case SOCKS4_REQUEST_IDENT_FAILED:
973          errstr = "SOCKS request rejected because "
974             "SOCKS server cannot connect to identd on the client.";
975          errno = EACCES;
976          break;
977       case SOCKS4_REQUEST_IDENT_CONFLICT:
978          errstr = "SOCKS request rejected because "
979             "the client program and identd report "
980             "different user-ids.";
981          errno = EACCES;
982          break;
983       default:
984          errno = ENOENT;
985          snprintf(buf, sizeof(buf),
986             "SOCKS request rejected for reason code %d.", s->cd);
987          errstr = buf;
988    }
989
990    log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
991    csp->error_message = strdup(errstr);
992    close_socket(sfd);
993
994    return(JB_INVALID_SOCKET);
995
996 }
997
998 /*********************************************************************
999  *
1000  * Function    :  translate_socks5_error
1001  *
1002  * Description :  Translates a SOCKS errors to a string.
1003  *
1004  * Parameters  :
1005  *          1  :  socks_error = The error code to translate.
1006  *
1007  * Returns     :  The string translation.
1008  *
1009  *********************************************************************/
1010 static const char *translate_socks5_error(int socks_error)
1011 {
1012    switch (socks_error)
1013    {
1014       /* XXX: these should be more descriptive */
1015       case SOCKS5_REQUEST_FAILED:
1016          return "SOCKS5 request failed";
1017       case SOCKS5_REQUEST_DENIED:
1018          return "SOCKS5 request denied";
1019       case SOCKS5_REQUEST_NETWORK_UNREACHABLE:
1020          return "SOCKS5 network unreachable";
1021       case SOCKS5_REQUEST_HOST_UNREACHABLE:
1022          return "SOCKS5 destination host unreachable";
1023       case SOCKS5_REQUEST_CONNECTION_REFUSED:
1024          return "SOCKS5 connection refused";
1025       case SOCKS5_REQUEST_TTL_EXPIRED:
1026          return "SOCKS5 TTL expired";
1027       case SOCKS5_REQUEST_PROTOCOL_ERROR:
1028          return "SOCKS5 client protocol error";
1029       case SOCKS5_REQUEST_BAD_ADDRESS_TYPE:
1030          return "SOCKS5 domain names unsupported";
1031       case SOCKS5_REQUEST_GRANTED:
1032          return "everything's peachy";
1033       default:
1034          return "SOCKS5 negotiation protocol error";
1035    }
1036 }
1037
1038
1039 /*********************************************************************
1040  *
1041  * Function    :  convert_ipv4_address_to_bytes
1042  *
1043  * Description :  Converts an IPv4 address from string to bytes.
1044  *
1045  * Parameters  :
1046  *          1  :  address = The IPv4 address string to convert.
1047  *          2  :  buf = The buffer to write the bytes to.
1048  *                      Must be at least four bytes long.
1049  *
1050  * Returns     :  JB_ERR_OK on success, JB_ERR_PARSE otherwise.
1051  *
1052  *********************************************************************/
1053 static jb_err convert_ipv4_address_to_bytes(const char *address, char *buf)
1054 {
1055    int i;
1056    const char *p = address;
1057
1058    for (i = 0; i < 4; i++)
1059    {
1060       unsigned byte;
1061       if (1 != sscanf(p, "%u", &byte))
1062       {
1063          return JB_ERR_PARSE;
1064       }
1065       if (byte > 255)
1066       {
1067          return JB_ERR_PARSE;
1068       }
1069       buf[i] = (char)byte;
1070       if (i < 3)
1071       {
1072          p = strstr(p, ".");
1073          if (p == NULL)
1074          {
1075             return JB_ERR_PARSE;
1076          }
1077          p++;
1078       }
1079    }
1080
1081    return JB_ERR_OK;
1082
1083 }
1084
1085
1086 /*********************************************************************
1087  *
1088  * Function    :  read_socks_reply
1089  *
1090  * Description :  Read from a socket connected to a socks server.
1091  *
1092  * Parameters  :
1093  *          1  :  sfd = file descriptor of the socket to read
1094  *          2  :  buf = pointer to buffer where data will be written
1095  *                Must be >= len bytes long.
1096  *          3  :  len = maximum number of bytes to read
1097  *          4  :  timeout = Number of seconds to wait.
1098  *
1099  * Returns     :  On success, the number of bytes read is returned (zero
1100  *                indicates end of file), and the file position is advanced
1101  *                by this number.  It is not an error if this number is
1102  *                smaller than the number of bytes requested; this may hap-
1103  *                pen for example because fewer bytes are actually available
1104  *                right now (maybe because we were close to end-of-file, or
1105  *                because we are reading from a pipe, or from a terminal,
1106  *                or because read() was interrupted by a signal).  On error,
1107  *                -1 is returned, and errno is set appropriately.  In this
1108  *                case it is left unspecified whether the file position (if
1109  *                any) changes.
1110  *
1111  *********************************************************************/
1112 static int read_socks_reply(jb_socket sfd, char *buf, int len, int timeout)
1113 {
1114    if (!data_is_available(sfd, timeout))
1115    {
1116       if (socket_is_still_alive(sfd))
1117       {
1118          log_error(LOG_LEVEL_ERROR,
1119             "The socks connection timed out after %d seconds.", timeout);
1120       }
1121       else
1122       {
1123          log_error(LOG_LEVEL_ERROR, "The socks server hung "
1124             "up the connection without sending a response.");
1125       }
1126       return -1;
1127    }
1128
1129    return read_socket(sfd, buf, len);
1130
1131 }
1132
1133
1134 /*********************************************************************
1135  *
1136  * Function    :  socks5_connect
1137  *
1138  * Description :  Connect to the SOCKS server, and connect through
1139  *                it to the specified server.   This handles
1140  *                all the SOCKS negotiation, and returns a file
1141  *                descriptor for a socket which can be treated as a
1142  *                normal (non-SOCKS) socket.
1143  *
1144  * Parameters  :
1145  *          1  :  fwd = Specifies the SOCKS proxy to use.
1146  *          2  :  target_host = The final server to connect to.
1147  *          3  :  target_port = The final port to connect to.
1148  *          4  :  csp = Current client state (buffers, headers, etc...)
1149  *
1150  * Returns     :  JB_INVALID_SOCKET => failure, else a socket file descriptor.
1151  *
1152  *********************************************************************/
1153 static jb_socket socks5_connect(const struct forward_spec *fwd,
1154                                 const char *target_host,
1155                                 int target_port,
1156                                 struct client_state *csp)
1157 {
1158 #define SIZE_SOCKS5_REPLY_IPV4 10
1159 #define SIZE_SOCKS5_REPLY_IPV6 22
1160 #define SIZE_SOCKS5_REPLY_DOMAIN 300
1161 #define SOCKS5_REPLY_DIFFERENCE (SIZE_SOCKS5_REPLY_IPV6 - SIZE_SOCKS5_REPLY_IPV4)
1162    int err = 0;
1163    char cbuf[300];
1164    char sbuf[SIZE_SOCKS5_REPLY_DOMAIN];
1165    size_t client_pos = 0;
1166    int server_size = 0;
1167    size_t hostlen = 0;
1168    jb_socket sfd;
1169    const char *errstr = NULL;
1170
1171    assert(fwd->gateway_host);
1172    if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
1173    {
1174       errstr = "NULL gateway host specified";
1175       err = 1;
1176    }
1177
1178    if (fwd->gateway_port <= 0)
1179    {
1180       /*
1181        * XXX: currently this can't happen because in
1182        * case of invalid gateway ports we use the defaults.
1183        * Of course we really shouldn't do that.
1184        */
1185       errstr = "invalid gateway port specified";
1186       err = 1;
1187    }
1188
1189    hostlen = strlen(target_host);
1190    if (hostlen > (size_t)255)
1191    {
1192       errstr = "target host name is longer than 255 characters";
1193       err = 1;
1194    }
1195
1196    if ((fwd->type != SOCKS_5) && (fwd->type != SOCKS_5T))
1197    {
1198       /* Should never get here */
1199       log_error(LOG_LEVEL_FATAL,
1200          "SOCKS5 impossible internal error - bad SOCKS type");
1201       err = 1;
1202    }
1203
1204    if (err)
1205    {
1206       errno = EINVAL;
1207       assert(errstr != NULL);
1208       log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1209       csp->error_message = strdup(errstr);
1210       return(JB_INVALID_SOCKET);
1211    }
1212
1213 #ifdef FUZZ
1214    sfd = 0;
1215    if (!err && read_socket(sfd, sbuf, 2) != 2)
1216 #else
1217    /* pass the request to the socks server */
1218    sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
1219
1220    if (sfd == JB_INVALID_SOCKET)
1221    {
1222       errstr = "socks5 server unreachable";
1223       log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1224       /* Free the generic error message provided by connect_to() */
1225       freez(csp->error_message);
1226       csp->error_message = strdup(errstr);
1227       return(JB_INVALID_SOCKET);
1228    }
1229
1230    client_pos = 0;
1231    cbuf[client_pos++] = '\x05'; /* Version */
1232
1233    if (fwd->auth_username && fwd->auth_password)
1234    {
1235       cbuf[client_pos++] = '\x02'; /* Two authentication methods supported */
1236       cbuf[client_pos++] = '\x02'; /* Username/password */
1237    }
1238    else
1239    {
1240       cbuf[client_pos++] = '\x01'; /* One authentication method supported */
1241    }
1242    cbuf[client_pos++] = '\x00'; /* The no authentication authentication method */
1243
1244    if (write_socket(sfd, cbuf, client_pos))
1245    {
1246       errstr = "SOCKS5 negotiation write failed";
1247       csp->error_message = strdup(errstr);
1248       log_error(LOG_LEVEL_CONNECT, "%s", errstr);
1249       close_socket(sfd);
1250       return(JB_INVALID_SOCKET);
1251    }
1252    if (read_socks_reply(sfd, sbuf, sizeof(sbuf),
1253          csp->config->socket_timeout) != 2)
1254 #endif
1255    {
1256       errstr = "SOCKS5 negotiation read failed";
1257       err = 1;
1258    }
1259
1260    if (!err && (sbuf[0] != '\x05'))
1261    {
1262       errstr = "SOCKS5 negotiation protocol version error";
1263       err = 1;
1264    }
1265
1266    if (!err && (sbuf[1] == '\xff'))
1267    {
1268       errstr = "SOCKS5 authentication required";
1269       err = 1;
1270    }
1271
1272    if (!err && (sbuf[1] == '\x02'))
1273    {
1274       if (fwd->auth_username && fwd->auth_password)
1275       {
1276          /* check cbuf overflow */
1277          size_t auth_len = strlen(fwd->auth_username) + strlen(fwd->auth_password) + 3;
1278          if (auth_len > sizeof(cbuf))
1279          {
1280             errstr = "SOCKS5 username and/or password too long";
1281             err = 1;
1282          }
1283       }
1284       else
1285       {
1286          errstr = "SOCKS5 server requested authentication while "
1287             "no credentials are configured";
1288          err = 1;
1289       }
1290
1291       if (!err)
1292       {
1293          client_pos = 0;
1294          cbuf[client_pos++] = '\x01'; /* Version */
1295          cbuf[client_pos++] = (char)strlen(fwd->auth_username);
1296
1297          memcpy(cbuf + client_pos, fwd->auth_username, strlen(fwd->auth_username));
1298          client_pos += strlen(fwd->auth_username);
1299          cbuf[client_pos++] = (char)strlen(fwd->auth_password);
1300          memcpy(cbuf + client_pos, fwd->auth_password, strlen(fwd->auth_password));
1301          client_pos += strlen(fwd->auth_password);
1302
1303          if (write_socket(sfd, cbuf, client_pos))
1304          {
1305             errstr = "SOCKS5 negotiation auth write failed";
1306             csp->error_message = strdup(errstr);
1307             log_error(LOG_LEVEL_CONNECT, "%s", errstr);
1308             close_socket(sfd);
1309             return(JB_INVALID_SOCKET);
1310          }
1311
1312          if (read_socks_reply(sfd, sbuf, sizeof(sbuf),
1313                csp->config->socket_timeout) != 2)
1314          {
1315             errstr = "SOCKS5 negotiation auth read failed";
1316             err = 1;
1317          }
1318       }
1319
1320       if (!err && (sbuf[1] != '\x00'))
1321       {
1322          errstr = "SOCKS5 authentication failed";
1323          err = 1;
1324       }
1325    }
1326    else if (!err && (sbuf[1] != '\x00'))
1327    {
1328       errstr = "SOCKS5 negotiation protocol error";
1329       err = 1;
1330    }
1331
1332    if (err)
1333    {
1334       assert(errstr != NULL);
1335       log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1336       csp->error_message = strdup(errstr);
1337       close_socket(sfd);
1338       errno = EINVAL;
1339       return(JB_INVALID_SOCKET);
1340    }
1341
1342    client_pos = 0;
1343    cbuf[client_pos++] = '\x05'; /* Version */
1344    cbuf[client_pos++] = '\x01'; /* TCP connect */
1345    cbuf[client_pos++] = '\x00'; /* Reserved, must be 0x00 */
1346    if (host_is_ip_address(target_host) && NULL == strstr(target_host, ":"))
1347    {
1348       cbuf[client_pos++] = '\x01'; /* Address is IPv4 address. */
1349       if (JB_ERR_OK != convert_ipv4_address_to_bytes(target_host, &cbuf[client_pos]))
1350       {
1351          errstr = "SOCKS5 error. Failed to convert target address to IP address";
1352          csp->error_message = strdup(errstr);
1353          log_error(LOG_LEVEL_CONNECT, "%s", errstr);
1354          close_socket(sfd);
1355          errno = EINVAL;
1356          return(JB_INVALID_SOCKET);
1357       }
1358       client_pos += 4;
1359    }
1360    else
1361    {
1362       /*
1363        * XXX: This branch is currently also used for IPv6 addresses
1364        */
1365       cbuf[client_pos++] = '\x03'; /* Address is domain name. */
1366       cbuf[client_pos++] = (char)(hostlen & 0xffu);
1367       assert(sizeof(cbuf) - client_pos > (size_t)255);
1368       /* Using strncpy because we really want the nul byte padding. */
1369       strncpy(cbuf + client_pos, target_host, sizeof(cbuf) - client_pos - 1);
1370       client_pos += (hostlen & 0xffu);
1371    }
1372    cbuf[client_pos++] = (char)((target_port >> 8) & 0xff);
1373    cbuf[client_pos++] = (char)((target_port     ) & 0xff);
1374
1375 #ifndef FUZZ
1376    if (write_socket(sfd, cbuf, client_pos))
1377    {
1378       errstr = "SOCKS5 negotiation write failed";
1379       csp->error_message = strdup(errstr);
1380       log_error(LOG_LEVEL_CONNECT, "%s", errstr);
1381       close_socket(sfd);
1382       errno = EINVAL;
1383       return(JB_INVALID_SOCKET);
1384    }
1385
1386    /*
1387     * Optimistically send the HTTP request with the initial
1388     * SOCKS request if the user enabled the use of Tor extensions,
1389     * the CONNECT method isn't being used (in which case the client
1390     * doesn't send data until it gets our 200 response) and the
1391     * client request has actually been completely read already.
1392     */
1393    if ((fwd->type == SOCKS_5T) && (csp->http->ssl == 0)
1394       && (csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
1395    {
1396       char *client_headers = list_to_text(csp->headers);
1397       size_t header_length;
1398
1399       if (client_headers == NULL)
1400       {
1401          log_error(LOG_LEVEL_FATAL, "Out of memory rebuilding client headers.");
1402       }
1403       list_remove_all(csp->headers);
1404       header_length= strlen(client_headers);
1405
1406       log_error(LOG_LEVEL_CONNECT,
1407          "Optimistically sending %lu bytes of client headers intended for %s.",
1408          header_length, csp->http->hostport);
1409
1410       if (write_socket(sfd, client_headers, header_length))
1411       {
1412          log_error(LOG_LEVEL_CONNECT,
1413             "optimistically writing header to: %s failed: %E", csp->http->hostport);
1414          freez(client_headers);
1415          return(JB_INVALID_SOCKET);
1416       }
1417       freez(client_headers);
1418       if (csp->expected_client_content_length != 0)
1419       {
1420          unsigned long long buffered_request_bytes =
1421             (unsigned long long)(csp->client_iob->eod - csp->client_iob->cur);
1422          log_error(LOG_LEVEL_CONNECT,
1423             "Optimistically sending %llu bytes of client body. Expected %llu.",
1424             csp->expected_client_content_length, buffered_request_bytes);
1425          assert(csp->expected_client_content_length == buffered_request_bytes);
1426          if (write_socket(sfd, csp->client_iob->cur, buffered_request_bytes))
1427          {
1428             log_error(LOG_LEVEL_CONNECT,
1429                "optimistically writing %llu bytes of client body to: %s failed: %E",
1430                buffered_request_bytes, csp->http->hostport);
1431             return(JB_INVALID_SOCKET);
1432          }
1433          clear_iob(csp->client_iob);
1434       }
1435    }
1436 #endif
1437
1438    server_size = read_socks_reply(sfd, sbuf, SIZE_SOCKS5_REPLY_IPV4,
1439       csp->config->socket_timeout);
1440    if (server_size != SIZE_SOCKS5_REPLY_IPV4)
1441    {
1442       errstr = "SOCKS5 negotiation read failed";
1443    }
1444    else
1445    {
1446       if (sbuf[0] != '\x05')
1447       {
1448          errstr = "SOCKS5 negotiation protocol version error";
1449       }
1450       else if (sbuf[2] != '\x00')
1451       {
1452          errstr = "SOCKS5 negotiation protocol error";
1453       }
1454       else if (sbuf[1] != SOCKS5_REQUEST_GRANTED)
1455       {
1456          errstr = translate_socks5_error(sbuf[1]);
1457       }
1458       else
1459       {
1460          if (sbuf[3] == '\x04')
1461          {
1462             /*
1463              * The address field contains an IPv6 address
1464              * which means we didn't get the whole reply
1465              * yet. Read and discard the rest of it to make
1466              * sure it isn't treated as HTTP data later on.
1467              */
1468             server_size = read_socks_reply(sfd, sbuf, SOCKS5_REPLY_DIFFERENCE,
1469                csp->config->socket_timeout);
1470             if (server_size != SOCKS5_REPLY_DIFFERENCE)
1471             {
1472                errstr = "SOCKS5 negotiation read failed (IPv6 address)";
1473             }
1474          }
1475          else if (sbuf[3] == '\x03')
1476          {
1477             /*
1478              * The address field contains a domain name
1479              * which means we didn't get the whole reply
1480              * yet. Read and discard the rest of it to make
1481              * sure it isn't treated as HTTP data later on.
1482              */
1483             unsigned domain_length = (unsigned)sbuf[4];
1484             int bytes_left_to_read = 5 + (int)domain_length + 2 - SIZE_SOCKS5_REPLY_IPV4;
1485             if (bytes_left_to_read <= 0 || sizeof(sbuf) < bytes_left_to_read)
1486             {
1487                errstr = "SOCKS5 negotiation read failed (Invalid domain length)";
1488             }
1489             else
1490             {
1491                server_size = read_socks_reply(sfd, sbuf, bytes_left_to_read,
1492                   csp->config->socket_timeout);
1493                if (server_size != bytes_left_to_read)
1494                {
1495                   errstr = "SOCKS5 negotiation read failed (Domain name)";
1496                }
1497             }
1498          }
1499          else if (sbuf[3] != '\x01')
1500          {
1501             errstr = "SOCKS5 reply contains unsupported address type";
1502          }
1503          if (errstr == NULL)
1504          {
1505             return(sfd);
1506          }
1507       }
1508    }
1509
1510    assert(errstr != NULL);
1511    csp->error_message = strdup(errstr);
1512    log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1513    close_socket(sfd);
1514    errno = EINVAL;
1515
1516    return(JB_INVALID_SOCKET);
1517
1518 }
1519
1520 /*
1521   Local Variables:
1522   tab-width: 3
1523   end:
1524 */