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