mirror of
https://github.com/bol-van/zapret.git
synced 2025-04-19 05:22:58 +03:00
Merge branch 'bol-van:master' into master
This commit is contained in:
commit
5874500977
@ -1,4 +1,9 @@
|
|||||||
# zapret v.67
|
# zapret v.68
|
||||||
|
|
||||||
|
# SCAMMER WARNING
|
||||||
|
|
||||||
|
This software is free and open source under [MIT license](./LICENSE.txt).
|
||||||
|
If anyone demands you to download this software only from their webpage, telegram channel, forces you to delete links, videos, makes copyright claims, you are dealing with scammers.
|
||||||
|
|
||||||
# Multilanguage/Мультиязычный README
|
# Multilanguage/Мультиязычный README
|
||||||
___
|
___
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
# zapret v.68
|
# zapret v.68
|
||||||
|
|
||||||
|
# ВНИМАНИЕ, остерегайтесь мошенников
|
||||||
|
|
||||||
|
zapret является свободным и open source.
|
||||||
|
Всякий, кто понуждает вас скачивать zapret только с его ресурса, требует удалить ссылки, видео, файлы, обосновывая эти требования авторскими правами, сам нарушает [лицензию](./LICENSE.txt).
|
||||||
|
|
||||||
# Multilanguage README
|
# Multilanguage README
|
||||||
|
|
||||||
[](./readme.en.md)
|
[](./readme.en.md)
|
||||||
@ -1313,9 +1318,9 @@ linux, но через раз приобретает статус INVALID в con
|
|||||||
она стабильна, на третьих полный хаос, и проще отказаться.
|
она стабильна, на третьих полный хаос, и проще отказаться.
|
||||||
|
|
||||||
`Blockcheck` имеет 3 уровня сканирования.
|
`Blockcheck` имеет 3 уровня сканирования.
|
||||||
Цель режима quick - максимально быстро найти хоть что-то работающее.\
|
* `quick` - максимально быстро найти хоть что-то работающее.
|
||||||
`standard` дает возможность провести исследование как и на что реагирует DPI в плане методов обхода.\
|
* `standard` дает возможность провести исследование как и на что реагирует DPI в плане методов обхода.
|
||||||
`force` дает максимум проверок даже в случаях, когда ресурс работает без обхода или с более простыми стратегиями.
|
* `force` дает максимум проверок даже в случаях, когда ресурс работает без обхода или с более простыми стратегиями.
|
||||||
|
|
||||||
Есть ряд других параметров, которые не будут спрашиваться в диалоге, но которые можно переопределить через
|
Есть ряд других параметров, которые не будут спрашиваться в диалоге, но которые можно переопределить через
|
||||||
переменные.
|
переменные.
|
||||||
@ -1333,9 +1338,11 @@ PKTWS_EXTRA_1 .. PKTWS_EXTRA_9, TPWS_EXTRA_1 .. TPWS_EXTRA_9 - отдельно
|
|||||||
SECURE_DNS=0|1 - принудительно выключить или включить DoH
|
SECURE_DNS=0|1 - принудительно выключить или включить DoH
|
||||||
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
|
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
|
||||||
DOH_SERVER - конкретный DoH URL, отказ от поиска
|
DOH_SERVER - конкретный DoH URL, отказ от поиска
|
||||||
|
CURL - замена программы curl
|
||||||
```
|
```
|
||||||
|
|
||||||
Пример запуска с переменными: `SECURE_DNS=1 SKIP_TPWS=1 CURL_MAX_TIME=1 ./blockcheck.sh`
|
Пример запуска с переменными:\
|
||||||
|
`SECURE_DNS=1 SKIP_TPWS=1 CURL_MAX_TIME=1 CURL=/tmp/curl ./blockcheck.sh`
|
||||||
|
|
||||||
**СКАН ПОРТОВ**\
|
**СКАН ПОРТОВ**\
|
||||||
Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в openwrt по умолчанию нет),
|
Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в openwrt по умолчанию нет),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=gnu99 -O3
|
CFLAGS += -std=gnu99 -Os
|
||||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||||
CFLAGS_WIN = -static
|
CFLAGS_WIN = -static
|
||||||
LIBS =
|
LIBS =
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=gnu99 -O3
|
CFLAGS += -std=gnu99 -Os
|
||||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||||
CFLAGS_WIN = -static
|
CFLAGS_WIN = -static
|
||||||
LIBS = -lpthread
|
LIBS = -lpthread
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -21,7 +20,9 @@
|
|||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2ipdef.h>
|
#include <ws2ipdef.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#else
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@ -364,6 +365,9 @@ int dns_make_query(const char *dom, char family)
|
|||||||
fprintf(stderr, "could not make DNS query\n");
|
fprintf(stderr, "could not make DNS query\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#ifdef _WIN32
|
||||||
|
_setmode(_fileno(stdout), _O_BINARY);
|
||||||
|
#endif
|
||||||
if (fwrite(q,l,1,stdout)!=1)
|
if (fwrite(q,l,1,stdout)!=1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "could not write DNS query blob to stdout\n");
|
fprintf(stderr, "could not write DNS query blob to stdout\n");
|
||||||
@ -422,6 +426,9 @@ int dns_parse_query()
|
|||||||
{
|
{
|
||||||
uint8_t a[1500];
|
uint8_t a[1500];
|
||||||
size_t l;
|
size_t l;
|
||||||
|
#ifdef _WIN32
|
||||||
|
_setmode(_fileno(stdin), _O_BINARY);
|
||||||
|
#endif
|
||||||
l = fread(a,1,sizeof(a),stdin);
|
l = fread(a,1,sizeof(a),stdin);
|
||||||
if (!l || !feof(stdin))
|
if (!l || !feof(stdin))
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CC ?= cc
|
CC ?= cc
|
||||||
CFLAGS += -std=gnu99 -s -O3 -Wno-address-of-packed-member
|
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member
|
||||||
LIBS = -lz
|
LIBS = -lz
|
||||||
SRC_FILES = *.c crypto/*.c
|
SRC_FILES = *.c crypto/*.c
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=gnu99 -O3
|
CFLAGS += -std=gnu99 -Os
|
||||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||||
CFLAGS_MAC = -mmacosx-version-min=10.8
|
CFLAGS_MAC = -mmacosx-version-min=10.8
|
||||||
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
||||||
|
@ -1270,7 +1270,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
seg_len = dis->len_payload-split_pos;
|
seg_len = dis->len_payload-split_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(net32_add(dis->tcp->th_seq,split_pos),-dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||||
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||||
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||||
seg, seg_len, pkt1, &pkt1_len))
|
seg, seg_len, pkt1, &pkt1_len))
|
||||||
|
@ -927,7 +927,7 @@ static void exithelp(void)
|
|||||||
" --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n"
|
" --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n"
|
||||||
" --dpi-desync-split-pos=<1..%u>\t\t; data payload split position\n"
|
" --dpi-desync-split-pos=<1..%u>\t\t; data payload split position\n"
|
||||||
" --dpi-desync-split-http-req=method|host\t; split at specified logical part of plain http request\n"
|
" --dpi-desync-split-http-req=method|host\t; split at specified logical part of plain http request\n"
|
||||||
" --dpi-desync-split-tls=sni|sniext\t\t; split at specified logical part of TLS ClientHello\n"
|
" --dpi-desync-split-tls=sni|sniext|snisld\t; split at specified logical part of TLS ClientHello\n"
|
||||||
" --dpi-desync-split-seqovl=<int>\t\t; use sequence overlap before first sent original split segment\n"
|
" --dpi-desync-split-seqovl=<int>\t\t; use sequence overlap before first sent original split segment\n"
|
||||||
" --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n"
|
" --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n"
|
||||||
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||||
@ -983,6 +983,8 @@ bool parse_tlspos(const char *s, enum tlspos *pos)
|
|||||||
*pos = tlspos_sni;
|
*pos = tlspos_sni;
|
||||||
else if (!strcmp(s, "sniext"))
|
else if (!strcmp(s, "sniext"))
|
||||||
*pos = tlspos_sniext;
|
*pos = tlspos_sniext;
|
||||||
|
else if (!strcmp(s, "snisld"))
|
||||||
|
*pos = tlspos_snisld;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -7,6 +7,23 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
// find N level domain
|
||||||
|
static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **p, size_t *len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const uint8_t *p1,*p2;
|
||||||
|
for (i=1,p2=dom+dlen;i<level;i++)
|
||||||
|
{
|
||||||
|
for (p2--; p2>dom && *p2!='.'; p2--);
|
||||||
|
if (p2<=dom) return false;
|
||||||
|
}
|
||||||
|
for (p1=p2-1 ; p1>dom && *p1!='.'; p1--);
|
||||||
|
if (*p1=='.') p1++;
|
||||||
|
if (p) *p = p1;
|
||||||
|
if (len) *len = p2-p1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
const char *HttpMethod(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
@ -116,17 +133,6 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
|
|||||||
{
|
{
|
||||||
return HttpExtractHeader(data, len, "\nHost:", host, len_host);
|
return HttpExtractHeader(data, len, "\nHost:", host, len_host);
|
||||||
}
|
}
|
||||||
const char *HttpFind2ndLevelDomain(const char *host)
|
|
||||||
{
|
|
||||||
const char *p=NULL;
|
|
||||||
if (*host)
|
|
||||||
{
|
|
||||||
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
|
|
||||||
if (*p=='.') for (p--; p>host && *p!='.'; p--);
|
|
||||||
if (*p=='.') p++;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
// DPI redirects are global redirects to another domain
|
// DPI redirects are global redirects to another domain
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
|
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
|
||||||
{
|
{
|
||||||
@ -157,10 +163,11 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
// somethinkg like : censor.net
|
// somethinkg like : censor.net
|
||||||
|
|
||||||
// extract 2nd level domains
|
// extract 2nd level domains
|
||||||
|
const char *dhost, *drhost;
|
||||||
|
if (!FindNLD((uint8_t*)host,strlen(host),2,(const uint8_t**)&dhost,NULL) || !FindNLD((uint8_t*)redirect_host,strlen(redirect_host),2,(const uint8_t**)&drhost,NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
const char *dhost = HttpFind2ndLevelDomain(host);
|
// compare 2nd level domains
|
||||||
const char *drhost = HttpFind2ndLevelDomain(redirect_host);
|
|
||||||
|
|
||||||
return strcasecmp(dhost, drhost)!=0;
|
return strcasecmp(dhost, drhost)!=0;
|
||||||
}
|
}
|
||||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
||||||
@ -305,15 +312,24 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
||||||
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
||||||
}
|
}
|
||||||
|
static bool TLSAdvanceToHostInSNI(const uint8_t **ext, size_t *elen, size_t *slen)
|
||||||
|
{
|
||||||
|
// u16 data+0 - name list length
|
||||||
|
// u8 data+2 - server name type. 0=host_name
|
||||||
|
// u16 data+3 - server name length
|
||||||
|
if (*elen < 5 || (*ext)[2] != 0) return false;
|
||||||
|
*slen = pntoh16(*ext + 3);
|
||||||
|
*ext += 5; *elen -= 5;
|
||||||
|
return *slen <= *elen;
|
||||||
|
}
|
||||||
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
||||||
{
|
{
|
||||||
// u16 data+0 - name list length
|
// u16 data+0 - name list length
|
||||||
// u8 data+2 - server name type. 0=host_name
|
// u8 data+2 - server name type. 0=host_name
|
||||||
// u16 data+3 - server name length
|
// u16 data+3 - server name length
|
||||||
if (elen < 5 || ext[2] != 0) return false;
|
size_t slen;
|
||||||
size_t slen = pntoh16(ext + 3);
|
if (!TLSAdvanceToHostInSNI(&ext,&elen,&slen))
|
||||||
ext += 5; elen -= 5;
|
return false;
|
||||||
if (slen < elen) return false;
|
|
||||||
if (host && len_host)
|
if (host && len_host)
|
||||||
{
|
{
|
||||||
if (slen >= len_host) slen = len_host - 1;
|
if (slen >= len_host) slen = len_host - 1;
|
||||||
@ -338,22 +354,46 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
|||||||
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find N level domain in SNI
|
||||||
|
static bool TLSHelloFindNLDInSNI(const uint8_t *ext, size_t elen, int level, const uint8_t **p, size_t *len)
|
||||||
|
{
|
||||||
|
size_t slen;
|
||||||
|
return TLSAdvanceToHostInSNI(&ext,&elen,&slen) && FindNLD(ext,slen,level,p,len);
|
||||||
|
}
|
||||||
|
// find the middle of second level domain (SLD) in SNI ext : www.sobaka.ru => aka.ru
|
||||||
|
// return false if SNI ext is bad or SLD is not found
|
||||||
|
static bool TLSHelloFindMiddleOfSLDInSNI(const uint8_t *ext, size_t elen, const uint8_t **p)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
if (!TLSHelloFindNLDInSNI(ext,elen,2,p,&len))
|
||||||
|
return false;
|
||||||
|
// in case of one letter SLD (x.com) we split at '.' to prevent appearance of the whole SLD
|
||||||
|
*p = (len==1) ? *p+1 : *p+len/2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
||||||
{
|
{
|
||||||
size_t elen;
|
size_t elen;
|
||||||
const uint8_t *ext;
|
const uint8_t *ext, *p;
|
||||||
switch(tpos_type)
|
switch(tpos_type)
|
||||||
{
|
{
|
||||||
case tlspos_sni:
|
case tlspos_sni:
|
||||||
case tlspos_sniext:
|
case tlspos_sniext:
|
||||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||||
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
||||||
// fall through
|
break;
|
||||||
|
case tlspos_snisld:
|
||||||
|
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||||
|
if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p))
|
||||||
|
return p-tls;
|
||||||
|
break;
|
||||||
case tlspos_pos:
|
case tlspos_pos:
|
||||||
return tpos_pos<sz ? tpos_pos : 0;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
return tpos_pos<sz ? tpos_pos : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos };
|
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_snisld, tlspos_pos };
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
||||||
|
|
||||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CC ?= cc
|
CC ?= cc
|
||||||
CFLAGS += -std=gnu99 -s -O3
|
CFLAGS += -std=gnu99 -s -Os
|
||||||
LIBS = -lz -lpthread
|
LIBS = -lz -lpthread
|
||||||
SRC_FILES = *.c
|
SRC_FILES = *.c
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -std=gnu99 -O3
|
CFLAGS += -std=gnu99 -Os
|
||||||
CFLAGS_BSD = -Wno-address-of-packed-member
|
CFLAGS_BSD = -Wno-address-of-packed-member
|
||||||
LIBS = -lz -lpthread
|
LIBS = -lz -lpthread
|
||||||
SRC_FILES = *.c
|
SRC_FILES = *.c
|
||||||
|
@ -7,6 +7,22 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
// find N level domain
|
||||||
|
static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **p, size_t *len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const uint8_t *p1,*p2;
|
||||||
|
for (i=1,p2=dom+dlen;i<level;i++)
|
||||||
|
{
|
||||||
|
for (p2--; p2>dom && *p2!='.'; p2--);
|
||||||
|
if (p2<=dom) return false;
|
||||||
|
}
|
||||||
|
for (p1=p2-1 ; p1>dom && *p1!='.'; p1--);
|
||||||
|
if (*p1=='.') p1++;
|
||||||
|
if (p) *p = p1;
|
||||||
|
if (len) *len = p2-p1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
const char *HttpMethod(const uint8_t *data, size_t len)
|
||||||
@ -116,17 +132,6 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
|
|||||||
{
|
{
|
||||||
return HttpExtractHeader(data, len, "\nHost:", host, len_host);
|
return HttpExtractHeader(data, len, "\nHost:", host, len_host);
|
||||||
}
|
}
|
||||||
const char *HttpFind2ndLevelDomain(const char *host)
|
|
||||||
{
|
|
||||||
const char *p=NULL;
|
|
||||||
if (*host)
|
|
||||||
{
|
|
||||||
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
|
|
||||||
if (*p=='.') for (p--; p>host && *p!='.'; p--);
|
|
||||||
if (*p=='.') p++;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
// DPI redirects are global redirects to another domain
|
// DPI redirects are global redirects to another domain
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
|
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
|
||||||
{
|
{
|
||||||
@ -157,10 +162,11 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
// somethinkg like : censor.net
|
// somethinkg like : censor.net
|
||||||
|
|
||||||
// extract 2nd level domains
|
// extract 2nd level domains
|
||||||
|
const char *dhost, *drhost;
|
||||||
|
if (!FindNLD((uint8_t*)host,strlen(host),2,(const uint8_t**)&dhost,NULL) || !FindNLD((uint8_t*)redirect_host,strlen(redirect_host),2,(const uint8_t**)&drhost,NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
const char *dhost = HttpFind2ndLevelDomain(host);
|
// compare 2nd level domains
|
||||||
const char *drhost = HttpFind2ndLevelDomain(redirect_host);
|
|
||||||
|
|
||||||
return strcasecmp(dhost, drhost)!=0;
|
return strcasecmp(dhost, drhost)!=0;
|
||||||
}
|
}
|
||||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
||||||
@ -295,15 +301,24 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
||||||
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
||||||
}
|
}
|
||||||
|
static bool TLSAdvanceToHostInSNI(const uint8_t **ext, size_t *elen, size_t *slen)
|
||||||
|
{
|
||||||
|
// u16 data+0 - name list length
|
||||||
|
// u8 data+2 - server name type. 0=host_name
|
||||||
|
// u16 data+3 - server name length
|
||||||
|
if (*elen < 5 || (*ext)[2] != 0) return false;
|
||||||
|
*slen = pntoh16(*ext + 3);
|
||||||
|
*ext += 5; *elen -= 5;
|
||||||
|
return *slen <= *elen;
|
||||||
|
}
|
||||||
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
||||||
{
|
{
|
||||||
// u16 data+0 - name list length
|
// u16 data+0 - name list length
|
||||||
// u8 data+2 - server name type. 0=host_name
|
// u8 data+2 - server name type. 0=host_name
|
||||||
// u16 data+3 - server name length
|
// u16 data+3 - server name length
|
||||||
if (elen < 5 || ext[2] != 0) return false;
|
size_t slen;
|
||||||
size_t slen = pntoh16(ext + 3);
|
if (!TLSAdvanceToHostInSNI(&ext,&elen,&slen))
|
||||||
ext += 5; elen -= 5;
|
return false;
|
||||||
if (slen < elen) return false;
|
|
||||||
if (host && len_host)
|
if (host && len_host)
|
||||||
{
|
{
|
||||||
if (slen >= len_host) slen = len_host - 1;
|
if (slen >= len_host) slen = len_host - 1;
|
||||||
@ -328,20 +343,44 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
|||||||
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find N level domain in SNI
|
||||||
|
static bool TLSHelloFindNLDInSNI(const uint8_t *ext, size_t elen, int level, const uint8_t **p, size_t *len)
|
||||||
|
{
|
||||||
|
size_t slen;
|
||||||
|
return TLSAdvanceToHostInSNI(&ext,&elen,&slen) && FindNLD(ext,slen,level,p,len);
|
||||||
|
}
|
||||||
|
// find the middle of second level domain (SLD) in SNI ext : www.sobaka.ru => aka.ru
|
||||||
|
// return false if SNI ext is bad or SLD is not found
|
||||||
|
static bool TLSHelloFindMiddleOfSLDInSNI(const uint8_t *ext, size_t elen, const uint8_t **p)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
if (!TLSHelloFindNLDInSNI(ext,elen,2,p,&len))
|
||||||
|
return false;
|
||||||
|
// in case of one letter SLD (x.com) we split at '.' to prevent appearance of the whole SLD
|
||||||
|
*p = (len==1) ? *p+1 : *p+len/2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
||||||
{
|
{
|
||||||
size_t elen;
|
size_t elen;
|
||||||
const uint8_t *ext;
|
const uint8_t *ext, *p;
|
||||||
switch(tpos_type)
|
switch(tpos_type)
|
||||||
{
|
{
|
||||||
case tlspos_sni:
|
case tlspos_sni:
|
||||||
case tlspos_sniext:
|
case tlspos_sniext:
|
||||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||||
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
||||||
// fall through
|
break;
|
||||||
|
case tlspos_snisld:
|
||||||
|
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||||
|
if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p))
|
||||||
|
return p-tls;
|
||||||
|
break;
|
||||||
case tlspos_pos:
|
case tlspos_pos:
|
||||||
return tpos_pos<sz ? tpos_pos : 0;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
return tpos_pos<sz ? tpos_pos : 0;
|
||||||
}
|
}
|
||||||
|
@ -29,5 +29,5 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
|||||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||||
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos };
|
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_snisld, tlspos_pos };
|
||||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
||||||
|
@ -183,7 +183,7 @@ static void exithelp(void)
|
|||||||
" --hostlist-auto-debug=<logfile>\t; debug auto hostlist positives\n"
|
" --hostlist-auto-debug=<logfile>\t; debug auto hostlist positives\n"
|
||||||
"\nTAMPER:\n"
|
"\nTAMPER:\n"
|
||||||
" --split-http-req=method|host\t\t; split at specified logical part of plain http request\n"
|
" --split-http-req=method|host\t\t; split at specified logical part of plain http request\n"
|
||||||
" --split-tls=sni|sniext\t\t\t; split at specified logical part of TLS ClientHello\n"
|
" --split-tls=sni|sniext|snisld\t\t; split at specified logical part of TLS ClientHello\n"
|
||||||
" --split-pos=<numeric_offset>\t\t; split at specified pos. split-http-req or split-tls take precedence for http.\n"
|
" --split-pos=<numeric_offset>\t\t; split at specified pos. split-http-req or split-tls take precedence for http.\n"
|
||||||
" --split-any-protocol\t\t\t; split not only http and https\n"
|
" --split-any-protocol\t\t\t; split not only http and https\n"
|
||||||
#if defined(BSD) && !defined(__APPLE__)
|
#if defined(BSD) && !defined(__APPLE__)
|
||||||
@ -203,7 +203,7 @@ static void exithelp(void)
|
|||||||
" --methodspace\t\t\t\t; add extra space after method\n"
|
" --methodspace\t\t\t\t; add extra space after method\n"
|
||||||
" --methodeol\t\t\t\t; add end-of-line before method\n"
|
" --methodeol\t\t\t\t; add end-of-line before method\n"
|
||||||
" --unixeol\t\t\t\t; replace 0D0A to 0A\n"
|
" --unixeol\t\t\t\t; replace 0D0A to 0A\n"
|
||||||
" --tlsrec=sni|sniext\t\t\t; make 2 TLS records. split at specified logical part. don't split if SNI is not present\n"
|
" --tlsrec=sni|sniext|snisld\t\t; make 2 TLS records. split at specified logical part. don't split if SNI is not present\n"
|
||||||
" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
|
" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
|
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
|
||||||
@ -292,6 +292,8 @@ bool parse_tlspos(const char *s, enum tlspos *pos)
|
|||||||
*pos = tlspos_sni;
|
*pos = tlspos_sni;
|
||||||
else if (!strcmp(s, "sniext"))
|
else if (!strcmp(s, "sniext"))
|
||||||
*pos = tlspos_sniext;
|
*pos = tlspos_sniext;
|
||||||
|
else if (!strcmp(s, "snisld"))
|
||||||
|
*pos = tlspos_snisld;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user