diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index c449713..1dbeaae 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws index c8151ad..43923ed 100755 Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ diff --git a/binaries/arm/nfqws b/binaries/arm/nfqws index fe22aa6..438cdb3 100755 Binary files a/binaries/arm/nfqws and b/binaries/arm/nfqws differ diff --git a/binaries/arm/tpws b/binaries/arm/tpws index 0e1902d..c63a7f5 100755 Binary files a/binaries/arm/tpws and b/binaries/arm/tpws differ diff --git a/binaries/freebsd-x64/dvtws b/binaries/freebsd-x64/dvtws index 42e12fa..81b4275 100755 Binary files a/binaries/freebsd-x64/dvtws and b/binaries/freebsd-x64/dvtws differ diff --git a/binaries/freebsd-x64/tpws b/binaries/freebsd-x64/tpws index aa1a9f3..e43cc6e 100755 Binary files a/binaries/freebsd-x64/tpws and b/binaries/freebsd-x64/tpws differ diff --git a/binaries/mac64/tpws b/binaries/mac64/tpws index f034c79..f0ed304 100755 Binary files a/binaries/mac64/tpws and b/binaries/mac64/tpws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index 3d39484..cb254fd 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index 56cf476..86ee06a 100755 Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index 4051396..acb7bee 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index 58f4bfe..2b8bd36 100755 Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ diff --git a/binaries/mips64r2-msb/nfqws b/binaries/mips64r2-msb/nfqws index 5f18b6c..a23366f 100755 Binary files a/binaries/mips64r2-msb/nfqws and b/binaries/mips64r2-msb/nfqws differ diff --git a/binaries/mips64r2-msb/tpws b/binaries/mips64r2-msb/tpws index b15615f..6d39360 100755 Binary files a/binaries/mips64r2-msb/tpws and b/binaries/mips64r2-msb/tpws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index 738d630..da7cc14 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws index 8e92d86..35e534e 100755 Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 198a099..bbbcfb5 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index 186380d..1e5323b 100755 Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index 96b3165..c44b1e6 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws index 8074ce1..afca0fd 100755 Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ diff --git a/binaries/x86_64/tpws_wsl.tgz b/binaries/x86_64/tpws_wsl.tgz index 419741e..e5331e2 100644 Binary files a/binaries/x86_64/tpws_wsl.tgz and b/binaries/x86_64/tpws_wsl.tgz differ diff --git a/nfq/protocol.c b/nfq/protocol.c index 69eca78..819815d 100644 --- a/nfq/protocol.c +++ b/nfq/protocol.c @@ -200,7 +200,10 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t ** // u8 ContentType: Handshake // u16 Version: TLS1.0 // u16 Length + size_t reclen; if (!IsTLSClientHello(data, len, bPartialIsOK)) return false; + reclen=TLSRecordLen(data); + if (reclen +#include + +#undef uthash_nonfatal_oom +#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) + +static bool oom = false; +static void ut_oom_recover(strpool *elem) +{ + oom = true; +} + +// for zero terminated strings +bool StrPoolAddStr(strpool **pp, const char *s) +{ + strpool *elem; + if (!(elem = (strpool*)malloc(sizeof(strpool)))) + return false; + if (!(elem->str = strdup(s))) + { + free(elem); + return false; + } + oom = false; + HASH_ADD_KEYPTR(hh, *pp, elem->str, strlen(elem->str), elem); + if (oom) + { + free(elem->str); + free(elem); + return false; + } + 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) +{ + strpool *elem; + HASH_FIND_STR(p, s, elem); + return elem != NULL; +} + +void StrPoolDestroy(strpool **p) +{ + strpool *elem, *tmp; + HASH_ITER(hh, *p, elem, tmp) { + free(elem->str); + HASH_DEL(*p, elem); + free(elem); + } + *p = NULL; +} + + + + +bool strlist_add(struct str_list_head *head, const char *filename) +{ + struct str_list *entry = malloc(sizeof(struct str_list)); + if (!entry) return false; + entry->str = strdup(filename); + if (!entry->str) + { + free(entry); + return false; + } + LIST_INSERT_HEAD(head, entry, next); + return true; +} +static void strlist_entry_destroy(struct str_list *entry) +{ + if (entry->str) free(entry->str); + free(entry); +} +void strlist_destroy(struct str_list_head *head) +{ + struct str_list *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + strlist_entry_destroy(entry); + } +} diff --git a/nfq/strpool.h b/nfq/strpool.h new file mode 100644 index 0000000..36d484e --- /dev/null +++ b/nfq/strpool.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +//#define HASH_BLOOM 20 +#define HASH_NONFATAL_OOM 1 +#define HASH_FUNCTION HASH_BER +#include "uthash.h" + +typedef struct strpool { + char *str; /* key */ + UT_hash_handle hh; /* makes this structure hashable */ +} strpool; + +void StrPoolDestroy(strpool **p); +bool StrPoolAddStr(strpool **pp,const char *s); +bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen); +bool StrPoolCheckStr(strpool *p,const char *s); + +struct str_list { + char *str; + LIST_ENTRY(str_list) next; +}; +LIST_HEAD(str_list_head, str_list); + +bool strlist_add(struct str_list_head *head, const char *filename); +void strlist_destroy(struct str_list_head *head); diff --git a/tpws/protocol.c b/tpws/protocol.c index b5c80c5..4c5e996 100644 --- a/tpws/protocol.c +++ b/tpws/protocol.c @@ -110,17 +110,27 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char * -bool IsTLSClientHello(const uint8_t *data, size_t len) +uint16_t TLSRecordDataLen(const uint8_t *data) { - return len>=6 && data[0]==0x16 && data[1]==0x03 && data[2]>=0x01 && data[2]<=0x03 && data[5]==0x01 && (pntoh16(data+3)+5)<=len; + return pntoh16(data + 3); } -bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext) +size_t TLSRecordLen(const uint8_t *data) +{ + return TLSRecordDataLen(data) + 5; +} +bool IsTLSRecordFull(const uint8_t *data, size_t len) +{ + return TLSRecordLen(data)<=len; +} +bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK) +{ + return len >= 6 && data[0] == 0x16 && data[1] == 0x03 && data[2] >= 0x01 && data[2] <= 0x03 && data[5] == 0x01 && (bPartialIsOK || TLSRecordLen(data) <= len); +} + +// bPartialIsOK=true - accept partial packets not containing the whole TLS message +bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK) { // +0 - // u8 ContentType: Handshake - // u16 Version: TLS1.0 - // u16 Length - // +5 // u8 HandshakeType: ClientHello // u24 Length // u16 Version @@ -133,35 +143,46 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t ** // // u16 ExtensionsLength - size_t l,ll; + size_t l, ll; - l = 1+2+2+1+3+2+32; + l = 1 + 3 + 2 + 32; // SessionIDLength - if (len<(l+1)) return false; - ll = data[6]<<16 | data[7]<<8 | data[8]; // HandshakeProtocol length - if (len<(ll+9)) return false; - l += data[l]+1; - // CipherSuitesLength - if (len<(l+2)) return false; - l += pntoh16(data+l)+2; - // CompressionMethodsLength - if (len<(l+1)) return false; - l += data[l]+1; - // ExtensionsLength - if (len<(l+2)) return false; - - data+=l; len-=l; - l=pntoh16(data); - data+=2; len-=2; - if (len=4) + if (len < (l + 1)) return false; + if (!bPartialIsOK) { - uint16_t etype=pntoh16(data); - size_t elen=pntoh16(data+2); - data+=4; l-=4; - if (l= 4) + { + uint16_t etype = pntoh16(data); + size_t elen = pntoh16(data + 2); + data += 4; l -= 4; + if (l < elen) break; + if (etype == type) { if (ext && len_ext) { @@ -170,29 +191,53 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t ** } return true; } - data+=elen; l-=elen; + data += elen; l -= elen; } return false; } -bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host) +bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK) +{ + // +0 + // u8 ContentType: Handshake + // u16 Version: TLS1.0 + // u16 Length + size_t reclen; + if (!IsTLSClientHello(data, len, bPartialIsOK)) return false; + reclen=TLSRecordLen(data); + if (reclen= len_host) slen = len_host - 1; + for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]); + host[slen] = 0; + } + return true; +} +bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK) { const uint8_t *ext; size_t elen; - if (!TLSFindExt(data,len,0,&ext,&elen)) return false; - // 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; - size_t slen = pntoh16(ext+3); - ext+=5; elen-=5; - if (slen=len_host) slen=len_host-1; - for(size_t i=0;i +#include + +#undef uthash_nonfatal_oom +#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) + +static bool oom = false; +static void ut_oom_recover(strpool *elem) +{ + oom = true; +} + +// for zero terminated strings +bool StrPoolAddStr(strpool **pp, const char *s) +{ + strpool *elem; + if (!(elem = (strpool*)malloc(sizeof(strpool)))) + return false; + if (!(elem->str = strdup(s))) + { + free(elem); + return false; + } + oom = false; + HASH_ADD_KEYPTR(hh, *pp, elem->str, strlen(elem->str), elem); + if (oom) + { + free(elem->str); + free(elem); + return false; + } + 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) +{ + strpool *elem; + HASH_FIND_STR(p, s, elem); + return elem != NULL; +} + +void StrPoolDestroy(strpool **p) +{ + strpool *elem, *tmp; + HASH_ITER(hh, *p, elem, tmp) { + free(elem->str); + HASH_DEL(*p, elem); + free(elem); + } + *p = NULL; +} + + + + +bool strlist_add(struct str_list_head *head, const char *filename) +{ + struct str_list *entry = malloc(sizeof(struct str_list)); + if (!entry) return false; + entry->str = strdup(filename); + if (!entry->str) + { + free(entry); + return false; + } + LIST_INSERT_HEAD(head, entry, next); + return true; +} +static void strlist_entry_destroy(struct str_list *entry) +{ + if (entry->str) free(entry->str); + free(entry); +} +void strlist_destroy(struct str_list_head *head) +{ + struct str_list *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + strlist_entry_destroy(entry); + } +} diff --git a/tpws/strpool.h b/tpws/strpool.h new file mode 100644 index 0000000..36d484e --- /dev/null +++ b/tpws/strpool.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +//#define HASH_BLOOM 20 +#define HASH_NONFATAL_OOM 1 +#define HASH_FUNCTION HASH_BER +#include "uthash.h" + +typedef struct strpool { + char *str; /* key */ + UT_hash_handle hh; /* makes this structure hashable */ +} strpool; + +void StrPoolDestroy(strpool **p); +bool StrPoolAddStr(strpool **pp,const char *s); +bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen); +bool StrPoolCheckStr(strpool *p,const char *s); + +struct str_list { + char *str; + LIST_ENTRY(str_list) next; +}; +LIST_HEAD(str_list_head, str_list); + +bool strlist_add(struct str_list_head *head, const char *filename); +void strlist_destroy(struct str_list_head *head); diff --git a/tpws/tamper.c b/tpws/tamper.c index 782e218..6eb7541 100644 --- a/tpws/tamper.c +++ b/tpws/tamper.c @@ -215,7 +215,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si VPRINT("Not acting on this request") } } - else if (IsTLSClientHello(segment,*size)) + else if (IsTLSClientHello(segment,*size,false)) { size_t tpos=0,elen; const uint8_t *ext; @@ -224,7 +224,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si VPRINT("packet contains TLS ClientHello") // we need host only if hostlist is present - if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host))) + if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false)) { VPRINT("hostname: %s",Host) bHaveHost = true; @@ -239,7 +239,7 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si switch(params.tlsrec) { case tlsrec_sni: - if (TLSFindExt(segment,*size,0,&ext,&elen)) + if (TLSFindExt(segment,*size,0,&ext,&elen,false)) tpos = ext-segment+1; // between typical 1st and 2nd char of hostname break; case tlsrec_pos: