gzip support in ipset/*.sh and tpws

This commit is contained in:
bolvan 2019-05-09 19:03:50 +03:00
parent 7d59377009
commit c5dc07d049
30 changed files with 364 additions and 121 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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

View File

@ -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.
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6 --bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
--port=<port> ; на каком порту слушать --port=<port> ; на каком порту слушать
--daemon ; демонизировать прогу
--user=<username> ; менять uid процесса
--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
@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

View File

@ -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,9 +433,11 @@ 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
@ -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)
{
int pid;
pid = fork(); if (daemon) daemonize();
if (pid == -1)
return -1; h = NULL;
else if (pid != 0) qh = NULL;
return 0;
if (setsid() == -1) if (*pidfile && !writepid(pidfile))
return -1; {
if (chdir ("/") == -1) fprintf(stderr,"could not write pidfile\n");
return -1; goto exiterr;
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;
} }

View File

@ -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 Normal file
View File

@ -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 Normal file
View File

@ -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 Normal file
View File

@ -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 Normal file
View File

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

View File

@ -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;

View File

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

View File

@ -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);
if (params.hostlist) StrPoolDestroy(&params.hostlist); close(listen_fd);
cleanup_params();
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;
} }