Пример #1
0
int proto_process(struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

    struct proto_process_stack *s = &stack[stack_index];

    struct proto *proto = s->proto;

    if (!proto || !proto->info->process)
        return PROTO_ERR;
    int res = proto->info->process(proto->priv, p, stack, stack_index);

    registry_perf_inc(proto->perf_pkts, 1);
    registry_perf_inc(proto->perf_bytes, s->plen);


    if (res != PROTO_OK)
        return res;

    // Process the expectations !
    pom_rwlock_rlock(&proto->expectation_lock);
    struct proto_expectation *e = proto->expectations;
    while (e) {

        int expt_dir = POM_DIR_UNK;

        struct proto_expectation_stack *es = e->tail;
        struct ptype *fwd_value = s->pkt_info->fields_value[s->proto->info->ct_info->fwd_pkt_field_id];
        struct ptype *rev_value = s->pkt_info->fields_value[s->proto->info->ct_info->rev_pkt_field_id];

        if ((!es->fields[POM_DIR_FWD] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) &&
                (!es->fields[POM_DIR_REV] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) {
            // Expectation matched the forward direction
            expt_dir = POM_DIR_FWD;
        } else if ((!es->fields[POM_DIR_FWD] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) &&
                   (!es->fields[POM_DIR_REV] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) {
            // Expectation matched the reverse direction
            expt_dir = POM_DIR_REV;
        }

        if (expt_dir == POM_DIR_UNK) {
            // Expectation not matched
            e = e->next;
            continue;
        }

        es = es->prev;
        int stack_index_tmp = stack_index - 1;
        while (es) {

            struct proto_process_stack *s_tmp = &stack[stack_index_tmp];

            if (s_tmp->proto != es->proto) {
                e = e->next;
                continue;
            }

            fwd_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->fwd_pkt_field_id];
            rev_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->rev_pkt_field_id];

            if (expt_dir == POM_DIR_FWD) {
                if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) ||
                        (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) {
                    e = e->next;
                    continue;
                }
            } else {
                if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) ||
                        (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) {
                    e = e->next;
                    continue;
                }

            }

            es = es->prev;
            stack_index_tmp--;
        }

        // Expectation matched !
        // Relock with write access
        pom_rwlock_unlock(&proto->expectation_lock);
        pom_rwlock_wlock(&proto->expectation_lock);

        debug_expectation("Expectation %p matched !", e);

        // Remove it from the list

        if (e->next)
            e->next->prev = e->prev;

        if (e->prev)
            e->prev->next = e->next;
        else
            proto->expectations = e->next;

        struct proto_process_stack *s_next = &stack[stack_index + 1];
        s_next->proto = e->proto;


        if (conntrack_get_unique_from_parent(stack, stack_index + 1) != POM_OK) {
            proto_expectation_cleanup(e);
            return PROTO_ERR;
        }

        s_next->ce->priv = e->priv;

        if (conntrack_session_bind(s_next->ce, e->session)) {
            proto_expectation_cleanup(e);
            return PROTO_ERR;
        }

        registry_perf_dec(e->proto->perf_expt_pending, 1);
        registry_perf_inc(e->proto->perf_expt_matched, 1);

        proto_expectation_cleanup(e);
        conntrack_unlock(s_next->ce);

        break;

    }
    pom_rwlock_unlock(&proto->expectation_lock);

    return res;
}
Пример #2
0
int proto_process(struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct proto_process_stack *s = &stack[stack_index];

	struct proto *proto = s->proto;

	if (!proto || !proto->info->process)
		return PROTO_ERR;
	int res = proto->info->process(proto->priv, p, stack, stack_index);

	registry_perf_inc(proto->perf_pkts, 1);
	registry_perf_inc(proto->perf_bytes, s->plen);

	if (res != PROTO_OK)
		return res;

	int matched = 0;

	// Process the expectations !
	pom_rwlock_rlock(&proto->expectation_lock);
	struct proto_expectation *e = NULL;
	for (e = proto->expectations; e; e = e->next) {

		if (e->flags & PROTO_EXPECTATION_FLAG_MATCHED) {
			// Another thread already matched the expectation, continue
			continue;
		}
		
		// Bit one means it matches the forward direction
		// Bit two means it matches the reverse direction

		int expt_dir = 3;

		struct proto_expectation_stack *es = e->tail;
		int stack_index_tmp = stack_index;
		while (es) {

			struct proto_process_stack *s_tmp = &stack[stack_index_tmp];

			if (s_tmp->proto != es->proto) {
				expt_dir = 0;
				break;
			}

			struct ptype *fwd_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->fwd_pkt_field_id];
			struct ptype *rev_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->rev_pkt_field_id];

			if (expt_dir & 1) {
				if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) ||
					(es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) {
					expt_dir &= ~1; // It doesn't match in the forward direction
				}
			}

			if (expt_dir & 2) {
				if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) ||
					(es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) {
					expt_dir &= ~2;
				}
			}

			if (!expt_dir)
				break;

			es = es->prev;
			stack_index_tmp--;
		}

		if (expt_dir) {
			// It matched
			if (!(__sync_fetch_and_or(&e->flags, PROTO_EXPECTATION_FLAG_MATCHED) & PROTO_EXPECTATION_FLAG_MATCHED)) {
				// Something matched
				matched++;
			}
		}
	}
	pom_rwlock_unlock(&proto->expectation_lock);

	if (!matched)
		return POM_OK;

	// At least one expectation matched !
	debug_expectation("%u expectation matched !", matched);

	// Relock with write access
	pom_rwlock_wlock(&proto->expectation_lock);
	e = proto->expectations;
	while (e) {

		struct proto_expectation *cur = e;
		e = e->next;

		if (!(cur->flags & PROTO_EXPECTATION_FLAG_MATCHED))
			continue;

		// Remove the expectation from the conntrack
		if (cur->next)
			cur->next->prev = cur->prev;
		if (cur->prev)
			cur->prev->next = cur->next;
		else
			proto->expectations = cur->next;

		// Remove matched and queued flags
		__sync_fetch_and_and(&cur->flags, ~(PROTO_EXPECTATION_FLAG_MATCHED | PROTO_EXPECTATION_FLAG_QUEUED));

		struct proto_process_stack *s_next = &stack[stack_index + 1];
		s_next->proto = cur->proto;

		if (conntrack_get_unique_from_parent(stack, stack_index + 1) != POM_OK) {
			proto_expectation_cleanup(cur);
			continue;
		}

		if (!s_next->ce->priv) {
			s_next->ce->priv = cur->priv;
			// Prevent cleanup of private data while cleaning the expectation
			cur->priv = NULL;
		}


		if (cur->session) {
			if (conntrack_session_bind(s_next->ce, cur->session)) {
				proto_expectation_cleanup(cur);
				continue;
			}
		}

		registry_perf_dec(cur->proto->perf_expt_pending, 1);
		registry_perf_inc(cur->proto->perf_expt_matched, 1);

		if (cur->match_callback) {
			// Call the callback with the conntrack locked
			cur->match_callback(cur, cur->callback_priv, s_next->ce);
			// Nullify callback_priv so it doesn't get cleaned up
			cur->callback_priv = NULL;
		}

		if (cur->expiry) {
			// The expectation was added using 'add_and_cleanup' function
			proto_expectation_cleanup(cur);
		}

		conntrack_unlock(s_next->ce);

	}
	pom_rwlock_unlock(&proto->expectation_lock);


	return res;
}