示例#1
0
文件: proto.c 项目: nomnom100/pom-ng
static struct proto_expectation_stack *proto_expectation_stack_alloc(struct proto *p, struct ptype *fwd_value, struct ptype *rev_value) {

    if (!p || !fwd_value)
        return NULL;

    struct proto_expectation_stack *es = malloc(sizeof(struct proto_expectation_stack));
    if (!es) {
        pom_oom(sizeof(struct proto_expectation_stack));
        return NULL;
    }
    memset(es, 0, sizeof(struct proto_expectation_stack));
    es->proto = p;

    es->fields[POM_DIR_FWD] = ptype_alloc_from(fwd_value);
    if (!es->fields[POM_DIR_FWD]) {
        free(es);
        return NULL;
    }

    if (rev_value) {
        es->fields[POM_DIR_REV] = ptype_alloc_from(rev_value);
        if (!es->fields[POM_DIR_REV]) {
            ptype_cleanup(es->fields[POM_DIR_FWD]);
            free(es);
            return NULL;
        }
    }

    return es;
}
示例#2
0
static struct proto_expectation_stack *proto_expectation_stack_alloc(struct proto *p, struct ptype *fwd_value, struct ptype *rev_value) {

	if (!p || !fwd_value) {
		pomlog(POMLOG_ERR "Cannot allocate expectation with a forward nor reverse conntrack entry field value");
		return NULL;
	}

	struct proto_expectation_stack *es = malloc(sizeof(struct proto_expectation_stack));
	if (!es) {
		pom_oom(sizeof(struct proto_expectation_stack));
		return NULL;
	}
	memset(es, 0, sizeof(struct proto_expectation_stack));
	es->proto = p;

	es->fields[POM_DIR_FWD] = ptype_alloc_from(fwd_value);
	if (!es->fields[POM_DIR_FWD]) {
		free(es);
		return NULL;
	}

	if (rev_value) {
		es->fields[POM_DIR_REV] = ptype_alloc_from(rev_value);
		if (!es->fields[POM_DIR_REV]) {
			ptype_cleanup(es->fields[POM_DIR_FWD]);
			free(es);
			return NULL;
		}
	}

