adcb11c9cede2440ec2891ff3c9b26df0a8c5c96
[privoxy.git] / gateway.c
1 const char gateway_rcs[] = "$Id: gateway.c,v 1.44 2008/11/22 11:54:04 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
5  *
6  * Purpose     :  Contains functions to connect to a server, possibly
7  *                using a "forwarder" (i.e. HTTP proxy and/or a SOCKS4
8  *                proxy).
9  *
10  * Copyright   :  Written by and Copyright (C) 2001-2008 the SourceForge
11  *                Privoxy team. http://www.privoxy.org/
12  *
13  *                Based on the Internet Junkbuster originally written
14  *                by and Copyright (C) 1997 Anonymous Coders and
15  *                Junkbusters Corporation.  http://www.junkbusters.com
16  *
17  *                This program is free software; you can redistribute it
18  *                and/or modify it under the terms of the GNU General
19  *                Public License as published by the Free Software
20  *                Foundation; either version 2 of the License, or (at
21  *                your option) any later version.
22  *
23  *                This program is distributed in the hope that it will
24  *                be useful, but WITHOUT ANY WARRANTY; without even the
25  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
26  *                PARTICULAR PURPOSE.  See the GNU General Public
27  *                License for more details.
28  *
29  *                The GNU General Public License should be included with
30  *                this file.  If not, you can view it at
31  *                http://www.gnu.org/copyleft/gpl.html
32  *                or write to the Free Software Foundation, Inc., 59
33  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
34  *
35  * Revisions   :
36  *    $Log: gateway.c,v $
37  *    Revision 1.44  2008/11/22 11:54:04  fabiankeil
38  *    Move log message around to include the socket number.
39  *
40  *    Revision 1.43  2008/11/13 09:15:51  fabiankeil
41  *    Make keep_alive_timeout static.
42  *
43  *    Revision 1.42  2008/11/13 09:08:42  fabiankeil
44  *    Add new config option: keep-alive-timeout.
45  *
46  *    Revision 1.41  2008/11/08 15:29:58  fabiankeil
47  *    Unify two debug messages.
48  *
49  *    Revision 1.40  2008/11/08 15:14:05  fabiankeil
50  *    Fix duplicated debugging check.
51  *
52  *    Revision 1.39  2008/10/25 11:33:01  fabiankeil
53  *    Remove already out-commented line left over from debugging.
54  *
55  *    Revision 1.38  2008/10/24 17:33:00  fabiankeil
56  *    - Tone the "keep-alive support is experimental" warning
57  *      down a bit as hackish 0-chunk detection has been
58  *      implemented recently.
59  *    - Only show the "ndef HAVE_POLL" warning once on start-up.
60  *
61  *    Revision 1.37  2008/10/23 17:40:53  fabiankeil
62  *    Fix forget_connection() and mark_connection_unused(),
63  *    which would both under certain circumstances access
64  *    reusable_connection[MAX_REUSABLE_CONNECTIONS]. Oops.
65  *
66  *    Revision 1.36  2008/10/18 19:49:15  fabiankeil
67  *    - Factor close_unusable_connections() out of
68  *      get_reusable_connection() to make sure we really check
69  *      all the remembered connections, not just the ones before
70  *      the next reusable one.
71  *    - Plug two file descriptor leaks. Internally marking
72  *      connections as closed doesn't cut it.
73  *
74  *    Revision 1.35  2008/10/17 17:12:01  fabiankeil
75  *    In socket_is_still_usable(), use select()
76  *    and FD_ISSET() if poll() isn't available.
77  *
78  *    Revision 1.34  2008/10/17 17:07:13  fabiankeil
79  *    Add preliminary timeout support.
80  *
81  *    Revision 1.33  2008/10/16 16:34:21  fabiankeil
82  *    Fix two gcc44 warnings.
83  *
84  *    Revision 1.32  2008/10/16 16:27:22  fabiankeil
85  *    Fix compiler warning.
86  *
87  *    Revision 1.31  2008/10/16 07:31:11  fabiankeil
88  *    - Factor socket_is_still_usable() out of get_reusable_connection().
89  *    - If poll() isn't available, show a warning and assume the socket
90  *      is still usable.
91  *
92  *    Revision 1.30  2008/10/13 17:31:03  fabiankeil
93  *    If a remembered connection is no longer usable and
94  *    has been marked closed, don't bother checking if the
95  *    destination matches.
96  *
97  *    Revision 1.29  2008/10/11 16:59:41  fabiankeil
98  *    Add missing dots for two log messages.
99  *
100  *    Revision 1.28  2008/10/09 18:21:41  fabiankeil
101  *    Flush work-in-progress changes to keep outgoing connections
102  *    alive where possible. Incomplete and mostly #ifdef'd out.
103  *
104  *    Revision 1.27  2008/09/27 15:05:51  fabiankeil
105  *    Return only once in forwarded_connect().
106  *
107  *    Revision 1.26  2008/08/18 17:42:06  fabiankeil
108  *    Fix typo in macro name.
109  *
110  *    Revision 1.25  2008/02/07 18:09:46  fabiankeil
111  *    In socks5_connect:
112  *    - make the buffers quite a bit smaller.
113  *    - properly report "socks5 server unreachable" failures.
114  *    - let strncpy() use the whole buffer. Using a length of 0xffu wasn't actually
115  *      wrong, but requires too much thinking as it doesn't depend on the buffer size.
116  *    - log a message if the socks5 server sends more data than expected.
117  *    - add some assertions and comments.
118  *
119  *    Revision 1.24  2008/02/04 14:56:29  fabiankeil
120  *    - Fix a compiler warning.
121  *    - Stop assuming that htonl(INADDR_NONE) equals INADDR_NONE.
122  *
123  *    Revision 1.23  2008/02/04 13:11:35  fabiankeil
124  *    Remember the cause of the SOCKS5 error for the CGI message.
125  *
126  *    Revision 1.22  2008/02/03 13:46:15  fabiankeil
127  *    Add SOCKS5 support. Patch #1862863 by Eric M. Hopper with minor changes.
128  *
129  *    Revision 1.21  2007/07/28 12:30:03  fabiankeil
130  *    Modified patch from Song Weijia (#1762559) to
131  *    fix socks requests on big-endian platforms.
132  *
133  *    Revision 1.20  2007/05/14 10:23:48  fabiankeil
134  *    - Use strlcpy() instead of strcpy().
135  *    - Use the same buffer for socks requests and socks responses.
136  *    - Fix bogus warning about web_server_addr being used uninitialized.
137  *
138  *    Revision 1.19  2007/01/25 14:09:45  fabiankeil
139  *    - Save errors in socks4_connect() to csp->error_message.
140  *    - Silence some gcc43 warnings, hopefully the right way.
141  *
142  *    Revision 1.18  2006/07/18 14:48:46  david__schmidt
143  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
144  *    with what was really the latest development (the v_3_0_branch branch)
145  *
146  *    Revision 1.16  2002/05/12 21:36:29  jongfoster
147  *    Correcting function comments
148  *
149  *    Revision 1.15  2002/03/26 22:29:54  swa
150  *    we have a new homepage!
151  *
152  *    Revision 1.14  2002/03/24 13:25:43  swa
153  *    name change related issues
154  *
155  *    Revision 1.13  2002/03/13 00:29:59  jongfoster
156  *    Killing warnings
157  *
158  *    Revision 1.12  2002/03/09 20:03:52  jongfoster
159  *    - Making various functions return int rather than size_t.
160  *      (Undoing a recent change).  Since size_t is unsigned on
161  *      Windows, functions like read_socket that return -1 on
162  *      error cannot return a size_t.
163  *
164  *      THIS WAS A MAJOR BUG - it caused frequent, unpredictable
165  *      crashes, and also frequently caused JB to jump to 100%
166  *      CPU and stay there.  (Because it thought it had just
167  *      read ((unsigned)-1) == 4Gb of data...)
168  *
169  *    - The signature of write_socket has changed, it now simply
170  *      returns success=0/failure=nonzero.
171  *
172  *    - Trying to get rid of a few warnings --with-debug on
173  *      Windows, I've introduced a new type "jb_socket".  This is
174  *      used for the socket file descriptors.  On Windows, this
175  *      is SOCKET (a typedef for unsigned).  Everywhere else, it's
176  *      an int.  The error value can't be -1 any more, so it's
177  *      now JB_INVALID_SOCKET (which is -1 on UNIX, and in
178  *      Windows it maps to the #define INVALID_SOCKET.)
179  *
180  *    - The signature of bind_port has changed.
181  *
182  *    Revision 1.11  2002/03/08 17:46:04  jongfoster
183  *    Fixing int/size_t warnings
184  *
185  *    Revision 1.10  2002/03/07 03:50:19  oes
186  *     - Improved handling of failed DNS lookups
187  *     - Fixed compiler warnings
188  *
189  *    Revision 1.9  2001/10/25 03:40:48  david__schmidt
190  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
191  *    threads to call select() simultaneously.  So, it's time to do a real, live,
192  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
193  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
194  *
195  *    Revision 1.8  2001/09/13 20:10:12  jongfoster
196  *    Fixing missing #include under Windows
197  *
198  *    Revision 1.7  2001/09/12 17:58:26  steudten
199  *
200  *    add #include <string.h>
201  *
202  *    Revision 1.6  2001/09/10 10:41:16  oes
203  *    Added #include in.h
204  *
205  *    Revision 1.5  2001/07/29 18:47:57  jongfoster
206  *    Adding missing #include project.h
207  *
208  *    Revision 1.4  2001/07/24 12:47:06  oes
209  *    Applied BeOS support update by Eugenia
210  *
211  *    Revision 1.3  2001/06/09 10:55:28  jongfoster
212  *    Changing BUFSIZ ==> BUFFER_SIZE
213  *
214  *    Revision 1.2  2001/06/07 23:11:38  jongfoster
215  *    Removing gateways[] list - no longer used.
216  *    Replacing function pointer in struct gateway with a directly
217  *    called function forwarded_connect(), which can do the common
218  *    task of deciding whether to connect to the web server or HTTP
219  *    proxy.
220  *    Replacing struct gateway with struct forward_spec
221  *    Fixing bug with SOCKS4A and HTTP proxy server in combination.
222  *    It was a bug which led to the connection being made to the web
223  *    server rather than the HTTP proxy, and also a buffer overrun.
224  *
225  *    Revision 1.1.1.1  2001/05/15 13:58:54  oes
226  *    Initial import of version 2.9.3 source tree
227  *
228  *
229  *********************************************************************/
230 \f
231
232 #include "config.h"
233
234 #include <stdio.h>
235 #include <sys/types.h>
236
237 #ifndef _WIN32
238 #include <netinet/in.h>
239 #endif
240
241 #include <errno.h>
242 #include <string.h>
243 #include "assert.h"
244
245 #ifdef _WIN32
246 #include <winsock2.h>
247 #endif /* def _WIN32 */
248
249 #ifdef __BEOS__
250 #include <netdb.h>
251 #endif /* def __BEOS__ */
252
253 #ifdef __OS2__
254 #include <utils.h>
255 #endif /* def __OS2__ */
256
257 #include "project.h"
258 #include "jcc.h"
259 #include "errlog.h"
260 #include "jbsockets.h"
261 #include "gateway.h"
262 #include "miscutil.h"
263 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
264 #ifdef HAVE_POLL
265 #ifdef __GLIBC__ 
266 #include <sys/poll.h>
267 #else
268 #include <poll.h>
269 #endif /* def __GLIBC__ */
270 #endif /* HAVE_POLL */
271 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
272
273 const char gateway_h_rcs[] = GATEWAY_H_VERSION;
274
275 static jb_socket socks4_connect(const struct forward_spec * fwd,
276                                 const char * target_host,
277                                 int target_port,
278                                 struct client_state *csp);
279
280 static jb_socket socks5_connect(const struct forward_spec *fwd,
281                                 const char *target_host,
282                                 int target_port,
283                                 struct client_state *csp);
284
285
286 #define SOCKS_REQUEST_GRANTED          90
287 #define SOCKS_REQUEST_REJECT           91
288 #define SOCKS_REQUEST_IDENT_FAILED     92
289 #define SOCKS_REQUEST_IDENT_CONFLICT   93
290
291 #define SOCKS5_REQUEST_GRANTED             0
292 #define SOCKS5_REQUEST_FAILED              1
293 #define SOCKS5_REQUEST_DENIED              2
294 #define SOCKS5_REQUEST_NETWORK_UNREACHABLE 3
295 #define SOCKS5_REQUEST_HOST_UNREACHABLE    4
296 #define SOCKS5_REQUEST_CONNECTION_REFUSED  5
297 #define SOCKS5_REQUEST_TTL_EXPIRED         6
298 #define SOCKS5_REQUEST_PROTOCOL_ERROR      7
299 #define SOCKS5_REQUEST_BAD_ADDRESS_TYPE    8
300
301 /* structure of a socks client operation */
302 struct socks_op {
303    unsigned char vn;          /* socks version number */
304    unsigned char cd;          /* command code */
305    unsigned char dstport[2];  /* destination port */
306    unsigned char dstip[4];    /* destination address */
307    char userid;               /* first byte of userid */
308    char padding[3];           /* make sure sizeof(struct socks_op) is endian-independent. */
309    /* more bytes of the userid follow, terminated by a NULL */
310 };
311
312 /* structure of a socks server reply */
313 struct socks_reply {
314    unsigned char vn;          /* socks version number */
315    unsigned char cd;          /* command code */
316    unsigned char dstport[2];  /* destination port */
317    unsigned char dstip[4];    /* destination address */
318 };
319
320 static const char socks_userid[] = "anonymous";
321
322 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
323
324 #define MAX_REUSABLE_CONNECTIONS 100
325 static int keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
326
327 struct reusable_connection
328 {
329    jb_socket sfd;
330    int       in_use;
331    char      *host;
332    int       port;
333    time_t    timestamp;
334
335    int       forwarder_type;
336    char      *gateway_host;
337    int       gateway_port;
338    char      *forward_host;
339    int       forward_port;
340 };
341
342 static struct reusable_connection reusable_connection[MAX_REUSABLE_CONNECTIONS];
343
344 static int mark_connection_unused(jb_socket sfd);
345 static void mark_connection_closed(struct reusable_connection *closed_connection);
346 static int socket_is_still_usable(jb_socket sfd);
347
348
349 /*********************************************************************
350  *
351  * Function    :  initialize_reusable_connections
352  *
353  * Description :  Initializes the reusable_connection structures.
354  *                Must be called with connection_reuse_mutex locked.
355  *
356  * Parameters  : N/A
357  *
358  * Returns     : void
359  *
360  *********************************************************************/
361 extern void initialize_reusable_connections(void)
362 {
363    unsigned int slot = 0;
364
365    log_error(LOG_LEVEL_INFO,
366       "Support for 'Connection: keep-alive' is experimental."
367 #ifndef HAVE_POLL
368       " Detecting already dead connections might not work"
369       " correctly on your platform."
370 #endif /* ndef HAVE_POLL */
371    );
372
373    for (slot = 0; slot < SZ(reusable_connection); slot++)
374    {
375       mark_connection_closed(&reusable_connection[slot]);
376    }
377
378    log_error(LOG_LEVEL_CONNECT, "Initialized %d socket slots.", slot);
379 }
380
381
382 /*********************************************************************
383  *
384  * Function    :  remember_connection
385  *
386  * Description :  Remembers a connection for reuse later on.
387  *
388  * Parameters  :
389  *          1  :  sfd  = Open socket to remember.
390  *          2  :  http = The destination for the connection.
391  *          3  :  fwd  = The forwarder settings used.
392  *
393  * Returns     : void
394  *
395  *********************************************************************/
396 void remember_connection(jb_socket sfd, const struct http_request *http,
397                                         const struct forward_spec *fwd)
398 {
399    unsigned int slot = 0;
400    int free_slot_found = FALSE;
401
402    assert(sfd != JB_INVALID_SOCKET);
403
404    if (mark_connection_unused(sfd))
405    {
406       return;
407    }
408
409    privoxy_mutex_lock(&connection_reuse_mutex);
410
411    /* Find free socket slot. */
412    for (slot = 0; slot < SZ(reusable_connection); slot++)
413    {
414       if (reusable_connection[slot].sfd == JB_INVALID_SOCKET)
415       {
416          assert(reusable_connection[slot].in_use == 0);
417          log_error(LOG_LEVEL_CONNECT,
418             "Remembering socket %d for %s:%d in slot %d.",
419             sfd, http->host, http->port, slot);
420          free_slot_found = TRUE;
421          break;
422       }
423    }
424
425    if (!free_slot_found)
426    {
427       log_error(LOG_LEVEL_CONNECT,
428         "No free slots found to remembering socket for %s:%d. Last slot %d.",
429         http->host, http->port, slot);
430       privoxy_mutex_unlock(&connection_reuse_mutex);
431       close_socket(sfd);
432       return;
433    }
434
435    assert(NULL != http->host);
436    reusable_connection[slot].host = strdup(http->host);
437    if (NULL == reusable_connection[slot].host)
438    {
439       log_error(LOG_LEVEL_FATAL, "Out of memory saving socket.");
440    }
441    reusable_connection[slot].sfd = sfd;
442    reusable_connection[slot].port = http->port;
443    reusable_connection[slot].in_use = 0;
444    reusable_connection[slot].timestamp = time(NULL);
445
446    assert(NULL != fwd);
447    assert(reusable_connection[slot].gateway_host == NULL);
448    assert(reusable_connection[slot].gateway_port == 0);
449    assert(reusable_connection[slot].forwarder_type == SOCKS_NONE);
450    assert(reusable_connection[slot].forward_host == NULL);
451    assert(reusable_connection[slot].forward_port == 0);
452
453    reusable_connection[slot].forwarder_type = fwd->type;
454    if (NULL != fwd->gateway_host)
455    {
456       reusable_connection[slot].gateway_host = strdup(fwd->gateway_host);
457       if (NULL == reusable_connection[slot].gateway_host)
458       {
459          log_error(LOG_LEVEL_FATAL, "Out of memory saving gateway_host.");
460       }
461    }
462    else
463    {
464       reusable_connection[slot].gateway_host = NULL;
465    }
466    reusable_connection[slot].gateway_port = fwd->gateway_port;
467
468    if (NULL != fwd->forward_host)
469    {
470       reusable_connection[slot].forward_host = strdup(fwd->forward_host);
471       if (NULL == reusable_connection[slot].forward_host)
472       {
473          log_error(LOG_LEVEL_FATAL, "Out of memory saving forward_host.");
474       }
475    }
476    else
477    {
478       reusable_connection[slot].forward_host = NULL;
479    }
480    reusable_connection[slot].forward_port = fwd->forward_port;
481
482    privoxy_mutex_unlock(&connection_reuse_mutex);
483 }
484
485
486 /*********************************************************************
487  *
488  * Function    :  mark_connection_closed
489  *
490  * Description : Marks a reused connection closed.
491  *               Must be called with connection_reuse_mutex locked.
492  *
493  * Parameters  :
494  *          1  :  closed_connection = The connection to mark as closed.
495  *
496  * Returns     : void
497  *
498  *********************************************************************/
499 static void mark_connection_closed(struct reusable_connection *closed_connection)
500 {
501    closed_connection->in_use = FALSE;
502    closed_connection->sfd = JB_INVALID_SOCKET;
503    freez(closed_connection->host);
504    closed_connection->port = 0;
505    closed_connection->timestamp = 0;
506    closed_connection->forwarder_type = SOCKS_NONE;
507    freez(closed_connection->gateway_host);
508    closed_connection->gateway_port = 0;
509    freez(closed_connection->forward_host);
510    closed_connection->forward_port = 0;
511 }
512
513
514 /*********************************************************************
515  *
516  * Function    :  forget_connection
517  *
518  * Description :  Removes a previously remembered connection from
519  *                the list of reusable connections.
520  *
521  * Parameters  :
522  *          1  :  sfd = The socket belonging to the connection in question.
523  *
524  * Returns     : void
525  *
526  *********************************************************************/
527 void forget_connection(jb_socket sfd)
528 {
529    unsigned int slot = 0;
530
531    assert(sfd != JB_INVALID_SOCKET);
532
533    privoxy_mutex_lock(&connection_reuse_mutex);
534
535    for (slot = 0; slot < SZ(reusable_connection); slot++)
536    {
537       if (reusable_connection[slot].sfd == sfd)
538       {
539          assert(reusable_connection[slot].in_use);
540
541          log_error(LOG_LEVEL_CONNECT,
542             "Forgetting socket %d for %s:%d in slot %d.",
543             sfd, reusable_connection[slot].host,
544             reusable_connection[slot].port, slot);
545          mark_connection_closed(&reusable_connection[slot]);
546          privoxy_mutex_unlock(&connection_reuse_mutex);
547
548          return;
549       }
550    }
551
552    log_error(LOG_LEVEL_CONNECT,
553       "Socket %d already forgotten or never remembered.", sfd);
554
555    privoxy_mutex_unlock(&connection_reuse_mutex);
556 }
557
558
559 /*********************************************************************
560  *
561  * Function    :  connection_destination_matches
562  *
563  * Description :  Determines whether a remembered connection can
564  *                be reused. That is whether the destination and
565  *                the forwarding settings match.
566  *
567  * Parameters  :
568  *          1  :  connection = The connection to check.
569  *          2  :  http = The destination for the connection.
570  *          3  :  fwd  = The forwarder settings.
571  *
572  * Returns     :  TRUE for yes, FALSE otherwise.
573  *
574  *********************************************************************/
575 static int connection_destination_matches(const struct reusable_connection *connection,
576                                           const struct http_request *http,
577                                           const struct forward_spec *fwd)
578 {
579    /* XXX: Start of duplicated checks for debugging purposes. */
580    if (strcmpic(connection->host, http->host))
581    {
582       return FALSE;
583    }
584
585    if (connection->forwarder_type != fwd->type)
586    {
587       log_error(LOG_LEVEL_CONNECT, "Type mismatch: %d %d (%s)",
588          connection->forwarder_type, fwd->type, http->host);
589       return FALSE;
590    }
591    if (connection->gateway_port   != fwd->gateway_port)
592    {
593       log_error(LOG_LEVEL_CONNECT, "Gateway port mismatch: %d %d (%s)",
594          connection->gateway_port, fwd->gateway_port, http->host);
595       return FALSE;
596    }
597    if (connection->forward_port   != fwd->forward_port)
598    {
599       log_error(LOG_LEVEL_CONNECT, "Forward port mismatch: %d %d (%s)",
600          connection->forward_port, fwd->forward_port, http->host);
601       return FALSE;
602    }
603    if (connection->port != http->port)
604    {
605       log_error(LOG_LEVEL_CONNECT, "Server port mismatch: %d %d (%s)",
606          connection->port, http->port, http->host);
607       return FALSE;
608    }
609
610    /* XXX: End of duplicated checks for debugging purposes. */
611
612    if ((connection->forwarder_type != fwd->type)
613     || (connection->gateway_port   != fwd->gateway_port)
614     || (connection->forward_port   != fwd->forward_port)
615     || (connection->port           != http->port))
616    {
617       return FALSE;
618    }
619
620    if ((    (NULL != connection->gateway_host)
621          && (NULL != fwd->gateway_host)
622          && strcmpic(connection->gateway_host, fwd->gateway_host))
623        && (connection->gateway_host != fwd->gateway_host))
624    {
625       log_error(LOG_LEVEL_CONNECT, "Gateway mismatch.");
626       return FALSE;
627    }
628
629    if ((    (NULL != connection->forward_host)
630          && (NULL != fwd->forward_host)
631          && strcmpic(connection->forward_host, fwd->forward_host))
632       && (connection->forward_host != fwd->forward_host))
633    {
634       log_error(LOG_LEVEL_CONNECT, "Forwarding proxy mismatch.");
635       return FALSE;
636    }
637
638    return (!strcmpic(connection->host, http->host));
639
640 }
641
642
643 /*********************************************************************
644  *
645  * Function    :  close_unusable_connections
646  *
647  * Description :  Closes remembered connections that have timed
648  *                out or have been closed on the other side.
649  *
650  * Parameters  :  none
651  *
652  * Returns     :  void
653  *
654  *********************************************************************/
655 static void close_unusable_connections(void)
656 {
657    unsigned int slot = 0;
658
659    for (slot = 0; slot < SZ(reusable_connection); slot++)
660    {
661       if (!reusable_connection[slot].in_use
662          && (JB_INVALID_SOCKET != reusable_connection[slot].sfd))
663       {
664          time_t time_open = time(NULL) - reusable_connection[slot].timestamp;
665
666          if (keep_alive_timeout < time_open)
667          {
668             log_error(LOG_LEVEL_CONNECT,
669                "The connection to %s:%d in slot %d timed out. "
670                "Closing socket %d. Timeout is: %d.",
671                reusable_connection[slot].host,
672                reusable_connection[slot].port, slot,
673                reusable_connection[slot].sfd, keep_alive_timeout);
674             close_socket(reusable_connection[slot].sfd);
675             mark_connection_closed(&reusable_connection[slot]);
676             continue;
677          }
678
679          if (!socket_is_still_usable(reusable_connection[slot].sfd))
680          {
681             log_error(LOG_LEVEL_CONNECT,
682                "The connection to %s:%d in slot %d is no longer usable. "
683                "Closing socket %d.", reusable_connection[slot].host,
684                reusable_connection[slot].port, slot,
685                reusable_connection[slot].sfd);
686             close_socket(reusable_connection[slot].sfd);
687             mark_connection_closed(&reusable_connection[slot]);
688             continue;
689          }
690       }
691    }
692 }
693
694
695 /*********************************************************************
696  *
697  * Function    :  socket_is_still_usable
698  *
699  * Description :  Decides whether or not an open socket is still usable.
700  *
701  * Parameters  :
702  *          1  :  sfd = The socket to check.
703  *
704  * Returns     :  TRUE for yes, otherwise FALSE.
705  *
706  *********************************************************************/
707 static int socket_is_still_usable(jb_socket sfd)
708 {
709 #ifdef HAVE_POLL
710    int poll_result;
711    struct pollfd poll_fd[1];
712
713    memset(poll_fd, 0, sizeof(poll_fd));
714    poll_fd[0].fd = sfd;
715    poll_fd[0].events = POLLIN;
716
717    poll_result = poll(poll_fd, 1, 0);
718
719    if (-1 != poll_result)
720    {
721       return !(poll_fd[0].revents & POLLIN);
722    }
723    else
724    {
725       log_error(LOG_LEVEL_CONNECT, "Polling socket %d failed.", sfd);
726       return FALSE;
727    }
728 #else
729    fd_set readable_fds;
730    struct timeval timeout;
731    int ret;
732    int socket_is_alive = 0;
733
734    memset(&timeout, '\0', sizeof(timeout));
735    FD_ZERO(&readable_fds);
736    FD_SET(sfd, &readable_fds);
737
738    ret = select((int)sfd+1, &readable_fds, NULL, NULL, &timeout);
739    if (ret < 0)
740    {
741       log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
742    }
743
744    /*
745     * XXX: I'm not sure why !FD_ISSET() works,
746     * but apparently it does.
747     */
748    socket_is_alive = !FD_ISSET(sfd, &readable_fds);
749
750    return socket_is_alive;
751 #endif /* def HAVE_POLL */
752 }
753
754
755 /*********************************************************************
756  *
757  * Function    :  get_reusable_connection
758  *
759  * Description :  Returns an open socket to a previously remembered
760  *                open connection (if there is one).
761  *
762  * Parameters  :
763  *          1  :  http = The destination for the connection.
764  *          2  :  fwd  = The forwarder settings.
765  *
766  * Returns     :  JB_INVALID_SOCKET => No reusable connection found,
767  *                otherwise a usable socket.
768  *
769  *********************************************************************/
770 static jb_socket get_reusable_connection(const struct http_request *http,
771                                          const struct forward_spec *fwd)
772 {
773    jb_socket sfd = JB_INVALID_SOCKET;
774    unsigned int slot = 0;
775
776    privoxy_mutex_lock(&connection_reuse_mutex);
777
778    close_unusable_connections();
779
780    for (slot = 0; slot < SZ(reusable_connection); slot++)
781    {
782       if (!reusable_connection[slot].in_use
783          && (JB_INVALID_SOCKET != reusable_connection[slot].sfd))
784       {
785          if (connection_destination_matches(&reusable_connection[slot], http, fwd))
786          {
787             reusable_connection[slot].in_use = TRUE;
788             sfd = reusable_connection[slot].sfd;
789             log_error(LOG_LEVEL_CONNECT,
790                "Found reusable socket %d for %s:%d in slot %d.",
791                sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot);
792             break;
793          }
794       }
795    }
796
797    privoxy_mutex_unlock(&connection_reuse_mutex);
798
799    return sfd;
800
801 }
802
803
804 /*********************************************************************
805  *
806  * Function    :  mark_connection_unused
807  *
808  * Description :  Gives a remembered connection free for reuse.
809  *
810  * Parameters  :
811  *          1  :  sfd = The socket belonging to the connection in question.
812  *
813  * Returns     :  TRUE => Socket found and marked as unused.
814  *                FALSE => Socket not found.
815  *
816  *********************************************************************/
817 static int mark_connection_unused(jb_socket sfd)
818 {
819    unsigned int slot = 0;
820    int socket_found = FALSE;
821
822    assert(sfd != JB_INVALID_SOCKET);
823
824    privoxy_mutex_lock(&connection_reuse_mutex);
825
826    for (slot = 0; slot < SZ(reusable_connection); slot++)
827    {
828       if (reusable_connection[slot].sfd == sfd)
829       {
830          assert(reusable_connection[slot].in_use);
831          socket_found = TRUE;
832          log_error(LOG_LEVEL_CONNECT,
833             "Marking open socket %d for %s:%d in slot %d as unused.",
834             sfd, reusable_connection[slot].host,
835             reusable_connection[slot].port, slot);
836          reusable_connection[slot].in_use = 0;
837          reusable_connection[slot].timestamp = time(NULL);
838          break;
839       }
840    }
841
842    privoxy_mutex_unlock(&connection_reuse_mutex);
843
844    return socket_found;
845
846 }
847
848
849 /*********************************************************************
850  *
851  * Function    :  set_keep_alive_timeout
852  *
853  * Description :  Sets the timeout after which open
854  *                connections will no longer be reused.
855  *
856  * Parameters  :
857  *          1  :  timeout = The timeout in seconds.
858  *
859  * Returns     :  void
860  *
861  *********************************************************************/
862 void set_keep_alive_timeout(int timeout)
863 {
864    keep_alive_timeout = timeout;
865 }
866 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
867
868
869 /*********************************************************************
870  *
871  * Function    :  forwarded_connect
872  *
873  * Description :  Connect to a specified web server, possibly via
874  *                a HTTP proxy and/or a SOCKS proxy.
875  *
876  * Parameters  :
877  *          1  :  fwd = the proxies to use when connecting.
878  *          2  :  http = the http request and apropos headers
879  *          3  :  csp = Current client state (buffers, headers, etc...)
880  *
881  * Returns     :  JB_INVALID_SOCKET => failure, else it is the socket file descriptor.
882  *
883  *********************************************************************/
884 jb_socket forwarded_connect(const struct forward_spec * fwd,
885                             struct http_request *http,
886                             struct client_state *csp)
887 {
888    const char * dest_host;
889    int dest_port;
890    jb_socket sfd = JB_INVALID_SOCKET;
891
892 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
893    sfd = get_reusable_connection(http, fwd);
894    if (JB_INVALID_SOCKET != sfd)
895    {
896       return sfd;
897    }
898 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
899
900    /* Figure out if we need to connect to the web server or a HTTP proxy. */
901    if (fwd->forward_host)
902    {
903       /* HTTP proxy */
904       dest_host = fwd->forward_host;
905       dest_port = fwd->forward_port;
906    }
907    else
908    {
909       /* Web server */
910       dest_host = http->host;
911       dest_port = http->port;
912    }
913
914    /* Connect, maybe using a SOCKS proxy */
915    switch (fwd->type)
916    {
917       case SOCKS_NONE:
918          sfd = connect_to(dest_host, dest_port, csp);
919          break;
920       case SOCKS_4:
921       case SOCKS_4A:
922          sfd = socks4_connect(fwd, dest_host, dest_port, csp);
923          break;
924       case SOCKS_5:
925          sfd = socks5_connect(fwd, dest_host, dest_port, csp);
926          break;
927       default:
928          /* Should never get here */
929          log_error(LOG_LEVEL_FATAL,
930             "SOCKS4 impossible internal error - bad SOCKS type.");
931    }
932
933    if (JB_INVALID_SOCKET != sfd)
934    {
935       log_error(LOG_LEVEL_CONNECT,
936          "Created new connection to %s:%d on socket %d.",
937          http->host, http->port, sfd);
938    }
939
940    return sfd;
941
942 }
943
944
945 /*********************************************************************
946  *
947  * Function    :  socks4_connect
948  *
949  * Description :  Connect to the SOCKS server, and connect through
950  *                it to the specified server.   This handles
951  *                all the SOCKS negotiation, and returns a file
952  *                descriptor for a socket which can be treated as a
953  *                normal (non-SOCKS) socket.
954  *
955  *                Logged error messages are saved to csp->error_message
956  *                and later reused by error_response() for the CGI
957  *                message. strdup allocation failures are handled there.
958  *
959  * Parameters  :
960  *          1  :  fwd = Specifies the SOCKS proxy to use.
961  *          2  :  target_host = The final server to connect to.
962  *          3  :  target_port = The final port to connect to.
963  *          4  :  csp = Current client state (buffers, headers, etc...)
964  *
965  * Returns     :  JB_INVALID_SOCKET => failure, else a socket file descriptor.
966  *
967  *********************************************************************/
968 static jb_socket socks4_connect(const struct forward_spec * fwd,
969                                 const char * target_host,
970                                 int target_port,
971                                 struct client_state *csp)
972 {
973    unsigned int web_server_addr;
974    char buf[BUFFER_SIZE];
975    struct socks_op    *c = (struct socks_op    *)buf;
976    struct socks_reply *s = (struct socks_reply *)buf;
977    size_t n;
978    size_t csiz;
979    jb_socket sfd;
980    int err = 0;
981    char *errstr = NULL;
982
983    if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
984    {
985       /* XXX: Shouldn't the config file parser prevent this? */
986       errstr = "NULL gateway host specified.";
987       err = 1;
988    }
989
990    if (fwd->gateway_port <= 0)
991    {
992       errstr = "invalid gateway port specified.";
993       err = 1;
994    }
995
996    if (err)
997    {
998       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
999       csp->error_message = strdup(errstr); 
1000       errno = EINVAL;
1001       return(JB_INVALID_SOCKET);
1002    }
1003
1004    /* build a socks request for connection to the web server */
1005
1006    strlcpy(&(c->userid), socks_userid, sizeof(buf) - sizeof(struct socks_op));
1007
1008    csiz = sizeof(*c) + sizeof(socks_userid) - sizeof(c->userid) - sizeof(c->padding);
1009
1010    switch (fwd->type)
1011    {
1012       case SOCKS_4:
1013          web_server_addr = resolve_hostname_to_ip(target_host);
1014          if (web_server_addr == INADDR_NONE)
1015          {
1016             errstr = "could not resolve target host";
1017             log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s %s", errstr, target_host);
1018             err = 1;
1019          }
1020          else
1021          {
1022             web_server_addr = htonl(web_server_addr);
1023          }
1024          break;
1025       case SOCKS_4A:
1026          web_server_addr = 0x00000001;
1027          n = csiz + strlen(target_host) + 1;
1028          if (n > sizeof(buf))
1029          {
1030             errno = EINVAL;
1031             errstr = "buffer cbuf too small.";
1032             log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
1033             err = 1;
1034          }
1035          else
1036          {
1037             strlcpy(buf + csiz, target_host, sizeof(buf) - sizeof(struct socks_op) - csiz);
1038             /*
1039              * What we forward to the socks4a server should have the
1040              * size of socks_op, plus the length of the userid plus
1041              * its \0 byte (which we don't have to add because the
1042              * first byte of the userid is counted twice as it's also
1043              * part of sock_op) minus the padding bytes (which are part
1044              * of the userid as well), plus the length of the target_host
1045              * (which is stored csiz bytes after the beginning of the buffer),
1046              * plus another \0 byte.
1047              */
1048             assert(n == sizeof(struct socks_op) + strlen(&(c->userid)) - sizeof(c->padding) + strlen(buf + csiz) + 1);
1049             csiz = n;
1050          }
1051          break;
1052       default:
1053          /* Should never get here */
1054          log_error(LOG_LEVEL_FATAL,
1055             "socks4_connect: SOCKS4 impossible internal error - bad SOCKS type.");
1056          /* Not reached */
1057          return(JB_INVALID_SOCKET);
1058    }
1059
1060    if (err)
1061    {
1062       csp->error_message = strdup(errstr);
1063       return(JB_INVALID_SOCKET);
1064    }
1065
1066    c->vn          = 4;
1067    c->cd          = 1;
1068    c->dstport[0]  = (unsigned char)((target_port       >> 8  ) & 0xff);
1069    c->dstport[1]  = (unsigned char)((target_port             ) & 0xff);
1070    c->dstip[0]    = (unsigned char)((web_server_addr   >> 24 ) & 0xff);
1071    c->dstip[1]    = (unsigned char)((web_server_addr   >> 16 ) & 0xff);
1072    c->dstip[2]    = (unsigned char)((web_server_addr   >>  8 ) & 0xff);
1073    c->dstip[3]    = (unsigned char)((web_server_addr         ) & 0xff);
1074
1075    /* pass the request to the socks server */
1076    sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
1077
1078    if (sfd == JB_INVALID_SOCKET)
1079    {
1080       /*
1081        * XXX: connect_to should fill in the exact reason.
1082        * Most likely resolving the IP of the forwarder failed.
1083        */
1084       errstr = "connect_to failed: see logfile for details";
1085       err = 1;
1086    }
1087    else if (write_socket(sfd, (char *)c, csiz))
1088    {
1089       errstr = "SOCKS4 negotiation write failed.";
1090       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
1091       err = 1;
1092       close_socket(sfd);
1093    }
1094    else if (read_socket(sfd, buf, sizeof(buf)) != sizeof(*s))
1095    {
1096       errstr = "SOCKS4 negotiation read failed.";
1097       log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
1098       err = 1;
1099       close_socket(sfd);
1100    }
1101
1102    if (err)
1103    {
1104       csp->error_message = strdup(errstr);      
1105       return(JB_INVALID_SOCKET);
1106    }
1107
1108    switch (s->cd)
1109    {
1110       case SOCKS_REQUEST_GRANTED:
1111          return(sfd);
1112       case SOCKS_REQUEST_REJECT:
1113          errstr = "SOCKS request rejected or failed.";
1114          errno = EINVAL;
1115          break;
1116       case SOCKS_REQUEST_IDENT_FAILED:
1117          errstr = "SOCKS request rejected because "
1118             "SOCKS server cannot connect to identd on the client.";
1119          errno = EACCES;
1120          break;
1121       case SOCKS_REQUEST_IDENT_CONFLICT:
1122          errstr = "SOCKS request rejected because "
1123             "the client program and identd report "
1124             "different user-ids.";
1125          errno = EACCES;
1126          break;
1127       default:
1128          errno = ENOENT;
1129          snprintf(buf, sizeof(buf),
1130             "SOCKS request rejected for reason code %d.", s->cd);
1131          errstr = buf;
1132    }
1133
1134    log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr);
1135    csp->error_message = strdup(errstr);
1136    close_socket(sfd);
1137
1138    return(JB_INVALID_SOCKET);
1139
1140 }
1141
1142 /*********************************************************************
1143  *
1144  * Function    :  translate_socks5_error
1145  *
1146  * Description :  Translates a SOCKS errors to a string.
1147  *
1148  * Parameters  :
1149  *          1  :  socks_error = The error code to translate.
1150  *
1151  * Returns     :  The string translation.
1152  *
1153  *********************************************************************/
1154 static const char *translate_socks5_error(int socks_error)
1155 {
1156    switch (socks_error)
1157    {
1158       /* XXX: these should be more descriptive */
1159       case SOCKS5_REQUEST_FAILED:
1160          return "SOCKS5 request failed";
1161       case SOCKS5_REQUEST_DENIED:
1162          return "SOCKS5 request denied";
1163       case SOCKS5_REQUEST_NETWORK_UNREACHABLE:
1164          return "SOCKS5 network unreachable";
1165       case SOCKS5_REQUEST_HOST_UNREACHABLE:
1166          return "SOCKS5 host unreachable";
1167       case SOCKS5_REQUEST_CONNECTION_REFUSED:
1168          return "SOCKS5 connection refused";
1169       case SOCKS5_REQUEST_TTL_EXPIRED:
1170          return "SOCKS5 TTL expired";
1171       case SOCKS5_REQUEST_PROTOCOL_ERROR:
1172          return "SOCKS5 client protocol error";
1173       case SOCKS5_REQUEST_BAD_ADDRESS_TYPE:
1174          return "SOCKS5 domain names unsupported";
1175       case SOCKS5_REQUEST_GRANTED:
1176          return "everything's peachy";
1177       default:
1178          return "SOCKS5 negotiation protocol error";
1179    }
1180 }
1181
1182 /*********************************************************************
1183  *
1184  * Function    :  socks5_connect
1185  *
1186  * Description :  Connect to the SOCKS server, and connect through
1187  *                it to the specified server.   This handles
1188  *                all the SOCKS negotiation, and returns a file
1189  *                descriptor for a socket which can be treated as a
1190  *                normal (non-SOCKS) socket.
1191  *
1192  * Parameters  :
1193  *          1  :  fwd = Specifies the SOCKS proxy to use.
1194  *          2  :  target_host = The final server to connect to.
1195  *          3  :  target_port = The final port to connect to.
1196  *          4  :  csp = Current client state (buffers, headers, etc...)
1197  *
1198  * Returns     :  JB_INVALID_SOCKET => failure, else a socket file descriptor.
1199  *
1200  *********************************************************************/
1201 static jb_socket socks5_connect(const struct forward_spec *fwd,
1202                                 const char *target_host,
1203                                 int target_port,
1204                                 struct client_state *csp)
1205 {
1206    int err = 0;
1207    char cbuf[300];
1208    char sbuf[30];
1209    size_t client_pos = 0;
1210    int server_size = 0;
1211    size_t hostlen = 0;
1212    jb_socket sfd;
1213    const char *errstr = NULL;
1214
1215    assert(fwd->gateway_host);
1216    if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
1217    {
1218       errstr = "NULL gateway host specified";
1219       err = 1;
1220    }
1221
1222    if (fwd->gateway_port <= 0)
1223    {
1224       /*
1225        * XXX: currently this can't happen because in
1226        * case of invalid gateway ports we use the defaults.
1227        * Of course we really shouldn't do that.
1228        */
1229       errstr = "invalid gateway port specified";
1230       err = 1;
1231    }
1232
1233    hostlen = strlen(target_host);
1234    if (hostlen > (size_t)255)
1235    {
1236       errstr = "target host name is longer than 255 characters";
1237       err = 1;
1238    }
1239
1240    if (fwd->type != SOCKS_5)
1241    {
1242       /* Should never get here */
1243       log_error(LOG_LEVEL_FATAL,
1244          "SOCKS5 impossible internal error - bad SOCKS type");
1245       err = 1;
1246    }
1247
1248    if (err)
1249    {
1250       errno = EINVAL;
1251       assert(errstr != NULL);
1252       log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1253       csp->error_message = strdup(errstr);
1254       return(JB_INVALID_SOCKET);
1255    }
1256
1257    /* pass the request to the socks server */
1258    sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
1259
1260    if (sfd == JB_INVALID_SOCKET)
1261    {
1262       errstr = "socks5 server unreachable";
1263       log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1264       csp->error_message = strdup(errstr);
1265       return(JB_INVALID_SOCKET);
1266    }
1267
1268    client_pos = 0;
1269    cbuf[client_pos++] = '\x05'; /* Version */
1270    cbuf[client_pos++] = '\x01'; /* One authentication method supported */
1271    cbuf[client_pos++] = '\x00'; /* The no authentication authentication method */
1272
1273    if (write_socket(sfd, cbuf, client_pos))
1274    {
1275       errstr = "SOCKS5 negotiation write failed";
1276       csp->error_message = strdup(errstr);
1277       log_error(LOG_LEVEL_CONNECT, "%s", errstr);
1278       close_socket(sfd);
1279       return(JB_INVALID_SOCKET);
1280    }
1281
1282    if (read_socket(sfd, sbuf, sizeof(sbuf)) != 2)
1283    {
1284       errstr = "SOCKS5 negotiation read failed";
1285       err = 1;
1286    }
1287
1288    if (!err && (sbuf[0] != '\x05'))
1289    {
1290       errstr = "SOCKS5 negotiation protocol version error";
1291       err = 1;
1292    }
1293
1294    if (!err && (sbuf[1] == '\xff'))
1295    {
1296       errstr = "SOCKS5 authentication required";
1297       err = 1;
1298    }
1299
1300    if (!err && (sbuf[1] != '\x00'))
1301    {
1302       errstr = "SOCKS5 negotiation protocol error";
1303       err = 1;
1304    }
1305
1306    if (err)
1307    {
1308       assert(errstr != NULL);
1309       log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1310       csp->error_message = strdup(errstr);
1311       close_socket(sfd);
1312       errno = EINVAL;
1313       return(JB_INVALID_SOCKET);
1314    }
1315
1316    client_pos = 0;
1317    cbuf[client_pos++] = '\x05'; /* Version */
1318    cbuf[client_pos++] = '\x01'; /* TCP connect */
1319    cbuf[client_pos++] = '\x00'; /* Reserved, must be 0x00 */
1320    cbuf[client_pos++] = '\x03'; /* Address is domain name */
1321    cbuf[client_pos++] = (char)(hostlen & 0xffu);
1322    assert(sizeof(cbuf) - client_pos > (size_t)255);
1323    /* Using strncpy because we really want the nul byte padding. */
1324    strncpy(cbuf + client_pos, target_host, sizeof(cbuf) - client_pos);
1325    client_pos += (hostlen & 0xffu);
1326    cbuf[client_pos++] = (char)((target_port >> 8) & 0xff);
1327    cbuf[client_pos++] = (char)((target_port     ) & 0xff);
1328
1329    if (write_socket(sfd, cbuf, client_pos))
1330    {
1331       errstr = "SOCKS5 negotiation read failed";
1332       csp->error_message = strdup(errstr);
1333       log_error(LOG_LEVEL_CONNECT, "%s", errstr);
1334       close_socket(sfd);
1335       errno = EINVAL;
1336       return(JB_INVALID_SOCKET);
1337    }
1338
1339    server_size = read_socket(sfd, sbuf, sizeof(sbuf));
1340    if (server_size < 3)
1341    {
1342       errstr = "SOCKS5 negotiation read failed";
1343       err = 1;
1344    }
1345    else if (server_size > 20)
1346    {
1347       /* This is somewhat unexpected but doesn't realy matter. */
1348       log_error(LOG_LEVEL_CONNECT, "socks5_connect: read %d bytes "
1349          "from socks server. Would have accepted up to %d.",
1350          server_size, sizeof(sbuf));
1351    }
1352
1353    if (!err && (sbuf[0] != '\x05'))
1354    {
1355       errstr = "SOCKS5 negotiation protocol version error";
1356       err = 1;
1357    }
1358
1359    if (!err && (sbuf[2] != '\x00'))
1360    {
1361       errstr = "SOCKS5 negotiation protocol error";
1362       err = 1;
1363    }
1364
1365    if (!err)
1366    {
1367       if (sbuf[1] == SOCKS5_REQUEST_GRANTED)
1368       {
1369          return(sfd);
1370       }
1371       errstr = translate_socks5_error(sbuf[1]);
1372       err = 1;
1373    }
1374
1375    assert(errstr != NULL);
1376    csp->error_message = strdup(errstr);
1377    log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr);
1378    close_socket(sfd);
1379    errno = EINVAL;
1380
1381    return(JB_INVALID_SOCKET);
1382
1383 }
1384
1385 /*
1386   Local Variables:
1387   tab-width: 3
1388   end:
1389 */