Commit 6387315c authored by bol-van's avatar bol-van
Browse files

nfqws: multiple fakes

parent 3d4b395b
Loading
Loading
Loading
Loading
+126 −78
Original line number Diff line number Diff line
@@ -606,47 +606,50 @@ static uint16_t IP4_IP_ID_FIX(const struct ip *ip)
// fake_mod buffer must at least sizeof(desync_profile->fake_tls)
// size does not change
// return : true - altered, false - not altered
static bool runtime_tls_mod(const struct desync_profile *dp, uint8_t *fake_mod, const uint8_t *payload, size_t payload_len)
static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache, uint8_t fake_tls_mod, const uint8_t *fake_data, size_t fake_data_size, const uint8_t *payload, size_t payload_len, uint8_t *fake_mod)
{
	bool b=false;
	if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
	if (IsTLSClientHello(fake_data,fake_data_size,false))
	{
		size_t sz_rec = pntoh16(dp->fake_tls+3) + payload_len;
		size_t sz_handshake = pntoh24(dp->fake_tls+6) + payload_len;
		size_t sz_ext = pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset) + payload_len;
		size_t sz_pad = pntoh16(dp->fake_tls+dp->fake_tls_padlen_offset) + payload_len;
		if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
		{
			size_t sz_rec = pntoh16(fake_data+3) + payload_len;
			size_t sz_handshake = pntoh24(fake_data+6) + payload_len;
			size_t sz_ext = pntoh16(fake_data+modcache->extlen_offset) + payload_len;
			size_t sz_pad = pntoh16(fake_data+modcache->padlen_offset) + payload_len;
			if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
			DLOG("cannot apply padencap tls mod. length overflow.\n");
				DLOG("fake[%d] cannot apply padencap tls mod. length overflow.\n", fake_n);
			else
			{
			memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
				memcpy(fake_mod,fake_data,fake_data_size);
				phton16(fake_mod+3,(uint16_t)sz_rec);
				phton24(fake_mod+6,(uint32_t)sz_handshake);
			phton16(fake_mod+dp->fake_tls_extlen_offset,(uint16_t)sz_ext);
			phton16(fake_mod+dp->fake_tls_padlen_offset,(uint16_t)sz_pad);
				phton16(fake_mod+modcache->extlen_offset,(uint16_t)sz_ext);
				phton16(fake_mod+modcache->padlen_offset,(uint16_t)sz_pad);
				b=true;
			}
		}
	if (dp->fake_tls_mod & FAKE_TLS_MOD_RND)
		if (fake_tls_mod & FAKE_TLS_MOD_RND)
		{
		if (!b)	memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
			if (!b)	memcpy(fake_mod,fake_data,fake_data_size);
			fill_random_bytes(fake_mod+11,32); // random
			fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
			b=true;
		}
	if (dp->fake_tls_mod & FAKE_TLS_MOD_DUP_SID)
		if (fake_tls_mod & FAKE_TLS_MOD_DUP_SID)
		{
		if (dp->fake_tls[43]!=payload[43])
			DLOG("cannot apply dupsid tls mod. fake and orig session id length mismatch.\n");
			if (fake_data[43]!=payload[43])
				DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch.\n",fake_n);
			else if (payload_len<(44+payload[43]))
			DLOG("cannot apply dupsid tls mod. data payload is not valid.\n");
				DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n",fake_n);
			else
			{
			if (!b)	memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
				if (!b)	memcpy(fake_mod,fake_data,fake_data_size);
				memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id
				b=true;
			}
		}
	}
	return b;
}

@@ -880,8 +883,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint

	if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload)
	{
		const uint8_t *fake;
		size_t fake_size;
		struct blob_collection_head *fake;

		char host[256];
		bool bHaveHost=false;
		uint8_t *p, *phost=NULL;
@@ -893,7 +896,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		int i;
		uint16_t ip_id;
		t_l7proto l7proto = UNKNOWN;
		uint8_t fake_mod[sizeof(dp->fake_tls)];

		if (replay)
		{
@@ -1183,16 +1185,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		switch(l7proto)
		{
			case HTTP:
				fake = dp->fake_http;
				fake_size = dp->fake_http_size;
				fake = &dp->fake_http;
				break;
			case TLS:
				fake = runtime_tls_mod(dp,fake_mod,rdata_payload,rlen_payload) ? fake_mod : dp->fake_tls;
				fake_size = dp->fake_tls_size;
				fake = &dp->fake_tls;
				break;
			default:
				fake = dp->fake_unknown;
				fake_size = dp->fake_unknown_size;
				fake = &dp->fake_unknown;
				break;
		}
		if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
@@ -1273,13 +1272,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
		else
			seqovl_pos = 0;

		// we do not need reasm buffer anymore
		reasm_orig_cancel(ctrack);
		rdata_payload=NULL;

		uint32_t fooling_orig = FOOL_NONE;
		bool bFake = false;
		pkt1_len = sizeof(pkt1);
		switch(dp->desync_mode)
		{
			case DESYNC_FAKE_KNOWN:
@@ -1291,28 +1285,69 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
				}
			case DESYNC_FAKE:
				if (reasm_offset) break;

				{
					struct blob_item *fake_item;
					uint8_t *fake_data;
					uint8_t fake_data_buf[FAKE_MAX_TCP];
					int n=0;

					ip_id = IP4_IP_ID_FIX(dis->ip);

					LIST_FOREACH(fake_item, fake, next)
					{
						n++;
						switch(l7proto)
						{
							case TLS:
								if ((fake_item->size <= sizeof(fake_data_buf)) && 
									runtime_tls_mod(n,(struct fake_tls_mod_cache *)fake_item->extra, dp->fake_tls_mod, fake_item->data, fake_item->size, rdata_payload, rlen_payload, fake_data_buf))
								{
									fake_data = fake_data_buf;
									break;
								}
							default:
								fake_data = fake_item->data;
						}
						pkt1_len = sizeof(pkt1);
						if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
					ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
							ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
							dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
					fake, fake_size, pkt1, &pkt1_len))
							fake_data, fake_item->size, pkt1, &pkt1_len))
						{
							reasm_orig_cancel(ctrack);
							return verdict;
						}
				DLOG("sending fake : ");
				hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
						DLOG("sending fake[%d] : ", n);
						hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
						if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
						{
							reasm_orig_cancel(ctrack);
							return verdict;
						}
						ip_id=IP4_IP_ID_NEXT(ip_id);
					}
				}
				bFake = true;
				break;
			case DESYNC_RST:
			case DESYNC_RSTACK:
				if (reasm_offset) break;
				pkt1_len = sizeof(pkt1);
				if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
					ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
					dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
					NULL, 0, pkt1, &pkt1_len))
				{
					reasm_orig_cancel(ctrack);
					return verdict;
				}
				DLOG("sending fake RST/RSTACK\n");
				if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
				{
					reasm_orig_cancel(ctrack);
					return verdict;
				}
				bFake = true;
				break;
			case DESYNC_HOPBYHOP:
@@ -1323,8 +1358,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
					(!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) ||
					(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
				{
					reasm_orig_cancel(ctrack);

					pkt1_len = sizeof(pkt1);
					if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
						ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
						ttl_orig,0,0,IP6_FLOW(dis->ip6),
						fooling_orig,0,0,
						dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
					{
@@ -1341,11 +1379,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
				break;
		}

		if (bFake)
		{
			if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
				return verdict;
		}
		// we do not need reasm buffer anymore
		reasm_orig_cancel(ctrack);
		rdata_payload=NULL;

		enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
		switch(desync_mode)
@@ -1875,8 +1911,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint

	if (dis->len_payload)
	{
		const uint8_t *fake;
		size_t fake_size;
		struct blob_collection_head *fake;
		char host[256];
		bool bHaveHost=false;
		uint16_t ip_id;
@@ -2110,20 +2145,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
		switch(l7proto)
		{
			case QUIC:
				fake = dp->fake_quic;
				fake_size = dp->fake_quic_size;
				fake = &dp->fake_quic;
				break;
			case WIREGUARD:
				fake = dp->fake_wg;
				fake_size = dp->fake_wg_size;
				fake = &dp->fake_wg;
				break;
			case DHT:
				fake = dp->fake_dht;
				fake_size = dp->fake_dht_size;
				fake = &dp->fake_dht;
				break;
			default:
				fake = dp->fake_unknown_udp;
				fake_size = dp->fake_unknown_udp_size;
				fake = &dp->fake_unknown_udp;
				break;
		}

@@ -2140,7 +2171,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
		}

		bool bFake = false;
		pkt1_len = sizeof(pkt1);
		switch(dp->desync_mode)
		{
			case DESYNC_FAKE_KNOWN:
@@ -2150,12 +2180,30 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
					break;
				}
			case DESYNC_FAKE:
				if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len))
				{
					struct blob_item *fake_item;
					int n=0;

					ip_id = IP4_IP_ID_FIX(dis->ip);

					LIST_FOREACH(fake_item, fake, next)
					{
						n++;
						pkt1_len = sizeof(pkt1);
						if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
							ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
							dp->desync_fooling_mode, NULL, 0, 0,
							fake_item->data, fake_item->size, pkt1, &pkt1_len))
						{
							return verdict;
				DLOG("sending fake : ");
				hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
						}
						DLOG("sending fake[%d] : ", n);
						hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
						if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
							return verdict;
						ip_id=IP4_IP_ID_NEXT(ip_id);
					}
				}
				bFake = true;
				break;
			case DESYNC_HOPBYHOP:
@@ -2164,9 +2212,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
				fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
				if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2)))
				{
					pkt1_len = sizeof(pkt1);
					if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
						ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
						fooling_orig,NULL,0,0,
						ttl_orig,0,0,IP6_FLOW(dis->ip6),fooling_orig,NULL,0,0,
						dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
					{
						return verdict;
+108 −59
Original line number Diff line number Diff line
@@ -1007,74 +1007,67 @@ static void SplitDebug(void)
}

static const char * tld[]={"com","org","net","edu","gov","biz"};
static void onetime_tls_mod(struct desync_profile *dp)

static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint8_t fake_tls_mod, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size, struct fake_tls_mod_cache *modcache)
{
	const uint8_t *ext;
	size_t extlen, slen;

	if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE)))
		dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid
	if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK))
		return; // nothing to do
	if (!IsTLSClientHello(dp->fake_tls,dp->fake_tls_size,false) || (dp->fake_tls_size<(44+dp->fake_tls[43]))) // has session id ?
	{
		DLOG_ERR("profile %d tls mod set but tls fake structure invalid\n", dp->n);
		exit_clean(1);
	}
	if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
	modcache->extlen_offset = modcache->padlen_offset = 0;
	if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
	{
		if (!TLSFindExtLen(dp->fake_tls,dp->fake_tls_size,&dp->fake_tls_extlen_offset))
		if (!TLSFindExtLen(fake_tls,*fake_tls_size,&modcache->extlen_offset))
		{
			DLOG_ERR("profile %d padencap set but tls fake structure invalid\n", dp->n);
			exit_clean(1);
			DLOG_ERR("profile %d fake[%d] padencap set but tls fake structure invalid\n", profile_n, fake_n);
			return false;
		}
		DLOG("profile %d fake tls extensions length offset : %zu\n", dp->n, dp->fake_tls_extlen_offset);
		if (TLSFindExt(dp->fake_tls,dp->fake_tls_size,21,&ext,&extlen,false))
		DLOG("profile %d fake[%d] tls extensions length offset : %zu\n", profile_n, fake_n, modcache->extlen_offset);
		if (TLSFindExt(fake_tls,*fake_tls_size,21,&ext,&extlen,false))
		{
			if ((ext-dp->fake_tls+extlen)!=dp->fake_tls_size)
			if ((ext-fake_tls+extlen)!=*fake_tls_size)
			{
				DLOG_ERR("profile %d fake tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", dp->n, ext-dp->fake_tls, extlen, dp->fake_tls_size);
				exit_clean(1);
				DLOG_ERR("profile %d fake[%d] tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", profile_n, fake_n, ext-fake_tls, extlen, *fake_tls_size);
				return false;
			}
			dp->fake_tls_padlen_offset = ext-dp->fake_tls-2;
			DLOG("profile %d fake tls padding ext is present, padding length offset %zu\n", dp->n, dp->fake_tls_padlen_offset);
			modcache->padlen_offset = ext-fake_tls-2;
			DLOG("profile %d fake[%d] tls padding ext is present, padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
		}
		else
		{
			if ((dp->fake_tls_size+4)>sizeof(dp->fake_tls))
			if ((*fake_tls_size+4)>fake_tls_buf_size)
			{
				DLOG_ERR("profile %d fake tls padding is absent and there's not space to add it\n", dp->n);
				exit_clean(1);
				DLOG_ERR("profile %d fake[%d] tls padding is absent and there's no space to add it\n", profile_n, fake_n);
				return false;
			}
			phton16(dp->fake_tls+dp->fake_tls_size,21);
			dp->fake_tls_size+=2;
			dp->fake_tls_padlen_offset=dp->fake_tls_size;
			phton16(dp->fake_tls+dp->fake_tls_size,0);
			dp->fake_tls_size+=2;
			phton16(dp->fake_tls+dp->fake_tls_extlen_offset,pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset)+4);
			phton16(dp->fake_tls+3,pntoh16(dp->fake_tls+3)+4); // increase tls record len
			phton24(dp->fake_tls+6,pntoh24(dp->fake_tls+6)+4); // increase tls handshake len
			DLOG("profile %d fake tls padding is absent. added. padding ledgth offset %zu\n", dp->n, dp->fake_tls_padlen_offset);
			phton16(fake_tls+*fake_tls_size,21);
			*fake_tls_size+=2;
			modcache->padlen_offset=*fake_tls_size;
			phton16(fake_tls+*fake_tls_size,0);
			*fake_tls_size+=2;
			phton16(fake_tls+modcache->extlen_offset,pntoh16(fake_tls+modcache->extlen_offset)+4);
			phton16(fake_tls+3,pntoh16(fake_tls+3)+4); // increase tls record len
			phton24(fake_tls+6,pntoh24(fake_tls+6)+4); // increase tls handshake len
			DLOG("profile %d fake[%d] tls padding is absent. added. padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
		}
	}
	if (dp->fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
	if (fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
	{
		if (!TLSFindExt(dp->fake_tls,dp->fake_tls_size,0,&ext,&extlen,false))
		if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false))
		{
			DLOG_ERR("profile %d rndsni set but tls fake does not have SNI\n", dp->n);
			exit_clean(1);
			DLOG_ERR("profile %d fake[%d] rndsni set but tls fake does not have SNI\n", profile_n, fake_n);
			return false;
		}
		if (!TLSAdvanceToHostInSNI(&ext,&extlen,&slen))
		{
			DLOG_ERR("profile %d rndsni set but tls fake has invalid SNI structure\n", dp->n);
			exit_clean(1);
			DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has invalid SNI structure\n", profile_n, fake_n);
			return false;
		}
		if (!slen)
		{
			DLOG_ERR("profile %d rndsni set but tls fake has zero sized SNI\n", dp->n);
			exit_clean(1);
			DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has zero sized SNI\n", profile_n, fake_n);
			return false;
		}
		uint8_t *sni = dp->fake_tls + (ext - dp->fake_tls);
		uint8_t *sni = fake_tls + (ext - fake_tls);

		char *s1=NULL, *s2=NULL;
		if (params.debug)
@@ -1100,11 +1093,66 @@ static void onetime_tls_mod(struct desync_profile *dp)
			if (s1 && (s2 = malloc(slen+1)))
			{
				memcpy(s2,sni,slen); s2[slen]=0;
				DLOG("profile %d generated random SNI : %s -> %s\n",dp->n,s1,s2);
				DLOG("profile %d fake[%d] generated random SNI : %s -> %s\n",profile_n,fake_n,s1,s2);
			}
			free(s1); free(s2);
		}
	}
	return true;
}
static bool onetime_tls_mod(struct desync_profile *dp)
{
	if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE)))
		dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid
	if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK))
		return true; // nothing to do

	struct blob_item *fake_tls;
	int n=0;
	bool bMod=false;

	LIST_FOREACH(fake_tls, &dp->fake_tls, next)
	{
		++n;
		if (!IsTLSClientHello(fake_tls->data,fake_tls->size,false) || (fake_tls->size < (44+fake_tls->data[43]))) // has session id ?
		{
			DLOG_ERR("profile %d fake[%d] tls mod set but tls fake structure invalid. mod skipped.\n", dp->n, n);
			continue;

		}
		bMod = true;
		if (!fake_tls->extra)
		{
			fake_tls->extra = malloc(sizeof(struct fake_tls_mod_cache));
			if (!fake_tls->extra) return false;
		}
		if (!onetime_tls_mod_blob(dp->n,n,dp->fake_tls_mod,fake_tls->data,&fake_tls->size,fake_tls->size_buf,(struct fake_tls_mod_cache*)fake_tls->extra))
			return false;
	}
	if (!bMod)
		DLOG_ERR("profile %d tls fake list does not have any valid TLS ClientHello\n", dp->n);
	return bMod;
}

static void load_blob_to_collection(const char *filename, struct blob_collection_head *blobs, size_t max_size, size_t size_reserve)
{
	struct blob_item *blob = blob_collection_add(blobs);
	uint8_t *p;
	if (!blob || (!(blob->data = malloc(max_size+size_reserve))))
	{
		DLOG_ERR("out of memory\n");
		exit_clean(1);
	}
	blob->size = max_size;
	load_file_or_exit(filename,blob->data,&blob->size);
	p = realloc(blob->data,blob->size+size_reserve);
	if (!p)
	{
		DLOG_ERR("out of memory\n");
		exit_clean(1);
	}
	blob->data = p;
	blob->size_buf = blob->size+size_reserve;
}


@@ -1992,13 +2040,10 @@ int main(int argc, char **argv)
			dp->desync_any_proto = !optarg || atoi(optarg);
			break;
		case 38: /* dpi-desync-fake-http */
			dp->fake_http_size = sizeof(dp->fake_http);
			load_file_or_exit(optarg,dp->fake_http,&dp->fake_http_size);
			load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP,0);
			break;
		case 39: /* dpi-desync-fake-tls */
			dp->fake_tls_size = sizeof(dp->fake_tls);
			load_file_or_exit(optarg,dp->fake_tls,&dp->fake_tls_size);
			dp->fake_tls_mod |= FAKE_TLS_MOD_CUSTOM_FAKE;
			load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4);
			break;
		case 40: /* dpi-desync-fake-tls-mod */
			if (!parse_tlsmod_list(optarg,&dp->fake_tls_mod))
