Hard tabs->Spaces
[privoxy.git] / jcc.c
1 const char jcc_rcs[] = "$Id: jcc.c,v 1.6 2001/05/23 00:13:58 joergs Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
5  *
6  * Purpose     :  Main file.  Contains main() method, main loop, and 
7  *                the main connection-handling function.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
10  *                IJBSWA team.  http://ijbswa.sourceforge.net
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and 
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it 
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: jcc.c,v $
36  *    Revision 1.6  2001/05/23 00:13:58  joergs
37  *    AmigaOS support fixed.
38  *
39  *    Revision 1.5  2001/05/22 18:46:04  oes
40  *
41  *    - Enabled filtering banners by size rather than URL
42  *      by adding patterns that replace all standard banner
43  *      sizes with the "Junkbuster" gif to the re_filterfile
44  *
45  *    - Enabled filtering WebBugs by providing a pattern
46  *      which kills all 1x1 images
47  *
48  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
49  *      which is selected by the (nonstandard and therefore
50  *      capital) letter 'U' in the option string.
51  *      It causes the quantifiers to be ungreedy by default.
52  *      Appending a ? turns back to greedy (!).
53  *
54  *    - Added a new interceptor ijb-send-banner, which
55  *      sends back the "Junkbuster" gif. Without imagelist or
56  *      MSIE detection support, or if tinygif = 1, or the
57  *      URL isn't recognized as an imageurl, a lame HTML
58  *      explanation is sent instead.
59  *
60  *    - Added new feature, which permits blocking remote
61  *      script redirects and firing back a local redirect
62  *      to the browser.
63  *      The feature is conditionally compiled, i.e. it
64  *      can be disabled with --disable-fast-redirects,
65  *      plus it must be activated by a "fast-redirects"
66  *      line in the config file, has its own log level
67  *      and of course wants to be displayed by show-proxy-args
68  *      Note: Boy, all the #ifdefs in 1001 locations and
69  *      all the fumbling with configure.in and acconfig.h
70  *      were *way* more work than the feature itself :-(
71  *
72  *    - Because a generic redirect template was needed for
73  *      this, tinygif = 3 now uses the same.
74  *
75  *    - Moved GIFs, and other static HTTP response templates
76  *      to project.h
77  *
78  *    - Some minor fixes
79  *
80  *    - Removed some >400 CRs again (Jon, you really worked
81  *      a lot! ;-)
82  *
83  *    Revision 1.4  2001/05/21 19:34:01  jongfoster
84  *    Made failure to bind() a fatal error.
85  *
86  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
87  *    Version 2.9.4 checkin.
88  *    - Merged popupfile and cookiefile, and added control over PCRS
89  *      filtering, in new "permissionsfile".
90  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
91  *      file error you now get a message box (in the Win32 GUI) rather
92  *      than the program exiting with no explanation.
93  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
94  *      skipping.
95  *    - Removed tabs from "config"
96  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
97  *    - Bumped up version number.
98  *
99  *    Revision 1.2  2001/05/17 22:34:44  oes
100  *     - Added hint on GIF char array generation to jcc.c
101  *     - Cleaned CRLF's from the sources and related files
102  *     - Repaired logging for REF and FRC
103  *
104  *    Revision 1.1.1.1  2001/05/15 13:58:56  oes
105  *    Initial import of version 2.9.3 source tree
106  *
107  *
108  *********************************************************************/
109 \f
110
111 #include "config.h"
112
113 #include <stdio.h>
114 #include <sys/types.h>
115 #include <stdlib.h>
116 #include <string.h>
117 #include <signal.h>
118 #include <fcntl.h>
119 #include <errno.h>
120
121 #ifdef _WIN32
122
123 # include <sys/timeb.h>
124 # include <windows.h>
125 # include <io.h>
126 # include <process.h>
127 # ifdef TOGGLE
128 #  include <time.h>
129 # endif /* def TOGGLE */
130
131 # include "win32.h"
132 # ifndef _WIN_CONSOLE
133 #  include "w32log.h"
134 # endif /* ndef _WIN_CONSOLE */
135
136 #else /* ifndef _WIN32 */
137
138 # include <unistd.h>
139 # include <sys/time.h>
140 # include <sys/wait.h>
141 # include <sys/stat.h>
142 # include <signal.h>
143
144 # ifdef __BEOS__
145 #  include <socket.h>  /* BeOS has select() for sockets only. */
146 #  include <OS.h>      /* declarations for threads and stuff. */
147 # endif
148
149 # ifndef FD_ZERO
150 #  include <select.h>
151 # endif
152
153 #endif
154
155 #include "project.h"
156 #include "jcc.h"
157 #include "filters.h"
158 #include "loaders.h"
159 #include "showargs.h"
160 #include "parsers.h"
161 #include "killpopup.h"
162 #include "miscutil.h"
163 #include "errlog.h"
164 #include "jbsockets.h"
165 #include "gateway.h"
166
167 const char jcc_h_rcs[] = JCC_H_VERSION;
168 const char project_h_rcs[] = PROJECT_H_VERSION;
169
170 const char DEFAULT_USER_AGENT[] ="User-Agent: Mozilla (X11; I; Linux 2.0.32 i586)";
171
172 struct client_state  clients[1];
173 struct file_list     files[1];
174
175 #ifdef STATISTICS
176 int urls_read     = 0;     /* total nr of urls read inc rejected */
177 int urls_rejected = 0;     /* total nr of urls rejected */
178 #endif /* def STATISTICS */
179
180
181 static void listen_loop(void);
182 static void chat(struct client_state *csp);
183 #ifdef AMIGA
184 void serve(struct client_state *csp);
185 #else /* ifndef AMIGA */
186 static void serve(struct client_state *csp);
187 #endif /* def AMIGA */
188
189 #ifdef __BEOS__
190 static int32 server_thread(void *data);
191 #endif /* def __BEOS__ */
192
193 #ifdef _WIN32
194 #define sleep(N)  Sleep(((N) * 1000))
195 #endif
196
197
198 /*********************************************************************
199  *
200  * Function    :  chat
201  *
202  * Description :  Once a connection to the client has been accepted,
203  *                this function is called (via serve()) to handle the
204  *                main business of the communication.  When this 
205  *                function returns, the caller must close the client
206  *                socket handle.
207  *
208  * Parameters  :
209  *          1  :  csp = Current client state (buffers, headers, etc...)
210  *
211  * Returns     :  On success, the number of bytes written are returned (zero
212  *                indicates nothing was written).  On error, -1 is returned,
213  *                and errno is set appropriately.  If count is zero and the
214  *                file descriptor refers to a regular file, 0 will be
215  *                returned without causing any other effect.  For a special
216  *                file, the results are not portable.
217  *
218  *********************************************************************/
219 static void chat(struct client_state *csp)
220 {
221 /* This next line is a little ugly, but it simplifies the if statement below. */
222 /* Basically if TOGGLE, then we want the if to test "csp->toggled_on", else we don't */
223 #ifdef TOGGLE
224 #   define IS_TOGGLED_ON csp->toggled_on &&
225 #else /* ifndef TOGGLE */
226 #   define IS_TOGGLED_ON
227 #endif /* ndef TOGGLE */
228
229 /* This next line is a little ugly, but it simplifies the if statement below. */
230 /* Basically if TRUST_FILES, then we want the if to call "trust_url", else we don't */
231 #ifdef TRUST_FILES
232 #   define IS_TRUSTED_URL (p = trust_url(http, csp)) ||
233 #else /* ifndef TRUST_FILES */
234 #   define IS_TRUSTED_URL
235 #endif /* ndef TRUST_FILES */
236
237    char buf[BUFSIZ], *hdr, *p, *req;
238    char *err = NULL;
239    char *eno;
240    fd_set rfds;
241    int n, maxfd, server_body, ms_iis5_hack = 0;
242    const struct gateway *gw;
243    struct http_request *http;
244 #ifdef KILLPOPUPS
245    int block_popups;         /* bool, 1==will block popups */
246    int block_popups_now = 0; /* bool, 1==currently blocking popups */
247 #endif /* def KILLPOPUPS */
248 #ifdef PCRS
249    int pcrs_filter;   /* bool, 1==will filter through pcrs */
250    int filtering = 0; /* bool, 1==currently filtering through pcrs */
251 #endif /* def PCRS */
252
253    http = csp->http;
254
255    /*
256     * Read the client's request.  Note that since we're not using select() we
257     * could get blocked here if a client connected, then didn't say anything!
258     */
259
260    while (FOREVER)
261    {
262       n = read_socket(csp->cfd, buf, sizeof(buf));
263
264       if (n <= 0) break;      /* error! */
265
266       add_to_iob(csp, buf, n);
267
268       req = get_header(csp);
269
270       if (req == NULL)
271       {
272          break;    /* no HTTP request! */
273       }
274
275       if (*req == '\0')
276       {
277          continue;   /* more to come! */
278       }
279  
280 #ifdef FORCE_LOAD
281       /* If this request contains the FORCE_PREFIX,
282        * better get rid of it now and set the force flag --oes
283        */
284
285       if (strstr(req, FORCE_PREFIX))
286       {
287          strclean(req, FORCE_PREFIX);
288          log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", req);
289          csp->force = 1;
290       } 
291       else
292       {
293          csp->force = 0;
294       }
295 #endif /* def FORCE_LOAD */
296   
297       parse_http_request(req, http, csp);
298       freez(req);
299       break;
300    }
301
302    if (http->cmd == NULL)
303    {
304       strcpy(buf, CHEADER);
305       write_socket(csp->cfd, buf, strlen(buf));
306       return;
307    }
308
309    /* decide how to route the HTTP request */
310
311    if ((gw = forward_url(http, csp)) == NULL)
312    {
313       log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!?  This can't happen!");
314       /* Never get here - LOG_LEVEL_FATAL causes program exit */
315    }
316
317    /* build the http request to send to the server
318     * we have to do one of the following:
319     *
320     * create = use the original HTTP request to create a new
321     *          HTTP request that has only the path component
322     *          without the http://domainspec
323     * pass   = pass the original HTTP request unchanged
324     *
325     * drop   = drop the HTTP request
326     *
327     * here's the matrix:
328     *                        SSL
329     *                    0        1
330     *                +--------+--------+
331     *                |        |        |
332     *             0  | create | drop   |
333     *                |        |        |
334     *  Forwarding    +--------+--------+
335     *                |        |        |
336     *             1  | pass   | pass   |
337     *                |        |        |
338     *                +--------+--------+
339     *
340     */
341
342    if (gw->forward_host)
343    {
344       /* if forwarding, just pass the request as is */
345       enlist(csp->headers, http->cmd);
346    }
347    else
348    {
349       if (http->ssl == 0)
350       {
351          /* otherwise elide the host information from the url */
352          p = NULL;
353          p = strsav(p, http->gpc);
354          p = strsav(p, " ");
355          p = strsav(p, http->path);
356          p = strsav(p, " ");
357          p = strsav(p, http->ver);
358          enlist(csp->headers, p);
359          freez(p);
360       }
361    }
362
363    /* decide what we're to do with cookies */
364
365 #ifdef TOGGLE
366    if (!csp->toggled_on)
367    {
368       /* Most compatible set of permissions */
369       csp->permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS;
370    }
371    else
372    {
373       csp->permissions = url_permissions(http, csp);
374    }
375 #else /* ifndef TOGGLE */
376    csp->permissions = url_permissions(http, csp);
377 #endif /* ndef TOGGLE */
378
379 #ifdef KILLPOPUPS
380    block_popups               = ((csp->permissions & PERMIT_POPUPS) == 0);
381 #endif /* def KILLPOPUPS */
382 #ifdef PCRS
383    pcrs_filter                = (csp->rlist != NULL) &&  /* There are expressions to be used */
384                                 ((csp->permissions & PERMIT_RE_FILTER) != 0);
385 #endif /* def PCRS */
386
387
388    /* grab the rest of the client's headers */
389
390    while (FOREVER)
391    {
392       if ( ( p = get_header(csp) ) && ( *p == '\0' ) )
393       {
394          n = read_socket(csp->cfd, buf, sizeof(buf));
395          if (n <= 0)
396          {
397             log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
398             return;
399          }
400          add_to_iob(csp, buf, n);
401          continue;
402       }
403
404       if (p == NULL) break;
405
406       enlist(csp->headers, p);
407       freez(p);
408    }
409
410    /* filter it as required */
411
412    hdr = sed(client_patterns, add_client_headers, csp);
413
414    destroy_list(csp->headers);
415
416    /* Check the request against all rules, unless
417     * we're toggled off or in force mode. 
418     */
419  
420    if (IS_TOGGLED_ON
421 #ifdef FORCE_LOAD
422        (!csp->force) && 
423 #endif /* def FORCE_LOAD */
424        ( (p = intercept_url(http, csp)) ||
425          IS_TRUSTED_URL
426          (p = block_url(http, csp))
427 #ifdef FAST_REDIRECTS
428          || (fast_redirects && (p = redirect_url(http, csp))) 
429 #endif /* def FAST_REDIRECTS */
430       ))
431    {
432 #ifdef STATISTICS
433       csp->rejected = 1;
434 #endif /* def STATISTICS */
435
436       log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path);
437
438 #if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
439       /* Block as image?  */
440       if ( (tinygif > 0) && block_imageurl(http, csp) )
441       {
442          /* Send "blocked" image */
443          log_error(LOG_LEVEL_GPC, "%s%s image crunch!",
444                    http->hostport, http->path);
445
446          if ((tinygif == 2) || strstr(http->path, "ijb-send-banner"))
447          {
448             write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
449          }
450          if (tinygif == 1)
451          {
452             write_socket(csp->cfd, BLANKGIF, sizeof(BLANKGIF)-1);
453          }
454          else if ((tinygif == 3) && (tinygifurl))
455          {
456             p = (char *)malloc(strlen(HTTP_REDIRECT_TEMPLATE) + strlen(tinygifurl));
457             sprintf(p, HTTP_REDIRECT_TEMPLATE, tinygifurl);
458             write_socket(csp->cfd, p, strlen(p));
459          }
460          else
461          {
462             write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
463          }
464       }
465       else
466 #endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
467       /* Block as HTML */
468       {
469          /* Send HTML "blocked" message, interception, or redirection result */
470          write_socket(csp->cfd, p, strlen(p));
471       }
472
473       log_error(LOG_LEVEL_LOG, "%s", p);
474
475       freez(p);
476       freez(hdr);
477       return;
478    }
479
480    log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path);
481
482    if (gw->forward_host)
483    {
484       log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s",
485                gw->forward_host, gw->forward_port, http->hostport);
486    }
487    else
488    {
489       log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport);
490    }
491
492    /* here we connect to the server, gateway, or the forwarder */
493
494    csp->sfd = (gw->conn)(gw, http, csp);
495
496    if (csp->sfd < 0)
497    {
498       log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
499                 http->hostport);
500
501       if (errno == EINVAL)
502       {
503          err = zalloc(strlen(CNXDOM) + strlen(http->host));
504          sprintf(err, CNXDOM, http->host);
505       }
506       else
507       {
508          eno = safe_strerror(errno);
509          err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
510          sprintf(err, CFAIL, http->hostport, eno);
511       }
512
513       write_socket(csp->cfd, err, strlen(err));
514
515       log_error(LOG_LEVEL_LOG, err);
516
517       freez(err);
518       freez(hdr);
519       return;
520    }
521
522    log_error(LOG_LEVEL_CONNECT, "OK");
523
524    if (gw->forward_host || (http->ssl == 0))
525    {
526       /* write the client's (modified) header to the server
527        * (along with anything else that may be in the buffer)
528        */
529
530       n = strlen(hdr);
531
532       if ((write_socket(csp->sfd, hdr, n) != n)
533           || (flush_socket(csp->sfd, csp   ) <  0))
534       {
535          log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
536                     http->hostport);
537
538          eno = safe_strerror(errno);
539          err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
540          sprintf(err, CFAIL, http->hostport, eno);
541          write_socket(csp->cfd, err, strlen(err));
542
543          freez(err);
544          freez(hdr);
545          return;
546       }
547    }
548    else
549    {
550       /*
551        * We're running an SSL tunnel and we're not forwarding,
552        * so just send the "connect succeeded" message to the
553        * client, flush the rest, and get out of the way.
554        */
555       if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0)
556       {
557          freez(hdr);
558          return;
559       }
560       IOB_RESET(csp);
561    }
562
563    /* we're finished with the client's header */
564    freez(hdr);
565
566    maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
567
568    /* pass data between the client and server
569     * until one or the other shuts down the connection.
570     */
571
572    server_body = 0;
573
574    while (FOREVER)
575    {
576       FD_ZERO(&rfds);
577
578       FD_SET(csp->cfd, &rfds);
579       FD_SET(csp->sfd, &rfds);
580
581       n = select(maxfd+1, &rfds, NULL, NULL, NULL);
582
583       if (n < 0)
584       {
585          log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
586          return;
587       }
588
589       /* this is the body of the browser's request
590        * just read it and write it.
591        */
592
593       if (FD_ISSET(csp->cfd, &rfds))
594       {
595          n = read_socket(csp->cfd, buf, sizeof(buf));
596
597          if (n <= 0) break; /* "game over, man" */
598
599          if (write_socket(csp->sfd, buf, n) != n)
600          {
601             log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
602             return;
603          }
604          continue;
605       }
606
607       /*
608        * The server wants to talk.  It could be the header or the body.
609        * If `hdr' is null, then it's the header otherwise it's the body.
610        * FIXME: Does `hdr' really mean `host'?
611        */
612
613
614       if (FD_ISSET(csp->sfd, &rfds))
615       {
616          fflush( 0 );
617          n = read_socket(csp->sfd, buf, sizeof(buf) - 1);
618
619          if (n < 0)
620          {
621             log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host);
622
623             eno = safe_strerror(errno);
624             sprintf(buf, CFAIL, http->hostport, eno);
625             freez(eno);
626             write_socket(csp->cfd, buf, strlen(buf));
627             return;
628          }
629
630          /* Add a trailing zero.  This lets filter_popups
631           * use string operations.
632           */
633          buf[n] = '\0';
634
635 #ifdef KILLPOPUPS
636          /* Filter the popups on this read. */
637          if (block_popups_now)
638          {
639             filter_popups(buf, n);
640          }
641 #endif /* def KILLPOPUPS */
642
643          /* Normally, this would indicate that we've read
644           * as much as the server has sent us and we can
645           * close the client connection.  However, Microsoft
646           * in its wisdom has released IIS/5 with a bug that
647           * prevents it from sending the trailing \r\n in
648           * a 302 redirect header (and possibly other headers).
649           * To work around this if we've haven't parsed
650           * a full header we'll append a trailing \r\n
651           * and see if this now generates a valid one.
652           *
653           * This hack shouldn't have any impacts.  If we've
654           * already transmitted the header or if this is a
655           * SSL connection, then we won't bother with this
656           * hack.  So we only work on partially received
657           * headers.  If we append a \r\n and this still
658           * doesn't generate a valid header, then we won't
659           * transmit anything to the client.
660           */
661          if (n == 0)
662          {
663             /* This hack must only be enforced for headers. */
664             if (server_body || http->ssl)
665             {
666 #ifdef PCRS
667                if (filtering)
668                {
669                   re_process_buffer(csp);
670                }
671 #endif /* def PCRS */
672                break; /* "game over, man" */
673             }
674
675             /* Let's pretend the server just sent us a blank line. */
676             n = sprintf(buf, "\r\n");
677
678             /*
679              * Now, let the normal header parsing algorithm below do its
680              * job.  If it fails, we'll exit instead of continuing.
681              */
682
683             ms_iis5_hack = 1;
684          }
685
686          /*
687           * If this is an SSL connection or we're in the body
688           * of the server document, just write it to the client.
689           */
690
691          if (server_body || http->ssl)
692          {
693 #ifdef PCRS
694             if (filtering)
695             {
696                add_to_iob(csp, buf, n); /* Buffer the body for filtering */
697             }
698             else
699 #endif /* def PCRS */
700             {
701                /* just write */
702                if (write_socket(csp->cfd, buf, n) != n)
703                {
704                   log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
705                   return;
706                }
707             }
708             continue;
709          }
710          else
711          {
712             /* we're still looking for the end of the
713              * server's header ... (does that make header
714              * parsing an "out of body experience" ?
715              */
716
717             /* buffer up the data we just read */
718             add_to_iob(csp, buf, n);
719
720             /* get header lines from the iob */
721
722             while ((p = get_header(csp)))
723             {
724                if (*p == '\0')
725                {
726                   /* see following note */
727                   break;
728                }
729                enlist(csp->headers, p);
730                freez(p);
731             }
732
733             /* NOTE: there are no "empty" headers so
734              * if the pointer `p' is not NULL we must
735              * assume that we reached the end of the
736              * buffer before we hit the end of the header.
737              */
738
739             if (p)
740             {
741                if (ms_iis5_hack)
742                {
743                   /* Well, we tried our MS IIS/5
744                    * hack and it didn't work.
745                    * The header is incomplete
746                    * and there isn't anything
747                    * we can do about it.
748                    */
749                   break;
750                }
751                else
752                {
753                   /* Since we have to wait for
754                    * more from the server before
755                    * we can parse the headers
756                    * we just continue here.
757                    */
758                   continue;
759                }
760             }
761
762             /* we have now received the entire header.
763              * filter it and send the result to the client
764              */
765
766             hdr = sed(server_patterns, add_server_headers, csp);
767             n   = strlen(hdr);
768
769             /* write the server's (modified) header to
770              * the client (along with anything else that
771              * may be in the buffer)
772              */
773
774 #ifdef KILLPOPUPS
775             /* Start blocking popups if appropriate. */
776
777             if (csp->is_text  &&  /* It's a text / * MIME-Type */
778                 !http->ssl    &&  /* We talk plaintext */
779                 block_popups)
780             {
781                block_popups_now = 1;
782             }
783
784 #endif /* def KILLPOPUPS */
785
786 #ifdef PCRS
787             /* Start re_filtering this if appropriate. */
788
789             if (csp->is_text  &&  /* It's a text / * MIME-Type */
790                 !http->ssl    &&  /* We talk plaintext */
791                 pcrs_filter)      /* Policy allows */
792             {
793                filtering = 1;
794             }
795
796 /* This next line is a little ugly, but it simplifies the if statement below. */
797 /* Basically if using PCRS, we want the OR condition to require "!filtering"  */
798 #define NOT_FILTERING_AND !filtering &&
799
800 #else /* not def PCRS */
801
802 #define NOT_FILTERING_AND
803
804 #endif /* def PCRS */
805
806
807             if ((write_socket(csp->cfd, hdr, n) != n)
808                 || (NOT_FILTERING_AND (flush_socket(csp->cfd, csp) < 0)))
809             {
810                log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
811
812                /* the write failed, so don't bother
813                 * mentioning it to the client...
814                 * it probably can't hear us anyway.
815                 */
816                freez(hdr);
817                return;
818             }
819
820             /* we're finished with the server's header */
821
822             freez(hdr);
823             server_body = 1;
824
825             /* If this was a MS IIS/5 hack then it means
826              * the server has already closed the
827              * connection.  Nothing more to read.  Time
828              * to bail.
829              */
830             if (ms_iis5_hack)
831             {
832                break;
833             }
834          }
835          continue;
836       }
837
838       return; /* huh? we should never get here */
839    }
840
841
842 }
843
844
845 /*********************************************************************
846  *
847  * Function    :  serve
848  *
849  * Description :  This is little more than chat.  We only "serve" to
850  *                to close any socket that chat may have opened.
851  *
852  * Parameters  :
853  *          1  :  csp = Current client state (buffers, headers, etc...)
854  *
855  * Returns     :  N/A
856  *
857  *********************************************************************/
858 #ifdef AMIGA
859 void serve(struct client_state *csp)
860 #else /* ifndef AMIGA */
861 static void serve(struct client_state *csp)
862 #endif /* def AMIGA */
863 {
864    chat(csp);
865    close_socket(csp->cfd);
866
867    if (csp->sfd >= 0)
868    {
869       close_socket(csp->sfd);
870    }
871
872    csp->active = 0;
873
874 }
875
876
877 #ifdef __BEOS__
878
879 /*********************************************************************
880  *
881  * Function    :  server_thread
882  *
883  * Description :  We only exist to call `serve' in a threaded environment.
884  *
885  * Parameters  :
886  *          1  :  data = Current client state (buffers, headers, etc...)
887  *
888  * Returns     :  Always 0.
889  *
890  *********************************************************************/
891 static int32 server_thread(void *data)
892 {
893    serve((struct client_state *) data);
894    return 0;
895
896 }
897
898 #endif
899
900
901 /*********************************************************************
902  *
903  * Function    :  main
904  *
905  * Description :  Load the config file and start the listen loop.
906  *                This function is a lot more *sane* with the `load_config'
907  *                and `listen_loop' functions; although it stills does
908  *                a *little* too much for my taste.
909  *
910  * Parameters  :
911  *          1  :  argc = Number of parameters (including $0).
912  *          2  :  argv = Array of (char *)'s to the parameters.
913  *
914  * Returns     :  1 if : can't open config file, unrecognized directive,
915  *                stats requested in multi-thread mode, can't open the
916  *                log file, can't open the jar file, listen port is invalid,
917  *                any load fails, and can't bind port.
918  *
919  *                Else main never returns, the process must be signaled
920  *                to terminate execution.  Or, on Windows, use the 
921  *                "File", "Exit" menu option.
922  *
923  *********************************************************************/
924 #ifdef __MINGW32__
925 int _main(int argc, const char *argv[])
926 #else
927 int main(int argc, const char *argv[])
928 #endif
929 {
930    configfile =
931 #ifdef AMIGA
932    "AmiTCP:db/junkbuster.config"
933 #elif !defined(_WIN32)
934    "config"
935 #else
936    "junkbstr.txt"
937 #endif
938       ;
939
940 #if !defined(_WIN32) || defined(_WIN_CONSOLE)
941    if ((argc >= 2) && (strcmp(argv[1], "--help")==0))
942    {
943       printf("JunkBuster proxy version " VERSION ".\n\n"
944          "Usage: %s [configfile]\n\n"
945          "See " HOME_PAGE_URL " for details.\n"
946          "This program is distributed under the GNU GPL, version 2 or later.\n",
947          argv[0]);
948       exit(2);
949    }
950    if ((argc >= 2) && (strcmp(argv[1], "--version")==0))
951    {
952       printf(VERSION "\n");
953       exit(2);
954    }
955 #endif /* !defined(_WIN32) || defined(_WIN_CONSOLE) */
956
957 #ifdef AMIGA
958    InitAmiga();
959 #endif
960
961    Argc = argc;
962    Argv = argv;
963
964    if (argc > 1)
965    {
966       configfile = argv[1];
967    }
968
969    remove_all_loaders();
970    memset( proxy_args, 0, sizeof( proxy_args ) );
971    files->next = NULL;
972
973    load_config( 0 );
974
975    /*
976     * Since load_config acts as a signal handler too, it returns
977     * its status in configret.  Check it for an error in loading.
978     */
979    if ( 0 != configret )
980    {
981       /* load config failed!  Exit with error. */
982       return( 1 );
983    }
984
985 #ifdef _WIN32
986    InitWin32();
987 #endif
988
989
990 #ifndef _WIN32
991    signal(SIGPIPE, SIG_IGN);
992    signal(SIGCHLD, SIG_IGN);
993    signal(SIGHUP, load_config);
994
995 #else /* ifdef _WIN32 */
996 # ifdef _WIN_CONSOLE
997    /*
998     * We *are* in a windows console app.
999     * Print a verbose messages about FAQ's and such
1000     */
1001    printf(win32_blurb);
1002 # endif /* def _WIN_CONSOLE */
1003 #endif /* def _WIN32 */
1004
1005
1006    listen_loop();
1007
1008    /* NOTREACHED */
1009    return(-1);
1010
1011 }
1012
1013
1014 /*********************************************************************
1015  *
1016  * Function    :  listen_loop
1017  *
1018  * Description :  bind the listen port and enter a "FOREVER" listening loop.
1019  *
1020  * Parameters  :  N/A
1021  *
1022  * Returns     :  Never.
1023  *
1024  *********************************************************************/
1025 static void listen_loop(void)
1026 {
1027    struct client_state *csp = NULL;
1028    int bfd;
1029
1030    log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
1031              haddr ? haddr : "INADDR_ANY", hport);
1032
1033    bfd = bind_port(haddr, hport);
1034    config_changed = 0;
1035
1036    if (bfd < 0)
1037    {
1038       log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E "
1039          "- There may be another junkbuster or some other "
1040          "proxy running on port %d", 
1041          (NULL != haddr) ? haddr : "INADDR_ANY", hport, hport
1042       );
1043       /* shouldn't get here */
1044       return;
1045    }
1046
1047
1048    while (FOREVER)
1049    {
1050 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1051       while (waitpid(-1, NULL, WNOHANG) > 0)
1052       {
1053          /* zombie children */
1054       }
1055 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1056       sweep();
1057
1058       if ( NULL == (csp = (struct client_state *) malloc(sizeof(*csp))) )
1059       {
1060          log_error(LOG_LEVEL_ERROR, "malloc(%d) for csp failed: %E", sizeof(*csp));
1061          continue;
1062       }
1063
1064       memset(csp, '\0', sizeof(*csp));
1065
1066       csp->active = 1;
1067       csp->sfd    = -1;
1068
1069       if ( config_changed )
1070       {
1071          /*
1072           * Since we were listening to the "old port", we will not see
1073           * a "listen" param change until the next IJB request.  So, at
1074           * least 1 more request must be made for us to find the new
1075           * setting.  I am simply closing the old socket and binding the
1076           * new one.
1077           *
1078           * Which-ever is correct, we will serve 1 more page via the
1079           * old settings.  This should probably be a "show-proxy-args"
1080           * request.  This should not be a so common of an operation
1081           * that this will hurt people's feelings.
1082           */
1083          close_socket(bfd);
1084
1085          log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)",
1086                    haddr ? haddr : "INADDR_ANY", hport);
1087          bfd = bind_port(haddr, hport);
1088
1089          config_changed = 0;
1090       }
1091
1092       log_error(LOG_LEVEL_CONNECT, "accept connection ... ");
1093
1094       if (!accept_connection(csp, bfd))
1095       {
1096          log_error(LOG_LEVEL_CONNECT, "accept failed: %E");
1097
1098 #ifdef AMIGA
1099          if(!childs)
1100          {
1101             exit(1); 
1102          }
1103 #endif
1104          continue;
1105       }
1106       else
1107       {
1108          log_error(LOG_LEVEL_CONNECT, "OK");
1109       }
1110
1111 #if defined(TOGGLE)
1112       /* by haroon - most of credit to srt19170 */
1113       csp->toggled_on = g_bToggleIJB;
1114 #endif
1115
1116       /* add it to the list of clients */
1117       csp->next = clients->next;
1118       clients->next = csp;
1119
1120       if (run_loader(csp))
1121       {
1122          log_error(LOG_LEVEL_FATAL, "a loader failed - must exit");
1123          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1124       }
1125
1126       if (multi_threaded)
1127       {
1128          int child_id;
1129
1130 /* this is a switch () statment in the C preprocessor - ugh */
1131 #undef SELECTED_ONE_OPTION
1132
1133 #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION)
1134 #define SELECTED_ONE_OPTION
1135          child_id = _beginthread(
1136             (void*)serve,
1137             64 * 1024,
1138             csp);
1139 #endif
1140
1141 #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
1142 #define SELECTED_ONE_OPTION
1143          {
1144             thread_id tid = spawn_thread
1145                (server_thread, "server", B_NORMAL_PRIORITY, csp);
1146
1147             if ((tid >= 0) && (resume_thread(tid) == B_OK))
1148             {
1149                child_id = (int) tid;
1150             }
1151             else
1152             {
1153                child_id = -1;
1154             }
1155          }
1156 #endif
1157
1158 #if defined(AMIGA) && !defined(SELECTED_ONE_OPTION)
1159 #define SELECTED_ONE_OPTION
1160          csp->cfd = ReleaseSocket(csp->cfd, -1);
1161          if((child_id = (int)CreateNewProcTags(
1162             NP_Entry, (ULONG)server_thread,
1163             NP_Output, Output(),
1164             NP_CloseOutput, FALSE,
1165             NP_Name, (ULONG)"junkbuster child",
1166             NP_StackSize, 20*1024,
1167             TAG_DONE)))
1168          {
1169             childs++;
1170             ((struct Task *)child_id)->tc_UserData = csp;
1171             Signal((struct Task *)child_id, SIGF_SINGLE);
1172             Wait(SIGF_SINGLE);
1173          }
1174 #endif
1175
1176 #if !defined(SELECTED_ONE_OPTION)
1177          child_id = fork();
1178 #endif
1179
1180 #undef SELECTED_ONE_OPTION
1181 /* end of cpp switch () */
1182
1183          if (child_id < 0) /* failed */
1184          {
1185             char buf[BUFSIZ];
1186
1187             log_error(LOG_LEVEL_ERROR, "can't fork: %E");
1188
1189             sprintf(buf , "JunkBuster: can't fork: errno = %d", errno);
1190
1191             write_socket(csp->cfd, buf, strlen(buf));
1192             close_socket(csp->cfd);
1193             csp->active = 0;
1194             sleep(5);
1195             continue;
1196          }
1197
1198 #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA)
1199          /* This block is only needed when using fork().
1200           * When using threads, the server thread was
1201           * created and run by the call to _beginthread().
1202           */
1203          if (child_id == 0)   /* child */
1204          {
1205             serve(csp);
1206             _exit(0);
1207
1208          }
1209          else  /* parent */
1210          {
1211             /* in a fork()'d environment, the parent's
1212              * copy of the client socket and the CSP
1213              * are not used.
1214              */
1215
1216 #if !defined(_WIN32) && defined(__CYGWIN__)
1217             wait( NULL );
1218 #endif /* !defined(_WIN32) && defined(__CYGWIN__) */
1219             close_socket(csp->cfd);
1220             csp->active = 0;
1221          }
1222 #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */
1223       }
1224       else
1225       {
1226          serve(csp);
1227       }
1228    }
1229    /* NOTREACHED */
1230
1231 }
1232
1233
1234 /*
1235   Local Variables:
1236   tab-width: 3
1237   end:
1238 */