Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: nf_conntrack: Introduces nf_ct_get_tuplepr and uses it

nf_ct_get_tuple() requires the offset to transport header and that bothers
callers such as icmp[v6] l4proto modules. This introduces new function
to simplify them.

Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Yasuyuki Kozakai and committed by
David S. Miller
e2a3123f ffc30690

+49 -59
+4
include/net/netfilter/nf_conntrack.h
··· 186 186 187 187 extern void nf_conntrack_flush(void); 188 188 189 + extern int nf_ct_get_tuplepr(const struct sk_buff *skb, 190 + unsigned int nhoff, 191 + u_int16_t l3num, 192 + struct nf_conntrack_tuple *tuple); 189 193 extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, 190 194 const struct nf_conntrack_tuple *orig); 191 195
+7 -25
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
··· 136 136 unsigned int hooknum) 137 137 { 138 138 struct nf_conntrack_tuple innertuple, origtuple; 139 - struct { 140 - struct icmphdr icmp; 141 - struct iphdr ip; 142 - } _in, *inside; 143 139 struct nf_conntrack_l4proto *innerproto; 144 140 struct nf_conntrack_tuple_hash *h; 145 - int dataoff; 146 141 147 142 NF_CT_ASSERT(skb->nfct == NULL); 148 143 149 - /* Not enough header? */ 150 - inside = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_in), &_in); 151 - if (inside == NULL) 152 - return -NF_ACCEPT; 153 - 154 - /* Ignore ICMP's containing fragments (shouldn't happen) */ 155 - if (inside->ip.frag_off & htons(IP_OFFSET)) { 156 - pr_debug("icmp_error_message: fragment of proto %u\n", 157 - inside->ip.protocol); 144 + /* Are they talking about one of our connections? */ 145 + if (!nf_ct_get_tuplepr(skb, 146 + skb_network_offset(skb) + ip_hdrlen(skb) 147 + + sizeof(struct icmphdr), 148 + PF_INET, &origtuple)) { 149 + pr_debug("icmp_error_message: failed to get tuple\n"); 158 150 return -NF_ACCEPT; 159 151 } 160 152 161 153 /* rcu_read_lock()ed by nf_hook_slow */ 162 - innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); 163 - 164 - dataoff = ip_hdrlen(skb) + sizeof(inside->icmp); 165 - /* Are they talking about one of our connections? */ 166 - if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, 167 - inside->ip.protocol, &origtuple, 168 - &nf_conntrack_l3proto_ipv4, innerproto)) { 169 - pr_debug("icmp_error_message: ! get_tuple p=%u", 170 - inside->ip.protocol); 171 - return -NF_ACCEPT; 172 - } 154 + innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum); 173 155 174 156 /* Ordinarily, we'd expect the inverted tupleproto, but it's 175 157 been preserved inside the ICMP. */
+8 -34
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
··· 136 136 { 137 137 struct nf_conntrack_tuple intuple, origtuple; 138 138 struct nf_conntrack_tuple_hash *h; 139 - struct icmp6hdr _hdr, *hp; 140 - unsigned int inip6off; 141 139 struct nf_conntrack_l4proto *inproto; 142 - u_int8_t inprotonum; 143 - unsigned int inprotoff; 144 140 145 141 NF_CT_ASSERT(skb->nfct == NULL); 146 142 147 - hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr); 148 - if (hp == NULL) { 149 - pr_debug("icmpv6_error: Can't get ICMPv6 hdr.\n"); 150 - return -NF_ACCEPT; 151 - } 152 - 153 - inip6off = icmp6off + sizeof(_hdr); 154 - if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr), 155 - &inprotonum, sizeof(inprotonum)) != 0) { 156 - pr_debug("icmpv6_error: Can't get nexthdr in inner IPv6 " 157 - "header.\n"); 158 - return -NF_ACCEPT; 159 - } 160 - inprotoff = nf_ct_ipv6_skip_exthdr(skb, 161 - inip6off + sizeof(struct ipv6hdr), 162 - &inprotonum, 163 - skb->len - inip6off 164 - - sizeof(struct ipv6hdr)); 165 - 166 - if ((inprotoff > skb->len) || (inprotonum == NEXTHDR_FRAGMENT)) { 167 - pr_debug("icmpv6_error: Can't get protocol header in ICMPv6 " 168 - "payload.\n"); 143 + /* Are they talking about one of our connections? */ 144 + if (!nf_ct_get_tuplepr(skb, 145 + skb_network_offset(skb) 146 + + sizeof(struct ipv6hdr) 147 + + sizeof(struct icmp6hdr), 148 + PF_INET6, &origtuple)) { 149 + pr_debug("icmpv6_error: Can't get tuple\n"); 169 150 return -NF_ACCEPT; 170 151 } 171 152 172 153 /* rcu_read_lock()ed by nf_hook_slow */ 173 - inproto = __nf_ct_l4proto_find(PF_INET6, inprotonum); 174 - 175 - /* Are they talking about one of our connections? */ 176 - if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, 177 - &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) { 178 - pr_debug("icmpv6_error: Can't get tuple\n"); 179 - return -NF_ACCEPT; 180 - } 154 + inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum); 181 155 182 156 /* Ordinarily, we'd expect the inverted tupleproto, but it's 183 157 been preserved inside the ICMP. */
+30
net/netfilter/nf_conntrack_core.c
··· 113 113 } 114 114 EXPORT_SYMBOL_GPL(nf_ct_get_tuple); 115 115 116 + int nf_ct_get_tuplepr(const struct sk_buff *skb, 117 + unsigned int nhoff, 118 + u_int16_t l3num, 119 + struct nf_conntrack_tuple *tuple) 120 + { 121 + struct nf_conntrack_l3proto *l3proto; 122 + struct nf_conntrack_l4proto *l4proto; 123 + unsigned int protoff; 124 + u_int8_t protonum; 125 + int ret; 126 + 127 + rcu_read_lock(); 128 + 129 + l3proto = __nf_ct_l3proto_find(l3num); 130 + ret = l3proto->get_l4proto(skb, nhoff, &protoff, &protonum); 131 + if (ret != NF_ACCEPT) { 132 + rcu_read_unlock(); 133 + return 0; 134 + } 135 + 136 + l4proto = __nf_ct_l4proto_find(l3num, protonum); 137 + 138 + ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, tuple, 139 + l3proto, l4proto); 140 + 141 + rcu_read_unlock(); 142 + return ret; 143 + } 144 + EXPORT_SYMBOL_GPL(nf_ct_get_tuplepr); 145 + 116 146 int 117 147 nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, 118 148 const struct nf_conntrack_tuple *orig,