mirror of
https://github.com/ValdikSS/GoodbyeDPI.git
synced 2024-12-22 14:26:08 +00:00
Improved tls parsing
This commit is contained in:
parent
4a82fd442d
commit
12e5d77375
143
src/goodbyedpi.c
143
src/goodbyedpi.c
@ -19,6 +19,7 @@
|
||||
#include "ttltrack.h"
|
||||
#include "blackwhitelist.h"
|
||||
#include "fakepackets.h"
|
||||
#include "tls.h"
|
||||
|
||||
// My mingw installation does not load inet_pton definition for some reason
|
||||
WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr);
|
||||
@ -387,48 +388,136 @@ static int find_header_and_get_info(const char *pktdata, unsigned int pktlen,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int contains_tls_record_with_client_hello(const char* pktdata, unsigned int pktlen) {
|
||||
// check min header sizes
|
||||
if (pktlen < TLS_RECORD_HEADER_SIZE + TLS_MESSAGE_HEADER_SIZE) {
|
||||
debug("Packet too small for TLS record and message header\n");
|
||||
return FALSE;
|
||||
}
|
||||
// check content type handshake
|
||||
if (pktdata[0] != TLS_CONTENT_TYPE_HANDSHAKE) {
|
||||
debug("Packet does not contain TLS handshake\n");
|
||||
return FALSE;
|
||||
}
|
||||
// check if record header matches any TLS version
|
||||
if (
|
||||
// TLS 1.0 Version is also used for backwards compatibility
|
||||
memcmp(pktdata+1, TLS_1_0_VERSION, TLS_VERSION_LENGTH) == 1 &&
|
||||
memcmp(pktdata+1, TLS_1_1_VERSION, TLS_VERSION_LENGTH) == 1 &&
|
||||
memcmp(pktdata+1, TLS_1_2_AND_1_3_VERSION, TLS_VERSION_LENGTH) == 1) {
|
||||
debug("Packet does not contain TLS 1.0, 1.1, 1.2 or 1.3\n");
|
||||
return FALSE;
|
||||
}
|
||||
// check if handshake message contains client hello
|
||||
if (pktdata[5] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
|
||||
debug("Packet does not contain TLS client hello\n");
|
||||
return FALSE;
|
||||
}
|
||||
// looks good otherwise
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Very crude Server Name Indication (TLS ClientHello hostname) extractor.
|
||||
* Extracts the (first) hostname in the SNI of the given packet. Assumes that the packet is a TLS Client Hello.
|
||||
*/
|
||||
static int extract_sni(const char *pktdata, unsigned int pktlen,
|
||||
char **hostnameaddr, unsigned int *hostnamelen) {
|
||||
unsigned int ptr = 0;
|
||||
unsigned const char *d = (unsigned const char *)pktdata;
|
||||
unsigned const char *hnaddr = 0;
|
||||
int hnlen = 0;
|
||||
|
||||
while (ptr + 8 < pktlen) {
|
||||
/* Search for specific Extensions sequence */
|
||||
if (d[ptr] == '\0' && d[ptr+1] == '\0' && d[ptr+2] == '\0' &&
|
||||
d[ptr+4] == '\0' && d[ptr+6] == '\0' && d[ptr+7] == '\0' &&
|
||||
/* Check Extension length, Server Name list length
|
||||
* and Server Name length relations
|
||||
*/
|
||||
d[ptr+3] - d[ptr+5] == 2 && d[ptr+5] - d[ptr+8] == 3)
|
||||
{
|
||||
if (ptr + 8 + d[ptr+8] > pktlen) {
|
||||
unsigned const char *d = (unsigned const char *)pktdata;
|
||||
unsigned const char *host_name_address = 0;
|
||||
unsigned int host_name_length = 0;
|
||||
|
||||
// offset for first length_field to parse
|
||||
unsigned int p = TLS_RECORD_HEADER_SIZE + TLS_MESSAGE_HEADER_SIZE + TLS_VERSION_LENGTH + TLS_RANDOM_LENGTH;
|
||||
|
||||
if (p + TLS_SESSION_ID_LENGTH >= pktlen) {
|
||||
debug("Packet too small for header\n");
|
||||
return FALSE;
|
||||
}
|
||||
hnaddr = &d[ptr+9];
|
||||
hnlen = d[ptr+8];
|
||||
|
||||
// skip session id
|
||||
unsigned int session_id_length = d[p];
|
||||
p += (session_id_length + TLS_SESSION_ID_LENGTH);
|
||||
|
||||
if (p + TLS_CIPHER_SUITES_LENGTH >= pktlen) {
|
||||
debug("Packet too small for session id\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// skip cipher suites
|
||||
unsigned int cipher_suites_length = (unsigned int)(d[p] << 8) + d[p+1];
|
||||
p += (cipher_suites_length + TLS_CIPHER_SUITES_LENGTH);
|
||||
|
||||
if (p + TLS_COMPRESSION_METHODS_LENGTH >= pktlen) {
|
||||
debug("Packet too small for cipher suites\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// skip compression methods
|
||||
unsigned int compression_methods_length = d[p];
|
||||
p += (compression_methods_length + TLS_COMPRESSION_METHODS_LENGTH);
|
||||
|
||||
if (p + TLS_EXTENSIONS_LENGTH >= pktlen) {
|
||||
debug("Packet too small for compression methods\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
unsigned int extensions_length = (unsigned int)(d[p] << 8) + d[p+1];
|
||||
p += TLS_EXTENSIONS_LENGTH;
|
||||
|
||||
while (p + TLS_EXTENSION_TYPE_LENGTH + TLS_EXTENSION_LENGTH_LENGTH < min(pktlen, p + extensions_length)) {
|
||||
|
||||
if (memcmp(d+p, TLS_EXTENSION_TYPE_SERVER_NAME, TLS_EXTENSION_TYPE_LENGTH) == 0) {
|
||||
// finally extract sni
|
||||
p += TLS_EXTENSION_TYPE_LENGTH + TLS_EXTENSION_LENGTH_LENGTH;
|
||||
|
||||
if (p + TLS_SNI_HEADER_LENGTH >= pktlen) {
|
||||
debug("Packet too small for extension header\n");
|
||||
return FALSE;
|
||||
}
|
||||
unsigned int host_name_type = d[p+TLS_EXTENSION_TYPE_LENGTH];
|
||||
|
||||
if (host_name_type != TLS_SNI_HOST_NAME_TYPE) {
|
||||
debug("SNI type is not host name\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
host_name_length = (unsigned int)(d[p + TLS_EXTENSION_TYPE_LENGTH + 1] << 8) + d[p + TLS_EXTENSION_TYPE_LENGTH + 2];
|
||||
p += TLS_SNI_HEADER_LENGTH;
|
||||
|
||||
if (p + host_name_length >= pktlen) {
|
||||
debug("Packet too small for host name\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
host_name_address = &d[p];
|
||||
/* Limit hostname size up to 253 bytes */
|
||||
if (hnlen < 3 || hnlen > HOST_MAXLEN) {
|
||||
if (host_name_length < 3) {
|
||||
debug("Host name too short\n");
|
||||
return FALSE;
|
||||
} else if (host_name_length > HOST_MAXLEN) {
|
||||
debug("Host name too long\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* Validate that hostname has only ascii lowercase characters */
|
||||
for (int i=0; i<hnlen; i++) {
|
||||
|
||||
*hostnameaddr = (char*)host_name_address;
|
||||
*hostnamelen = host_name_length;
|
||||
|
||||
// TODO: is this necessary? if yes: why? domain names are case insensitive
|
||||
/* for (int i=0; i<hnlen; i++) {
|
||||
if (!( (hnaddr[i] >= '0' && hnaddr[i] <= '9') ||
|
||||
(hnaddr[i] >= 'a' && hnaddr[i] <= 'z') ||
|
||||
hnaddr[i] == '.' || hnaddr[i] == '-'))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
*hostnameaddr = (char*)hnaddr;
|
||||
*hostnamelen = (unsigned int)hnlen;
|
||||
} */
|
||||
return TRUE;
|
||||
} else {
|
||||
// skip extension
|
||||
unsigned int extension_length = (unsigned int)(d[p+TLS_EXTENSION_TYPE_LENGTH] << 8) + d[p+TLS_EXTENSION_TYPE_LENGTH+1];
|
||||
p += TLS_EXTENSION_TYPE_LENGTH + TLS_EXTENSION_LENGTH_LENGTH + extension_length;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@ -1128,8 +1217,10 @@ int main(int argc, char *argv[]) {
|
||||
* In case of Window Size fragmentation=2, we'll receive only 2 byte packet.
|
||||
* But if the packet is more than 2 bytes, check ClientHello byte.
|
||||
*/
|
||||
if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) ||
|
||||
(packet_dataLen >= 3 && memcmp(packet_data, "\x16\x03\x01", 3) == 0))
|
||||
if (
|
||||
// TODO: feedback on when this triggers and whether this is necessary, if we cannot check for sni do we want to circumvent?
|
||||
(packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) ||
|
||||
(packet_dataLen >= 3 && contains_tls_record_with_client_hello(packet_data, packet_dataLen)))
|
||||
{
|
||||
if (do_blacklist) {
|
||||
sni_ok = extract_sni(packet_data, packet_dataLen,
|
||||
|
23
src/tls.h
Normal file
23
src/tls.h
Normal file
@ -0,0 +1,23 @@
|
||||
#define TLS_CONTENT_TYPE_HANDSHAKE 22
|
||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 1
|
||||
#define TLS_SNI_HOST_NAME_TYPE 0
|
||||
|
||||
#define TLS_1_0_VERSION "\x03\x01"
|
||||
#define TLS_1_1_VERSION "\x03\x02"
|
||||
#define TLS_1_2_AND_1_3_VERSION "\x03\x03"
|
||||
#define TLS_EXTENSION_TYPE_SERVER_NAME "\x00\x00"
|
||||
|
||||
#define TLS_CONTENT_TYPE_LENGTH 1
|
||||
#define TLS_VERSION_LENGTH 2
|
||||
#define TLS_RECORD_LENGTH_LENGTH 2
|
||||
#define TLS_RANDOM_LENGTH 32
|
||||
#define TLS_SESSION_ID_LENGTH 1
|
||||
#define TLS_CIPHER_SUITES_LENGTH 2
|
||||
#define TLS_COMPRESSION_METHODS_LENGTH 1
|
||||
#define TLS_EXTENSIONS_LENGTH 2
|
||||
#define TLS_EXTENSION_TYPE_LENGTH 2
|
||||
#define TLS_EXTENSION_LENGTH_LENGTH 2
|
||||
#define TLS_SNI_HEADER_LENGTH 5
|
||||
|
||||
#define TLS_RECORD_HEADER_SIZE TLS_CONTENT_TYPE_LENGTH + TLS_VERSION_LENGTH + TLS_RECORD_LENGTH_LENGTH
|
||||
#define TLS_MESSAGE_HEADER_SIZE 4
|
Loading…
Reference in New Issue
Block a user