Commit 9629ce5c authored by bol-van's avatar bol-van
Browse files

tpws: ipcache

parent c626d88f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@

#define FIX_SEG_DEFAULT_MAX_WAIT		50

#define IPCACHE_LIFETIME		7200

enum bindll { unwanted=0, no, prefer, force };

#define MAX_BINDS	32
@@ -140,6 +142,10 @@ struct params_s
	bool tamper; // any tamper option is set
	bool tamper_lim; // tamper-start or tamper-cutoff set in any profile
	struct desync_profile_list_head desync_profiles;

	unsigned int ipcache_lifetime;
	bool cache_hostname;
	ip_cache ipcache;
};

extern struct params_s params;
+275 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>

#define DESTROY_STR_POOL(etype, ppool) \
	etype *elem, *tmp; \
@@ -517,3 +518,277 @@ 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->extra2);
		free(entry->data);
		free(entry);
	}
}
bool blob_collection_empty(const struct blob_collection_head *head)
{
	return !LIST_FIRST(head);
}



static void ipcache_item_touch(ip_cache_item *item)
{
	time(&item->last);
}
static void ipcache_item_init(ip_cache_item *item)
{
	ipcache_item_touch(item);
	item->hostname = NULL;
}
static void ipcache_item_destroy(ip_cache_item *item)
{
	free(item->hostname);
}

static void ipcache4Destroy(ip_cache4 **ipcache)
{
	ip_cache4 *elem, *tmp;
	HASH_ITER(hh, *ipcache, elem, tmp)
	{
		HASH_DEL(*ipcache, elem);
		ipcache_item_destroy(&elem->data);
		free(elem);
	}
}
static void ipcache4Key(ip4if *key, const struct in_addr *a)
{
	memset(key,0,sizeof(*key)); // make sure everything is zero
	key->addr = *a;
}
static ip_cache4 *ipcache4Find(ip_cache4 *ipcache, const struct in_addr *a)
{
	ip_cache4 *entry;
	struct ip4if key;

	ipcache4Key(&key,a);
	HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
	return entry;
}
static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a)
{
	// avoid dups
	ip_cache4 *entry = ipcache4Find(*ipcache,a);
	if (entry) return entry; // already included

	entry = malloc(sizeof(ip_cache4));
	if (!entry) return NULL;
	ipcache4Key(&entry->key,a);

	oom = false;
	HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
	if (oom) { free(entry); return NULL; }

	ipcache_item_init(&entry->data);

	return entry;
}
static void ipcache4Print(ip_cache4 *ipcache)
{
	char s_ip[16];
	time_t now;
	ip_cache4 *ipc, *tmp;

	time(&now);
	HASH_ITER(hh, ipcache , ipc, tmp)
	{
		*s_ip=0;
		inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
		printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
	}
}

static void ipcache6Destroy(ip_cache6 **ipcache)
{
	ip_cache6 *elem, *tmp;
	HASH_ITER(hh, *ipcache, elem, tmp)
	{
		HASH_DEL(*ipcache, elem);
		ipcache_item_destroy(&elem->data);
		free(elem);
	}
}
static void ipcache6Key(ip6if *key, const struct in6_addr *a)
{
	memset(key,0,sizeof(*key)); // make sure everything is zero
	key->addr = *a;
}
static ip_cache6 *ipcache6Find(ip_cache6 *ipcache, const struct in6_addr *a)
{
	ip_cache6 *entry;
	ip6if key;

	ipcache6Key(&key,a);
	HASH_FIND(hh, ipcache, &key, sizeof(key), entry);
	return entry;
}
static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a)
{
	// avoid dups
	ip_cache6 *entry = ipcache6Find(*ipcache,a);
	if (entry) return entry; // already included

	entry = malloc(sizeof(ip_cache6));
	if (!entry) return NULL;
	ipcache6Key(&entry->key,a);

	oom = false;
	HASH_ADD(hh, *ipcache, key, sizeof(entry->key), entry);
	if (oom) { free(entry); return NULL; }

	ipcache_item_init(&entry->data);

	return entry;
}
static void ipcache6Print(ip_cache6 *ipcache)
{
	char s_ip[40];
	time_t now;
	ip_cache6 *ipc, *tmp;

	time(&now);
	HASH_ITER(hh, ipcache , ipc, tmp)
	{
		*s_ip=0;
		inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
		printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
	}
}

void ipcacheDestroy(ip_cache *ipcache)
{
	ipcache4Destroy(&ipcache->ipcache4);
	ipcache6Destroy(&ipcache->ipcache6);
}
void ipcachePrint(ip_cache *ipcache)
{
	ipcache4Print(ipcache->ipcache4);
	ipcache6Print(ipcache->ipcache6);
}

ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6)
{
	ip_cache4 *ipcache4;
	ip_cache6 *ipcache6;
	if (a4)
	{
		if ((ipcache4 = ipcache4Add(&ipcache->ipcache4,a4)))
		{
			ipcache_item_touch(&ipcache4->data);
			return &ipcache4->data;
		}
	}
	else if (a6)
	{
		if ((ipcache6 = ipcache6Add(&ipcache->ipcache6,a6)))
		{
			ipcache_item_touch(&ipcache6->data);
			return &ipcache6->data;
		}
	}
	return NULL;
}

