コード例 #1
0
ファイル: analyzer_smtp.c プロジェクト: elfixit/pom-ng
static int analyzer_smtp_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct analyzer *analyzer = obj;
	struct proto_process_stack *s = &stack[stack_index - 1];
	if (!s->ce)
		return POM_ERR;

	struct analyzer_smtp_ce_priv *cpriv = conntrack_get_priv(s->ce, analyzer);

	if (!event_is_started(cpriv->evt_msg)) {
		pomlog(POMLOG_ERR "Payload received while data event not found");
		return POM_OK;
	}

	struct pload *pload_buff = event_get_priv(cpriv->evt_msg);

	if (!pload_buff) {
		pload_buff = pload_alloc(cpriv->evt_msg, 0);
		pload_set_type(pload_buff, ANALYZER_SMTP_RFC822_PLOAD_TYPE);
		if (!pload_buff)
			return POM_ERR;

		event_set_priv(cpriv->evt_msg, pload_buff);
	}

	struct proto_process_stack *pload_stack = &stack[stack_index];

	char *pload = pload_stack->pload;
	size_t plen = pload_stack->plen;


	// Look for the end of the "<CR><LF>.." sequence if any
	if (cpriv->dotdot_pos > 0){
		int i, found = 1;
		for (i = 0; i < ANALYZER_SMTP_DOTDOT_LEN - cpriv->dotdot_pos && i <= plen; i++) {
			if (*(char*)(pload + i) != ANALYZER_SMTP_DOTDOT[cpriv->dotdot_pos + i]) {
				found = 0;
				break;
			}
		}
		if (i >= ANALYZER_SMTP_DOTDOT_LEN - cpriv->dotdot_pos) {
			if (found && (i >= ANALYZER_SMTP_DOTDOT_LEN - cpriv->dotdot_pos)) {
				// Process up to the last dot
				size_t len = ANALYZER_SMTP_DOTDOT_LEN - cpriv->dotdot_pos;
				if (pload_append(pload_buff, pload, len - 1) != POM_OK)
					return POM_ERR;
				pload += len;
				plen -= len;

			}
			cpriv->dotdot_pos = 0;
		} else {
			cpriv->dotdot_pos += i;	
		}
	}

	while (plen) {
		char * dotdot = pom_strnstr(pload, ANALYZER_SMTP_DOTDOT, plen);

		if (!dotdot)
			break;

		size_t dotdot_len = dotdot - pload + ANALYZER_SMTP_DOTDOT_LEN;
		if (pload_append(pload_buff, pload, dotdot_len - 1) != POM_OK)
			return POM_ERR;
		pload = dotdot + ANALYZER_SMTP_DOTDOT_LEN;
		plen -= dotdot_len;

	}

	// Check for a possible partial dotdot at the end of the pload
	int i, found = 0;
	for (i = 1; (i < ANALYZER_SMTP_DOTDOT_LEN) && (i <= plen); i++) {
		if (!memcmp(pload + plen - i, ANALYZER_SMTP_DOTDOT, i)) {
			found = 1;
		}	break;
	}

	if (found)
		cpriv->dotdot_pos = i;

	// Add whatever remains
	if (plen && pload_append(pload_buff, pload, plen) != POM_OK)
		return POM_ERR;

	return POM_OK;
}
コード例 #2
0
static int analyzer_rtp_pload_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct analyzer *analyzer = obj;
	struct analyzer_rtp_priv *priv = analyzer->priv;

	struct proto_process_stack *pload_stack = &stack[stack_index];
	struct proto_process_stack *s = &stack[stack_index - 1];

	if (!s->ce)
		return POM_ERR;

	struct analyzer_rtp_ce_priv *cp = conntrack_get_priv(s->ce, obj);
	if (!cp) {
		cp = malloc(sizeof(struct analyzer_rtp_ce_priv));
		if (!cp) {
			pom_oom(sizeof(struct analyzer_rtp_ce_priv));
			return POM_ERR;
		}
		memset(cp, 0, sizeof(struct analyzer_rtp_ce_priv));

		if (conntrack_add_priv(s->ce, obj, cp, analyzer_rtp_ce_cleanup) != POM_OK)
			return POM_ERR;
	}

	int dir = s->direction;

	if (!cp->evt[dir]) {
		cp->evt[dir] = event_alloc(priv->evt_rtp_stream);
		if (!cp->evt[dir])
			return POM_ERR;

		struct data *evt_data = event_get_data(cp->evt[dir]);
		ptype_copy(evt_data[analyzer_rtp_stream_ssrc].value, s->pkt_info->fields_value[proto_rtp_field_ssrc]);
		data_set(evt_data[analyzer_rtp_stream_ssrc]);

		// For now we always assume RTP is over UDP or TCP
		if (stack_index > 2) {
			struct proto_process_stack *l4_stack = &stack[stack_index - 2];
			unsigned int i;
			for (i = 0; !data_is_set(evt_data[analyzer_rtp_stream_src_port]) || !data_is_set(evt_data[analyzer_rtp_stream_dst_port]); i++) {
				struct proto_reg_info *l4_info = proto_get_info(l4_stack->proto);
				char *name = l4_info->pkt_fields[i].name;
				if (!name)
					break;
				if (!data_is_set(evt_data[analyzer_rtp_stream_src_port]) && !strcmp(name, "sport")) {
					ptype_copy(evt_data[analyzer_rtp_stream_src_port].value, l4_stack->pkt_info->fields_value[i]);
					data_set(evt_data[analyzer_rtp_stream_src_port]);
				} else if (!data_is_set(evt_data[analyzer_rtp_stream_dst_port]) && !strcmp(name, "dport")) {
					ptype_copy(evt_data[analyzer_rtp_stream_dst_port].value, l4_stack->pkt_info->fields_value[i]);
					data_set(evt_data[analyzer_rtp_stream_dst_port]);
				}
			}

		}

		if (stack_index > 3) {
			struct proto_process_stack *l3_stack = &stack[stack_index - 3];
			unsigned int i;
			for (i = 0; !data_is_set(evt_data[analyzer_rtp_stream_src_addr]) || !data_is_set(evt_data[analyzer_rtp_stream_dst_addr]); i++) {
				struct proto_reg_info *l3_info = proto_get_info(l3_stack->proto);
				char *name = l3_info->pkt_fields[i].name;
				if (!name)
					break;
				if (!data_is_set(evt_data[analyzer_rtp_stream_src_addr]) && !strcmp(name, "src")) {
					evt_data[analyzer_rtp_stream_src_addr].value = ptype_alloc_from(l3_stack->pkt_info->fields_value[i]);
					if (evt_data[analyzer_rtp_stream_src_addr].value)
						data_set(evt_data[analyzer_rtp_stream_src_addr]);
				} else if (!data_is_set(evt_data[analyzer_rtp_stream_dst_addr]) && !strcmp(name, "dst")) {
					evt_data[analyzer_rtp_stream_dst_addr].value = ptype_alloc_from(l3_stack->pkt_info->fields_value[i]);
					if (evt_data[analyzer_rtp_stream_dst_addr].value)
						data_set(evt_data[analyzer_rtp_stream_dst_addr]);
				}
			}

		}

		struct proto *sess_proto = telephony_stream_info_get_sess_proto(s->ce);
		if (sess_proto) {
			struct proto_reg_info *proto_reg = proto_get_info(sess_proto);
			PTYPE_STRING_SETVAL(evt_data[analyzer_rtp_stream_sess_proto].value, proto_reg->name);
			data_set(evt_data[analyzer_rtp_stream_sess_proto]);
		}

		char *call_id = telephony_stream_info_get_call_id(s->ce);
		if (call_id) {
			PTYPE_STRING_SETVAL_P(evt_data[analyzer_rtp_stream_call_id].value, call_id);
			data_set(evt_data[analyzer_rtp_stream_call_id]);
		}

		if (event_process_begin(cp->evt[dir], stack, stack_index, p->ts) != POM_OK)
			return POM_ERR;
	}

	if (!cp->pload[dir]) {
		cp->pload[dir] = pload_alloc(cp->evt[dir], 0);
		if (!cp->pload[dir])
			return POM_ERR;

		struct telephony_codec_info info = { 0 };
		if (telephony_stream_info_get_codec(&info, stack, stack_index - 1) == POM_OK) {
			char *pload_type = telephony_codec_info_get_pload_type(&info);
			if (pload_type)
				pload_set_type(cp->pload[dir], pload_type);
		}
	}

	if (pload_append(cp->pload[dir], pload_stack->pload, pload_stack->plen) != POM_OK)
		return POM_ERR;

	return POM_OK;
}
コード例 #3
0
ファイル: analyzer_multipart.c プロジェクト: elfixit/pom-ng
static int analyzer_multipart_pload_write(void *obj, void *p, void *data, size_t len) {

	struct analyzer_multipart_pload_priv *priv = p;

	if (priv->state == analyzer_multipart_pload_state_end)
		return POM_OK;

	if (priv->state == analyzer_multipart_pload_state_error)
		return POM_ERR;

	unsigned int line_len, remaining_len = len;

	while (remaining_len > 0) {
	
		// Because of the NOTE in RFC 2046 section 5.1.1, line start at CR 

		void *cr = memchr(data + 1, '\r', remaining_len - 1);
		if (!cr || priv->last_line) {

			size_t add_len = remaining_len;
			if (cr)
				add_len = cr - data;

			size_t new_len = add_len + 1;
			if (priv->last_line)
				new_len += strlen(priv->last_line);
			if (priv->last_line_len < new_len) {
				char *new_last_line = realloc(priv->last_line, new_len);
				if (!new_last_line) {
					pom_oom(new_len);
					goto err;
				}
				if (!priv->last_line_len)
					new_last_line[0] = 0;
				priv->last_line_len = new_len;
				priv->last_line = new_last_line;
			}
			strncat(priv->last_line, data, add_len);
			priv->last_line[new_len - 1] = 0;

			if (!cr)
				break;

			// Process this line and continue to the next
			if (analyzer_multipart_pload_process_line(priv, priv->last_line, strlen(priv->last_line)) != POM_OK)
				goto err;

			// We need to process this part of the payload
			if (priv->state == analyzer_multipart_pload_state_content && priv->pload_start) {
				if (pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK)
					goto err;
			}

			priv->pload_start = NULL;
			priv->pload_end = NULL;
			
			free(priv->last_line);
			priv->last_line = NULL;
			priv->last_line_len = 0;
			data = cr;
			remaining_len -= add_len;
			
			continue;
		}

		line_len = cr - data;
		
		if (analyzer_multipart_pload_process_line(priv, data, line_len) != POM_OK)
			goto err;

		remaining_len -= line_len;
		data = cr;
	}

	if (priv->state == analyzer_multipart_pload_state_content && priv->pload_start) {
		if (pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK)
			goto err;
	}

	priv->pload_start = NULL;
	priv->pload_end = NULL;

	return POM_OK;

err:
	if (priv->pload) {
		pload_end(priv->pload);
		priv->pload = NULL;
	}

	priv->state = analyzer_multipart_pload_state_error;
	return POM_ERR;
}
コード例 #4
0
ファイル: analyzer_tftp.c プロジェクト: elfixit/pom-ng
static int analyzer_tftp_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct analyzer_tftp_priv *priv = obj;

	struct proto_process_stack *s = &stack[stack_index];
	struct proto_process_stack *s_prev = &stack[stack_index - 1];

	uint16_t opcode = *PTYPE_UINT16_GETVAL(s_prev->pkt_info->fields_value[proto_tftp_field_opcode]);

	// Get the session
	struct conntrack_session *session = conntrack_session_get(s_prev->ce);
	if (!session)
		return POM_ERR;

	struct analyzer_tftp_session_priv *spriv = conntrack_session_get_priv(session, obj);

	if (!spriv) {
		// Add session priv if it is not done yet
		spriv = malloc(sizeof(struct analyzer_tftp_session_priv));
		if (!spriv) {
			pom_oom(sizeof(struct analyzer_tftp_session_priv));
			goto err;
		}
		memset(spriv, 0, sizeof(struct analyzer_tftp_session_priv));

		if (conntrack_session_add_priv(session, obj, spriv, analyzer_tftp_session_priv_cleanup) != POM_OK) {
			free(spriv);
			goto err;
		}
	}

	void *pload = s->pload;
	uint32_t plen = s->plen;

	switch (opcode) {
		case tftp_rrq:
		case tftp_wrq: {

			if (plen < 3)
				return POM_OK; // Invalid packet

			// Find the filename
			// The below should always be valid as proto_tftp already checked this
			char *filename = pload; 
			char *mode = memchr(filename, 0, plen - 1) + 1;

			struct analyzer_tftp_file *fq = malloc(sizeof(struct analyzer_tftp_file));
			if (!fq) {
				pom_oom(sizeof(struct analyzer_tftp_file));
				goto err;
			}
			memset(fq, 0, sizeof(struct analyzer_tftp_file));

			// Get the port on which we expect this file
			// No need to check the IP as we got the session biding
			struct proto_process_stack *s_l4 = &stack[stack_index - 2];
			unsigned int i;
			for (i = 0; !fq->port ; i++) {
				struct proto_reg_info *pinfo = proto_get_info(s_l4->proto);
				char *name = pinfo->pkt_fields[i].name;
				if (!name) {
					pomlog(POMLOG_ERR "Source port not found in RRQ/WRQ packets");
					goto err;
				}
				if (!strcmp(name, "sport")) {
					fq->port = *PTYPE_UINT16_GETVAL(s_l4->pkt_info->fields_value[i]);
					break;
				}
			}

			fq->evt = event_alloc(priv->evt_file);
			if (!fq->evt) {
				free(fq);
				goto err;
			}
			struct data *evt_data = event_get_data(fq->evt);

			PTYPE_STRING_SETVAL(evt_data[analyzer_tftp_file_filename].value, filename);
			data_set(evt_data[analyzer_tftp_file_filename]);
			PTYPE_STRING_SETVAL(evt_data[analyzer_tftp_file_mode].value, mode);
			data_set(evt_data[analyzer_tftp_file_mode]);
			PTYPE_BOOL_SETVAL(evt_data[analyzer_tftp_file_write].value, opcode == tftp_wrq);
			data_set(evt_data[analyzer_tftp_file_write]);



			fq->next = spriv->files;
			if (fq->next)
				fq->next->prev = fq;
			spriv->files = fq;
			conntrack_session_unlock(session);

			event_process_begin(fq->evt, stack, stack_index, p->ts);

			break;
		}

		case tftp_data: {

			if (plen < sizeof(uint16_t))
				return POM_OK; // Invalid packet

			struct analyzer_tftp_file *f = conntrack_get_priv(s_prev->ce, obj);
			struct data *evt_data = NULL;

			if (!f) {
				// The file is not yet associated to this connection
				// Find it in the queue
				
				struct proto_process_stack *s_l4 = &stack[stack_index - 2];
				unsigned int i;
				uint16_t sport = 0, dport = 0;
				for (i = 0; !sport || !dport ; i++) {
					struct proto_reg_info *pinfo = proto_get_info(s_l4->proto);
					char *name = pinfo->pkt_fields[i].name;
					if (!name) {
						pomlog(POMLOG_ERR "Source port not found in data packets");
						goto err;
					}
					if (!strcmp(name, "sport"))
						sport = *PTYPE_UINT16_GETVAL(s_l4->pkt_info->fields_value[i]);

					if (!strcmp(name, "dport"))
						dport = *PTYPE_UINT16_GETVAL(s_l4->pkt_info->fields_value[i]);
				}

				// Find the file in the session list
				for (f = spriv->files; ; f = f->next) {
					evt_data = event_get_data(f->evt);
					if (*PTYPE_BOOL_GETVAL(evt_data[analyzer_tftp_file_write].value)) {
						if (f->port == sport)
							break;
					} else {
						if (f->port == dport)
							break;
					}
				}

				if (!f) {
					pomlog(POMLOG_DEBUG "File not found in queued file request.");
					conntrack_session_unlock(session);
					return POM_OK;
				}
				
				// Remove the file from the queue and assign it to the conntrack
				if (f->prev)
					f->prev->next = f->next;
				else
					spriv->files = f->next;
				if (f->next)
					f->next->prev = f->prev;
				
				f->prev = NULL;
				f->next = NULL;

				// Create the payload buffer
				f->pload = pload_alloc(f->evt, PLOAD_FLAG_NEED_MAGIC);
				if (!f->pload)
					goto err;

				conntrack_add_priv(s_prev->ce, obj, f, analyzer_tftp_conntrack_priv_cleanup);
			} else {
				evt_data = event_get_data(f->evt);
			}
			conntrack_session_unlock(session);
		
			if (!f->pload) {
				pomlog(POMLOG_DEBUG "Ignoring extra packet");
				return POM_OK;
			}

			// Discard the block ID
			pload += sizeof(uint16_t);
			plen -= sizeof(uint16_t);

			if (pload_append(f->pload, pload, plen) != POM_OK)
				goto err;

			uint32_t *size = PTYPE_UINT32_GETVAL(evt_data[analyzer_tftp_file_size].value);
			*size += plen;

			if (plen < ANALYZER_TFTP_BLK_SIZE) {
				// Got last packet !
				data_set(evt_data[analyzer_tftp_file_size]);
				
				int res = pload_end(f->pload);
				res += event_process_end(f->evt);
				f->evt = NULL;	
				f->pload = NULL;
				if (res)
					goto err;
			}

			break;
		}

		case tftp_error: {
			conntrack_session_unlock(session);

			struct analyzer_tftp_file *f = conntrack_get_priv(s_prev->ce, obj);
			if (f && f->pload) {
				int res = pload_end(f->pload);
				res += event_process_end(f->evt);
				f->pload = NULL;
				f->evt = NULL;
				if (res)
					goto err;
			}
			break;
		}

		default:
			conntrack_session_unlock(session);
			break;
	}
	
	return POM_OK;

