예제 #1
0
파일: packet.c 프로젝트: dkarametos/pom-ng
int packet_pool_release(struct packet *p) {

	struct packet_multipart *multipart = NULL;
	pom_mutex_lock(&packet_list_mutex);
	if (p->multipart) {
		multipart = p->multipart;
		p->multipart = NULL;
	}

	p->refcount--;
	if (p->refcount) {
		pom_mutex_unlock(&packet_list_mutex);
		if (multipart) // Always release the multipart
			return packet_multipart_cleanup(multipart);
		return POM_OK;
	}

	// Remove the packet from the used list
	if (p->next)
		p->next->prev = p->prev;

	if (p->prev)
		p->prev->next = p->next;
	else
		packet_head = p->next;

	if (p->pkt_buff) {
		packet_buffer_pool_release(p->pkt_buff);
		p->pkt_buff = NULL;
		p->buff = NULL;
	}

	memset(p, 0, sizeof(struct packet));
	
	// Add it back to the unused list

#ifdef PACKET_INFO_POOL_ALLOC_DEBUG
	free(p);
#else
	p->next = packet_unused_head;
	if (p->next)
		p->next->prev = p;
	packet_unused_head = p;
#endif
	pom_mutex_unlock(&packet_list_mutex);

	int res = POM_OK;

	if (multipart)
		res = packet_multipart_cleanup(multipart);



	return res;
}
예제 #2
0
파일: proto_ipv4.c 프로젝트: k0a1a/pom-ng
static int proto_ipv4_fragment_cleanup(struct conntrack_entry *ce, void *priv, ptime now) {

	struct proto_ipv4_fragment *f = priv;

	// Remove the frag from the conntrack
	if (f->prev)
		f->prev->next = f->next;
	else
		ce->priv = f->next;

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

	conntrack_unlock(ce);


	if (!(f->flags & PROTO_IPV4_FLAG_PROCESSED)) {
		registry_perf_inc(perf_frags_dropped, f->count);
	}

	if (f->multipart)
		packet_multipart_cleanup(f->multipart);
	
	if (f->t)
		conntrack_timer_cleanup(f->t);
	
	free(f);

	return POM_OK;

}
예제 #3
0
파일: packet.c 프로젝트: dkarametos/pom-ng
int packet_multipart_process(struct packet_multipart *multipart, struct proto_process_stack *stack, unsigned int stack_index) {

	struct packet *p = packet_pool_get();
	if (!p) {
		packet_multipart_cleanup(multipart);
		return PROTO_ERR;
	}


	// FIXME align offset
	if (packet_buffer_pool_get(p, multipart->cur, 0)) {
		packet_pool_release(p);
		packet_multipart_cleanup(multipart);
		pom_oom(multipart->cur);
		return PROTO_ERR;
	}

	struct packet_multipart_pkt *tmp = multipart->head;
	for (; tmp; tmp = tmp->next) {
		if (tmp->offset + tmp->len > multipart->cur) {
			pomlog(POMLOG_DEBUG "Offset in packet fragment is bigger than packet size.");
			packet_pool_release(p);
			packet_multipart_cleanup(multipart);
			return PROTO_INVALID;
		}
		memcpy(p->buff + tmp->offset, tmp->pkt->buff + tmp->pkt_buff_offset, tmp->len);
	}

	memcpy(&p->ts, &multipart->tail->pkt->ts, sizeof(struct timeval));
	
	p->multipart = multipart;
	p->len = multipart->cur;
	p->datalink = multipart->proto;
	p->input = multipart->head->pkt->input;
	stack[stack_index].pload = p->buff;
	stack[stack_index].plen = p->len;
	stack[stack_index].proto = p->datalink;

	int res = core_process_multi_packet(stack, stack_index, p);

	packet_pool_release(p);

	return res;
}
예제 #4
0
int packet_multipart_process(struct packet_multipart *multipart, struct proto_process_stack *stack, unsigned int stack_index) {

	struct packet *p = packet_alloc();
	if (!p) {
		packet_multipart_cleanup(multipart);
		return PROTO_ERR;
	}


	if (packet_buffer_alloc(p, multipart->cur, multipart->align_offset)) {
		packet_release(p);
		packet_multipart_cleanup(multipart);
		return PROTO_ERR;
	}

	struct packet_multipart_pkt *tmp = multipart->head;
	for (; tmp; tmp = tmp->next) {
		if (tmp->offset + tmp->len > multipart->cur) {
			pomlog(POMLOG_DEBUG "Offset in packet fragment is bigger than packet size.");
			packet_release(p);
			packet_multipart_cleanup(multipart);
			return PROTO_INVALID;
		}
		memcpy(p->buff + tmp->offset, tmp->pkt->buff + tmp->pkt_buff_offset, tmp->len);
	}

	p->ts = multipart->tail->pkt->ts;
	
	p->multipart = multipart;
	p->len = multipart->cur;
	p->datalink = multipart->proto;
	p->input = multipart->head->pkt->input;
	stack[stack_index].pload = p->buff;
	stack[stack_index].plen = p->len;
	stack[stack_index].proto = p->datalink;

	int res = core_process_multi_packet(stack, stack_index, p);

	packet_release(p);

	return (res == PROTO_ERR ? POM_ERR : POM_OK);
}
예제 #5
0
파일: packet.c 프로젝트: nomnom100/pom-ng
int packet_release(struct packet *p) {

    // Release the multipart
    struct packet_multipart *multipart = __sync_fetch_and_and(&p->multipart, 0);
    if (multipart && packet_multipart_cleanup(multipart) != POM_OK)
        return POM_ERR;

    // The packet refcount will be 0 afterwards
    // We can clean up the buffer if any
    if (p->refcount > 1) {
        __sync_fetch_and_sub(&p->refcount, 1);
        return POM_OK;
    }

    if (p->pkt_buff)
        packet_buffer_release(p->pkt_buff);

    registry_perf_dec(perf_pkt_in_use, 1);
    free(p);

    return POM_OK;
}
예제 #6
0
파일: proto_ipv4.c 프로젝트: k0a1a/pom-ng
static int proto_ipv4_conntrack_cleanup(void *ce_priv) {

	struct proto_ipv4_fragment *frag_list = ce_priv;

	while (frag_list) {
		struct proto_ipv4_fragment *f = frag_list;
		frag_list = f->next;

		if (!(f->flags & PROTO_IPV4_FLAG_PROCESSED)) {
			registry_perf_inc(perf_frags_dropped, f->count);
		}

		if (f->multipart)
			packet_multipart_cleanup(f->multipart);
		
		if (f->t)
			conntrack_timer_cleanup(f->t);
		
		free(f);

	}

	return POM_OK;
}
예제 #7
0
파일: proto_ipv4.c 프로젝트: k0a1a/pom-ng
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

}