@@ -2008,28 +2053,23 @@ int main(int argc, char **argv)
			}
			break;
		case 41: /* dpi-desync-fake-unknown */
			dp->fake_unknown_size = sizeof(dp->fake_unknown);
			load_file_or_exit(optarg,dp->fake_unknown,&dp->fake_unknown_size);
			load_blob_to_collection(optarg, &dp->fake_unknown, FAKE_MAX_TCP, 0);
			break;
		case 42: /* dpi-desync-fake-syndata */
			dp->fake_syndata_size = sizeof(dp->fake_syndata);
			load_file_or_exit(optarg,dp->fake_syndata,&dp->fake_syndata_size);
			break;
		case 43: /* dpi-desync-fake-quic */
			dp->fake_quic_size = sizeof(dp->fake_quic);
			load_file_or_exit(optarg,dp->fake_quic,&dp->fake_quic_size);
			load_blob_to_collection(optarg, &dp->fake_quic, FAKE_MAX_UDP, 0);
			break;
		case 44: /* dpi-desync-fake-wireguard */
			dp->fake_wg_size = sizeof(dp->fake_wg);
			load_file_or_exit(optarg,dp->fake_wg,&dp->fake_wg_size);
			load_blob_to_collection(optarg, &dp->fake_wg, FAKE_MAX_UDP, 0);
			break;
		case 45: /* dpi-desync-fake-dht */
			dp->fake_dht_size = sizeof(dp->fake_dht);
			load_file_or_exit(optarg,dp->fake_dht,&dp->fake_dht_size);
			load_blob_to_collection(optarg, &dp->fake_dht, FAKE_MAX_UDP, 0);
			break;
		case 46: /* dpi-desync-fake-unknown-udp */
			dp->fake_unknown_udp_size = sizeof(dp->fake_unknown_udp);
			load_file_or_exit(optarg,dp->fake_unknown_udp,&dp->fake_unknown_udp_size);
			load_blob_to_collection(optarg, &dp->fake_unknown_udp, FAKE_MAX_UDP, 0);
			break;
		case 47: /* dpi-desync-udplen-increment */
			if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000)
