Removing ACL and forward file loaders - these
[privoxy.git] / gateway.c
1 const char gateway_rcs[] = "$Id: gateway.c,v 1.1.1.1 2001/05/15 13:58:54 oes 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 the SourceForge
11  *                IJBSWA team.  http://ijbswa.sourceforge.net
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.1.1.1  2001/05/15 13:58:54  oes
38  *    Initial import of version 2.9.3 source tree
39  *
40  *
41  *********************************************************************/
42 \f
43
44 #include "config.h"
45
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <errno.h>
49
50 #ifdef _WIN32
51 #include <winsock2.h>
52 #endif /* def _WIN32 */
53
54 #include "jcc.h"
55 #include "errlog.h"
56 #include "jbsockets.h"
57 #include "gateway.h"
58
59 const char gateway_h_rcs[] = GATEWAY_H_VERSION;
60
61 static int socks4_connect(const struct forward_spec * fwd, 
62                           const char * target_host,
63                           int target_port,
64                           struct client_state *csp);
65
66
67 #define SOCKS_REQUEST_GRANTED          90
68 #define SOCKS_REQUEST_REJECT           91
69 #define SOCKS_REQUEST_IDENT_FAILED     92
70 #define SOCKS_REQUEST_IDENT_CONFLICT   93
71
72 /* structure of a socks client operation */
73 struct socks_op {
74    unsigned char vn;          /* socks version number */
75    unsigned char cd;          /* command code */
76    unsigned char dstport[2];  /* destination port */
77    unsigned char dstip[4];    /* destination address */
78    unsigned char userid;      /* first byte of userid */
79    /* more bytes of the userid follow, terminated by a NULL */
80 };
81
82 /* structure of a socks server reply */
83 struct socks_reply {
84    unsigned char vn;          /* socks version number */
85    unsigned char cd;          /* command code */
86    unsigned char dstport[2];  /* destination port */
87    unsigned char dstip[4];    /* destination address */
88 };
89
90 static const char socks_userid[] = "anonymous";
91
92
93 /*********************************************************************
94  *
95  * Function    :  forwarded_connect
96  *
97  * Description :  Connect to a specified web server, possibly via
98  *                a HTTP proxy and/or a SOCKS proxy.
99  *
100  * Parameters  :
101  *          1  :  gw = pointer to a gateway structure (such as gw_default)
102  *          2  :  http = the http request and apropos headers
103  *          3  :  csp = Current client state (buffers, headers, etc...)
104  *
105  * Returns     :  -1 => failure, else it is the socket file descriptor.
106  *
107  *********************************************************************/
108 int forwarded_connect(const struct forward_spec * fwd, 
109                       struct http_request *http, 
110                       struct client_state *csp)
111 {
112    const char * dest_host;
113    int dest_port;
114
115    /* Figure out if we need to connect to the web server or a HTTP proxy. */
116    if (fwd->forward_host)
117    {
118       /* HTTP proxy */
119       dest_host = fwd->forward_host;
120       dest_port = fwd->forward_port;
121    }
122    else
123    {
124       /* Web server */
125       dest_host = http->host;
126       dest_port = http->port;
127    }
128
129    /* Connect, maybe using a SOCKS proxy */
130    switch (fwd->type)
131    {
132       case SOCKS_NONE:
133          return (connect_to(dest_host, dest_port, csp));
134
135       case SOCKS_4:
136       case SOCKS_4A:
137          return (socks4_connect(fwd, dest_host, dest_port, csp));
138
139       default:
140          /* Should never get here */
141          log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
142          errno = EINVAL;
143          return(-1);
144    }
145 }
146
147
148 /*********************************************************************
149  *
150  * Function    :  socks4_connect
151  *
152  * Description :  Connect to the SOCKS server, and connect through
153  *                it to the specified server.   This handles
154  *                all the SOCKS negotiation, and returns a file
155  *                descriptor for a socket which can be treated as a
156  *                normal (non-SOCKS) socket.
157  *
158  * Parameters  :
159  *          1  :  gw = pointer to a gateway structure (such as gw_default)
160  *          2  :  http = the http request and apropos headers
161  *          3  :  csp = Current client state (buffers, headers, etc...)
162  *
163  * Returns     :  -1 => failure, else a socket file descriptor.
164  *
165  *********************************************************************/
166 static int socks4_connect(const struct forward_spec * fwd, 
167                           const char * target_host,
168                           int target_port,
169                           struct client_state *csp)
170 {
171    int web_server_addr;
172    unsigned char cbuf[BUFSIZ];
173    unsigned char sbuf[BUFSIZ];
174    struct socks_op    *c = (struct socks_op    *)cbuf;
175    struct socks_reply *s = (struct socks_reply *)sbuf;
176    int n;
177    int csiz;
178    int sfd;
179    int err = 0;
180    char *errstr;
181
182    if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0'))
183    {
184       log_error(LOG_LEVEL_CONNECT, "socks4_connect: NULL gateway host specified");
185       err = 1;
186    }
187
188    if (fwd->gateway_port <= 0)
189    {
190       log_error(LOG_LEVEL_CONNECT, "socks4_connect: invalid gateway port specified");
191       err = 1;
192    }
193
194    if (err)
195    {
196       errno = EINVAL;
197       return(-1);
198    }
199
200    /* build a socks request for connection to the web server */
201
202    strcpy((char *)&(c->userid), socks_userid);
203
204    csiz = sizeof(*c) + sizeof(socks_userid) - 1;
205
206    switch (fwd->type)
207    {
208       case SOCKS_4:
209          web_server_addr = htonl(resolve_hostname_to_ip(target_host));
210          break;
211       case SOCKS_4A:
212          web_server_addr = 0x00000001;
213          n = csiz + strlen(target_host) + 1;
214          if (n > sizeof(cbuf))
215          {
216             errno = EINVAL;
217             return(-1);
218          }
219          strcpy(((char *)cbuf) + csiz, target_host);
220          csiz = n;
221          break;
222       default:
223          /* Should never get here */
224          log_error(LOG_LEVEL_FATAL, "SOCKS4 impossible internal error - bad SOCKS type.");
225          errno = EINVAL;
226          return(-1);
227    }
228
229    c->vn          = 4;
230    c->cd          = 1;
231    c->dstport[0]  = (target_port       >> 8  ) & 0xff;
232    c->dstport[1]  = (target_port             ) & 0xff;
233    c->dstip[0]    = (web_server_addr   >> 24 ) & 0xff;
234    c->dstip[1]    = (web_server_addr   >> 16 ) & 0xff;
235    c->dstip[2]    = (web_server_addr   >>  8 ) & 0xff;
236    c->dstip[3]    = (web_server_addr         ) & 0xff;
237
238    /* pass the request to the socks server */
239    sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp);
240
241    if (sfd < 0)
242    {
243       return(-1);
244    }
245
246    if ((n = write_socket(sfd, (char *)c, csiz)) != csiz)
247    {
248       log_error(LOG_LEVEL_CONNECT, "SOCKS4 negotiation write failed...");
249       close_socket(sfd);
250       return(-1);
251    }
252
253    if ((n = read_socket(sfd, sbuf, sizeof(sbuf))) != sizeof(*s))
254    {
255       log_error(LOG_LEVEL_CONNECT, "SOCKS4 negotiation read failed...");
256       close_socket(sfd);
257       return(-1);
258    }
259
260    switch (s->cd)
261    {
262       case SOCKS_REQUEST_GRANTED:
263          return(sfd);
264          break;
265       case SOCKS_REQUEST_REJECT:
266          errstr = "SOCKS request rejected or failed";
267          errno = EINVAL;
268          break;
269       case SOCKS_REQUEST_IDENT_FAILED:
270          errstr = "SOCKS request rejected because "
271             "SOCKS server cannot connect to identd on the client";
272          errno = EACCES;
273          break;
274       case SOCKS_REQUEST_IDENT_CONFLICT:
275          errstr = "SOCKS request rejected because "
276             "the client program and identd report "
277             "different user-ids";
278          errno = EACCES;
279          break;
280       default:
281          errstr = (char *) cbuf;
282          errno = ENOENT;
283          sprintf(errstr,
284                  "SOCKS request rejected for reason code %d\n", s->cd);
285    }
286
287    log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s ...", errstr);
288
289    close_socket(sfd);
290    return(-1);
291
292 }
293
294
295 /*
296   Local Variables:
297   tab-width: 3
298   end:
299 */