summaryrefslogtreecommitdiff
path: root/entry/src/kni_dynamic_bypass.cpp
blob: 8425bcbc95a81fc3108c8fb900794cd58b3d03c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#include "kni_dynamic_bypass.h"

#define SSL_INFO_LEN 512

struct dynamic_bypass_ssl_feature{
	size_t vlen;
	char value[SSL_INFO_LEN];
};

extern struct kni_handle *g_kni_handle;
extern struct kni_field_stat_handle *g_kni_fs_handle;

char * stream_addr_to_str(struct pme_info *pmeinfo,struct pkt_info *pktinfo)
{
	char * __str_ret = NULL;
	if(pmeinfo==NULL || pktinfo == NULL) return NULL;
	if (pmeinfo->addr_type == ADDR_TYPE_IPV4)
	{
		char __src_addr[INET_ADDRSTRLEN];
		char __dst_addr[INET_ADDRSTRLEN];
		uint16_t __src_port;
		uint16_t __dst_port;
		if(pktinfo->iphdr.v4->saddr < pktinfo->iphdr.v4->daddr){
			__src_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->source);
			__dst_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->dest);
			inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->saddr), __src_addr, sizeof(__src_addr));
			inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->daddr), __dst_addr, sizeof(__dst_addr));
		}
		else
		{
			__src_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->dest);
			__dst_port = ntohs((uint16_t) pmeinfo->stream->addr.tuple4_v4->source);
			inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->daddr), __src_addr, sizeof(__src_addr));
			inet_ntop(AF_INET, &(pmeinfo->stream->addr.tuple4_v4->saddr), __dst_addr, sizeof(__dst_addr));
		}
		asprintf(&__str_ret, "%s %u %s %u", __src_addr, __src_port, __dst_addr, __dst_port);
	}

	if (pmeinfo->addr_type == ADDR_TYPE_IPV6)
	{
		char __src_addr[INET6_ADDRSTRLEN];
		char __dst_addr[INET6_ADDRSTRLEN];
		uint16_t __src_port;
		uint16_t __dst_port;
		if(memcmp((void*)&(pktinfo->iphdr.v6->ip6_src), (void*)&(pktinfo->iphdr.v6->ip6_dst), IPV6_ADDR_LEN) < 0){
			__src_port = ntohs((uint16_t) pktinfo->tcphdr->source);
			__dst_port = ntohs((uint16_t) pktinfo->tcphdr->dest);
			memcpy(__src_addr, &(pktinfo->iphdr.v6->ip6_src), sizeof(__src_addr));
			memcpy(__dst_addr, &(pktinfo->iphdr.v6->ip6_dst), sizeof(__dst_addr));
		}
		else
		{
			__src_port = ntohs((uint16_t) pktinfo->tcphdr->dest);
			__dst_port = ntohs((uint16_t) pktinfo->tcphdr->source);
			memcpy(__src_addr, &(pktinfo->iphdr.v6->ip6_dst), sizeof(__src_addr));
			memcpy(__dst_addr, &(pktinfo->iphdr.v6->ip6_src), sizeof(__dst_addr));
		}
		asprintf(&__str_ret, "%s %u %s %u", __src_addr, __src_port, __dst_addr, __dst_port);
	}

	return __str_ret;
}

int stream_addr_str_split(char* addr_str, const char** sip, const char** sport, const char** dip, const char** dport)
{
	const char* seps=" ";
	char* saveptr=NULL, *subtoken=NULL, *str=NULL;
	int i=0;
	for (str = addr_str, i=0; ; str = NULL, i++)
	{
		subtoken = strtok_r(str, seps, &saveptr);
		if (subtoken == NULL)
			break;
		switch(i)
		{
			case 0:
				if(sip!=NULL) *sip=subtoken;
				break;
			case 1:
				if(sport!=NULL) *sport=subtoken;
				break;
			case 2:
				if(dip!=NULL) *dip=subtoken;
				break;
			case 3:
				if(dport!=NULL)	*dport=subtoken;
				break;
			default:
				return -1;
				break;
		}
	}
	return 0;

}

static long sslinfo2bypass_htable_search_cb(void *data, const uchar *key, uint size, void *user_args){
	if(data != NULL)
		return 0;
	else
		return -1;
}

