From f0e68527ba794d161fbaa08f87faa01419ffa0e2 Mon Sep 17 00:00:00 2001 From: bol-van Date: Sat, 9 Nov 2024 15:53:28 +0300 Subject: [PATCH] nfqws,tpws: snisld split --- nfq/desync.c | 2 +- nfq/nfqws.c | 4 ++- nfq/protocol.c | 82 ++++++++++++++++++++++++++++++++++++------------- nfq/protocol.h | 2 +- tpws/protocol.c | 81 +++++++++++++++++++++++++++++++++++------------- tpws/protocol.h | 2 +- tpws/tpws.c | 6 ++-- 7 files changed, 131 insertions(+), 48 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index 7251e49..cf942e1 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -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; } - 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), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, seg, seg_len, pkt1, &pkt1_len)) diff --git a/nfq/nfqws.c b/nfq/nfqws.c index a27ffcf..e07054f 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -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-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-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=\t\t; use sequence overlap before first sent original split segment\n" " --dpi-desync-split-seqovl-pattern=|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" @@ -983,6 +983,8 @@ bool parse_tlspos(const char *s, enum tlspos *pos) *pos = tlspos_sni; else if (!strcmp(s, "sniext")) *pos = tlspos_sniext; + else if (!strcmp(s, "snisld")) + *pos = tlspos_snisld; else return false; return true; diff --git a/nfq/protocol.c b/nfq/protocol.c index b83607e..bec8362 100644 --- a/nfq/protocol.c +++ b/nfq/protocol.c @@ -7,6 +7,23 @@ #include #include +// 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;idom && *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 *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); } -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 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 // 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); - const char *drhost = HttpFind2ndLevelDomain(redirect_host); - + // compare 2nd level domains return strcasecmp(dhost, drhost)!=0; } 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_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; 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 elen; - const uint8_t *ext; + const uint8_t *ext, *p; switch(tpos_type) { case tlspos_sni: case tlspos_sniext: if (TLSFindExt(tls,sz,0,&ext,&elen,false)) 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: - return tpos_pos #include +// 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;idom && *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 *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); } -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 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 // 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); - const char *drhost = HttpFind2ndLevelDomain(redirect_host); - + // compare 2nd level domains return strcasecmp(dhost, drhost)!=0; } 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_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; 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 elen; - const uint8_t *ext; + const uint8_t *ext, *p; switch(tpos_type) { case tlspos_sni: case tlspos_sniext: if (TLSFindExt(tls,sz,0,&ext,&elen,false)) 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: - return tpos_pos\t; debug auto hostlist positives\n" "\nTAMPER:\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=\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" #if defined(BSD) && !defined(__APPLE__) @@ -203,7 +203,7 @@ static void exithelp(void) " --methodspace\t\t\t\t; add extra space after method\n" " --methodeol\t\t\t\t; add end-of-line before method\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=\t\t\t; make 2 TLS records. split at specified pos\n" #ifdef __linux__ " --mss=\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; else if (!strcmp(s, "sniext")) *pos = tlspos_sniext; + else if (!strcmp(s, "snisld")) + *pos = tlspos_snisld; else return false; return true;