LCOV - code coverage report
Current view: top level - fuzz - gateway.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 51 440 11.6 %
Date: 2021-02-22 04:51:02 Functions: 5 15 33.3 %

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

Generated by: LCOV version 1.14