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