static int sslinfo2bypass_htable_search(MESA_htable_handle htable,char *key, int klen,  struct pme_info *pmeinfo)
{
	void *logger = g_kni_handle->local_logger;
    long cb_ret = -1;
	void *value;
    value = MESA_htable_search_cb(htable, (const unsigned char *)key, (unsigned int )klen, sslinfo2bypass_htable_search_cb, NULL, &cb_ret);
	if(cb_ret == 0)
	{
		pmeinfo->ssl_pinningst = *((uint64_t *)value);
		KNI_LOG_DEBUG(logger, "MESA_htable: success to search, table = sslinfo2bypass_htable,key = %s, key_size = %d, ret =%d", key, klen,cb_ret);
	}
	else
	{
		KNI_LOG_DEBUG(logger, "MESA_htable:Search result value is null, table = sslinfo2bypass_htable,key = %s, key_size = %d, ret =%d", key, klen,cb_ret);
	}
	return cb_ret;
}

static int traceid2sslinfo_htable_add(char *key, uint klen, void * value,int thread_seq)
{
	void *logger = g_kni_handle->local_logger;
	int ret;
	MESA_htable_handle traceid2sslinfo_htable = g_kni_handle->threads_handle[thread_seq].traceid2sslinfo_htable;
	ret = MESA_htable_add(traceid2sslinfo_htable, (const unsigned char *)key, klen, (const void*)value);
	if(ret >= 0)
	{
		FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_ADD_SUCC], 0, FS_OP_ADD, 1);
		FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, 1);
		KNI_LOG_DEBUG(logger, "MESA_htable:Success to add, table = traceid2sslinfo_htable,key = %s, key_size = %d, ret =%d , thread_seq=%d", key, klen,ret, thread_seq);
	}
	else
	{
		KNI_LOG_ERROR(logger, "MESA_htable:Fail to add, table = traceid2sslinfo_htable,key = %s, key_size = %d, ret =%d , thread_seq=%d", key, klen,ret, thread_seq);
	}
	return ret;
}


static int sslinfo2bypass_htable_add(char *key, uint klen, void * value, void *logger)
{
	int ret = -1;
	MESA_htable_handle sslinfo2bypass_htable = g_kni_handle->sslinfo2bypass_htable;
	ret = MESA_htable_add(sslinfo2bypass_htable, (const unsigned char *)key, klen, (const void*)value);
	if(ret < 0)
	{
		KNI_LOG_ERROR(logger, "MESA_htable: Failed at add, table = sslinfo2bypass_htable, key = %s, key_size = %d, ret = %d",key, klen, ret);
	}
	else
	{
		KNI_LOG_DEBUG(logger, "MESA_htable: Success at add, table = sslinfo2bypass_htable, key = %s, key_size = %d, ret = %d",key, klen, ret);
		FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_ADD_SUCC], 0, FS_OP_ADD, 1);
		FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_CNT], 0, FS_OP_ADD, 1);

	}
	return ret;
}

static long traceid2sslinfo_htable_search_cb(void *data, const uchar *key, uint size, void *user_args)
{
	struct dynamic_bypass_ssl_feature * ssl_feature = (struct dynamic_bypass_ssl_feature *)data;
	void *logger = g_kni_handle->local_logger;
	uint64_t * p_ssl_pinningst = (uint64_t *)user_args;
	uint64_t *value = NULL;
	long cb_ret = -1;

	if(ssl_feature != NULL)
	{
		value = ALLOC(uint64_t, 1);
		*value = *p_ssl_pinningst;
		if(sslinfo2bypass_htable_add(ssl_feature->value, ssl_feature->vlen, (void *)value, logger) < 0)
		{
			KNI_LOG_ERROR(logger, "Dynamic bypass, fail add to table = sslinfo2bypass_htable, key = %s, key_size = %d",
						ssl_feature->value, ssl_feature->vlen);
		}
		cb_ret = 0;
	} 
	return cb_ret;
}


static int traceid2sslinfo_htable_search(MESA_htable_handle htable,char *key, int klen, int thread_seq,uint64_t ssl_pinningst)
{
    long cb_ret = -1;
	void *logger = g_kni_handle->local_logger;
    MESA_htable_search_cb(htable, (const unsigned char *)key, (unsigned int )klen, traceid2sslinfo_htable_search_cb, &ssl_pinningst, &cb_ret);
	if(cb_ret >= 0)
	{
		KNI_LOG_DEBUG(logger, "MESA_htable: success to search, table = traceid2sslinfo_htable,thread_seq = %d,key = %s, key_size = %d, ret = %d", 
							thread_seq, key, klen,cb_ret);
	}
	else
	{
		KNI_LOG_ERROR(logger, "MESA_htable: Fail to search, table = traceid2sslinfo_htable,thread_seq = %d,key = %s, key_size = %d, ret = %d", 
							thread_seq, key, klen,cb_ret);
	}
	
	return cb_ret;
}

static void traceid2sslinfo_htable_data_free_cb(void *data){
	FREE(&data);
}

static void sslinfo2bypass_htable_data_free_cb(void *data){
	FREE(&data);
}

static int traceid2sslinfo_htable_expire_notify_cb(void *data, int eliminate_type)
{
	FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_DEL_SUCC], 0, FS_OP_ADD, 1);
	FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, -1);
	return 1;
}

static int sslinfo2bypass_htable_expire_notify_cb(void *data, int eliminate_type)
{
	FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_DEL_SUCC], 0, FS_OP_ADD, 1);
	FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_SSL2PASS_CNT], 0, FS_OP_ADD, -1);
	return 1;
}



static int get_ssl_conn_info(struct pme_info *pmeinfo,struct pkt_info *pktinfo, struct dynamic_bypass_ssl_feature *ssl_feature)
{
	void *logger = g_kni_handle->local_logger;

	const char *sip=NULL, *sport=NULL, *dip=NULL, *dport=NULL;
	char *addr_str = NULL;

	if(pmeinfo->session_attribute->ja3_fingerprint == NULL)
	{
		KNI_LOG_DEBUG(logger, "Dynamic bypass:get stream label ja3_fingerprint is null, stream traceid = %s", pmeinfo->stream_traceid);
		return 1;
	}

	addr_str = stream_addr_to_str(pmeinfo,pktinfo);
	stream_addr_str_split(addr_str, &sip, &sport, &dip, &dport);


	ssl_feature->vlen = snprintf(ssl_feature->value, SSL_INFO_LEN, "%s:%s:%s",
																	pmeinfo->session_attribute->ja3_fingerprint,sip,
																	pmeinfo->domain_len > 0 ? (char*)&(pmeinfo->domain): dip);

	FREE(&addr_str);
	return 0;
}


int first_data_ssl_dynamic_bypass(struct streaminfo *stream, struct pme_info *pmeinfo, struct pkt_info *pktinfo, int thread_seq)
{
	struct dynamic_bypass_ssl_feature *ssl_feature = NULL;
	void *logger = g_kni_handle->local_logger;

	int ret = -1;
	if(pmeinfo->protocol != PROTO_SSL){
		KNI_LOG_DEBUG(logger, "Dynamic bypass: stream protocol is not ssl: stream traceid = %s, protocol = %d", pmeinfo->stream_traceid,pmeinfo->protocol);
		return ret;
	}

	ssl_feature = ALLOC(struct dynamic_bypass_ssl_feature,1);
 	if(get_ssl_conn_info(pmeinfo,pktinfo, ssl_feature) == 1){
		FREE(&ssl_feature);
	 	return ret;
	}
	
	KNI_LOG_DEBUG(logger, "Dynamic bypass: ssl_info: %s, ssl_info len:%d, stream traceid = %s", ssl_feature->value, ssl_feature->vlen, pmeinfo->stream_traceid);

	if(sslinfo2bypass_htable_search(g_kni_handle->sslinfo2bypass_htable,ssl_feature->value, ssl_feature->vlen,pmeinfo) == 0)
	{
		KNI_LOG_DEBUG(logger, "Dynamic bypass: passthrough ok, stream traceid = %s,ssl_pinningst = %d", pmeinfo->stream_traceid, pmeinfo->ssl_pinningst);
		FREE(&ssl_feature);
		ret = 0; 
	}
	else
	{
		KNI_LOG_DEBUG(logger, "Dynamic bypass: not passthrough, stream traceid = %s", pmeinfo->stream_traceid);
		if(traceid2sslinfo_htable_add(pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid),ssl_feature,thread_seq) >=0)
		{
			ret = 1;
		}
		else
		{
			FREE(&ssl_feature);
		}
	}

	return ret;
}


