Browse Source

gzip support in ipset/*.sh and tpws

pull/33/head
bolvan 6 years ago
parent
commit
c5dc07d049
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/aarch64/tpws
  3. BIN
      binaries/armhf/nfqws
  4. BIN
      binaries/armhf/tpws
  5. BIN
      binaries/mips32r1-lsb/nfqws
  6. BIN
      binaries/mips32r1-lsb/tpws
  7. BIN
      binaries/mips32r1-msb/nfqws
  8. BIN
      binaries/mips32r1-msb/tpws
  9. BIN
      binaries/ppc/nfqws
  10. BIN
      binaries/ppc/tpws
  11. BIN
      binaries/x86/nfqws
  12. BIN
      binaries/x86/tpws
  13. BIN
      binaries/x86_64/nfqws
  14. BIN
      binaries/x86_64/tpws
  15. 1
      docs/compile/openwrt/package/zapret/tpws/Makefile
  16. 37
      docs/readme.txt
  17. 3
      init.d/openwrt/zapret
  18. 3
      init.d/sysv/zapret
  19. 5
      install_easy.sh
  20. 2
      ipset/get_hostlist.sh
  21. 0
      ipset/zapret-hosts.txt
  22. 98
      nfq/nfqws.c
  23. 2
      tpws/Makefile
  24. 75
      tpws/gzip.c
  25. 6
      tpws/gzip.h
  26. 82
      tpws/hostlist.c
  27. 5
      tpws/hostlist.h
  28. 25
      tpws/strpool.c
  29. 1
      tpws/strpool.h
  30. 140
      tpws/tpws.c

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/aarch64/tpws

Binary file not shown.

BIN
binaries/armhf/nfqws

Binary file not shown.

BIN
binaries/armhf/tpws

Binary file not shown.

BIN
binaries/mips32r1-lsb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-lsb/tpws

Binary file not shown.

BIN
binaries/mips32r1-msb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-msb/tpws

Binary file not shown.

BIN
binaries/ppc/nfqws

Binary file not shown.

BIN
binaries/ppc/tpws

Binary file not shown.

BIN
binaries/x86/nfqws

Binary file not shown.

BIN
binaries/x86/tpws

Binary file not shown.

BIN
binaries/x86_64/nfqws

Binary file not shown.

BIN
binaries/x86_64/tpws

Binary file not shown.

1
docs/compile/openwrt/package/zapret/tpws/Makefile

@ -12,6 +12,7 @@ define Package/tpws
CATEGORY:=Network CATEGORY:=Network
TITLE:=tpws TITLE:=tpws
SUBMENU:=Zapret SUBMENU:=Zapret
DEPENDS:=+zlib
endef endef
define Build/Prepare define Build/Prepare

37
docs/readme.txt

@ -97,6 +97,7 @@ nfqws
Эта программа - модификатор пакетов и обработчик очереди NFQUEUE. Эта программа - модификатор пакетов и обработчик очереди NFQUEUE.
Она берет следующие параметры : Она берет следующие параметры :
--daemon ; демонизировать прогу --daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--qnum=200 ; номер очереди --qnum=200 ; номер очереди
--wsize=4 ; менять tcp window size на указанный размер --wsize=4 ; менять tcp window size на указанный размер
--hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:". --hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:".
@ -108,10 +109,11 @@ tpws
----- -----
tpws - это transparent proxy. tpws - это transparent proxy.
--bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
--port=<port> ; на каком порту слушать
--daemon ; демонизировать прогу --daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса --user=<username> ; менять uid процесса
--bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
--port=<port> ; на каком порту слушать
--split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host --split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host
--split-pos=<offset> ; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb. --split-pos=<offset> ; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb.
--hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:". --hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:".
@ -126,6 +128,7 @@ tpws - это transparent proxy.
; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска. ; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка. ; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка.
; по сигналу HUP список будет перечитан при следующем принятом соединении ; по сигналу HUP список будет перечитан при следующем принятом соединении
; список может быть запакован в gzip. формат автоматически распознается и разжимается
Параметры манипуляции могут сочетаться в любых комбинациях. Параметры манипуляции могут сочетаться в любых комбинациях.
Есть исключения : split-pos заменяет split-http-req. hostdot и hosttab взаимоисключающи. Есть исключения : split-pos заменяет split-http-req. hostdot и hosttab взаимоисключающи.
@ -136,7 +139,7 @@ tpws - это transparent proxy.
На выходе получите ipset/zapret-ip-user.txt с IP адресами. На выходе получите ipset/zapret-ip-user.txt с IP адресами.
2) ipset/get_reestr.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса 2) ipset/get_reestr.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса
в файл ipset/zapret-ip.txt. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде, в файл ipset/zapret-ip.txt.gz. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде,
что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко
банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости
от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени. от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени.
@ -185,7 +188,7 @@ get_reestr.sh может использовать мультипоточный
---------------------------- ----------------------------
Альтернативой ipset является использование tpws со списком доменов. Альтернативой ipset является использование tpws со списком доменов.
Список доменов РКН может быть получен скриптом ipset/get_hostlist.sh - кладется в ipset/zapret-hosts.txt. Список доменов РКН может быть получен скриптом ipset/get_hostlist.sh - кладется в ipset/zapret-hosts.txt.gz.
Этот скрипт автоматически добавляет к списку РКН домены из zapret-hosts-user.txt. Этот скрипт автоматически добавляет к списку РКН домены из zapret-hosts-user.txt.
tpws должен запускаться без фильтрации по ipset. Весь трафик http идет через tpws, и он решает нужно ли tpws должен запускаться без фильтрации по ipset. Весь трафик http идет через tpws, и он решает нужно ли
применять дурение в зависимости от поля Host: в http запросе. применять дурение в зависимости от поля Host: в http запросе.
@ -273,7 +276,7 @@ TPWS_OPT_HTTPS="--split-pos=3"
systemctl enable zapret 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/zapret-hosts-user.txt свои домены.
Выполнить скрипт обновления листа : Выполнить скрипт обновления листа :
/opt/zapret/ipset/get_config.sh /opt/zapret/ipset/get_config.sh
@ -446,18 +449,18 @@ ipset можно выкинуть, если не будем пользовать
rm /tmp/zapret-master.zip rm /tmp/zapret-master.zip
Если места совсем мало : Если места совсем мало :
opkg update opkg update
opkg install netcat opkg install netcat
cd /tmp cd /tmp
netcat -l -p 1111 >zapret.tar.gz netcat -l -p 1111 >zapret.tar.gz
На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов. На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов.
Запаковать в архив zapret.tar.gz. Запаковать в архив zapret.tar.gz.
md5sum zapret.tar.gz md5sum zapret.tar.gz
netcat <router_ip> 1111 <zapret.tar.gz netcat <router_ip> 1111 <zapret.tar.gz
<ctrl+c> <ctrl+c>
На роутере На роутере
md5sum zapret.tar.gz md5sum zapret.tar.gz
Проверить соответствие hash. Проверить соответствие hash.
Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod. Не стоит работать с распакованной версией 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/zapret-hosts-user.txt свои домены.
Выполнить скрипт обновления листа : Выполнить скрипт обновления листа :
/opt/zapret/ipset/get_config.sh /opt/zapret/ipset/get_config.sh

3
init.d/openwrt/zapret

@ -21,7 +21,8 @@ TPPORT_HTTP=1188
TPPORT_HTTPS=1189 TPPORT_HTTPS=1189
TPWS=$ZAPRET_BASE/tpws/tpws TPWS=$ZAPRET_BASE/tpws/tpws
TPWS_USER=daemon 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="--user=$TPWS_USER --bind-addr=127.0.0.1"
TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE" TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE"
TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE" TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE"

3
init.d/sysv/zapret

@ -28,7 +28,8 @@ TPPORT_HTTP=1188
TPPORT_HTTPS=1189 TPPORT_HTTPS=1189
TPWS=$ZAPRET_BASE/tpws/tpws TPWS=$ZAPRET_BASE/tpws/tpws
TPWS_USER=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="--user=$TPWS_USER --bind-addr=127.0.0.1"
TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE" TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE"
TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE" TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE"

5
install_easy.sh

@ -283,7 +283,7 @@ check_preprequisites_linux()
exitp 6 exitp 6
} }
elif [ -x "$YUM" ] ; then elif [ -x "$YUM" ] ; then
"$YUM" -y install curl ipset daemonize || { "$YUM" -y install curl ipset || {
echo could not install prerequisites echo could not install prerequisites
exitp 6 exitp 6
} }
@ -366,7 +366,8 @@ download_list()
# can be txt or txt.gz # can be txt or txt.gz
rm -f "$EXEDIR/ipset/zapret-ip.txt"* "$EXEDIR/ipset/zapret-ip-user.txt"* \ 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" || { "$GET_LIST" || {
echo could not download ip list echo could not download ip list
exitp 25 exitp 25

2
ipset/get_hostlist.sh

@ -20,7 +20,7 @@ if test $dlsize -lt 204800; then
echo list file is too small. can be bad. echo list file is too small. can be bad.
exit 2 exit 2
fi 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" rm -f "$ZREESTR"
# force tpws to reload if its running # force tpws to reload if its running

0
ipset/zapret-hosts.txt

98
nfq/nfqws.c

@ -366,6 +366,46 @@ bool droproot(uid_t uid, gid_t gid)
return true; 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() void exithelp()
{ {
printf( printf(
@ -375,6 +415,7 @@ void exithelp()
" --hostspell\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --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" " --hostnospace\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
" --daemon\t\t; daemonize\n" " --daemon\t\t; daemonize\n"
" --pidfile=<filename>\t; write pid to file\n"
); );
exit(1); exit(1);
} }
@ -392,10 +433,12 @@ int main(int argc, char **argv)
bool daemon=false; bool daemon=false;
uid_t uid=0; uid_t uid=0;
gid_t gid; gid_t gid;
char pidfile[256];
memset(&cbdata,0,sizeof(cbdata)); memset(&cbdata,0,sizeof(cbdata));
memcpy(cbdata.hostspell,"host",4); // default hostspell memcpy(cbdata.hostspell,"host",4); // default hostspell
*pidfile = 0;
const struct option long_options[] = { const struct option long_options[] = {
{"qnum",required_argument,0,0}, // optidx=0 {"qnum",required_argument,0,0}, // optidx=0
{"daemon",no_argument,0,0}, // optidx=1 {"daemon",no_argument,0,0}, // optidx=1
@ -404,6 +447,7 @@ int main(int argc, char **argv)
{"hostspell",required_argument,0,0}, // optidx=4 {"hostspell",required_argument,0,0}, // optidx=4
{"hostnospace",no_argument,0,0}, // optidx=5 {"hostnospace",no_argument,0,0}, // optidx=5
{"user",required_argument,0,0}, // optidx=6 {"user",required_argument,0,0}, // optidx=6
{"pidfile",required_argument,0,0}, // optidx=7
{NULL,0,NULL,0} {NULL,0,NULL,0}
}; };
if (argc<2) exithelp(); if (argc<2) exithelp();
@ -458,64 +502,55 @@ int main(int argc, char **argv)
gid = pwd->pw_gid; gid = pwd->pw_gid;
break; 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; fprintf(stderr,"could not write pidfile\n");
goto exiterr;
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 */
} }
printf("opening library handle\n"); printf("opening library handle\n");
h = nfq_open(); h = nfq_open();
if (!h) { if (!h) {
fprintf(stderr, "error during nfq_open()\n"); fprintf(stderr, "error during nfq_open()\n");
exit(1); goto exiterr;
} }
printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
if (nfq_unbind_pf(h, AF_INET) < 0) { if (nfq_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_unbind_pf()\n"); fprintf(stderr, "error during nfq_unbind_pf()\n");
exit(1); goto exiterr;
} }
printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
if (nfq_bind_pf(h, AF_INET) < 0) { if (nfq_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_bind_pf()\n"); fprintf(stderr, "error during nfq_bind_pf()\n");
exit(1); goto exiterr;
} }
printf("binding this socket to queue '%u'\n", cbdata.qnum); printf("binding this socket to queue '%u'\n", cbdata.qnum);
qh = nfq_create_queue(h, cbdata.qnum, &cb, &cbdata); qh = nfq_create_queue(h, cbdata.qnum, &cb, &cbdata);
if (!qh) { if (!qh) {
fprintf(stderr, "error during nfq_create_queue()\n"); fprintf(stderr, "error during nfq_create_queue()\n");
exit(1); goto exiterr;
} }
printf("setting copy_packet mode\n"); printf("setting copy_packet mode\n");
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "can't set packet_copy mode\n"); fprintf(stderr, "can't set packet_copy mode\n");
exit(1); goto exiterr;
} }
fd = nfq_fd(h); fd = nfq_fd(h);
@ -542,5 +577,10 @@ int main(int argc, char **argv)
printf("closing library handle\n"); printf("closing library handle\n");
nfq_close(h); nfq_close(h);
exit(0); return 0;
exiterr:
if (qh) nfq_destroy_queue(qh);
if (h) nfq_close(h);
return 1;
} }

