Exemplo n.º 1
0
static int proto_ppp_pap_init(struct proto *proto, struct registry_instance *i) {

	if (proto_number_register("ppp", 0xc023, proto) != POM_OK)
		return POM_ERR;

	struct proto_ppp_pap_priv *priv = malloc(sizeof(struct proto_ppp_pap_priv));
	if (!priv) {
		pom_oom(sizeof(struct proto_ppp_pap_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct proto_ppp_pap_priv));
	proto_set_priv(proto, priv);


	static struct data_item_reg evt_request_data_items[PROTO_PPP_PAP_EVT_REQUEST_DATA_COUNT] = { { 0 } };
	evt_request_data_items[evt_ppp_pap_request_code].name = "code";
	evt_request_data_items[evt_ppp_pap_request_code].value_type = ptype_get_type("uint8");
	evt_request_data_items[evt_ppp_pap_request_identifier].name = "identifier";
	evt_request_data_items[evt_ppp_pap_request_identifier].value_type = ptype_get_type("uint8");
	evt_request_data_items[evt_ppp_pap_request_peer_id].name = "peer_id";
	evt_request_data_items[evt_ppp_pap_request_peer_id].value_type = ptype_get_type("string");
	evt_request_data_items[evt_ppp_pap_request_password].name = "password";
	evt_request_data_items[evt_ppp_pap_request_password].value_type = ptype_get_type("string");

	static struct data_reg evt_ppp_pap_request_data = {
		.items = evt_request_data_items,
		.data_count = PROTO_PPP_PAP_EVT_REQUEST_DATA_COUNT
	};

	static struct event_reg_info proto_ppp_pap_request = { 0 };
	proto_ppp_pap_request.source_name = "proto_ppp_pap";
	proto_ppp_pap_request.source_obj = priv;
	proto_ppp_pap_request.name = "ppp_pap_request";
	proto_ppp_pap_request.description = "PPP PAP Authentication request";
	proto_ppp_pap_request.data_reg = &evt_ppp_pap_request_data;

	priv->evt_request = event_register(&proto_ppp_pap_request);
	if (!priv->evt_request)
		goto err;


	static struct data_item_reg evt_ack_nack_data_items[PROTO_PPP_PAP_EVT_ACK_NACK_DATA_COUNT] = { { 0 } };
	evt_ack_nack_data_items[evt_ppp_pap_ack_nack_code].name = "code";
	evt_ack_nack_data_items[evt_ppp_pap_ack_nack_code].value_type = ptype_get_type("uint8");
	evt_ack_nack_data_items[evt_ppp_pap_ack_nack_identifier].name = "identifier";
	evt_ack_nack_data_items[evt_ppp_pap_ack_nack_identifier].value_type = ptype_get_type("uint8");
	evt_ack_nack_data_items[evt_ppp_pap_ack_nack_message].name = "message";
	evt_ack_nack_data_items[evt_ppp_pap_ack_nack_message].value_type = ptype_get_type("string");

	static struct data_reg evt_ppp_pap_ack_nack_data = {
		.items = evt_ack_nack_data_items,
		.data_count = PROTO_PPP_PAP_EVT_ACK_NACK_DATA_COUNT
	};

	static struct event_reg_info proto_ppp_pap_ack_nack = { 0 };
	proto_ppp_pap_ack_nack.source_name = "proto_ppp_pap";
	proto_ppp_pap_ack_nack.source_obj = priv;
	proto_ppp_pap_ack_nack.name = "ppp_pap_ack_nack";
	proto_ppp_pap_ack_nack.description = "PPP-PAP ACK/NACK";
	proto_ppp_pap_ack_nack.data_reg = &evt_ppp_pap_ack_nack_data;

	priv->evt_ack_nack = event_register(&proto_ppp_pap_ack_nack);
	if (!priv->evt_ack_nack)
		goto err;

	priv->p_auth_timeout = ptype_alloc_unit("uint32", "seconds");
	if (!priv->p_auth_timeout)
		goto err;

	struct registry_param *p = registry_new_param("auth_timeout", "60", priv->p_auth_timeout, "Authentication timeout", 0);
	if (proto_add_param(proto, p) != POM_OK) {
		registry_cleanup_param(p);
		goto err;
	}

	return POM_OK;

err:
	proto_ppp_pap_cleanup(priv);
	return POM_ERR;

}
Exemplo n.º 2
0
int registry_config_save(char *config_name) {

	if (strlen(config_name) >= REGISTRY_CONFIG_NAME_MAX) {
		pomlog(POMLOG_ERR "Configuration name too long, max %u characters.", REGISTRY_CONFIG_NAME_MAX);
		return POM_ERR;
	}

	struct dataset_query *dsq_config_list = NULL, *dsq_config = NULL;
	
	struct datastore *sys_dstore = system_datastore();
	if (!sys_dstore)
		return POM_ERR;

	struct datastore_connection *dc = datastore_connection_new(sys_dstore);
	if (!dc)
		return POM_ERR;

	dsq_config_list = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG_LIST, registry_config_list_dataset_template, dc);
	if (!dsq_config_list)
		goto err;

	if (datastore_dataset_query_set_string_condition(dsq_config_list, 0, PTYPE_OP_EQ, config_name) != POM_OK)
		goto err;

	dsq_config = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG, registry_config_dataset_template, dc);
	if (!dsq_config)
		goto err;

	if (datastore_transaction_begin(dc) != POM_OK)
		goto err;

	// Find out if we already have a config by that name
	int res = datastore_dataset_read_single(dsq_config_list);
	if (res == DATASET_QUERY_MORE) {

		// Delete existing stuff about this config
		if (datastore_dataset_query_set_uint64_condition(dsq_config, 0, PTYPE_OP_EQ, dsq_config_list->data_id) != POM_OK)
			goto err;

		if (datastore_dataset_delete(dsq_config_list) != DATASET_QUERY_OK)
			goto err;

		if (datastore_dataset_delete(dsq_config) != DATASET_QUERY_OK)
			goto err;
	}

	if (res < 0)
		goto err;

	// Add the config to the config list
	PTYPE_STRING_SETVAL(dsq_config_list->values[0].value, config_name);
	PTYPE_TIMESTAMP_SETVAL(dsq_config_list->values[1].value, pom_gettimeofday());

	if (datastore_dataset_write(dsq_config_list) != DATASET_QUERY_OK)
		goto err;



	PTYPE_UINT64_SETVAL(dsq_config->values[0].value, dsq_config_list->data_id);

	registry_lock();
	struct registry_class *cls;

	// Browse each class
	for (cls = registry_head; cls; cls = cls->next) {

		// Browse each instance of the class
		struct registry_instance *inst;
		for (inst = cls->instances; inst; inst = inst->next) {
			
			// Don't add the instance if it's not added by the user
			
			if (cls->instance_add) {

				// The system datastore will always exist
				if (inst == sys_dstore->reg_instance)
					continue;

				char *buff = malloc(strlen(cls->name) + 1 + strlen(inst->name) + 1);
				if (!buff) {
					pom_oom(strlen(cls->name) + 1 + strlen(inst->name) + 1);
					goto err_locked;
				}

				strcpy(buff, cls->name);
				strcat(buff, ".");
				strcat(buff, inst->name);
				PTYPE_STRING_SETVAL_P(dsq_config->values[1].value, buff);

				struct registry_param *p;
				for (p = inst->params; p && strcmp(p->name, "type"); p = p->next);

				if (p) {
					dsq_config->values[2].is_null = 0;
					char *type = PTYPE_STRING_GETVAL(p->value);
					PTYPE_STRING_SETVAL(dsq_config->values[2].value, type);
				} else {
					dsq_config->values[2].is_null = 1;
				}

				PTYPE_UINT8_SETVAL(dsq_config->values[3].value, registry_config_instance);

				if (datastore_dataset_write(dsq_config) != DATASET_QUERY_OK)
					goto err_locked;

			}

			// Browse the parametrers and add the non default ones

			struct registry_param *param;
			for (param = inst->params; param; param = param->next) {

				// Check if the parameter value is not the default one anymore
				if (param->default_value) {
					struct ptype *defval = ptype_alloc_from(param->value);
					if (!defval)
						goto err_locked;

					if (ptype_parse_val(defval, param->default_value) != POM_OK) {
						pomlog(POMLOG_ERR "Unable to parse default value !");
						ptype_cleanup(defval);
						goto err_locked;
					}

					if (ptype_compare_val(PTYPE_OP_EQ, param->value, defval)) {
						// Param still has the default value, do nothing
						ptype_cleanup(defval);
						continue;
					}

					ptype_cleanup(defval);
				}

				char *buff = malloc(strlen(cls->name) + 1 + strlen(inst->name) + 1 + strlen(param->name) + 1);
				if (!buff) {
					pom_oom(strlen(cls->name) + 1 + strlen(inst->name) + 1 + strlen(param->name) + 1);
					goto err_locked;
				}
				strcpy(buff, cls->name);
				strcat(buff, ".");
				strcat(buff, inst->name);
				strcat(buff, ".");
				strcat(buff, param->name);
				PTYPE_STRING_SETVAL_P(dsq_config->values[1].value, buff);

				char *value = ptype_print_val_alloc(param->value, NULL);
				if (!value)
					goto err_locked;
				
				dsq_config->values[2].is_null = 0;
				PTYPE_STRING_SETVAL_P(dsq_config->values[2].value, value);

				PTYPE_UINT8_SETVAL(dsq_config->values[3].value, registry_config_instance_param);

				if (datastore_dataset_write(dsq_config) != DATASET_QUERY_OK)
					goto err_locked;
			}
		
		}

	}

	registry_config_serial++;
	registry_serial++;
	xmlrcpcmd_serial_inc();

	registry_unlock();

	if (datastore_transaction_commit(dc) != POM_OK)
		goto err;

	datastore_dataset_query_cleanup(dsq_config_list);
	datastore_dataset_query_cleanup(dsq_config);
	
	datastore_connection_release(dc);

	pomlog("Registry configuration saved as \"%s\"", config_name);

	return POM_OK;

err_locked:
	registry_unlock();

