diff -uNr ffproxy-1.4.1/BUGS ffproxy-1.5/BUGS --- ffproxy-1.4.1/BUGS Sun Jul 20 09:58:57 2003 +++ ffproxy-1.5/BUGS Fri Aug 8 22:31:38 2003 @@ -1,2 +1,12 @@ -Send bug reports to -Niklas Olmes +I've access to a limited number of different +systems only, so it's not guaranteed that +ffproxy will compile at all. + +So far, I've tested ffproxy to work under +OpenBSD, FreeBSD, Linux, and Solaris8. + +If you've patches to make ffproxy work +on other systems, please let me know. + +Send bug reports, comments, questions +to Niklas Olmes diff -uNr ffproxy-1.4.1/ChangeLog ffproxy-1.5/ChangeLog --- ffproxy-1.4.1/ChangeLog Fri Aug 1 20:09:11 2003 +++ ffproxy-1.5/ChangeLog Fri Aug 8 22:32:15 2003 @@ -1,3 +1,38 @@ +Version 1.5 +=========== + + * IPv6 bind() support + + * changed db/* + You'll perhaps need to update files, + also please take a look at ffproxy(8) + + * allow comments and empty lines in db/* + + * removed caching complety from code + + * changed debug() to macro DEBUG() + + * code cleanups + + * check on configuration errors + + * more documentation in manual pages + ffproxy(8), ffproxy.conf(5), ffproxy.quick(7) + + * added HTTP Accelerator feature + + * more configuration file options, + more command line options + (for IPv6 and HTTP Accelerator) + + * allow non-numerical arguments to + uid, gid, -u, and -g + + * more minor changes + + * allow ffproxy to be compiled under Solaris8 + Version 1.4.1 ============= diff -uNr ffproxy-1.4.1/Makefile ffproxy-1.5/Makefile --- ffproxy-1.4.1/Makefile Fri Aug 1 20:24:07 2003 +++ ffproxy-1.5/Makefile Sat Aug 9 12:45:23 2003 @@ -1,33 +1,41 @@ # # change the following lines to fit your needs # -#CC = gcc -DDEBUG -#OCFLAGS = -W -Wall -Werror -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wbad-function-cast -ansi -pedantic-errors -O2 -# -# remove the # in front of the next line if you're using linux -#OCFLAGS = -DLINUX +# debugging: +#CC = cc -DUSE_DEBUG +#OCFLAGS = -W -Wall -Werror -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wbad-function-cast -pedantic-errors -O2 -SRCS = main.c print.c socket.c request.c http.c alloc.c filter.c db.c file.c dns.c signals.c access.c regex.c msg.c poll.c cache.c time.c +SRCS = main.c print.c socket.c request.c http.c alloc.c filter.c db.c file.c dns.c signals.c access.c regex.c msg.c poll.c OBJS = $(SRCS:.c=.o) -MANPAGES = ffproxy.8 +MANPAGES = ffproxy.8 ffproxy.conf.5 ffproxy.quick.7 PREFIX?=/usr/local CC?=cc DATADIR?=/var/ffproxy SYSCONFDIR?=/etc -CFLAGS = ${OCFLAGS} -DCFGFILE="\"${SYSCONFDIR}/ffproxy.conf\"" -DDATADIR="\"${DATADIR}\"" +CFLAGS += ${OCFLAGS} -DCFGFILE="\"${SYSCONFDIR}/ffproxy.conf\"" -DDATADIR="\"${DATADIR}\"" all: proxy +lint: + lint -aa -b -c -e -g -h -x -s ${SRCS} + install: install -c ffproxy ${PREFIX}/bin/ffproxy + install -d ${PREFIX}/bin + install -d ${PREFIX}/man + install -d ${PREFIX}/man/man5 + install -d ${PREFIX}/man/man7 install -d ${PREFIX}/man/man8 install -c ffproxy.8 ${PREFIX}/man/man8/ffproxy.8 + install -c ffproxy.conf.5 ${PREFIX}/man/man5/ffproxy.conf.5 + install -c ffproxy.quick.7 ${PREFIX}/man/man7/ffproxy.quick.7 proxy: $(OBJS) - ${CC} ${CFLAGS} -o ffproxy $(OBJS) + @./sys-dep.sh "${CC}" "${CFLAGS}" "-o ffproxy" "$(OBJS)" + strip ffproxy clean: rm -f *.o ffproxy diff -uNr ffproxy-1.4.1/README ffproxy-1.5/README --- ffproxy-1.4.1/README Fri Aug 1 20:40:21 2003 +++ ffproxy-1.5/README Fri Aug 8 22:37:58 2003 @@ -1,138 +1,41 @@ Description =========== -ffproxy -- full featured, secure HTTP proxy server - -ffproxy is a filtering HTTP proxy server. It is able to filter -by host, url, and header. Custom header entries can be filtered -and added. It can even drop its privileges and chroot() to some -directory. Logging to syslog() is supported, as is using another -auxiliary proxy server. Contacting servers via IPv6 is supported -as well. +ffproxy is a filtering HTTP proxy server. It is able to filter by host, +url, and header. Custom header entries can be filtered and added. It +can even drop its privileges and chroot(2) to some directory. Logging to +syslogd(8) is supported, as is using another auxiliary proxy server. +IPv6 is fully supported and allows IPv6 HTTP over IPv4 tunneling (and +vice versa). Website: http://faith.eu.org/programs.html Compilation =========== - * Edit Makefile to fit your needs. - (uncomment OCFLAGS = -DLINUX if you're using Linux) + * Edit Makefile and sys-dep.sh to fit your needs. + If you're using OpenBSD, FreeBSD, Linux, or Solaris8, + you normally don't have to change anything. + * After making your changes, compile ffproxy with make. - (see section `Bugs' at the very end of the file if - ffproxy won't compile or crashes) + (see file `BUGS' if ffproxy won't compile or crashes) Installation ============ - * Copy directories db/ and html/ to some other directory, - like /var/ffproxy. * Execute make install - This will copy ffproxy to /usr/local/bin and the manpage - ffproxy.8 to /usr/local/man/man8. - -Documentation -============= + This will copy ffproxy to ${PREFIX}/bin + and manpages to ${PREFIX}/man/man[578] - o For a quick summary and reference on ffproxy, - read the manual page. - - o For a longer introduction to configuring with the - db/ files, read this file. - + * Copy directories db/ and html/ to some other directory, + like /var/ffproxy. See ffproxy.quick(7) for example + installation. -Configuration +Documentation ============= - -ffproxy's basic settings (like the port to bind to) are determined at -program invocation by means of command line options, or by means -of a config file and the command line option `-f'. If no config -file is given, /etc/ffproxy.conf is used. - -See file config.sample for a configuration template. - -Filtering settings are read from directory db/ in /var/ffproxy -by default (use -D or db_files_path in config file to change). -These files do the following: - -The following three files are for filtering User Agent Headers: - - * filter.header.add Header entries to add - - * filter.header.drop If the regular expression matches any line of - the header, the complete request will be dropped - - * filter.header.entry Header entries to remove (i.e. `User-Agent:') - - - * filter.header.match If regular expression matches any header entry, - that one will be removed - -The files filter.rheader.drop, filter.rheader.entry, filter.rheader.match -do exactly the same on the remote side. - -The following files are for filtering hosts and urls: - - * filter.host.match Don't get anything from these hosts - (extended regular expression) - - * filter.url.match Don't get URLs that match any of - the extended regular expressions - -Access settings are read from db/, too: - - * host.dyndns Hostnames with dynamic IP addresses that have - access permission (matched case insensitive - without regular expressions) - - * host.ip static IP addresses (regular expressions) - - * host.name Official hostnames (regular expressions) - - -All entries are one line each. Comments are not allowed. - -All files ending in `match' or `drop' do pattern matching with extended -regular expressions, see manpage re_format(7) or regex(7), depending -on your system, for more information. - - Examples: - in db/filter.url.match: - /\.\./ don't allow to trick us or remote servers. - (prevent directory traversal, don't remove that) - - WERBUNG don't get file if URL contains the string `WERBUNG' - (German for commercial) - /[Rr]eal[Mm]edia don't get any URL that contains this string, - the effect is that directories or files - starting with `RealMedia' get filtered out - /ads/ this will prevent from receiving advertisements, - which quite often lie in directories named like - this - - in db/filter.host.match: - ^ad[0-9]*\. don't get anything from hosts with names starting - with `ad' followed by a dot or an abitrary - number followed by a dot. - - -Reloading Configuration -======================= - -If you altered files in db/ or html/ and want to make the changes -take effect, you don't have to restart ffproxy. - -Simply send a SIGHUP to the master process. It'll reload all files -and report success (by logging to syslog). Note that fatal errors, -like non existing files, cause ffproxy to terminate. Non fatal errors, -like broken extended regular expressions are logged while reloading -configuration. - -Bugs -==== - -Before I release a new version of ffproxy, I eliminate all known bugs. -Though I have only access to a limited number of different systems, -it's possible that ffproxy won't run correctly or won't compile at all. - -I would appreciate to hear succes stories or receive error reports -from you. Send these to my e-mail address, Niklas Olmes + + Documentation was moved to manual pages + + * ffproxy.quick(7) - quick introduction to setting up ffproxy + * ffproxy(8) - command line options; db/ and html/ description + * ffproxy.conf(5) - description of configuration files diff -uNr ffproxy-1.4.1/TODO ffproxy-1.5/TODO --- ffproxy-1.4.1/TODO Sun Jul 20 09:56:35 2003 +++ ffproxy-1.5/TODO Fri Aug 8 22:38:11 2003 @@ -1,8 +1,7 @@ New Features to add: - * allow ffproxy to *bind* to IPv6 - * change access.c so that IPv6 addresses will be recognized - * add content filtering + + * caching support More ideas? Mail me. diff -uNr ffproxy-1.4.1/access.c ffproxy-1.5/access.c --- ffproxy-1.4.1/access.c Sun Jul 20 11:26:45 2003 +++ ffproxy-1.5/access.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: access.c,v 1.6 2003/07/20 11:26:44 niklas Exp niklas $ + * $Id: access.c,v 1.7 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -20,6 +20,7 @@ * Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include "req.h" @@ -34,23 +35,25 @@ { int i; - i = 0; - while (a_ip[i] != NULL) - if (do_regex(host->ip, a_ip[i++]) == 0) - return 0; + if (*host->ip != '\0') { + i = 0; + while (a_ip[i] != NULL) + if (do_regex(host->ip, a_ip[i++]) == 0) + return 0; - if (strcmp(host->ip, host->rip) == 0) { + if (*host->name != '\0') { + i = 0; + while (a_host[i] != NULL) + if (do_regex(host->name, a_host[i++]) == 0) + return 0; + } i = 0; - while (a_host[i] != NULL) - if (do_regex(host->name, a_host[i++]) == 0) + while (a_dyndns[i] != NULL) + if (strcmp(host->ip, resolve_to_a(a_dyndns[i++])) == 0) return 0; } - i = 0; - while (a_dyndns[i] != NULL) - if (strcmp(host->ip, resolve_to_a(a_dyndns[i++])) == 0) - return 0; - debug("check_access() => done, no access. IP (%s) Host (%s) RIP (%s)", host->ip, host->name, host->rip); + DEBUG(("check_access() => done, no access. IP (%s) Host (%s)", host->ip, host->name)); return 1; } diff -uNr ffproxy-1.4.1/alloc.c ffproxy-1.5/alloc.c --- ffproxy-1.4.1/alloc.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/alloc.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: alloc.c,v 1.4 2003/07/20 10:38:23 niklas Exp $ + * $Id: alloc.c,v 1.5 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -22,6 +22,7 @@ #include #include +#include #include "print.h" #include "alloc.h" @@ -33,6 +34,6 @@ if ((p = malloc(size)) == NULL) fatal("malloc() failed"); - + (void) memset(p, 0, size); return p; } diff -uNr ffproxy-1.4.1/cache.c ffproxy-1.5/cache.c --- ffproxy-1.4.1/cache.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/cache.c Thu Jan 1 00:00:00 1970 @@ -1,366 +0,0 @@ -/* - * ffproxy (c) 2002, 2003 Niklas Olmes - * - * http://faith.eu.org - * - * $Id: cache.c,v 1.6 2003/07/20 10:38:23 niklas Exp $ - * - * 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 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 675 - * Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include -#include -#include -#ifdef LINUX -#define __USE_GNU 1 -#endif -#include -#include -#include - -#include "cfg.h" -#include "req.h" -#include "print.h" -#include "time.h" -#include "cache.h" - -#define MODE_FILE 0640 - -static int mktree(char *); -static int url_to_file(const char *, char *, size_t); -static int openfile(const struct req *, int); -static int lock(const struct req *); -static int islocked(const struct req *); - -static const char simple_header[] = "HTTP/1.0 200 OK (cached)\r\nProxy-Connection: close\r\nConnection: close\r\nContent-Type: "; -static const char default_mime[] = "application/octet-stream"; -static const char cache_dir[] = "cache/"; -static const char http_index[] = "index.html"; - -static const struct mt { - const char *ext, *ctype; -} mimetypes[] = { - { - "html", "text/html" - }, - { - "htm", "text/html" - }, - { - "css", "text/css" - }, - { - "gif", "image/gif" - }, - { - "png", "image/png" - }, - { - "jpeg", "image/jpeg" - }, - { - "jpg", "image/jpeg" - }, - { - "avi", "video/x-msvideo" - }, - { - "mpeg", "video/mpeg" - }, - { - "mp3", "audio/mpeg" - }, - { - "ogg", "audio/x-oggvorbis" - }, - { - "dvi", "application/x-dvi" - }, - { - "ps", "application/postscript" - }, - { - "pdf", "application/pdf" - }, - { - NULL, NULL - } -}; - -extern struct cfg config; - -int -deliverfromcache(int cl, int f, const struct req * r) -{ - char buf[4096]; - int len; - - if (!config.cache) - return -1; - - if (!config.online) { - char line[256]; - int p, i; - struct stat fstat; - - (void) strcpy(buf, simple_header); - - p = strlen(r->fname); - while (p > 0 && r->fname[p] != '.' && r->fname[p] != '/') - p--; - i = -1; - if (r->fname[p] == '.') { - p++; - i = 0; - while (mimetypes[i].ext != NULL) - if (strcmp(mimetypes[i++].ext, r->fname + p) == 0) - break; - } - if (i >= 0 && mimetypes[i].ext != NULL) - (void) strcat(buf, mimetypes[i].ctype); - else - (void) strcat(buf, default_mime); - - (void) strcat(buf, "\r\n"); - - if (stat(r->fname, &fstat) == 0) { - (void) sprintf(line, - "Server: ffproxy\r\n" - "Connection: close\r\n" - "Accept-Ranges: bytes\r\n" - "Content-Length: %ld\r\n" - "Last-Modified: ", - (long) fstat.st_size); - (void) strcat(buf, line); - (void) strftime(line, sizeof(line), - "%a, %d %b %Y %T GMT", - gmtime(&fstat.st_mtime)); - (void) strcat(buf, line); - (void) strcat(buf, "\r\n"); - } - (void) strcat(buf, "\r\n"); - - debug("deliverfromcache() => our header is (%s)", buf); - (void) write(cl, buf, strlen(buf)); - } - while ((len = read(f, buf, sizeof(buf))) > 0) - if (write(cl, buf, len) < 0) { - (void) close(f); - (void) close(cl); - return -1; - } - (void) close(f); - - return 0; -} - -int -havecached(const struct req * r) -{ - struct stat fstat; - time_t remote, local; - - if (!config.cache) - return 0; - - if (stat(r->fname, &fstat) != 0) - return 0; - - local = fstat.st_mtime; - remote = my_convtime(r->tstamp); - - debug("havecached() => times local (%d) remote (%d)", - local, remote); - debug("havecached() => sizes local (%ld) remote (%ld)", - (long) fstat.st_size, r->clen); - - if (local != remote) { - debug("havecached() => times differ"); - return 0; - } - if (fstat.st_size != r->clen) { - debug("havecached() => sizes differ"); - return 0; - } - return 1; -} - -int -opencache(struct req * r, int create) -{ - char buf[512]; - - if (!config.cache) - return -1; - - if (url_to_file(r->url, buf, sizeof(buf)) != 0) - return -1; - - if (config.online && create) - if (mktree(buf) != 0) - return -1; - - (void) strcpy(r->fname, buf); - (void) strcpy(r->lname, buf); - r->lname[strlen(buf)] = ','; - r->lname[strlen(buf) + 1] = '\0'; - - debug("opencache() => created lock file name (%s) for (%s)", r->lname, r->fname); - - return openfile(r, create); -} - -static int -lock(const struct req * r) -{ - if (link(r->fname, r->lname) != 0) { - debug("lock() => failed to lock file (%s)", r->fname); - return 1; - } - debug("lock() => LOCKED file (%s)", r->fname); - - return 0; -} - -int -unlock(const struct req * r) -{ - if (unlink(r->lname) != 0) { - debug("unlock() => failed to remove lock for file (%s)", r->fname); - return 1; - } - debug("lock() => UN-LOCKED file (%s)", r->fname); - - return 0; -} - -static int -islocked(const struct req * r) -{ - struct stat s; - - if (stat(r->lname, &s) == 0) { - debug("islocked() => file (%s) is locked", r->fname); - return 1; - } - return 0; -} - -void -closecache(int f, const struct req * r) -{ - (void) unlock(r); - (void) close(f); -} - -static int -mktree(char *path) -{ - size_t i, len; - - len = strlen(path); - i = 0; - if (path[i++] == '/' || len < 2) - return -1; - - while (i < len) { - if (path[i] == '/') { - path[i] = '\0'; - debug("mktree() => mkdir (%s)", path); - (void) mkdir(path, 0750); - path[i] = '/'; - } - i++; - } - - return 0; -} - -static int -url_to_file(const char *url, char *buf, size_t size) -{ - size_t i, j; - int passed_host; - char last; - - last = '.'; - j = strlen("http://"); - if (strlen(url) <= j || j >= size || url[j] == '/') - return -1; - if (strlen(cache_dir) >= size) - return -1; - (void) strcpy(buf, cache_dir); - i = strlen(cache_dir); - passed_host = 0; - while (i < size - 1 && url[j] != '\0' && - (isalnum(url[j]) || url[j] == '.' || url[j] == ',' - || url[j] == ':' || url[j] == '-' || url[j] == '_' - || url[j] == '/')) { - - if (last == '.' && url[j] == '.') { - buf[i] = '\0'; - return -1; - } - last = url[j]; - - if (!passed_host && url[j] == '/') - passed_host = 1; - - buf[i++] = url[j++]; - } - buf[i] = '\0'; - - if ((i < 2 || url[j] != '\0') && url[j] != '#') - return -1; - - if (buf[i - 1] == '/' || !passed_host) { - if (i + 2 + strlen(http_index) >= size) - return -1; - if (!passed_host) { - buf[i++] = '/'; - buf[i] = '\0'; - } - strcat(buf, http_index); - } - debug("url_to_file() => filename (%s)", buf); - - return 0; -} - -static int -openfile(const struct req * r, int create) -{ - int f; - - debug("openfile() => opening (%s) mode %d", r->fname, create); - - if (islocked(r)) { - debug("openfile() => file (%s) is locked", r->fname); - return -1; - } - if ((f = open(r->fname, create ? - (O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW) - : (O_RDONLY | O_NOFOLLOW), MODE_FILE)) < 0) { - debug("openfile() => error opening file (%s)", r->fname); - return -1; - } - if (create) - (void) lock(r); - - return f; -} diff -uNr ffproxy-1.4.1/cache.h ffproxy-1.5/cache.h --- ffproxy-1.4.1/cache.h Thu Jul 25 12:07:39 2002 +++ ffproxy-1.5/cache.h Thu Jan 1 00:00:00 1970 @@ -1,5 +0,0 @@ -int deliverfromcache(int, int, const struct req *); -int opencache(struct req *, int); -int havecached(const struct req *); -void closecache(int, const struct req *); -int unlock(const struct req *); diff -uNr ffproxy-1.4.1/cfg.h ffproxy-1.5/cfg.h --- ffproxy-1.4.1/cfg.h Sun Jul 20 09:51:54 2003 +++ ffproxy-1.5/cfg.h Sat Aug 9 02:02:22 2003 @@ -1,14 +1,16 @@ struct cfg { - unsigned long ip; unsigned int port; + + char ipv4[256]; + char ipv6[256]; int daemon; int childs; int ccount; int backlog; - int uid; - int gid; + unsigned long uid; + unsigned long gid; char chroot[256]; char dbdir[256]; char file[256]; @@ -19,9 +21,24 @@ int syslog; int logrequests; - int online; - int cache; - unsigned long cache_max_file_size; int use_ipv6; int aux_proxy_ipv6; + + int bind_ipv6; + int bind_ipv4; + + int accel; + int accelusrhost; + char accelhost[256]; + unsigned int accelport; + + int nowarn; + int first; }; + +#define MAX_CHILDS 1024 +#define MAX_BACKLOG 64 +#define MAX_PORTS 65535 +#define MAX_UID 65535 +#define MAX_GID MAX_UID +#define MAX_FSIZE 256*1024 diff -uNr ffproxy-1.4.1/db/access.dyndns ffproxy-1.5/db/access.dyndns --- ffproxy-1.4.1/db/access.dyndns Mon Jul 8 20:24:07 2002 +++ ffproxy-1.5/db/access.dyndns Fri Aug 8 12:00:41 2003 @@ -0,0 +1,10 @@ +# db/access.dyndns +# +# put hostnames with changing IPv4 addresses allowed to connect here +# empty lines and lines starting with # are ignored +# hostnames are resolved to IPv4 address, if IPv4 address matches +# IP address of connecting host, access is granted +# +# Example: +#myhost.dyndns.org +#dynip.myip.com diff -uNr ffproxy-1.4.1/db/access.host ffproxy-1.5/db/access.host --- ffproxy-1.4.1/db/access.host Mon Jul 8 22:53:14 2002 +++ ffproxy-1.5/db/access.host Fri Aug 8 12:10:20 2003 @@ -1 +1,15 @@ -^menuhin\.dpmurdock\.eu\.org$ +# db/access.host +# +# put IPv4 and IPv6 hostnames (reverse names) allowed to connect here +# use db/access.dyndns for hosts without proper reverse name +# use db/access.ip for IPv4 and IPv6 IP addresses +# empty lines and lines starting with # are ignored +# regular expression matching is used here, +# hostnames are converted to lowercase before matching +# +# Examples: +#^menuhin\.burden\.eu\.org$ +#^.*\.mydomain\.org$ +# +# This would allow everyone with a valid reverse name to connect: +#.* diff -uNr ffproxy-1.4.1/db/access.ip ffproxy-1.5/db/access.ip --- ffproxy-1.4.1/db/access.ip Thu Jul 25 11:58:39 2002 +++ ffproxy-1.5/db/access.ip Fri Aug 8 12:01:18 2003 @@ -1,2 +1,21 @@ -^192\.168\.10\.(1|2|3|128)$ -^127\.0\.0\.1$ +# db/access.ip +# +# put IPv4 and IPv6 addresses allowed to connect here +# empty lines and lines starting with # are ignored +# regular expression matching is used here +# +# Examples: +#^192\.168\.10\.(1|2|3|128)$ +#^127\.0\.0\.1$ +#^2001:768:18ff:4:: +#:bfcf%9005$ +# +# This allows everyone to connect: +#.* +# +# This allows everyone to connect via IPv6: +#: +# +# This allows everyone to connect via IPv4: +#\. +# diff -uNr ffproxy-1.4.1/db/filter.header.add ffproxy-1.5/db/filter.header.add --- ffproxy-1.4.1/db/filter.header.add Thu Jul 25 11:59:37 2002 +++ ffproxy-1.5/db/filter.header.add Thu Aug 7 19:51:06 2003 @@ -1,3 +1,13 @@ -User-Agent: Foo/5.3 (5.3; BarOS; BazCompatible; QuxExtension; QuuxDumb) +# db/filter.header.add +# +# put header entries to add to outgoing headers here +# use db/filter.header.entry to delete header entries via string matching +# use db/filter.header.match to delete header entries via regular expressions +# empty lines and lines starting with # are ignored +# +# Examples: +#User-Agent: Mozilla/4.0 (4.0; BarOS; BazCompatible; QuxExtension; QuuxDumb) +# +# The following entries should always be used: Connection: close Proxy-Connection: close diff -uNr ffproxy-1.4.1/db/filter.header.drop ffproxy-1.5/db/filter.header.drop --- ffproxy-1.4.1/db/filter.header.drop Mon Jul 8 20:48:11 2002 +++ ffproxy-1.5/db/filter.header.drop Fri Aug 8 12:10:56 2003 @@ -0,0 +1,9 @@ +# db/filter.header.drop +# +# put header entries here that cause ffproxy to drop entire request +# empty lines and lines starting with # are ignored +# string matching is performed here (case insensitive) +# +# Examples: +#Cookie: +#Session-Id: diff -uNr ffproxy-1.4.1/db/filter.header.entry ffproxy-1.5/db/filter.header.entry --- ffproxy-1.4.1/db/filter.header.entry Thu Jul 25 12:00:35 2002 +++ ffproxy-1.5/db/filter.header.entry Fri Aug 8 12:11:04 2003 @@ -1,9 +1,23 @@ -Accept-Language: -Language: -User-Agent: -From: -Set-Cookie: -Cookie: +# db/filter.header.entry +# +# put header entries to remove here +# use filter.header.add to add custom entries +# use filter.header.match to remove entries via regular expressions +# empty lines and lines starting with # are ignored +# string matching is performed here (case insensitive) +# +# Examples: +#Accept-Language: +#User-Agent: +#From: +# +# Prohibit cookie usage: +#Set-Cookie: +#Cookie: +# +# The following entries should always be used: +Accept-Encoding: +Accept: Connection: Proxy-Connection: Host: diff -uNr ffproxy-1.4.1/db/filter.header.match ffproxy-1.5/db/filter.header.match --- ffproxy-1.4.1/db/filter.header.match Mon Jul 8 15:28:21 2002 +++ ffproxy-1.5/db/filter.header.match Fri Aug 8 11:59:57 2003 @@ -0,0 +1,11 @@ +# db/filter.header.match +# +# put header entries to remove here +# use filter.header.add to add custom entries +# use filter.header.entry to remove entries without regular expressions +# empty lines and lines starting with # are ignored +# regular expression matching is performed here +# +# Examples: +#\*/\* +#iso-8859-([1-9]|1[0-4]) diff -uNr ffproxy-1.4.1/db/filter.host.match ffproxy-1.5/db/filter.host.match --- ffproxy-1.4.1/db/filter.host.match Thu Jul 25 12:01:48 2002 +++ ffproxy-1.5/db/filter.host.match Fri Aug 8 12:11:24 2003 @@ -1,24 +1,39 @@ -endemann -bannercommunity -doubleclick -sponsornetz -badservant -adult -xxx -sex -porn -gamez -warez -erotic -erotik -^ad(s|[0-9]*)\..* -^.*\.admaster.* -^adserver\..* -^adfarm.*\..* -^bs.*\.gmx\.net$ -^banner.*\..* -^finance\.altavista\..* -^werbung.*\..* -^213\.165\.64\.4.$ -^213\.165\.64\.3.$ -^rgs.*\.opera\.com$ +# db/filter.host.match +# +# put hosts disallowed connecting to here +# empty lines and lines starting with # are ignored +# regular expression matching is used, +# hostnames are converted to lower case before matching +# +# Examples: +# Don't get ads from hostnames matching these expressions: +#endemann +#bannercommunity +#doubleclick +#sponsornetz +#badservant +# +# Don't connect to `bad' sites: +#adult +#xxx +#sex +#porn +#gamez +#warez +#eroti[ck] +#erotik +# +# More ads: +#^ad(s|[0-9]*)\..* +#^.*\.admaster.* +#^adserver\..* +#^adfarm.*\..* +#^bs.*\.gmx\.net$ +#^banner.*\..* +#^finance\.altavista\..* +#^werbung.*\..* +# +# Don't allow Opera to connect to its secret servers: +#^213\.165\.64\.4.$ +#^213\.165\.64\.3.$ +#^rgs.*\.opera\.com$ diff -uNr ffproxy-1.4.1/db/filter.rheader.drop ffproxy-1.5/db/filter.rheader.drop --- ffproxy-1.4.1/db/filter.rheader.drop Mon Jul 8 21:11:50 2002 +++ ffproxy-1.5/db/filter.rheader.drop Fri Aug 8 12:11:36 2003 @@ -0,0 +1,16 @@ +# db/filter.rheader.drop +# response filtering +# +# put header entries here that cause ffproxy to drop entire response +# empty lines and lines starting with # are ignored +# string matching is performed here (case insensitive) +# +# Examples: +#Content-Type: application/ +# +# perhaps better: +#application/ +#audio/mpeg +# +#Cookie: +#Session-Id: diff -uNr ffproxy-1.4.1/db/filter.rheader.entry ffproxy-1.5/db/filter.rheader.entry --- ffproxy-1.4.1/db/filter.rheader.entry Thu Jul 25 12:02:48 2002 +++ ffproxy-1.5/db/filter.rheader.entry Fri Aug 8 12:11:43 2003 @@ -1,4 +1,16 @@ -Set-Cookie: -Cookie: +# db/filter.rheader.entry +# response filtering +# +# put header entries to remove from response here +# use filter.rheader.match to remove entries via regular expressions +# empty lines and lines starting with # are ignored +# string matching is performed here (case insensitive) +# +# Examples: +# Prohibit cookie usage: +#Set-Cookie: +#Cookie: +# +# The following entries should always be used: Connection: Proxy-Connection: diff -uNr ffproxy-1.4.1/db/filter.rheader.match ffproxy-1.5/db/filter.rheader.match --- ffproxy-1.4.1/db/filter.rheader.match Mon Jul 8 21:11:57 2002 +++ ffproxy-1.5/db/filter.rheader.match Fri Aug 8 12:02:10 2003 @@ -0,0 +1,10 @@ +# db/filter.rheader.match +# response filtering +# +# put header entries to remove from response here +# use filter.rheader.entry to remove entries without regular expressions +# empty lines and lines starting with # are ignored +# regular expression matching is performed here +# +# Examples: +#[Cc]ookie: diff -uNr ffproxy-1.4.1/db/filter.url.match ffproxy-1.5/db/filter.url.match --- ffproxy-1.4.1/db/filter.url.match Thu Jul 25 12:03:10 2002 +++ ffproxy-1.5/db/filter.url.match Fri Aug 8 12:02:19 2003 @@ -1,14 +1,26 @@ -WERBUNG -/RealMedia -/ads/ +# db/filter.url.match +# +# put URIs to filter here +# empty lines and lines starting with # are ignored +# regular expression matching is used +# +# Examples: +# Filter Ads: +#WERBUNG +#/ads/ +#/RealMedia +#\.ads/ +#ooperatio +#/advert +#banner/ +#/scripts/cms/ +#/xrps\.asp +#/event\.ng +# +# File types we don't like: +# (also use Content-Type filtering via db/filter.rheader.drop) +#\.com$ +#\.exe$ +#\.doc$ +# /\.\./ -\.ads/ -ooperatio -/advert -banner/ -/scripts/cms/ -/xrps\.asp -/event\.ng -\.com$ -\.exe$ -\.doc$ diff -uNr ffproxy-1.4.1/db.c ffproxy-1.5/db.c --- ffproxy-1.4.1/db.c Fri Aug 1 20:41:50 2003 +++ ffproxy-1.5/db.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: db.c,v 1.1 2003/08/01 20:41:49 niklas Exp niklas $ + * $Id: db.c,v 1.23 2003/08/09 03:38:04 niklas Exp $ * * 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 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "cfg.h" #include "print.h" @@ -41,7 +43,8 @@ static void read_db(const char *, char *[]); static void read_rdb(const char *, regex_t *[]); static void read_file(const char *, struct msg *); -static void read_config_file(void); +static void read_config_file(void); +static void verify_config(void); #define MAX_E 256 regex_t *a_ip[MAX_E]; @@ -61,7 +64,6 @@ struct msg e_con; struct msg e_post; struct msg e_fil; -struct msg e_nic; void @@ -77,6 +79,7 @@ extern struct cfg config; read_config_file(); + verify_config(); if (*config.dbdir != '\0' && chdir(config.dbdir) != 0) fatal("could not chdir() to dbdir (%s)", config.dbdir); @@ -98,7 +101,6 @@ read_file("html/connect", &e_con); read_file("html/post", &e_post); read_file("html/filtered", &e_fil); - read_file("html/notcached", &e_nic); } static void @@ -121,9 +123,7 @@ free(e_con.c); free(e_post.c); free(e_fil.c); - free(e_nic.c); - e_inv.len = e_res.len = e_con.len = e_post.len = 0; - e_fil.len = e_nic.len = 0; + e_inv.len = e_res.len = e_con.len = e_post.len = e_fil.len = 0; } static void @@ -162,9 +162,11 @@ i = 0; while (fgets(buf, sizeof(buf), fp) != NULL && i < MAX_E - 1) { + if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n') + continue; if ((p = strchr(buf, '\n')) == NULL) { (void) fclose(fp); - fatal("line too long in file %s", f); + fatal_n("line too long in file %s", f); } *p = '\0'; p = (char *) my_alloc(strlen(buf) + 1); @@ -190,15 +192,17 @@ i = 0; while (fgets(buf, sizeof(buf), fp) != NULL && i < MAX_E - 1) { + if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') + continue; if ((p = strchr(buf, '\n')) == NULL) { (void) fclose(fp); - fatal("line too long in file %s", f); + fatal_n("line too long in file %s", f); } *p = '\0'; regex = (regex_t *) my_alloc(sizeof(regex_t)); if ((err = regcomp(regex, buf, REG_EXTENDED)) != 0) { (void) regerror(err, regex, errbuf, sizeof(errbuf)); - warn("invalid regular expression (%s): %s", buf, errbuf); + warn("invalid regular expression (%s) in file (%s): %s", buf, f, errbuf); free(regex); continue; } @@ -229,7 +233,7 @@ #include "dns.h" -void +static void read_config_file(void) { extern struct cfg config; @@ -238,10 +242,12 @@ char abuf[100]; char b[300]; - if ((fp = fopen(config.file, "r")) != NULL) { + if (*config.file == '\0') { + ; + } else if ((fp = fopen(config.file, "r")) != NULL) { while (fgets(b, sizeof(b), fp) != NULL) { (void) sscanf(b, "%99s %99s", obuf, abuf); - if (strcmp("daemonize", obuf) == 0) { + if (config.first && strcmp("daemonize", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.daemon = 1; else @@ -250,10 +256,27 @@ } else if (strcmp("child_processes", obuf) == 0) { config.childs = atoi(abuf); continue; - } else if (strcmp("bind_to", obuf) == 0) { - config.ip = resolve(abuf); + } else if (config.first && strcmp("bind_ipv4", obuf) == 0) { + if (strcmp(abuf, "yes") == 0) + config.bind_ipv4 = 1; + else + config.bind_ipv4 = 0; continue; - } else if (strcmp("port", obuf) == 0) { + } else if (config.first && strcmp("bind_ipv6", obuf) == 0) { + if (strcmp(abuf, "yes") == 0) + config.bind_ipv6 = 1; + else + config.bind_ipv6 = 0; + continue; + } else if (config.first && strcmp("bind_ipv4_host", obuf) == 0) { + (void) strncpy(config.ipv4, abuf, sizeof(config.ipv4) - 1); + config.ipv4[sizeof(config.ipv4) - 1] = '\0'; + continue; + } else if (config.first && strcmp("bind_ipv6_host", obuf) == 0) { + (void) strncpy(config.ipv6, abuf, sizeof(config.ipv6) - 1); + config.ipv6[sizeof(config.ipv6) - 1] = '\0'; + continue; + } else if (config.first && strcmp("port", obuf) == 0) { config.port = atoi(abuf); continue; } else if (strcmp("use_ipv6", obuf) == 0) { @@ -262,13 +285,25 @@ else config.use_ipv6 = 0; continue; - } else if (strcmp("uid", obuf) == 0) { - config.uid = atoi(abuf); - continue; - } else if (strcmp("gid", obuf) == 0) { - config.gid = atoi(abuf); + } else if (config.first && strcmp("uid", obuf) == 0) { + if (!(config.uid = atoi(abuf))) { + struct passwd *pwd; + if ((pwd = getpwnam(abuf))) + config.uid = (unsigned long) pwd->pw_uid; + else + fatal_n("UID %s not found", abuf); + } + continue; + } else if (config.first && strcmp("gid", obuf) == 0) { + if (!(config.gid = atoi(abuf))) { + struct group *grp; + if ((grp = getgrnam(abuf))) + config.gid = (unsigned long) grp->gr_gid; + else + fatal_n("GID %s not found", abuf); + } continue; - } else if (strcmp("chroot_dir", obuf) == 0) { + } else if (config.first && strcmp("chroot_dir", obuf) == 0) { (void) strncpy(config.chroot, abuf, sizeof(config.chroot) - 1); config.chroot[sizeof(config.chroot) - 1] = 0; continue; @@ -285,7 +320,7 @@ else config.aux_proxy_ipv6 = 0; continue; - } else if (strcmp("db_files_path", obuf) == 0) { + } else if (config.first && strcmp("db_files_path", obuf) == 0) { (void) strncpy(config.dbdir, abuf, sizeof(config.dbdir) - 1); config.dbdir[sizeof(config.dbdir) - 1] = 0; continue; @@ -304,20 +339,20 @@ else config.logrequests = 0; continue; - } else if (strcmp("use_cache", obuf) == 0) { - if (strcmp(abuf, "yes") == 0) - config.cache = 1; - else - config.cache = 0; + } else if (strcmp("accel_host", obuf) == 0) { + (void) strncpy(config.accelhost, abuf, sizeof(config.accelhost) - 1); + config.accelhost[sizeof(config.accelhost) - 1] = '\0'; continue; - } else if (strcmp("cache_max_file_size", obuf) == 0) { - config.cache_max_file_size = atoi(abuf) * 1024; + } else if (strcmp("accel_port", obuf) == 0) { + config.accelport = atoi(abuf); continue; - } else if (strcmp("use_ipv6", obuf) == 0) { + } else if (strcmp("accel_user_host", obuf) == 0) { if (strcmp(abuf, "yes") == 0) - config.use_ipv6 = 1; + config.accelusrhost = 1; else - config.use_ipv6 = 0; + config.accelusrhost = 0; + continue; + } else if (!config.first) { continue; } else if (*obuf != '#') { warn("unknown option in config file %s: %s", config.file, obuf); @@ -325,5 +360,38 @@ } } (void) fclose(fp); + } else { + if (strcmp(config.file, CFGFILE) == 0) + info("default config file (%s) not available, not using config file", CFGFILE); + else + fatal("unable to open config file %s", config.file); } + config.first = 0; +} + +#define ZHWRONG(a, o, v) if(a < 1 || a > v) fatal_n("%s is set < 1 or value is too high (maximum: %d, current: %d)", o, v, a); +#define HWRONG(a, o, v) if(a < 0 || a > v) fatal_n("Value of %s is set too high or negative (maximum: %d, current: %d)", o, v, a); +#define HUWRONG(a, o, v) if(a > v) fatal_n("Value of %s is set too high (maximum: %d, current: %d)", o, v, a); + +static void +verify_config(void) +{ + extern struct cfg config; + + HUWRONG(config.port, "port", MAX_PORTS); + ZHWRONG(config.childs, "child_processes", MAX_CHILDS); + HWRONG(config.backlog, "backlog_size", MAX_BACKLOG); + HUWRONG(config.proxyport, "forward_proxy_port", MAX_PORTS); + HUWRONG(config.uid, "uid", MAX_UID); + HUWRONG(config.gid, "gid", MAX_GID); + HUWRONG(config.accelport, "accel_port", MAX_PORTS); + + if ((config.uid && !config.gid) || (!config.uid && config.gid)) + fatal_n("Only one of uid and gid is set to non-zero.\nYou have to use both or none of them"); + if (*config.accelhost && config.accelport) + config.accel = 1; + else + config.accel = 0; + if (!config.bind_ipv4 && !config.bind_ipv6) + fatal_n("Both IPv4 and IPv6 binding disabled. This makes no sense"); } diff -uNr ffproxy-1.4.1/db.h ffproxy-1.5/db.h --- ffproxy-1.4.1/db.h Thu Jul 25 12:07:39 2002 +++ ffproxy-1.5/db.h Fri Aug 8 13:12:46 2003 @@ -1,2 +1,2 @@ -void load_databases(void); +void load_databases(void); void reload_databases(void); diff -uNr ffproxy-1.4.1/dns.c ffproxy-1.5/dns.c --- ffproxy-1.4.1/dns.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/dns.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: dns.c,v 1.6 2003/07/20 10:38:23 niklas Exp $ + * $Id: dns.c,v 1.7 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -28,17 +28,19 @@ #include #include #include -#include #include "req.h" #include "alloc.h" +#include "print.h" #include "dns.h" -unsigned long +static char *ip_to_a(in_addr_t); + +in_addr_t resolve(const char *h) { struct hostent *hp; - unsigned long ip; + in_addr_t ip; if ((ip = inet_addr(h)) != INADDR_NONE) return ip; @@ -51,8 +53,8 @@ } } -char * -ip_to_a(int ip) +static char * +ip_to_a(in_addr_t ip) { char *p; struct in_addr addr; @@ -74,30 +76,20 @@ } struct clinfo * -identify(const struct sockaddr_in * addr) +identify(const struct sockaddr * addr, socklen_t salen) { struct clinfo *host; - struct hostent *hp; - struct in_addr ip; host = (struct clinfo *) my_alloc(sizeof(struct clinfo)); (void) memset(host, 0, sizeof(struct clinfo)); - (void) strncpy(host->ip, inet_ntoa(addr->sin_addr), sizeof(host->ip) - 1); - host->ip[sizeof(host->ip) - 1] = '\0'; - - if ((hp = gethostbyaddr((char *) &addr->sin_addr, sizeof(addr->sin_addr), AF_INET)) != NULL) { - (void) strncpy(host->name, hp->h_name, sizeof(host->name) - 1); - host->name[sizeof(host->name) - 1] = '\0'; - } else + if (getnameinfo(addr, salen, host->name, sizeof(host->name), NULL, 0, NI_NAMEREQD)) *host->name = '\0'; + DEBUG(("identify() => getnameinfo() for Reverse Name returned (%s)", host->name)); - if ((hp = gethostbyname(host->name)) != NULL) { - (void) memcpy(&ip.s_addr, hp->h_addr, hp->h_length); - (void) strncpy(host->rip, inet_ntoa(ip), sizeof(host->rip) - 1); - host->rip[sizeof(host->rip) - 1] = '\0'; - } else - *host->rip = '\0'; + if (getnameinfo(addr, salen, host->ip, sizeof(host->ip), NULL, 0, NI_NUMERICHOST)) + *host->ip = '\0'; + DEBUG(("identify() => getnameinfo() for IP Address returned (%s)", host->ip)); return host; } diff -uNr ffproxy-1.4.1/dns.h ffproxy-1.5/dns.h --- ffproxy-1.4.1/dns.h Thu Jul 25 12:07:39 2002 +++ ffproxy-1.5/dns.h Fri Aug 8 21:47:15 2003 @@ -1,6 +1,11 @@ #include +#include +#include -unsigned long resolve(const char *); -char *ip_to_a(int); +#ifndef INADDR_NONE +#define INADDR_NONE -1 +#endif + +in_addr_t resolve(const char *); char *resolve_to_a(const char *); -struct clinfo *identify(const struct sockaddr_in *); +struct clinfo *identify(const struct sockaddr *, socklen_t); diff -uNr ffproxy-1.4.1/ffproxy.8 ffproxy-1.5/ffproxy.8 --- ffproxy-1.4.1/ffproxy.8 Fri Aug 1 20:42:00 2003 +++ ffproxy-1.5/ffproxy.8 Sat Aug 9 15:13:01 2003 @@ -1,8 +1,8 @@ -.\" $Id: ffproxy.8,v 1.42 2003/08/01 20:41:49 niklas Exp niklas $ +.\" $Id: ffproxy.8,v 1.8 2003/08/09 00:41:31 niklas Exp $ .\" Copyright (c) 2002, 2003 Niklas Olmes .\" See COPYING for license (GNU GPL) .\" http://faith.eu.org -.Dd August 1, 2003 +.Dd August 9, 2003 .Dt ffproxy 8 .Sh NAME .Nm ffproxy @@ -11,17 +11,16 @@ .Nm ffproxy .Op Fl p Ar port .Op Fl c Ar ip|hostname +.Op Fl C Ar ip|hostname .Op Fl l Ar childs -.Op Fl u Ar uid Fl g Ar gid +.Op Fl u Ar uid|user Fl g Ar gid|group .Op Fl r Ar dir -.Op Fl x Ar proxyip|proxyhost Fl X Ar proxyport .Op Fl D Ar datadir +.Op Fl x Ar proxyip|proxyhost Fl X Ar proxyport +.Op Fl a Ar ip|hostname +.Op Fl A Ar port .Op Fl f Ar configfile -.Op Fl d -.Op Fl s -.Op Fl 4 -.Op Fl h -.Op Fl v +.Op Fl ds4bBhv .Sh DESCRIPTION .Nm ffproxy is a filtering HTTP proxy server. It is able to filter @@ -32,58 +31,80 @@ directory. Logging to .Xr syslogd 8 is supported, as is using another auxiliary proxy server. -Contacting IPv6 servers is supported since version 1.4. +IPv6 is fully supported and allows IPv6 HTTP over IPv4 +tunneling (and vice versa). +.Pp +Remind that there is an alternative to command line options +by using configuration files. See +.Xr ffproxy.conf 5 +and +.Pa sample.config +for details. It allows options that are not available +on command line. .Pp -The following options are recognized. They specify general -settings like IP to bind to or place of the db/ and html/ +The following command line options are recognized. They specify +general settings like IP to bind to or place of the db/ and html/ directories. Note that arguments to options must be seperated -from the option by spaces, as are options from each other. -Please notice that there is an alternative to command line options -by using the command line option -f to specify a user configuration -file to load. See sample.conf for details and description. It may -contain options that are not available on command line. Default -location for config file is /etc/ffproxy.conf, default location -for ffproxy's working directory is /var/ffproxy. +from the option by spaces, as are such options from each other. .Pp .Bl -tag -width "message" .It Fl p Ar port Bind to port. Default is 8080. .It Fl c Ar ip|hostname -Bind to IP (or hostname). Default is any IP. IPv6 is unsupported here. +Bind to IPv4. Default is any IPv4. +.It Fl C Ar ip|hostname +Bind to IPv6. Default is any IPv6. .It Fl l Ar childs Maximum number of child processes to be forked. That is, the maximum number of concurrent requests allowed. Default is 10. -.It Fl u Ar uid Fl g Ar gid -Change UID and GID. If at least one of these two options is set -to zero, the feature is completely disabled. +.It Fl u Ar uid|user Fl g Ar gid|group +Change UID and GID. Both options must be used. Default is +not changing UID and GID. .It Fl r Ar dir Change root .Xr chroot 7 to dir. Used in conjunction with -u and -g. Because ffproxy -drops its privileges and chroots after reading the config files, --D should be set to . (the current dir). Example: -/usr/local/bin/ffproxy -r /var/ffproxy -D . -u 50 -g 50 +drops its privileges and chroots after reading the configuration files, +-D should be set to . (the current dir). It might need +.Pa /etc/resolv.conf +copied as etc/resolv.conf in its working directory. Example: +``# cd /var/ffproxy ; /usr/local/bin/ffproxy -r /var/ffproxy -D . -d -u proxy -g proxy -f ""'' .It Fl x Ar ip|hostname Specify IP (or hostname) of an auxiliary proxy server that -ffproxy will forward requests to. Used together with -X. IPv6 -is supported. +the program will forward requests to. Used together with -X. .It Fl X Ar port Port number of auxiliary proxy. .It Fl D Ar dir Location of the db/ and html/ directories. For example, -specifying -D /var/ffproxy would tell ffproxy to search +specifying -D /var/ffproxy tells the proxy to search for db/ files in .Pa /var/ffproxy/db/ and html/ files in .Pa /var/ffproxy/html/ . +.It Fl a Ar ip|hostname +Auxiliary forward HTTP server to use (see section ACCELERATOR). +.It Fl A Ar port +Port to use for above. Defaults to 80. .It Fl f Ar configfile -User configuration file to load. +User configuration file to load. Please note that command +line options get overwritten by set configuration file options. +Default location is +.Pa /etc/ffproxy.conf . +Read +.Xr ffproxy.conf 5 +for details. Use -f "" to disable configuration files. .It Fl d Run as daemon. .It Fl s Be silent. Don't log to syslog. .It Fl 4 Use IPv4 only. Do not try contacting servers via IPv6. +.It Fl b +Don't bind to IPv4. Might be needed under Linux 2.4, due to a ``Feature'' +IPv6 binds to IPv4, too. Try using this option or bind to specific +IPv6 address via -C. +.It Fl B +Don't bind to IPv6. .It Fl h Show usage information. .It Fl v @@ -96,46 +117,102 @@ `host'. .Ss Filtering Requests or header entries to be filtered are matched by extended -regular expressions. +regular expressions or case insensitive by strings. .Pp ffproxy is able to filter requests by host, header, remote header, and URL. The specific files are -.Ar filter.host.match , filter.header.* , filter.rheader.* , filter.url.match . .Pp -Files ending in `drop' specify requests to be completely filtered. -Files ending in `entry' specify header entries to be filtered. +.Bl -tag -width xxxx -compact -offset indent +.It Ar filter.host.match +.It Ar filter.header.drop +.It Ar filter.header.entry +.It Ar filter.header.match +.It Ar filter.rheader.drop +.It Ar filter.rheader.entry +.It Ar filter.rheader.match +.It Ar filter.url.match +.El +.Pp +Files ending in `drop' specify requests to be completely filtered (dropped). +Files ending in `entry' specify header entries to be removed from the header. They are matched case insensitive without extended regular expressions. Files ending in `match' specify extended regular expressions to be -matched against header entries. If a match occurs, the corresponding line -is removed from the header. +matched against header entries, host, or URL. .Pp Adding custom header entries is also supported. The entries of file .Pa filter.header.add will be added to every outgoing request. .Ss Access Control -Access to ffproxy is controlled through the files named `host'. +Access to the proxy is controlled through the files prefixed `host'. +.Pp .Pa host.dyndns contains host names with dynamic -IP addresses. +IPv4 addresses. The host names are resolved to IPv4 addresses and +compared to the client's IP. If it matches, access is granted. +.Pp .Pa host.ip -contains static IP address. And -finally, +contains static IPv4 and IPv6 address. +.Pp .Pa host.name -contains official hostnames -(reverse lookup). Except for +contains official hostnames (reverse lookup). +.Pp +Except for .Pa host.dyndns , the files contain extended regular expressions. -If any of the entries matches, access -is granted. +If any of the entries matches, access is granted. .Ss Layout of db/ Files Every mentioned file above must exist, although it may be empty. -Every entry is exact one line. Comments are not allowed. +Every entry is exactly one line. Empty lines are ignored, as +are lines beginning with a # (comments). +.Pp The location of the db/ directory may be specified by an argument to the command line option -D. -If this option and config file option db_files_path are not used, -ffproxy will search for db/ and html/ in /var/ffproxy. +If this option and configuration file option db_files_path are not used, +ffproxy will search for db/ and html/ in +.Pa /var/ffproxy . +.Pp +ffproxy comes with sample db/ files. They also contain +needed and suggested entries, as described next. +.Ss Suggested db/ file entries +The file +.Pa filter.header.entry +should contain following entries for the program's proper operation +.Bd -literal -offset indent +Accept-Encoding: +Accept: +Connection: +Proxy-Connection: +Host: +.Ed +.Pp +First two lines are needed for browsers that send out Accept*: Headers +but don't understand encoded data coming back from the proxy. +Host: has to be removed, since proxies require absolute URIs +(Host: is redundant). +.Pp +.Pa filter.header.add +should contain +.Bd -literal -offset indent +Connection: close +Proxy-Connection: close +.Ed +.Pp +We removed the two entries through +.Pa filter.header.entry +and now implant our own to force disconnection after each +request. +.Pp +.Pa filter.rheader.entry +should contain +.Bd -literal -offset indent +Connection: +Proxy-Connection: +.Ed +.Pp +Whatever the server answered, we remove it. .Sh THE HTML/ DIRECTORY -This directory contains HTML files that are sent to +This directory contains files with HTTP header +and HTML that are sent to the user's browser if either an error occured or a request was filtered. In the files, the variable .Va $u @@ -144,20 +221,65 @@ by the host to connect to, and .Va $c by the hostname of the client. +.Pp +Since the files are loaded into memory for faster +execution, the size of each file is limited to +about 8 kB (what is more than enough, the default +files are under 1 kB). +.Pp +The specific files are (every file must exist) +.Pp +.Bl -tag -width xxxxxxxxxxx -compact -offset indent +.It Ar connect +Connection failed (503) +.It Ar filtered +Request filtered (200) +.It Ar invalid +Invalid request (400) +.It Ar post +Unable to post data (400) +.It Ar resolve +Resolve error (503) +.El +.Sh HTTP ACCELERATOR +ffproxy may also be used as a HTTP accelerator, that +is, connecting to just one HTTP server and beeing +a front-end to that. Use accel_host and accel_port +in configuration file or command line options -a and -A +to use this feature. +.Pp +Default behaviour is *not* sending Host: header to +allow insertion of a custom one via +.Pa filter.header.add +(see section THE DB/ DIRECTORY) +or keeping the original one used by connecting client +(`Host:' hast to be removed from default +.Pa filter.header.entry , +of course). To change this, use `accel_user_host no' +in configuration file. ``Host: accel_host:accel_port'' +will be used then. .Sh RELOADING CONFIGURATION Send a SIGHUP to the pid of the ffproxy master process -to let it reload db/ and html/ files. -If daemonized, ffproxy writes the pid file +to let it reload db/ files, html/ files, *and* configuration file. +If no configuration file was specified, +.Pa /etc/ffproxy.conf +is tried. Of course, only some changes to the program can be +done at runtime. See +.Xr ffproxy.conf 5 +for details on options that may be changed at runtime. +.Pp +If daemonized, the master process writes the pid file .Pa ffproxy.pid to the working directory, that is, the directory -specified by db_path or the command line parameter -D. -It defaults to /var/ffproxy. +specified by db_files_path or the command line parameter -D. +It defaults to +.Pa /var/ffproxy . +The program will terminate if writing fails. .Sh LOGGING -By default, ffproxy logs incorrect and filtered requests. -Connection attempts from disallowed hosts get logged, -too. To log all requests, use the config file keyword +By default, the proxy logs incorrect and filtered requests. +To log all requests, use the configuration file keyword `log_all_requests yes'. Please make sure that you seperate -ffproxy's log output from that of other programs by modifying +the programs log output from that of other programs by modifying .Xr syslog.conf 5 , since the output is very noisy. .Sh FILES @@ -165,8 +287,9 @@ .Bl -bullet .It startup options given either on the command line -or read from configuration files -(/etc/ffproxy.conf is loaded by default) +or read from configuration files -- +.Pa /etc/ffproxy.conf +is loaded by default. .It the files in db/ which specify filtering options and who is allowed to connect and use ffproxy @@ -175,17 +298,22 @@ If daemonized, ffproxy writes the pid of its master process to the file named .Pa ffproxy.pid -in its working directory (/var/ffproxy by default). +in its working directory -- +.Pa /var/ffproxy +by default. .Sh SEE ALSO -.Pa README -file for some configuration examples and general explanation -.Pp .Pa sample.config for a sample configuration file .Pp .Pa /etc/ffproxy.conf for default configuration file .Pp +.Xr ffproxy.conf 5 +for details on config file +.Pp +.Xr ffproxy.quick 7 +for a short description of how to set up the proxy +.Pp .Pa http://faith.eu.org/programs.html for latest version and patches .Pp @@ -194,11 +322,11 @@ .Xr syslogd 8 , .Xr chroot 2 , .Xr kill 1 +.Sh CONTRIBUTORS +Dobrica Pavlinusic +provided patches for http accelerator feature .Sh VERSION -This manual documents ffproxy 1.4.1 (2003-08-01). -.Sh BUGS -Although contacting IPv6 servers is supported since version 1.4, -binding and listening to IPv6 is not yet supported. +This manual documents ffproxy 1.5 (2003-08-09). .Pp Send bug reports, comments, suggestions to .Sh AUTHOR diff -uNr ffproxy-1.4.1/ffproxy.conf.5 ffproxy-1.5/ffproxy.conf.5 --- ffproxy-1.4.1/ffproxy.conf.5 Thu Jan 1 00:00:00 1970 +++ ffproxy-1.5/ffproxy.conf.5 Sat Aug 9 15:13:01 2003 @@ -0,0 +1,204 @@ +.\" $Id: ffproxy.conf.5,v 1.9 2003/08/09 12:18:58 niklas Exp $ +.\" Copyright (c) 2002, 2003 Niklas Olmes +.\" See COPYING for license (GNU GPL) +.\" http://faith.eu.org +.Dd August 9, 2003 +.Dt ffproxy.conf 5 +.Sh NAME +.Nm ffproxy.conf +.Nd filtering HTTP proxy server configuration file +.Sh DESCRIPTION +.Nm ffproxy +is a filtering HTTP proxy server. It is able to filter +by host, url, and header. Custom header entries can be filtered +and added. It can even drop its privileges and +.Xr chroot 2 +to some +directory. Logging to +.Xr syslogd 8 +is supported, as is using another auxiliary proxy server. +IPv6 is fully supported and allows IPv6 HTTP over IPv4 +tunneling (and vice versa). +.Pp +This manual describes how to use configuration files with the program +and documents the options. +.Sh USING CONFIGURATION FILES +.Ss Default ffproxy.conf +If the command line parameters -f or -F are not used, the proxy +tries to open +.Pa /etc/ffproxy.conf . +If this file does not exist, the program continues execution. +.Ss User Configuration File +Use command line parameter -f to load a non-default configuration +file. You will notice the warning at the program's startup. This +is due to the programs implementation that allows to reload +all configuration files. To disable the warning, use -F instead. +.Ss Deactivating +To use command line options only, use -f "". +.Ss Reloading Configuration +To let the proxy reload its configuration files, that is, besides +the configuration file specified, the contents of db/ and html/, +send the signal HUP to the program's master process. If +ffproxy runs daemonized, the PID can be found in +.Pa db_files_path/ffproxy.conf . +Otherwise look into your system's syslog log files or process table. +.Pp +Options that can be successfully altered at runtime are +.Bd -literal -offset indent +child_processes +use_ipv6 +use_syslog +log_all_requests +forward_proxy +forward_proxy_port +forward_proxy_ipv6 +accel_host +accel_port +accel_user_host +backlog_size +.Ed +.Pp +Set `accel_port 0' or `forward_proxy_port 0' to explicitly disable +acceleration or auxiliary proxy. Commenting out options is not +sufficient, since configuration options may only overwritten. +.Pp +Changes to other options not mentioned above get silently ignored. +.Sh CONFIGURATION OPTIONS +.Bd -literal +# +# lines starting with '#' are comments +# + +# run as daemon? +# (default: no) +#daemonize yes +#daemonize no + +# number of child processes, +# that is, the maximum number of concurrent requests +# (default: 10) +#child_processes 10 + +# ffproxy binds to any IPv4 address +# and any IPv6 address by default +# +# bind to IPv4? (default: yes) +#bind_ipv4 no +#bind_ipv4 yes +# bind to IPv6? (default: yes) +#bind_ipv6 no +#bind_ipv6 yes +# +# Hostname or IP to bind to +# (default is any IP) +# +#bind_ipv4_host 192.168.10.1 +#bind_ipv4_host martyr.burden.eu.org +#bind_ipv6_host ::1 +#bind_ipv6_host oz.burden.eu.org + +# listen on port +# (default: 8080) +#port 1111 +#port 8080 + +# use IPv6 when contacting servers? +# (default: yes) +#use_ipv6 no +#use_ipv6 yes + +# use syslog? +# (default: yes) +#use_syslog no +#use_syslog yes + +# log all requests? +# (default: no) +# to use, set also use_syslog to yes +#log_all_requests yes +#log_all_requests no + +# change UID and GID +# +# to use, both uid and gid must be set +# (disabled by default) +#uid proxy +#gid proxy +#uid 37 +#gid 38 + +# change root to (only in connection with uid and gid change) +# /etc/resolv.conf might need to be copied +# to chroot_dir/etc/resolv.conf +# (disabled by default) +#chroot_dir /var/ffproxy + +# forward to proxy (auxiliary proxy) +# (set `forward_proxy_port 0' to explicitly disable feature +# (i.e, when reloading configuration file via SIGHUP)) +# (disabled by default) +#forward_proxy blackness.burden.eu.org +#forward_proxy 192.168.10.5 +#forward_proxy ::1 +#forward_proxy_port 8082 +#forward_proxy_port 0 + +# try IPv6 for auxiliary proxy? +# use_ipv6 must be set to yes, too +# (default: yes) +#forward_proxy_ipv6 no +#forward_proxy_ipv6 yes + +# path to db/ and html/ directories +# (default: /var/ffproxy) +# (Note: if ffproxy runs chrooted, +# give a path name relative to new root, or, +# if db_files_path is the same as root, use db_files_path ./ +# You have to start ffproxy in the new root directory, +# otherwise it won't find the database files. +# Please keep in mind that ffproxy's config file has to +# be within chroot directory, otherwise it will not find +# its config file on reload) +#db_files_path ./ +#db_files_path /var/ffproxy + +# http accelerator +# (disabled by default) +# +# if you want to use ffproxy as http accelerator (that is, connecting +# to just one http server and beeing used as front-end to that, e.g. +# in DMZ) uncomments options below (port is optional, defaults to 80) +# (set `accel_port 0' to explicitly disable feature +# (i.e, when reloading configuration file via SIGHUP)) +#accel_host 10.254.1.2 +#accel_host revelation.martyr.eu.org +#accel_port 80 +#accel_port 0 +# +# Omit Host: accel_host:accel_port in Header +# to provide own Host: header via db/filter.header.add? +# (default: yes) +#accel_user_host no +#accel_user_host yes + +# backlog size for accept() +# (default: 4) +#backlog_size 16 +#backlog_size 4 +.Ed +.Sh VERSION +This manual documents ffproxy 1.5 (2003-08-09). +.Sh FILES +.Pa /etc/ffproxy.conf +default configuration file +.Pp +.Pa sample.config +sample configuration file +.Sh SEE ALSO +.Xr ffproxy 8 , +.Xr ffproxy.quick 7 , +.Xr regex 7 , +.Xr re_format 7 , +.Xr syslogd 8 , +.Xr chroot 2 , +.Xr kill 1 diff -uNr ffproxy-1.4.1/ffproxy.quick.7 ffproxy-1.5/ffproxy.quick.7 --- ffproxy-1.4.1/ffproxy.quick.7 Thu Jan 1 00:00:00 1970 +++ ffproxy-1.5/ffproxy.quick.7 Sat Aug 9 15:13:01 2003 @@ -0,0 +1,127 @@ +.\" $Id: ffproxy.quick.7,v 1.5 2003/08/09 00:15:33 niklas Exp $ +.\" Copyright (c) 2002, 2003 Niklas Olmes +.\" See COPYING for license (GNU GPL) +.\" http://faith.eu.org +.Dd August 9, 2003 +.Dt ffproxy.quick 7 +.Sh NAME +.Nm ffproxy.quick +.Nd filtering HTTP proxy server quick introduction +.Sh DESCRIPTION +.Nm ffproxy +is a filtering HTTP proxy server. It is able to filter +by host, url, and header. Custom header entries can be filtered +and added. It can even drop its privileges and +.Xr chroot 2 +to some +directory. Logging to +.Xr syslogd 8 +is supported, as is using another auxiliary proxy server. +IPv6 is fully supported and allows IPv6 HTTP over IPv4 +tunneling (and vice versa). +.Pp +This manual describes how to set up a basic HTTP proxy installation. +It is assumed that you already have compiled the program or +installed it via port or package. +.Sh COPYING FILES +The program comes with default configuration files that contain +both examples and suggested entries. You can simply copy them to +a directory of your choice. This directory will become the program's +working directory. +.Bd -literal -offset indent +mkdir /var/ffproxy +tar cf - db/ html/ | ( cd /var/ffproxy ; tar xf - ) +cp sample.config /var/ffproxy/ffproxy.conf +.Ed +.Pp +Above example would install all needed files to +.Pa /var/ffproxy , +which is ffproxy's default working directory. +.Sh SECURING +The proxy now has its own working directory. By default, +ffproxy does not change UID/GID after start. For security +reasons we want to enable it. You have two choices know: +Either use existing UID/GID or add custom UID/GID for ffproxy. +See +.Xr adduser 8 +or +.Xr useradd 8 , +depending on your system, on how to create new IDs. +.Pp +Edit +.Pa ffproxy.conf +and change the lines containing uid and gid +.Bd -literal -offset indent +# change UID and GID +# +# to use, both uid and gid must be set +# (disabled by default) +#uid proxy +#gid proxy +uid _ffproxy +gid _ffproxy +.Ed +.Pp +In addition to changing UID and GID, ffproxy should be +executed change-rooted to its working directory. So we +change chroot_dir and db_files_path in the configuration file +.Bd -literal -offset indent +# change root to (only in connection with uid and gid change) +# (disabled by default) +chroot_dir /var/ffproxy + +# path to db/ and html/ directories +# (default: /var/ffproxy) +db_files_path . +.Ed +.Pp +db_files_path must be changed, too, since that is relative +to new root. Finally, we copy /etc/resolv.conf to ffproxy's +home to enable DNS in chroot and chown /var/ffproxy so +the proxy's master process can write its PID file +.Bd -literal -offset indent +mkdir /var/ffproxy/etc +cp /etc/resolv.conf /var/ffproxy/etc/ +chmod 750 /var/ffproxy +chown _ffproxy._ffproxy /var/ffproxy +.Ed +.Sh ACCESS TO THE PROXY +By default, nobody is allowed to connect to ffproxy. +Let's say, we want to provide LAN users a filtering proxy +to shut down malicous content coming from the Internet. +So the proxy has to be listening on the local network +interface only. We change bind_ipv4 and bind_ipv6 +appropiately in +.Pa ffproxy.conf +.Bd -literal -offset indent +bind_ipv4 martyr.burden.eu.org +bind_ipv6 martyr.burden.eu.org +.Ed +.Pp +Additionally, we have to change +.Pa db/access.ip . +By, for example, +.Bd -literal -offset indent +^192\\.168\\.10\\. +.Ed +.Pp +we allow 192.168.10.0/24 to use our proxy. +.Sh STARTING THE PROXY +Last step is starting ffproxy. Keep in mind that +we run the program change-rooted to /var/ffproxy, +so files are relative to new root. +.Bd -literal -offset indent +cd /var/ffproxy ; /usr/local/bin/ffproxy -f ffproxy.conf +.Ed +.Pp +starts ffproxy. Now test if it works correctly. +If not, change ffproxy.conf and/or read +.Xr ffproxy 8 +.Xr ffproxy.conf 5 +.Pp +ffproxy is not running as daemon right know. If everything +seems to work, simply shut down the proxy by pressing +CTRL-C, set `daemonize yes' in the configuration file and +start ffproxy again. +.Sh VERSION +This manual documents ffproxy 1.5 (2003-08-09). diff -uNr ffproxy-1.4.1/filter.c ffproxy-1.5/filter.c --- ffproxy-1.4.1/filter.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/filter.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: filter.c,v 1.8 2003/07/20 10:38:23 niklas Exp $ + * $Id: filter.c,v 1.10 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -55,10 +55,10 @@ i = 0; start_over: while (r->header[i] != NULL && i < sizeof(r->header) - 2) { - debug("filter_request() => header entry %d (%s)", i, r->header[i]); + DEBUG(("filter_request() => header entry %d (%s)", i, r->header[i])); if (strncasecmp(r->header[i], loop_header, strlen(loop_header)) == 0) { - debug("filter_request() => LOOP DETECTED"); + DEBUG(("filter_request() => LOOP DETECTED")); r->loop = 1; return -1; } @@ -98,7 +98,7 @@ r->header[i] = (char *) my_alloc(strlen(loop_header) + 1); (void) strcpy(r->header[i], loop_header); - debug("filter_request() => added loop header[%d] (%s)", i, r->header[i]); + DEBUG(("filter_request() => added loop header[%d] (%s)", i, r->header[i])); i++; j = 0; @@ -106,12 +106,12 @@ r->header[i] = (char *) my_alloc(strlen(f_hdr_add[j]) + 1); (void) strcpy(r->header[i], f_hdr_add[j]); - debug("filter_request() => added header[%d] (%s)", i, r->header[i]); + DEBUG(("filter_request() => added header[%d] (%s)", i, r->header[i])); i++, j++; } r->header[i] = NULL; - debug("filter_request() => done, request ok"); + DEBUG(("filter_request() => done, request ok")); return 0; } @@ -124,10 +124,10 @@ i = 0; start_over: while (r->header[i] != NULL) { - debug("filter_remote() => remote header entry %d (%s)", i, r->header[i]); + DEBUG(("filter_remote() => remote header entry %d (%s)", i, r->header[i])); if (strncasecmp(r->header[i], loop_header, strlen(loop_header)) == 0) { - debug("filter_request() => LOOP DETECTED"); + DEBUG(("filter_request() => LOOP DETECTED")); r->loop = 1; return -1; } @@ -161,7 +161,7 @@ } - debug("filter_remote() => done, request ok"); + DEBUG(("filter_remote() => done, request ok")); return 0; } @@ -170,10 +170,10 @@ static void rotate(int i, char *a[]) { - if (a[i] == NULL) - debug("rotate() => entry to rotate, %d, is NULL", i); - else { - debug("rotate() => freeing a[%d] == (%s)", i, a[i]); + if (a[i] == NULL) { + DEBUG(("rotate() => entry to rotate, %d, is NULL", i)); + } else { + DEBUG(("rotate() => freeing a[%d] == (%s)", i, a[i])); free(a[i]); a[i] = a[i + 1]; if (a[i + 1] != NULL) { @@ -185,5 +185,5 @@ } } - debug("rotate() => done"); + DEBUG(("rotate() => done")); } diff -uNr ffproxy-1.4.1/html/notcached ffproxy-1.5/html/notcached --- ffproxy-1.4.1/html/notcached Tue Jul 9 11:45:11 2002 +++ ffproxy-1.5/html/notcached Thu Jan 1 00:00:00 1970 @@ -1,16 +0,0 @@ -HTTP/1.1 404 NOT FOUND (not found in cache) -Connection: close -Content-Type: text/html; charset=iso-8859-1 - - - -404 -- not found in cache - - -

Error

-

-Currently offline and requested document is not yet cached. Go online. -

-URL: ($u) on host $h - - diff -uNr ffproxy-1.4.1/http.c ffproxy-1.5/http.c --- ffproxy-1.4.1/http.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/http.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: http.c,v 1.4 2003/05/12 00:41:40 niklas Exp $ + * $Id: http.c,v 1.7 2003/08/08 22:44:47 niklas Exp $ * * 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 @@ -20,13 +20,17 @@ * Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include "req.h" #include "print.h" +#include "cfg.h" #include "http.h" +#define my_isblank(c) ((c) == ' ' || (c) == '\t') + static const char http_get[] = "GET "; static const char http_post[] = "POST "; static const char http_head[] = "HEAD "; @@ -36,6 +40,7 @@ int http_url(struct req * r, const char *s) { + extern struct cfg config; size_t i, k; char *p; @@ -56,28 +61,43 @@ while (*s == ' ') s++; - debug("http_url() => got url part (%s)", s); + DEBUG(("http_url() => got url part (%s)", s)); - if (strncmp(s, http, strlen(http)) != 0) { - r->type = UNKNOWN; - return -1; - } + if (config.accel) { + DEBUG(("http_url() => using as accelerator proxy")); + DEBUG(("http_url() => accelhost (%s) port %d", config.accelhost, config.accelport)); + i = snprintf(r->url, sizeof(r->url), "%s%s:%d", http, config.accelhost, config.accelport); + if (i < 1) + fatal_n("http_url() => accelhost is too long, can't create r->url"); + DEBUG(("http_url() => created url (%s) length (%d)", r->url, i)); + } else { + if (strncmp(s, http, strlen(http)) != 0) { + r->type = UNKNOWN; + return -1; + } - i = 0; - while (i < strlen(http)) { - r->url[i] = http[i]; - i++, s++; - } + i = 0; + while (i < strlen(http)) { + r->url[i] = http[i]; + i++, s++; + } - while (i < sizeof(r->url) - 1 && *s != '_' - && (isalnum(*s) || *s == '-' || *s == '.' || *s == ':')) - r->url[i++] = tolower(*(s++)); - r->url[i] = '\0'; - if (*s != '/' && *s != ' ') { - r->type = UNKNOWN; - return -1; + while (i < sizeof(r->url) - 1 && *s != '_' + && (isalnum(*s) || *s == '-' || *s == '.' || *s == ':')) + r->url[i++] = tolower(*(s++)); + r->url[i] = '\0'; + if (*s != '/' && *s != ' ') { + r->type = UNKNOWN; + return -1; + } } + if (config.accel && strncmp(s, http, strlen(http)) == 0) { + r->url[i++] = '\0'; + s += strlen(http); + while (*s != ' ' && *s != '/' && *s != '\0' && isprint(*s)) + s++; + } k = 0; while (i < sizeof(r->url) - 1 && k < sizeof(r->urlpath) - 1 && *s != ' ' && *s != '\0' && isprint(*s)) { r->urlpath[k++] = *s; @@ -92,13 +112,13 @@ return -1; } - debug("http_url() => extracted urlpath (%s)", r->urlpath); - debug("http_url() => extracted url (%s)", r->url); + DEBUG(("http_url() => extracted urlpath (%s)", r->urlpath)); + DEBUG(("http_url() => extracted url (%s)", r->url)); while (*s == ' ') s++; - debug("http_url() => got version part (%s)", s); + DEBUG(("http_url() => got version part (%s)", s)); if (strncasecmp(s, httpv, strlen(httpv)) != 0) return -1; @@ -112,13 +132,13 @@ } if (*s == '.') { s++; - while (i < 2 && *s != '\0' && isdigit(*s)) { + while (i < 4 && *s != '\0' && isdigit(*s)) { r->vminor = r->vminor * 10 + (*(s++) - '0'); i++; } } - debug("http_url() => got type %d url (%s) version maj %d min %d", - r->type, r->url, r->vmajor, r->vminor); + DEBUG(("http_url() => got type %d url (%s) version maj %d min %d", + r->type, r->url, r->vmajor, r->vminor)); p = r->url; p += strlen(http); @@ -129,7 +149,7 @@ r->host[i] = '\0'; if (i >= sizeof(r->host) - 1) { - debug("http_url() => host: too long (%s)", r->host); + DEBUG(("http_url() => host: too long (%s)", r->host)); *r->host = '\0'; r->port = 0; return -1; @@ -140,19 +160,19 @@ while (isdigit(*p)) { r->port = r->port * 10 + (*(p++) - '0'); if (r->port >= 65534) { - debug("http_url() => port: bad port number"); + DEBUG(("http_url() => port: bad port number")); r->port = 0; return -1; } } if (*p != '\0' && *p != ' ' && *p != '/') { - debug("http_url() => port: bad port"); + DEBUG(("http_url() => port: bad port")); r->port = 0; return -1; } - debug("http_url() => port: %d", r->port); + DEBUG(("http_url() => port: %d", r->port)); } else { - debug("http_url() => default port 80"); + DEBUG(("http_url() => default port 80")); r->port = 80; } @@ -168,15 +188,15 @@ size_t i; if (strncasecmp(http_clen, s, strlen(http_clen)) == 0) { - debug("http_parse() => found clen header (%s)", s); + DEBUG(("http_parse() => found clen header (%s)", s)); s += strlen(http_clen); - while (isblank(*s)) + while (my_isblank(*s)) s++; if (!isdigit(*s)) { - debug("http_parse() => clen: no digit found (%s)", s); + DEBUG(("http_parse() => clen: no digit found (%s)", s)); return -1; } r->clen = 0L; @@ -186,17 +206,17 @@ if (*s != '\0') { r->clen = 0L; - debug("http_parse() => clen: too long"); + DEBUG(("http_parse() => clen: too long")); return -1; } - debug("http_parse() => clen: %ld bytes", r->clen); + DEBUG(("http_parse() => clen: %ld bytes", r->clen)); return 0; } else if (strncasecmp(http_tstamp, s, strlen(http_tstamp)) == 0) { - debug("http_parse() => found tstamp header (%s)", s); + DEBUG(("http_parse() => found tstamp header (%s)", s)); s += strlen(http_tstamp); - while (isblank(*s)) + while (my_isblank(*s)) s++; i = 0; @@ -206,10 +226,10 @@ if (*s != '\0') { r->tstamp[0] = '\0'; - debug("http_parse()_ => tstamp: too long"); + DEBUG(("http_parse()_ => tstamp: too long")); return -1; } - debug("http_parse() => tstamp: extracted (%s)", r->tstamp); + DEBUG(("http_parse() => tstamp: extracted (%s)", r->tstamp)); return 0; } return 1; diff -uNr ffproxy-1.4.1/main.c ffproxy-1.5/main.c --- ffproxy-1.4.1/main.c Fri Aug 1 20:22:01 2003 +++ ffproxy-1.5/main.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: main.c,v 1.41 2003/08/01 20:11:05 niklas Exp niklas $ + * $Id: main.c,v 1.26 2003/08/09 12:30:50 niklas Exp $ * * 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 @@ -28,6 +28,7 @@ #include #include #include +#include #include "cfg.h" #include "print.h" @@ -36,11 +37,31 @@ #include "dns.h" #include "signals.h" +#if defined(NEED_DAEMON) || defined(__sun__) +#include +#include +#include + +static int daemon(int, int); +int +daemon(int nochdir, int noclose) +{ + int f; + f = open("/dev/null", O_RDWR); + (void) dup2(STDIN_FILENO, f); + (void) dup2(STDERR_FILENO, f); + (void) dup2(STDOUT_FILENO, f); + if (fork()) + _exit(0); + return 0; +} +#endif + static void usage(void); static void drop_privileges(void); -static const char version[] = "1.4.1"; -static const char rcsid[] = "$Id: main.c,v 1.41 2003/08/01 20:11:05 niklas Exp niklas $"; +static const char version[] = "1.5"; +static const char rcsid[] = "$Id: main.c,v 1.26 2003/08/09 12:30:50 niklas Exp $"; char loop_header[100]; struct cfg config; @@ -48,17 +69,22 @@ int main(int argc, char *argv[]) { - int c; + int c, nowarn; + char *prgname; + + prgname = argv[0]; + nowarn = 0; (void) memset(&config, 0, sizeof(config)); - config.ip = 0L; + *config.ipv4 = '\0'; + *config.ipv6 = '\0'; config.port = 0; config.daemon = 0; config.childs = 10; config.ccount = 0; - config.backlog = 0; - config.uid = 0; - config.gid = 0; + config.backlog = 4; + config.uid = 0L; + config.gid = 0L; *config.chroot = '\0'; (void) strncpy(config.dbdir, DATADIR, sizeof(config.dbdir) - 1); config.dbdir[sizeof(config.dbdir) - 1] = '\0'; @@ -68,13 +94,17 @@ config.proxyport = 0; config.syslog = 1; config.logrequests = 0; - config.online = 1; - config.cache = 0; - config.cache_max_file_size = 1024 * 2; config.use_ipv6 = 1; config.aux_proxy_ipv6 = 1; + config.bind_ipv6 = 1; + config.bind_ipv4 = 1; + config.accel = 0; + config.accelusrhost = 1; + *config.accelhost = '\0'; + config.accelport = 80; + config.first = 1; - while ((c = getopt(argc, argv, "vdc:p:x:X:l:u:g:r:D:f:s4h")) != -1) { + while ((c = getopt(argc, argv, "vdbBc:C:p:x:X:l:u:g:r:D:F:f:s4a:A:h")) != -1) { switch (c) { case 'v': (void) printf("ffproxy version %s, %s\n", @@ -84,39 +114,98 @@ case 'd': config.daemon = 1; break; + case 'b': + config.bind_ipv4 = 0; + break; + case 'B': + config.bind_ipv6 = 0; + break; case 'c': - config.ip = resolve(optarg); + (void) strncpy(config.ipv4, optarg, sizeof(config.ipv4) - 1); + config.ipv4[sizeof(config.ipv4) - 1] = '\0'; + break; + case 'C': + (void) strncpy(config.ipv6, optarg, sizeof(config.ipv6) - 1); + config.ipv6[sizeof(config.ipv6) - 1] = '\0'; break; case 'p': config.port = atoi(optarg); + if (config.port > MAX_PORTS || !config.port) { + (void) fprintf(stderr, "Invalid port number (-p %s)\n", optarg); + exit(1); + } break; case 'x': + if (strlen(optarg) > sizeof(config.proxyhost) - 1 ) { + (void) fprintf(stderr, "Proxy host name too long\n"); + exit(1); + } (void) strncpy(config.proxyhost, optarg, sizeof(config.proxyhost) - 1); config.proxyhost[sizeof(config.proxyhost) - 1] = '\0'; break; case 'X': config.proxyport = atoi(optarg); + if (config.proxyport > MAX_PORTS || !config.proxyport) { + (void) fprintf(stderr, "Invalid port number (-X %s)\n", optarg); + exit(1); + } break; case 'l': config.childs = atoi(optarg); + if (!config.childs || config.childs > MAX_CHILDS) { + (void) fprintf(stderr, "Invalid limit of child processes (-l %s)\n", optarg); + exit(1); + } break; case 'u': - config.uid = atoi(optarg); + if (!(config.uid = atoi(optarg))) { + struct passwd *pwd; + if ((pwd = getpwnam(optarg))) + config.uid = (unsigned long) pwd->pw_uid; + else { + (void) fprintf(stderr, "UID %s not found\n", optarg); + exit(1); + } + } break; case 'g': - config.gid = atoi(optarg); + if (!(config.gid = atoi(optarg))) { + struct group *grp; + if ((grp = getgrnam(optarg))) + config.gid = (unsigned long) grp->gr_gid; + else { + (void) fprintf(stderr, "GID %s not found\n", optarg); + exit(1); + } + } break; case 'r': + if (strlen(optarg) > sizeof(config.chroot) - 1 ) { + (void) fprintf(stderr, "chroot directory too long\n"); + exit(1); + } (void) strncpy(config.chroot, optarg, sizeof(config.chroot) - 1); config.chroot[sizeof(config.chroot) - 1] = '\0'; break; case 'D': + if (strlen(optarg) > sizeof(config.dbdir) - 1 ) { + (void) fprintf(stderr, "dbdir directory too long\n"); + exit(1); + } (void) strncpy(config.dbdir, optarg, sizeof(config.dbdir) - 1); config.dbdir[sizeof(config.dbdir) - 1] = '\0'; break; + case 'F': + nowarn = 1; case 'f': + if (strlen(optarg) > sizeof(config.file) - 1 ) { + (void) fprintf(stderr, "config file name too long\n"); + exit(1); + } (void) strncpy(config.file, optarg, sizeof(config.file) - 1); config.file[sizeof(config.file) - 1] = '\0'; + if (*config.file && !nowarn && strcmp(config.file, "/dev/null") != 0) + (void) fprintf(stdout, "Using config file (%s).\nPlease note that due to design, config file overwrites command line options.\nUse -F instead of -f to omit this warning message.\n", config.file); break; case 's': config.syslog = 0; @@ -124,16 +213,31 @@ case '4': config.use_ipv6 = 0; break; + case 'a': + (void) strncpy(config.accelhost, optarg, sizeof(config.accelhost) - 1); + config.accelhost[sizeof(config.accelhost) - 1] = '\0'; + break; + case 'A': + config.accelport = atoi(optarg); + break; case 'h': - default: usage(); /* NOTREACHED */ break; + default: + (void) fprintf(stderr, "Error, type `%s -h' for help on usage\n", prgname); + exit(1); + break; } } argc -= optind; argv += optind; + if (*argv) { + (void) fprintf(stderr, "Unknown argument left (%s)\nType `%s -h' for usage\n", *argv, prgname); + exit(1); + } + setup_log_master(); info("started, initializing"); load_databases(); @@ -168,28 +272,29 @@ usage(void) { (void) fprintf(stderr, "ffproxy %s -- (c) 2002, 2003 Niklas Olmes \n", version); - (void) fprintf(stderr, " \n"); (void) fprintf(stderr, " GNU GPL. Website: http://faith.eu.org/programs.html\n"); (void) fprintf(stderr, - "usage: ffproxy [-vds4h] [-c host|ip] [-p port] [-x host|ip] [-X port] [-l max]\n" - " [-u uid -g gid] [-r dir] [-D dir] [-f file]\n" - "\n" - " -v print version number\n" - " -d become daemon\n" - " -s silent. don't log to syslog.\n" - " -4 Use IPv4 only. Don't try contacting via IPv6.\n" - " -h usage (this screen)\n" - "\n" - " -c host|ip bind to IP\n" - " -p port bind to port\n" - " -x host|ip auxiliary forward proxy\n" - " -X port auxiliary forward proxy port\n" - " -l max maximum number of concurrent requests\n" - " -u uid change uid\n" - " -g gid change gid\n" - " -r dir chroot to dir\n" - " -D dir databases are in dir (default is %s)\n" - " -f file use config file (default is %s)\n", + "usage: ffproxy [-vhds4bB] [-c host|ip] [-C host|ip] [-p port]\n" + " [-x host|ip -X port] [-l max] [-u uid|usr -g gid|grp] [-r dir]\n" + " [-D dir] [-f file] [-a host|ip] [-A port]\n" + " -v print version number -h usage (this screen)\n" + " -d become daemon -s silent. don't log to syslog.\n" + " -4 use IPv4 only. don't try contacting via IPv6.\n" + " -b do *not* bind to IPv4\n" + " -B do *not* bind to IPv6\n" + " -c host|ip bind to IPv4 address (default is any)\n" + " -C host|ip bind to IPv6 address (default is any)\n" + " -p port bind to port\n" + " -x host|ip auxiliary forward proxy\n" + " -X port auxiliary forward proxy port\n" + " -l max maximum number of concurrent requests\n" + " -u uid|user change uid\n" + " -g gid|group change gid\n" + " -r dir chroot to dir\n" + " -D dir databases are in dir (default is %s)\n" + " -f file use config file (default is %s; *overwrites*)\n" + " -a host|ip auxiliary forward server to use\n" + " -A port auxiliary forward server port (default is 80)\n", DATADIR, CFGFILE); exit(1); } @@ -203,7 +308,8 @@ if (config.uid == 0 || config.gid == 0) { info("not changing UID/GID"); } else { - pwd = getpwuid(config.uid); + if ((pwd = getpwuid(config.uid)) == NULL) + fatal("getpwuid() failed (non-existent UID entry?)"); if (*config.chroot != '\0') { if (chdir(config.chroot) != 0) diff -uNr ffproxy-1.4.1/msg.c ffproxy-1.5/msg.c --- ffproxy-1.4.1/msg.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/msg.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: msg.c,v 1.8 2003/07/20 10:38:23 niklas Exp $ + * $Id: msg.c,v 1.9 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -55,9 +55,6 @@ break; case E_FIL: p = e_fil; - break; - case E_NIC: - p = e_nic; break; } diff -uNr ffproxy-1.4.1/msg.h ffproxy-1.5/msg.h --- ffproxy-1.4.1/msg.h Thu Jul 25 12:07:39 2002 +++ ffproxy-1.5/msg.h Fri Aug 8 01:04:43 2003 @@ -8,7 +8,7 @@ }; enum { - E_INV = 10, E_RES, E_CON, E_POST, E_FIL, E_NIC + E_INV = 10, E_RES, E_CON, E_POST, E_FIL }; void err_msg(int, struct req *, int); diff -uNr ffproxy-1.4.1/print.c ffproxy-1.5/print.c --- ffproxy-1.4.1/print.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/print.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: print.c,v 1.9 2003/07/20 10:38:23 niklas Exp $ + * $Id: print.c,v 1.11 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -106,24 +106,7 @@ if (config.syslog) syslog(LOG_INFO, "%s\n", buf); -#ifdef DEBUG +#ifdef USE_DEBUG (void) fprintf(stdout, "%s\n", buf); -#endif -} - -void -debug(const char *fmt,...) -{ -#ifdef DEBUG - va_list ap; - char buf[2048]; - - va_start(ap, fmt); - (void) vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - (void) fprintf(stdout, "%s\n", buf); -#else - (void) fmt; #endif } diff -uNr ffproxy-1.4.1/print.h ffproxy-1.5/print.h --- ffproxy-1.4.1/print.h Thu Jul 25 12:07:39 2002 +++ ffproxy-1.5/print.h Wed Aug 6 02:36:52 2003 @@ -1,7 +1,12 @@ +#ifdef USE_DEBUG +#define DEBUG(args) (void) printf args , (void) printf("\n");; +#else +#define DEBUG(args) ; +#endif + void setup_log_master(void); void setup_log_slave(void); void fatal(const char *,...); void fatal_n(const char *,...); void warn(const char *,...); void info(const char *,...); -void debug(const char *,...); diff -uNr ffproxy-1.4.1/req.h ffproxy-1.5/req.h --- ffproxy-1.4.1/req.h Sun May 11 22:56:52 2003 +++ ffproxy-1.5/req.h Thu Aug 7 01:54:17 2003 @@ -2,8 +2,7 @@ struct clinfo { char name[128]; - char ip[64]; - char rip[64]; + char ip[128]; }; struct req { diff -uNr ffproxy-1.4.1/request.c ffproxy-1.5/request.c --- ffproxy-1.4.1/request.c Fri Aug 1 20:11:13 2003 +++ ffproxy-1.5/request.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: request.c,v 1.41 2003/08/01 20:11:05 niklas Exp niklas $ + * $Id: request.c,v 1.25 2003/08/08 22:44:47 niklas Exp $ * * 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 @@ -36,7 +36,6 @@ #include "http.h" #include "filter.h" #include "poll.h" -#include "cache.h" #include "request.h" static int read_header(int, struct req *); @@ -51,6 +50,7 @@ struct req r; char buf[2048]; + (void) memset(&r, 0, sizeof(r)); r.cl = clinfo; if (getline(cl, buf, sizeof(buf)) < 1) @@ -62,7 +62,7 @@ r.loop = 0; if (read_header(cl, &r) != 0) { - info("invalid header from %s [%s]/[%s]", clinfo->name, clinfo->ip, clinfo->rip); + info("invalid header from (%s) [%s]", clinfo->name, clinfo->ip); err_msg(cl, &r, E_INV); i = 0; @@ -70,9 +70,9 @@ free(r.header[i++]); r.header[0] = NULL; } else if (filter_request(&r) != 0) { - info("filtered request for URL (%s) from %s [%s]/[%s]", r.url, clinfo->name, clinfo->ip, clinfo->rip); + info("filtered request for URL (%s) from (%s) [%s]", r.url, clinfo->name, clinfo->ip); if (r.loop) - warn("LOOP DETECTED for URL (%s) from %s [%s]/[%s]", r.url, clinfo->name, clinfo->ip, clinfo->rip); + warn("LOOP DETECTED for URL (%s) from (%s) [%s]", r.url, clinfo->name, clinfo->ip); else err_msg(cl, &r, E_FIL); @@ -82,35 +82,33 @@ r.header[0] = NULL; } else { if (config.logrequests) - info("request for URL (%s) from %s [%s]/[%s]", r.url, clinfo->name, clinfo->ip, clinfo->rip); + info("request for URL (%s) from (%s) [%s]", r.url, clinfo->name, clinfo->ip); i = do_request(cl, &r); switch (i) { case E_INV: - info("invalid request for URL (%s) from %s [%s]/[%s]", r.url, clinfo->name, clinfo->ip, clinfo->rip); + info("invalid request for URL (%s) from (%s) [%s]", r.url, clinfo->name, clinfo->ip); break; case E_RES: - info("resolve failure for host %s from %s [%s]/[%s]", r.host, clinfo->name, clinfo->ip, clinfo->rip); + info("resolve failure for host (%s) from (%s) [%s]", r.host, clinfo->name, clinfo->ip); break; case E_CON: - info("connection failure for host %s from %s [%s]/[%s]", r.host, clinfo->name, clinfo->ip, clinfo->rip); + info("connection failure for host (%s) from (%s) [%s]", r.host, clinfo->name, clinfo->ip); break; case E_POST: - info("failure while post for URL (%s) from %s [%s]/[%s]", r.url, clinfo->name, clinfo->ip, clinfo->rip); + info("failure while post for URL (%s) from (%s) [%s]", r.url, clinfo->name, clinfo->ip); break; case E_FIL: - info("filtered request for URL (%s) from %s [%s]/[%s]", r.url, clinfo->name, clinfo->ip, clinfo->rip); + info("filtered request for URL (%s) from (%s) [%s]", r.url, clinfo->name, clinfo->ip); break; default: i = 0; } - if(config.cache) - (void) unlock(&r); if (i != 0) err_msg(cl, &r, i); } } else { - info("invalid request from %s [%s]/[%s]", clinfo->name, clinfo->ip, clinfo->rip); + info("invalid request from (%s) [%s]", clinfo->name, clinfo->ip); } } @@ -132,7 +130,7 @@ (void) strcpy(p, b); r->header[i] = p; - debug("read_header() => entry %d (%s)", i, r->header[i]); + DEBUG(("read_header() => entry %d (%s)", i, r->header[i])); i++; } @@ -179,11 +177,6 @@ #include #include -#ifdef LINUX - #include -#else - #include -#endif #include #include @@ -209,283 +202,266 @@ ip = 0L; s = 0; + if (config.use_ipv6 && (config.aux_proxy_ipv6 || *config.proxyhost == '\0')) { + struct addrinfo hints, *res, *res0; + char port[6]; + + DEBUG(("do_request() => trying ipv6")); + + port[0] = '\0'; + (void) memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (*config.proxyhost != '\0' && config.proxyport) { + DEBUG(("do_request() => trying ipv6 for proxy %s port %d", config.proxyhost, config.proxyport)); + (void) snprintf(port, 6, "%d", config.proxyport); + if (getaddrinfo(config.proxyhost, port, &hints, &res)) { + DEBUG(("do_request() => getaddrinfo() failed for proxy %s", config.proxyhost)); + return E_RES; + } + } else { + (void) snprintf(port, 6, "%d", r->port); + if (getaddrinfo(r->host, port, &hints, &res)) { + DEBUG(("do_request() => getaddrinfo() failed for %s", r->host)); + return E_RES; + } + } - if (config.online) { - if (config.use_ipv6 && (config.aux_proxy_ipv6 || *config.proxyhost == '\0')) { - struct addrinfo hints, *res, *res0; - char port[6]; - - debug("do_request() => trying ipv6"); - - port[0] = '\0'; - (void) memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; + s = -1; + for (res0 = res; res; res = res->ai_next) { + if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) + continue; + else if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + (void) close(s); + s = -1; + continue; + } else + break; + } + freeaddrinfo(res0); + if (s == -1) { if (*config.proxyhost != '\0' && config.proxyport) { - debug("do_request() => trying ipv6 for proxy %s port %d", config.proxyhost, config.proxyport); - (void) snprintf(port, 6, "%d", config.proxyport); - if (getaddrinfo(config.proxyhost, port, &hints, &res)) { - debug("do_request() => getaddrinfo() failed for proxy %s", config.proxyhost); - return E_CON; - } + DEBUG(("do_request() => socket() or connect() after getaddrinfo() failed for proxy %s port %d", config.proxyhost, config.proxyport)); } else { - (void) snprintf(port, 6, "%d", r->port); - if (getaddrinfo(r->host, port, &hints, &res)) { - debug("do_request() => getaddrinfo() failed for %s", r->host); - return E_CON; - } - } - - s = -1; - for (res0 = res; res; res = res->ai_next) { - if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - continue; - else if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { - (void) close(s); - s = -1; - continue; - } else - break; + DEBUG(("do_request() => socket() or connect() after getaddrinfo() failed for %s port %d", r->host, r->port)); } - freeaddrinfo(res0); + return E_CON; + } + } else { + struct sockaddr_in addr; - if (s == -1) { - if (*config.proxyhost != '\0' && config.proxyport) - debug("do_request() => socket() or connect() after getaddrinfo() failed for proxy %s port %d", - config.proxyhost, config.proxyport); - else - debug("do_request() => socket() or connect() after getaddrinfo() failed for %s port %d", r->host, r->port); - return E_CON; + DEBUG(("do_request() => not trying ipv6")); + + (void) memset(&addr, 0, sizeof(addr)); + + if (*config.proxyhost != '\0' && config.proxyport) { + DEBUG(("do_request() => using aux proxy w/o trying ipv6")); + if ((addr.sin_addr.s_addr = resolve(config.proxyhost)) == INADDR_NONE) { + DEBUG(("do_request() => resolve failure for proxy %s", config.proxyhost)); + return E_RES; } + addr.sin_port = htons(config.proxyport); + addr.sin_family = AF_INET; } else { - struct sockaddr_in addr; - - debug("do_request() => not trying ipv6"); - - (void) memset(&addr, 0, sizeof(addr)); - - if (*config.proxyhost != '\0' && config.proxyport) { - debug("do_request() => using aux proxy w/o trying ipv6"); - if ((addr.sin_addr.s_addr = resolve(config.proxyhost)) == INADDR_NONE) { - debug("do_request() => resolve failure for proxy %s", config.proxyhost); - return E_RES; - } - addr.sin_port = htons(config.proxyport); - addr.sin_family = AF_INET; - } else { - if ((ip = resolve(r->host)) == INADDR_NONE) { - debug("do_request() => resolve failure for %s", r->host); - return E_RES; - } - addr.sin_addr.s_addr = ip; - addr.sin_port = htons(r->port); - addr.sin_family = AF_INET; + if ((ip = resolve(r->host)) == INADDR_NONE) { + DEBUG(("do_request() => resolve failure for %s", r->host)); + return E_RES; } + addr.sin_addr.s_addr = ip; + addr.sin_port = htons(r->port); + addr.sin_family = AF_INET; + } - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - debug("do_request() => socket() failed for %s port %d", r->host, r->port); - return E_CON; - } else if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &foo, sizeof(foo)) != 0) { - debug("do_request() => setsockopt() failed for %s port %d", r->host, r->port); - return E_CON; - } else if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) == -1) { - debug("do_request() => connect() failed for %s port %d", r->host, r->port); - return E_CON; - } + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + DEBUG(("do_request() => socket() failed for %s port %d", r->host, r->port)); + return E_CON; + } else if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &foo, sizeof(foo)) != 0) { + DEBUG(("do_request() => setsockopt() failed for %s port %d", r->host, r->port)); + return E_CON; + } else if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) == -1) { + DEBUG(("do_request() => connect() failed for %s port %d", r->host, r->port)); + return E_CON; } - } else - s = 0; + } - debug("do_request() => header is:"); +#ifdef USE_DEBUG i = 0; + DEBUG(("do_request() => header is:")); while (r->header[i] != NULL) - debug("=> [%s]", r->header[i++]); + DEBUG(("=> [%s]", r->header[i++])); +#endif - if (config.online) { - if (r->vmajor >= 1 && r->vminor >= 0) - r->vmajor = 1, r->vminor = 0; - - if (r->port == 80) - len = snprintf(buf, sizeof(buf), - "%s %s HTTP/%d.%d\r\n" - "Host: %s\r\n", - ((r->type == GET) ? "GET" - : ((r->type) == HEAD) ? "HEAD" : "POST"), - (*config.proxyhost && config.proxyport) != '\0' ? r->url : r->urlpath, - r->vmajor, r->vminor, - r->host); - else - len = snprintf(buf, sizeof(buf), - "%s %s HTTP/%d.%d\r\n" - "Host: %s:%d\r\n", - ((r->type == GET) ? "GET" - : ((r->type) == HEAD) ? "HEAD" : "POST"), - (*config.proxyhost && config.proxyport) != '\0' ? r->url : r->urlpath, - r->vmajor, r->vminor, - r->host, r->port); + if (r->vmajor >= 1 && r->vminor >= 0) + r->vmajor = 1, r->vminor = 0; - i = 0; - while (r->header[i] != NULL) { - len += strlen(r->header[i]) + strlen("\r\n"); - if (len < sizeof(buf)) { - (void) strncat(buf, r->header[i++], len); - (void) strncat(buf, "\r\n", strlen("\r\n")); - } else { - debug("do_request() => header too big"); - (void) close(s); - i = 0; - while (r->header[i] != NULL) - free(r->header[i++]); - r->header[0] = NULL; - return E_INV; - } - } - i = 0; - while (r->header[i] != NULL) - free(r->header[i++]); - r->header[0] = NULL; + if (config.accel && config.accelusrhost) + len = snprintf(buf, sizeof(buf), + "%s %s HTTP/%d.%d\r\n", + ((r->type == GET) ? "GET" + : ((r->type) == HEAD) ? "HEAD" : "POST"), + (*config.proxyhost && config.proxyport) != '\0' ? r->url : r->urlpath, + r->vmajor, r->vminor); + else if (r->port == 80) + len = snprintf(buf, sizeof(buf), + "%s %s HTTP/%d.%d\r\n" + "Host: %s\r\n", + ((r->type == GET) ? "GET" + : ((r->type) == HEAD) ? "HEAD" : "POST"), + (*config.proxyhost && config.proxyport) != '\0' ? r->url : r->urlpath, + r->vmajor, r->vminor, + r->host); + else + len = snprintf(buf, sizeof(buf), + "%s %s HTTP/%d.%d\r\n" + "Host: %s:%d\r\n", + ((r->type == GET) ? "GET" + : ((r->type) == HEAD) ? "HEAD" : "POST"), + (*config.proxyhost && config.proxyport) != '\0' ? r->url : r->urlpath, + r->vmajor, r->vminor, + r->host, r->port); - len += strlen("\r\n"); - if (len >= sizeof(buf) - 1) { - debug("do_request() => header too big"); + i = 0; + while (r->header[i] != NULL) { + len += strlen(r->header[i]) + strlen("\r\n"); + if (len < sizeof(buf)) { + (void) strncat(buf, r->header[i++], len); + (void) strncat(buf, "\r\n", strlen("\r\n")); + } else { + DEBUG(("do_request() => header too big")); (void) close(s); + i = 0; + while (r->header[i] != NULL) + free(r->header[i++]); + r->header[0] = NULL; return E_INV; } - (void) strncat(buf, "\r\n", strlen("\r\n")); + } + i = 0; + while (r->header[i] != NULL) + free(r->header[i++]); + r->header[0] = NULL; - debug("do_request() => request ready: type %d url (%s) host (%s) port %d", - r->type, r->url, r->host, r->port); - debug("=> version maj %d min %d", r->vmajor, r->vminor); - debug("=> header: (%s)", buf); + len += strlen("\r\n"); + if (len >= sizeof(buf) - 1) { + DEBUG(("do_request() => header too big")); + (void) close(s); + return E_INV; + } + (void) strncat(buf, "\r\n", strlen("\r\n")); - if (my_poll(s, OUT) <= 0 || write(s, buf, len) < 1) { - debug("do_request() => sending request failed"); - (void) close(s); - return E_CON; - } - if (r->type == POST) { - long rest; + DEBUG(("do_request() => request ready: type %d url (%s) host (%s) port %d", + r->type, r->url, r->host, r->port)); + DEBUG(("=> version maj %d min %d", r->vmajor, r->vminor)); + DEBUG(("=> header: (%s)", buf)); + + if (my_poll(s, OUT) <= 0 || write(s, buf, len) < 1) { + DEBUG(("do_request() => sending request failed")); + (void) close(s); + return E_CON; + } + if (r->type == POST) { + long rest; - debug("do_request() => posting data"); + DEBUG(("do_request() => posting data")); - if ((rest = r->clen) < 0L) { - debug("do_request() => post: invalid clen %ld", r->clen); + if ((rest = r->clen) < 0L) { + DEBUG(("do_request() => post: invalid clen %ld", r->clen)); + (void) close(s); + return E_POST; + } + while (rest > 0L) { + if (my_poll(cl, OUT) <= 0) { (void) close(s); return E_POST; } - while (rest > 0L) { - if (my_poll(cl, OUT) <= 0) { - (void) close(s); - return E_POST; - } - len = read(cl, buf, sizeof(buf)); - if (len < 1) - break; - else - rest -= len; - - if (my_poll(s, OUT) <= 0 || write(s, buf, len) < 1) { - debug("do_request() => post: error writing post data"); - (void) close(s); - return E_POST; - } - } - debug("do_request() => post done"); - } - i = 0; - while ((len = getline(s, buf, sizeof(buf))) > 0 && i < sizeof(r->header) - 1) { - debug("do_request() => got remote header line: (%s)", buf); - r->header[i] = (char *) my_alloc(len + 1); - (void) strcpy(r->header[i++], buf); - } - r->header[i] = NULL; + len = read(cl, buf, sizeof(buf)); + if (len < 1) + break; + else + rest -= len; - if (len > 0) { - debug("do_request() => remote header too big"); - (void) close(s); - i = 0; - while (r->header[i] != NULL) - free(r->header[i++]); - r->header[0] = NULL; - return E_FIL; - } - if (filter_remote(r) != 0) { - debug("do_request() => response was filtered"); - (void) close(s); - i = 0; - while (r->header[i] != NULL) - free(r->header[i++]); - r->header[0] = NULL; - return E_FIL; - } - *buf = '\0'; - len = 0; - i = 0; - while (r->header[i] != NULL) { - len += strlen(r->header[i]) + strlen("\r\n"); - if (len < sizeof(buf) - 1) { - (void) strcat(buf, r->header[i++]); - (void) strcat(buf, "\r\n"); - } else { - debug("do_request() => remote header too big (at concatenation)"); - i = 0; - while (r->header[i] != NULL) - free(r->header[i++]); - r->header[0] = NULL; + if (my_poll(s, OUT) <= 0 || write(s, buf, len) < 1) { + DEBUG(("do_request() => post: error writing post data")); (void) close(s); - return E_FIL; + return E_POST; } } + DEBUG(("do_request() => post done")); + } + i = 0; + while ((len = getline(s, buf, sizeof(buf))) > 0 && i < sizeof(r->header) - 1) { + DEBUG(("do_request() => got remote header line: (%s)", buf)); + r->header[i] = (char *) my_alloc(len + 1); + (void) strcpy(r->header[i++], buf); + } + r->header[i] = NULL; + + if (len > 0) { + DEBUG(("do_request() => remote header too big")); + (void) close(s); i = 0; while (r->header[i] != NULL) free(r->header[i++]); r->header[0] = NULL; - - len += strlen("\r\n"); - if (len >= sizeof(buf) - 1) { - debug("do_request() => remote header too big (at final)"); + return E_FIL; + } + if (filter_remote(r) != 0) { + DEBUG(("do_request() => response was filtered")); + (void) close(s); + i = 0; + while (r->header[i] != NULL) + free(r->header[i++]); + r->header[0] = NULL; + return E_FIL; + } + *buf = '\0'; + len = 0; + i = 0; + while (r->header[i] != NULL) { + len += strlen(r->header[i]) + strlen("\r\n"); + if (len < sizeof(buf) - 1) { + (void) strcat(buf, r->header[i++]); + (void) strcat(buf, "\r\n"); + } else { + DEBUG(("do_request() => remote header too big (at concatenation)")); + i = 0; + while (r->header[i] != NULL) + free(r->header[i++]); + r->header[0] = NULL; (void) close(s); return E_FIL; } - (void) strcat(buf, "\r\n"); - - debug("do_request() => remote header ready: (%s)", buf); + } + i = 0; + while (r->header[i] != NULL) + free(r->header[i++]); + r->header[0] = NULL; - if (my_poll(cl, OUT) <= 0 || write(cl, buf, len) < 1) { - (void) close(s); - return -1; - } - if (r->type != HEAD) { - int f; + len += strlen("\r\n"); + if (len >= sizeof(buf) - 1) { + DEBUG(("do_request() => remote header too big (at final)")); + (void) close(s); + return E_FIL; + } + (void) strcat(buf, "\r\n"); - f = opencache(r, 1); + DEBUG(("do_request() => remote header ready: (%s)", buf)); - while (my_poll(s, IN) > 0 && (len = read(s, buf, sizeof(buf))) > 0) { - if (my_poll(cl, OUT) <= 0 || write(cl, buf, len) < 1) { - if (f != -1) - closecache(f, r); - (void) close(s); - return -1; - } - if (f != -1 && write(f, buf, len) < 1) { - closecache(f, r); - f = -1; - } + if (my_poll(cl, OUT) <= 0 || write(cl, buf, len) < 1) { + (void) close(s); + return -1; + } + if (r->type != HEAD) { + while (my_poll(s, IN) > 0 && (len = read(s, buf, sizeof(buf))) > 0) { + if (my_poll(cl, OUT) <= 0 || write(cl, buf, len) < 1) { + (void) close(s); + return -1; } - if (f != -1) - closecache(f, r); - (void) close(s); - return 0; } - } else { - int f; - - if ((f = opencache(r, 0)) < 0) - return E_NIC; - - (void) deliverfromcache(cl, f, r); - debug("do_request() => cache: done"); + (void) close(s); + return 0; } return 0; diff -uNr ffproxy-1.4.1/sample.config ffproxy-1.5/sample.config --- ffproxy-1.4.1/sample.config Fri Aug 1 20:40:50 2003 +++ ffproxy-1.5/sample.config Sat Aug 9 12:14:52 2003 @@ -1,60 +1,88 @@ # # sample configuration file for ffproxy(8) +# (version 1.5) # # lines starting with '#' are comments -# run as daemon? yes|no (default: no) + +# run as daemon? +# (default: no) #daemonize yes -daemonize no +#daemonize no # number of child processes, # that is, the maximum number of concurrent requests # (default: 10) -child_processes 10 +#child_processes 10 -# bind to (IP or hostname), 0 is any IP (default) -#bind_to 192.168.10.1 -#bind_to martyr.burden.eu.org -bind_to 0 +# ffproxy binds to any IPv4 address +# and any IPv6 address by default +# +# bind to IPv4? (default: yes) +#bind_ipv4 no +#bind_ipv4 yes +# bind to IPv6? (default: yes) +#bind_ipv6 no +#bind_ipv6 yes +# +# Hostname or IP to bind to +# (default is any IP) +# +#bind_ipv4_host 192.168.10.1 +#bind_ipv4_host martyr.burden.eu.org +#bind_ipv6_host ::1 +#bind_ipv6_host oz.burden.eu.org -# listen on port (default: 8080) +# listen on port +# (default: 8080) #port 1111 -port 8080 +#port 8080 -# use IPv6? (default: yes) -# NOTE: ffproxy 1.4 does not yet bind to IPv6, it will -# only try to contact servers via IPv6 if -# use_ipv6 is set to yes +# use IPv6 when contacting servers? +# (default: yes) #use_ipv6 no -use_ipv6 yes +#use_ipv6 yes -# use syslog? (default: yes) +# use syslog? +# (default: yes) #use_syslog no -use_syslog yes +#use_syslog yes -# log all requests? (default: no) +# log all requests? +# (default: no) # to use, set also use_syslog to yes #log_all_requests yes -log_all_requests no +#log_all_requests no -# change uid to id, 0 disables (default) -uid 0 -# change gid to id, 0 disables (default) -gid 0 +# change UID and GID +# +# to use, both uid and gid must be set +# (disabled by default) +#uid proxy +#gid proxy +#uid 37 +#gid 38 # change root to (only in connection with uid and gid change) +# /etc/resolv.conf might need to be copied +# to chroot_dir/etc/resolv.conf # (disabled by default) #chroot_dir /var/ffproxy # forward to proxy (auxiliary proxy) +# (set `forward_proxy_port 0' to explicitly disable feature +# (i.e, when reloading configuration file via SIGHUP)) # (disabled by default) #forward_proxy blackness.burden.eu.org +#forward_proxy 192.168.10.5 +#forward_proxy ::1 #forward_proxy_port 8082 -forward_proxy_port 0 +#forward_proxy_port 0 -# try IPv6 for auxiliary proxy? (default yes) -# (use_ipv6 must be set to yes, too) +# try IPv6 for auxiliary proxy? +# use_ipv6 must be set to yes, too +# (default: yes) #forward_proxy_ipv6 no -forward_proxy_ipv6 yes +#forward_proxy_ipv6 yes # path to db/ and html/ directories # (default: /var/ffproxy) @@ -62,8 +90,35 @@ # give a path name relative to new root, or, # if db_files_path is the same as root, use db_files_path ./ # You have to start ffproxy in the new root directory, -# otherwise it won't find the database files) +# otherwise it won't find the database files. +# Please keep in mind that ffproxy's config file has to +# be within chroot directory, otherwise it will not find +# its config file on reload) #db_files_path ./ -db_files_path /var/ffproxy +#db_files_path /var/ffproxy + +# http accelerator +# (disabled by default) +# +# if you want to use ffproxy as http accelerator (that is, connecting +# to just one http server and beeing used as front-end to that, e.g. +# in DMZ) uncomments options below (port is optional, defaults to 80) +# (set `accel_port 0' to explicitly disable feature +# (i.e, when reloading configuration file via SIGHUP)) +#accel_host 10.254.1.2 +#accel_host revelation.martyr.eu.org +#accel_port 80 +#accel_port 0 +# +# Omit Host: accel_host:accel_port in Header +# to provide own Host: header via db/filter.header.add? +# (default: yes) +#accel_user_host no +#accel_user_host yes + +# backlog size for accept() +# (default: 4) +#backlog_size 16 +#backlog_size 4 # end of file diff -uNr ffproxy-1.4.1/signals.c ffproxy-1.5/signals.c --- ffproxy-1.4.1/signals.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/signals.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: signals.c,v 1.5 2003/07/20 10:38:23 niklas Exp $ + * $Id: signals.c,v 1.6 2003/08/08 14:10:28 niklas Exp $ * * 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 @@ -34,8 +34,6 @@ static void sighup(int); static void sigterm(int); static void sigint(int); -static void sigusr1(int); -static void sigusr2(int); extern struct cfg config; @@ -72,32 +70,6 @@ fatal_n("SIGINT received"); } -static void -sigusr1(int dummy) -{ - (void) dummy; - - if (config.online) - info("already online"); - else - info("now ONLINE"); - - config.online = 1; -} - -static void -sigusr2(int dummy) -{ - (void) dummy; - - if (!config.online) - info("already offline"); - else - info("now OFFLINE"); - - config.online = 0; -} - void init_sighandlers(void) { @@ -105,6 +77,4 @@ signal(SIGHUP, sighup); signal(SIGTERM, sigterm); signal(SIGINT, sigint); - signal(SIGUSR1, sigusr1); - signal(SIGUSR2, sigusr2); } diff -uNr ffproxy-1.4.1/socket.c ffproxy-1.5/socket.c --- ffproxy-1.4.1/socket.c Fri Aug 1 20:11:15 2003 +++ ffproxy-1.5/socket.c Sat Aug 9 15:13:01 2003 @@ -3,7 +3,7 @@ * * http://faith.eu.org * - * $Id: socket.c,v 1.41 2003/08/01 20:11:05 niklas Exp niklas $ + * $Id: socket.c,v 1.19 2003/08/09 14:32:00 niklas Exp $ * * 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 @@ -22,16 +22,13 @@ #include #include -#include -#ifdef LINUX - #include -#else - #include -#endif +#include #include #include #include +#include +#include #include "req.h" #include "cfg.h" @@ -41,68 +38,144 @@ #include "access.h" #include "socket.h" +#define DFLT_PORT 8080 +#ifndef INFTIM +#define INFTIM -1 +#endif + void open_socket(void) { extern struct cfg config; - struct sockaddr_in addr, claddr; + struct sockaddr claddr; + struct addrinfo hints[2], *res; struct clinfo *clinfo; + struct pollfd s[2]; socklen_t claddr_len; pid_t pid; void *foo; - int s, cl; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) - fatal("socket() failed"); - - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &foo, sizeof(foo)) != 0) - fatal("setsockopt() failed"); - - (void) memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = config.ip ? config.ip : htonl(INADDR_ANY); - addr.sin_port = config.port ? htons(config.port) : htons(8080); - - if (bind(s, (struct sockaddr *) & addr, sizeof(addr)) != 0) - fatal("bind() failed"); - - if (listen(s, config.backlog) != 0) - fatal("listen() failed"); - - info("ready, waiting for requests on IP %s port %d", config.ip ? ip_to_a(config.ip) : "(any)", config.port ? config.port : 8080); + char strport[6]; + char *ip_add; + int st, cl, i; + int num_fd; + int isipv4; + + if (config.port == 0) + config.port = DFLT_PORT; + (void) snprintf(strport, sizeof(strport), "%d", config.port); + + num_fd = 0; + if (config.bind_ipv4) + num_fd++; + if (config.bind_ipv6) + num_fd++; + + i = 0; + (void) memset(s, 0, sizeof(s)); + s[0].fd = s[1].fd = 0; + while (i < num_fd) { + (void) memset(&hints[i], 0, sizeof(struct addrinfo)); + hints[i].ai_family = (i == 0 && config.bind_ipv4) ? PF_INET : PF_INET6; + hints[i].ai_socktype = SOCK_STREAM; + hints[i].ai_flags = AI_PASSIVE; + if (i == 0 && config.bind_ipv4) { + if (*config.ipv4 == '\0') + ip_add = NULL; + else + ip_add = config.ipv4; + } else { + if (*config.ipv6 == '\0') + ip_add = NULL; + else + ip_add = config.ipv6; + } + if (getaddrinfo(ip_add, strport, &hints[i], &res)) + fatal("getaddrinfo() failed for (%s) %s", ip_add, (i == 0 && config.bind_ipv4) ? "IPv4" : "IPv6"); + if ((s[i].fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) { + if (i == 1 || (config.ipv6 && !config.ipv4)) + fatal("socket() failed for IPv6, perhaps your system does not support IPv6.\nTry -B or `bind_ipv6 no' to disable IPv6 binding.\nError message"); + else + fatal("socket() failed for IPv4"); + } + if (setsockopt(s[i].fd, SOL_SOCKET, SO_REUSEADDR, &foo, sizeof(foo)) != 0) { + (void) close(s[i].fd); + fatal("setsockopt() failed for (%s) %s", ip_add, (i == 0 && config.bind_ipv4) ? "IPv4" : "IPv6"); + } + if (bind(s[i].fd, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { + (void) close(s[i].fd); +#if defined(__linux__) + if (i == 1) + fatal("could not bind to IPv6, possibly because of\nLinux's ``feature'' to bind to IPv4 also.\nTry -b or binding to specific IPv6 address via -C\nif you're using IPv6 with Linux 2.4\nError message"); +#endif /* __linux__ */ + fatal("bind() failed for (%s) %s", ip_add, (i == 0 && config.bind_ipv4) ? "IPv4" : "IPv6"); + } + if (listen(s[i].fd, config.backlog) != 0) { + (void) close(s[i].fd); + fatal("listen() failed for (%s) %s",ip_add, (i == 0 && config.bind_ipv4) ? "IPv4" : "IPv6"); + } + freeaddrinfo(res); + + s[i].events = POLLIN; + i++; + } + + if (config.bind_ipv4) + info("waiting for requests on %s port %d (IPv4)", *config.ipv4 ? config.ipv4 : "(any)", config.port); + if (config.bind_ipv6) + info("waiting for requests on %s port %d (IPv6)", *config.ipv6 ? config.ipv6 : "(any)", config.port); claddr_len = sizeof(claddr); config.ccount = 0; + cl = 0; + isipv4 = config.bind_ipv4; for (;;) { if (config.ccount >= config.childs) { - usleep(50000); + (void) usleep(50000); continue; } - if ((cl = accept(s, (struct sockaddr *) & claddr, &claddr_len)) == -1) { - debug("open_socket() => accept() failed"); + if (num_fd == 2) { + i = poll(s, 2, INFTIM); + if (i < 1) { + continue; + } else { + if (s[0].revents == POLLIN) { + st = s[0].fd; + isipv4 = 1; + } else { + st = s[1].fd; + isipv4 = 0; + } + } + } else + st = s[0].fd; + if ((cl = accept(st, (struct sockaddr *) & claddr, &claddr_len)) == -1) { + DEBUG(("open_socket() => accept() failed")); continue; } - debug("open_socket() => connection, checking access"); - clinfo = identify(&claddr); + + DEBUG(("open_socket() => connection, checking access")); + clinfo = identify(&claddr, (socklen_t) isipv4 ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); if (check_access(clinfo) != 0) { - debug("open_socket() => no access"); + DEBUG(("open_socket() => no access")); if (config.logrequests) - info("connection attempt from %s [%s]/[%s], ACCESS DENIED", clinfo->name, clinfo->ip, clinfo->rip); + info("connection attempt from (%s) [%s], ACCESS DENIED", clinfo->name, clinfo->ip); free(clinfo); (void) close(cl); continue; } if (config.logrequests) - info("connection attempt from %s [%s]/[%s], access granted", clinfo->name, clinfo->ip, clinfo->rip); + info("connection attempt from (%s) [%s], access granted", clinfo->name, clinfo->ip); if ((pid = fork()) == -1) { - debug("open_socket() => fork() failed"); + DEBUG(("open_socket() => fork() failed")); free(clinfo); (void) close(cl); continue; } else if (pid == 0) { - (void) close(s); + (void) close(s[0].fd); + if (num_fd == 2) + (void) close(s[1].fd); setup_log_slave(); handle_request(cl, clinfo); free(clinfo); diff -uNr ffproxy-1.4.1/sys-dep.sh ffproxy-1.5/sys-dep.sh --- ffproxy-1.4.1/sys-dep.sh Thu Jan 1 00:00:00 1970 +++ ffproxy-1.5/sys-dep.sh Sat Aug 9 15:13:01 2003 @@ -0,0 +1,17 @@ +#!/bin/sh +# $Id: sys-dep.sh,v 1.2 2003/08/08 22:44:47 niklas Exp $ +# SunOS needs libraries libsocket and libnsl + +SYSTEM=`(uname -s) 2>/dev/null` || SYSTEM="unknown" +case "${SYSTEM}" in + SunOS) + LIBS="-lsocket -lnsl" + echo "Linking for SunOS..." + echo $1 $2 ${LIBS} $3 $4 + $1 $2 ${LIBS} $3 $4 + ;; + *) + echo $1 $2 $3 $4 + $1 $2 $3 $4 + ;; +esac diff -uNr ffproxy-1.4.1/time.c ffproxy-1.5/time.c --- ffproxy-1.4.1/time.c Sun Jul 20 11:25:05 2003 +++ ffproxy-1.5/time.c Thu Jan 1 00:00:00 1970 @@ -1,75 +0,0 @@ -/* - * ffproxy (c) 2002, 2003 Niklas Olmes - * - * http://faith.eu.org - * - * $Id: time.c,v 1.4 2003/07/20 10:38:23 niklas Exp $ - * - * 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 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 675 - * Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include -#include -#include - -#include "req.h" -#include "print.h" -#include "time.h" - -static time_t my_mktime(struct tm *); - -int -timestamp(struct req * r) -{ - struct utimbuf time; - - debug("timestamp() => string is (%s)", r->tstamp); - if ((time.actime = time.modtime = my_convtime(r->tstamp)) != -1) { - debug("timestamp() => stamping file (%s) (%d)", r->fname, time.actime); - (void) utime(r->fname, &time); - return 0; - } - return -1; -} - -time_t -my_convtime(const char *tstamp) -{ - struct tm t; - time_t tm; - - t.tm_isdst = 0; - - if (strptime(tstamp, "%a, %d %b %Y %T", &t) != NULL) { - if ((tm = my_mktime(&t)) == -1) - return -1; - else - return tm; - } - return -1; -} - -static time_t -my_mktime(struct tm * t) -{ - time_t tl, tb; - - tl = mktime(t); - tb = mktime(gmtime(&tl)); - - return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl))); -} diff -uNr ffproxy-1.4.1/time.h ffproxy-1.5/time.h --- ffproxy-1.4.1/time.h Thu Jul 25 12:07:39 2002 +++ ffproxy-1.5/time.h Thu Jan 1 00:00:00 1970 @@ -1,5 +0,0 @@ -#include -#include - -int timestamp(struct req * r); -time_t my_convtime(const char *);