void next_data_ssl_dynamic_bypass(struct pkt_info *pktinfo)
{
	//FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_INTCP_BYTE], 0, FS_OP_ADD, pktinfo->ip_totlen);
	return;
}


int ssl_dynamic_bypass_htable_add(struct pme_info *pmeinfo)
{
	void *logger = g_kni_handle->local_logger;
	long cb_ret;
	int ret = -1;
	MESA_htable_handle traceid2sslinfo_htable = g_kni_handle->threads_handle[pmeinfo->thread_seq].traceid2sslinfo_htable;
	if(pmeinfo->ssl_intercept_state == 0)
	{
		cb_ret = traceid2sslinfo_htable_search(traceid2sslinfo_htable,pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid), pmeinfo->thread_seq, pmeinfo->ssl_pinningst);
		if(cb_ret >= 0)
		{
			cb_ret = MESA_htable_del(traceid2sslinfo_htable, (const unsigned char *)pmeinfo->stream_traceid, strlen(pmeinfo->stream_traceid), NULL);
			if(cb_ret < 0)
			{
				KNI_LOG_ERROR(logger, "Delete traceid2sslinfo_htable fail,key=%s",pmeinfo->stream_traceid);
			}
			else
			{
				FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_DEL_SUCC], 0, FS_OP_ADD, 1);
				FS_operate(g_kni_fs_handle->handle, g_kni_fs_handle->fields[KNI_FIELD_ID2SSL_CNT], 0, FS_OP_ADD, -1);
			}
			ret = 0;
		}
	}
	return ret;		
}


int ssl_dynamic_bypass_htable_init(const char *profile,void *local_logger)
{
	struct kni_htable_opt opt;
	MESA_htable_handle sslinfo2bypass_htable = NULL;
	int ret = 0;
	int ssl_dynamic_bypass_enable = 1;

	MESA_load_profile_int_def(profile, "ssl_dynamic_bypass", "enabled", &ssl_dynamic_bypass_enable, 1);
    KNI_LOG_ERROR(local_logger, "Dynamic bypass: MESA_prof_load, [%s]:\n enabled: %d", "ssl_dynamic_bypass",ssl_dynamic_bypass_enable);
	g_kni_handle->ssl_dynamic_bypass_enable = ssl_dynamic_bypass_enable;

	if(ssl_dynamic_bypass_enable == 1){
		//init traceid2sslinfo_htable
		memset(&opt, 0, sizeof(opt));
		kni_get_htable_opt(&opt, profile, "traceid2sslinfo_htable", (void*)traceid2sslinfo_htable_data_free_cb, (void *)traceid2sslinfo_htable_expire_notify_cb, local_logger);
		for(int i = 0; i < g_kni_handle->thread_count; i++){
			MESA_htable_handle traceid2sslinfo_htable = kni_create_htable((char*)"traceid2sslinfo_htable", &opt, local_logger);
			if(traceid2sslinfo_htable == NULL){
				KNI_LOG_ERROR(local_logger, "Failed at kni_create_htable, table = traceid2sslinfo_htable");
				ret = -1;
				return ret;
			}
			g_kni_handle->threads_handle[i].traceid2sslinfo_htable = traceid2sslinfo_htable;
		}
		
		//init sslinfo2bypass_htable
		memset(&opt, 0, sizeof(opt));
		kni_get_htable_opt(&opt, profile, "sslinfo2bypass_htable", (void*)sslinfo2bypass_htable_data_free_cb, (void *)sslinfo2bypass_htable_expire_notify_cb, local_logger);
		sslinfo2bypass_htable = kni_create_htable((char*)"sslinfo2bypass_htable", &opt, local_logger);
		if(sslinfo2bypass_htable == NULL){
			KNI_LOG_ERROR(local_logger, "Failed at create sslinfo2bypass_htable");
			ret = -2;
			return ret;
		}
		g_kni_handle->sslinfo2bypass_htable = sslinfo2bypass_htable;
	}
	return ret;

}