diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index 603c793..61508cf 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws index 619222c..1f3d955 100755 Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ diff --git a/binaries/armhf/nfqws b/binaries/armhf/nfqws index a4c934e..25a3b0d 100755 Binary files a/binaries/armhf/nfqws and b/binaries/armhf/nfqws differ diff --git a/binaries/armhf/tpws b/binaries/armhf/tpws index f3d5341..e2a51bb 100755 Binary files a/binaries/armhf/tpws and b/binaries/armhf/tpws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index 0c32f1e..a7b3f94 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index f6d9610..26458f4 100755 Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index 412614b..f2d14bf 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index f76aa02..55023c0 100755 Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index 9b42a38..6e43fe1 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws index ae3b5da..0ea5c18 100755 Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 71da68c..b81558d 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index 0aa1284..bbe2efb 100755 Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index bd3d1ee..35d2595 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws index 668bcb1..0217859 100755 Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ diff --git a/docs/compile/openwrt/package/zapret/tpws/Makefile b/docs/compile/openwrt/package/zapret/tpws/Makefile index c3a111c..f8dc5cf 100644 --- a/docs/compile/openwrt/package/zapret/tpws/Makefile +++ b/docs/compile/openwrt/package/zapret/tpws/Makefile @@ -12,6 +12,7 @@ define Package/tpws CATEGORY:=Network TITLE:=tpws SUBMENU:=Zapret + DEPENDS:=+zlib endef define Build/Prepare diff --git a/docs/readme.txt b/docs/readme.txt index 84da266..b8cbe10 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -97,6 +97,7 @@ nfqws Эта программа - модификатор пакетов и обработчик очереди NFQUEUE. Она берет следующие параметры : --daemon ; демонизировать прогу + --pidfile=<file> ; сохранить PID в файл --qnum=200 ; номер очереди --wsize=4 ; менять tcp window size на указанный размер --hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:". @@ -108,10 +109,11 @@ tpws ----- tpws - это transparent proxy. + --daemon ; демонизировать прогу + --pidfile=<file> ; сохранить PID в файл + --user=<username> ; менять uid процесса --bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6 --port=<port> ; на каком порту слушать - --daemon ; демонизировать прогу - --user=<username> ; менять uid процесса --split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host --split-pos=<offset> ; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb. --hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:". @@ -126,6 +128,7 @@ tpws - это transparent proxy. ; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска. ; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка. ; по сигналу HUP список будет перечитан при следующем принятом соединении + ; список может быть запакован в gzip. формат автоматически распознается и разжимается Параметры манипуляции могут сочетаться в любых комбинациях. Есть исключения : split-pos заменяет split-http-req. hostdot и hosttab взаимоисключающи. @@ -136,7 +139,7 @@ tpws - это transparent proxy. На выходе получите ipset/zapret-ip-user.txt с IP адресами. 2) ipset/get_reestr.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса -в файл ipset/zapret-ip.txt. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде, +в файл ipset/zapret-ip.txt.gz. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде, что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени. @@ -185,7 +188,7 @@ get_reestr.sh может использовать мультипоточный ---------------------------- Альтернативой ipset является использование tpws со списком доменов. -Список доменов РКН может быть получен скриптом ipset/get_hostlist.sh - кладется в ipset/zapret-hosts.txt. +Список доменов РКН может быть получен скриптом ipset/get_hostlist.sh - кладется в ipset/zapret-hosts.txt.gz. Этот скрипт автоматически добавляет к списку РКН домены из zapret-hosts-user.txt. tpws должен запускаться без фильтрации по ipset. Весь трафик http идет через tpws, и он решает нужно ли применять дурение в зависимости от поля Host: в http запросе. @@ -273,7 +276,7 @@ TPWS_OPT_HTTPS="--split-pos=3" systemctl enable zapret Удалить старые листы, если они были созданы ранее : - rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt + rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt* По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. Выполнить скрипт обновления листа : /opt/zapret/ipset/get_config.sh @@ -446,18 +449,18 @@ ipset можно выкинуть, если не будем пользовать rm /tmp/zapret-master.zip Если места совсем мало : - opkg update - opkg install netcat - cd /tmp - netcat -l -p 1111 >zapret.tar.gz + opkg update + opkg install netcat + cd /tmp + netcat -l -p 1111 >zapret.tar.gz На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов. -Запаковать в архив zapret.tar.gz. - md5sum zapret.tar.gz - netcat <router_ip> 1111 <zapret.tar.gz - <ctrl+c> -На роутере - md5sum zapret.tar.gz -Проверить соответствие hash. +Запаковать в архив zapret.tar.gz. + md5sum zapret.tar.gz + netcat <router_ip> 1111 <zapret.tar.gz + <ctrl+c> +На роутере + md5sum zapret.tar.gz +Проверить соответствие hash. Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod. @@ -470,7 +473,7 @@ ipset можно выкинуть, если не будем пользовать Настроить параметры согласно разделу "Выбор параметров". Удалить старые листы, если они были созданы ранее : - rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt + rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt* По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. Выполнить скрипт обновления листа : /opt/zapret/ipset/get_config.sh diff --git a/init.d/openwrt/zapret b/init.d/openwrt/zapret index aa9a813..c25a616 100755 --- a/init.d/openwrt/zapret +++ b/init.d/openwrt/zapret @@ -21,7 +21,8 @@ TPPORT_HTTP=1188 TPPORT_HTTPS=1189 TPWS=$ZAPRET_BASE/tpws/tpws TPWS_USER=daemon -TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt +TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt.gz +[ -f "$TPWS_HOSTLIST" ] || TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts-user.txt TPWS_OPT_BASE="--user=$TPWS_USER --bind-addr=127.0.0.1" TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE" TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE" diff --git a/init.d/sysv/zapret b/init.d/sysv/zapret index 7892552..098d73b 100755 --- a/init.d/sysv/zapret +++ b/init.d/sysv/zapret @@ -28,7 +28,8 @@ TPPORT_HTTP=1188 TPPORT_HTTPS=1189 TPWS=$ZAPRET_BASE/tpws/tpws TPWS_USER=tpws -TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt +TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt.gz +[ -f "$TPWS_HOSTLIST" ] || TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts-user.txt TPWS_OPT_BASE="--user=$TPWS_USER --bind-addr=127.0.0.1" TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE" TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE" diff --git a/install_easy.sh b/install_easy.sh index 9dc0945..cf71605 100755 --- a/install_easy.sh +++ b/install_easy.sh @@ -283,7 +283,7 @@ check_preprequisites_linux() exitp 6 } elif [ -x "$YUM" ] ; then - "$YUM" -y install curl ipset daemonize || { + "$YUM" -y install curl ipset || { echo could not install prerequisites exitp 6 } @@ -366,7 +366,8 @@ download_list() # can be txt or txt.gz rm -f "$EXEDIR/ipset/zapret-ip.txt"* "$EXEDIR/ipset/zapret-ip-user.txt"* \ - "$EXEDIR/ipset/zapret-ip-ipban.txt"* "$EXEDIR/ipset/zapret-ip-user-ipban.txt"* + "$EXEDIR/ipset/zapret-ip-ipban.txt"* "$EXEDIR/ipset/zapret-ip-user-ipban.txt"* \ + "$EXEDIR/ipset/zapret-hosts.txt"* "$GET_LIST" || { echo could not download ip list exitp 25 diff --git a/ipset/get_hostlist.sh b/ipset/get_hostlist.sh index f37dfc4..b912cc9 100755 --- a/ipset/get_hostlist.sh +++ b/ipset/get_hostlist.sh @@ -20,7 +20,7 @@ if test $dlsize -lt 204800; then echo list file is too small. can be bad. exit 2 fi -(cut -s -f2 -d';' "$ZREESTR" | grep -a . | sed -re 's/^\*\.(.+)$/\1/' | awk '{ print tolower($0) }' ; cat "$ZUSERLIST" ) | sort -u >"$ZHOSTLIST" +(cut -s -f2 -d';' "$ZREESTR" | grep -a . | sed -re 's/^\*\.(.+)$/\1/' | awk '{ print tolower($0) }' ; cat "$ZUSERLIST" ) | sort -u | zz "$ZHOSTLIST" rm -f "$ZREESTR" # force tpws to reload if its running diff --git a/ipset/zapret-hosts.txt b/ipset/zapret-hosts.txt deleted file mode 100644 index e69de29..0000000 diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 61ffaae..0395996 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -366,6 +366,46 @@ bool droproot(uid_t uid, gid_t gid) return true; } +void daemonize() +{ + int pid; + + pid = fork(); + if (pid == -1) + { + perror("fork: "); + exit(2); + } + else if (pid != 0) + exit(0); + + if (setsid() == -1) + exit(2); + if (chdir("/") == -1) + exit(2); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + /* redirect fd's 0,1,2 to /dev/null */ + open("/dev/null", O_RDWR); + /* stdin */ + dup(0); + /* stdout */ + dup(0); + /* stderror */ +} + +bool writepid(const char *filename) +{ + FILE *F; + if (!(F=fopen(filename,"w"))) + return false; + fprintf(F,"%d",getpid()); + fclose(F); + return true; +} + + void exithelp() { printf( @@ -375,6 +415,7 @@ void exithelp() " --hostspell\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostnospace\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" " --daemon\t\t; daemonize\n" + " --pidfile=<filename>\t; write pid to file\n" ); exit(1); } @@ -392,10 +433,12 @@ int main(int argc, char **argv) bool daemon=false; uid_t uid=0; gid_t gid; + char pidfile[256]; memset(&cbdata,0,sizeof(cbdata)); memcpy(cbdata.hostspell,"host",4); // default hostspell - + *pidfile = 0; + const struct option long_options[] = { {"qnum",required_argument,0,0}, // optidx=0 {"daemon",no_argument,0,0}, // optidx=1 @@ -404,6 +447,7 @@ int main(int argc, char **argv) {"hostspell",required_argument,0,0}, // optidx=4 {"hostnospace",no_argument,0,0}, // optidx=5 {"user",required_argument,0,0}, // optidx=6 + {"pidfile",required_argument,0,0}, // optidx=7 {NULL,0,NULL,0} }; if (argc<2) exithelp(); @@ -458,64 +502,55 @@ int main(int argc, char **argv) gid = pwd->pw_gid; break; } + case 7: /* pidfile */ + strncpy(pidfile,optarg,sizeof(pidfile)); + pidfile[sizeof(pidfile)-1]='\0'; + break; } } - if (daemon) + + if (daemon) daemonize(); + + h = NULL; + qh = NULL; + + if (*pidfile && !writepid(pidfile)) { - int pid; - - pid = fork(); - if (pid == -1) - return -1; - else if (pid != 0) - return 0; - if (setsid() == -1) - return -1; - if (chdir ("/") == -1) - return -1; - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - /* redirect fd's 0,1,2 to /dev/null */ - open ("/dev/null", O_RDWR); - /* stdin */ - dup(0); - /* stdout */ - dup(0); - /* stderror */ + fprintf(stderr,"could not write pidfile\n"); + goto exiterr; } printf("opening library handle\n"); h = nfq_open(); if (!h) { fprintf(stderr, "error during nfq_open()\n"); - exit(1); + goto exiterr; } printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); if (nfq_unbind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_unbind_pf()\n"); - exit(1); + goto exiterr; } printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); if (nfq_bind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_bind_pf()\n"); - exit(1); + goto exiterr; } printf("binding this socket to queue '%u'\n", cbdata.qnum); qh = nfq_create_queue(h, cbdata.qnum, &cb, &cbdata); if (!qh) { fprintf(stderr, "error during nfq_create_queue()\n"); - exit(1); + goto exiterr; } printf("setting copy_packet mode\n"); if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { fprintf(stderr, "can't set packet_copy mode\n"); - exit(1); + goto exiterr; } fd = nfq_fd(h); @@ -542,5 +577,10 @@ int main(int argc, char **argv) printf("closing library handle\n"); nfq_close(h); - exit(0); + return 0; + +exiterr: + if (qh) nfq_destroy_queue(qh); + if (h) nfq_close(h); + return 1; } diff --git a/tpws/Makefile b/tpws/Makefile index a0cc861..d48ed0b 100644 --- a/tpws/Makefile +++ b/tpws/Makefile @@ -1,6 +1,6 @@ CC ?= gcc CFLAGS += -s -O3 -LIBS = +LIBS = -lz SRC_FILES = *.c all: tpws diff --git a/tpws/gzip.c b/tpws/gzip.c new file mode 100644 index 0000000..e0f1d83 --- /dev/null +++ b/tpws/gzip.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "gzip.h" + +#define ZCHUNK 16384 +#define BUFMIN 128 +#define BUFCHUNK (1024*128) + +int z_readfile(FILE *F,char **buf,size_t *size) +{ + z_stream zs; + int r; + unsigned char in[ZCHUNK]; + size_t bufsize; + void *newbuf; + + memset(&zs,0,sizeof(zs)); + + *buf = NULL; + bufsize=*size=0; + + r=inflateInit2(&zs,47); + if (r != Z_OK) return r; + + do + { + zs.avail_in = fread(in, 1, sizeof(in), F); + if (ferror(F)) + { + r = Z_ERRNO; + goto zerr; + } + if (!zs.avail_in) break; + zs.next_in = in; + do + { + if ((bufsize-*size)<BUFMIN) + { + bufsize += BUFCHUNK; + newbuf = *buf ? realloc(*buf,bufsize) : malloc(bufsize); + if (newbuf==*buf) + if (!newbuf) + { + r = Z_MEM_ERROR; + goto zerr; + } + *buf = newbuf; + } + zs.avail_out = bufsize - *size; + zs.next_out = (unsigned char*)(*buf + *size); + r = inflate(&zs, Z_NO_FLUSH); + if (r!=Z_OK && r!=Z_STREAM_END) goto zerr; + *size = bufsize - zs.avail_out; + } while (r==Z_OK && zs.avail_in); + } while (r==Z_OK); + + if (*size<bufsize) + { + // free extra space + if (newbuf = realloc(*buf,*size)) *buf=newbuf; + } + + inflateEnd(&zs); + return Z_OK; + +zerr: + inflateEnd(&zs); + if (*buf) + { + free(*buf); + *buf = NULL; + } + return r; +} diff --git a/tpws/gzip.h b/tpws/gzip.h new file mode 100644 index 0000000..75c3d87 --- /dev/null +++ b/tpws/gzip.h @@ -0,0 +1,6 @@ +#pragma once + +#include <stdio.h> +#include <zlib.h> + +int z_readfile(FILE *F,char **buf,size_t *size); diff --git a/tpws/hostlist.c b/tpws/hostlist.c new file mode 100644 index 0000000..553d7d2 --- /dev/null +++ b/tpws/hostlist.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include "hostlist.h" +#include "gzip.h" + + +static bool addpool(strpool **hostlist, char **s, char *end) +{ + char *p; + + // advance until eol lowering all chars + for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p); + if (!StrPoolAddStrLen(hostlist, *s, p-*s)) + { + StrPoolDestroy(hostlist); + *hostlist = NULL; + return false; + } + // advance to the next line + for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++); + *s = p; + return true; +} + + +bool LoadHostList(strpool **hostlist, char *filename) +{ + char *p, *e, s[256], *zbuf; + size_t zsize; + int ct = 0; + FILE *F; + + if (*hostlist) + { + StrPoolDestroy(hostlist); + *hostlist = NULL; + } + + if (!(F = fopen(filename, "rb"))) + { + fprintf(stderr, "Could not open %s\n", filename); + return false; + } + if (z_readfile(F,&zbuf,&zsize)==Z_OK) + { + + printf("libz compression detected. uncompressed size : %zu\n", zsize); + fclose(F); + + p = zbuf; + e = zbuf + zsize; + while(p<e) + { + if (!addpool(hostlist,&p,e)) + { + fprintf(stderr, "Not enough memory to store host list : %s\n", filename); + free(zbuf); + return false; + } + ct++; + } + free(zbuf); + } + else + { + fseek(F,0,SEEK_SET); + + while (fgets(s, 256, F)) + { + p = s; + if (!addpool(hostlist,&p,p+strlen(p))) + { + fprintf(stderr, "Not enough memory to store host list : %s\n", filename); + fclose(F); + return false; + } + ct++; + } + fclose(F); + } + printf("Loaded %d hosts from %s\n", ct, filename); + return true; +} diff --git a/tpws/hostlist.h b/tpws/hostlist.h new file mode 100644 index 0000000..186eabd --- /dev/null +++ b/tpws/hostlist.h @@ -0,0 +1,5 @@ +#pragma once + +#include "strpool.h" + +bool LoadHostList(strpool **hostlist, char *filename); diff --git a/tpws/strpool.c b/tpws/strpool.c index dc1ecbf..4ffeb8a 100644 --- a/tpws/strpool.c +++ b/tpws/strpool.c @@ -11,6 +11,7 @@ static void ut_oom_recover(strpool *elem) oom=true; } +// for zero terminated strings bool StrPoolAddStr(strpool **pp,const char *s) { strpool *elem; @@ -31,6 +32,30 @@ bool StrPoolAddStr(strpool **pp,const char *s) } return true; } +// for not zero terminated strings +bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen) +{ + strpool *elem; + if (!(elem = (strpool*)malloc(sizeof(strpool)))) + return false; + if (!(elem->str = malloc(slen+1))) + { + free(elem); + return false; + } + memcpy(elem->str,s,slen); + elem->str[slen]=0; + oom = false; + HASH_ADD_KEYPTR( hh, *pp, elem->str, strlen(elem->str), elem ); + if (oom) + { + free(elem->str); + free(elem); + return false; + } + return true; +} + bool StrPoolCheckStr(strpool *p,const char *s) { strpool *elem; diff --git a/tpws/strpool.h b/tpws/strpool.h index 4579d77..5932ba3 100644 --- a/tpws/strpool.h +++ b/tpws/strpool.h @@ -15,4 +15,5 @@ typedef struct strpool { void StrPoolDestroy(strpool **p); bool StrPoolAddStr(strpool **pp,const char *s); +bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen); bool StrPoolCheckStr(strpool *p,const char *s); diff --git a/tpws/tpws.c b/tpws/tpws.c index 4bddf45..8bd7095 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -24,38 +24,7 @@ #include "tpws.h" #include "tpws_conn.h" -#include "strpool.h" - -bool LoadHostList(strpool **hostlist, char *filename) -{ - char *p, s[256]; - FILE *F = fopen(filename, "rt"); - int ct = 0; - - *hostlist = NULL; - if (!F) - { - fprintf(stderr, "Could not open %s\n", filename); - return false; - } - while (fgets(s, 256, F)) - { - for (p = s + strlen(s) - 1; p >= s && (*p == '\r' || *p == '\n'); p--) *p = 0; - for (p = s; *p; p++) *p=tolower(*p); - if (!StrPoolAddStr(hostlist, s)) - { - StrPoolDestroy(hostlist); - *hostlist = NULL; - fprintf(stderr, "Not enough memory to store host list : %s\n", filename); - fclose(F); - return false; - } - ct++; - } - fclose(F); - printf("Loaded %d hosts from %s\n", ct, filename); - return true; -} +#include "hostlist.h" enum splithttpreq { split_none = 0, split_method, split_host }; @@ -72,6 +41,7 @@ struct params_s int split_pos; int maxconn; char hostfile[256]; + char pidfile[256]; strpool *hostlist; }; @@ -104,7 +74,6 @@ void dohup() { if (params.hostlist) { - StrPoolDestroy(¶ms.hostlist); if (!LoadHostList(¶ms.hostlist, params.hostfile)) exit(1); } @@ -547,11 +516,29 @@ void exithelp() " --methodeol\t\t; add end-of-line before method\n" " --unixeol\t\t; replace 0D0A to 0A\n" " --daemon\t\t; daemonize\n" + " --pidfile=<filename>\t; write pid to file\n" " --user=<username>\t; drop root privs\n" ); exit(1); } - +void cleanup_params() +{ + if (params.hostlist) + { + StrPoolDestroy(¶ms.hostlist); + params.hostlist = NULL; + } +} +void exithelp_clean() +{ + cleanup_params(); + exithelp(); +} +void exit_clean(int code) +{ + cleanup_params(); + exit(code); +} void parse_params(int argc, char *argv[]) { int option_index = 0; @@ -580,16 +567,17 @@ void parse_params(int argc, char *argv[]) { "hosttab",no_argument,0,0 },// optidx=15 { "unixeol",no_argument,0,0 },// optidx=16 { "hostlist",required_argument,0,0 },// optidx=17 + { "pidfile",required_argument,0,0 },// optidx=18 { NULL,0,NULL,0 } }; while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { - if (v) exithelp(); + if (v) exithelp_clean(); switch (option_index) { case 0: case 1: - exithelp(); + exithelp_clean(); break; case 2: /* bind-addr */ strncpy(params.bindaddr, optarg, sizeof(params.bindaddr)); @@ -600,7 +588,7 @@ void parse_params(int argc, char *argv[]) if (i <= 0 || i > 65535) { fprintf(stderr, "bad port number\n"); - exit(1); + exit_clean(1); } params.port = (uint16_t)i; break; @@ -613,7 +601,7 @@ void parse_params(int argc, char *argv[]) if (!pwd) { fprintf(stderr, "non-existent username supplied\n"); - exit(1); + exit_clean(1); } params.uid = pwd->pw_uid; params.gid = pwd->pw_gid; @@ -624,7 +612,7 @@ void parse_params(int argc, char *argv[]) if (params.maxconn <= 0) { fprintf(stderr, "bad maxconn\n"); - exit(1); + exit_clean(1); } break; case 7: /* hostcase */ @@ -634,7 +622,7 @@ void parse_params(int argc, char *argv[]) if (strlen(optarg) != 4) { fprintf(stderr, "hostspell must be exactly 4 chars long\n"); - exit(1); + exit_clean(1); } params.hostcase = true; memcpy(params.hostspell, optarg, 4); @@ -653,7 +641,7 @@ void parse_params(int argc, char *argv[]) else { fprintf(stderr, "Invalid argument for split-http-req\n"); - exit(1); + exit_clean(1); } break; case 12: /* split-pos */ @@ -663,7 +651,7 @@ void parse_params(int argc, char *argv[]) else { fprintf(stderr, "Invalid argument for split-pos\n"); - exit(1); + exit_clean(1); } break; case 13: /* methodspace */ @@ -680,16 +668,20 @@ void parse_params(int argc, char *argv[]) break; case 17: /* hostlist */ if (!LoadHostList(¶ms.hostlist, optarg)) - exit(1); + exit_clean(1); strncpy(params.hostfile,optarg,sizeof(params.hostfile)); params.hostfile[sizeof(params.hostfile)-1]='\0'; break; + case 18: /* pidfile */ + strncpy(params.pidfile,optarg,sizeof(params.pidfile)); + params.pidfile[sizeof(params.pidfile)-1]='\0'; + break; } } if (!params.port) { fprintf(stderr, "Need port number\n"); - exit(1); + exit_clean(1); } } @@ -740,8 +732,18 @@ bool droproot() return true; } +bool writepid(const char *filename) +{ + FILE *F; + if (!(F=fopen(filename,"w"))) + return false; + fprintf(F,"%d",getpid()); + fclose(F); + return true; +} + int main(int argc, char *argv[]) { - int listen_fd = 0; + int listen_fd = -1; int yes = 1, retval = 0; int r; struct sockaddr_storage salisten; @@ -769,7 +771,7 @@ int main(int argc, char *argv[]) { else { printf("bad bind addr\n"); - exit(1); + goto exiterr; } } else @@ -783,29 +785,32 @@ int main(int argc, char *argv[]) { if (params.daemon) daemonize(); + if (*params.pidfile && !writepid(params.pidfile)) + { + fprintf(stderr,"could not write pidfile\n"); + goto exiterr; + } + if ((listen_fd = socket(salisten.ss_family, SOCK_STREAM, 0)) == -1) { perror("socket: "); - exit(EXIT_FAILURE); + goto exiterr; } if ((salisten.ss_family == AF_INET6) && setsockopt(listen_fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)) == -1) { perror("setsockopt (IPV6_ONLY): "); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { perror("setsockopt (SO_REUSEADDR): "); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } if (setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) { perror("setsockopt (SO_KEEPALIVE): "); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } //Mark that this socket can be used for transparent proxying @@ -813,26 +818,22 @@ int main(int argc, char *argv[]) { if (setsockopt(listen_fd, SOL_IP, IP_TRANSPARENT, &yes, sizeof(yes)) == -1) { perror("setsockopt (IP_TRANSPARENT): "); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } if (!droproot()) { - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } if (bind(listen_fd, (struct sockaddr *)&salisten, salisten_len) == -1) { perror("bind: "); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } if (listen(listen_fd, BACKLOG) == -1) { perror("listen: "); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } //splice() causes the process to receive the SIGPIPE-signal if one part (for @@ -840,8 +841,7 @@ int main(int argc, char *argv[]) { //fail and return -1, so blocking SIGPIPE. if (block_sigpipe() == -1) { fprintf(stderr, "Could not block SIGPIPE signal\n"); - close(listen_fd); - exit(EXIT_FAILURE); + goto exiterr; } fprintf(stderr, "Will listen to port %d\n", params.port); @@ -849,14 +849,16 @@ int main(int argc, char *argv[]) { signal(SIGHUP, onhup); retval = event_loop(listen_fd); + close(listen_fd); - - if (params.hostlist) StrPoolDestroy(¶ms.hostlist); + cleanup_params(); fprintf(stderr, "Will exit\n"); - if (retval < 0) - exit(EXIT_FAILURE); - else - exit(EXIT_SUCCESS); + return retval < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + +exiterr: + if (listen_fd!=-1) close(listen_fd); + cleanup_params(); + return EXIT_FAILURE; }