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; + if (len < (l + 1)) return false; + if (!bPartialIsOK) + { + ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length + if (len < (ll + 4)) return false; + } + l += data[l] + 1; // CipherSuitesLength - if (len<(l+2)) return false; - l += pntoh16(data+l)+2; + if (len < (l + 2)) return false; + l += pntoh16(data + l) + 2; // CompressionMethodsLength - if (len<(l+1)) return false; - l += data[l]+1; + if (len < (l + 1)) return false; + l += data[l] + 1; // ExtensionsLength - if (len<(l+2)) return false; + if (len < (l + 2)) return false; - data+=l; len-=l; - l=pntoh16(data); - data+=2; len-=2; - if (len=4) + while (l >= 4) { - uint16_t etype=pntoh16(data); - size_t elen=pntoh16(data+2); - data+=4; l-=4; - if (l=len_host) slen=len_host-1; - for(size_t i=0;i= 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, bPartialIsOK)) return false; + return TLSExtractHostFromExt(ext, elen, host, len_host); +} +bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK) +{ + const uint8_t *ext; + size_t elen; + + if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false; + return TLSExtractHostFromExt(ext, elen, host, len_host); +} diff --git a/tpws/protocol.h b/tpws/protocol.h index 94be21f..324e0ad 100644 --- a/tpws/protocol.h +++ b/tpws/protocol.h @@ -15,6 +15,11 @@ int HttpReplyCode(const uint8_t *data, size_t len); // must be pre-checked by IsHttpReply bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host); -bool IsTLSClientHello(const uint8_t *data, size_t len); -bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext); -bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host); +uint16_t TLSRecordDataLen(const uint8_t *data); +size_t TLSRecordLen(const uint8_t *data); +bool IsTLSRecordFull(const uint8_t *data, size_t len); +bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK); +bool TLSFindExt(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 TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK); diff --git a/tpws/strpool.c b/tpws/strpool.c new file mode 100644 index 0000000..183b17f --- /dev/null +++ b/tpws/strpool.c @@ -0,0 +1,107 @@ +#define _GNU_SOURCE +#include "strpool.h" +#include +#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: