Commit dfe36aee authored by bol-van's avatar bol-van
Browse files

nfqws: special case for ip looking hostnames

parent 2d704a85
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ void ConntrackClearHostname(t_ctrack *track)
{
	free(track->hostname);
	track->hostname = NULL;
	track->hostname_is_ip = false;
}
static void ConntrackClearTrack(t_ctrack *track)
{
+1 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ typedef struct
	t_l7proto l7proto;
	bool l7proto_discovered;
	char *hostname;
	bool hostname_is_ip;
	bool hostname_discovered;
	bool hostname_ah_check;			// should perform autohostlist checks
	
+41 −27
Original line number Diff line number Diff line
@@ -223,7 +223,7 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)

static bool dp_match(
	struct desync_profile *dp,
	uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, const char *ssid,
	uint8_t l3proto, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid,
	bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{
	bool bHostlistsEmpty;
@@ -267,7 +267,7 @@ static bool dp_match(
		{
			if (bCheckDone) *bCheckDone = true;
			bool b;
			b = HostlistCheck(dp, hostname, bExcluded, true);
			b = HostlistCheck(dp, hostname, bNoSubdom, bExcluded, true);
			if (bCheckResult) *bCheckResult = b;
			return b;
		}
@@ -276,7 +276,7 @@ static bool dp_match(
}
static struct desync_profile *dp_find(
	struct desync_profile_list_head *head,
	uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, const char *ssid,
	uint8_t l3proto, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid,
	bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{
	struct desync_profile_list *dpl;
@@ -289,7 +289,7 @@ static struct desync_profile *dp_find(
	if (bCheckDone) *bCheckDone = false;
	LIST_FOREACH(dpl, head, next)
	{
		if (dp_match(&dpl->dp,l3proto,dest,hostname,l7proto,ssid,bCheckDone,bCheckResult,bExcluded))
		if (dp_match(&dpl->dp,l3proto,dest,hostname,bNoSubdom,l7proto,ssid,bCheckDone,bCheckResult,bExcluded))
		{
			DLOG("desync profile %d matches\n",dpl->dp.n);
			return &dpl->dp;
@@ -418,7 +418,7 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
	}
	return false;
}
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, bool bNoSubdom, const char *client_ip_port, t_l7proto l7proto)
{
	hostfail_pool *fail_counter;
	
@@ -442,7 +442,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
		
		DLOG("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname);
		bool bExcluded=false;
		if (!HostlistCheck(dp, hostname, &bExcluded, false) && !bExcluded)
		if (!HostlistCheck(dp, hostname, bNoSubdom, &bExcluded, false) && !bExcluded)
		{
			DLOG("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
			HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
@@ -477,7 +477,7 @@ static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct s
	if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto))
	{
		HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
		auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
		auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
	}
}

@@ -783,7 +783,7 @@ static void autottl_rediscover(t_ctrack *ctrack, const struct in_addr *a4, const
	}
}

static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname)
static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip)
{
	if (!params.cache_hostname) return true;

@@ -801,11 +801,12 @@ static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr
			DLOG_ERR("ipcache_put_hostname: out of memory\n");
			return false;
		}
		DLOG("hostname cached: %s\n", hostname);
		ipc->hostname_is_ip = hostname_is_ip;
		DLOG("hostname cached (is_ip=%u): %s\n", hostname_is_ip, hostname);
	}
	return true;
}
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len)
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len, bool *hostname_is_ip)
{
	if (!params.cache_hostname)
	{
@@ -820,8 +821,9 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
	}
	if (ipc->hostname)
	{
		DLOG("got cached hostname: %s\n", ipc->hostname);
		DLOG("got cached hostname (is_ip=%u): %s\n", ipc->hostname_is_ip, ipc->hostname);
		snprintf(hostname,hostname_buf_len,"%s",ipc->hostname);
		if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip;
	}
	else
		*hostname = 0;
@@ -1140,11 +1142,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		{
			if (!ctrack_replay->hostname && !bReverse)
			{
				if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host)
				if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &ctrack_replay->hostname_is_ip) && *host)
					if (!(ctrack_replay->hostname = strdup(host)))
						DLOG_ERR("strdup(host): out of memory\n");
			}
			dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, ssid, NULL, NULL, NULL);
			dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, ctrack_replay->l7proto, ssid, NULL, NULL, NULL);
			ctrack_replay->dp_search_complete = true;
		}
		if (!dp)
