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