diff --git a/changes.txt b/changes.txt index dca8114..9618cf1 100644 --- a/changes.txt +++ b/changes.txt @@ -22,3 +22,6 @@ ISP support : successfully tested sknt.ru on 'domru' configuration other configs will probably also work, but cannot test compile : openwrt compile howto +v4 + +tpws : added ability to insert extra space after http method : "GET /" => "GET /" diff --git a/readme.txt b/readme.txt index d8089a2..ae1597d 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -zapret v.3 +zapret v.4 Для чего это надо ----------------- @@ -23,6 +23,7 @@ что сервер увеличил window size, и все пойдет как обычно. Другие DPI спотыкаются, когда заголовок "Host:" пишется в другом регистре : например, "host:". +Кое-где работает добавление дополнительного проблема после метода : "GET /" => "GET /". Как это реализовать на практике в системе linux ----------------------------------------------- @@ -76,11 +77,13 @@ transparent proxy (TPROXY или DNAT). TPROXY не работает с соед и для этого пользователя отключается DNAT через "-m owner". Полное проксирование требует больше ресурсов процессора, чем манипуляция с исходящими пакетами без реконструкции TCP соединения. +iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 127.0.0.1:1188 +iptables -t nat -I OUTPUT -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.1:1188 nfqws ----- -Эта программа и есть модификатор пакетов и обработчик очереди NFQUEUE. +Эта программа - модификатор пакетов и обработчик очереди NFQUEUE. Она берет следующие параметры : --qnum=200 ; номер очереди --wsize=4 ; менять tcp window size на указанный размер @@ -91,11 +94,13 @@ tpws ----- tpws - это transparent proxy. - --bind-addr ; на каком адресе слушать + --bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6 --port= ; на каком порту слушать --split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host - --hostcase ; change Host: => host: - --daemon ; daemonize + --hostcase ; замена "Host:" => "host:" + --methodspace ; добавить пробел после метода : "GET /" => "GET /" + --daemon ; демонизировать прогу + --user= ; менять uid процесса Провайдеры ---------- @@ -107,6 +112,8 @@ dom.ru : нужно проксирование HTTP сессий через tpws блокировок, поэтому если вдруг на каком-то сайте вылезает блокировочный баннер, то идите в консоль firefox, вкладка network. Загружайте сайт и смотрите куда идет редирект. Потом вносите домен в zapret-hosts-user.txt. Например, на kinozal.tv имеются 2 запрашиваемых поддомена : s.kinozal.tv и st.kinozal.tv с разными IP адресами. +sknt.ru : проверена работа с tpws с параметром "--split-http-req=method". возможно, будет работать nfqueue, пока возможности + проверить нет Пример установки на debian 7 ---------------------------- @@ -141,6 +148,31 @@ dom.ru : нужно проксирование HTTP сессий через tpws Попробуйте снять дамп в wireshark или "tcpdump -vvv -X host ", посмотрите действительно ли первый сегмент TCP уходит коротким и меняется ли регистр "Host:". +ubuntu 12,14 +------------ + +Имеется готовый конфиг для upstart : zapret.conf. Его нужно скопировать в /etc/init и настроить по аналогии с debian. +Запуск службы : "start zapret" +Останов службы : "stop zapret" + +Другие linux системы +-------------------- + +Существует несколько основных систем запуска служб : sysvinit, upstart, systemd. +Насройка зависит от системы, используемой в вашем дистрибутиве. +Типичная стратегия - найти скрипт или конфигурацию запуска других служб и написать свой по аналогии, +при необходимости почитывая документации по системе запуска. +Нужные команды можно взять из предложенных скриптов. + +Фаерволлы +--------- + +Если вы используете какую-то систему управления фаерволом, то она может вступать в конфликт +с имеющимся скриптом запуска. В этом случае правила для iptables должны быть прикручены +к вашему фаерволу отдельно от скрипта запуска tpws или nfqws. +Именно так решается вопрос в случае с openwrt, поскольку там своя система управления фаерволом. +При повторном применении правил она могла бы поломать настройки iptables, сделанные скриптом из init.d. + Что делать с openwrt -------------------- diff --git a/tpws/tpws.c b/tpws/tpws.c index 1cfe900..fd8c8a9 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -33,7 +33,7 @@ struct params_s gid_t gid; uint16_t port; bool daemon; - bool hostcase,methodcase; + bool hostcase,methodcase,methodspace; enum splithttpreq split_http_req; int maxconn; }; @@ -77,11 +77,13 @@ void close_tcp_conn(tproxy_conn_t *conn, struct tailhead *conn_list, static const char *http_split_methods[]={"GET /","POST /","HEAD /","OPTIONS /",NULL}; static const char *http_split_host[]={"\r\nHost: ",NULL}; +#define RD_BLOCK_SIZE 8192 + bool handle_epollin(tproxy_conn_t *conn,int *data_transferred){ int numbytes; int fd_in, fd_out; bool bOutgoing; - ssize_t rd=0,wr=0; + ssize_t rd=0,wr=0,bs; //Easy way to determin which socket is ready for reading //TODO: Optimize. This one allows me quick lookup for conn, but @@ -104,40 +106,63 @@ bool handle_epollin(tproxy_conn_t *conn,int *data_transferred){ { if (bOutgoing) { - char buf[8192],*p; - ssize_t l,split_pos=0; - const char **split_array,**split_item; + char buf[RD_BLOCK_SIZE+1],*p; + ssize_t l,split_pos=0,pos; + const char **split_array,**split_item,**item; - rd = recv(fd_in,buf,sizeof(buf),MSG_DONTWAIT); + rd = recv(fd_in,buf,RD_BLOCK_SIZE,MSG_DONTWAIT); if (rd>0) { + bs = rd; + if (params.methodspace) + { + for(item=http_split_methods;*item;item++) + { + l = strlen(*item); + if (p=find_bin(buf,bs,*item,l)) + { + pos = p-buf; + printf("Found http method '%s' at pos %d. Adding extra space.\n",*item,pos); + p += l-1; + pos += l-1; + memmove(p+1,p,bs-pos); + *p = ' '; // insert extra space + bs++; // block will grow by 1 byte + split_pos = pos; // remember split positing and use it if required + break; + } + } + } switch (params.split_http_req) { case split_method: - split_array = http_split_methods; + // do we have already split position ? if so use it without another search + split_array = split_pos ? NULL : http_split_methods; break; case split_host: split_array = http_split_host; break; default: split_array = NULL; + split_pos=0; } if (split_array) { for(split_item=split_array;*split_item;split_item++) { l = strlen(*split_item); - if (p=find_bin(buf,rd,*split_item,l)) + if (p=find_bin(buf,bs,*split_item,l)) { split_pos = p-buf; printf("Found split item '%s' at pos %d\n",*split_item,split_pos); split_pos += l-1; + break; } } } if (params.hostcase) { - if (p=find_bin(buf,rd,"\r\nHost: ",8)) + if (p=find_bin(buf,bs,"\r\nHost: ",8)) { printf("Changing 'Host:' => 'host:' at pos %d\n",p-buf); p[2]='h'; @@ -148,7 +173,7 @@ bool handle_epollin(tproxy_conn_t *conn,int *data_transferred){ for(split_item=http_split_methods;*split_item;split_item++) { l = strlen(*split_item); - if (p=find_bin(buf,rd,*split_item,l)) + if (p=find_bin(buf,bs,*split_item,l)) { printf("Changing '%s' case\n",*split_item); *p += 'a'-'A'; @@ -160,11 +185,11 @@ bool handle_epollin(tproxy_conn_t *conn,int *data_transferred){ { wr=send_with_flush(fd_out,buf,split_pos,0); if (wr>=0) - wr=send(fd_out,buf+split_pos,rd-split_pos,0); + wr=send(fd_out,buf+split_pos,bs-split_pos,0); } else { - wr=send(fd_out,buf,rd,0); + wr=send(fd_out,buf,bs,0); } } } @@ -341,7 +366,7 @@ int8_t block_sigpipe(){ void exithelp() { - printf(" --bind-addr=|\n --port=\n --maxconn=\n --split-http-req=method|host\n --hostcase\t\t; change Host: => host:\n --methodcase\t\t; change GET => gET, POST=>pOST, ...\n --daemon\t\t; daemonize\n --user=\t; drop root privs\n"); + printf(" --bind-addr=|\n --port=\n --maxconn=\n --split-http-req=method|host\n --hostcase\t\t; change Host: => host:\n --methodcase\t\t; change GET => gET, POST=>pOST, ...\n --methodspace\t\t; add extra space after method\n --daemon\t\t; daemonize\n --user=\t; drop root privs\n"); exit(1); } @@ -364,6 +389,7 @@ void parse_params(int argc, char *argv[]) {"hostcase",no_argument,0,0},// optidx=7 {"methodcase",no_argument,0,0},// optidx=8 {"split-http-req",required_argument,0,0},// optidx=9 + {"methodspace",no_argument,0,0},// optidx=10 {NULL,0,NULL,0} }; while ((v=getopt_long_only(argc,argv,"",long_options,&option_index))!=-1) @@ -428,6 +454,9 @@ void parse_params(int argc, char *argv[]) exit(1); } break; + case 10: /* methodspace */ + params.methodspace = true; + break; } } if (!params.port)