Support for both static and dynamically generated CGI pages.
[privoxy.git] / jbsockets.c
1 const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.16 2001/07/30 22:08:36 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
5  *
6  * Purpose     :  Contains wrappers for system-specific sockets code,
7  *                so that the rest of JunkBuster can be more
8  *                OS-independent.  Contains #ifdefs to make this work
9  *                on many platforms.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and 
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it 
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: jbsockets.c,v $
38  *    Revision 1.16  2001/07/30 22:08:36  jongfoster
39  *    Tidying up #defines:
40  *    - All feature #defines are now of the form FEATURE_xxx
41  *    - Permanently turned off WIN_GUI_EDIT
42  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
43  *
44  *    Revision 1.15  2001/07/29 17:40:43  jongfoster
45  *    Fixed compiler warning by adding a cast
46  *
47  *    Revision 1.14  2001/07/18 13:47:59  oes
48  *    Eliminated dirty hack for getsockbyname()
49  *
50  *    Revision 1.13  2001/07/15 13:56:57  jongfoster
51  *    Removing unused local variable.
52  *
53  *    Revision 1.12  2001/07/01 17:04:11  oes
54  *    Bugfix: accept_connection no longer uses the obsolete hstrerror() function
55  *
56  *    Revision 1.11  2001/06/29 21:45:41  oes
57  *    Indentation, CRLF->LF, Tab-> Space
58  *
59  *    Revision 1.10  2001/06/29 13:29:15  oes
60  *    - Added remote (server) host IP to csp->http->host_ip_addr_str
61  *    - Added detection of local socket IP and fqdn
62  *    - Removed logentry from cancelled commit
63  *
64  *    Revision 1.9  2001/06/07 23:06:09  jongfoster
65  *    The host parameter to connect_to() is now const.
66  *
67  *    Revision 1.8  2001/06/03 19:12:07  oes
68  *    filled comment
69  *
70  *    Revision 1.7  2001/05/28 16:14:00  jongfoster
71  *    Fixing bug in LOG_LEVEL_LOG
72  *
73  *    Revision 1.6  2001/05/26 17:28:32  jongfoster
74  *    Fixed LOG_LEVEL_LOG
75  *
76  *    Revision 1.5  2001/05/26 15:26:15  jongfoster
77  *    ACL feature now provides more security by immediately dropping
78  *    connections from untrusted hosts.
79  *
80  *    Revision 1.4  2001/05/26 00:37:42  jongfoster
81  *    Cosmetic indentation correction.
82  *
83  *    Revision 1.3  2001/05/25 21:57:54  jongfoster
84  *    Now gives a warning under Windows if you try to bind
85  *    it to a port that's already in use.
86  *
87  *    Revision 1.2  2001/05/17 23:01:01  oes
88  *     - Cleaned CRLF's from the sources and related files
89  *
90  *    Revision 1.1.1.1  2001/05/15 13:58:54  oes
91  *    Initial import of version 2.9.3 source tree
92  *
93  *
94  *********************************************************************/
95 \f
96
97 #include "config.h"
98
99 #include <stdlib.h>
100 #include <stdio.h>
101 #include <string.h>
102 #include <errno.h>
103 #include <fcntl.h>
104 #include <sys/types.h>
105
106 #ifdef _WIN32
107
108 #include <windows.h>
109 #include <sys/timeb.h>
110 #include <io.h>
111
112 #else
113
114 #include <unistd.h>
115 #include <sys/time.h>
116 #include <netinet/in.h>
117 #include <sys/ioctl.h>
118 #include <netdb.h>
119 #include <sys/socket.h>
120
121 #ifndef __BEOS__
122 #include <netinet/tcp.h>
123 #include <arpa/inet.h>
124 #else
125 #include <socket.h>
126 #endif
127
128 #endif
129
130 #include "project.h"
131 #include "jbsockets.h"
132 #include "filters.h"
133 #include "errlog.h"
134
135 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
136
137
138 /*********************************************************************
139  *
140  * Function    :  connect_to
141  *
142  * Description :  Open a socket and connect to it.  Will check
143  *                that this is allowed according to ACL.
144  *
145  * Parameters  :
146  *          1  :  host = hostname to connect to
147  *          2  :  portnum = port to connent on
148  *          3  :  csp = Current client state (buffers, headers, etc...)
149  *                      Not modified, only used for source IP and ACL.
150  *
151  * Returns     :  -1 => failure, else it is the socket file descriptor.
152  *
153  *********************************************************************/
154 int connect_to(const char *host, int portnum, struct client_state *csp)
155 {
156    struct sockaddr_in inaddr;
157    int   fd, addr;
158    fd_set wfds;
159    struct timeval tv[1];
160 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
161    int   flags;
162 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
163
164 #ifdef FEATURE_ACL
165    struct access_control_addr dst[1];
166 #endif /* def FEATURE_ACL */
167
168    memset((char *)&inaddr, 0, sizeof inaddr);
169
170    if ((addr = resolve_hostname_to_ip(host)) == -1)
171    {
172       csp->http->host_ip_addr_str = strdup("unknown");
173       return(-1);
174    }
175
176 #ifdef FEATURE_ACL
177    dst->addr = ntohl(addr);
178    dst->port = portnum;
179
180    if (block_acl(dst, csp))
181    {
182       errno = EPERM;
183       return(-1);
184    }
185 #endif /* def FEATURE_ACL */
186
187    inaddr.sin_addr.s_addr = addr;
188    inaddr.sin_family      = AF_INET;
189    csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
190
191 #ifndef _WIN32
192    if (sizeof(inaddr.sin_port) == sizeof(short))
193 #endif /* ndef _WIN32 */
194    {
195       inaddr.sin_port = htons((short)portnum);
196    }
197 #ifndef _WIN32
198    else
199    {
200       inaddr.sin_port = htonl(portnum);
201    }
202 #endif /* ndef _WIN32 */
203
204    if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
205    {
206       return(-1);
207    }
208
209 #ifdef TCP_NODELAY
210    {  /* turn off TCP coalescence */
211       int mi = 1;
212       setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
213    }
214 #endif /* def TCP_NODELAY */
215
216 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
217    if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
218    {
219       flags |= O_NDELAY;
220       fcntl(fd, F_SETFL, flags);
221    }
222 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
223
224    while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == -1)
225    {
226 #ifdef _WIN32
227       if (errno == WSAEINPROGRESS)
228 #else /* ifndef _WIN32 */
229       if (errno == EINPROGRESS)
230 #endif /* ndef _WIN32 */
231       {
232          break;
233       }
234
235       if (errno != EINTR)
236       {
237          close_socket(fd);
238          return(-1);
239       }
240    }
241
242 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
243    if (flags != -1)
244    {
245       flags &= ~O_NDELAY;
246       fcntl(fd, F_SETFL, flags);
247    }
248 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
249
250    /* wait for connection to complete */
251    FD_ZERO(&wfds);
252    FD_SET(fd, &wfds);
253
254    tv->tv_sec  = 30;
255    tv->tv_usec = 0;
256
257    if (select(fd + 1, NULL, &wfds, NULL, tv) <= 0)
258    {
259       close_socket(fd);
260       return(-1);
261    }
262    return(fd);
263
264 }
265
266
267 /*********************************************************************
268  *
269  * Function    :  write_socket
270  *
271  * Description :  Write the contents of buf (for n bytes) to socket fd.
272  *
273  * Parameters  :
274  *          1  :  fd = file descriptor (aka. handle) of socket to write to.
275  *          2  :  buf = pointer to data to be written.
276  *          3  :  len = length of data to be written to the socket "fd".
277  *
278  * Returns     :  Win32 & Unix: If no error occurs, returns the total number of
279  *                bytes sent, which can be less than the number
280  *                indicated by len. Otherwise, returns (-1).
281  *
282  *********************************************************************/
283 int write_socket(int fd, const char *buf, int len)
284 {
285    if (len <= 0)
286    {
287       return(0);
288    }
289
290    log_error(LOG_LEVEL_LOG, "%N", len, buf);
291
292 #if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA)
293    return( send(fd, buf, len, 0));
294 #else
295    return( write(fd, buf, len));
296 #endif
297
298 }
299
300
301 /*********************************************************************
302  *
303  * Function    :  read_socket
304  *
305  * Description :  Read from a TCP/IP socket in a platform independent way.
306  *
307  * Parameters  :
308  *          1  :  fd = file descriptor of the socket to read
309  *          2  :  buf = pointer to buffer where data will be written
310  *                Must be >= len bytes long.
311  *          3  :  len = maximum number of bytes to read
312  *
313  * Returns     :  On success, the number of bytes read is returned (zero
314  *                indicates end of file), and the file position is advanced
315  *                by this number.  It is not an error if this number is
316  *                smaller than the number of bytes requested; this may hap-
317  *                pen for example because fewer bytes are actually available
318  *                right now (maybe because we were close to end-of-file, or
319  *                because we are reading from a pipe, or from a terminal),
320  *                or because read() was interrupted by a signal.  On error,
321  *                -1 is returned, and errno is set appropriately.  In this
322  *                case it is left unspecified whether the file position (if
323  *                any) changes.
324  *
325  *********************************************************************/
326 int read_socket(int fd, char *buf, int len)
327 {
328    if (len <= 0)
329    {
330       return(0);
331    }
332
333 #if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA)
334    return( recv(fd, buf, len, 0));
335 #else
336    return( read(fd, buf, len));
337 #endif
338 }
339
340
341 /*********************************************************************
342  *
343  * Function    :  close_socket
344  *
345  * Description :  Closes a TCP/IP socket
346  *
347  * Parameters  :
348  *          1  :  fd = file descriptor of socket to be closed
349  *
350  * Returns     :  void
351  *
352  *********************************************************************/
353 void close_socket(int fd)
354 {
355 #if defined(_WIN32) || defined(__BEOS__)
356    closesocket(fd);
357 #elif defined(AMIGA)
358    CloseSocket(fd); 
359 #else
360    close(fd);
361 #endif
362
363 }
364
365
366 /*********************************************************************
367  *
368  * Function    :  bind_port
369  *
370  * Description :  Call socket, set socket options, and listen.
371  *                Called by listen_loop to "boot up" our proxy address.
372  *
373  * Parameters  :
374  *          1  :  hostnam = TCP/IP address to bind/listen to
375  *          2  :  portnum = port to listen on
376  *
377  * Returns     :  if success, return file descriptor
378  *                if failure, returns -2 if address is in use, otherwise -1
379  *
380  *********************************************************************/
381 int bind_port(const char *hostnam, int portnum)
382 {
383    struct sockaddr_in inaddr;
384    int fd;
385    int one = 1;
386
387    memset((char *)&inaddr, '\0', sizeof inaddr);
388
389    inaddr.sin_family      = AF_INET;
390    inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
391
392 #ifndef _WIN32
393    if (sizeof(inaddr.sin_port) == sizeof(short))
394 #endif /* ndef _WIN32 */
395    {
396       inaddr.sin_port = htons((short)portnum);
397    }
398 #ifndef _WIN32
399    else
400    {
401       inaddr.sin_port = htonl(portnum);
402    }
403 #endif /* ndef _WIN32 */
404
405    fd = socket(AF_INET, SOCK_STREAM, 0);
406
407    if (fd < 0)
408    {
409       return(-1);
410    }
411
412 #ifndef _WIN32
413    /*
414     * FIXME: This is not needed for Win32 - in fact, it stops
415     * duplicate instances of JunkBuster from being caught.
416     * Is this really needed under UNIX, or should it be taked out?
417     * -- Jon
418     */
419    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
420 #endif /* ndef _WIN32 */
421
422    if (bind (fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
423    {
424       close_socket (fd);
425 #ifdef _WIN32
426       if (errno == WSAEADDRINUSE)
427 #else
428       if (errno == EADDRINUSE)
429 #endif
430       {
431          return(-2);
432       }
433       else
434       {
435          return(-1);
436       }
437    }
438
439    while (listen(fd, 5) == -1)
440    {
441       if (errno != EINTR)
442       {
443          return(-1);
444       }
445    }
446
447    return fd;
448
449 }
450
451
452 /*********************************************************************
453  *
454  * Function    :  accept_connection
455  *
456  * Description :  Accepts a connection on a socket.  Socket must have
457  *                been created using bind_port().
458  *
459  * Parameters  :
460  *          1  :  csp = Client state, cfd, ip_addr_str, and 
461  *                ip_addr_long will be set by this routine.
462  *          2  :  fd  = file descriptor returned from bind_port
463  *
464  * Returns     :  when a connection is accepted, it returns 1 (TRUE).
465  *                On an error it returns 0 (FALSE).
466  *
467  *********************************************************************/
468 int accept_connection(struct client_state * csp, int fd)
469 {
470    struct sockaddr_in client, server;
471    struct hostent *host = NULL;
472    int afd, c_length, s_length;
473
474    c_length = s_length = sizeof(client);
475
476    do
477    {
478       afd = accept (fd, (struct sockaddr *) &client, &c_length);
479    } while (afd < 1 && errno == EINTR);
480
481    if (afd < 0)
482    {
483       return 0;
484    }
485
486    /* 
487     * Determine the IP-Adress that the client used to reach us
488     * and the hostname associated with that address
489     */
490    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
491    {
492       csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
493
494       host = gethostbyaddr((const char *)&server.sin_addr, 
495                            sizeof(server.sin_addr), AF_INET);
496       if (host == NULL)
497       {
498          log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
499       }
500       else
501       {
502          csp->my_hostname = strdup(host->h_name);
503       }
504    }
505
506    csp->cfd    = afd;
507    csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
508    csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
509
510    return 1;
511
512 }
513
514
515 /*********************************************************************
516  *
517  * Function    :  resolve_hostname_to_ip
518  *
519  * Description :  Resolve a hostname to an internet tcp/ip address.
520  *                NULL or an empty string resolve to INADDR_ANY.
521  *
522  * Parameters  :
523  *          1  :  host = hostname to resolve
524  *
525  * Returns     :  -1 => failure, INADDR_ANY or tcp/ip address if succesful.
526  *
527  *********************************************************************/
528 int resolve_hostname_to_ip(const char *host)
529 {
530    struct sockaddr_in inaddr;
531    struct hostent *hostp;
532
533    if ((host == NULL) || (*host == '\0'))
534    {
535       return(INADDR_ANY);
536    }
537
538    memset((char *) &inaddr, 0, sizeof inaddr);
539
540    if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
541    {
542       if ((hostp = gethostbyname(host)) == NULL)
543       {
544          errno = EINVAL;
545          return(-1);
546       }
547       if (hostp->h_addrtype != AF_INET)
548       {
549 #ifdef _WIN32
550          errno = WSAEPROTOTYPE;
551 #else
552          errno = EPROTOTYPE;
553 #endif
554          return(-1);
555       }
556       memcpy(
557          (char *) &inaddr.sin_addr,
558          (char *) hostp->h_addr,
559          sizeof(inaddr.sin_addr)
560       );
561    }
562    return(inaddr.sin_addr.s_addr);
563
564 }
565
566
567 /*
568   Local Variables:
569   tab-width: 3
570   end:
571 */