X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=4700d2f4e8989a1b465a6862cc45634fc4fb9d3b;hp=ee27d19d4642c803af42d27ab92a0b26c033cd9a;hb=5f390b415777db21894f1b856ab3d21c9c24f7c6;hpb=1381e110e8518401178f393ac0e1e281040ad3d5 diff --git a/jcc.c b/jcc.c index ee27d19d..4700d2f4 100644 --- a/jcc.c +++ b/jcc.c @@ -1,19 +1,19 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.49 2001/10/23 21:41:35 jongfoster Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ * - * Purpose : Main file. Contains main() method, main loop, and + * Purpose : Main file. Contains main() method, main loop, and * the main connection-handling function. * * Copyright : Written by and Copyright (C) 2001 the SourceForge * IJBSWA team. http://ijbswa.sourceforge.net * * Based on the Internet Junkbuster originally written - * by and Copyright (C) 1997 Anonymous Coders and + * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * - * This program is free software; you can redistribute it + * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at @@ -33,6 +33,285 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $"; * * Revisions : * $Log: jcc.c,v $ + * Revision 1.49 2001/10/23 21:41:35 jongfoster + * Added call to initialize the (statically-allocated of course) + * "out of memory" CGI response. + * + * Revision 1.48 2001/10/10 19:56:46 jongfoster + * Moving some code that wasn't cookie-related out of an #ifdef + * FEATURE_COOKIE_JAR + * + * Revision 1.47 2001/10/10 16:44:36 oes + * Added CONNECT destination port limitation check + * + * Revision 1.46 2001/10/08 15:17:41 oes + * Re-enabled SSL forwarding + * + * Revision 1.45 2001/10/07 15:42:11 oes + * Replaced 6 boolean members of csp with one bitmap (csp->flags) + * + * Moved downgrading of the HTTP version from parse_http_request to + * chat(), since we can't decide if it is necessary before we have + * determined the actions for the URL. The HTTP command is now + * *always* re-built so the repairs need no longer be special-cased. + * + * filter_popups now gets a csp pointer so it can raise the new + * CSP_FLAG_MODIFIED flag. + * + * Bugfix + * + * Added configurable size limit for the IOB. If the IOB grows so + * large that the next read would exceed the limit, the header + * is generated, and the header & unfiltered buffer are flushed + * to the client. Chat then continues in non-buffering, + * non-filtering body mode. + * + * Revision 1.44 2001/10/02 18:13:57 oes + * Ooops + * + * Revision 1.43 2001/10/02 15:32:13 oes + * Moved generation of hdr + * + * Revision 1.42 2001/09/21 23:02:02 david__schmidt + * Cleaning up 2 compiler warnings on OS/2. + * + * Revision 1.41 2001/09/16 17:05:14 jongfoster + * Removing unused #include showarg.h + * + * Revision 1.40 2001/09/16 15:41:45 jongfoster + * Fixing signed/unsigned comparison warning. + * + * Revision 1.39 2001/09/16 13:21:27 jongfoster + * Changes to use new list functions. + * + * Revision 1.38 2001/09/16 13:01:46 jongfoster + * Removing redundant function call that zeroed zalloc()'d memory. + * + * Revision 1.37 2001/09/10 11:12:24 oes + * Deleted unused variable + * + * Revision 1.36 2001/09/10 10:56:15 oes + * Silenced compiler warnings + * + * Revision 1.35 2001/07/31 14:44:22 oes + * Deleted unused size parameter from filter_popups() + * + * Revision 1.34 2001/07/30 22:08:36 jongfoster + * Tidying up #defines: + * - All feature #defines are now of the form FEATURE_xxx + * - Permanently turned off WIN_GUI_EDIT + * - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS + * + * Revision 1.33 2001/07/29 19:32:00 jongfoster + * Renaming _main() [mingw32 only] to real_main(), for ANSI compliance. + * + * Revision 1.32 2001/07/29 18:47:05 jongfoster + * Adding missing #include "loadcfg.h" + * + * Revision 1.31 2001/07/29 12:17:48 oes + * Applied pthread fix by Paul Lieverse + * + * Revision 1.30 2001/07/25 22:57:13 jongfoster + * __BEOS__ no longer overrides FEATURE_PTHREAD. + * This is because FEATURE_PTHREAD will soon be widely used, so I + * want to keep it simple. + * + * Revision 1.29 2001/07/24 12:47:06 oes + * Applied BeOS support update by Eugenia + * + * Revision 1.28 2001/07/23 13:26:12 oes + * Fixed bug in popup-killing for the first read that caused binary garbage to be sent between headers and body + * + * Revision 1.27 2001/07/19 19:09:47 haroon + * - Added code to take care of the situation where while processing the first + * server response (which includes the server header), after finding the end + * of the headers we were not looking past the end of the headers for + * content modification. I enabled it for filter_popups. + * Someone else should look to see if other similar operations should be + * done to the discarded portion of the buffer. + * + * Note 2001/07/20: No, the other content modification mechanisms will process + * the whole iob later anyway. --oes + * + * Revision 1.26 2001/07/18 12:31:36 oes + * cosmetics + * + * Revision 1.25 2001/07/15 19:43:49 jongfoster + * Supports POSIX threads. + * Also removed some unused #includes. + * + * Revision 1.24 2001/07/13 14:00:40 oes + * - Generic content modification scheme: + * Each feature has its own applicability flag that is set + * from csp->action->flags. + * Replaced the "filtering" int flag , by a function pointer + * "content_filter" to the function that will do the content + * modification. If it is != NULL, the document will be buffered + * and processed through *content_filter, which must set + * csp->content_length and return a modified copy of the body + * or return NULL (on failiure). + * - Changed csp->is_text to the more generic bitmap csp->content_type + * which can currently take the valued CT_TEXT or CT_GIF + * - Reformatting etc + * - Removed all #ifdef PCRS + * + * Revision 1.23 2001/07/02 02:28:25 iwanttokeepanon + * Added "#ifdef ACL_FILES" conditional compilation to line 1291 to exclude + * the `block_acl' call. This prevents a compilation error when the user + * does not wish to use the "ACL" feature. + * + * Revision 1.22 2001/06/29 21:45:41 oes + * Indentation, CRLF->LF, Tab-> Space + * + * Revision 1.21 2001/06/29 13:29:36 oes + * - Cleaned up, improved comments + * - Unified all possible interceptors (CGI, + * block, trust, fast_redirect) in one + * place, with one (CGI) answer generation + * mechansim. Much clearer now. + * - Removed the GIF image generation, which + * is now done in filters.c:block_url() + * - Made error conditions like domain lookup + * failiure or (various) problems while talking + * to the server use cgi.c:error_response() + * instead of generating HTML/HTTP in chat() (yuck!) + * - Removed logentry from cancelled commit + * + * Revision 1.20 2001/06/09 10:55:28 jongfoster + * Changing BUFSIZ ==> BUFFER_SIZE + * + * Revision 1.19 2001/06/07 23:12:52 jongfoster + * Replacing function pointer in struct gateway with a directly + * called function forwarded_connect(). + * Replacing struct gateway with struct forward_spec + * + * Revision 1.18 2001/06/03 19:12:16 oes + * introduced new cgi handling + * + * Revision 1.17 2001/06/01 20:07:23 jongfoster + * Now uses action +image-blocker{} rather than config->tinygif + * + * Revision 1.16 2001/06/01 18:49:17 jongfoster + * Replaced "list_share" with "list" - the tiny memory gain was not + * worth the extra complexity. + * + * Revision 1.15 2001/05/31 21:24:47 jongfoster + * Changed "permission" to "action" throughout. + * Removed DEFAULT_USER_AGENT - it must now be specified manually. + * Moved vanilla wafer check into chat(), since we must now + * decide whether or not to add it based on the URL. + * + * Revision 1.14 2001/05/29 20:14:01 joergs + * AmigaOS bugfix: PCRS needs a lot of stack, stacksize for child threads + * increased. + * + * Revision 1.13 2001/05/29 09:50:24 jongfoster + * Unified blocklist/imagelist/permissionslist. + * File format is still under discussion, but the internal changes + * are (mostly) done. + * + * Also modified interceptor behaviour: + * - We now intercept all URLs beginning with one of the following + * prefixes (and *only* these prefixes): + * * http://i.j.b/ + * * http://ijbswa.sf.net/config/ + * * http://ijbswa.sourceforge.net/config/ + * - New interceptors "home page" - go to http://i.j.b/ to see it. + * - Internal changes so that intercepted and fast redirect pages + * are not replaced with an image. + * - Interceptors now have the option to send a binary page direct + * to the client. (i.e. ijb-send-banner uses this) + * - Implemented show-url-info interceptor. (Which is why I needed + * the above interceptors changes - a typical URL is + * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif". + * The previous mechanism would not have intercepted that, and + * if it had been intercepted then it then it would have replaced + * it with an image.) + * + * Revision 1.12 2001/05/27 22:17:04 oes + * + * - re_process_buffer no longer writes the modified buffer + * to the client, which was very ugly. It now returns the + * buffer, which it is then written by chat. + * + * - content_length now adjusts the Content-Length: header + * for modified documents rather than crunch()ing it. + * (Length info in csp->content_length, which is 0 for + * unmodified documents) + * + * - For this to work, sed() is called twice when filtering. + * + * Revision 1.11 2001/05/26 17:27:53 jongfoster + * Added support for CLF and fixed LOG_LEVEL_LOG. + * Also did CRLF->LF fix of my previous patch. + * + * Revision 1.10 2001/05/26 15:26:15 jongfoster + * ACL feature now provides more security by immediately dropping + * connections from untrusted hosts. + * + * Revision 1.9 2001/05/26 00:28:36 jongfoster + * Automatic reloading of config file. + * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32). + * Most of the global variables have been moved to a new + * struct configuration_spec, accessed through csp->config->globalname + * Most of the globals remaining are used by the Win32 GUI. + * + * Revision 1.8 2001/05/25 22:43:18 jongfoster + * Fixing minor memory leak and buffer overflow. + * + * Revision 1.7 2001/05/25 22:34:30 jongfoster + * Hard tabs->Spaces + * + * Revision 1.6 2001/05/23 00:13:58 joergs + * AmigaOS support fixed. + * + * Revision 1.5 2001/05/22 18:46:04 oes + * + * - Enabled filtering banners by size rather than URL + * by adding patterns that replace all standard banner + * sizes with the "Junkbuster" gif to the re_filterfile + * + * - Enabled filtering WebBugs by providing a pattern + * which kills all 1x1 images + * + * - Added support for PCRE_UNGREEDY behaviour to pcrs, + * which is selected by the (nonstandard and therefore + * capital) letter 'U' in the option string. + * It causes the quantifiers to be ungreedy by default. + * Appending a ? turns back to greedy (!). + * + * - Added a new interceptor ijb-send-banner, which + * sends back the "Junkbuster" gif. Without imagelist or + * MSIE detection support, or if tinygif = 1, or the + * URL isn't recognized as an imageurl, a lame HTML + * explanation is sent instead. + * + * - Added new feature, which permits blocking remote + * script redirects and firing back a local redirect + * to the browser. + * The feature is conditionally compiled, i.e. it + * can be disabled with --disable-fast-redirects, + * plus it must be activated by a "fast-redirects" + * line in the config file, has its own log level + * and of course wants to be displayed by show-proxy-args + * Note: Boy, all the #ifdefs in 1001 locations and + * all the fumbling with configure.in and acconfig.h + * were *way* more work than the feature itself :-( + * + * - Because a generic redirect template was needed for + * this, tinygif = 3 now uses the same. + * + * - Moved GIFs, and other static HTTP response templates + * to project.h + * + * - Some minor fixes + * + * - Removed some >400 CRs again (Jon, you really worked + * a lot! ;-) + * + * Revision 1.4 2001/05/21 19:34:01 jongfoster + * Made failure to bind() a fatal error. + * * Revision 1.3 2001/05/20 01:21:20 jongfoster * Version 2.9.4 checkin. * - Merged popupfile and cookiefile, and added control over PCRS @@ -68,15 +347,15 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $"; #include #include -#ifdef _WIN32 +#ifdef FEATURE_PTHREAD +#include +#endif /* def FEATURE_PTHREAD */ -# include -# include -# include -# include -# ifdef TOGGLE -# include -# endif /* def TOGGLE */ +#ifdef _WIN32 +# ifndef FEATURE_PTHREAD +# include +# include +# endif /* ndef FEATURE_PTHREAD */ # include "win32.h" # ifndef _WIN_CONSOLE @@ -85,9 +364,11 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $"; #else /* ifndef _WIN32 */ +# if !defined (__OS2__) # include -# include # include +# endif /* ndef __OS2__ */ +# include # include # include @@ -96,6 +377,15 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $"; # include /* declarations for threads and stuff. */ # endif +# if defined(__EMX__) || defined(__OS2__) +# include /* OS/2/EMX needs a little help with select */ +# endif +# ifdef __OS2__ +#define INCL_DOS +# include +#define bzero(B,N) memset(B,0x00,n) +# endif + # ifndef FD_ZERO # include # endif @@ -103,126 +393,63 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $"; #endif #include "project.h" +#include "list.h" #include "jcc.h" #include "filters.h" #include "loaders.h" -#include "showargs.h" #include "parsers.h" #include "killpopup.h" #include "miscutil.h" #include "errlog.h" #include "jbsockets.h" #include "gateway.h" +#include "actions.h" +#include "cgi.h" +#include "loadcfg.h" const char jcc_h_rcs[] = JCC_H_VERSION; const char project_h_rcs[] = PROJECT_H_VERSION; -const char DEFAULT_USER_AGENT[] ="User-Agent: Mozilla (X11; I; Linux 2.0.32 i586)"; - struct client_state clients[1]; struct file_list files[1]; -#ifdef STATISTICS +#ifdef FEATURE_STATISTICS int urls_read = 0; /* total nr of urls read inc rejected */ int urls_rejected = 0; /* total nr of urls rejected */ -#endif /* def STATISTICS */ +#endif /* def FEATURE_STATISTICS */ static void listen_loop(void); static void chat(struct client_state *csp); +#ifdef AMIGA +void serve(struct client_state *csp); +#else /* ifndef AMIGA */ static void serve(struct client_state *csp); +#endif /* def AMIGA */ + #ifdef __BEOS__ static int32 server_thread(void *data); #endif /* def __BEOS__ */ - -#define BODY "\n" - -static const char CFAIL[] = - "HTTP/1.0 503 Connect failed\n" - "Content-Type: text/html\n\n" - "\n" - "\n" - "Internet Junkbuster: Connect failed\n" - "\n" - BODY - "