err:
	if (dsq_config_list)
		datastore_dataset_query_cleanup(dsq_config_list);

	if (dsq_config)
		datastore_dataset_query_cleanup(dsq_config);

	if (dc) {
		datastore_transaction_rollback(dc);
		datastore_connection_release(dc);
	}

	return POM_ERR;

}
Exemplo n.º 3
0
Arquivo: core.c Projeto: k0a1a/pom-ng
int core_init(unsigned int num_threads) {

	core_registry_class = registry_add_class(CORE_REGISTRY);
	if (!core_registry_class)
		return POM_ERR;

	perf_pkt_queue = registry_class_add_perf(core_registry_class, "pkt_queue", registry_perf_type_gauge, "Number of packets in the queue waiting to be processed", "pkts");
	perf_thread_active = registry_class_add_perf(core_registry_class, "active_thread", registry_perf_type_gauge, "Number of active threads", "threads");

	if (!perf_pkt_queue || !perf_thread_active)
		return POM_OK;

	core_param_dump_pkt = ptype_alloc("bool");
	if (!core_param_dump_pkt)
		return POM_ERR;

	core_param_offline_dns = ptype_alloc("bool");
	if (!core_param_offline_dns) {
		ptype_cleanup(core_param_dump_pkt);
		core_param_dump_pkt = NULL;
		return POM_ERR;
	}

	core_param_reset_perf_on_restart = ptype_alloc("bool");
	if (!core_param_reset_perf_on_restart) {
		ptype_cleanup(core_param_dump_pkt);
		core_param_dump_pkt = NULL;
		ptype_cleanup(core_param_offline_dns);
		core_param_offline_dns = NULL;
		return POM_ERR;
	}

	struct registry_param *param = registry_new_param("dump_pkt", "no", core_param_dump_pkt, "Dump packets to logs", REGISTRY_PARAM_FLAG_CLEANUP_VAL);
	if (registry_class_add_param(core_registry_class, param) != POM_OK)
		goto err;

	param = registry_new_param("offline_dns", "yes", core_param_offline_dns, "Enable offline DNS resolver", REGISTRY_PARAM_FLAG_CLEANUP_VAL);
	if (registry_class_add_param(core_registry_class, param) != POM_OK)
		goto err;

	param = registry_new_param("reset_perf_on_restart", "no", core_param_reset_perf_on_restart, "Reset performances when core restarts", REGISTRY_PARAM_FLAG_CLEANUP_VAL);
	if (registry_class_add_param(core_registry_class, param) != POM_OK)
		goto err;
	
	param = NULL;

	// Start the processing threads
	unsigned int num_cpu = sysconf(_SC_NPROCESSORS_ONLN) - 1;
	if (num_cpu < 1) {
		pomlog(POMLOG_WARN "Could not find the number of CPU, assuming %u", CORE_PROCESS_THREAD_DEFAULT);
		num_cpu = CORE_PROCESS_THREAD_DEFAULT;
	}

	if (num_threads < 1)
		num_threads = num_cpu;

	if (num_threads > num_cpu)
		pomlog(POMLOG_WARN "WARNING : Running more processing threads than available CPU is discouraged as it will cause issues by creating higher latencies and eventually dropping packets !!! You have been warned !");

	if (num_threads > CORE_PROCESS_THREAD_MAX)
		num_threads = CORE_PROCESS_THREAD_MAX;

	core_num_threads = num_threads;	
	pomlog(POMLOG_INFO "Starting %u processing thread(s)", core_num_threads);

	core_run = 1;

	memset(core_processing_threads, 0, sizeof(struct core_processing_thread*) * CORE_PROCESS_THREAD_MAX);

	unsigned int i;

	for (i = 0; i < core_num_threads; i++) {
		struct core_processing_thread *tmp = malloc(sizeof(struct core_processing_thread));
		if (!tmp) {
			pom_oom(sizeof(struct core_processing_thread));
			goto err;
		}
		memset(tmp, 0, sizeof(struct core_processing_thread));

		tmp->thread_id = i;

		int res = pthread_mutex_init(&tmp->pkt_queue_lock, NULL);
		if (res) {
			pomlog(POMLOG_ERR "Error while initializing a thread pkt_queue lock : %s", pom_strerror(res));
			free(tmp);
			goto err;
		}

		res = pthread_cond_init(&tmp->pkt_queue_cond, NULL);
		if (res) {
			pomlog(POMLOG_ERR "Error while initializing a thread pkt_queue condition : %s", pom_strerror(res));
			pthread_mutex_destroy(&tmp->pkt_queue_lock);
			free(tmp);
			goto err;
		}


		if (pthread_create(&tmp->thread, NULL, core_processing_thread_func, tmp)) {
			pomlog(POMLOG_ERR "Error while creating a new processing thread : %s", pom_strerror(errno));
			pthread_mutex_destroy(&tmp->pkt_queue_lock);
			pthread_cond_destroy(&tmp->pkt_queue_cond);
			free(tmp);
			goto err;
		}


		core_processing_threads[i] = tmp;
	}

	return POM_OK;

err:

	if (param)
		registry_cleanup_param(param);

	core_cleanup(0);
	return POM_ERR;

}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
int registry_config_load(char *config_name) {

	struct dataset_query *dsq_config_list = NULL, *dsq_config = NULL;
	
	struct datastore *sys_dstore = system_datastore();
	if (!sys_dstore) {
		pomlog(POMLOG_ERR "No system datastore declared");
		return POM_ERR;
	}


	// Find what is the id corresponding to the name given if any
	dsq_config_list = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG_LIST, registry_config_list_dataset_template, NULL);
	if (!dsq_config_list)
		goto err;

	if (datastore_dataset_query_set_string_condition(dsq_config_list, 0, PTYPE_OP_EQ, config_name) != POM_OK)
		goto err;

	int res = datastore_dataset_read_single(dsq_config_list);

	if (res < 0)
		goto err;

	if (res == DATASET_QUERY_OK) {
		pomlog(POMLOG_ERR "Configuration \"%s\" not found in the database", config_name);
		goto err;
	}

	uint64_t config_id = dsq_config_list->data_id;

	datastore_dataset_query_cleanup(dsq_config_list);
	dsq_config_list = NULL;

	// Fetch the config
	dsq_config = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG, registry_config_dataset_template, NULL);
	if (!dsq_config)
		goto err;

	if (datastore_dataset_query_set_uint64_condition(dsq_config, 0, PTYPE_OP_EQ, config_id) != POM_OK)
		goto err;

	// Fetch the config in a convenient way
	if (datastore_dataset_query_set_order(dsq_config, 3, DATASET_READ_ORDER_ASC) != POM_OK)
		goto err;

	registry_lock();

	// Reset the registry
	if (registry_config_reset() != POM_OK)
		goto err_locked;


	while ((res = datastore_dataset_read(dsq_config)) != DATASET_QUERY_OK) {
		if (res < 0)
			goto err_locked;

		if (dsq_config->values[1].is_null || dsq_config->values[3].is_null) {
			pomlog(POMLOG_ERR "Got NULL values while they were not supposed to be !");
			goto err_locked;
		}
		enum registry_config_entry_types type = *PTYPE_UINT8_GETVAL(dsq_config->values[3].value);
		char *entry = PTYPE_STRING_GETVAL(dsq_config->values[1].value);
		char *value = NULL;
		if (!dsq_config->values[2].is_null)
			value = PTYPE_STRING_GETVAL(dsq_config->values[2].value);

		// Parse the entry
		char *name1 = strdup(entry);
		if (!name1) {
			pom_oom(strlen(entry) + 1);
			goto err_locked;
		}
		char *name2 = strchr(name1, '.');
		if (!name2) {
			pomlog(POMLOG_ERR "Unparseable entry name \"%s\"", entry);
			free(name1);
			goto err_locked;
		}
		*name2 = 0;
		name2++;

		char *name3 = strchr(name2, '.');
		if (name3) {
			*name3 = 0;
			name3++;
		}

		switch (type) {

			case registry_config_instance: {

				if (!value) {
					pomlog(POMLOG_WARN "Instance type not provided for entry %s, skipping", entry);
					break;
				}

				struct registry_class *cls = registry_find_class(name1);
				if (!cls) {
					pomlog(POMLOG_WARN "Cannot add instance %s to class %s as this class doesn't exists. skipping", name2, name1);
					break;
				}

				struct registry_instance *inst;
				for (inst = cls->instances; inst && strcmp(inst->name, name2); inst = inst->next);
				if (inst) {
					pomlog(POMLOG_WARN "Cannot add instance %s as it's already in the registry, skipping", entry);
					break;
				}

				if (!cls->instance_add) {
					pomlog(POMLOG_WARN "Cannot add instances to class %s as it doesn't support it. skipping", name1);
					break;
				}

				if (cls->instance_add(value, name2) != POM_OK) {
					pomlog(POMLOG_WARN "Unable to add instance %s of type %s, skipping", entry, value);
					break;
				}

				break;

			}

			case registry_config_instance_param: {

				if (!value) {
					pomlog(POMLOG_WARN "Parameter value not provided for entry %s, skipping", entry);
					break;
				}

				if (!name3) {
					pomlog(POMLOG_WARN "Parameter name not provided for entry %s, skipping", entry);
					break;
				}

				struct registry_instance *inst = registry_find_instance(name1, name2);
				if (!inst) {
					pomlog(POMLOG_WARN "Cannot find instance %s.%s to set parameter, skipping", name1, name2);
					break;
				}


				if (!strcmp(name3, "uid")) {
					// Special handling for uids
					if (registry_uid_assign(inst, value) != POM_OK) {
						pomlog(POMLOG_WARN "Error while setting the uid, skipping");
						break;
					}

				} else if (!strcmp(name3, "running")) {
					// For now don't do anything for running

				} else {
					registry_set_param(inst, name3, value);
				}

				break;
			}
				
			
			default:
				pomlog(POMLOG_WARN "Unhandled configuration entry type %u for item %s", entry);

		}

		free(name1);
		

	}

	registry_classes_serial_inc();
	registry_unlock();

	datastore_dataset_query_cleanup(dsq_config);

	pomlog("Registry configuration \"%s\" loaded", config_name);

	return POM_OK;

err_locked:
	registry_unlock();
err:

	if (dsq_config_list)
		datastore_dataset_query_cleanup(dsq_config_list);

	if (dsq_config)
		datastore_dataset_query_cleanup(dsq_config);

	return POM_ERR;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
int analyzer_ppp_pap_init(struct analyzer *analyzer) {


	struct analyzer_ppp_pap_priv *priv = malloc(sizeof(struct analyzer_ppp_pap_priv));
	if (!priv) {
		pom_oom(sizeof(struct analyzer_ppp_pap_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct analyzer_ppp_pap_priv));
	analyzer->priv = priv;

	priv->evt_request = event_find("ppp_pap_request");
	priv->evt_ack_nack = event_find("ppp_pap_ack_nack");
	if (!priv->evt_request || !priv->evt_ack_nack)
		goto err;

	static struct data_item_reg evt_auth_data_items[ANALYZER_PPP_PAP_AUTH_DATA_COUNT] = { { 0 } };

	evt_auth_data_items[analyzer_ppp_pap_auth_client].name = "client";
	evt_auth_data_items[analyzer_ppp_pap_auth_client].flags = DATA_REG_FLAG_NO_ALLOC;

	evt_auth_data_items[analyzer_ppp_pap_auth_server].name = "server";
	evt_auth_data_items[analyzer_ppp_pap_auth_server].flags = DATA_REG_FLAG_NO_ALLOC;

	evt_auth_data_items[analyzer_ppp_pap_auth_top_proto].name = "top_proto";
	evt_auth_data_items[analyzer_ppp_pap_auth_top_proto].value_type = ptype_get_type("string");

	evt_auth_data_items[analyzer_ppp_pap_auth_vlan].name = "vlan";
	evt_auth_data_items[analyzer_ppp_pap_auth_vlan].flags = DATA_REG_FLAG_NO_ALLOC;
	
	evt_auth_data_items[analyzer_ppp_pap_auth_identifier].name = "identifier";
	evt_auth_data_items[analyzer_ppp_pap_auth_identifier].value_type = ptype_get_type("uint8");

	evt_auth_data_items[analyzer_ppp_pap_auth_success].name = "success";
	evt_auth_data_items[analyzer_ppp_pap_auth_success].value_type = ptype_get_type("bool");

	evt_auth_data_items[analyzer_ppp_pap_auth_peer_id].name = "peer_id";
	evt_auth_data_items[analyzer_ppp_pap_auth_peer_id].value_type = ptype_get_type("string");

	evt_auth_data_items[analyzer_ppp_pap_auth_password].name = "password";
	evt_auth_data_items[analyzer_ppp_pap_auth_password].value_type = ptype_get_type("string");

	static struct data_reg evt_auth_data = {
		.items = evt_auth_data_items,
		.data_count = ANALYZER_PPP_PAP_AUTH_DATA_COUNT
	};

	static struct event_reg_info analyzer_ppp_pap_evt_auth = { 0 };
	analyzer_ppp_pap_evt_auth.source_name = "analyzer_ppp_pap";
	analyzer_ppp_pap_evt_auth.source_obj = analyzer;
	analyzer_ppp_pap_evt_auth.name = "ppp_pap_auth";
	analyzer_ppp_pap_evt_auth.description = "PPP PAP MD5 authentication";
	analyzer_ppp_pap_evt_auth.data_reg = &evt_auth_data;
	analyzer_ppp_pap_evt_auth.listeners_notify = analyzer_ppp_pap_event_listeners_notify;

	priv->evt_auth = event_register(&analyzer_ppp_pap_evt_auth);
	if (!priv->evt_auth)
		goto err;

	return POM_OK;

err:
	analyzer_ppp_pap_cleanup(analyzer);
	return POM_ERR;
}
Exemplo n.º 8
0
static int analyzer_docsis_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

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

	struct proto_process_stack *s = &stack[stack_index];

	uint8_t *type = PTYPE_UINT8_GETVAL(s->pkt_info->fields_value[proto_docsis_mgmt_field_type]);

	char *mac_dst = PTYPE_MAC_GETADDR(s->pkt_info->fields_value[proto_docsis_mgmt_field_dst]);

	// FIXME : improve this filtering at the source
	// Filter some useless messages we don't care about
	
	if (*type == MMT_UCD2 || *type == MMT_UCD3 || *type == MMT_MDD)
		return POM_OK;

	if (*type != MMT_RNG_RSP) {
		pomlog(POMLOG_DEBUG "Unhandled DOCSIS MGMT message type %u for destination mac %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", *type, mac_dst[0], mac_dst[1], mac_dst[2], mac_dst[3], mac_dst[4], mac_dst[5]);
		return POM_OK;
	}

	// Use the last bits for the modem ID
	uint16_t id = ntohs(*(uint16_t*) (mac_dst + 4)) & ANALYZER_DOCSIS_CM_MASK;

	pom_mutex_lock(&priv->lock);

	struct analyzer_docsis_cm *cm;
	for (cm = priv->cms[id]; cm; cm = cm->next) {
		if (!memcmp(cm->mac, mac_dst, sizeof(cm->mac)))
			break;
	}

	if (!cm) {
		// Cable modem not found !
		cm = malloc(sizeof(struct analyzer_docsis_cm));
		if (!cm) {
			pom_mutex_unlock(&priv->lock);
			pom_oom(sizeof(struct analyzer_docsis_cm));
			return POM_ERR;
		}
		memset(cm, 0, sizeof(struct analyzer_docsis_cm));

		cm->t = timer_alloc(cm, analyzer_docsis_cm_timeout);
		if (!cm->t) {
			pom_mutex_unlock(&priv->lock);
			free(cm);
			return POM_ERR;
		}
	
		cm->analyzer = analyzer;
		memcpy(cm->mac, mac_dst, sizeof(cm->mac));
		cm->t4_multiplier = 1;

		cm->next = priv->cms[id];
		if (cm->next)
			cm->next->prev = cm;

		priv->cms[id] = cm;

		// Announce the new CM
		if (event_has_listener(priv->evt_cm_new)) {
			struct event *evt = event_alloc(priv->evt_cm_new);
			if (!evt) {
				pom_mutex_unlock(&priv->lock);
				return POM_ERR;
			}

			struct data *evt_data = event_get_data(evt);
			PTYPE_MAC_SETADDR(evt_data[analyzer_docsis_cm_new_mac].value, cm->mac);
			data_set(evt_data[analyzer_docsis_cm_new_mac]);
			PTYPE_STRING_SETVAL(evt_data[analyzer_docsis_cm_new_input].value, p->input->name);
			data_set(evt_data[analyzer_docsis_cm_new_input]);

			if (event_process(evt, stack, stack_index, p->ts) != POM_OK) {
				pom_mutex_unlock(&priv->lock);
				return POM_ERR;
			}
		}
	}


	switch (*type) {

		case MMT_RNG_RSP:
			analyzer_docsis_pkt_parse_rng_rsp(priv, cm, p, stack, stack_index);
			break;

		// FIXME If ranging_status is 0 and we receive another msg, probably it's actually registered
		// and we need to call analyzer_docsis_reg_status_update();

	}

	timer_queue_now(cm->t, T4_TIMEOUT * cm->t4_multiplier, p->ts);

	pom_mutex_unlock(&priv->lock);

	return POM_OK;
}
Exemplo n.º 9
0
static int analyzer_docsis_init(struct analyzer *analyzer) {

	struct analyzer_docsis_priv *priv = malloc(sizeof(struct analyzer_docsis_priv));
	if (!priv) {
		pom_oom(sizeof(struct analyzer_docsis_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct analyzer_docsis_priv));

	analyzer->priv = priv;

	if (pthread_mutex_init(&priv->lock, NULL)) {
		pomlog(POMLOG_ERR "Error while initializing table lock : %s", pom_strerror(errno));
		free(priv);
		return POM_ERR;
	}

	static struct data_item_reg evt_cm_new_data_items[ANALYZER_DOCSIS_EVT_CM_NEW_DATA_COUNT] = { { 0 } };
	evt_cm_new_data_items[analyzer_docsis_cm_new_mac].name = "mac",
	evt_cm_new_data_items[analyzer_docsis_cm_new_mac].value_type = ptype_get_type("mac");
	evt_cm_new_data_items[analyzer_docsis_cm_new_input].name = "input",
	evt_cm_new_data_items[analyzer_docsis_cm_new_input].value_type = ptype_get_type("string");

	static struct data_reg evt_cm_new_data = {
		.items = evt_cm_new_data_items,
		.data_count = ANALYZER_DOCSIS_EVT_CM_NEW_DATA_COUNT
	};

	static struct event_reg_info analyzer_docsis_evt_cm_new = { 0 };
	analyzer_docsis_evt_cm_new.source_name = "analyzer_docsis";
	analyzer_docsis_evt_cm_new.source_obj = analyzer;
	analyzer_docsis_evt_cm_new.name = "docsis_cm_new";
	analyzer_docsis_evt_cm_new.description = "New cable modem found";
	analyzer_docsis_evt_cm_new.data_reg = &evt_cm_new_data;
	analyzer_docsis_evt_cm_new.listeners_notify = analyzer_docsis_event_listeners_notify;

	priv->evt_cm_new = event_register(&analyzer_docsis_evt_cm_new);
	if (!priv->evt_cm_new)
		goto err;

	static struct data_item_reg evt_cm_reg_status_data_items[ANALYZER_DOCSIS_EVT_CM_REG_STATUS_DATA_COUNT] = { { 0 } };
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_old].name = "old_status",
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_old].value_type = ptype_get_type("uint8");
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_new].name = "new_status",
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_new].value_type = ptype_get_type("uint8");
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_mac].name = "mac";
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_mac].value_type = ptype_get_type("mac");
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_timeout].name = "timeout",
	evt_cm_reg_status_data_items[analyzer_docsis_cm_reg_status_timeout].value_type = ptype_get_type("uint8");

	static struct data_reg evt_cm_reg_status_data = {
		.items = evt_cm_reg_status_data_items,
		.data_count = ANALYZER_DOCSIS_EVT_CM_REG_STATUS_DATA_COUNT
	};

	static struct event_reg_info analyzer_docsis_evt_cm_reg_status = { 0 };
	analyzer_docsis_evt_cm_reg_status.source_name = "analyzer_docsis";
	analyzer_docsis_evt_cm_reg_status.source_obj = analyzer;
	analyzer_docsis_evt_cm_reg_status.name = "docsis_cm_reg_status";
	analyzer_docsis_evt_cm_reg_status.description = "Cable modem registration status changed";
	analyzer_docsis_evt_cm_reg_status.data_reg = &evt_cm_reg_status_data;
	analyzer_docsis_evt_cm_reg_status.listeners_notify = analyzer_docsis_event_listeners_notify;

	priv->evt_cm_reg_status = event_register(&analyzer_docsis_evt_cm_reg_status);
	if (!priv->evt_cm_reg_status)
		goto err;

	return POM_OK;

