static int timeout_ct_or_exp(const struct ip_conntrack_tuple *t)
{
	struct ip_conntrack_tuple_hash *h;
	struct ip_conntrack_expect *exp;

	DEBUGP("trying to timeout ct or exp for tuple ");
	DUMP_TUPLE(t);

	h = __ip_conntrack_find(t, NULL);
	if (h)  {
		struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
		DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
		sibling->proto.gre.timeout = 0;
		sibling->proto.gre.stream_timeout = 0;
		/* refresh_acct will not modify counters if skb == NULL */
		ip_ct_refresh_acct(sibling, 0, NULL, 0);
		return 1;
	} else {
		exp = __ip_conntrack_exp_find(t);
		if (exp) {
			DEBUGP("unexpect_related of expect %p\n", exp);
			ip_conntrack_unexpect_related(exp);
			return 1;
		}
	}

	return 0;
}
static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
{
	struct ip_conntrack_tuple_hash *h;
	struct ip_conntrack_expect *exp;

	DEBUGP("trying to timeout ct or exp for tuple ");
	DUMP_TUPLE(t);

	h = ip_conntrack_find_get(t, NULL);
	if (h)  {
		struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
		DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
		sibling->proto.gre.timeout = 0;
		sibling->proto.gre.stream_timeout = 0;
		if (del_timer(&sibling->timeout))
			sibling->timeout.function((unsigned long)sibling);
		ip_conntrack_put(sibling);
		return 1;
	} else {
		exp = ip_conntrack_expect_find(t);
		if (exp) {
			DEBUGP("unexpect_related of expect %p\n", exp);
			ip_conntrack_unexpect_related(exp);
			ip_conntrack_expect_put(exp);
			return 1;
		}
	}

	return 0;
}
/* return 0 on success, 1 in case of error */
static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash,
			    struct seq_file *s)
{
	const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash);
	struct ip_conntrack_protocol *proto;

	MUST_BE_READ_LOCKED(&ip_conntrack_lock);

	IP_NF_ASSERT(conntrack);

	/* we only want to print DIR_ORIGINAL */
	if (DIRECTION(hash))
		return 0;

	proto = ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
			       .tuple.dst.protonum);
	IP_NF_ASSERT(proto);

	if (seq_printf(s, "%-8s %u %lu ",
		      proto->name,
		      conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
		      timer_pending(&conntrack->timeout)
		      ? (conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
		return 1;

	if (proto->print_conntrack(s, conntrack))
		return 1;
  
	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
			proto))
		return 1;

 	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
		return 1;

	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
		if (seq_printf(s, "[UNREPLIED] "))
			return 1;

	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
			proto))
		return 1;

 	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
		return 1;

	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
		if (seq_printf(s, "[ASSURED] "))
			return 1;

#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
	if (seq_printf(s, "mark=%ld ", conntrack->mark))
		return 1;
#endif

	if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
		return 1;

	return 0;
}
Exemple #4
0
static int count_them(struct xt_connlimit_data *data,
		      const struct ip_conntrack_tuple *tuple, const __be32 addr,
		      const __be32 mask, const struct xt_match *match)
{
	struct ip_conntrack_tuple_hash *found;
	struct xt_connlimit_conn *conn;
	struct xt_connlimit_conn *tmp;
	struct ip_conntrack *found_ct;
	struct list_head *hash;
	bool addit = true;
	int matches = 0;


	hash = &data->iphash[connlimit_iphash(addr & mask)];

	read_lock_bh(&ip_conntrack_lock);

	/* check the saved connections */
	list_for_each_entry_safe(conn, tmp, hash, list) {
		found    = __ip_conntrack_find(&conn->tuple, NULL);
		found_ct = NULL;

		if (found != NULL)
			found_ct = tuplehash_to_ctrack(found);

		if (found_ct != NULL &&
		    ip_ct_tuple_equal(&conn->tuple, tuple) &&
		    !already_closed(found_ct))
			/*
			 * Just to be sure we have it only once in the list.
			 * We should not see tuples twice unless someone hooks
			 * this into a table without "-p tcp --syn".
			 */
			addit = false;

		if (found == NULL) {
			/* this one is gone */
			list_del(&conn->list);
			kfree(conn);
			continue;
		}

		if (already_closed(found_ct)) {
			/*
			 * we do not care about connections which are
			 * closed already -> ditch it
			 */
			list_del(&conn->list);
			kfree(conn);
			continue;
		}

		if (same_source_net(addr, mask, conn->tuple.src.ip,
		    match->family))
			/* same source network -> be counted! */
			++matches;
	}
static int
icmp_error_message(struct sk_buff *skb,
		   enum ip_conntrack_info *ctinfo,
		   unsigned int hooknum)
{
	struct ip_conntrack_tuple innertuple, origtuple;
	struct {
		struct icmphdr icmp;
		struct iphdr ip;
	} _in, *inside;
	struct ip_conntrack_protocol *innerproto;
	struct ip_conntrack_tuple_hash *h;
	int dataoff;

	IP_NF_ASSERT(skb->nfct == NULL);

	/* Not enough header? */
	inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
	if (inside == NULL)
		return -NF_ACCEPT;

	/* Ignore ICMP's containing fragments (shouldn't happen) */
	if (inside->ip.frag_off & htons(IP_OFFSET)) {
		DEBUGP("icmp_error_track: fragment of proto %u\n",
		       inside->ip.protocol);
		return -NF_ACCEPT;
	}

	innerproto = ip_conntrack_proto_find_get(inside->ip.protocol);
	dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp) + inside->ip.ihl*4;
	/* Are they talking about one of our connections? */
	if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) {
		DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol);
		ip_conntrack_proto_put(innerproto);
		return -NF_ACCEPT;
	}

	/* Ordinarily, we'd expect the inverted tupleproto, but it's
	   been preserved inside the ICMP. */
	if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
		DEBUGP("icmp_error_track: Can't invert tuple\n");
		ip_conntrack_proto_put(innerproto);
		return -NF_ACCEPT;
	}
	ip_conntrack_proto_put(innerproto);

	*ctinfo = IP_CT_RELATED;

	h = ip_conntrack_find_get(&innertuple, NULL);
	if (!h) {
		/* Locally generated ICMPs will match inverted if they
		   haven't been SNAT'ed yet */
		/* FIXME: NAT code has to handle half-done double NAT --RR */
		if (hooknum == NF_IP_LOCAL_OUT)
			h = ip_conntrack_find_get(&origtuple, NULL);

		if (!h) {
			DEBUGP("icmp_error_track: no match\n");
			return -NF_ACCEPT;
		}
		/* Reverse direction from that found */
		if (DIRECTION(h) != IP_CT_DIR_REPLY)
			*ctinfo += IP_CT_IS_REPLY;
	} else {
		if (DIRECTION(h) == IP_CT_DIR_REPLY)
			*ctinfo += IP_CT_IS_REPLY;
	}

	/* Update skb to refer to this connection */
	skb->nfct = &tuplehash_to_ctrack(h)->ct_general;
	skb->nfctinfo = *ctinfo;
	return -NF_ACCEPT;
}