@@ -2475,7 +2515,16 @@ int main(int argc, char **argv)
		if (AUTOTTL_ENABLED(dp->desync_autottl6))
			DLOG("profile %d autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
		split_compat(dp);
		onetime_tls_mod(dp);
		if (!dp_fake_defaults(dp))
		{
			DLOG_ERR("could not fill fake defaults\n");
			exit_clean(1);
		}
		if (!onetime_tls_mod(dp))
		{
			DLOG_ERR("could not mod tls\n");
			exit_clean(1);
		}
#ifndef __CYGWIN__
		if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
			DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
+52 −11
Original line number Diff line number Diff line
@@ -184,18 +184,8 @@ void dp_init(struct desync_profile *dp)
	dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
	dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
	dp->desync_repeats = 1;
	dp->fake_tls_size = sizeof(fake_tls_clienthello_default);
	memcpy(dp->fake_tls,fake_tls_clienthello_default,dp->fake_tls_size);
	dp->fake_tls_mod = 0;
	dp->fake_http_size = strlen(fake_http_request_default);
	memcpy(dp->fake_http,fake_http_request_default,dp->fake_http_size);
	dp->fake_quic_size = 620; // must be 601+ for TSPU hack
	dp->fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
	dp->fake_wg_size = 64;
	dp->fake_dht_size = 64;
	dp->fake_unknown_size = 256;
	dp->fake_syndata_size = 16;
	dp->fake_unknown_udp_size = 64;
	dp->wscale=-1; // default - dont change scale factor (client)
	dp->desync_ttl6 = 0xFF; // unused
	dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
@@ -207,6 +197,50 @@ void dp_init(struct desync_profile *dp)
	dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
	dp->filter_ipv4 = dp->filter_ipv6 = true;
}
bool dp_fake_defaults(struct desync_profile *dp)
{
	struct blob_item *item;
	if (blob_collection_empty(&dp->fake_http))
		if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0))
			return false;
	if (blob_collection_empty(&dp->fake_tls))
	{
		if (!blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4))
			return false;
	}
	if (blob_collection_empty(&dp->fake_unknown))
	{
		if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0)))
			return false;
		memset(item->data,0,item->size);
	}
	if (blob_collection_empty(&dp->fake_quic))
	{
		if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0)))
			return false;
		memset(item->data,0,item->size);
		item->data[0] = 0x40;
	}
	if (blob_collection_empty(&dp->fake_wg))
	{
		if (!(item=blob_collection_add_blob(&dp->fake_wg,NULL,64,0)))
			return false;
		memset(item->data,0,item->size);
	}
	if (blob_collection_empty(&dp->fake_dht))
	{
		if (!(item=blob_collection_add_blob(&dp->fake_dht,NULL,64,0)))
			return false;
		memset(item->data,0,item->size);
	}
	if (blob_collection_empty(&dp->fake_unknown_udp))
	{
		if (!(item=blob_collection_add_blob(&dp->fake_unknown_udp,NULL,64,0)))
			return false;
		memset(item->data,0,item->size);
	}
	return true;
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{
	struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
@@ -234,6 +268,13 @@ static void dp_clear_dynamic(struct desync_profile *dp)
	ipset_collection_destroy(&dp->ips_collection_exclude);
	port_filters_destroy(&dp->pf_tcp);
	port_filters_destroy(&dp->pf_udp);
	blob_collection_destroy(&dp->fake_http);
	blob_collection_destroy(&dp->fake_tls);
	blob_collection_destroy(&dp->fake_unknown);
	blob_collection_destroy(&dp->fake_unknown_udp);
	blob_collection_destroy(&dp->fake_quic);
	blob_collection_destroy(&dp->fake_wg);
	blob_collection_destroy(&dp->fake_dht);
	HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
}
void dp_clear(struct desync_profile *dp)
+14 −5

File changed.

Preview size limit exceeded, changes collapsed.

+61 −0
Original line number Diff line number Diff line
@@ -517,3 +517,64 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
	if (LIST_FIRST(head)) return true;
	return pf_parse("0",&pf) && port_filter_add(head,&pf);
}


		
struct blob_item *blob_collection_add(struct blob_collection_head *head)
{
	struct blob_item *entry = calloc(1,sizeof(struct blob_item));
	if (entry)
	{
		// insert to the end
		struct blob_item *itemc,*iteml=LIST_FIRST(head);
		if (iteml)
		{
			while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
			LIST_INSERT_AFTER(iteml, entry, next);
		}
		else
			LIST_INSERT_HEAD(head, entry, next);
	}
	return entry;
}
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve)
{
	struct blob_item *entry = calloc(1,sizeof(struct blob_item));
	if (!entry) return NULL;
	if (!(entry->data = malloc(size+size_reserve))) 
	{
		free(entry);
		return NULL;
	}
	if (data) memcpy(entry->data,data,size);
	entry->size = size;
	entry->size_buf = size+size_reserve;
	
	// insert to the end
	struct blob_item *itemc,*iteml=LIST_FIRST(head);
	if (iteml)
	{
		while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
		LIST_INSERT_AFTER(iteml, entry, next);
	}
	else
		LIST_INSERT_HEAD(head, entry, next);

	return entry;
}

void blob_collection_destroy(struct blob_collection_head *head)
{
	struct blob_item *entry;
	while ((entry = LIST_FIRST(head)))
	{
		LIST_REMOVE(entry, next);
		free(entry->extra);
		free(entry->data);
		free(entry);
	}
}
bool blob_collection_empty(const struct blob_collection_head *head)
{
	return !LIST_FIRST(head);
}
Loading