tinyproxy/src/filter.c

198 lines
3.9 KiB
C

/* $Id: filter.c,v 1.14 2002-06-07 19:10:05 rjkaes Exp $
*
* Copyright (c) 1999 George Talusan (gstalusan@uwaterloo.ca)
* Copyright (c) 2002 James E. Flemer (jflemer@acm.jhu.edu)
* Copyright (c) 2002 Robert James Kaes (rjkaes@flarenet.com)
*
* A substring of the domain to be filtered goes into the file
* pointed at by DEFAULT_FILTER.
*
* 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, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include "tinyproxy.h"
#include "filter.h"
#include "heap.h"
#include "log.h"
#include "regexp.h"
#include "reqs.h"
#define FILTER_BUFFER_LEN (512)
static int err;
struct filter_list {
struct filter_list *next;
char *pat;
regex_t *cpat;
};
static struct filter_list *fl = NULL;
static int already_init = 0;
static filter_policy_t default_policy = FILTER_DEFAULT_ALLOW;
/*
* Initializes a linked list of strings containing hosts/urls to be filtered
*/
void
filter_init(void)
{
FILE *fd;
struct filter_list *p;
char buf[FILTER_BUFFER_LEN];
char *s, *t;
int cflags;
if (!fl && !already_init) {
fd = fopen(config.filter, "r");
if (fd) {
p = NULL;
cflags = REG_NEWLINE | REG_NOSUB;
if (config.filter_extended)
cflags |= REG_EXTENDED;
while (fgets(buf, FILTER_BUFFER_LEN, fd)) {
s = buf;
if (!p) /* head of list */
fl = p =
safecalloc(1,
sizeof(struct
filter_list));
else { /* next entry */
p->next =
safecalloc(1,
sizeof(struct
filter_list));
p = p->next;
}
/* strip trailing whitespace & comments */
t = s;
while (*s && *s != '#') {
if (!isspace((unsigned char)*(s++)))
t = s;
}
*t = '\0';
/* skip leading whitespace */
s = buf;
while (*s && isspace((unsigned char)*s))
s++;
/* skip blank lines and comments */
if (*s == '\0')
continue;
p->pat = safestrdup(s);
p->cpat = safemalloc(sizeof(regex_t));
if ((err = regcomp(p->cpat, p->pat, cflags)) != 0) {
fprintf(stderr, "Bad regex in %s: %s\n",
config.filter, p->pat);
exit(EX_DATAERR);
}
}
if (ferror(fd)) {
perror("fgets");
exit(EX_DATAERR);
}
fclose(fd);
already_init = 1;
}
}
}
/* unlink the list */
void
filter_destroy(void)
{
struct filter_list *p, *q;
if (already_init) {
for (p = q = fl; p; p = q) {
regfree(p->cpat);
safefree(p->cpat);
safefree(p->pat);
q = p->next;
safefree(p);
}
fl = NULL;
already_init = 0;
}
}
/* Return 0 to allow, non-zero to block */
int
filter_domain(const char *host)
{
struct filter_list *p;
int result;
if (!fl || !already_init)
goto COMMON_EXIT;
for (p = fl; p; p = p->next) {
result = regexec(p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0);
if (result == 0) {
if (default_policy == FILTER_DEFAULT_ALLOW)
return 1;
else
return 0;
}
}
COMMON_EXIT:
if (default_policy == FILTER_DEFAULT_ALLOW)
return 0;
else
return 1;
}
/* returns 0 to allow, non-zero to block */
int
filter_url(const char *url)
{
struct filter_list *p;
int result;
if (!fl || !already_init)
goto COMMON_EXIT;
for (p = fl; p; p = p->next) {
result = regexec(p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0);
if (result == 0) {
if (default_policy == FILTER_DEFAULT_ALLOW)
return 1;
else
return 0;
}
}
COMMON_EXIT:
if (default_policy == FILTER_DEFAULT_ALLOW)
return 0;
else
return 1;
}
/*
* Set the default filtering policy
*/
void
filter_set_default_policy(filter_policy_t policy)
{
default_policy = policy;
}