err:
	analyzer_docsis_cleanup(analyzer);

	return POM_ERR;
}
Exemplo n.º 10
0
static int proto_ipv4_process(void *proto_priv, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct proto_process_stack *s = &stack[stack_index];
	struct proto_process_stack *s_next = &stack[stack_index + 1];

	struct ip* hdr = s->pload;

	unsigned int hdr_len = hdr->ip_hl * 4;

	if (s->plen < sizeof(struct ip) || // length smaller than header
		hdr->ip_hl < 5 || // ip header < 5 bytes
		ntohs(hdr->ip_len) < hdr_len || // datagram size < ip header length
		ntohs(hdr->ip_len) > s->plen) { // datagram size > given size
		return PROTO_INVALID;
	}


	PTYPE_IPV4_SETADDR(s->pkt_info->fields_value[proto_ipv4_field_src], hdr->ip_src);
	PTYPE_IPV4_SETADDR(s->pkt_info->fields_value[proto_ipv4_field_dst], hdr->ip_dst);
	PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_ipv4_field_tos], hdr->ip_tos);
	PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_ipv4_field_ttl], hdr->ip_ttl);

	// Handle conntrack stuff
	if (conntrack_get(stack, stack_index) != POM_OK)
		return PROTO_ERR;


	s_next->pload = s->pload + hdr_len;
	s_next->plen = ntohs(hdr->ip_len) - hdr_len;

	s_next->proto = proto_get_by_number(s->proto, hdr->ip_p);


	int res = POM_ERR;
	if (s->ce->children) {
		res = conntrack_delayed_cleanup(s->ce, 0, p->ts);
	} else {
		uint32_t *conntrack_timeout = PTYPE_UINT32_GETVAL(param_conntrack_timeout);
		res = conntrack_delayed_cleanup(s->ce, *conntrack_timeout, p->ts);
	}
	if (res == POM_ERR) {
		conntrack_unlock(s->ce);
		return PROTO_ERR;
	}

	uint16_t frag_off = ntohs(hdr->ip_off);

	// Check if packet is fragmented and need more handling

	if (frag_off & IP_DONT_FRAG) {
		conntrack_unlock(s->ce);
		return PROTO_OK; // Nothing to do
	}

	if (!(frag_off & IP_MORE_FRAG) && !(frag_off & IP_OFFSET_MASK)) {
		conntrack_unlock(s->ce);
		return PROTO_OK; // Nothing to do, full packet
	}

	uint16_t offset = (frag_off & IP_OFFSET_MASK) << 3;
	size_t frag_size = ntohs(hdr->ip_len) - (hdr->ip_hl * 4);

	// Ignore invalid fragments
	if (frag_size > 0xFFFF) {
		conntrack_unlock(s->ce);
		return PROTO_INVALID;
	}

	if (frag_size > s->plen + hdr_len) {
		conntrack_unlock(s->ce);
		return PROTO_INVALID;
	}

	// Account for one more fragment
	registry_perf_inc(perf_frags, 1);

	struct proto_ipv4_fragment *tmp = s->ce->priv;

	// Let's find the right buffer
	for (; tmp && tmp->id != hdr->ip_id; tmp = tmp->next);

	if (!tmp) {
		// Buffer not found, create it
		tmp = malloc(sizeof(struct proto_ipv4_fragment));
		if (!tmp) {
			pom_oom(sizeof(struct proto_ipv4_fragment));
			conntrack_unlock(s->ce);
			return PROTO_ERR;
		}
		memset(tmp, 0, sizeof(struct proto_ipv4_fragment));

		tmp->t = conntrack_timer_alloc(s->ce, proto_ipv4_fragment_cleanup, tmp);
		if (!tmp->t) {
			conntrack_unlock(s->ce);
			free(tmp);
			return PROTO_ERR;
		}
		
		tmp->id = hdr->ip_id;

		if (!s_next->proto) {
			// Set processed flag so no attempt to process this will be done
			tmp->flags |= PROTO_IPV4_FLAG_PROCESSED;
			conntrack_unlock(s->ce);
			conntrack_timer_cleanup(tmp->t);
			free(tmp);
			return PROTO_STOP;
		}

		tmp->multipart = packet_multipart_alloc(s_next->proto, 0);
		if (!tmp->multipart) {
			conntrack_unlock(s->ce);
			conntrack_timer_cleanup(tmp->t);
			free(tmp);
			return PROTO_ERR;
		}

		tmp->next = s->ce->priv;
		if (tmp->next)
			tmp->next->prev = tmp;
		s->ce->priv = tmp;
	}

	// Fragment was already handled
	if (tmp->flags & PROTO_IPV4_FLAG_PROCESSED) {
		conntrack_unlock(s->ce);
		registry_perf_inc(perf_frags_dropped, 1);
		return PROTO_STOP;
	}
	
	// Add the fragment
	if (packet_multipart_add_packet(tmp->multipart, p, offset, frag_size, (s->pload - (void*)p->buff) + (hdr->ip_hl * 4)) != POM_OK) {
		conntrack_unlock(s->ce);
		packet_multipart_cleanup(tmp->multipart);
		conntrack_timer_cleanup(tmp->t);
		free(tmp);
		return PROTO_ERR;
	}
	tmp->count++;

	// Schedule the timeout for the fragment
	uint32_t *frag_timeout = PTYPE_UINT32_GETVAL(param_frag_timeout);
	conntrack_timer_queue(tmp->t, *frag_timeout, p->ts);


	if (!(frag_off & IP_MORE_FRAG))
		tmp->flags |= PROTO_IPV4_FLAG_GOT_LAST;

	if ((tmp->flags & PROTO_IPV4_FLAG_GOT_LAST) && !tmp->multipart->gaps)
		tmp->flags |= PROTO_IPV4_FLAG_PROCESSED;


	conntrack_unlock(s->ce);
	
	if ((tmp->flags & PROTO_IPV4_FLAG_PROCESSED)) {
		int res = packet_multipart_process(tmp->multipart, stack, stack_index + 1);
		tmp->multipart = NULL; // Multipart will be cleared automatically
		if (res == PROTO_ERR) {
			return PROTO_ERR;
		} else if (res == PROTO_INVALID) {
			registry_perf_inc(perf_frags_dropped, tmp->count);
		} else {
			registry_perf_inc(perf_reassembled_pkts, 1);
		}
	}

	return PROTO_STOP; // Stop processing the packet

}
Exemplo n.º 11
0
static int input_pcap_dir_browse(struct input_pcap_priv *priv) {

	// Open the directory
	char *path = PTYPE_STRING_GETVAL(priv->tpriv.dir.p_dir);

	DIR *dir = opendir(path);
	if (!dir) {
		pomlog(POMLOG_ERR "Error while opening directory %s : %s", path, pom_strerror(errno));
		return POM_ERR;
	}

	// Compile the regex used to match files
	char *match = PTYPE_STRING_GETVAL(priv->tpriv.dir.p_match);
	regex_t preg;
	int errcode = regcomp(&preg, match, REG_NOSUB);

	if (errcode) {
		char errbuf[256] = { 0 };
		regerror(errcode, &preg, errbuf, sizeof(errbuf) - 1);
		pomlog(POMLOG_ERR "Error while compiling regex \"%s\" : %s", match, errbuf);
		return POM_ERR;
	}


	// Browse the given directory
	struct dirent *buf, *de;
	size_t len = offsetof(struct dirent, d_name) + pathconf(path, _PC_NAME_MAX) + 1;
	buf = malloc(len);

	int tot_files = 0;

	while (!priv->tpriv.dir.interrupt_scan) {

		int res = readdir_r(dir, buf, &de);
		if (res) {
			pomlog(POMLOG_ERR "Error while reading directory entry : %s", pom_strerror(errno));
			regfree(&preg);
			free(buf);
			closedir(dir);
			return POM_ERR;
		}

		if (!de)
			break;

		// Match our file against regex
		if (regexec(&preg, buf->d_name, 1, NULL, 0)) {
			pomlog(POMLOG_DEBUG "Discarding file %s, regular expression not matched", buf->d_name);
			continue;
		}

		// Check if we already know about that file
		struct input_pcap_dir_file *tmp = priv->tpriv.dir.files;
		int found = 0;
		while (tmp) {
			if (!strcmp(tmp->filename, buf->d_name)) {
				found = 1;
				break;
			}
			tmp = tmp->next;
		}
		if (found)
			continue;


		// We don't know about this file, parse it
		char errbuf[PCAP_ERRBUF_SIZE + 1];

		// Alloc the new file
		struct input_pcap_dir_file *cur = malloc(sizeof(struct input_pcap_dir_file));
		if (!cur) {
			free(cur->full_path);
			regfree(&preg);
			pom_oom(sizeof(struct input_pcap_dir_file));
			return POM_ERR;
		}
		memset(cur, 0, sizeof(struct input_pcap_dir_file));

		cur->full_path = malloc(strlen(path) + strlen(buf->d_name) + 2);
		if (!cur->full_path) {
			regfree(&preg);
			pom_oom(strlen(path) + strlen(buf->d_name) + 2);
			return POM_ERR;
		}
		strcpy(cur->full_path, path);
		if (*cur->full_path && cur->full_path[strlen(cur->full_path) - 1] != '/')
			strcat(cur->full_path, "/");
		cur->filename = cur->full_path + strlen(cur->full_path);
		strcat(cur->full_path, buf->d_name);

		// Get the time of the first packet
		pcap_t *p = pcap_open_offline(cur->full_path, errbuf);
		if (!p) {
			cur->next = priv->tpriv.dir.files;
			priv->tpriv.dir.files = cur; // Add at the begning in order not to process it again
			pomlog(POMLOG_WARN "Unable to open file %s : %s", cur->full_path, errbuf);
			continue;
		}
	
		if (input_pcap_set_filter(priv->p, PTYPE_STRING_GETVAL(priv->p_filter)) != POM_OK) {
			cur->next = priv->tpriv.dir.files;
			priv->tpriv.dir.files = cur; // Add at the begning in order not to process it again
			pomlog(POMLOG_WARN "Could not set filter on file %s", cur->full_path);
			continue;
		}

		const u_char *next_pkt;
		struct pcap_pkthdr *phdr;

		int result = pcap_next_ex(p, &phdr, &next_pkt);

		if (result <= 0) {
			cur->next = priv->tpriv.dir.files;
			priv->tpriv.dir.files = cur; // Add at the begning in order not to process it again
			pomlog(POMLOG_WARN "Could not read first packet from file %s", cur->full_path);
			free(cur->full_path);
			pcap_close(p);
			continue;
		}

		cur->first_pkt = pom_timeval_to_ptime(phdr->ts);
		pcap_close(p);

		// Add the packet at the right position
		tmp = priv->tpriv.dir.files;

		if (!tmp || (tmp && (cur->first_pkt < tmp->first_pkt))) {
			// Add at the begining
			cur->next = priv->tpriv.dir.files;
			priv->tpriv.dir.files = cur;

		} else {
			while (tmp->next) {
				if (cur->first_pkt < tmp->next->first_pkt) {
					// Add in the middle
					cur->next = tmp->next;
					tmp->next = cur;
					break;
				}
				tmp = tmp->next;
			}

			if (!tmp->next) {
				// Add at the end
				tmp->next = cur;
			}
		}


		pomlog(POMLOG_DEBUG "Added file %s to the list", cur->full_path);
		tot_files++;

	}

	regfree(&preg);
	free(buf);

	closedir(dir);

	if (priv->tpriv.dir.interrupt_scan)
		return 0;

	return tot_files;

}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
static int analyzer_arp_init(struct analyzer *analyzer) {

	struct analyzer_arp_priv *priv = malloc(sizeof(struct analyzer_arp_priv));
	if (!priv) {
		pom_oom(sizeof(struct analyzer_arp_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct analyzer_arp_priv));

	analyzer->priv = priv;

	if (pthread_mutex_init(&priv->lock, NULL)) {
		pomlog(POMLOG_ERR "Error while initializing table lock : %s", pom_strerror(errno));
		free(priv);
		return POM_ERR;
	}

	priv->proto_vlan = proto_get("vlan");
	if (!priv->proto_vlan)
		goto err;

	static struct data_item_reg evt_new_sta_data_items[ANALYZER_ARP_EVT_NEW_STA_DATA_COUNT] = { { 0 } };

	evt_new_sta_data_items[analyzer_arp_new_sta_mac_addr].name = "mac_addr";
	evt_new_sta_data_items[analyzer_arp_new_sta_mac_addr].value_type = ptype_get_type("mac");
	evt_new_sta_data_items[analyzer_arp_new_sta_ip_addr].name = "ip_addr";
	evt_new_sta_data_items[analyzer_arp_new_sta_ip_addr].value_type = ptype_get_type("ipv4");
	evt_new_sta_data_items[analyzer_arp_new_sta_vlan].name = "vlan";
	evt_new_sta_data_items[analyzer_arp_new_sta_vlan].value_type = ptype_get_type("uint16");
	evt_new_sta_data_items[analyzer_arp_new_sta_input].name = "input";
	evt_new_sta_data_items[analyzer_arp_new_sta_input].value_type = ptype_get_type("string");


	static struct data_reg evt_new_sta_data = {
		.items = evt_new_sta_data_items,
		.data_count = ANALYZER_ARP_EVT_NEW_STA_DATA_COUNT
	};

	static struct event_reg_info analyzer_arp_evt_new_sta = { 0 };
	analyzer_arp_evt_new_sta.source_name = "analyzer_arp";
	analyzer_arp_evt_new_sta.source_obj = analyzer;
	analyzer_arp_evt_new_sta.name = "arp_new_sta";
	analyzer_arp_evt_new_sta.description = "New station found";
	analyzer_arp_evt_new_sta.data_reg = &evt_new_sta_data;
	analyzer_arp_evt_new_sta.listeners_notify = analyzer_arp_event_listeners_notify;

	priv->evt_new_sta = event_register(&analyzer_arp_evt_new_sta);
	if (!priv->evt_new_sta)
		goto err;

	static struct data_item_reg evt_sta_changed_data_items[ANALYZER_ARP_EVT_STA_CHANGED_DATA_COUNT] = { { 0 } };

	evt_sta_changed_data_items[analyzer_arp_sta_changed_old_mac_addr].name = "old_mac_addr";
	evt_sta_changed_data_items[analyzer_arp_sta_changed_old_mac_addr].value_type = ptype_get_type("mac");
	evt_sta_changed_data_items[analyzer_arp_sta_changed_new_mac_addr].name = "new_mac_addr";
	evt_sta_changed_data_items[analyzer_arp_sta_changed_new_mac_addr].value_type = ptype_get_type("mac");
	evt_sta_changed_data_items[analyzer_arp_sta_changed_ip_addr].name = "ip_addr";
	evt_sta_changed_data_items[analyzer_arp_sta_changed_ip_addr].value_type = ptype_get_type("ipv4");
	evt_sta_changed_data_items[analyzer_arp_sta_changed_vlan].name = "vlan";
	evt_sta_changed_data_items[analyzer_arp_sta_changed_vlan].value_type = ptype_get_type("uint16");
	evt_sta_changed_data_items[analyzer_arp_sta_changed_input].name = "input";
	evt_sta_changed_data_items[analyzer_arp_sta_changed_input].value_type = ptype_get_type("string");

	static struct data_reg evt_sta_changed_data = {
		.items = evt_sta_changed_data_items,
		.data_count = ANALYZER_ARP_EVT_STA_CHANGED_DATA_COUNT
	};

	static struct event_reg_info analyzer_arp_evt_sta_changed = { 0 };
	analyzer_arp_evt_sta_changed.source_name = "analyzer_arp";
	analyzer_arp_evt_sta_changed.source_obj = analyzer;
	analyzer_arp_evt_sta_changed.name = "arp_sta_changed";
	analyzer_arp_evt_sta_changed.description = "Station MAC address changed";
	analyzer_arp_evt_sta_changed.data_reg = &evt_sta_changed_data;
	analyzer_arp_evt_sta_changed.listeners_notify = analyzer_arp_event_listeners_notify;

	priv->evt_sta_changed = event_register(&analyzer_arp_evt_sta_changed);
	if (!priv->evt_sta_changed)
		goto err;

	return POM_OK;

err:
	analyzer_arp_cleanup(analyzer);

	return POM_ERR;
}
Exemplo n.º 14
0
static int analyzer_arp_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

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

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

	struct in_addr arp_ip = PTYPE_IPV4_GETADDR(s->pkt_info->fields_value[proto_arp_field_sender_proto_addr]);

	// Discard bogon 0.0.0.0
	if (!arp_ip.s_addr)
		return POM_OK;

	// Find that IP in the table
	uint32_t id = arp_ip.s_addr & ANALYZER_ARP_HOST_MASK;
	char *arp_mac = PTYPE_MAC_GETADDR(s->pkt_info->fields_value[proto_arp_field_sender_hw_addr]);

	uint16_t vlan = 0;
	if (s_prev->proto == priv->proto_vlan)
		vlan = *PTYPE_UINT16_GETVAL(s_prev->pkt_info->fields_value[proto_vlan_field_vid]);

	pom_mutex_lock(&priv->lock);

	struct analyzer_arp_host *host;
	for (host = priv->hosts[id]; host; host = host->next) {
		if (host->ip.s_addr == arp_ip.s_addr && host->vlan == vlan)
			break;
	}

	if (!host) {
		// Host not found !
		host = malloc(sizeof(struct analyzer_arp_host));
		if (!host) {
			pom_mutex_unlock(&priv->lock);
			pom_oom(sizeof(struct analyzer_arp_host));
			return POM_ERR;
		}
		memset(host, 0, sizeof(struct analyzer_arp_host));

		host->ip.s_addr = arp_ip.s_addr;
		memcpy(host->mac, arp_mac, sizeof(host->mac));
		host->vlan = vlan;

		host->next = priv->hosts[id];
		if (host->next)
			host->next->prev = host;

		priv->hosts[id] = host;
		pom_mutex_unlock(&priv->lock);

		// Announce the new station
	
		if (event_has_listener(priv->evt_new_sta)) {
			struct event *evt = event_alloc(priv->evt_new_sta);
			if (!evt)
				return POM_ERR;

			struct data *evt_data = evt->data;
			ptype_copy(evt_data[analyzer_arp_new_sta_mac_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_hw_addr]);
			data_set(evt_data[analyzer_arp_new_sta_mac_addr]);
			ptype_copy(evt_data[analyzer_arp_new_sta_ip_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_proto_addr]);
			data_set(evt_data[analyzer_arp_new_sta_ip_addr]);
			PTYPE_UINT16_SETVAL(evt_data[analyzer_arp_new_sta_vlan].value, vlan);
			data_set(evt_data[analyzer_arp_new_sta_vlan]);
			PTYPE_STRING_SETVAL(evt_data[analyzer_arp_new_sta_input].value, p->input->name);
			data_set(evt_data[analyzer_arp_new_sta_input]);
			if (event_process(evt, stack, stack_index) != POM_OK)
				return POM_ERR;
		}
		
		// Nothing else to do
		return POM_OK;
	}

	// Host was found, check mac
	if (memcmp(host->mac, arp_mac, sizeof(host->mac))) {
		if (event_has_listener(priv->evt_sta_changed)) {
			struct event *evt = event_alloc(priv->evt_sta_changed);
			if (!evt) {
				pom_mutex_unlock(&priv->lock);
				return POM_ERR;
			}

			struct data *evt_data = evt->data;
			PTYPE_MAC_SETADDR(evt_data[analyzer_arp_sta_changed_old_mac_addr].value, host->mac);
			data_set(evt_data[analyzer_arp_sta_changed_old_mac_addr]);
			ptype_copy(evt_data[analyzer_arp_sta_changed_new_mac_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_hw_addr]);
			data_set(evt_data[analyzer_arp_sta_changed_new_mac_addr]);
			ptype_copy(evt_data[analyzer_arp_sta_changed_ip_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_proto_addr]);
			data_set(evt_data[analyzer_arp_sta_changed_ip_addr]);
			PTYPE_UINT16_SETVAL(evt_data[analyzer_arp_sta_changed_vlan].value, vlan);
			data_set(evt_data[analyzer_arp_sta_changed_vlan]);
			PTYPE_STRING_SETVAL(evt_data[analyzer_arp_sta_changed_input].value, p->input->name);
			data_set(evt_data[analyzer_arp_sta_changed_input]);

			if (event_process(evt, stack, stack_index) != POM_OK) {
				pom_mutex_unlock(&priv->lock);
				return POM_ERR;
			}
		}
		memcpy(host->mac, arp_mac, sizeof(host->mac));
	}
	


	pom_mutex_unlock(&priv->lock);
	return POM_OK;
}
Exemplo n.º 15
0
int output_log_xml_open(void *output_priv) {

	struct output_log_xml_priv *priv = output_priv;

	if (addon_log_xml_open(priv) != POM_OK)
		return POM_ERR;

	if (!strlen(PTYPE_STRING_GETVAL(priv->p_source))) {
		pomlog(POMLOG_ERR "You need to specify a source for this output");
		goto err;
	}

	char *src = strdup(PTYPE_STRING_GETVAL(priv->p_source));

	if (!src) {
		pom_oom(strlen(PTYPE_STRING_GETVAL(priv->p_source)));
		goto err;
	}

	char *token, *saveptr, *str = src;
	for (; ; str = NULL) {
		token = strtok_r(str, ", ", &saveptr);

		if (!token)
			break;

		struct event_reg *evt = event_find(token);
		if (!evt) {
			pomlog(POMLOG_WARN "Event \"%s\" does not exists", token);
			continue;
		}

		struct output_log_xml_evt *evt_lst = malloc(sizeof(struct output_log_xml_evt));
		if (!evt_lst) {
			pom_oom(sizeof(struct output_log_xml_evt));
			free(src);
			goto err;
		}
		memset(evt_lst, 0, sizeof(struct output_log_xml_evt));
		evt_lst->evt = evt;

		// Start listening to the event
		if (event_listener_register(evt, priv, NULL, output_log_xml_process) != POM_OK) {
			free(evt_lst);
			free(src);
			goto err;
		}

		evt_lst->next = priv->evt_lst;
		priv->evt_lst = evt_lst;


	}

	free(src);

	if (!priv->evt_lst)
		goto err;

	return POM_OK;

err:
	output_log_xml_close(priv);

	return POM_ERR;

}
Exemplo n.º 16
0
int packet_stream_force_dequeue(struct packet_stream *stream) {

	struct packet_stream_pkt *p = NULL;
	unsigned int next_dir = 0;

	while (1) {

		if (!stream->head[POM_DIR_FWD] && !stream->head[POM_DIR_REV])
			return POM_OK;


		if (!stream->head[POM_DIR_FWD]) {
			next_dir = POM_DIR_REV;
		} else if (!stream->head[POM_DIR_REV]) {
			next_dir = POM_DIR_FWD;
		} else {
			// We have packets in both direction, lets see which one we'll process first
			int i;
			for (i = 0; i < POM_DIR_TOT; i++) {
				int r = POM_DIR_REVERSE(i);
				struct packet_stream_pkt *a = stream->head[i], *b = stream->head[r];
				uint32_t end_seq = a->seq + a->plen;
				if ((end_seq <= b->ack && b->ack - end_seq < PACKET_HALF_SEQ) ||
					(b->ack > end_seq && end_seq - b->ack > PACKET_HALF_SEQ))
					break;

			}
			if (i == POM_DIR_TOT) {
				// There is a gap in both direction
				// Process the first packet received
				struct packet *a = stream->head[POM_DIR_FWD]->pkt, *b = stream->head[POM_DIR_REV]->pkt;
				if (a->ts.tv_sec < b->ts.tv_sec || 
					(a->ts.tv_sec == b->ts.tv_sec && a->ts.tv_usec < b->ts.tv_usec)) {
					next_dir = POM_DIR_FWD;
				} else {
					next_dir = POM_DIR_REV;
				}
				debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : processing next by timestamp", pthread_self(), stream, stream->head[next_dir]->pkt->ts.tv_sec, stream->head[next_dir]->pkt->ts.tv_usec, stream->head[next_dir]->seq, stream->head[next_dir]->ack);
			} else {
				next_dir = i;
			}
		}

		p = stream->head[next_dir];
		if (p->next)
			p->next->prev = NULL;
		else
			stream->tail[next_dir] = NULL;
		
		stream->head[next_dir] = p->next;
		stream->cur_buff_size -= p->plen;


		if (packet_stream_is_packet_old_dupe(stream, p, next_dir)) {
			packet_stream_free_packet(p);
		} else {
			break;
		}
	}

	if (packet_stream_remove_dupe_bytes(stream, p, next_dir) == POM_ERR)
		return POM_ERR;


	uint32_t gap = p->seq - stream->cur_seq[next_dir];

	int res = PROTO_OK;

	if (gap) {
		
		if (gap < stream->max_buff_size) {
		
			debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : filling gap of %u", pthread_self(), stream, p->pkt->ts.tv_sec, p->pkt->ts.tv_usec, p->seq, p->ack, gap);
			uint32_t gap_step = gap;
			if (gap_step > 2048)
				gap_step = 2048;

			void *zero = malloc(gap_step);
			if (!zero) {
				pom_oom(gap_step);
				return POM_ERR;
			}
			memset(zero, 0, gap_step);
			
			struct proto_process_stack *s = &p->stack[p->stack_index];
			uint32_t plen_old = s->plen;
			void *pload_old = s->pload;


			uint32_t pos;
			for (pos = 0; pos < gap; pos += gap_step) {
				if (pos + gap_step < gap)
					s->plen = gap_step;
				else
					s->plen = gap - pos;
				s->pload = zero;
				res = stream->handler(stream->ce, p->pkt, p->stack, p->stack_index);
				s->direction = next_dir;
				if (res == PROTO_ERR)
					break;
			}

			free(zero);

			s->pload = pload_old;
			s->plen = plen_old;

		} else {
			debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : gap of %u too big. not filling", pthread_self(), stream, p->pkt->ts.tv_sec, p->pkt->ts.tv_usec, p->seq, p->ack, gap);
		}
		
	}

	if (res != PROTO_ERR) {
		debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : process forced", pthread_self(), stream, p->pkt->ts.tv_sec, p->pkt->ts.tv_usec, p->seq, p->ack);
		res = stream->handler(stream->ce, p->pkt, p->stack, p->stack_index);
	}

	stream->cur_seq[next_dir] = p->seq + p->plen;
	stream->cur_ack[next_dir] = p->ack;

	packet_stream_free_packet(p);


	if (res == PROTO_ERR) 
		return POM_ERR;

	// See if we can process additional packets

	// Check if additional packets can be processed
	while ((p = packet_stream_get_next(stream, &next_dir))) {

		debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : process additional", pthread_self(), stream, p->pkt->ts.tv_sec, p->pkt->ts.tv_usec, p->seq, p->ack);

		if (stream->handler(stream->ce, p->pkt, p->stack, p->stack_index) == PROTO_ERR)
			return POM_ERR;

		stream->cur_seq[next_dir] += p->plen;
		stream->cur_ack[next_dir] = p->ack;

		packet_stream_free_packet(p);
	}

	return POM_OK;
}
Exemplo n.º 17
0
int timer_queue(struct timer *t, unsigned int expiry) {

	pom_mutex_lock(&timer_main_lock);

	// Timer is still queued, dequeue it
	if (t->queue) {
		if (t->prev) {
			t->prev->next = t->next;
		} else {
			t->queue->head = t->next;
			if (t->queue->head)
				t->queue->head->prev = NULL;
		}

		if (t->next) {
			t->next->prev = t->prev;
		} else {
			t->queue->tail = t->prev;
			if (t->queue->tail)
				t->queue->tail->next = NULL;
			
		}
		t->queue = NULL;
		t->prev = NULL;
		t->next = NULL;
	}

	struct timer_queue *tq = timer_queues;

	// First find the right queue or create it
	
	if (!tq) {

		// There is no queue yet
		tq = malloc(sizeof(struct timer_queue));
		if (!tq) {
			pom_mutex_unlock(&timer_main_lock);
			pom_oom(sizeof(struct timer_queue));
			return POM_ERR;
		}
		memset(tq, 0, sizeof(struct timer_queue));
		timer_queues = tq;

		tq->expiry = expiry;

	} else {

		while (tq) {
			
			if (tq->expiry == expiry) { // The right queue already exists
				
				break;

			} else if (tq->expiry > expiry) { // The right queue doesn't exists and we are too far in the list

				struct timer_queue *tmp;
				tmp = malloc(sizeof(struct timer_queue));
				if (!tmp) {
					pom_oom(sizeof(struct timer_queue));
					pom_mutex_unlock(&timer_main_lock);
					return POM_ERR;
				}
				memset(tmp, 0, sizeof(struct timer_queue));

				tmp->prev = tq->prev;
				tmp->next = tq;
				tq->prev = tmp;

				if (tmp->prev)
					tmp->prev->next = tmp;
				else
					timer_queues = tmp;


				tq = tmp;
				tq->expiry = expiry;

				break;
			
			} else if (!tq->next) { // Looks like we are at the end of our list

				struct timer_queue *tmp;
				tmp = malloc(sizeof(struct timer_queue));
				if (!tmp) {
					pom_oom(sizeof(struct timer_queue));
					pom_mutex_unlock(&timer_main_lock);
					return POM_ERR;
				}
				memset(tmp, 0, sizeof(struct timer_queue));

				tmp->prev = tq;
				
				tq->next = tmp;

				tq = tmp;

				tq->expiry = expiry;
				
				break;
			}

			tq = tq->next;
		}

	}

	// Now we can queue the timer
	
	if (tq->head == NULL) {
		tq->head = t;
		tq->tail = t;
	} else {
		t->prev = tq->tail;
		tq->tail = t;
		t->prev->next = t;
	}

	// Update the expiry time

	core_get_clock(&t->expires);
	t->expires.tv_sec += expiry;
	t->queue = tq;
	pom_mutex_unlock(&timer_main_lock);

	return POM_OK;
}
Exemplo n.º 18
0
int packet_stream_parser_get_line(struct packet_stream_parser *sp, char **line, unsigned int *len) {

	if (!line || !len)
		return POM_ERR;

	// Find the next line return in the current payload
	
	char *pload = sp->pload;
	
	int str_len = sp->plen, tmp_len = 0;
	
	char *lf = memchr(pload, '\n', sp->plen);
	if (!lf) {

		if (sp->buff) {
			memmove(sp->buff, sp->pload, sp->plen);
			sp->buff_pos = sp->plen;
		} else {
			sp->buff = malloc(sp->plen);
			if (!sp->buff) {
				pom_oom(sp->plen);
				return POM_ERR;
			}
			memcpy(sp->buff, sp->pload, sp->plen);
			sp->buff_len = sp->plen;
			sp->buff_pos = sp->plen;
		}

		// \n not found
		*line = NULL;
		*len = 0;
		debug_stream_parser("entry %p, no line found", sp);
		return POM_OK;
	}


	tmp_len = lf - pload;
	str_len = tmp_len + 1;
	if (lf > pload && *(lf - 1) == '\r')
		tmp_len--;

	
	sp->plen -= str_len;
	if (!sp->plen)
		sp->pload = NULL;
	else
		sp->pload += str_len;

	// Trim the string
	while (*pload == ' ' && tmp_len) {
		pload++;
		tmp_len--;
	}
	while (pload[tmp_len] == ' ' && tmp_len)
		tmp_len--;

	*line = pload;
	*len = tmp_len;

	debug_stream_parser("entry %p, got line of %u bytes", sp, tmp_len);

	return POM_OK;
}
Exemplo n.º 19
0
int analyzer_ppp_pap_event_process_begin(struct event *evt, void *obj, struct proto_process_stack *stack, unsigned int stack_index) {

	struct analyzer *analyzer = obj;

	struct analyzer_ppp_pap_priv *apriv = analyzer->priv;

	struct proto_process_stack *s = &stack[stack_index];
	if (!s->ce)
		return PROTO_ERR;

	conntrack_lock(s->ce);

	struct ptype *src = NULL, *dst = NULL;

	struct analyzer_ppp_pap_ce_priv *cpriv = conntrack_get_priv(s->ce, analyzer);
	if (!cpriv) {
		cpriv = malloc(sizeof(struct analyzer_ppp_pap_ce_priv));
		if (!cpriv) {
			pom_oom(sizeof(struct analyzer_ppp_pap_ce_priv));
			goto err;
		}
		memset(cpriv, 0, sizeof(struct analyzer_ppp_pap_ce_priv));


		if (conntrack_add_priv(s->ce, analyzer, cpriv, analyzer_ppp_pap_ce_priv_cleanup) != POM_OK) {
			free(cpriv);
			goto err;
		}

		// Try to find the source and destination
		
		unsigned int i = 0;
		for (i = 1; i <= 4; i++) {
			struct proto_process_stack *prev_stack = &stack[stack_index - i];
			if (!prev_stack->proto)	
				break;

			struct proto_reg_info *info = proto_get_info(prev_stack->proto);
			if (!strcmp(info->name, "vlan")) {
				cpriv->vlan = ptype_alloc_from(prev_stack->pkt_info->fields_value[proto_vlan_field_vid]);
				if (!cpriv->vlan)
					return POM_ERR;
			}

			unsigned int j;
			for (j = 0; !src || !dst; j++) {
				struct proto_reg_info *prev_info = proto_get_info(prev_stack->proto);
				if (!prev_info->pkt_fields)
					break;
				char *name = prev_info->pkt_fields[j].name;
				if (!name)
					break;

				if (!src && !strcmp(name, "src"))
					src = prev_stack->pkt_info->fields_value[j];
				else if (!dst && !strcmp(name, "dst"))
					dst = prev_stack->pkt_info->fields_value[j];
			}

			if (src || dst)
				break;
		}

		struct proto_process_stack *prev_stack = &stack[stack_index - 2];
		if (prev_stack->proto) {
			struct proto_reg_info *info = proto_get_info(prev_stack->proto);
			cpriv->top_proto = info->name;
		}
	}

	struct event_reg *evt_reg = event_get_reg(evt);

	int dir = POM_DIR_UNK;

	if (evt_reg == apriv->evt_request) {

		if (!cpriv->evt_request) {
			event_refcount_inc(evt);
			cpriv->evt_request = evt;
		}
		dir = POM_DIR_FWD;

	} else {
		if (!cpriv->evt_ack_nack) {
			event_refcount_inc(evt);
			cpriv->evt_ack_nack = evt;
		}
		dir = POM_DIR_REV;
	}

	if (src && dst && dir != POM_DIR_UNK) {
		if (dir == POM_DIR_FWD) {
			cpriv->client = ptype_alloc_from(src);
			cpriv->server = ptype_alloc_from(dst);
		} else {
			cpriv->client = ptype_alloc_from(dst);
			cpriv->server = ptype_alloc_from(src);
		}
	}

	int res = POM_OK;

	if (cpriv->evt_request && cpriv->evt_ack_nack)
		res = analyzer_ppp_pap_finalize(apriv, cpriv);

	conntrack_unlock(s->ce);

	return res;

err:
	conntrack_unlock(s->ce);
	return POM_ERR;

}
Exemplo n.º 20
0
int packet_multipart_add_packet(struct packet_multipart *multipart, struct packet *pkt, size_t offset, size_t len, size_t pkt_buff_offset) {

	struct packet_multipart_pkt *tmp = multipart->tail;

	// Check where to add the packet
	
	while (tmp) {

		if (tmp->offset + tmp->len <= offset)
			break; // Packet is after is one

		if (tmp->offset == offset) {
			if (tmp->len != len)
				pomlog(POMLOG_WARN "Size missmatch for packet already in the buffer");
			return POM_OK;
		}

		tmp = tmp->prev;

	}

	struct packet_multipart_pkt *res = malloc(sizeof(struct packet_multipart_pkt));
	if (!res) {
		pom_oom(sizeof(struct packet_multipart_pkt));
		return POM_ERR;
	}
	memset(res, 0, sizeof(struct packet_multipart_pkt));

	res->offset = offset;
	res->pkt_buff_offset = pkt_buff_offset;
	res->len = len;


	// Copy the packet

	
	res->pkt = packet_clone(pkt, multipart->flags);
	if (!res->pkt) {
		free(res);
		return POM_ERR;
	}

	multipart->cur += len;

	if (tmp) {
		// Packet is after this one, add it
	
		res->prev = tmp;
		res->next = tmp->next;

		tmp->next = res;

		if (res->next) {
			res->next->prev = res;

			if ((res->next->offset == res->offset + res->len) &&
				(res->prev->offset + res->prev->len == res->offset))
				// A gap was filled
				multipart->gaps--;
			else if ((res->next->offset > res->offset + res->len) &&
				(res->prev->offset + res->prev->len < res->offset))
				// A gap was created
				multipart->gaps++;

		} else {
			multipart->tail = res;
		}


		return POM_OK;
	} else {
		// Add it at the head
		res->next = multipart->head;
		if (res->next)
			res->next->prev = res;
		else
			multipart->tail = res;
		multipart->head = res;

		if (res->offset) {
			// There is a gap at the begining
			multipart->gaps++;
		} else if (res->next && res->len == res->next->offset) {
			// Gap filled
			multipart->gaps--;
		}
	}

	return POM_OK;
}
Exemplo n.º 21
0
static int proto_eap_init(struct proto *proto, struct registry_instance *i) {

	if (proto_number_register("8021x", 0x0, proto) != POM_OK ||
		proto_number_register("ppp", 0xc227, proto) != POM_OK)
		return POM_ERR;

	struct proto_eap_priv *priv = malloc(sizeof(struct proto_eap_priv));
	if (!priv) {
		pom_oom(sizeof(struct proto_eap_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct proto_eap_priv));
	proto_set_priv(proto, priv);

	priv->p_timeout = ptype_alloc_unit("uint32", "seconds");
	if (!priv->p_timeout)
		goto err;

	struct registry_param *p = registry_new_param("timeout", "60", priv->p_timeout, "Transaction timeout", 0);
	if (registry_instance_add_param(i, p) != POM_OK) {
		registry_cleanup_param(p);
		goto err;
	}

	static struct data_item_reg evt_identity_data_items[PROTO_EAP_EVT_IDENTITY_DATA_COUNT] = { { 0 } };
	evt_identity_data_items[evt_eap_common_identifier].name = "identifier";
	evt_identity_data_items[evt_eap_common_identifier].value_type = ptype_get_type("uint8");
	evt_identity_data_items[evt_eap_common_code].name = "code";
	evt_identity_data_items[evt_eap_common_code].value_type = ptype_get_type("uint8");
	evt_identity_data_items[evt_eap_identity_identity].name = "identity";
	evt_identity_data_items[evt_eap_identity_identity].value_type = ptype_get_type("string");

	static struct data_reg evt_eap_identity_data = {
		.items = evt_identity_data_items,
		.data_count = PROTO_EAP_EVT_IDENTITY_DATA_COUNT
	};

	static struct event_reg_info proto_eap_identity = { 0 };
	proto_eap_identity.source_name = "proto_eap";
	proto_eap_identity.source_obj = priv;
	proto_eap_identity.name = "eap_identity";
	proto_eap_identity.description = "EAP Identity";
	proto_eap_identity.data_reg = &evt_eap_identity_data;

	priv->evt_identity = event_register(&proto_eap_identity);
	if (!priv->evt_identity)
		goto err;

	static struct data_item_reg evt_md5_challenge_data_items[PROTO_EAP_EVT_MD5_CHALLENGE_DATA_COUNT] = { { 0 } };
	evt_md5_challenge_data_items[evt_eap_common_identifier].name = "identifier";
	evt_md5_challenge_data_items[evt_eap_common_identifier].value_type = ptype_get_type("uint8");
	evt_md5_challenge_data_items[evt_eap_common_code].name = "code";
	evt_md5_challenge_data_items[evt_eap_common_code].value_type = ptype_get_type("uint8");
	evt_md5_challenge_data_items[evt_eap_md5_challenge_value].name = "value";
	evt_md5_challenge_data_items[evt_eap_md5_challenge_value].value_type = ptype_get_type("bytes");
	evt_md5_challenge_data_items[evt_eap_md5_challenge_name].name = "name";
	evt_md5_challenge_data_items[evt_eap_md5_challenge_name].value_type = ptype_get_type("string");

	static struct data_reg evt_eap_md5_challenge_data = {
		.items = evt_md5_challenge_data_items,
		.data_count = PROTO_EAP_EVT_MD5_CHALLENGE_DATA_COUNT
	};

	static struct event_reg_info proto_eap_md5_challenge = { 0 };
	proto_eap_md5_challenge.source_name = "proto_eap";
	proto_eap_md5_challenge.source_obj = priv;
	proto_eap_md5_challenge.name = "eap_md5_challenge";
	proto_eap_md5_challenge.description = "EAP MD5-Challenge";
	proto_eap_md5_challenge.data_reg = &evt_eap_md5_challenge_data;

	priv->evt_md5_challenge = event_register(&proto_eap_md5_challenge);
	if (!priv->evt_md5_challenge)
		goto err;

	static struct data_item_reg evt_success_failure_data_items[PROTO_EAP_EVT_SUCCESS_FAILURE_DATA_COUNT] = { { 0 } };
	evt_success_failure_data_items[evt_eap_common_identifier].name = "identifier";
	evt_success_failure_data_items[evt_eap_common_identifier].value_type = ptype_get_type("uint8");
	evt_success_failure_data_items[evt_eap_success_failure_success].name = "success";
	evt_success_failure_data_items[evt_eap_success_failure_success].value_type = ptype_get_type("bool");

	static struct data_reg evt_eap_success_failure_data = {
		.items = evt_success_failure_data_items,
		.data_count = PROTO_EAP_EVT_SUCCESS_FAILURE_DATA_COUNT
	};

	static struct event_reg_info proto_eap_success_failure = { 0 };
	proto_eap_success_failure.source_name = "proto_eap";
	proto_eap_success_failure.source_obj = priv;
	proto_eap_success_failure.name = "eap_success_failure";
	proto_eap_success_failure.description = "EAP Success/Failure";
	proto_eap_success_failure.data_reg = &evt_eap_success_failure_data;

	priv->evt_success_failure = event_register(&proto_eap_success_failure);
	if (!priv->evt_success_failure)
		goto err;

	return POM_OK;
	
err:
	proto_eap_cleanup(priv);
	return POM_ERR;
}
Exemplo n.º 22
0
int packet_buffer_pool_get(struct packet *pkt, size_t size, size_t align_offset) {

	if (align_offset >= PACKET_BUFFER_ALIGNMENT) {
		pomlog(POMLOG_ERR "Alignment offset too big");
		return POM_ERR;
	}

	size_t tot_size = size + align_offset + PACKET_BUFFER_ALIGNMENT;

	if (tot_size > packet_buffer_pool_size[PACKET_BUFFER_POOL_COUNT - 1]) {
		pomlog(POMLOG_ERR "Requested size too big : %llu", size);
		return POM_ERR;
	}

	int i;
	for (i = 0; i < PACKET_BUFFER_POOL_COUNT && packet_buffer_pool_size[i] < tot_size; i++);

	struct packet_buffer *pb = NULL;

	pom_mutex_lock(&packet_buffer_pool_mutex);

	if (!packet_buffer_pool[i].unused) {

		// Allocate a new one
		size_t alloc_size = packet_buffer_pool_size[i] + sizeof(struct packet_buffer);

		pb = malloc(alloc_size);
		if (!pb) {
			pom_mutex_unlock(&packet_buffer_pool_mutex);
			pom_oom(alloc_size);
			return POM_ERR;
		}
		memset(pb, 0, alloc_size);

		pb->base_buff = (void*)pb + sizeof(struct packet_buffer);
		pb->aligned_buff = (void*) (((long)pb->base_buff & ~(PACKET_BUFFER_ALIGNMENT - 1)) + PACKET_BUFFER_ALIGNMENT + align_offset);
		pb->pool_id = i;

	} else {
		// Reuse an unused one
		pb = packet_buffer_pool[i].unused;
		if (pb->next)
			pb->next->prev = NULL;

		packet_buffer_pool[i].unused = pb->next;


	}

	// Put this one in the used list

	pb->next = packet_buffer_pool[i].used;
	if (pb->next)
		pb->next->prev = pb;
	packet_buffer_pool[i].used = pb;

	pom_mutex_unlock(&packet_buffer_pool_mutex);

	pkt->pkt_buff = pb;
	pkt->len = size;
	pkt->buff = pb->aligned_buff;

	return POM_OK;
}
Exemplo n.º 23
0
static int analyzer_rtp_init(struct analyzer *analyzer) {

	struct analyzer_rtp_priv *priv = malloc(sizeof(struct analyzer_rtp_priv));
	if (!priv) {
		pom_oom(sizeof(struct analyzer_rtp_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct analyzer_rtp_priv));
	analyzer->priv = priv;

	priv->proto_rtp = proto_get("rtp");
	if (!priv->proto_rtp)
		goto err;

	static struct data_item_reg evt_rtp_stream_data_items[ANALYZER_RTP_STREAM_DATA_COUNT] = { { 0 } };

	evt_rtp_stream_data_items[analyzer_rtp_stream_src_addr].name = "src_addr";
	evt_rtp_stream_data_items[analyzer_rtp_stream_src_addr].flags = DATA_REG_FLAG_NO_ALLOC;

	evt_rtp_stream_data_items[analyzer_rtp_stream_dst_addr].name = "dst_addr";
	evt_rtp_stream_data_items[analyzer_rtp_stream_dst_addr].flags = DATA_REG_FLAG_NO_ALLOC;

	evt_rtp_stream_data_items[analyzer_rtp_stream_src_port].name = "src_port";
	evt_rtp_stream_data_items[analyzer_rtp_stream_src_port].value_type = ptype_get_type("uint16");

	evt_rtp_stream_data_items[analyzer_rtp_stream_dst_port].name = "dst_port";
	evt_rtp_stream_data_items[analyzer_rtp_stream_dst_port].value_type = ptype_get_type("uint16");

	evt_rtp_stream_data_items[analyzer_rtp_stream_sess_proto].name = "sess_proto";
	evt_rtp_stream_data_items[analyzer_rtp_stream_sess_proto].value_type = ptype_get_type("string");

	evt_rtp_stream_data_items[analyzer_rtp_stream_call_id].name = "call_id";
	evt_rtp_stream_data_items[analyzer_rtp_stream_call_id].value_type = ptype_get_type("string");

	evt_rtp_stream_data_items[analyzer_rtp_stream_ssrc].name = "ssrc";
	evt_rtp_stream_data_items[analyzer_rtp_stream_ssrc].value_type = ptype_get_type("uint32");

	static struct data_reg evt_rtp_stream_data = {
		.items = evt_rtp_stream_data_items,
		.data_count = ANALYZER_RTP_STREAM_DATA_COUNT
	};

	static struct event_reg_info analyzer_rtp_evt_stream = { 0 };
	analyzer_rtp_evt_stream.source_name = "analyzer_rtp";
	analyzer_rtp_evt_stream.source_obj = analyzer;
	analyzer_rtp_evt_stream.name = "rtp_stream";
	analyzer_rtp_evt_stream.description = "RTP stream in a single direction";
	analyzer_rtp_evt_stream.data_reg = &evt_rtp_stream_data;
	analyzer_rtp_evt_stream.flags = EVENT_REG_FLAG_PAYLOAD;
	analyzer_rtp_evt_stream.listeners_notify = analyzer_rtp_event_listeners_notify;
	analyzer_rtp_evt_stream.cleanup = analyzer_rtp_stream_event_cleanup;
	
	priv->evt_rtp_stream = event_register(&analyzer_rtp_evt_stream);
	if (!priv->evt_rtp_stream)
		goto err;

	return POM_OK;

err:
	analyzer_rtp_cleanup(analyzer);
	return POM_ERR;
}
Exemplo n.º 24
0
int packet_stream_process_packet(struct packet_stream *stream, struct packet *pkt, struct proto_process_stack *stack, unsigned int stack_index, uint32_t seq, uint32_t ack) {

	if (!stream || !pkt || !stack)
		return PROTO_ERR;

	debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : start", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);

	struct proto_process_stack *cur_stack = &stack[stack_index];
	int direction = cur_stack->direction;

	int must_wait = 0;

	pom_mutex_lock(&stream->wait_lock);

	int res = pthread_mutex_trylock(&stream->lock);
	if (res == EBUSY) {
		// Already locked, let's wait a bit
		must_wait = 1;
	} else if (res) {
		pomlog(POMLOG_ERR "Error while locking packet stream lock : %s", pom_strerror(errno));
		abort();
		return POM_ERR;
	} else {

		// We got the processing lock. But was it really this thread's turn ?

		struct packet_stream_thread_wait *tmp = stream->wait_list_head;
		// A thread with a packet preceding ours is waiting
		if (tmp && (tmp->ts.tv_sec < pkt->ts.tv_sec || (tmp->ts.tv_sec == pkt->ts.tv_sec && tmp->ts.tv_usec < pkt->ts.tv_usec))) {
			// No it wasn't, release it and signal the right thread
			must_wait = 2;
			pom_mutex_unlock(&stream->lock);
			debug_stream("thread %p, entry %p : signaling thread %p", pthread_self(), stream, stream->wait_list_head->thread);
			pthread_cond_broadcast(&stream->wait_list_head->cond);
		} else {
			// Yes it was. YAY !
			pom_mutex_unlock(&stream->wait_lock);
		}

	}


	if (must_wait) {

		// Add ourself in the waiting list
		struct packet_stream_thread_wait *lst = NULL;
		if (stream->wait_list_unused) {
			lst = stream->wait_list_unused;
			stream->wait_list_unused = lst->next;
			lst->next = NULL;
		} else {
			lst = malloc(sizeof(struct packet_stream_thread_wait));
			if (!lst) {
				pom_oom(sizeof(struct packet_stream_thread_wait));
				pom_mutex_unlock(&stream->wait_lock);
				return POM_ERR;
			}
			memset(lst, 0, sizeof(struct packet_stream_thread_wait));
			
			if (pthread_cond_init(&lst->cond, NULL)) {
				pomlog(POMLOG_ERR "Error while initializing wait list condition : %s", pom_strerror(errno));
				free(lst);
				return POM_ERR;
			}
		}
		memcpy(&lst->ts, &pkt->ts, sizeof(struct timeval));
		lst->thread = pthread_self();

		struct packet_stream_thread_wait *tmp;
		for (tmp = stream->wait_list_head; tmp && (tmp->ts.tv_sec < lst->ts.tv_sec || (tmp->ts.tv_sec == lst->ts.tv_sec && tmp->ts.tv_usec < lst->ts.tv_usec)); tmp = tmp->next);
		if (tmp) {

			lst->prev = tmp->prev;
			if (lst->prev)
				lst->prev->next = lst;
			else
				stream->wait_list_head = lst;

			lst->next = tmp;
			lst->next->prev = lst;
		} else {
			lst->prev = stream->wait_list_tail;
			if (lst->prev)
				lst->prev->next = lst;
			else
				stream->wait_list_head = lst;

			stream->wait_list_tail = lst;
		}


		while (1) {
			debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : waiting", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);
			if (pthread_cond_wait(&lst->cond, &stream->wait_lock)) {
				pomlog(POMLOG_ERR "Error while waiting for the packet stream wait cond : %s", pom_strerror(errno));
				abort();
				return POM_ERR;
			}

			if (stream->wait_list_head != lst) {
				// There is a small chance that another stream lock stream->wait_lock while pthread_cond_wait acquires it
				// If we are not the right thread, then simply signal the right one and wait again for our turn
				debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : wrong thread woke up", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);
				pthread_cond_broadcast(&stream->wait_list_head->cond);
				continue;
			}
			break;
		}

		tmp = stream->wait_list_head;
		stream->wait_list_head = tmp->next;
		if (stream->wait_list_head)
			stream->wait_list_head->prev = NULL;
		else
			stream->wait_list_tail = NULL;

		tmp->next = stream->wait_list_unused;
		tmp->prev = NULL;
		stream->wait_list_unused = tmp;

		pom_mutex_unlock(&stream->wait_lock);
		pom_mutex_lock(&stream->lock);

	}

	debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : start locked", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);

	// Update the stream flags
	if (stream->flags & PACKET_FLAG_STREAM_BIDIR) {

		// Update flags
		if (direction == POM_DIR_FWD && !(stream->flags & PACKET_FLAG_STREAM_GOT_FWD_DIR)) {
			stream->flags |= PACKET_FLAG_STREAM_GOT_FWD_DIR;
		} else if (direction == POM_DIR_REV && !(stream->flags & PACKET_FLAG_STREAM_GOT_REV_DIR)) {
			stream->flags |= PACKET_FLAG_STREAM_GOT_REV_DIR;
		}

	}

	// Put this packet in our struct packet_stream_pkt
	struct packet_stream_pkt spkt = {0};
	spkt.pkt = pkt;
	spkt.seq = seq;
	spkt.ack = ack;
	spkt.plen = cur_stack->plen;
	spkt.stack = stack;
	spkt.stack_index = stack_index;


	// Check if the packet is worth processing
	uint32_t cur_seq = stream->cur_seq[direction];
	if (cur_seq != seq) {
		if (packet_stream_is_packet_old_dupe(stream, &spkt, direction)) {
			// cur_seq is after the end of the packet, discard it
			packet_stream_end_process_packet(stream);
			debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : discard", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);
			return PROTO_OK;
		}

		if (packet_stream_remove_dupe_bytes(stream, &spkt, direction) == POM_ERR) {
			packet_stream_end_process_packet(stream);
			return PROTO_ERR;
		}
	}


	// Ok let's process it then

	// Check if it is the packet we're waiting for
	if (packet_stream_is_packet_next(stream, &spkt, direction)) {

		// Process it
		stream->cur_seq[direction] += cur_stack->plen;
		stream->cur_ack[direction] = ack;
		debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : process", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);

		int res = stream->handler(stream->ce, pkt, stack, stack_index);
		if (res == PROTO_ERR) {
			packet_stream_end_process_packet(stream);
			return PROTO_ERR;
		}

		// Check if additional packets can be processed
		struct packet_stream_pkt *p = NULL;
		unsigned int cur_dir = direction, additional_processed = 0;
		while ((p = packet_stream_get_next(stream, &cur_dir))) {


			debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : process additional", pthread_self(), stream, p->pkt->ts.tv_sec, p->pkt->ts.tv_usec, p->seq, p->ack);

			if (stream->handler(stream->ce, p->pkt, p->stack, p->stack_index) == POM_ERR) {
				packet_stream_end_process_packet(stream);
				return PROTO_ERR;
			}

			stream->cur_seq[cur_dir] += p->plen;
			stream->cur_ack[cur_dir] = p->ack;
	
			packet_stream_free_packet(p);

			additional_processed = 1;
		}

		if (additional_processed) {
			if (!stream->head[POM_DIR_FWD] && !stream->head[POM_DIR_REV])
				conntrack_timer_dequeue(stream->t);
			else
				conntrack_timer_queue(stream->t, stream->same_dir_timeout);
		}

		packet_stream_end_process_packet(stream);
		debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : done processed", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);
		return res;
	}

	// Queue the packet then

	debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : queue", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);

	struct packet_stream_pkt *p = malloc(sizeof(struct packet_stream_pkt));
	if (!p) {
		pom_oom(sizeof(struct packet_stream_pkt));
		packet_stream_end_process_packet(stream);
		return PROTO_ERR;
	}
	memset(p, 0 , sizeof(struct packet_stream_pkt));


	if (cur_stack->plen) {
		// No need to backup this if there is no payload
		p->pkt = packet_clone(pkt, stream->flags);
		if (!p->pkt) {
			packet_stream_end_process_packet(stream);
			free(p);
			return PROTO_ERR;
		}
		p->stack = core_stack_backup(stack, pkt, p->pkt);
		if (!p->stack) {
			packet_stream_end_process_packet(stream);
			packet_pool_release(p->pkt);
			free(p);
			return PROTO_ERR;
		}
	}


	p->plen = cur_stack->plen;
	p->seq = seq;
	p->ack = ack;
	p->stack_index = stack_index;


	if (!stream->tail[direction]) {
		stream->head[direction] = p;
		stream->tail[direction] = p;
	} else { 

		struct packet_stream_pkt *tmp = stream->tail[direction];
		while ( tmp && 
			((tmp->seq >= seq && tmp->seq - seq < PACKET_HALF_SEQ)
			|| (tmp->seq <= seq && seq - tmp->seq > PACKET_HALF_SEQ))) {

			tmp = tmp->prev;

		}

		if (!tmp) {
			// Packet goes at the begining of the list
			p->next = stream->head[direction];
			if (p->next)
				p->next->prev = p;
			else
				stream->tail[direction] = p;
			stream->head[direction] = p;

		} else {
			// Insert the packet after the current one
			p->next = tmp->next;
			p->prev = tmp;

			if (p->next)
				p->next->prev = p;
			else
				stream->tail[direction] = p;

			tmp->next = p;

		}
	}
	
	stream->cur_buff_size += cur_stack->plen;

	
	if (stream->cur_buff_size >= stream->max_buff_size) {
		// Buffer overflow
		debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : buffer overflow, forced dequeue", pthread_self(), stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);
		if (packet_stream_force_dequeue(stream) != POM_OK) {
			packet_stream_end_process_packet(stream);
			return POM_ERR;
		}

		if (stream->t)
			conntrack_timer_dequeue(stream->t);
	}

	// Add timeout
	if (stream->t && (stream->head[POM_DIR_FWD] || stream->head[POM_DIR_REV])) 
		conntrack_timer_queue(stream->t, stream->same_dir_timeout);
	packet_stream_end_process_packet(stream);

	debug_stream("thread %p, entry %p, packet %u.%06u, seq %u, ack %u : done queued", pthread_self(),  stream, pkt->ts.tv_sec, pkt->ts.tv_usec, seq, ack);
	return PROTO_OK;
}
Exemplo n.º 25
0
struct registry_config_entry* registry_config_list() {

	struct dataset_query *dsq_config_list = NULL;

	struct registry_config_entry *list = NULL;
	ssize_t list_size = 0;

	struct datastore *sys_dstore = system_datastore();
	if (!sys_dstore)
		return NULL;

	struct datastore_connection *dc = datastore_connection_new(sys_dstore);
	if (!dc)
		return NULL;

	dsq_config_list = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG_LIST, registry_config_list_dataset_template, dc);
	if (!dsq_config_list)
		goto err;

	int res;

	while ((res = datastore_dataset_read(dsq_config_list)) != DATASET_QUERY_OK) {
		if (res < 0)
			goto err;

		if (dsq_config_list->values[0].is_null || dsq_config_list->values[1].is_null) {
			pomlog(POMLOG_ERR "Got NULL values while they were not supposed to be !");
			goto err;
		}

		
		struct registry_config_entry *new_list = realloc(list, sizeof(struct registry_config_entry) * (list_size + 2));
		if (!new_list) {
			pom_oom(sizeof(struct registry_config_entry) * (list_size + 2));
			goto err;
		}
		list = new_list;
		memset(&list[list_size], 0, sizeof(struct registry_config_entry) * 2);

		char *name = PTYPE_STRING_GETVAL(dsq_config_list->values[0].value);
		strncpy(list[list_size].name, name, REGISTRY_CONFIG_NAME_MAX - 1);
		list[list_size].ts = *PTYPE_TIMESTAMP_GETVAL(dsq_config_list->values[1].value);

		list_size++;
	}

	datastore_dataset_query_cleanup(dsq_config_list);

	datastore_connection_release(dc);

	return list;
err:
	if (dsq_config_list)
		datastore_dataset_query_cleanup(dsq_config_list);

	if (dc)
		datastore_connection_release(dc);

	if (list)
		free(list);

	return NULL;
}
Exemplo n.º 26
0
static int proto_smtp_process(void *proto_priv, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct proto_process_stack *s = &stack[stack_index];
	struct proto_process_stack *s_next = &stack[stack_index + 1];

	if (conntrack_get_unique_from_parent(stack, stack_index) != POM_OK) {
		pomlog(POMLOG_ERR "Could not get conntrack entry");
		return PROTO_ERR;
	}

	// There should no need to keep the lock here since we are in the packet_stream lock from proto_tcp
	conntrack_unlock(s->ce);

	struct proto_smtp_priv *ppriv = proto_priv;

	struct proto_smtp_conntrack_priv *priv = s->ce->priv;
	if (!priv) {
		priv = malloc(sizeof(struct proto_smtp_conntrack_priv));
		if (!priv) {
			pom_oom(sizeof(struct proto_smtp_conntrack_priv));
			return PROTO_ERR;
		}
		memset(priv, 0, sizeof(struct proto_smtp_conntrack_priv));

		priv->parser[POM_DIR_FWD] = packet_stream_parser_alloc(SMTP_MAX_LINE, PACKET_STREAM_PARSER_FLAG_TRIM);
		if (!priv->parser[POM_DIR_FWD]) {
			free(priv);
			return PROTO_ERR;
		}

		priv->parser[POM_DIR_REV] = packet_stream_parser_alloc(SMTP_MAX_LINE, PACKET_STREAM_PARSER_FLAG_TRIM);
		if (!priv->parser[POM_DIR_REV]) {
			packet_stream_parser_cleanup(priv->parser[POM_DIR_FWD]);
			free(priv);
			return PROTO_ERR;
		}

		priv->server_direction = POM_DIR_UNK;

		s->ce->priv = priv;
	}

	if (priv->flags & PROTO_SMTP_FLAG_INVALID)
		return PROTO_OK;

	struct packet_stream_parser *parser = priv->parser[s->direction];
	if (packet_stream_parser_add_payload(parser, s->pload, s->plen) != POM_OK)
		return PROTO_ERR;

	char *line = NULL;
	size_t len = 0;
	while (1) {

		// Some check to do prior to parse the payload
		
		if (s->direction == POM_DIR_REVERSE(priv->server_direction)) {
			if (priv->flags & PROTO_SMTP_FLAG_STARTTLS) {
				// Last command was a STARTTLS command, this is the TLS negociation
				// Since we can't parse this, mark it as invalid
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return PROTO_OK;

			} else if (priv->flags & PROTO_SMTP_FLAG_CLIENT_DATA) {

				// We are receiving payload data, check where the end is
				void *pload;
				size_t plen;
				packet_stream_parser_get_remaining(parser, &pload, &plen);

				if (!plen)
					return PROTO_OK;

				// Look for the "<CR><LF>.<CR><LF>" sequence
				if (priv->data_end_pos > 0) {
					
					// The previous packet ended with something that might be the final sequence
					// Check if we have the rest
					int i, found = 1;
					for (i = 0; i < PROTO_SMTP_DATA_END_LEN - priv->data_end_pos && i <= plen; i++) {
						if (*(char*)(pload + i) != PROTO_SMTP_DATA_END[priv->data_end_pos + i]) {
							found = 0;
							break;
						}
					}
					if (found) {
						// If we have already processed the dot after <CR><LF> there is no way to remove it
						// Thus we mark this connection as invalid. Most MTA will send at worst the last
						// 3 bytes of the end sequence in a sequence packet
						if (i != plen || (priv->data_end_pos >= 2 && plen < 3)) {
							pomlog(POMLOG_DEBUG "The final line was not at the of a packet as expected !");
							priv->flags |= PROTO_SMTP_FLAG_INVALID;
							event_process_end(priv->data_evt);
							priv->data_evt = NULL;
							return PROTO_OK;
						}
						s_next->pload = pload;
						s_next->plen = plen - PROTO_SMTP_DATA_END_LEN + 2; // The last line return is part of the payload
						priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA_END;

						priv->flags &= ~PROTO_SMTP_FLAG_CLIENT_DATA;
						priv->data_end_pos = 0;

						return PROTO_OK;
					}
					priv->data_end_pos = 0;
				}


				char *dotline = pom_strnstr(pload, PROTO_SMTP_DATA_END, plen);
				if (dotline) {
					if (pload + plen - PROTO_SMTP_DATA_END_LEN != dotline) {
						pomlog(POMLOG_DEBUG "The final line was not at the of a packet as expected !");
						priv->flags |= PROTO_SMTP_FLAG_INVALID;
						event_process_end(priv->data_evt);
						priv->data_evt = NULL;
						return PROTO_OK;
					}
					s_next->pload = pload;
					s_next->plen = plen - PROTO_SMTP_DATA_END_LEN + 2; // The last line return is part of the payload
					priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA_END;

					priv->flags &= ~PROTO_SMTP_FLAG_CLIENT_DATA;

				} else {
					// Check if the end of the payload contains part of the "<CR><LF>.<CR><LF>" sequence
					int i, found = 0;
					for (i = 1 ; (i < PROTO_SMTP_DATA_END_LEN) && (i <= plen); i++) {
						if (!memcmp(pload + plen - i, PROTO_SMTP_DATA_END, i)) {
							found = 1;
							break;
						}
					}

					if (found)
						priv->data_end_pos = i;

					s_next->pload = pload;
					s_next->plen = plen;
				}

				return PROTO_OK;
			}
		}

		// Process commands
		if (packet_stream_parser_get_line(parser, &line, &len) != POM_OK)
			return PROTO_ERR;

		if (!line)
			return PROTO_OK;

		if (!len) // Probably a missed packet
			return PROTO_OK;

		// Try to find the server direction
		if (priv->server_direction == POM_DIR_UNK) {
			unsigned int code = atoi(line);
			if (code > 0) {
				priv->server_direction = s->direction;
			} else {
				priv->server_direction = POM_DIR_REVERSE(s->direction);
			}
		}

		if (s->direction == priv->server_direction) {

			// Parse the response code and generate the event
			if ((len < 5) || // Server response is 3 digit error code, a space or hyphen and then at least one letter of text
				(line[3] != ' ' && line[3] != '-')) {
				pomlog(POMLOG_DEBUG "Too short or invalid response from server");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			int code = atoi(line);
			if (code == 0) {
				pomlog(POMLOG_DEBUG "Invalid response from server");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			if (event_has_listener(ppriv->evt_reply)) {

				struct data *evt_data = NULL;
				if (priv->reply_evt) {
					evt_data = event_get_data(priv->reply_evt);
					uint16_t cur_code = *PTYPE_UINT16_GETVAL(evt_data[proto_smtp_reply_code].value);
					if (cur_code != code) {
						pomlog(POMLOG_WARN "Multiline code not the same as previous line : %hu -> %hu", cur_code, code);
						event_process_end(priv->reply_evt);
						priv->reply_evt = NULL;
					}
				}


				if (!priv->reply_evt) {
					priv->reply_evt = event_alloc(ppriv->evt_reply);
					if (!priv->reply_evt)
						return PROTO_ERR;

					evt_data = event_get_data(priv->reply_evt);
					PTYPE_UINT16_SETVAL(evt_data[proto_smtp_reply_code].value, code);
					data_set(evt_data[proto_smtp_reply_code]);

				}

				if (len > 4) {
					struct ptype *txt = ptype_alloc("string");
					if (!txt)
						return PROTO_ERR;
					PTYPE_STRING_SETVAL_N(txt, line + 4, len - 4);
					if (data_item_add_ptype(evt_data, proto_smtp_reply_text, strdup("text"), txt) != POM_OK)
						return PROTO_ERR;
				}
				
				if (!event_is_started(priv->reply_evt))
					event_process_begin(priv->reply_evt, stack, stack_index, p->ts);
			}


			if (line[3] != '-') {
				// Last line in the response
				if (priv->reply_evt) {
					event_process_end(priv->reply_evt);
					priv->reply_evt = NULL;
				}
			}
			
			if (priv->flags & PROTO_SMTP_FLAG_STARTTLS) {
				// The last command was STARTTLS
				priv->flags &= ~PROTO_SMTP_FLAG_STARTTLS;
				if (code == 220) {
					// TLS has the go, we can't parse  from now so mark as invalid
					priv->flags |= PROTO_SMTP_FLAG_INVALID;
					return POM_OK;
				}
			}

		} else {

			// Client command

			if (len < 4) { // Client commands are at least 4 bytes long
				pomlog(POMLOG_DEBUG "Too short or invalid query from client");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			// Make sure it's a command by checking it's at least a four letter word
			int i;
			for (i = 0; i < 4; i++) {
				// In some case it can also be a base64 encoded word
				if (! ((line[i] >= 'A' && line[i] <= 'Z')
					|| (line[i] >= 'a' && line[i] <= 'z')
					|| (line[i] >= '0' && line [i] <= '9')
					|| line[i] == '='))
					break;
			}

			if ((i < 4)) {
				pomlog(POMLOG_DEBUG "Recieved invalid client command");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			if (!strncasecmp(line, "DATA", strlen("DATA")) && len == strlen("DATA")) {
				priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA;
			} else if (!strncasecmp(line, "STARTTLS", strlen("STARTTLS")) && len == strlen("STARTTLS")) {
				priv->flags |= PROTO_SMTP_FLAG_STARTTLS;
			}


			if (event_has_listener(ppriv->evt_cmd)) {
				struct event *evt = event_alloc(ppriv->evt_cmd);
				if (!evt)
					return PROTO_ERR;

				size_t cmdlen = len;
				char *space = memchr(line, ' ', len);
				if (space)
					cmdlen = space - line;

				struct data *evt_data = event_get_data(evt);
				PTYPE_STRING_SETVAL_N(evt_data[proto_smtp_cmd_name].value, line, cmdlen);
				data_set(evt_data[proto_smtp_cmd_name]);
				if (space) {
					PTYPE_STRING_SETVAL_N(evt_data[proto_smtp_cmd_arg].value, space + 1, len - 1 - cmdlen);
					data_set(evt_data[proto_smtp_cmd_arg]);
				}

				if (priv->flags & PROTO_SMTP_FLAG_CLIENT_DATA) {
					// The event ends at the end of the message
					priv->data_evt = evt;
					return event_process_begin(evt, stack, stack_index, p->ts);
				} else {
					return event_process(evt, stack, stack_index, p->ts);
				}
			}

		}



	}

	return PROTO_OK;

}
Exemplo n.º 27
0
Arquivo: core.c Projeto: k0a1a/pom-ng
int core_queue_packet(struct packet *p, unsigned int flags, unsigned int thread_affinity) {

	
	// Update the counters
	registry_perf_inc(p->input->perf_pkts_in, 1);
	registry_perf_inc(p->input->perf_bytes_in, p->len);

	if (!core_run)
		return POM_ERR;

	debug_core("Queuing packet %p (%u.%06u)", p, pom_ptime_sec(p->ts), pom_ptime_usec(p->ts));

	// Find the right thread to queue to

	struct core_processing_thread *t = NULL;
	if (flags & CORE_QUEUE_HAS_THREAD_AFFINITY) {
		t = core_processing_threads[thread_affinity % core_num_threads];
		pom_mutex_lock(&t->pkt_queue_lock);
	} else {
		static volatile unsigned int start = 0;
		unsigned int i;
		while (1) {
			unsigned int thread_id = start;
			for (i = 0; i < core_num_threads; i++) {
				thread_id++;
				if (thread_id >= core_num_threads)
					thread_id -= core_num_threads;
				t = core_processing_threads[thread_id];
				int res = pthread_mutex_trylock(&t->pkt_queue_lock);
				if (res == EBUSY) {
					// Thread is busy, go to the next one
					continue;
				} else if (res) {
					pomlog(POMLOG_ERR "Error while locking a processing thread pkt_queue mutex : %s", pom_strerror(res));
					abort();
					return POM_ERR;
				}

				// We've got the lock, check if it's ok to queue here
				if (t->pkt_count < CORE_THREAD_PKT_QUEUE_MAX) {
					// Use this thread
					break;
				}

				// Too many packets pending in this thread, go to the next one
				pom_mutex_unlock(&t->pkt_queue_lock);
			}

			if (i < core_num_threads) {
				// We locked on a thread
				start = thread_id;
				break;
			}

			// No thread found
			if (core_pkt_queue_count >= ((CORE_THREAD_PKT_QUEUE_MAX - 1) * core_num_threads)) {
				// Queue full
				if (flags & CORE_QUEUE_DROP_IF_FULL) {
					// TODO add dropped stats
					debug_core("Dropped packet %p (%u.%06u) to thread %u", p, pom_ptime_sec(p->ts), pom_ptime_usec(p->ts));
					return POM_OK;
				}

				// We're not going to drop this. Wait then
				debug_core("All queues full. Waiting ...");
				pom_mutex_lock(&core_pkt_queue_wait_lock);

				// Recheck the count after locking
				if (core_pkt_queue_count >= ((CORE_THREAD_PKT_QUEUE_MAX - 1) * core_num_threads)) {
					int res = pthread_cond_wait(&core_pkt_queue_wait_cond, &core_pkt_queue_wait_lock);
					if (res) {
						pomlog(POMLOG_ERR "Error while waiting for the core pkt_queue condition : %s", pom_strerror(res));
						abort();
					}
				}
				pom_mutex_unlock(&core_pkt_queue_wait_lock);

			}
		}

	}

	// We've got the thread's lock, add it to the queue

	struct core_packet_queue *tmp = NULL;
	if (t->pkt_queue_unused) {
		tmp = t->pkt_queue_unused;
		t->pkt_queue_unused = tmp->next;
	} else {
		tmp = malloc(sizeof(struct core_packet_queue));
		if (!tmp) {
			pom_mutex_unlock(&t->pkt_queue_lock);
			pom_oom(sizeof(struct core_packet_queue));
			return POM_ERR;
		}
	}

	tmp->pkt = p;
	tmp->next = NULL;
	if (t->pkt_queue_tail) {
		t->pkt_queue_tail->next = tmp;
	} else {
		t->pkt_queue_head = tmp;

		// The queue was empty, we need to signal it
		int res = pthread_cond_signal(&t->pkt_queue_cond);
		if (res) {
			pomlog(POMLOG_ERR "Error while signaling the thread pkt_queue restart condition : %s", pom_strerror(res));
			abort();
			return POM_ERR;
		}

	}
	t->pkt_queue_tail = tmp;

	t->pkt_count++;
	__sync_fetch_and_add(&core_pkt_queue_count, 1);

	registry_perf_inc(perf_pkt_queue, 1);

	debug_core("Queued packet %p (%u.%06u) to thread %u", p, pom_ptime_sec(p->ts), pom_ptime_usec(p->ts), t->thread_id);

	pom_mutex_unlock(&t->pkt_queue_lock);

	return POM_OK;
}
Exemplo n.º 28
0
static int proto_smtp_init(struct proto *proto, struct registry_instance *i) {

	if (proto_number_register("tcp", 25, proto) != POM_OK ||
		proto_number_register("tcp", 587, proto) != POM_OK)
		return POM_ERR;

	struct proto_smtp_priv *priv = malloc(sizeof(struct proto_smtp_priv));
	if (!priv) {
		pom_oom(sizeof(struct proto_smtp_priv));
		return POM_ERR;
	}
	memset(priv, 0, sizeof(struct proto_smtp_priv));

	proto_set_priv(proto, priv);

	// Register the smtp_cmd event
	static struct data_item_reg evt_cmd_data_items[PROTO_SMTP_EVT_CMD_DATA_COUNT] = { { 0 } };
	evt_cmd_data_items[proto_smtp_cmd_name].name = "name";
	evt_cmd_data_items[proto_smtp_cmd_name].value_type = ptype_get_type("string");
	evt_cmd_data_items[proto_smtp_cmd_arg].name = "arg";
	evt_cmd_data_items[proto_smtp_cmd_arg].value_type = ptype_get_type("string");

	static struct data_reg evt_cmd_data = {
		.items = evt_cmd_data_items,
		.data_count = PROTO_SMTP_EVT_CMD_DATA_COUNT
	};

	static struct event_reg_info proto_smtp_evt_cmd = { 0 };
	proto_smtp_evt_cmd.source_name = "proto_smtp";
	proto_smtp_evt_cmd.source_obj = proto;
	proto_smtp_evt_cmd.name = "smtp_cmd";
	proto_smtp_evt_cmd.description = "SMTP command from the client";
	proto_smtp_evt_cmd.data_reg = &evt_cmd_data;

	priv->evt_cmd = event_register(&proto_smtp_evt_cmd);
	if (!priv->evt_cmd)
		goto err;

	// Register the smtp_reply event
	static struct data_item_reg evt_reply_data_items[PROTO_SMTP_EVT_CMD_DATA_COUNT] = { { 0 } };
	evt_reply_data_items[proto_smtp_reply_code].name = "code";
	evt_reply_data_items[proto_smtp_reply_code].value_type = ptype_get_type("uint16");
	evt_reply_data_items[proto_smtp_reply_text].name = "text";
	evt_reply_data_items[proto_smtp_reply_text].flags = DATA_REG_FLAG_LIST;

	static struct data_reg evt_reply_data = {
		.items = evt_reply_data_items,
		.data_count = PROTO_SMTP_EVT_REPLY_DATA_COUNT
	};

	static struct event_reg_info proto_smtp_evt_reply = { 0 };
	proto_smtp_evt_reply.source_name = "proto_smtp";
	proto_smtp_evt_reply.source_obj = proto;
	proto_smtp_evt_reply.name = "smtp_reply";
	proto_smtp_evt_reply.description = "SMTP command from the client";
	proto_smtp_evt_reply.data_reg = &evt_reply_data;

	priv->evt_reply = event_register(&proto_smtp_evt_reply);
	if (!priv->evt_reply)
		goto err;

	return POM_OK;

err:
	proto_smtp_cleanup(priv);
	return POM_ERR;
}
Exemplo n.º 29
0
int proto_register(struct proto_reg_info *reg_info) {

    if (reg_info->api_ver != PROTO_API_VER) {
        pomlog(POMLOG_ERR "Cannot register proto as API version differ : expected %u got %u", PROTO_API_VER, reg_info->api_ver);
        return POM_ERR;
    }


    // Check if the protocol already exists
    struct proto *proto;
    for (proto = proto_head; proto && strcmp(proto->info->name, reg_info->name); proto = proto->next);
    if (proto)
        return POM_ERR;

    // Allocate the protocol
    proto = malloc(sizeof(struct proto));
    if (!proto) {
        pom_oom(sizeof(struct proto));
        return POM_ERR;
    }

    memset(proto, 0, sizeof(struct proto));
    proto->info = reg_info;
    proto->id = proto_count;
    proto_count++;

    if (reg_info->number_class) {
        proto->number_class = proto_number_class_get(reg_info->number_class);
        if (!proto->number_class)
            goto err_proto;
    }

    int res = pthread_rwlock_init(&proto->expectation_lock, NULL);
    if (res) {
        pomlog(POMLOG_ERR "Error while initializing the proto_expectation rwlock : %s", pom_strerror(res));
        goto err_proto;
    }

    res = pthread_rwlock_init(&proto->listeners_lock, NULL);
    if (res) {
        pomlog(POMLOG_ERR "Error while initializing the proto_listeners rwlock : %s", pom_strerror(res));
        goto err_lock1;
    }

    proto->reg_instance = registry_add_instance(proto_registry_class, reg_info->name);
    if (!proto->reg_instance) {
        pomlog(POMLOG_ERR "Error while adding the registry instanc for protocol %s", reg_info->name);
        goto err_lock;
    }


    // Allocate the conntrack table
    if (reg_info->ct_info) {
        proto->ct = conntrack_table_alloc(reg_info->ct_info->default_table_size, (reg_info->ct_info->rev_pkt_field_id == -1 ? 0 : 1));
        if (!proto->ct) {
            pomlog(POMLOG_ERR "Error while allocating conntrack tables");
            goto err_registry;
        }

        proto->perf_conn_cur = registry_instance_add_perf(proto->reg_instance, "conn_cur", registry_perf_type_gauge, "Current number of monitored connection", "connections");
        proto->perf_conn_tot = registry_instance_add_perf(proto->reg_instance, "conn_tot", registry_perf_type_counter, "Total number of connections", "connections");
        proto->perf_conn_hash_col = registry_instance_add_perf(proto->reg_instance, "conn_hash_col", registry_perf_type_counter, "Total number of conntrack hash collisions", "collisions");

        if (!proto->perf_conn_cur || !proto->perf_conn_tot || !proto->perf_conn_hash_col)
            goto err_conntrack;

    }

    proto->perf_pkts = registry_instance_add_perf(proto->reg_instance, "pkts", registry_perf_type_counter, "Number of packets processed", "pkts");
    proto->perf_bytes = registry_instance_add_perf(proto->reg_instance, "bytes", registry_perf_type_counter, "Number of bytes processed", "bytes");
    proto->perf_expt_pending = registry_instance_add_perf(proto->reg_instance, "expectations_pending", registry_perf_type_gauge, "Number of expectations pending", "expectations");
    proto->perf_expt_matched = registry_instance_add_perf(proto->reg_instance, "expectations_matched", registry_perf_type_counter, "Number of expectations matched", "expectations");

    if (!proto->perf_pkts || !proto->perf_bytes || !proto->perf_expt_pending || !proto->perf_expt_matched)
        goto err_conntrack;

    if (reg_info->init) {
        if (reg_info->init(proto, proto->reg_instance) == POM_ERR) {
            pomlog(POMLOG_ERR "Error while registering proto %s", reg_info->name);
            goto err_conntrack;
        }
    }

    mod_refcount_inc(reg_info->mod);

    proto->next = proto_head;
    if (proto->next)
        proto->next->prev = proto;
    proto_head = proto;

    pomlog(POMLOG_DEBUG "Proto %s registered", reg_info->name);

    return POM_OK;

err_conntrack:
    // Remove proto number if any
    proto_number_unregister(proto);
    conntrack_table_cleanup(proto->ct);
err_registry:
    registry_remove_instance(proto->reg_instance);
err_lock:
    pthread_rwlock_destroy(&proto->listeners_lock);
err_lock1:
    pthread_rwlock_destroy(&proto->expectation_lock);
err_proto:
    free(proto);

    return POM_ERR;

}
Exemplo n.º 30
0
int conntrack_get(struct proto_process_stack *stack, unsigned int stack_index) {

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

	if (s->ce)
		return POM_OK;
		
	if (!s->proto || !s->proto->info->ct_info)
		return POM_ERR;

	struct ptype *fwd_value = s->pkt_info->fields_value[s->proto->info->ct_info->fwd_pkt_field_id];
	if (!fwd_value)
		return POM_ERR;

	struct ptype *rev_value = NULL;
	if (s->proto->info->ct_info->rev_pkt_field_id != CONNTRACK_PKT_FIELD_NONE) {
		rev_value = s->pkt_info->fields_value[s->proto->info->ct_info->rev_pkt_field_id];
		if (!rev_value)
			return POM_ERR;
	}

	struct conntrack_tables *ct = s->proto->ct;

	uint32_t hash = conntrack_hash(fwd_value, rev_value, s_prev->ce) % ct->table_size;

	// Lock the specific hash while browsing for a conntrack
	pom_mutex_lock(&ct->locks[hash]);

	// Try to find the conntrack in the forward table

	// Check if we can find this entry in the forward way
	if (ct->table[hash]) {
		s->ce = conntrack_find(ct->table[hash], fwd_value, rev_value, s_prev->ce);
		if (s->ce) {
			s->direction = POM_DIR_FWD;
			s_next->direction = POM_DIR_FWD;
			pom_mutex_lock(&s->ce->lock);
			s->ce->refcount++;
			pom_mutex_unlock(&ct->locks[hash]);
			return POM_OK;;
		}
	}


	// It wasn't found in the forward way, maybe in the reverse direction ?
	if (rev_value) {
		s->ce = conntrack_find(ct->table[hash], rev_value, fwd_value, s_prev->ce);
		if (s->ce) {
			s->direction = POM_DIR_REV;
			s_next->direction = POM_DIR_REV;
			pom_mutex_lock(&s->ce->lock);
			s->ce->refcount++;
			pom_mutex_unlock(&ct->locks[hash]);
			return POM_OK;
		}

	}

	// It's not found in the reverse direction either, let's create it then

	if (s_prev->direction == POM_DIR_REV && rev_value) {
		// This indicates that the parent conntrack matched in a reverse direction
		// Let's keep directions consistent and swap fwd and rev values
		struct ptype *tmp = rev_value;
		rev_value = fwd_value;
		fwd_value = tmp;
	}


	// Alloc the conntrack entry
	struct conntrack_entry *ce = malloc(sizeof(struct conntrack_entry));
	if (!ce) {
		pom_mutex_unlock(&ct->locks[hash]);
		pom_oom(sizeof(struct conntrack_entry));
		return POM_ERR;
	}
	memset(ce, 0, sizeof(struct conntrack_entry));

	if (pom_mutex_init_type(&ce->lock, PTHREAD_MUTEX_ERRORCHECK) != POM_OK) {
		pom_mutex_unlock(&ct->locks[hash]);
		free(ce);
		return POM_ERR;
	}

	struct conntrack_node_list *child = NULL;

	// We shouldn't have to check if the parent still exists as it
	// is supposed to have a refcount since conntrack_get is called after
	// the parent's conntrack_get was called and before conntrack_refcount_dec
	// was called by core_process_stack.
	if (s_prev->ce) {

		child = malloc(sizeof(struct conntrack_node_list));
		if (!child) {
			pthread_mutex_destroy(&ce->lock);
			pom_mutex_unlock(&ct->locks[hash]);
			free(ce);
			pom_oom(sizeof(struct conntrack_node_list));
			return POM_ERR;
		}
		memset(child, 0, sizeof(struct conntrack_node_list));

		child->ce = ce;
		child->ct = s->proto->ct;
		child->hash = hash;

		ce->parent = malloc(sizeof(struct conntrack_node_list));
		if (!ce->parent) {
			pthread_mutex_destroy(&ce->lock);
			pom_mutex_unlock(&ct->locks[hash]);
			free(child);
			free(ce);
			pom_oom(sizeof(struct conntrack_node_list));
			return POM_ERR;
		}
		ce->parent->ce = s_prev->ce;
		ce->parent->ct = s_prev->ce->proto->ct;
		ce->parent->hash = s_prev->ce->hash;

	}

	ce->proto = s->proto;

	ce->hash = hash;

	struct conntrack_list *lst = NULL;

	ce->fwd_value = ptype_alloc_from(fwd_value);
	if (!ce->fwd_value)
		goto err;

	if (rev_value) {
		ce->rev_value = ptype_alloc_from(rev_value);
		if (!ce->rev_value)
			goto err;
	}
	// Alloc the list node
	lst = malloc(sizeof(struct conntrack_list));
	if (!lst) {
		ptype_cleanup(ce->fwd_value);
		pom_oom(sizeof(struct conntrack_list));
		goto err;
	}
	memset(lst, 0, sizeof(struct conntrack_list));
	lst->ce = ce;

	// Insert in the conntrack table
	lst->next = ct->table[hash];
	if (lst->next) {
		lst->next->prev = lst;
		registry_perf_inc(s->proto->perf_conn_hash_col, 1);
	}
	ct->table[hash] = lst;

	// Add the child to the parent if any
	if (child) {
		pom_mutex_lock(&s_prev->ce->lock);
		if (!s_prev->ce->refcount)
			pomlog(POMLOG_WARN "Internal error, the parent is supposed to have a refcount > 0");
		child->next = s_prev->ce->children;
		if (child->next)
			child->next->prev = child;
		s_prev->ce->children = child;
		pom_mutex_unlock(&s_prev->ce->lock);
	}

	// Unlock the table
	if (s_prev->ce) {
		debug_conntrack("Allocated conntrack %p with parent %p", ce, s_prev->ce);
	} else {
		debug_conntrack("Allocated conntrack %p with no parent", ce);
	}
	pom_mutex_lock(&ce->lock);
	ce->refcount++;
	pom_mutex_unlock(&ct->locks[hash]);

	s->ce = ce;
	s->direction = s_prev->direction;

	// Propagate the direction to the payload as well
	s_next->direction = s->direction;
	
	registry_perf_inc(ce->proto->perf_conn_cur, 1);
	registry_perf_inc(ce->proto->perf_conn_tot, 1);

	return POM_OK;

err:
	pom_mutex_unlock(&ct->locks[hash]);

	pthread_mutex_destroy(&ce->lock);
	if (child)
		free(child);

	if (lst)
		free(lst);

	if (ce->parent)
		free(ce->parent);
	
	if (ce->fwd_value)
		ptype_cleanup(ce->fwd_value);

	if (ce->rev_value)
		ptype_cleanup(ce->rev_value);

	free(ce);

	return POM_ERR;
}