@@ -1176,17 +1178,19 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		else if (!ctrack || !ctrack->dp_search_complete)
		{
			const char *hostname = NULL;
			bool hostname_is_ip = false;
			if (ctrack)
			{
				hostname = ctrack->hostname;
				hostname_is_ip = ctrack->hostname_is_ip;
				if (!hostname && !bReverse)
				{
					if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host)
					if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &hostname_is_ip) && *host)
						if (!(hostname = ctrack_replay->hostname = strdup(host)))
							DLOG_ERR("strdup(host): out of memory\n");
				}
			}
			dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
			dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, hostname_is_ip, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
			if (ctrack)
			{
				ctrack->dp = dp;
@@ -1268,7 +1272,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
					}
				}
				if (bFail)
					auto_hostlist_failed(dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
					auto_hostlist_failed(dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
				else
					if (dis->len_payload)
						auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
@@ -1426,7 +1430,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		int multisplit_count;
		int i;
		uint16_t ip_id;
		bool bHaveHost=false;
		bool bHaveHost=false, bHostIsIp=false;
		t_l7proto l7proto = UNKNOWN;

		if (replay)
@@ -1458,6 +1462,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
				DLOG("not applying tampering to HTTP without Host:\n");
				goto send_orig;
			}
			bHostIsIp=strip_host_to_ip(host);
			if (ctrack)
			{
				// we do not reassemble http
@@ -1479,6 +1484,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
			if (bReqFull) TLSDebug(rdata_payload,rlen_payload);

			bHaveHost=TLSHelloExtractHost(rdata_payload,rlen_payload,host,sizeof(host),TLS_PARTIALS_ENABLE);
			if (bHaveHost) bHostIsIp=strip_host_to_ip(host);

			if (ctrack)
			{
@@ -1567,6 +1573,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
			{
				free(ctrack_replay->hostname);
				ctrack_replay->hostname=strdup(host);
				ctrack_replay->hostname_is_ip=bHostIsIp;
				if (!ctrack_replay->hostname)
				{
					DLOG_ERR("hostname dup : out of memory");
@@ -1574,7 +1581,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
					goto send_orig;
				}
				ctrack_replay->hostname_discovered=true;
				if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host))
				if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, bHostIsIp))
				{
					reasm_orig_cancel(ctrack);
					goto send_orig;
@@ -1590,6 +1597,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint

			dp = dp_find(&params.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst,
				ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL,
				ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp,
				ctrack_replay ? ctrack_replay->l7proto : l7proto, ssid,
				&bCheckDone, &bCheckResult, &bCheckExcluded);
			if (ctrack_replay)
@@ -1638,7 +1646,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
		{
			if (!bCheckDone)
				bCheckResult = HostlistCheck(dp, host, &bCheckExcluded, false);
				bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
			if (bCheckResult)
				ctrack_stop_retrans_counter(ctrack_replay);
			else
@@ -2409,11 +2417,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
		{
			if (!ctrack_replay->hostname && !bReverse)
			{
				if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host)
				if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &ctrack_replay->hostname_is_ip) && *host)
					if (!(ctrack_replay->hostname = strdup(host)))
						DLOG_ERR("strdup(host): out of memory\n");
			}
			dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, ssid, NULL, NULL, NULL);
			dp = ctrack_replay->dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, ctrack_replay->l7proto, ssid, NULL, NULL, NULL);
			ctrack_replay->dp_search_complete = true;
		}
		if (!dp)