" - BANNER - "

" - "TCP connection to '%s' failed: %s.\n
" - "\n" - "\n"; - -static const char CNXDOM[] = - "HTTP/1.0 404 Non-existent domain\n" - "Content-Type: text/html\n\n" - "\n" - "\n" - "Internet Junkbuster: Non-existent domain\n" - "\n" - BODY - "

" - BANNER - "

" - "No such domain: %s\n" - "\n" - "\n"; - -static const char CSUCCEED[] = - "HTTP/1.0 200 Connection established\n" - "Proxy-Agent: IJ/" VERSION "\n\n"; - -static const char CHEADER[] = - "HTTP/1.0 400 Invalid header received from browser\n\n"; - -static const char SHEADER[] = - "HTTP/1.0 502 Invalid header received from server\n\n"; - -#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) - -/* - * Hint: You can encode your own GIFs like that: - * perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o,", unpack("C", $c)); }' - */ - -static const char BLANKGIF[] = - "HTTP/1.0 200 OK\r\n" - "Pragma: no-cache\r\n" - "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n" - "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\r\n" - "Content-type: image/gif\r\n\r\n" - "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000" - "\000!\371\004\001\000\000\000\000,\000\000\000\000\001" - "\000\001\000\000\002\002D\001\000;"; - -static const char JBGIF[] = - "HTTP/1.0 200 OK\r\n" - "Pragma: no-cache\r\n" - "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n" - "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\r\n" - "Content-type: image/gif\r\n\r\n" - "GIF89aD\000\013\000\360\000\000\000\000\000\377\377\377!" - "\371\004\001\000\000\001\000,\000\000\000\000D\000\013\000" - "\000\002a\214\217\251\313\355\277\000\200G&K\025\316hC\037" - "\200\234\230Y\2309\235S\230\266\206\372J\253<\3131\253\271" - "\270\215\342\254\013\203\371\202\264\334P\207\332\020o\266" - "N\215I\332=\211\312\3513\266:\026AK)\364\370\365aobr\305" - "\372\003S\275\274k2\354\254z\347?\335\274x\306^9\374\276" - "\037Q\000\000;"; - -static const char FWGIF[] = - "HTTP/1.0 302 Blocked Advert\r\n" - "Pragma: no-cache\r\n" - "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n" - "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\r\n" - "Location: "; - -#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */ - #ifdef _WIN32 #define sleep(N) Sleep(((N) * 1000)) #endif +#ifdef __OS2__ +#define sleep(N) DosSleep(((N) * 100)) +#endif + + +/* The vanilla wafer. */ +static const char VANILLA_WAFER[] = + "NOTICE=TO_WHOM_IT_MAY_CONCERN_" + "Do_not_send_me_any_copyrighted_information_other_than_the_" + "document_that_I_am_requesting_or_any_of_its_necessary_components._" + "In_particular_do_not_send_me_any_cookies_that_" + "are_subject_to_a_claim_of_copyright_by_anybody._" + "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_" + "(copyright_or_otherwise)_applying_to_any_cookie._"; + /********************************************************************* * @@ -230,7 +457,7 @@ static const char FWGIF[] = * * Description : Once a connection to the client has been accepted, * this function is called (via serve()) to handle the - * main business of the communication. When this + * main business of the communication. When this * function returns, the caller must close the client * socket handle. * @@ -247,38 +474,46 @@ static const char FWGIF[] = *********************************************************************/ static void chat(struct client_state *csp) { -/* This next line is a little ugly, but it simplifies the if statement below. */ -/* Basically if TOGGLE, then we want the if to test "csp->toggled_on", else we don't */ -#ifdef TOGGLE -# define IS_TOGGLED_ON csp->toggled_on && -#else /* ifndef TOGGLE */ -# define IS_TOGGLED_ON -#endif /* ndef TOGGLE */ - -/* This next line is a little ugly, but it simplifies the if statement below. */ -/* Basically if TRUST_FILES, then we want the if to call "trust_url", else we don't */ -#ifdef TRUST_FILES -# define IS_TRUSTED_URL (p = trust_url(http, csp)) || -#else /* ifndef TRUST_FILES */ -# define IS_TRUSTED_URL -#endif /* ndef TRUST_FILES */ - - - char buf[BUFSIZ], *hdr, *p, *req; - char *err = NULL; - char *eno; +/* + * This next lines are a little ugly, but they simplifies the if statements + * below. Basically if TOGGLE, then we want the if to test if the + * CSP_FLAG_TOGGLED_ON flag ist set, else we don't. And if FEATURE_FORCE_LOAD, + * then we want the if to test for CSP_FLAG_FORCED , else we don't + */ +#ifdef FEATURE_TOGGLE +# define IS_TOGGLED_ON_AND (csp->flags & CSP_FLAG_TOGGLED_ON) && +#else /* ifndef FEATURE_TOGGLE */ +# define IS_TOGGLED_ON_AND +#endif /* ndef FEATURE_TOGGLE */ +#ifdef FEATURE_FORCE_LOAD +# define IS_NOT_FORCED_AND !(csp->flags & CSP_FLAG_FORCED) && +#else /* ifndef FEATURE_FORCE_LOAD */ +# define IS_NOT_FORCED_AND +#endif /* def FEATURE_FORCE_LOAD */ + +#define IS_ENABLED_AND IS_TOGGLED_ON_AND IS_NOT_FORCED_AND + + char buf[BUFFER_SIZE]; + char *hdr, *p, *req; fd_set rfds; - int n, maxfd, server_body, ms_iis5_hack = 0; - const struct gateway *gw; - struct http_request *http; -#ifdef KILLPOPUPS - int block_popups; /* bool, 1==will block popups */ - int block_popups_now = 0; /* bool, 1==currently blocking popups */ -#endif /* def KILLPOPUPS */ -#ifdef PCRS - int pcrs_filter; /* bool, 1==will filter through pcrs */ - int filtering = 0; /* bool, 1==currently filtering through pcrs */ -#endif /* def PCRS */ + int n, maxfd, server_body; + int ms_iis5_hack = 0; + int byte_count = 0; + const struct forward_spec * fwd; + struct http_request *http; +#ifdef FEATURE_KILL_POPUPS + int block_popups; /* bool, 1==will block popups */ + int block_popups_now = 0; /* bool, 1==currently blocking popups */ +#endif /* def FEATURE_KILL_POPUPS */ + + int pcrs_filter; /* bool, 1==will filter through pcrs */ + int gif_deanimate; /* bool, 1==will deanimate gifs */ + + /* Function that does the content filtering for the current request */ + char *(*content_filter)() = NULL; + + /* Skeleton for HTTP response, if we should intercept the request */ + struct http_response *rsp; http = csp->http; @@ -306,24 +541,21 @@ static void chat(struct client_state *csp) { continue; /* more to come! */ } - -#ifdef FORCE_LOAD + +#ifdef FEATURE_FORCE_LOAD /* If this request contains the FORCE_PREFIX, - * better get rid of it now and set the force flag --oes + * better get rid of it now and set the force flag --oes */ - if(strstr(req, FORCE_PREFIX)) + if (strstr(req, FORCE_PREFIX)) { - strclean(req, FORCE_PREFIX); - log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", req); - csp->force = 1; - } - else - { - csp->force = 0; - } -#endif /* def FORCE_LOAD */ - + strclean(req, FORCE_PREFIX); + log_error(LOG_LEVEL_FORCE, "Enforcing request \"%s\".\n", req); + csp->flags |= CSP_FLAG_FORCED; + } + +#endif /* def FEATURE_FORCE_LOAD */ + parse_http_request(req, http, csp); freez(req); break; @@ -333,87 +565,154 @@ static void chat(struct client_state *csp) { strcpy(buf, CHEADER); write_socket(csp->cfd, buf, strlen(buf)); + + log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 400 0", csp->ip_addr_str); + return; } /* decide how to route the HTTP request */ - if ((gw = forward_url(http, csp)) == NULL) + if ((fwd = forward_url(http, csp)) == NULL) { log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!? This can't happen!"); - /* Never get here - LOG_LEVEL_FATAL causes program exit */ + /* Never get here - LOG_LEVEL_FATAL causes program exit */ } /* build the http request to send to the server * we have to do one of the following: * * create = use the original HTTP request to create a new - * HTTP request that has only the path component - * without the http://domainspec - * pass = pass the original HTTP request unchanged + * HTTP request that has either the path component + * without the http://domainspec (w/path) or the + * full orininal URL (w/url) + * Note that the path and/or the HTTP version may + * have been altered by now. * - * drop = drop the HTTP request + * connect = Open a socket to the host:port of the server + * and short-circuit server and client socket. + * + * pass = Pass the request unchanged if forwarding a CONNECT + * request to a parent proxy. Note that we'll be sending + * the CFAIL message ourselves if connecting to the parent + * fails, but we won't send a CSUCCEED message if it works, + * since that would result in a double message (ours and the + * parent's). After sending the request to the parent, we simply + * tunnel. * * here's the matrix: * SSL * 0 1 * +--------+--------+ * | | | - * 0 | create | drop | - * | | | + * 0 | create | connect| + * | w/path | | * Forwarding +--------+--------+ * | | | - * 1 | pass | pass | - * | | | + * 1 | create | pass | + * | w/url | | * +--------+--------+ * */ - if (gw->forward_host) + /* + * Determine the actions for this URL + */ +#ifdef FEATURE_TOGGLE + if (!(csp->flags & CSP_FLAG_TOGGLED_ON)) { - /* if forwarding, just pass the request as is */ - enlist(csp->headers, http->cmd); + /* Most compatible set of actions (i.e. none) */ + init_current_action(csp->action); } else +#endif /* ndef FEATURE_TOGGLE */ + { + url_actions(http, csp); + } + + + /* + * Check if a CONNECT request is allowable: + * In the absence of a +limit-connect action, allow only port 443. + * If there is an action, allow whatever matches the specificaton. + */ + if(http->ssl) + { + if( ( !(csp->action->flags & ACTION_LIMIT_CONNECT) && csp->http->port != 443) + || (csp->action->flags & ACTION_LIMIT_CONNECT + && !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) ) + { + strcpy(buf, CFORBIDDEN); + write_socket(csp->cfd, buf, strlen(buf)); + + log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str); + + return; + } + } + + + /* + * Downgrade http version from 1.1 to 1.0 if +downgrade + * action applies + */ + if (!strcmpic(http->ver, "HTTP/1.1") && csp->action->flags & ACTION_DOWNGRADE) { - if (http->ssl == 0) + freez(http->ver); + http->ver = strdup("HTTP/1.0"); + } + + /* + * (Re)build the HTTP request for non-SSL requests. + * If forwarding, use the whole URL, else, use only the path. + */ + if (http->ssl == 0) + { + freez(http->cmd); + + http->cmd = strsav(http->cmd, http->gpc); + http->cmd = strsav(http->cmd, " "); + + if (fwd->forward_host) { - /* otherwise elide the host information from the url */ - p = NULL; - p = strsav(p, http->gpc); - p = strsav(p, " "); - p = strsav(p, http->path); - p = strsav(p, " "); - p = strsav(p, http->ver); - enlist(csp->headers, p); - freez(p); + http->cmd = strsav(http->cmd, http->url); } + else + { + http->cmd = strsav(http->cmd, http->path); + } + + http->cmd = strsav(http->cmd, " "); + http->cmd = strsav(http->cmd, http->ver); + } - - /* decide what we're to do with cookies */ - -#ifdef TOGGLE - if (!csp->toggled_on) - { - /* Most compatible set of permissions */ - csp->permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS; - } - else - { - csp->permissions = url_permissions(http, csp); - } -#else /* ifndef TOGGLE */ - csp->permissions = url_permissions(http, csp); -#endif /* ndef TOGGLE */ - -#ifdef KILLPOPUPS - block_popups = ((csp->permissions & PERMIT_POPUPS) == 0); -#endif /* def KILLPOPUPS */ -#ifdef PCRS - pcrs_filter = (csp->rlist != NULL) && /* There are expressions to be used */ - ((csp->permissions & PERMIT_RE_FILTER) != 0); -#endif /* def PCRS */ - + enlist(csp->headers, http->cmd); + + +#ifdef FEATURE_COOKIE_JAR + /* + * If we're logging cookies in a cookie jar, and the user has not + * supplied any wafers, and the user has not told us to suppress the + * vanilla wafer, then send the vanilla wafer. + */ + if ((csp->config->jarfile != NULL) + && list_is_empty(csp->action->multi[ACTION_MULTI_WAFER]) + && ((csp->action->flags & ACTION_VANILLA_WAFER) != 0)) + { + enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER); + } +#endif /* def FEATURE_COOKIE_JAR */ + + +#ifdef FEATURE_KILL_POPUPS + block_popups = ((csp->action->flags & ACTION_NO_POPUPS) != 0); +#endif /* def FEATURE_KILL_POPUPS */ + + pcrs_filter = (csp->rlist != NULL) && /* There are expressions to be used */ + ((csp->action->flags & ACTION_FILTER) != 0); + + gif_deanimate = ((csp->action->flags & ACTION_DEANIMATE) != 0); /* grab the rest of the client's headers */ @@ -437,79 +736,63 @@ static void chat(struct client_state *csp) freez(p); } - /* filter it as required */ - - hdr = sed(client_patterns, add_client_headers, csp); - - destroy_list(csp->headers); + /* We have a request. */ + /* + * Now, check to see if we need to intercept it, i.e. + * If + */ - /* - * by haroon - most of credit to srt19170 - * if toggled_on flag is true then IJB is enabled, do the usual - * otherwise avoid crunching - */ + if ( + /* a CGI call was detected and answered */ + (NULL != (rsp = dispatch_cgi(csp))) - /* Check the request against all rules, unless - * we're disabled or in force mode. - */ - - if (IS_TOGGLED_ON -#ifdef FORCE_LOAD - (!csp->force) && -#endif /* def FORCE_LOAD */ - ( (p = intercept_url(http, csp)) || - IS_TRUSTED_URL - (p = block_url(http, csp)) )) - { -#ifdef STATISTICS - csp->rejected = 1; -#endif /* def STATISTICS */ + /* or we are enabled and... */ + || (IS_ENABLED_AND ( - log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path); + /* ..the request was blocked */ + ( NULL != (rsp = block_url(csp))) -#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) - /* now use block_imageurl */ - if ( (tinygif > 0) && block_imageurl(http, csp) ) - { - /* Send "blocked" image */ - log_error(LOG_LEVEL_GPC, "%s%s image crunch!", - http->hostport, http->path); + /* ..or untrusted */ +#ifdef FEATURE_TRUST + || ( NULL != (rsp = trust_url(csp))) +#endif /* def FEATURE_TRUST */ - if (tinygif == 1) - { - write_socket(csp->cfd, BLANKGIF, sizeof(BLANKGIF)-1); - } - else if ((tinygif == 3) && (tinygifurl)) - { - write_socket(csp->cfd, FWGIF, sizeof(FWGIF)-1); - write_socket(csp->cfd, tinygifurl, strlen(tinygifurl)); - } - else - { - write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1); - } - } - else -#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */ + /* ..or a fast redirect kicked in */ +#ifdef FEATURE_FAST_REDIRECTS + || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) && + (NULL != (rsp = redirect_url(csp)))) +#endif /* def FEATURE_FAST_REDIRECTS */ + )) + ) + { + /* Write the answer to the client */ + if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length) + || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length)) { - /* Send HTML "blocked" message */ - write_socket(csp->cfd, p, strlen(p)); + log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); } - log_error(LOG_LEVEL_LOG, "%s", p); +#ifdef FEATURE_STATISTICS + /* Count as a rejected request */ + csp->flags |= CSP_FLAG_REJECTED; +#endif /* def FEATURE_STATISTICS */ - freez(p); - freez(hdr); + /* Log (FIXME: All intercept reasons apprear as "crunch" with Status 200) */ + log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->cmd); + + /* Clean up and return */ + free_http_response(rsp); return; } log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path); - if (gw->forward_host) + if (fwd->forward_host) { log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s", - gw->forward_host, gw->forward_port, http->hostport); + fwd->forward_host, fwd->forward_port, http->hostport); } else { @@ -518,7 +801,7 @@ static void chat(struct client_state *csp) /* here we connect to the server, gateway, or the forwarder */ - csp->sfd = (gw->conn)(gw, http, csp); + csp->sfd = forwarded_connect(fwd, http, csp); if (csp->sfd < 0) { @@ -527,28 +810,39 @@ static void chat(struct client_state *csp) if (errno == EINVAL) { - err = zalloc(strlen(CNXDOM) + strlen(http->host)); - sprintf(err, CNXDOM, http->host); + rsp = error_response(csp, "no-such-domain", errno); + + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 404 0", + csp->ip_addr_str, http->cmd); } else { - eno = safe_strerror(errno); - err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno)); - sprintf(err, CFAIL, http->hostport, eno); - } + rsp = error_response(csp, "connect-failed", errno); - write_socket(csp->cfd, err, strlen(err)); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", + csp->ip_addr_str, http->cmd); + } - log_error(LOG_LEVEL_LOG, err); + /* Write the answer to the client */ + if(rsp) + { + if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length) + || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length)) + { + log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); + } + } - freez(err); - freez(hdr); + free_http_response(rsp); return; } log_error(LOG_LEVEL_CONNECT, "OK"); - if (gw->forward_host || (http->ssl == 0)) + hdr = sed(client_patterns, add_client_headers, csp); + list_remove_all(csp->headers); + + if (fwd->forward_host || (http->ssl == 0)) { /* write the client's (modified) header to the server * (along with anything else that may be in the buffer) @@ -562,12 +856,21 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E", http->hostport); - eno = safe_strerror(errno); - err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno)); - sprintf(err, CFAIL, http->hostport, eno); - write_socket(csp->cfd, err, strlen(err)); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", + csp->ip_addr_str, http->cmd); + + rsp = error_response(csp, "connect-failed", errno); + + if(rsp) + { + if ((write_socket(csp->cfd, rsp->head, n) != n) + || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length)) + { + log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); + } + } - freez(err); + free_http_response(rsp); freez(hdr); return; } @@ -579,6 +882,9 @@ static void chat(struct client_state *csp) * so just send the "connect succeeded" message to the * client, flush the rest, and get out of the way. */ + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 2\n", + csp->ip_addr_str, http->cmd); + if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0) { freez(hdr); @@ -621,7 +927,10 @@ static void chat(struct client_state *csp) { n = read_socket(csp->cfd, buf, sizeof(buf)); - if (n <= 0) break; /* "game over, man" */ + if (n <= 0) + { + break; /* "game over, man" */ + } if (write_socket(csp->sfd, buf, n) != n) { @@ -634,7 +943,7 @@ static void chat(struct client_state *csp) /* * The server wants to talk. It could be the header or the body. * If `hdr' is null, then it's the header otherwise it's the body. - * FIXME: Does `hdr' really mean `host'? + * FIXME: Does `hdr' really mean `host'? No. */ @@ -647,10 +956,21 @@ static void chat(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host); - eno = safe_strerror(errno); - sprintf(buf, CFAIL, http->hostport, eno); - freez(eno); - write_socket(csp->cfd, buf, strlen(buf)); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", + csp->ip_addr_str, http->cmd); + + rsp = error_response(csp, "connect-failed", errno); + + if(rsp) + { + if ((write_socket(csp->cfd, rsp->head, rsp->head_length) != rsp->head_length) + || (write_socket(csp->cfd, rsp->body, rsp->content_length) != rsp->content_length)) + { + log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); + } + } + + free_http_response(rsp); return; } @@ -659,13 +979,13 @@ static void chat(struct client_state *csp) */ buf[n] = '\0'; -#ifdef KILLPOPUPS +#ifdef FEATURE_KILL_POPUPS /* Filter the popups on this read. */ if (block_popups_now) { - filter_popups(buf, n); + filter_popups(buf, csp); } -#endif /* def KILLPOPUPS */ +#endif /* def FEATURE_KILL_POPUPS */ /* Normally, this would indicate that we've read * as much as the server has sent us and we can @@ -687,19 +1007,49 @@ static void chat(struct client_state *csp) */ if (n == 0) { - /* This hack must only be enforced for headers. */ + if (server_body || http->ssl) { -#ifdef PCRS - if (filtering) + /* + * If we have been buffering up the document, + * now is the time to apply content modification + * and send the result to the client. + */ + if (content_filter) { - re_process_buffer(csp); + /* + * If the content filter fails, use the original + * buffer and length. + * (see p != NULL ? p : csp->iob->cur below) + */ + if (NULL == (p = (*content_filter)(csp))) + { + csp->content_length = csp->iob->eod - csp->iob->cur; + } + + hdr = sed(server_patterns, add_server_headers, csp); + n = strlen(hdr); + + if ((write_socket(csp->cfd, hdr, n) != n) + || (write_socket(csp->cfd, p != NULL ? p : csp->iob->cur, csp->content_length) != (int)csp->content_length)) + { + log_error(LOG_LEVEL_ERROR, "write modified content to client failed: %E"); + return; + } + + freez(hdr); + if (NULL != p) { + freez(p); + } } -#endif /* def PCRS */ + break; /* "game over, man" */ } - /* Let's pretend the server just sent us a blank line. */ + /* + * This is NOT the body, so + * Let's pretend the server just sent us a blank line. + */ n = sprintf(buf, "\r\n"); /* @@ -712,26 +1062,55 @@ static void chat(struct client_state *csp) /* * If this is an SSL connection or we're in the body - * of the server document, just write it to the client. + * of the server document, just write it to the client, + * unless we need to buffer the body for later content-filtering */ if (server_body || http->ssl) { -#ifdef PCRS - if (filtering) + if (content_filter) { - add_to_iob(csp, buf, n); /* Buffer the body for filtering */ + add_to_iob(csp, buf, n); + + /* + * If the buffer limit will be reached on the next read, + * switch to non-filtering mode, i.e. make & write the + * header, flush the socket and get out of the way. + */ + if (csp->iob->eod - csp->iob->buf + BUFFER_SIZE > csp->config->buffer_limit) + { + log_error(LOG_LEVEL_ERROR, "Buffer size limit reached! Flushing and stepping back."); + + hdr = sed(server_patterns, add_server_headers, csp); + n = strlen(hdr); + byte_count += n; + + if (((write_socket(csp->cfd, hdr, n) != n) + || (n = flush_socket(csp->cfd, csp) < 0))) + { + log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E"); + + freez(hdr); + return; + } + + freez(hdr); + byte_count += n; + + content_filter = NULL; + server_body = 1; + + } } else -#endif /* def PCRS */ { - /* just write */ if (write_socket(csp->cfd, buf, n) != n) { log_error(LOG_LEVEL_ERROR, "write to client failed: %E"); return; } } + byte_count += n; continue; } else @@ -797,42 +1176,48 @@ static void chat(struct client_state *csp) * the client (along with anything else that * may be in the buffer) */ - -#ifdef KILLPOPUPS - /* Start blocking popups if appropriate. */ - - if (csp->is_text && /* It's a text / * MIME-Type */ - !http->ssl && /* We talk plaintext */ - block_popups) - { - block_popups_now = 1; - } - -#endif /* def KILLPOPUPS */ - -#ifdef PCRS - /* Start re_filtering this if appropriate. */ - - if (csp->is_text && /* It's a text / * MIME-Type */ - !http->ssl && /* We talk plaintext */ - pcrs_filter) /* Policy allows */ + +#ifdef FEATURE_KILL_POPUPS + /* Start blocking popups if appropriate. */ + + if ((csp->content_type & CT_TEXT) && /* It's a text / * MIME-Type */ + !http->ssl && /* We talk plaintext */ + block_popups) /* Policy allows */ { - filtering = 1; + block_popups_now = 1; + /* + * Filter the part of the body that came in the same read + * as the last headers: + */ + filter_popups(csp->iob->cur, csp); } -/* This next line is a little ugly, but it simplifies the if statement below. */ -/* Basically if using PCRS, we want the OR condition to require "!filtering" */ -#define NOT_FILTERING_AND !filtering && +#endif /* def FEATURE_KILL_POPUPS */ -#else /* not def PCRS */ + /* Buffer and pcrs filter this if appropriate. */ -#define NOT_FILTERING_AND + if ((csp->content_type & CT_TEXT) && /* It's a text / * MIME-Type */ + !http->ssl && /* We talk plaintext */ + pcrs_filter) /* Policy allows */ + { + content_filter = pcrs_filter_response; + } -#endif /* def PCRS */ + /* Buffer and gif_deanimate this if appropriate. */ + if ((csp->content_type & CT_GIF) && /* It's a image/gif MIME-Type */ + !http->ssl && /* We talk plaintext */ + gif_deanimate) /* Policy allows */ + { + content_filter = gif_deanimate_response; + } - if ((write_socket(csp->cfd, hdr, n) != n) - || (NOT_FILTERING_AND (flush_socket(csp->cfd, csp) < 0))) + + /* + * Only write if we're not buffering for content modification + */ + if (!content_filter && ((write_socket(csp->cfd, hdr, n) != n) + || (n = flush_socket(csp->cfd, csp) < 0))) { log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E"); @@ -844,6 +1229,8 @@ static void chat(struct client_state *csp) return; } + if(!content_filter) byte_count += n; + /* we're finished with the server's header */ freez(hdr); @@ -865,7 +1252,8 @@ static void chat(struct client_state *csp) return; /* huh? we should never get here */ } - + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d", + csp->ip_addr_str, http->cmd, byte_count); } @@ -882,7 +1270,11 @@ static void chat(struct client_state *csp) * Returns : N/A * *********************************************************************/ +#ifdef AMIGA +void serve(struct client_state *csp) +#else /* ifndef AMIGA */ static void serve(struct client_state *csp) +#endif /* def AMIGA */ { chat(csp); close_socket(csp->cfd); @@ -892,13 +1284,12 @@ static void serve(struct client_state *csp) close_socket(csp->sfd); } - csp->active = 0; + csp->flags &= ~CSP_FLAG_ACTIVE; } #ifdef __BEOS__ - /********************************************************************* * * Function : server_thread @@ -917,7 +1308,6 @@ static int32 server_thread(void *data) return 0; } - #endif @@ -940,18 +1330,20 @@ static int32 server_thread(void *data) * any load fails, and can't bind port. * * Else main never returns, the process must be signaled - * to terminate execution. Or, on Windows, use the + * to terminate execution. Or, on Windows, use the * "File", "Exit" menu option. * *********************************************************************/ #ifdef __MINGW32__ -int _main(int argc, const char *argv[]) +int real_main(int argc, const char *argv[]) #else int main(int argc, const char *argv[]) #endif { configfile = -#ifndef _WIN32 +#ifdef AMIGA + "AmiTCP:db/junkbuster/config" +#elif !defined(_WIN32) "config" #else "junkbstr.txt" @@ -983,31 +1375,18 @@ int main(int argc, const char *argv[]) configfile = argv[1]; } - remove_all_loaders(); - memset( proxy_args, 0, sizeof( proxy_args ) ); files->next = NULL; - load_config( 0 ); - - /* - * Since load_config acts as a signal handler too, it returns - * its status in configret. Check it for an error in loading. - */ - if ( 0 != configret ) - { - /* load config failed! Exit with error. */ - return( 1 ); - } - -#ifdef _WIN32 +#ifdef AMIGA + InitAmiga(); +#elif defined(_WIN32) InitWin32(); #endif -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__OS2__) signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); - signal(SIGHUP, load_config); #else /* ifdef _WIN32 */ # ifdef _WIN_CONSOLE @@ -1020,6 +1399,9 @@ int main(int argc, const char *argv[]) #endif /* def _WIN32 */ + /* Initialize the CGI subsystem */ + cgi_init_error_messages(); + listen_loop(); /* NOTREACHED */ @@ -1043,47 +1425,52 @@ static void listen_loop(void) { struct client_state *csp = NULL; int bfd; + struct configuration_spec * config; + + config = load_config(); log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)", - haddr ? haddr : "INADDR_ANY", hport); + config->haddr ? config->haddr : "INADDR_ANY", config->hport); - bfd = bind_port(haddr, hport); - config_changed = 0; + bfd = bind_port(config->haddr, config->hport); if (bfd < 0) { log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E " "- There may be another junkbuster or some other " - "proxy running on port %d", - (NULL != haddr) ? haddr : "INADDR_ANY", hport, hport - ); + "proxy running on port %d", + (NULL != config->haddr) ? config->haddr : "INADDR_ANY", + config->hport, config->hport + ); /* shouldn't get here */ return; } + config->need_bind = 0; + while (FOREVER) { -#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) +#if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) while (waitpid(-1, NULL, WNOHANG) > 0) { /* zombie children */ } -#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ +#endif /* !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ sweep(); - if ( NULL == (csp = (struct client_state *) malloc(sizeof(*csp))) ) + if ( NULL == (csp = (struct client_state *) zalloc(sizeof(*csp))) ) { - log_error(LOG_LEVEL_ERROR, "malloc(%d) for csp failed: %E", sizeof(*csp)); + log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp failed: %E", sizeof(*csp)); continue; } - memset(csp, '\0', sizeof(*csp)); - - csp->active = 1; + csp->flags |= CSP_FLAG_ACTIVE; csp->sfd = -1; - if ( config_changed ) + csp->config = config = load_config(); + + if ( config->need_bind ) { /* * Since we were listening to the "old port", we will not see @@ -1097,13 +1484,26 @@ static void listen_loop(void) * request. This should not be a so common of an operation * that this will hurt people's feelings. */ + close_socket(bfd); log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)", - haddr ? haddr : "INADDR_ANY", hport); - bfd = bind_port(haddr, hport); + config->haddr ? config->haddr : "INADDR_ANY", config->hport); + bfd = bind_port(config->haddr, config->hport); - config_changed = 0; + if (bfd < 0) + { + log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E " + "- There may be another junkbuster or some other " + "proxy running on port %d", + (NULL != config->haddr) ? config->haddr : "INADDR_ANY", + config->hport, config->hport + ); + /* shouldn't get here */ + return; + } + + config->need_bind = 0; } log_error(LOG_LEVEL_CONNECT, "accept connection ... "); @@ -1115,9 +1515,10 @@ static void listen_loop(void) #ifdef AMIGA if(!childs) { - exit(1); + exit(1); } #endif + freez(csp); continue; } else @@ -1125,28 +1526,55 @@ static void listen_loop(void) log_error(LOG_LEVEL_CONNECT, "OK"); } -#if defined(TOGGLE) - /* by haroon - most of credit to srt19170 */ - csp->toggled_on = g_bToggleIJB; -#endif - - /* add it to the list of clients */ - csp->next = clients->next; - clients->next = csp; +#ifdef FEATURE_TOGGLE + if (g_bToggleIJB) + { + csp->flags |= CSP_FLAG_TOGGLED_ON; + } +#endif /* def FEATURE_TOGGLE */ if (run_loader(csp)) { - log_error(LOG_LEVEL_FATAL, "a loader failed - must exit"); + log_error(LOG_LEVEL_FATAL, "a loader failed - must exit"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } - if (multi_threaded) +#ifdef FEATURE_ACL + if (block_acl(NULL,csp)) + { + log_error(LOG_LEVEL_CONNECT, "Connection dropped due to ACL"); + close_socket(csp->cfd); + freez(csp); + continue; + } +#endif /* def FEATURE_ACL */ + + /* add it to the list of clients */ + csp->next = clients->next; + clients->next = csp; + + if (config->multi_threaded) { int child_id; /* this is a switch () statment in the C preprocessor - ugh */ #undef SELECTED_ONE_OPTION +/* Use Pthreads in preference to native code */ +#if defined(FEATURE_PTHREAD) && !defined(SELECTED_ONE_OPTION) +#define SELECTED_ONE_OPTION + { + pthread_t the_thread; + pthread_attr_t attrs; + + pthread_attr_init(&attrs); + pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); + child_id = (pthread_create(&the_thread, &attrs, + (void*)serve, csp) ? -1 : 0); + pthread_attr_destroy(&attrs); + } +#endif + #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION child_id = _beginthread( @@ -1155,6 +1583,15 @@ static void listen_loop(void) csp); #endif +#if defined(__OS2__) && !defined(SELECTED_ONE_OPTION) +#define SELECTED_ONE_OPTION + child_id = _beginthread( + serve, + NULL, + 64 * 1024, + csp); +#endif + #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION { @@ -1180,7 +1617,7 @@ static void listen_loop(void) NP_Output, Output(), NP_CloseOutput, FALSE, NP_Name, (ULONG)"junkbuster child", - NP_StackSize, 20*1024, + NP_StackSize, 200*1024, TAG_DONE))) { childs++; @@ -1192,27 +1629,7 @@ static void listen_loop(void) #if !defined(SELECTED_ONE_OPTION) child_id = fork(); -#endif - -#undef SELECTED_ONE_OPTION -/* end of cpp switch () */ - - if (child_id < 0) /* failed */ - { - char buf[BUFSIZ]; - log_error(LOG_LEVEL_ERROR, "can't fork: %E"); - - sprintf(buf , "JunkBuster: can't fork: errno = %d", errno); - - write_socket(csp->cfd, buf, strlen(buf)); - close_socket(csp->cfd); - csp->active = 0; - sleep(5); - continue; - } - -#if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) /* This block is only needed when using fork(). * When using threads, the server thread was * created and run by the call to _beginthread(). @@ -1223,7 +1640,7 @@ static void listen_loop(void) _exit(0); } - else /* parent */ + else if (child_id > 0) /* parent */ { /* in a fork()'d environment, the parent's * copy of the client socket and the CSP @@ -1234,9 +1651,27 @@ static void listen_loop(void) wait( NULL ); #endif /* !defined(_WIN32) && defined(__CYGWIN__) */ close_socket(csp->cfd); - csp->active = 0; + csp->flags &= ~CSP_FLAG_ACTIVE; + } +#endif + +#undef SELECTED_ONE_OPTION +/* end of cpp switch () */ + + if (child_id < 0) /* failed */ + { + char buf[BUFFER_SIZE]; + + log_error(LOG_LEVEL_ERROR, "can't fork: %E"); + + sprintf(buf , "JunkBuster: can't fork: errno = %d", errno); + + write_socket(csp->cfd, buf, strlen(buf)); + close_socket(csp->cfd); + csp->flags &= ~CSP_FLAG_ACTIVE; + sleep(5); + continue; } -#endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ } else {