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