Adding newline to end of file
[privoxy.git] / jbsockets.c
1 const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.20 2001/11/16 00:48:48 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.20  2001/11/16 00:48:48  jongfoster
39  *    Enabling duplicate-socket detection for all platforms, not
40  *    just Win32.
41  *
42  *    Revision 1.19  2001/10/25 03:40:47  david__schmidt
43  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
44  *    threads to call select() simultaneously.  So, it's time to do a real, live,
45  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
46  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
47  *
48  *    Revision 1.18  2001/09/21 23:02:02  david__schmidt
49  *    Cleaning up 2 compiler warnings on OS/2.
50  *
51  *    Revision 1.17  2001/09/13 20:11:46  jongfoster
52  *    Fixing 2 compiler warnings under Win32
53  *
54  *    Revision 1.16  2001/07/30 22:08:36  jongfoster
55  *    Tidying up #defines:
56  *    - All feature #defines are now of the form FEATURE_xxx
57  *    - Permanently turned off WIN_GUI_EDIT
58  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
59  *
60  *    Revision 1.15  2001/07/29 17:40:43  jongfoster
61  *    Fixed compiler warning by adding a cast
62  *
63  *    Revision 1.14  2001/07/18 13:47:59  oes
64  *    Eliminated dirty hack for getsockbyname()
65  *
66  *    Revision 1.13  2001/07/15 13:56:57  jongfoster
67  *    Removing unused local variable.
68  *
69  *    Revision 1.12  2001/07/01 17:04:11  oes
70  *    Bugfix: accept_connection no longer uses the obsolete hstrerror() function
71  *
72  *    Revision 1.11  2001/06/29 21:45:41  oes
73  *    Indentation, CRLF->LF, Tab-> Space
74  *
75  *    Revision 1.10  2001/06/29 13:29:15  oes
76  *    - Added remote (server) host IP to csp->http->host_ip_addr_str
77  *    - Added detection of local socket IP and fqdn
78  *    - Removed logentry from cancelled commit
79  *
80  *    Revision 1.9  2001/06/07 23:06:09  jongfoster
81  *    The host parameter to connect_to() is now const.
82  *
83  *    Revision 1.8  2001/06/03 19:12:07  oes
84  *    filled comment
85  *
86  *    Revision 1.7  2001/05/28 16:14:00  jongfoster
87  *    Fixing bug in LOG_LEVEL_LOG
88  *
89  *    Revision 1.6  2001/05/26 17:28:32  jongfoster
90  *    Fixed LOG_LEVEL_LOG
91  *
92  *    Revision 1.5  2001/05/26 15:26:15  jongfoster
93  *    ACL feature now provides more security by immediately dropping
94  *    connections from untrusted hosts.
95  *
96  *    Revision 1.4  2001/05/26 00:37:42  jongfoster
97  *    Cosmetic indentation correction.
98  *
99  *    Revision 1.3  2001/05/25 21:57:54  jongfoster
100  *    Now gives a warning under Windows if you try to bind
101  *    it to a port that's already in use.
102  *
103  *    Revision 1.2  2001/05/17 23:01:01  oes
104  *     - Cleaned CRLF's from the sources and related files
105  *
106  *    Revision 1.1.1.1  2001/05/15 13:58:54  oes
107  *    Initial import of version 2.9.3 source tree
108  *
109  *
110  *********************************************************************/
111 \f
112
113 #include "config.h"
114
115 #include <stdlib.h>
116 #include <stdio.h>
117 #include <string.h>
118 #include <errno.h>
119 #include <fcntl.h>
120 #include <sys/types.h>
121
122 #ifdef _WIN32
123
124 #include <windows.h>
125 #include <sys/timeb.h>
126 #include <io.h>
127
128 #else
129
130 #ifndef __OS2__
131 #include <unistd.h>
132 #endif
133 #include <sys/time.h>
134 #include <netinet/in.h>
135 #include <sys/ioctl.h>
136 #include <netdb.h>
137 #include <sys/socket.h>
138
139 #ifndef __BEOS__
140 #include <netinet/tcp.h>
141 #ifndef __OS2__
142 #include <arpa/inet.h>
143 #endif
144 #else
145 #include <socket.h>
146 #endif
147
148 #if defined(__EMX__) || defined (__OS2__)
149 #include <sys/select.h>  /* OS/2/EMX needs a little help with select */
150 #include <nerrno.h>
151 #endif
152
153 #endif
154
155 #include "project.h"
156 #include "jbsockets.h"
157 #include "filters.h"
158 #include "errlog.h"
159
160 const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
161
162
163 /*********************************************************************
164  *
165  * Function    :  connect_to
166  *
167  * Description :  Open a socket and connect to it.  Will check
168  *                that this is allowed according to ACL.
169  *
170  * Parameters  :
171  *          1  :  host = hostname to connect to
172  *          2  :  portnum = port to connent on
173  *          3  :  csp = Current client state (buffers, headers, etc...)
174  *                      Not modified, only used for source IP and ACL.
175  *
176  * Returns     :  -1 => failure, else it is the socket file descriptor.
177  *
178  *********************************************************************/
179 int connect_to(const char *host, int portnum, struct client_state *csp)
180 {
181    struct sockaddr_in inaddr;
182    int   fd, addr;
183    fd_set wfds;
184    struct timeval tv[1];
185 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
186    int   flags;
187 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
188
189 #ifdef FEATURE_ACL
190    struct access_control_addr dst[1];
191 #endif /* def FEATURE_ACL */
192
193    memset((char *)&inaddr, 0, sizeof inaddr);
194
195    if ((addr = resolve_hostname_to_ip(host)) == -1)
196    {
197       csp->http->host_ip_addr_str = strdup("unknown");
198       return(-1);
199    }
200
201 #ifdef FEATURE_ACL
202    dst->addr = ntohl(addr);
203    dst->port = portnum;
204
205    if (block_acl(dst, csp))
206    {
207 #ifdef __OS2__
208       errno = SOCEPERM;
209 #else
210       errno = EPERM;
211 #endif
212       return(-1);
213    }
214 #endif /* def FEATURE_ACL */
215
216    inaddr.sin_addr.s_addr = addr;
217    inaddr.sin_family      = AF_INET;
218    csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr));
219
220 #ifndef _WIN32
221    if (sizeof(inaddr.sin_port) == sizeof(short))
222 #endif /* ndef _WIN32 */
223    {
224       inaddr.sin_port = htons((short)portnum);
225    }
226 #ifndef _WIN32
227    else
228    {
229       inaddr.sin_port = htonl(portnum);
230    }
231 #endif /* ndef _WIN32 */
232
233    if ((fd = socket(inaddr.sin_family, SOCK_STREAM, 0)) < 0)
234    {
235       return(-1);
236    }
237
238 #ifdef TCP_NODELAY
239    {  /* turn off TCP coalescence */
240       int mi = 1;
241       setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int));
242    }
243 #endif /* def TCP_NODELAY */
244
245 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
246    if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
247    {
248       flags |= O_NDELAY;
249       fcntl(fd, F_SETFL, flags);
250    }
251 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
252
253    while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == -1)
254    {
255 #ifdef _WIN32
256       if (errno == WSAEINPROGRESS)
257 #elif __OS2__ 
258       if (sock_errno() == EINPROGRESS)
259 #else /* ifndef _WIN32 */
260       if (errno == EINPROGRESS)
261 #endif /* ndef _WIN32 || __OS2__ */
262       {
263          break;
264       }
265
266 #ifdef __OS2__ 
267       if (sock_errno() != EINTR)
268 #else
269       if (errno != EINTR)
270 #endif /* __OS2__ */
271       {
272          close_socket(fd);
273          return(-1);
274       }
275    }
276
277 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__)
278    if (flags != -1)
279    {
280       flags &= ~O_NDELAY;
281       fcntl(fd, F_SETFL, flags);
282    }
283 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */
284
285    /* wait for connection to complete */
286    FD_ZERO(&wfds);
287    FD_SET(fd, &wfds);
288
289    tv->tv_sec  = 30;
290    tv->tv_usec = 0;
291
292    if (select(fd + 1, NULL, &wfds, NULL, tv) <= 0)
293    {
294       close_socket(fd);
295       return(-1);
296    }
297    return(fd);
298
299 }
300
301
302 /*********************************************************************
303  *
304  * Function    :  write_socket
305  *
306  * Description :  Write the contents of buf (for n bytes) to socket fd.
307  *
308  * Parameters  :
309  *          1  :  fd = file descriptor (aka. handle) of socket to write to.
310  *          2  :  buf = pointer to data to be written.
311  *          3  :  len = length of data to be written to the socket "fd".
312  *
313  * Returns     :  Win32 & Unix: If no error occurs, returns the total number of
314  *                bytes sent, which can be less than the number
315  *                indicated by len. Otherwise, returns (-1).
316  *
317  *********************************************************************/
318 int write_socket(int fd, const char *buf, int len)
319 {
320    if (len <= 0)
321    {
322       return(0);
323    }
324
325    log_error(LOG_LEVEL_LOG, "%N", len, buf);
326
327 #if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA) || defined(__OS2__)
328    return( send(fd, buf, len, 0));
329 #else
330    return( write(fd, buf, len));
331 #endif
332
333 }
334
335
336 /*********************************************************************
337  *
338  * Function    :  read_socket
339  *
340  * Description :  Read from a TCP/IP socket in a platform independent way.
341  *
342  * Parameters  :
343  *          1  :  fd = file descriptor of the socket to read
344  *          2  :  buf = pointer to buffer where data will be written
345  *                Must be >= len bytes long.
346  *          3  :  len = maximum number of bytes to read
347  *
348  * Returns     :  On success, the number of bytes read is returned (zero
349  *                indicates end of file), and the file position is advanced
350  *                by this number.  It is not an error if this number is
351  *                smaller than the number of bytes requested; this may hap-
352  *                pen for example because fewer bytes are actually available
353  *                right now (maybe because we were close to end-of-file, or
354  *                because we are reading from a pipe, or from a terminal),
355  *                or because read() was interrupted by a signal.  On error,
356  *                -1 is returned, and errno is set appropriately.  In this
357  *                case it is left unspecified whether the file position (if
358  *                any) changes.
359  *
360  *********************************************************************/
361 int read_socket(int fd, char *buf, int len)
362 {
363    if (len <= 0)
364    {
365       return(0);
366    }
367
368 #if defined(_WIN32) || defined(__BEOS__) || defined(AMIGA) || defined(__OS2__)
369    return( recv(fd, buf, len, 0));
370 #else
371    return( read(fd, buf, len));
372 #endif
373 }
374
375
376 /*********************************************************************
377  *
378  * Function    :  close_socket
379  *
380  * Description :  Closes a TCP/IP socket
381  *
382  * Parameters  :
383  *          1  :  fd = file descriptor of socket to be closed
384  *
385  * Returns     :  void
386  *
387  *********************************************************************/
388 void close_socket(int fd)
389 {
390 #if defined(_WIN32) || defined(__BEOS__)
391    closesocket(fd);
392 #elif defined(AMIGA)
393    CloseSocket(fd); 
394 #elif defined(__OS2__)
395    soclose(fd);
396 #else
397    close(fd);
398 #endif
399
400 }
401
402
403 /*********************************************************************
404  *
405  * Function    :  bind_port
406  *
407  * Description :  Call socket, set socket options, and listen.
408  *                Called by listen_loop to "boot up" our proxy address.
409  *
410  * Parameters  :
411  *          1  :  hostnam = TCP/IP address to bind/listen to
412  *          2  :  portnum = port to listen on
413  *
414  * Returns     :  if success, return file descriptor
415  *                if failure, returns -2 if address is in use, otherwise -1
416  *
417  *********************************************************************/
418 int bind_port(const char *hostnam, int portnum)
419 {
420    struct sockaddr_in inaddr;
421    int fd;
422 #if 0
423 #ifndef _WIN32
424    int one = 1;
425 #endif /* ndef _WIN32 */
426 #endif
427
428    memset((char *)&inaddr, '\0', sizeof inaddr);
429
430    inaddr.sin_family      = AF_INET;
431    inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam);
432
433 #ifndef _WIN32
434    if (sizeof(inaddr.sin_port) == sizeof(short))
435 #endif /* ndef _WIN32 */
436    {
437       inaddr.sin_port = htons((short)portnum);
438    }
439 #ifndef _WIN32
440    else
441    {
442       inaddr.sin_port = htonl(portnum);
443    }
444 #endif /* ndef _WIN32 */
445
446    fd = socket(AF_INET, SOCK_STREAM, 0);
447
448    if (fd < 0)
449    {
450       return(-1);
451    }
452
453 #if 0
454 #ifndef _WIN32
455    /*
456     * FIXME: This is not needed for Win32 - in fact, it stops
457     * duplicate instances of JunkBuster from being caught.
458     * Is this really needed under UNIX, or should it be taked out?
459     * -- Jon
460     */
461    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
462 #endif /* ndef _WIN32 */
463 #endif
464
465    if (bind (fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
466    {
467       close_socket (fd);
468 #ifdef _WIN32
469       if (errno == WSAEADDRINUSE)
470 #else
471       if (errno == EADDRINUSE)
472 #endif
473       {
474          return(-2);
475       }
476       else
477       {
478          return(-1);
479       }
480    }
481
482    while (listen(fd, 5) == -1)
483    {
484       if (errno != EINTR)
485       {
486          return(-1);
487       }
488    }
489
490    return fd;
491
492 }
493
494
495 /*********************************************************************
496  *
497  * Function    :  accept_connection
498  *
499  * Description :  Accepts a connection on a socket.  Socket must have
500  *                been created using bind_port().
501  *
502  * Parameters  :
503  *          1  :  csp = Client state, cfd, ip_addr_str, and 
504  *                ip_addr_long will be set by this routine.
505  *          2  :  fd  = file descriptor returned from bind_port
506  *
507  * Returns     :  when a connection is accepted, it returns 1 (TRUE).
508  *                On an error it returns 0 (FALSE).
509  *
510  *********************************************************************/
511 int accept_connection(struct client_state * csp, int fd)
512 {
513    struct sockaddr_in client, server;
514    struct hostent *host = NULL;
515    int afd, c_length, s_length;
516 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) ||  defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
517    struct hostent result;
518 #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
519    struct hostent_data hdata;
520 #else
521    char hbuf[HOSTENT_BUFFER_SIZE];
522    int thd_err;
523 #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */
524 #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */
525
526    c_length = s_length = sizeof(client);
527
528    do
529    {
530       afd = accept (fd, (struct sockaddr *) &client, &c_length);
531    } while (afd < 1 && errno == EINTR);
532
533    if (afd < 0)
534    {
535       return 0;
536    }
537
538    /* 
539     * Determine the IP-Adress that the client used to reach us
540     * and the hostname associated with that address
541     */
542    if (!getsockname(afd, (struct sockaddr *) &server, &s_length))
543    {
544       csp->my_ip_addr_str = strdup(inet_ntoa(server.sin_addr));
545 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS)
546       gethostbyaddr_r((const char *)&server.sin_addr,
547                       sizeof(server.sin_addr), AF_INET,
548                       &result, hbuf, HOSTENT_BUFFER_SIZE,
549                       &host, &thd_err);
550 #elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS)
551       host = gethostbyaddr_r((const char *)&server.sin_addr,
552                       sizeof(server.sin_addr), AF_INET,
553                       &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err);
554 #elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS)
555       if (0 == gethostbyaddr_r((const char *)&server.sin_addr,
556                                sizeof(server.sin_addr), AF_INET,
557                                &result, &hdata))
558       {
559          host = &result;
560       }
561       else
562       {
563          host = NULL;
564       }
565 #else
566       host = gethostbyaddr((const char *)&server.sin_addr, 
567                            sizeof(server.sin_addr), AF_INET);
568 #endif
569       if (host == NULL)
570       {
571          log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n");
572       }
573       else
574       {
575          csp->my_hostname = strdup(host->h_name);
576       }
577    }
578
579    csp->cfd    = afd;
580    csp->ip_addr_str  = strdup(inet_ntoa(client.sin_addr));
581    csp->ip_addr_long = ntohl(client.sin_addr.s_addr);
582
583    return 1;
584
585 }
586
587
588 /*********************************************************************
589  *
590  * Function    :  resolve_hostname_to_ip
591  *
592  * Description :  Resolve a hostname to an internet tcp/ip address.
593  *                NULL or an empty string resolve to INADDR_ANY.
594  *
595  * Parameters  :
596  *          1  :  host = hostname to resolve
597  *
598  * Returns     :  -1 => failure, INADDR_ANY or tcp/ip address if succesful.
599  *
600  *********************************************************************/
601 int resolve_hostname_to_ip(const char *host)
602 {
603    struct sockaddr_in inaddr;
604    struct hostent *hostp;
605 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
606    struct hostent result;
607 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
608    char hbuf[HOSTENT_BUFFER_SIZE];
609    int thd_err;
610 #else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */
611    struct hostent_data hdata;
612 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */
613 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
614
615    if ((host == NULL) || (*host == '\0'))
616    {
617       return(INADDR_ANY);
618    }
619
620    memset((char *) &inaddr, 0, sizeof inaddr);
621
622    if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1)
623    {
624 #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS)
625       gethostbyname_r(host, &result, hbuf,
626                       HOSTENT_BUFFER_SIZE, &hostp, &thd_err);
627 #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS)
628       hostp = gethostbyname_r(host, &result, hbuf,
629                       HOSTENT_BUFFER_SIZE, &thd_err);
630 #elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS)
631       if (0 == gethostbyname_r(host, &result, &hdata))
632       {
633          hostp = &result;
634       }
635       else
636       {
637          hostp = NULL;
638       }
639 #else
640       hostp = gethostbyname(host);
641 #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */
642       if (hostp == NULL)
643       {
644          errno = EINVAL;
645          return(-1);
646       }
647       if (hostp->h_addrtype != AF_INET)
648       {
649 #ifdef _WIN32
650          errno = WSAEPROTOTYPE;
651 #else
652          errno = EPROTOTYPE;
653 #endif 
654          return(-1);
655       }
656       memcpy(
657          (char *) &inaddr.sin_addr,
658          (char *) hostp->h_addr,
659          sizeof(inaddr.sin_addr)
660       );
661    }
662    return(inaddr.sin_addr.s_addr);
663
664 }
665
666
667 /*
668   Local Variables:
669   tab-width: 3
670   end:
671 */