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