	return es;
}
示例#3
0
static int analyzer_smtp_event_fetch_common_data(struct analyzer_smtp_ce_priv *cpriv, struct proto_process_stack *stack, unsigned int stack_index, int server_direction) {

	struct  proto_process_stack *l4_stack = &stack[stack_index - 1];
	struct  proto_process_stack *l3_stack = &stack[stack_index - 2];

	int i;

	char *port_str = "dport";
	if (server_direction == POM_DIR_REV)
		port_str = "sport";
	
	for (i = 0; !cpriv->server_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 (!strcmp(name, port_str))
			cpriv->server_port = *PTYPE_UINT16_GETVAL(l4_stack->pkt_info->fields_value[i]);
	}


	struct ptype *src = NULL, *dst = NULL;
	for (i = 0; !src || !dst; 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 (!src && !strcmp(name, "src"))
			src = l3_stack->pkt_info->fields_value[i];
		else if (!dst && !strcmp(name, "dst"))
			dst = l3_stack->pkt_info->fields_value[i];
	}

	if (server_direction == POM_DIR_FWD) {
		if (src)
			cpriv->client_addr = ptype_alloc_from(src);
		if (dst)
			cpriv->server_addr = ptype_alloc_from(dst);
	} else {
		if (src)
			cpriv->server_addr = ptype_alloc_from(src);
		if (dst)
			cpriv->client_addr = ptype_alloc_from(dst);
	}

	if (cpriv->server_addr) {
		char *host = dns_reverse_lookup_ptype(cpriv->server_addr);
		if (host)
			cpriv->server_host = host;
	}

	cpriv->common_data_fetched = 1;

	return POM_OK;
}
示例#4
0
文件: proto.c 项目: nomnom100/pom-ng
int proto_expectation_set_field(struct proto_expectation *e, int stack_index, struct ptype *value, int direction) {

    struct proto_expectation_stack *es = NULL;

    int i;
    if (stack_index > 0) {
        es = e->head;
        for (i = 1; es && i < stack_index; i++)
            es = es->next;
    } else {
        stack_index = -stack_index;
        es = e->tail;
        for (i = 1; es && i < stack_index; i++)
            es = es->prev;
    }

    if (!es) {
        pomlog(POMLOG_ERR "Invalid stack index in the expectation");
        return POM_ERR;
    }

    if (es->fields[direction]) {
        ptype_cleanup(es->fields[direction]);
        es->fields[direction] = NULL;
    }

    if (value) {
        es->fields[direction] = ptype_alloc_from(value);
        if (!es->fields[direction])
            return POM_ERR;
    }

    return POM_OK;
}
示例#5
0
static int analyzer_smtp_event_fill_common_data(struct analyzer_smtp_ce_priv *cpriv, struct data *data) {

	if (cpriv->client_hello) {
		PTYPE_STRING_SETVAL(data[analyzer_smtp_common_client_hello].value, cpriv->client_hello);
		data_set(data[analyzer_smtp_common_client_hello]);
	}

	if (cpriv->server_hello) {
		PTYPE_STRING_SETVAL(data[analyzer_smtp_common_server_hello].value, cpriv->server_hello);
		data_set(data[analyzer_smtp_common_server_hello]);
	}

	if (cpriv->client_addr) {
		data[analyzer_smtp_common_client_addr].value = ptype_alloc_from(cpriv->client_addr);
		data[analyzer_smtp_common_client_addr].flags &= ~DATA_FLAG_NO_CLEAN;
		if (data[analyzer_smtp_common_client_addr].value)
			data_set(data[analyzer_smtp_common_client_addr]);
	}

	if (cpriv->server_addr) {
		data[analyzer_smtp_common_server_addr].value = ptype_alloc_from(cpriv->server_addr);
		data[analyzer_smtp_common_server_addr].flags &= ~DATA_FLAG_NO_CLEAN;
		if (data[analyzer_smtp_common_server_addr].value)
			data_set(data[analyzer_smtp_common_server_addr]);
	}

	if (cpriv->server_port) {
		PTYPE_UINT16_SETVAL(data[analyzer_smtp_common_server_port].value, cpriv->server_port);
		data_set(data[analyzer_smtp_common_server_port]);
	}

	if (cpriv->server_host) {
		PTYPE_STRING_SETVAL(data[analyzer_smtp_common_server_host].value, cpriv->server_host);
		data_set(data[analyzer_smtp_common_server_host]);
	}

	return POM_OK;

}
示例#6
0
文件: registry.c 项目: k0a1a/pom-ng
int registry_set_param_value(struct registry_param *p, char *value) {

	if (!p || !value)
		return POM_ERR;

	if (p->flags & REGISTRY_PARAM_FLAG_IMMUTABLE)
		return POM_ERR;
	
	if (p->set_pre_callback && p->set_pre_callback(p->callback_priv, value) != POM_OK) {
		return POM_ERR;
	}

	core_pause_processing();

	struct ptype *old_value = ptype_alloc_from(p->value);

	if (ptype_parse_val(p->value, value) != POM_OK) {
		core_resume_processing();
		ptype_cleanup(old_value);
		return POM_ERR;
	}

	if (p->set_post_callback && p->set_post_callback(p->callback_priv, p->value) != POM_OK) {
		// Revert the old value
		ptype_copy(p->value, old_value);
		core_resume_processing();
		ptype_cleanup(old_value);
		return POM_ERR;
	}

	core_resume_processing();

	ptype_cleanup(old_value);
	
	return POM_OK;

}
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) {
                    conntrack_unlock(s->ce);
                    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;

}
示例#8
0
文件: registry.c 项目: k0a1a/pom-ng
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;

}
示例#9
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;
}
示例#10
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;
}