2
tpws/Makefile

@ -1,6 +1,6 @@
CC ?= gcc CC ?= gcc
CFLAGS += -s -O3 CFLAGS += -s -O3
LIBS = LIBS = -lz
SRC_FILES = *.c SRC_FILES = *.c
all: tpws all: tpws

75
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;
}

6
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);

82
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;
}

5
tpws/hostlist.h

@ -0,0 +1,5 @@
#pragma once
#include "strpool.h"
bool LoadHostList(strpool **hostlist, char *filename);

25
tpws/strpool.c

@ -11,6 +11,7 @@ static void ut_oom_recover(strpool *elem)
oom=true; oom=true;
} }
// for zero terminated strings
bool StrPoolAddStr(strpool **pp,const char *s) bool StrPoolAddStr(strpool **pp,const char *s)
{ {
strpool *elem; strpool *elem;
@ -31,6 +32,30 @@ bool StrPoolAddStr(strpool **pp,const char *s)
} }
return true; 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) bool StrPoolCheckStr(strpool *p,const char *s)
{ {
strpool *elem; strpool *elem;

1
tpws/strpool.h

@ -15,4 +15,5 @@ typedef struct strpool {
void StrPoolDestroy(strpool **p); void StrPoolDestroy(strpool **p);
bool StrPoolAddStr(strpool **pp,const char *s); bool StrPoolAddStr(strpool **pp,const char *s);
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
bool StrPoolCheckStr(strpool *p,const char *s); bool StrPoolCheckStr(strpool *p,const char *s);

140
tpws/tpws.c

@ -24,38 +24,7 @@
#include "tpws.h" #include "tpws.h"
#include "tpws_conn.h" #include "tpws_conn.h"
#include "strpool.h" #include "hostlist.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;
}
enum splithttpreq { split_none = 0, split_method, split_host }; enum splithttpreq { split_none = 0, split_method, split_host };
@ -72,6 +41,7 @@ struct params_s
int split_pos; int split_pos;
int maxconn; int maxconn;
char hostfile[256]; char hostfile[256];
char pidfile[256];
strpool *hostlist; strpool *hostlist;
}; };
@ -104,7 +74,6 @@ void dohup()
{ {
if (params.hostlist) if (params.hostlist)
{ {
StrPoolDestroy(&params.hostlist);
if (!LoadHostList(&params.hostlist, params.hostfile)) if (!LoadHostList(&params.hostlist, params.hostfile))
exit(1); exit(1);
} }
@ -547,11 +516,29 @@ void exithelp()
" --methodeol\t\t; add end-of-line before method\n" " --methodeol\t\t; add end-of-line before method\n"
" --unixeol\t\t; replace 0D0A to 0A\n" " --unixeol\t\t; replace 0D0A to 0A\n"
" --daemon\t\t; daemonize\n" " --daemon\t\t; daemonize\n"
" --pidfile=<filename>\t; write pid to file\n"
" --user=<username>\t; drop root privs\n" " --user=<username>\t; drop root privs\n"
); );
exit(1); exit(1);
} }
void cleanup_params()
{
if (params.hostlist)
{
StrPoolDestroy(&params.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[]) void parse_params(int argc, char *argv[])
{ {
int option_index = 0; int option_index = 0;
@ -580,16 +567,17 @@ void parse_params(int argc, char *argv[])
{ "hosttab",no_argument,0,0 },// optidx=15 { "hosttab",no_argument,0,0 },// optidx=15
{ "unixeol",no_argument,0,0 },// optidx=16 { "unixeol",no_argument,0,0 },// optidx=16
{ "hostlist",required_argument,0,0 },// optidx=17 { "hostlist",required_argument,0,0 },// optidx=17
{ "pidfile",required_argument,0,0 },// optidx=18
{ NULL,0,NULL,0 } { NULL,0,NULL,0 }
}; };
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{ {
if (v) exithelp(); if (v) exithelp_clean();
switch (option_index) switch (option_index)
{ {
case 0: case 0:
case 1: case 1:
exithelp(); exithelp_clean();
break; break;
case 2: /* bind-addr */ case 2: /* bind-addr */
strncpy(params.bindaddr, optarg, sizeof(params.bindaddr)); strncpy(params.bindaddr, optarg, sizeof(params.bindaddr));
@ -600,7 +588,7 @@ void parse_params(int argc, char *argv[])
if (i <= 0 || i > 65535) if (i <= 0 || i > 65535)
{ {
fprintf(stderr, "bad port number\n"); fprintf(stderr, "bad port number\n");
exit(1); exit_clean(1);
} }
params.port = (uint16_t)i; params.port = (uint16_t)i;
break; break;
@ -613,7 +601,7 @@ void parse_params(int argc, char *argv[])
if (!pwd) if (!pwd)
{ {
fprintf(stderr, "non-existent username supplied\n"); fprintf(stderr, "non-existent username supplied\n");
exit(1); exit_clean(1);
} }
params.uid = pwd->pw_uid; params.uid = pwd->pw_uid;
params.gid = pwd->pw_gid; params.gid = pwd->pw_gid;
@ -624,7 +612,7 @@ void parse_params(int argc, char *argv[])
if (params.maxconn <= 0) if (params.maxconn <= 0)
{ {
fprintf(stderr, "bad maxconn\n"); fprintf(stderr, "bad maxconn\n");
exit(1); exit_clean(1);
} }
break; break;
case 7: /* hostcase */ case 7: /* hostcase */
@ -634,7 +622,7 @@ void parse_params(int argc, char *argv[])
if (strlen(optarg) != 4) if (strlen(optarg) != 4)
{ {
fprintf(stderr, "hostspell must be exactly 4 chars long\n"); fprintf(stderr, "hostspell must be exactly 4 chars long\n");
exit(1); exit_clean(1);
} }
params.hostcase = true; params.hostcase = true;
memcpy(params.hostspell, optarg, 4); memcpy(params.hostspell, optarg, 4);
@ -653,7 +641,7 @@ void parse_params(int argc, char *argv[])
else else
{ {
fprintf(stderr, "Invalid argument for split-http-req\n"); fprintf(stderr, "Invalid argument for split-http-req\n");
exit(1); exit_clean(1);
} }
break; break;
case 12: /* split-pos */ case 12: /* split-pos */
@ -663,7 +651,7 @@ void parse_params(int argc, char *argv[])
else else
{ {
fprintf(stderr, "Invalid argument for split-pos\n"); fprintf(stderr, "Invalid argument for split-pos\n");
exit(1); exit_clean(1);
} }
break; break;
case 13: /* methodspace */ case 13: /* methodspace */
@ -680,16 +668,20 @@ void parse_params(int argc, char *argv[])
break; break;
case 17: /* hostlist */ case 17: /* hostlist */
if (!LoadHostList(&params.hostlist, optarg)) if (!LoadHostList(&params.hostlist, optarg))
exit(1); exit_clean(1);
strncpy(params.hostfile,optarg,sizeof(params.hostfile)); strncpy(params.hostfile,optarg,sizeof(params.hostfile));
params.hostfile[sizeof(params.hostfile)-1]='\0'; params.hostfile[sizeof(params.hostfile)-1]='\0';
break; break;
case 18: /* pidfile */
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
params.pidfile[sizeof(params.pidfile)-1]='\0';
break;
} }
} }
if (!params.port) if (!params.port)
{ {
fprintf(stderr, "Need port number\n"); fprintf(stderr, "Need port number\n");
exit(1); exit_clean(1);
} }
} }
@ -740,8 +732,18 @@ bool droproot()
return true; 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 main(int argc, char *argv[]) {
int listen_fd = 0; int listen_fd = -1;
int yes = 1, retval = 0; int yes = 1, retval = 0;
int r; int r;
struct sockaddr_storage salisten; struct sockaddr_storage salisten;
@ -769,7 +771,7 @@ int main(int argc, char *argv[]) {
else else
{ {
printf("bad bind addr\n"); printf("bad bind addr\n");
exit(1); goto exiterr;
} }
} }
else else
@ -783,29 +785,32 @@ int main(int argc, char *argv[]) {
if (params.daemon) daemonize(); 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) { if ((listen_fd = socket(salisten.ss_family, SOCK_STREAM, 0)) == -1) {
perror("socket: "); 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) if ((salisten.ss_family == AF_INET6) && setsockopt(listen_fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)) == -1)
{ {
perror("setsockopt (IPV6_ONLY): "); perror("setsockopt (IPV6_ONLY): ");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
{ {
perror("setsockopt (SO_REUSEADDR): "); perror("setsockopt (SO_REUSEADDR): ");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
if (setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) if (setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1)
{ {
perror("setsockopt (SO_KEEPALIVE): "); perror("setsockopt (SO_KEEPALIVE): ");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
//Mark that this socket can be used for transparent proxying //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) if (setsockopt(listen_fd, SOL_IP, IP_TRANSPARENT, &yes, sizeof(yes)) == -1)
{ {
perror("setsockopt (IP_TRANSPARENT): "); perror("setsockopt (IP_TRANSPARENT): ");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
if (!droproot()) if (!droproot())
{ {
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
if (bind(listen_fd, (struct sockaddr *)&salisten, salisten_len) == -1) { if (bind(listen_fd, (struct sockaddr *)&salisten, salisten_len) == -1) {
perror("bind: "); perror("bind: ");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
if (listen(listen_fd, BACKLOG) == -1) { if (listen(listen_fd, BACKLOG) == -1) {
perror("listen: "); perror("listen: ");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
//splice() causes the process to receive the SIGPIPE-signal if one part (for //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. //fail and return -1, so blocking SIGPIPE.
if (block_sigpipe() == -1) { if (block_sigpipe() == -1) {
fprintf(stderr, "Could not block SIGPIPE signal\n"); fprintf(stderr, "Could not block SIGPIPE signal\n");
close(listen_fd); goto exiterr;
exit(EXIT_FAILURE);
} }
fprintf(stderr, "Will listen to port %d\n", params.port); fprintf(stderr, "Will listen to port %d\n", params.port);
@ -849,14 +849,16 @@ int main(int argc, char *argv[]) {
signal(SIGHUP, onhup); signal(SIGHUP, onhup);
retval = event_loop(listen_fd); retval = event_loop(listen_fd);
close(listen_fd); close(listen_fd);
cleanup_params();
if (params.hostlist) StrPoolDestroy(&params.hostlist);
fprintf(stderr, "Will exit\n"); fprintf(stderr, "Will exit\n");
if (retval < 0) return retval < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
exit(EXIT_FAILURE);
else exiterr:
exit(EXIT_SUCCESS); if (listen_fd!=-1) close(listen_fd);
cleanup_params();
return EXIT_FAILURE;
} }

Loading…
Cancel
Save