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; }
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; }