err:
	conntrack_session_unlock(session);
	return POM_ERR;
}
コード例 #5
0
ファイル: analyzer_multipart.c プロジェクト: elfixit/pom-ng
static int analyzer_multipart_pload_process_line(struct analyzer_multipart_pload_priv *priv, char *line, size_t len) {

	char *my_line = line;
	size_t my_len = len;
	while (my_len > 0 && (*my_line == '\r' || *my_line == '\n')) {
		my_line++;
		my_len--;
	}

	if (my_len >= priv->boundary_len && !memcmp(my_line, priv->boundary, priv->boundary_len)) {
		// Process the rest of the payload

		if (priv->pload) {
			if (priv->pload_start && pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK)
				return POM_ERR;

			pload_end(priv->pload);
			priv->pload = NULL;
		}
		priv->pload_start = NULL;
		priv->pload_end = NULL;

		if (my_len >= priv->boundary_len + 2 && my_line[priv->boundary_len] == '-' && my_line[priv->boundary_len + 1] == '-')
			priv->state = analyzer_multipart_pload_state_end;
		else
			priv->state = analyzer_multipart_pload_state_header;
	
		return POM_OK;
	} else if (priv->state == analyzer_multipart_pload_state_header) {

		if (!my_len) {
			// End of the headers
			priv->state = analyzer_multipart_pload_state_content;
			return POM_OK;
		}

		if (mime_header_parse(&priv->pload_data, my_line, my_len) != POM_OK) {
			priv->state = analyzer_multipart_pload_state_error;
			return POM_OK;
		}


	} else if (priv->state == analyzer_multipart_pload_state_content) {

		if (!priv->pload) {
			struct event *rel_event = pload_get_related_event(priv->parent_pload);
			priv->pload = pload_alloc(rel_event, 0);
			if (!priv->pload)
				return POM_ERR;
			
			pload_set_parent(priv->pload, priv->parent_pload);

			// Parse the headers
			while (priv->pload_data.items) {
				struct data_item *itm = priv->pload_data.items;
				priv->pload_data.items = itm->next;

				if (!strcasecmp(itm->key, "Content-Type")) {
					pload_set_mime_type(priv->pload, PTYPE_STRING_GETVAL(itm->value));
				} else if (!strcasecmp(itm->key, "Content-Transfer-Encoding")) {
					pload_set_encoding(priv->pload, PTYPE_STRING_GETVAL(itm->value));
				}
				free(itm->key);
				ptype_cleanup(itm->value);
				free(itm);
			}

			// If it's the begining, discard CRLF
			line = my_line;
			len = my_len;
		}

		if (priv->pload_end != line) {
			// Process the payload we had and queue the this one
			if (priv->pload_start && pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK)
				return POM_ERR;
			priv->pload_start = line;
			priv->pload_end = line + len;
		} else {
			priv->pload_end += len;
		}
	}

	return POM_OK;
}