static void ipcache4_purge(ip_cache4 **ipcache, time_t lifetime)
{
	ip_cache4 *elem, *tmp;
	time_t now = time(NULL);
	HASH_ITER(hh, *ipcache, elem, tmp)
	{
		if (now >= (elem->data.last + lifetime))
		{
			HASH_DEL(*ipcache, elem);
			ipcache_item_destroy(&elem->data);
			free(elem);
		}
	}
}
static void ipcache6_purge(ip_cache6 **ipcache, time_t lifetime)
{
	ip_cache6 *elem, *tmp;
	time_t now = time(NULL);
	HASH_ITER(hh, *ipcache, elem, tmp)
	{
		if (now >= (elem->data.last + lifetime))
		{
			HASH_DEL(*ipcache, elem);
			ipcache_item_destroy(&elem->data);
			free(elem);
		}
	}
}
static void ipcache_purge(ip_cache *ipcache, time_t lifetime)
{
	if (lifetime) // 0 = no expire
	{
		ipcache4_purge(&ipcache->ipcache4, lifetime);
		ipcache6_purge(&ipcache->ipcache6, lifetime);
	}
}
static time_t ipcache_purge_prev=0;
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime)
{
	time_t now = time(NULL);
	// do not purge too often to save resources
	if (ipcache_purge_prev != now)
	{
		ipcache_purge(ipcache, lifetime);
		ipcache_purge_prev = now;
	}
}
+53 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include <ctype.h>
#include <sys/queue.h>
#include <net/if.h>
#include <time.h>

#include "helpers.h"
@@ -146,3 +147,55 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
void port_filters_destroy(struct port_filters_head *head);
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port);
bool port_filters_deny_if_empty(struct port_filters_head *head);


struct blob_item {
	uint8_t *data;	// main data blob
	size_t size;	// main data blob size
	size_t size_buf;// main data blob allocated size
	void *extra;	// any data without size
	void *extra2;	// any data without size
	LIST_ENTRY(blob_item) next;
};
LIST_HEAD(blob_collection_head, blob_item);
struct blob_item *blob_collection_add(struct blob_collection_head *head);
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const struct blob_collection_head *head);


typedef struct ip4if
{
	struct in_addr addr;
} ip4if;
typedef struct ip6if
{
	struct in6_addr addr;
} ip6if;
typedef struct ip_cache_item
{
	time_t last;
	char *hostname;
} ip_cache_item;
typedef struct ip_cache4
{
	ip4if key;
	ip_cache_item data;
	UT_hash_handle hh;	/* makes this structure hashable */
} ip_cache4;
typedef struct ip_cache6
{
	ip6if key;
	ip_cache_item data;
	UT_hash_handle hh;	/* makes this structure hashable */
} ip_cache6;
typedef struct ip_cache
{
	ip_cache4 *ipcache4;
	ip_cache6 *ipcache6;
} ip_cache;

ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6);
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime);
void ipcacheDestroy(ip_cache *ipcache);
void ipcachePrint(ip_cache *ipcache);
+59 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "ipset.h"
#include "protocol.h"
#include "helpers.h"
#include "pools.h"

#define PKTDATA_MAXDUMP 32

@@ -90,6 +91,48 @@ static void TLSDebug(const uint8_t *tls,size_t sz)
	TLSDebugHandshake(tls+5,sz-5);
}

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

	ip_cache_item *ipc = ipcacheTouch(&params.ipcache,a4,a6);
	if (!ipc)
	{
		DLOG_ERR("ipcache_put_hostname: out of memory\n");
		return false;
	}
	free(ipc->hostname);
	if (!(ipc->hostname = strdup(hostname)))
	{
		DLOG_ERR("ipcache_put_hostname: out of memory\n");
		return false;
	}
	VPRINT("hostname cached: %s\n", 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)
{
	if (!params.cache_hostname)
	{
		*hostname = 0;
		return true;
	}
	ip_cache_item *ipc = ipcacheTouch(&params.ipcache,a4,a6);
	if (!ipc)
	{
		DLOG_ERR("ipcache_get_hostname: out of memory\n");
		return false;
	}
	if (ipc->hostname)
	{
		VPRINT("got cached hostname: %s\n", ipc->hostname);
		snprintf(hostname,hostname_buf_len,"%s",ipc->hostname);
	}
	else
		*hostname = 0;
	return true;
}

static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
{
	bool bHostlistsEmpty;
@@ -145,8 +188,17 @@ static struct desync_profile *dp_find(struct desync_profile_list_head *head, con
	VPRINT("desync profile not found\n");
	return NULL;
}

void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
{
	ipcachePurgeRateLimited(&params.ipcache, params.ipcache_lifetime);
	if (!ctrack->hostname)
	{
		char host[256];
		if (ipcache_get_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , host, sizeof(host)) && *host)
			if (!(ctrack->hostname=strdup(host)))
				DLOG_ERR("hostname dup : out of memory");
	}
	ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->l7proto);
}

@@ -215,7 +267,11 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
	}

	if (bHaveHost)
	{
		VPRINT("request hostname: %s\n", Host);
		if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host))
			DLOG_ERR("ipcache_put_hostname: out of memory");
	}

	bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
	if (bDiscoveredL7)
@@ -224,15 +280,17 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
		ctrack->l7proto=l7proto;
	}

	bool bDiscoveredHostname = bHaveHost && !ctrack->hostname;
	bool bDiscoveredHostname = bHaveHost && !ctrack->hostname_discovered;
	if (bDiscoveredHostname)
	{
		VPRINT("discovered hostname\n");
		free(ctrack->hostname);
		if (!(ctrack->hostname=strdup(Host)))
		{
			DLOG_ERR("strdup hostname : out of memory\n");
			return;
		}
		ctrack->hostname_discovered = true;
	}

	if (bDiscoveredL7 || bDiscoveredHostname)
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ typedef struct
	t_l7proto l7proto;
	bool bTamperInCutoff;
	bool b_host_checked,b_host_matches,b_ah_check;
	bool hostname_discovered;
	char *hostname;
	struct desync_profile *dp;		// desync profile cache
} t_ctrack;
Loading