/* * Function to get the tuple out of a given struct sk_buff. */ bool nat64_get_tuple(u_int8_t l3protocol, u_int8_t l4protocol, struct sk_buff *skb, struct nf_conntrack_tuple * inner) { const struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_l3proto *l3proto; int l3_hdrlen, ret; unsigned int protoff = 0; u_int8_t protonum = 0; pr_debug("NAT64: Getting the protocol and header length"); /* * Get L3 header length */ l3_hdrlen = nat64_get_l3hdrlen(skb, l3protocol); if (l3_hdrlen == -1) { pr_debug("NAT64: Something went wrong getting the" " l3 header length"); return false; } /* * Get L3 struct to access it's functions. */ if (!(nat64_get_l3struct(l3protocol, &l3proto))) return false; if (l3proto == NULL) { pr_info("NAT64: nat64_get_tuple - the l3proto pointer is null"); return false; } rcu_read_lock(); pr_debug("NAT64: l3_hdrlen = %d", l3_hdrlen); /* * Gets the structure with the respective L4 protocol functions. */ ret = l3proto->get_l4proto(skb, skb_network_offset(skb), &protoff, &protonum); if (ret != NF_ACCEPT) { pr_info("NAT64: nat64_get_tuple - error getting the L4 offset"); pr_debug("NAT64: ret = %d", ret); pr_debug("NAT64: protoff = %u", protoff); rcu_read_unlock(); return false; } else if (protonum != l4protocol) { pr_info("NAT64: nat64_get_tuple - protocols don't match"); pr_debug("NAT64: protonum = %u", protonum); pr_debug("NAT64: l4protocol = %u", l4protocol); rcu_read_unlock(); return false; } l4proto = __nf_ct_l4proto_find(l3protocol, l4protocol); pr_debug("l4proto name = %s %d %d", l4proto->name, (u_int32_t)l4proto->l3proto, (u_int32_t)l4proto->l4proto); /* * Get the tuple out of the sk_buff. */ if (!nf_ct_get_tuple(skb, skb_network_offset(skb), l3_hdrlen, (u_int16_t)l3protocol, l4protocol, inner, l3proto, l4proto)) { pr_debug("NAT64: couldn't get the tuple"); rcu_read_unlock(); return false; } pr_debug("\nPRINTED TUPLE"); nat64_print_tuple(inner); pr_debug("\n"); rcu_read_unlock(); return true; }
/* Returns conntrack if it dealt with ICMP, and filled in skb fields */ static int icmp_error_message(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, unsigned int hooknum) { struct nf_conntrack_tuple innertuple, origtuple; struct { struct icmphdr icmp; struct iphdr ip; } _in, *inside; struct nf_conntrack_l4proto *innerproto; struct nf_conntrack_tuple_hash *h; int dataoff; NF_CT_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_message: fragment of proto %u\n", inside->ip.protocol); return -NF_ACCEPT; } innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); /* Are they talking about one of our connections? */ if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, inside->ip.protocol, &origtuple, &nf_conntrack_l3proto_ipv4, innerproto)) { DEBUGP("icmp_error_message: ! get_tuple p=%u", inside->ip.protocol); return -NF_ACCEPT; } /* Ordinarily, we'd expect the inverted tupleproto, but it's been preserved inside the ICMP. */ if (!nf_ct_invert_tuple(&innertuple, &origtuple, &nf_conntrack_l3proto_ipv4, innerproto)) { DEBUGP("icmp_error_message: no match\n"); return -NF_ACCEPT; } *ctinfo = IP_CT_RELATED; h = nf_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 = nf_conntrack_find_get(&origtuple, NULL); if (!h) { DEBUGP("icmp_error_message: no match\n"); return -NF_ACCEPT; } /* Reverse direction from that found */ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) *ctinfo += IP_CT_IS_REPLY; } else { if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) *ctinfo += IP_CT_IS_REPLY; } /* Update skb to refer to this connection */ skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general; skb->nfctinfo = *ctinfo; return -NF_ACCEPT; }