1 const char filters_rcs[] = "$Id: filters.c,v 1.9 2001/05/27 22:17:04 oes Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/filters.c,v $
6 * Purpose : Declares functions to parse/crunch headers and pages.
7 * Functions declared include:
8 * `acl_addr', `add_stats', `block_acl', `block_imageurl',
9 * `block_url', `url_permissions', `domaincmp', `dsplit',
10 * `filter_popups', `forward_url', 'redirect_url',
11 * `ij_untrusted_url', `intercept_url', `re_process_buffer',
12 * `show_proxy_args', 'ijb_send_banner', and `trust_url'
14 * Copyright : Written by and Copyright (C) 2001 the SourceForge
15 * IJBSWA team. http://ijbswa.sourceforge.net
17 * Based on the Internet Junkbuster originally written
18 * by and Copyright (C) 1997 Anonymous Coders and
19 * Junkbusters Corporation. http://www.junkbusters.com
21 * This program is free software; you can redistribute it
22 * and/or modify it under the terms of the GNU General
23 * Public License as published by the Free Software
24 * Foundation; either version 2 of the License, or (at
25 * your option) any later version.
27 * This program is distributed in the hope that it will
28 * be useful, but WITHOUT ANY WARRANTY; without even the
29 * implied warranty of MERCHANTABILITY or FITNESS FOR A
30 * PARTICULAR PURPOSE. See the GNU General Public
31 * License for more details.
33 * The GNU General Public License should be included with
34 * this file. If not, you can view it at
35 * http://www.gnu.org/copyleft/gpl.html
36 * or write to the Free Software Foundation, Inc., 59
37 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 * Revision 1.9 2001/05/27 22:17:04 oes
43 * - re_process_buffer no longer writes the modified buffer
44 * to the client, which was very ugly. It now returns the
45 * buffer, which it is then written by chat.
47 * - content_length now adjusts the Content-Length: header
48 * for modified documents rather than crunch()ing it.
49 * (Length info in csp->content_length, which is 0 for
50 * unmodified documents)
52 * - For this to work, sed() is called twice when filtering.
54 * Revision 1.8 2001/05/26 17:13:28 jongfoster
55 * Filled in a function comment.
57 * Revision 1.7 2001/05/26 15:26:15 jongfoster
58 * ACL feature now provides more security by immediately dropping
59 * connections from untrusted hosts.
61 * Revision 1.6 2001/05/26 00:28:36 jongfoster
62 * Automatic reloading of config file.
63 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
64 * Most of the global variables have been moved to a new
65 * struct configuration_spec, accessed through csp->config->globalname
66 * Most of the globals remaining are used by the Win32 GUI.
68 * Revision 1.5 2001/05/25 22:34:30 jongfoster
71 * Revision 1.4 2001/05/22 18:46:04 oes
73 * - Enabled filtering banners by size rather than URL
74 * by adding patterns that replace all standard banner
75 * sizes with the "Junkbuster" gif to the re_filterfile
77 * - Enabled filtering WebBugs by providing a pattern
78 * which kills all 1x1 images
80 * - Added support for PCRE_UNGREEDY behaviour to pcrs,
81 * which is selected by the (nonstandard and therefore
82 * capital) letter 'U' in the option string.
83 * It causes the quantifiers to be ungreedy by default.
84 * Appending a ? turns back to greedy (!).
86 * - Added a new interceptor ijb-send-banner, which
87 * sends back the "Junkbuster" gif. Without imagelist or
88 * MSIE detection support, or if tinygif = 1, or the
89 * URL isn't recognized as an imageurl, a lame HTML
90 * explanation is sent instead.
92 * - Added new feature, which permits blocking remote
93 * script redirects and firing back a local redirect
95 * The feature is conditionally compiled, i.e. it
96 * can be disabled with --disable-fast-redirects,
97 * plus it must be activated by a "fast-redirects"
98 * line in the config file, has its own log level
99 * and of course wants to be displayed by show-proxy-args
100 * Note: Boy, all the #ifdefs in 1001 locations and
101 * all the fumbling with configure.in and acconfig.h
102 * were *way* more work than the feature itself :-(
104 * - Because a generic redirect template was needed for
105 * this, tinygif = 3 now uses the same.
107 * - Moved GIFs, and other static HTTP response templates
112 * - Removed some >400 CRs again (Jon, you really worked
115 * Revision 1.3 2001/05/20 16:44:47 jongfoster
116 * Removing last hardcoded JunkBusters.com URLs.
118 * Revision 1.2 2001/05/20 01:21:20 jongfoster
119 * Version 2.9.4 checkin.
120 * - Merged popupfile and cookiefile, and added control over PCRS
121 * filtering, in new "permissionsfile".
122 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
123 * file error you now get a message box (in the Win32 GUI) rather
124 * than the program exiting with no explanation.
125 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
127 * - Removed tabs from "config"
128 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
129 * - Bumped up version number.
131 * Revision 1.1.1.1 2001/05/15 13:58:52 oes
132 * Initial import of version 2.9.3 source tree
135 *********************************************************************/
141 #include <sys/types.h>
148 #include <netinet/in.h>
150 #include <winsock2.h>
157 #include "showargs.h"
161 #include "jbsockets.h"
163 #include "jbsockets.h"
164 #include "miscutil.h"
170 const char filters_h_rcs[] = FILTERS_H_VERSION;
172 /* Fix a problem with Solaris. There should be no effect on other
174 * Solaris's isspace() is a macro which uses it's argument directly
175 * as an array index. Therefore we need to make sure that high-bit
176 * characters generate +ve values, and ideally we also want to make
177 * the argument match the declared parameter type of "int".
179 #define ijb_isdigit(__X) isdigit((int)(unsigned char)(__X))
182 static const char CBLOCK[] =
184 "HTTP/1.0 403 Request for blocked URL\n"
185 #else /* ifndef AMIGA */
186 "HTTP/1.0 202 Request for blocked URL\n"
187 #endif /* ndef AMIGA */
189 "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
190 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
191 "Content-Type: text/html\n\n"
194 "<title>Internet Junkbuster: Request for blocked URL</title>\n"
200 "<p align=center>Your request for <b>%s%s</b><br>\n"
203 " <a href=\"http://%s" FORCE_PREFIX "%s\">"
204 "Go there anyway.</a>"
205 #endif /* def FORCE_LOAD */
211 static const char CTRUST[] =
213 "HTTP/1.0 403 Request for untrusted URL\n"
214 #else /* ifndef AMIGA */
215 "HTTP/1.0 202 Request for untrusted URL\n"
216 #endif /* ndef AMIGA */
218 "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
219 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
220 "Content-Type: text/html\n\n"
223 "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
227 "<a href=http://i.j.b/ij-untrusted-url?%s+%s+%s>"
233 #endif /* def TRUST_FILES */
237 /*********************************************************************
239 * Function : block_acl
241 * Description : Block this request?
242 * Decide yes or no based on ACL file.
245 * 1 : dst = The proxy or gateway address this is going to.
246 * Or NULL to check all possible targets.
247 * 2 : csp = Current client state (buffers, headers, etc...)
248 * Also includes the client IP address.
250 * Returns : 0 = FALSE (don't block) and 1 = TRUE (do block)
252 *********************************************************************/
253 int block_acl(struct access_control_addr *dst,
254 struct client_state *csp)
256 struct file_list *fl;
257 struct access_control_list *a, *acl;
259 /* if not using an access control list, then permit the connection */
260 if (((fl = csp->alist) == NULL) ||
261 ((acl = (struct access_control_list *) fl->f) == NULL))
266 /* search the list */
267 for (a = acl->next ; a ; a = a->next)
269 if ((csp->ip_addr_long & a->src->mask) == a->src->addr)
273 /* Just want to check if they have any access */
274 if (a->action == ACL_PERMIT)
279 else if ( ((dst->addr & a->dst->mask) == a->dst->addr)
280 && ((dst->port == a->dst->port) || (a->dst->port == 0)))
282 if (a->action == ACL_PERMIT)
299 /*********************************************************************
301 * Function : acl_addr
303 * Description : Called from `load_aclfile' to parse an ACL address.
306 * 1 : aspec = String specifying ACL address.
307 * 2 : aca = struct access_control_addr to fill in.
309 * Returns : 0 => Ok, everything else is an error.
311 *********************************************************************/
312 int acl_addr(char *aspec, struct access_control_addr *aca)
314 int i, masklength, port;
320 if ((p = strchr(aspec, '/')))
324 if (ijb_isdigit(*p) == 0)
328 masklength = atoi(p);
331 if ((masklength < 0) || (masklength > 32))
336 if ((p = strchr(aspec, ':')))
340 if (ijb_isdigit(*p) == 0)
349 aca->addr = ntohl(resolve_hostname_to_ip(aspec));
353 log_error(LOG_LEVEL_ERROR, "can't resolve address for %s", aspec);
357 /* build the netmask */
359 for (i=1; i <= masklength ; i++)
361 aca->mask |= (1 << (32 - i));
364 /* now mask off the host portion of the ip address
365 * (i.e. save on the network portion of the address).
367 aca->addr = aca->addr & aca->mask;
372 #endif /* def ACL_FILES */
375 /*********************************************************************
377 * Function : block_url
379 * Description : Called from `chat'. Check to see if we need to block this.
382 * 1 : http = http_request request to "check" for blocked
383 * 2 : csp = Current client state (buffers, headers, etc...)
385 * Returns : NULL => unblocked, else string to HTML block description.
387 *********************************************************************/
388 char *block_url(struct http_request *http, struct client_state *csp)
393 if ((csp->permissions & PERMIT_BLOCK) == 0)
400 n += strlen(http->hostport);
401 n += strlen(http->path);
403 n += strlen(http->hostport);
404 n += strlen(http->path);
405 #endif /* def FORCE_LOAD */
407 p = (char *)malloc(n);
410 sprintf(p, CBLOCK, http->hostport, http->path, http->hostport, http->path);
412 sprintf(p, CBLOCK, http->hostport, http->path);
413 #endif /* def FORCE_LOAD */
420 #ifdef IMAGE_BLOCKING
421 /*********************************************************************
423 * Function : block_imageurl
425 * Description : Given a URL which is blocked, decide whether to
426 * send the "blocked" image or HTML.
429 * 1 : http = URL to check.
430 * 2 : csp = Current client state (buffers, headers, etc...)
432 * Returns : True (nonzero) if URL is in image list, false (0)
435 *********************************************************************/
436 int block_imageurl(struct http_request *http, struct client_state *csp)
438 #ifdef DETECT_MSIE_IMAGES
439 if ((csp->accept_types
440 & (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE|ACCEPT_TYPE_MSIE_HTML))
441 == (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE))
445 else if ((csp->accept_types
446 & (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_IMAGE|ACCEPT_TYPE_MSIE_HTML))
447 == (ACCEPT_TYPE_IS_MSIE|ACCEPT_TYPE_MSIE_HTML))
453 return ((csp->permissions & PERMIT_IMAGE) != 0);
455 #endif /* def IMAGE_BLOCKING */
459 /*********************************************************************
461 * Function : re_process_buffer
463 * Description : Apply all jobs from the joblist (aka. Perl regexp's) to
464 * the text buffer that's been accumulated in csp->iob->buf
465 * and set csp->content_length to the modified size.
468 * 1 : csp = Current client state (buffers, headers, etc...)
470 * Returns : a pointer to the (newly allocated) modified buffer.
473 *********************************************************************/
474 char *re_process_buffer(struct client_state *csp)
477 int size = csp->iob->eod - csp->iob->cur;
478 char *old=csp->iob->cur, *new = NULL;
479 pcrs_job *job, *joblist;
481 struct file_list *fl;
482 struct re_filterfile_spec *b;
484 /* Sanity first ;-) */
490 if ( ( NULL == (fl = csp->rlist) ) || ( NULL == (b = fl->f) ) )
492 log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
496 joblist = b->joblist;
499 log_error(LOG_LEVEL_RE_FILTER, "re_filtering %s%s (size %d) ...",
500 csp->http->hostport, csp->http->path, size);
502 /* Apply all jobs from the joblist */
503 for (job = joblist; NULL != job; job = job->next)
505 hits += pcrs_exec_substitution(job, old, size, &new, &size);
506 if (old != csp->iob->cur) free(old);
510 log_error(LOG_LEVEL_RE_FILTER, " produced %d hits (new size %d).", hits, size);
512 csp->content_length = size;
514 /* fwiw, reset the iob */
519 #endif /* def PCRS */
523 /*********************************************************************
525 * Function : trust_url
527 * Description : Should we "trust" this URL? See "trustfile" line in config.
530 * 1 : http = http_request request for requested URL
531 * 2 : csp = Current client state (buffers, headers, etc...)
533 * Returns : NULL => trusted, else string to HTML "untrusted" description.
535 *********************************************************************/
536 char *trust_url(struct http_request *http, struct client_state *csp)
538 struct file_list *fl;
539 struct block_spec *b;
540 struct url_spec url[1], **tl, *t;
542 char *hostport, *path, *refer;
543 struct http_request rhttp[1];
546 if (((fl = csp->tlist) == NULL) || ((b = fl->f) == NULL))
551 *url = dsplit(http->host);
553 /* if splitting the domain fails, punt */
554 if (url->dbuf == NULL) return(NULL);
556 memset(rhttp, '\0', sizeof(*rhttp));
558 for (b = b->next; b ; b = b->next)
560 if ((b->url->port == 0) || (b->url->port == http->port))
562 if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
564 if ((b->url->path == NULL) ||
566 (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
568 (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
575 if (b->reject == 0) return(NULL);
577 hostport = url_encode(http->hostport);
578 path = url_encode(http->path);
582 refer = url_encode(csp->referrer);
586 refer = url_encode("undefined");
590 n += strlen(hostport);
594 p = (char *)malloc(n);
596 sprintf(p, CTRUST, hostport, path, refer);
611 if ((csp->referrer == NULL)|| (strlen(csp->referrer) <= 9))
613 /* no referrer was supplied */
614 goto trust_url_not_trusted;
617 /* forge a URL from the referrer so we can use
618 * convert_url() to parse it into its components.
622 p = strsav(p, "GET ");
623 p = strsav(p, csp->referrer + 9); /* skip over "Referer: " */
624 p = strsav(p, " HTTP/1.0");
626 parse_http_request(p, rhttp, csp);
628 if (rhttp->cmd == NULL)
631 goto trust_url_not_trusted;
636 *url = dsplit(rhttp->host);
638 /* if splitting the domain fails, punt */
639 if (url->dbuf == NULL) goto trust_url_not_trusted;
641 for (tl = csp->config->trust_list; (t = *tl) ; tl++)
643 if ((t->port == 0) || (t->port == rhttp->port))
645 if ((t->domain[0] == '\0') || domaincmp(t, url) == 0)
647 if ((t->path == NULL) ||
649 (regexec(t->preg, rhttp->path, 0, NULL, 0) == 0)
651 (strncmp(t->path, rhttp->path, t->pathlen) == 0)
655 /* if the URL's referrer is from a trusted referrer, then
656 * add the target spec to the trustfile as an unblocked
657 * domain and return NULL (which means it's OK).
665 if ((fp = fopen(csp->config->trustfile, "a")))
670 h = strsav(h, http->hostport);
676 /* since this path points into a user's home space
677 * be sure to include this spec in the trustfile.
679 if ((p = strchr(p, '/')))
682 h = strsav(h, http->path);
687 free_http_request(rhttp);
689 fprintf(fp, "%s\n", h);
699 trust_url_not_trusted:
700 free_http_request(rhttp);
702 hostport = url_encode(http->hostport);
703 path = url_encode(http->path);
707 refer = url_encode(csp->referrer);
711 refer = url_encode("undefined");
715 n += strlen(hostport);
719 p = (char *)malloc(n);
720 sprintf(p, CTRUST, hostport, path, refer);
729 #endif /* def TRUST_FILES */
732 static const char C_HOME_PAGE[] =
735 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
736 "Content-Type: text/html\n\n"
739 "<title>Internet Junkbuster: Information</title>\n"
745 "<p><a href=\"" HOME_PAGE_URL "\">JunkBuster web site</a></p>\n"
746 "<p><a href=\"http://i.j.b/show-proxy-arg\">Proxy configuration</a></p>\n"
747 "<p><a href=\"http://i.j.b/show-url-info\">Look up a URL</a></p>\n"
752 /*********************************************************************
754 * Function : intercept_url
756 * Description : checks the URL `basename' against a list of URLs to
757 * snarf. If it matches, it calls the associated function
758 * which returns an HTML page to send back to the client.
759 * Right now, we snarf:
760 * "show-proxy-args", and
761 * "ij-untrusted-url" (optional w/TRUST_FILES)
764 * 1 : http = http_request request, check `basename's of blocklist
765 * 2 : csp = Current client state (buffers, headers, etc...)
767 * Returns : 1 if it intercepts & handles the request.
769 *********************************************************************/
770 int intercept_url(struct http_request *http, struct client_state *csp)
772 char *basename = NULL;
773 const struct interceptors *v;
775 if (0 == strcmpic(http->host,"i.j.b"))
778 * Catch http://i.j.b/...
780 basename = http->path;
782 else if ( ( (0 == strcmpic(http->host,"ijbswa.sourceforge.net"))
783 || (0 == strcmpic(http->host,"ijbswa.sf.net")) )
784 && (0 == strncmpic(http->path,"/config", 7))
785 && ((http->path[7] == '/') || (http->path[7] == '\0')))
788 * Catch http://ijbswa.sourceforge.net/config/...
789 * and http://ijbswa.sf.net/config/...
791 basename = http->path + 7;
796 /* Don't want to intercept */
800 /* We have intercepted it. */
802 /* remove any leading slash */
803 if (*basename == '/')
808 log_error(LOG_LEVEL_GPC, "%s%s intercepted!", http->hostport, http->path);
809 log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3",
810 csp->ip_addr_str, http->cmd);
812 for (v = intercept_patterns; v->str; v++)
814 if (strncmp(basename, v->str, v->len) == 0)
816 char * p = ((v->interceptor)(http, csp));
820 /* Send HTML redirection result */
821 write_socket(csp->cfd, p, strlen(p));
829 write_socket(csp->cfd, C_HOME_PAGE, strlen(C_HOME_PAGE));
834 #ifdef FAST_REDIRECTS
835 /*********************************************************************
837 * Function : redirect_url
839 * Description : Checks for redirection URLs and returns a HTTP redirect
840 * to the destination URL.
843 * 1 : http = http_request request, check `basename's of blocklist
844 * 2 : csp = Current client state (buffers, headers, etc...)
846 * Returns : NULL if URL was clean, HTTP redirect otherwise.
848 *********************************************************************/
849 char *redirect_url(struct http_request *http, struct client_state *csp)
853 p = q = csp->http->path;
854 log_error(LOG_LEVEL_REDIRECTS, "checking path: %s", p);
856 /* find the last URL encoded in the request */
857 while (p = strstr(p, "http://"))
862 /* if there was any, generate and return a HTTP redirect */
863 if (q != csp->http->path)
865 log_error(LOG_LEVEL_REDIRECTS, "redirecting to: %s", q);
867 p = (char *)malloc(strlen(HTTP_REDIRECT_TEMPLATE) + strlen(q));
868 sprintf(p, HTTP_REDIRECT_TEMPLATE, q);
877 #endif /* def FAST_REDIRECTS */
879 /*********************************************************************
881 * Function : url_permissions
883 * Description : Gets the permissions for this URL.
886 * 1 : http = http_request request for blocked URLs
887 * 2 : csp = Current client state (buffers, headers, etc...)
889 * Returns : permissions bitmask specifiying what this URL can do.
890 * If not on list, will be default_permissions.
892 *********************************************************************/
893 int url_permissions(struct http_request *http, struct client_state *csp)
895 struct file_list *fl;
896 struct permissions_spec *b;
897 struct url_spec url[1];
898 int permissions = csp->config->default_permissions;
900 if (((fl = csp->permissions_list) == NULL) || ((b = fl->f) == NULL))
905 *url = dsplit(http->host);
907 /* if splitting the domain fails, punt */
908 if (url->dbuf == NULL)
913 for (b = b->next; NULL != b; b = b->next)
915 if ((b->url->port == 0) || (b->url->port == http->port))
917 if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
919 if ((b->url->path == NULL) ||
921 (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
923 (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
927 permissions &= b->mask;
928 permissions |= b->add;
941 /*********************************************************************
943 * Function : forward_url
945 * Description : Should we forward this to another proxy?
948 * 1 : http = http_request request for current URL
949 * 2 : csp = Current client state (buffers, headers, etc...)
951 * Returns : Return gw_default for no forward match,
952 * else a gateway pointer to a specific forwarding proxy.
954 *********************************************************************/
955 const struct gateway *forward_url(struct http_request *http, struct client_state *csp)
957 struct file_list *fl;
958 struct forward_spec *b;
959 struct url_spec url[1];
961 if (((fl = csp->flist) == NULL) || ((b = fl->f) == NULL))
966 *url = dsplit(http->host);
968 /* if splitting the domain fails, punt */
969 if (url->dbuf == NULL) return(gw_default);
971 for (b = b->next; b ; b = b->next)
973 if ((b->url->port == 0) || (b->url->port == http->port))
975 if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
977 if ((b->url->path == NULL) ||
979 (regexec(b->url->preg, http->path, 0, NULL, 0) == 0)
981 (strncmp(b->url->path, http->path, b->url->pathlen) == 0)
1000 /*********************************************************************
1004 * Description : Takes a domain and returns a pointer to a url_spec
1005 * structure populated with dbuf, dcnt and dvec. The
1006 * other fields in the structure that is returned are zero.
1009 * 1 : domain = a URL address
1011 * Returns : url_spec structure populated with dbuf, dcnt and dvec.
1013 *********************************************************************/
1014 struct url_spec dsplit(char *domain)
1016 struct url_spec ret[1];
1021 memset(ret, '\0', sizeof(*ret));
1023 if ((p = strrchr(domain, '.')))
1031 ret->dbuf = strdup(domain);
1033 /* map to lower case */
1034 for (p = ret->dbuf; *p ; p++) *p = tolower(*p);
1036 /* split the domain name into components */
1037 ret->dcnt = ssplit(ret->dbuf, ".", v, SZ(v), 1, 1);
1041 memset(ret, '\0', sizeof(ret));
1045 /* save a copy of the pointers in dvec */
1046 size = ret->dcnt * sizeof(*ret->dvec);
1048 if ((ret->dvec = (char **)malloc(size)))
1050 memcpy(ret->dvec, v, size);
1058 /*********************************************************************
1060 * Function : domaincmp
1062 * Description : Compare domain names.
1063 * domaincmp("a.b.c" , "a.b.c") => 0 (MATCH)
1064 * domaincmp("a*.b.c", "a.b.c") => 0 (MATCH)
1065 * domaincmp("b.c" , "a.b.c") => 0 (MATCH)
1066 * domaincmp("" , "a.b.c") => 0 (MATCH)
1069 * 1 : pattern = a domain that may contain a '*' as a wildcard.
1070 * 2 : fqdn = domain name against which the patterns are compared.
1072 * Returns : 0 => domains are equivalent, else no match.
1074 *********************************************************************/
1075 int domaincmp(struct url_spec *pattern, struct url_spec *fqdn)
1077 char **pv, **fv; /* vectors */
1078 int pn, fn; /* counters */
1079 char *p, *f; /* chars */
1087 while ((pn > 0) && (fn > 0))
1092 while (*p && *f && (*p == tolower(*f)))
1097 if ((*p != tolower(*f)) && (*p != '*')) return(1);
1100 if (pn > 0) return(1);
1107 /* intercept functions */
1109 /*********************************************************************
1111 * Function : show_proxy_args
1113 * Description : This "crunch"es "http:/any.thing/show-proxy-args" and
1114 * returns a web page describing the current status of IJB.
1117 * 1 : http = ignored
1118 * 2 : csp = Current client state (buffers, headers, etc...)
1120 * Returns : A string that contains the current status of IJB.
1122 *********************************************************************/
1123 char *show_proxy_args(struct http_request *http, struct client_state *csp)
1127 #ifdef SPLIT_PROXY_ARGS
1131 const char * filename = NULL;
1132 const char * file_description = NULL;
1133 char * query_string = strrchr(http->path, '?');
1134 char which_file = '\0';
1137 if (query_string != NULL)
1139 /* first char past the last '?' (maybe '\0')*/
1140 which_file = query_string[1];
1145 if (csp->permissions_list)
1147 filename = csp->permissions_list->filename;
1148 file_description = "Permissions List";
1154 filename = csp->flist->filename;
1155 file_description = "Forward List";
1163 filename = csp->alist->filename;
1164 file_description = "Access Control List";
1167 #endif /* def ACL_FILES */
1173 filename = csp->rlist->filename;
1174 file_description = "RE Filter List";
1177 #endif /* def PCRS */
1183 filename = csp->tlist->filename;
1184 file_description = "Trust List";
1187 #endif /* def TRUST_FILES */
1192 /* Display specified file */
1193 /* FIXME: Add HTTP headers so this isn't cached */
1196 "Server: IJ/" VERSION "\n"
1197 "Content-type: text/html\n"
1198 "Pragma: no-cache\n"
1199 "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1200 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1205 "<title>Internet Junkbuster Proxy Status - ");
1206 s = strsav(s, file_description);
1210 "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
1212 "<h1>" BANNER "\n");
1213 s = strsav(s, file_description);
1216 "<p><a href=\"show-proxy-args\">Back to proxy status</a></p>\n"
1218 s = strsav(s, file_description);
1221 "Contents of file "<code>");
1222 p = html_encode(filename);
1226 "</code>":<br>\n"
1230 if ((fp = fopen(filename, "r")) == NULL)
1232 s = strsav(s, "</pre><h1>ERROR OPENING FILE!</h1><pre>");
1236 while (fgets(buf, sizeof(buf), fp))
1238 p = html_encode(buf);
1243 s = strsav(s, "<br>");
1252 "<p><a href=\"show-proxy-args\">Back to proxy status</a></p>\n"
1254 "<small><small><p>\n"
1255 "The " BANNER " Proxy - \n"
1256 "<a href=\"" HOME_PAGE_URL "\">" HOME_PAGE_URL "</a>\n"
1258 "</body></html>\n");
1261 #endif /* def SPLIT_PROXY_ARGS */
1263 s = strsav(s, csp->config->proxy_args_header);
1264 s = strsav(s, csp->config->proxy_args_invocation);
1267 #endif /* def STATISTICS */
1268 s = strsav(s, csp->config->proxy_args_gateways);
1270 #ifdef SPLIT_PROXY_ARGS
1272 "<h2>The following files are in use:</h2>\n"
1273 "<p>(Click a filename to view it)</p>\n"
1276 if (csp->permissions_list)
1278 s = strsav(s, "<li>Permissions List: <a href=\"show-proxy-args?permit\"><code>");
1279 s = strsav(s, csp->permissions_list->filename);
1280 s = strsav(s, "</code></a></li>\n");
1285 s = strsav(s, "<li>Forward List: <a href=\"show-proxy-args?forward\"><code>");
1286 s = strsav(s, csp->flist->filename);
1287 s = strsav(s, "</code></a></li>\n");
1293 s = strsav(s, "<li>Access Control List: <a href=\"show-proxy-args?acl\"><code>");
1294 s = strsav(s, csp->alist->filename);
1295 s = strsav(s, "</code></a></li>\n");
1297 #endif /* def ACL_FILES */
1302 s = strsav(s, "<li>RE Filter List: <a href=\"show-proxy-args?re\"><code>");
1303 s = strsav(s, csp->rlist->filename);
1304 s = strsav(s, "</code></a></li>\n");
1306 #endif /* def PCRS */
1311 s = strsav(s, "<li>Trust List: <a href=\"show-proxy-args?trust\"><code>");
1312 s = strsav(s, csp->tlist->filename);
1313 s = strsav(s, "</code></a></li>\n");
1315 #endif /* def TRUST_FILES */
1317 s = strsav(s, "</ul>");
1319 #else /* ifndef SPLIT_PROXY_ARGS */
1322 s = strsav(s, csp->clist->proxy_args);
1327 s = strsav(s, csp->flist->proxy_args);
1333 s = strsav(s, csp->alist->proxy_args);
1335 #endif /* def ACL_FILES */
1340 s = strsav(s, csp->rlist->proxy_args);
1342 #endif /* def PCRS */
1347 s = strsav(s, csp->tlist->proxy_args);
1349 #endif /* def TRUST_FILES */
1351 #endif /* ndef SPLIT_PROXY_ARGS */
1353 s = strsav(s, csp->config->proxy_args_trailer);
1360 static const char C_URL_INFO_HEADER[] =
1362 "Pragma: no-cache\n"
1363 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1364 "Content-Type: text/html\n\n"
1367 "<title>Internet Junkbuster: URL Info</title>\n"
1373 "<p>Information for: <a href=\"http://%s\">http://%s</a></p>\n";
1374 static const char C_URL_INFO_FOOTER[] =
1379 static const char C_URL_INFO_FORM[] =
1381 "Pragma: no-cache\n"
1382 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1383 "Content-Type: text/html\n\n"
1386 "<title>Internet Junkbuster: URL Info</title>\n"
1392 "<form method=\"GET\" action=\"http://i.j.b/show-url-info\">\n"
1393 "<p>Please enter a URL, without the leading "http:":</p>"
1394 "<p><input type=\"text\" name=\"url\" size=\"80\">"
1395 "<input type=\"submit\" value=\"Info\"></p>\n"
1401 /*********************************************************************
1403 * Function : permissions_to_text
1405 * Description : Converts a permissionsfil entry from numeric form
1406 * ("mask" and "add") to text.
1409 * 1 : mask = As from struct permissions_spec
1410 * 2 : add = As from struct permissions_spec
1412 * Returns : A string. Caller must free it.
1414 *********************************************************************/
1415 char * permissions_to_text(unsigned mask, unsigned add)
1417 char * result = strdup("");
1419 /* sanity - prevents "-feature +feature" */
1422 #define PERMISSION_TO_TEXT(__bit, __name) \
1423 if (!(mask & __bit)) \
1425 result = strsav(result, " -" __name); \
1427 else if (add & __bit) \
1429 result = strsav(result, " +" __name); \
1432 PERMISSION_TO_TEXT(PERMIT_COOKIE_SET, "cookies-set");
1433 PERMISSION_TO_TEXT(PERMIT_COOKIE_READ, "cookies-read");
1434 PERMISSION_TO_TEXT(PERMIT_RE_FILTER, "filter");
1435 PERMISSION_TO_TEXT(PERMIT_POPUPS, "popup");
1436 PERMISSION_TO_TEXT(PERMIT_REFERER, "referer");
1437 PERMISSION_TO_TEXT(PERMIT_FAST_REDIRECTS, "fast-redirects");
1438 PERMISSION_TO_TEXT(PERMIT_BLOCK, "block");
1439 PERMISSION_TO_TEXT(PERMIT_IMAGE, "image");
1445 /*********************************************************************
1447 * Function : ijb_show_url_info
1449 * Description : (please fill me in)
1452 * 1 : http = http_request request for crunched URL
1453 * 2 : csp = Current client state (buffers, headers, etc...)
1455 * Returns : ???FIXME
1457 *********************************************************************/
1458 char *ijb_show_url_info(struct http_request *http, struct client_state *csp)
1460 char * query_string = strchr(http->path, '?');
1463 if (query_string != NULL)
1465 query_string = url_decode(query_string + 1);
1466 if (strncmpic(query_string, "url=", 4) == 0)
1468 host = strdup(query_string + 4);
1470 freez(query_string);
1478 struct file_list *fl;
1479 struct permissions_spec *b;
1480 struct url_spec url[1];
1481 int permissions = csp->config->default_permissions;
1483 result = (char *)malloc(sizeof(C_URL_INFO_HEADER) + 2 * strlen(host));
1484 sprintf(result, C_URL_INFO_HEADER, host, host);
1486 s = permissions_to_text(permissions, permissions);
1487 result = strsav(result, "<h3>Defaults:</h3>\n<p><b>{");
1488 result = strsav(result, s);
1489 result = strsav(result, " }</b></p>\n<h3>Patterns affecting the URL:</h3>\n<p>\n");
1492 s = strchr(host, '/');
1502 s = strchr(host, ':');
1509 if (((fl = csp->permissions_list) == NULL) || ((b = fl->f) == NULL))
1513 result = strsav(result, C_URL_INFO_FOOTER);
1517 *url = dsplit(host);
1519 /* if splitting the domain fails, punt */
1520 if (url->dbuf == NULL)
1524 result = strsav(result, C_URL_INFO_FOOTER);
1528 for (b = b->next; NULL != b; b = b->next)
1530 if ((b->url->port == 0) || (b->url->port == port))
1532 if ((b->url->domain[0] == '\0') || (domaincmp(b->url, url) == 0))
1534 if ((b->url->path == NULL) ||
1536 (regexec(b->url->preg, path, 0, NULL, 0) == 0)
1538 (strncmp(b->url->path, path, b->url->pathlen) == 0)
1542 s = permissions_to_text(b->mask, b->add);
1543 result = strsav(result, "<b>{");
1544 result = strsav(result, s);
1545 result = strsav(result, " }</b><br>\n<code>");
1546 result = strsav(result, b->url->spec);
1547 result = strsav(result, "</code><br>\n<br>\n");
1549 permissions &= b->mask;
1550 permissions |= b->add;
1562 s = permissions_to_text(permissions, permissions);
1563 result = strsav(result, "</p>\n<h2>Final Results:</h2>\n<p><b>{");
1564 result = strsav(result, s);
1565 result = strsav(result, " }</b><br>\n<br>\n");
1568 result = strsav(result, C_URL_INFO_FOOTER);
1573 return strdup(C_URL_INFO_FORM);
1578 /*********************************************************************
1580 * Function : ijb_send_banner
1582 * Description : This "crunch"es "http://i.j.b/ijb-send-banner and
1586 * 1 : http = http_request request for crunched URL
1587 * 2 : csp = Current client state (buffers, headers, etc...)
1589 * Returns : NULL, indicating that it has already sent the data.
1591 *********************************************************************/
1592 char *ijb_send_banner(struct http_request *http, struct client_state *csp)
1594 write_socket(csp->cfd, JBGIF, sizeof(JBGIF)-1);
1600 /*********************************************************************
1602 * Function : ij_untrusted_url
1604 * Description : This "crunch"es "http:/any.thing/ij-untrusted-url" and
1605 * returns a web page describing why it was untrusted.
1608 * 1 : http = http_request request for crunched URL
1609 * 2 : csp = Current client state (buffers, headers, etc...)
1611 * Returns : A string that contains why this was untrusted.
1613 *********************************************************************/
1614 char *ij_untrusted_url(struct http_request *http, struct client_state *csp)
1617 char *hostport, *path, *refer, *p, *v[9];
1619 struct url_spec **tl, *t;
1622 static const char format[] =
1623 "HTTP/1.0 200 OK\r\n"
1624 "Pragma: no-cache\n"
1625 "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1626 "Expires: Thu Jul 31, 1997 07:42:22 pm GMT\n"
1627 "Content-Type: text/html\n\n"
1630 "<title>Internet Junkbuster: Request for untrusted URL</title>\n"
1636 "The " BANNER " Proxy "
1637 "<A href=\"" HOME_PAGE_URL "\">"
1638 "(" HOME_PAGE_URL ") </A>"
1639 "intercepted the request for %s%s\n"
1640 "because the URL is not trusted.\n"
1643 if ((n = ssplit(http->path, "?+", v, SZ(v), 0, 0)) == 4)
1645 hostport = url_decode(v[1]);
1646 path = url_decode(v[2]);
1647 refer = url_decode(v[3]);
1651 hostport = strdup("undefined_host");
1652 path = strdup("/undefined_path");
1653 refer = strdup("undefined");
1657 n += strlen(hostport);
1660 if ((p = (char *)malloc(n)))
1662 sprintf(p, format, hostport, path);
1665 strsav(p, "The referrer in this request was <strong>");
1667 strsav(p, "</strong><br>\n");
1673 p = strsav(p, "<h3>The following referrers are trusted</h3>\n");
1675 for (tl = csp->config->trust_list; (t = *tl) ; tl++)
1677 sprintf(buf, "%s<br>\n", t->spec);
1681 if (csp->config->trust_info->next)
1687 "You can learn more about what this means "
1688 "and what you may be able to do about it by "
1689 "reading the following documents:<br>\n"
1695 for (l = csp->config->trust_info->next; l ; l = l->next)
1698 "<li> <a href=%s>%s</a><br>\n",
1703 p = strsav(p, "</ol>\n");
1706 p = strsav(p, "</body>\n" "</html>\n");
1711 #endif /* def TRUST_FILES */
1715 /*********************************************************************
1717 * Function : add_stats
1719 * Description : Statistics function of JB. Called by `show_proxy_args'.
1722 * 1 : s = string that holds the proxy args description page
1724 * Returns : A pointer to the descriptive status web page.
1726 *********************************************************************/
1727 char *add_stats(char *s)
1730 * Output details of the number of requests rejected and
1731 * accepted. This is switchable in the junkbuster config.
1732 * Does nothing if this option is not enabled.
1735 float perc_rej; /* Percentage of http requests rejected */
1737 int local_urls_read = urls_read;
1738 int local_urls_rejected = urls_rejected;
1741 * Need to alter the stats not to include the fetch of this
1744 * Can't do following thread safely! doh!
1747 * urls_rejected--; * This will be incremented subsequently *
1750 s = strsav(s,"<h2>Statistics for this " BANNER ":</h2>\n");
1752 if (local_urls_read == 0)
1755 s = strsav(s,"No activity so far!\n");
1761 perc_rej = (float)local_urls_rejected * 100.0F /
1762 (float)local_urls_read;
1765 "%d requests received, %d filtered "
1768 local_urls_rejected, perc_rej);
1770 s = strsav(s,out_str);
1775 #endif /* def STATISTICS */