@@ -2445,17 +2453,19 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
		else if (!ctrack || !ctrack->dp_search_complete)
		{
			const char *hostname = NULL;
			bool hostname_is_ip = false;
			if (ctrack)
			{
				hostname = ctrack->hostname;
				hostname_is_ip = ctrack->hostname_is_ip;
				if (!hostname && !bReverse)
				{
					if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host)) && *host)
					if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, sizeof(host), &hostname_is_ip) && *host)
						if (!(hostname = ctrack_replay->hostname = strdup(host)))
							DLOG_ERR("strdup(host): out of memory\n");
				}
			}
			dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
			dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, hostname_is_ip, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL);
			if (ctrack)
			{
				ctrack->dp = dp;
@@ -2503,7 +2513,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
	if (dis->len_payload)
	{
		struct blob_collection_head *fake;
		bool bHaveHost=false;
		bool bHaveHost=false, bHostIsIp=false;
		uint16_t ip_id;

		if (IsQUICInitial(dis->data_payload,dis->len_payload))
@@ -2594,7 +2604,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
						if (bIsHello)
						{
							bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
							if (!bHaveHost && dp->desync_skip_nosni)
							if (bHaveHost)
								bHostIsIp=strip_host_to_ip(host);
							else if (dp->desync_skip_nosni)
							{
								reasm_orig_cancel(ctrack);
								DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
@@ -2711,12 +2723,13 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
				ctrack_replay->hostname_discovered=true;
				free(ctrack_replay->hostname);
				ctrack_replay->hostname=strdup(host);
				ctrack_replay->hostname_is_ip = bHostIsIp;
				if (!ctrack_replay->hostname)
				{
					DLOG_ERR("hostname dup : out of memory");
					goto send_orig;
				}
				if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host))
				if (!ipcache_put_hostname(dis->ip ? &dis->ip->ip_dst : NULL,dis->ip6 ? &dis->ip6->ip6_dst : NULL , host, bHostIsIp))
					goto send_orig;
			}
		}
@@ -2728,6 +2741,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint

			dp = dp_find(&params.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst,
				ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL,
				ctrack_replay ? ctrack_replay->hostname_is_ip : bHostIsIp,
				ctrack_replay ? ctrack_replay->l7proto : l7proto, ssid,
				&bCheckDone, &bCheckResult, &bCheckExcluded);
			if (ctrack_replay)
@@ -2772,7 +2786,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
		if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
		{
			if (!bCheckDone)
				bCheckResult = HostlistCheck(dp, host, &bCheckExcluded, false);
				bCheckResult = HostlistCheck(dp, host, bHostIsIp, &bCheckExcluded, false);
			if (bCheckResult)
				ctrack_stop_retrans_counter(ctrack_replay);
			else
+53 −0
Original line number Diff line number Diff line
@@ -124,6 +124,59 @@ void expand_bits(void *target, const void *source, unsigned int source_bitlen, u
	if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8-bitlen)) - 1));
}

// "       [fd00::1]"
// "[fd00::1]:8000"
// "127.0.0.1"
// " 127.0.0.1:8000"
bool strip_host_to_ip(char *host)
{
	size_t l;
	char *h,*p;
	uint8_t addr[16];

	for (h = host ; *h==' ' || *h=='\t' ; h++);
	l = strlen(h);
	if (l>=2)
	{
		if (*h=='[')
		{
			// ipv6 ?
			for (p=++h ; *p && *p!=']' ;  p++);
			if (*p==']')
			{
				l = p-h;
				memmove(host,h,l);
				host[l]=0;
				return inet_pton(AF_INET6, host, addr)>0;
			}
		}
		else
		{
			if (inet_pton(AF_INET6, h, addr)>0)
			{
				// ipv6 ?
				if (host!=h)
				{
					l = strlen(h);
					memmove(host,h,l);
					host[l]=0;
				}
				return true;
			}
			else
			{
				// ipv4 ?
				for (p=h ; *p && *p!=':' ;  p++);
				l = p-h;
				if (host!=h) memmove(host,h,l);
				host[l]=0;
				return inet_pton(AF_INET, host, addr)>0;
			}
		}
	}
	return false;
}

void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
	if (!len) return;
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ bool append_to_list_file(const char *filename, const char *s);

void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen);

bool strip_host_to_ip(char *host);

void print_sockaddr(const struct sockaddr *sa);
void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
Loading