Blame view
net/netfilter/nf_conntrack_proto_icmpv6.c
8.14 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
9fb9cbb10 [NETFILTER]: Add ... |
2 3 4 |
/* * Copyright (C)2003,2004 USAGI/WIDE Project * |
9fb9cbb10 [NETFILTER]: Add ... |
5 6 |
* Author: * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> |
9fb9cbb10 [NETFILTER]: Add ... |
7 8 9 |
*/ #include <linux/types.h> |
9fb9cbb10 [NETFILTER]: Add ... |
10 11 12 13 14 15 16 17 18 19 20 |
#include <linux/timer.h> #include <linux/module.h> #include <linux/netfilter.h> #include <linux/in6.h> #include <linux/icmpv6.h> #include <linux/ipv6.h> #include <net/ipv6.h> #include <net/ip6_checksum.h> #include <linux/seq_file.h> #include <linux/netfilter_ipv6.h> #include <net/netfilter/nf_conntrack_tuple.h> |
605dcad6c [NETFILTER]: nf_c... |
21 |
#include <net/netfilter/nf_conntrack_l4proto.h> |
9fb9cbb10 [NETFILTER]: Add ... |
22 |
#include <net/netfilter/nf_conntrack_core.h> |
c779e8496 netfilter: conntr... |
23 |
#include <net/netfilter/nf_conntrack_timeout.h> |
5d0aa2ccd netfilter: nf_con... |
24 |
#include <net/netfilter/nf_conntrack_zones.h> |
f01ffbd6e [NETFILTER]: nf_l... |
25 |
#include <net/netfilter/nf_log.h> |
9fb9cbb10 [NETFILTER]: Add ... |
26 |
|
cb8aa9a3a netfilter: ctnetl... |
27 |
#include "nf_internals.h" |
2c9e8637e netfilter: conntr... |
28 |
static const unsigned int nf_ct_icmpv6_timeout = 30*HZ; |
9fb9cbb10 [NETFILTER]: Add ... |
29 |
|
e2e48b471 netfilter: conntr... |
30 31 32 33 |
bool icmpv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct net *net, struct nf_conntrack_tuple *tuple) |
9fb9cbb10 [NETFILTER]: Add ... |
34 |
{ |
7cc3864d3 [NETFILTER]: nf_{... |
35 36 |
const struct icmp6hdr *hp; struct icmp6hdr _hdr; |
9fb9cbb10 [NETFILTER]: Add ... |
37 38 39 |
hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (hp == NULL) |
09f263cd3 [NETFILTER]: nf_c... |
40 |
return false; |
9fb9cbb10 [NETFILTER]: Add ... |
41 42 43 |
tuple->dst.u.icmp.type = hp->icmp6_type; tuple->src.u.icmp.id = hp->icmp6_identifier; tuple->dst.u.icmp.code = hp->icmp6_code; |
09f263cd3 [NETFILTER]: nf_c... |
44 |
return true; |
9fb9cbb10 [NETFILTER]: Add ... |
45 |
} |
c1d10adb4 [NETFILTER]: Add ... |
46 |
/* Add 1; spaces filled with 0. */ |
7cc3864d3 [NETFILTER]: nf_{... |
47 |
static const u_int8_t invmap[] = { |
c1d10adb4 [NETFILTER]: Add ... |
48 49 |
[ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, |
a51f42f3c netfilter: fix tu... |
50 |
[ICMPV6_NI_QUERY - 128] = ICMPV6_NI_REPLY + 1, |
f9527ea9b netfilter: ipv6: ... |
51 |
[ICMPV6_NI_REPLY - 128] = ICMPV6_NI_QUERY + 1 |
c1d10adb4 [NETFILTER]: Add ... |
52 |
}; |
3f9007135 netfilter: nf_con... |
53 54 |
static const u_int8_t noct_valid_new[] = { [ICMPV6_MGM_QUERY - 130] = 1, |
f9527ea9b netfilter: ipv6: ... |
55 |
[ICMPV6_MGM_REPORT - 130] = 1, |
3f9007135 netfilter: nf_con... |
56 57 58 59 60 61 62 |
[ICMPV6_MGM_REDUCTION - 130] = 1, [NDISC_ROUTER_SOLICITATION - 130] = 1, [NDISC_ROUTER_ADVERTISEMENT - 130] = 1, [NDISC_NEIGHBOUR_SOLICITATION - 130] = 1, [NDISC_NEIGHBOUR_ADVERTISEMENT - 130] = 1, [ICMPV6_MLD2_REPORT - 130] = 1 }; |
197c4300a netfilter: conntr... |
63 64 |
bool nf_conntrack_invert_icmpv6_tuple(struct nf_conntrack_tuple *tuple, const struct nf_conntrack_tuple *orig) |
9fb9cbb10 [NETFILTER]: Add ... |
65 |
{ |
f16c91072 [NETFILTER]: nf_c... |
66 67 |
int type = orig->dst.u.icmp.type - 128; if (type < 0 || type >= sizeof(invmap) || !invmap[type]) |
09f263cd3 [NETFILTER]: nf_c... |
68 |
return false; |
9fb9cbb10 [NETFILTER]: Add ... |
69 70 71 72 |
tuple->src.u.icmp.id = orig->src.u.icmp.id; tuple->dst.u.icmp.type = invmap[type] - 1; tuple->dst.u.icmp.code = orig->dst.u.icmp.code; |
09f263cd3 [NETFILTER]: nf_c... |
73 |
return true; |
9fb9cbb10 [NETFILTER]: Add ... |
74 |
} |
2c8503f55 netfilter: nf_con... |
75 76 |
static unsigned int *icmpv6_get_timeouts(struct net *net) { |
a95a7774d netfilter: conntr... |
77 |
return &nf_icmpv6_pernet(net)->timeout; |
2c8503f55 netfilter: nf_con... |
78 |
} |
9fb9cbb10 [NETFILTER]: Add ... |
79 |
/* Returns verdict for packet, or -1 for invalid. */ |
a47c54048 netfilter: conntr... |
80 81 82 83 |
int nf_conntrack_icmpv6_packet(struct nf_conn *ct, struct sk_buff *skb, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) |
9fb9cbb10 [NETFILTER]: Add ... |
84 |
{ |
c779e8496 netfilter: conntr... |
85 |
unsigned int *timeout = nf_ct_timeout_lookup(ct); |
9976fc6e6 netfilter: conntr... |
86 87 88 89 |
static const u8 valid_new[] = { [ICMPV6_ECHO_REQUEST - 128] = 1, [ICMPV6_NI_QUERY - 128] = 1 }; |
dd2934a95 netfilter: conntr... |
90 91 |
if (state->pf != NFPROTO_IPV6) return -NF_ACCEPT; |
9976fc6e6 netfilter: conntr... |
92 93 94 95 96 97 98 99 100 101 102 103 |
if (!nf_ct_is_confirmed(ct)) { int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128; if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) { /* Can't create a new ICMPv6 `conn' with this. */ pr_debug("icmpv6: can't create new conn with type %u ", type + 128); nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); return -NF_ACCEPT; } } |
c779e8496 netfilter: conntr... |
104 105 106 |
if (!timeout) timeout = icmpv6_get_timeouts(nf_ct_net(ct)); |
f87fb666b netfilter: nf_ct_... |
107 108 109 |
/* Do not immediately delete the connection after the first successful reply to avoid excessive conntrackd traffic and also to handle correctly ICMP echo reply duplicates. */ |
2c8503f55 netfilter: nf_con... |
110 |
nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
9fb9cbb10 [NETFILTER]: Add ... |
111 112 113 |
return NF_ACCEPT; } |
9fb9cbb10 [NETFILTER]: Add ... |
114 |
|
93e66024b netfilter: conntr... |
115 116 117 |
static void icmpv6_error_log(const struct sk_buff *skb, const struct nf_hook_state *state, const char *msg) |
c4f3db159 netfilter: conntr... |
118 |
{ |
93e66024b netfilter: conntr... |
119 120 |
nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_ICMPV6, "%s", msg); |
c4f3db159 netfilter: conntr... |
121 |
} |
6fe78fa48 netfilter: conntr... |
122 123 124 125 |
int nf_conntrack_icmpv6_error(struct nf_conn *tmpl, struct sk_buff *skb, unsigned int dataoff, const struct nf_hook_state *state) |
9fb9cbb10 [NETFILTER]: Add ... |
126 |
{ |
1025ce752 netfilter: conntr... |
127 |
union nf_inet_addr outer_daddr; |
7cc3864d3 [NETFILTER]: nf_{... |
128 129 |
const struct icmp6hdr *icmp6h; struct icmp6hdr _ih; |
3f9007135 netfilter: nf_con... |
130 |
int type; |
9fb9cbb10 [NETFILTER]: Add ... |
131 132 133 |
icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); if (icmp6h == NULL) { |
93e66024b netfilter: conntr... |
134 |
icmpv6_error_log(skb, state, "short packet"); |
9fb9cbb10 [NETFILTER]: Add ... |
135 136 |
return -NF_ACCEPT; } |
93e66024b netfilter: conntr... |
137 138 139 140 |
if (state->hook == NF_INET_PRE_ROUTING && state->net->ct.sysctl_checksum && nf_ip6_checksum(skb, state->hook, dataoff, IPPROTO_ICMPV6)) { icmpv6_error_log(skb, state, "ICMPv6 checksum failed"); |
9fb9cbb10 [NETFILTER]: Add ... |
141 142 |
return -NF_ACCEPT; } |
3f9007135 netfilter: nf_con... |
143 144 145 |
type = icmp6h->icmp6_type - 130; if (type >= 0 && type < sizeof(noct_valid_new) && noct_valid_new[type]) { |
cc41c84b7 netfilter: kill t... |
146 |
nf_ct_set(skb, NULL, IP_CT_UNTRACKED); |
3f9007135 netfilter: nf_con... |
147 148 |
return NF_ACCEPT; } |
9fb9cbb10 [NETFILTER]: Add ... |
149 150 151 |
/* is not error message ? */ if (icmp6h->icmp6_type >= 128) return NF_ACCEPT; |
1025ce752 netfilter: conntr... |
152 153 154 155 156 |
memcpy(&outer_daddr.ip6, &ipv6_hdr(skb)->daddr, sizeof(outer_daddr.ip6)); dataoff += sizeof(*icmp6h); return nf_conntrack_inet_error(tmpl, skb, dataoff, state, IPPROTO_ICMPV6, &outer_daddr); |
9fb9cbb10 [NETFILTER]: Add ... |
157 |
} |
07a936260 ipv6: use IS_ENAB... |
158 |
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
c1d10adb4 [NETFILTER]: Add ... |
159 160 161 |
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_conntrack.h> |
fdf708322 [NETFILTER]: nfne... |
162 |
static int icmpv6_tuple_to_nlattr(struct sk_buff *skb, |
c1d10adb4 [NETFILTER]: Add ... |
163 164 |
const struct nf_conntrack_tuple *t) { |
e549a6b3a netfilter: ipv6: ... |
165 166 167 168 |
if (nla_put_be16(skb, CTA_PROTO_ICMPV6_ID, t->src.u.icmp.id) || nla_put_u8(skb, CTA_PROTO_ICMPV6_TYPE, t->dst.u.icmp.type) || nla_put_u8(skb, CTA_PROTO_ICMPV6_CODE, t->dst.u.icmp.code)) goto nla_put_failure; |
c1d10adb4 [NETFILTER]: Add ... |
169 |
return 0; |
df6fb868d [NETFILTER]: nfne... |
170 |
nla_put_failure: |
c1d10adb4 [NETFILTER]: Add ... |
171 172 |
return -1; } |
f73e924cd [NETFILTER]: ctne... |
173 174 175 176 |
static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = { [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 }, [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 }, [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 }, |
c1d10adb4 [NETFILTER]: Add ... |
177 |
}; |
fdf708322 [NETFILTER]: nfne... |
178 |
static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], |
cb8aa9a3a netfilter: ctnetl... |
179 180 |
struct nf_conntrack_tuple *tuple, u_int32_t flags) |
c1d10adb4 [NETFILTER]: Add ... |
181 |
{ |
cb8aa9a3a netfilter: ctnetl... |
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_TYPE)) { if (!tb[CTA_PROTO_ICMPV6_TYPE]) return -EINVAL; tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); if (tuple->dst.u.icmp.type < 128 || tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || !invmap[tuple->dst.u.icmp.type - 128]) return -EINVAL; } if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_CODE)) { if (!tb[CTA_PROTO_ICMPV6_CODE]) return -EINVAL; tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); } if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_ID)) { if (!tb[CTA_PROTO_ICMPV6_ID]) return -EINVAL; tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); } |
c1d10adb4 [NETFILTER]: Add ... |
206 207 208 |
return 0; } |
a400c30ed netfilter: nf_con... |
209 |
|
5caaed151 netfilter: conntr... |
210 |
static unsigned int icmpv6_nlattr_tuple_size(void) |
a400c30ed netfilter: nf_con... |
211 |
{ |
5caaed151 netfilter: conntr... |
212 213 214 215 216 217 |
static unsigned int size __read_mostly; if (!size) size = nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1); return size; |
a400c30ed netfilter: nf_con... |
218 |
} |
c1d10adb4 [NETFILTER]: Add ... |
219 |
#endif |
a874752a1 netfilter: conntr... |
220 |
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
509784623 netfilter: add ct... |
221 222 223 |
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_cttimeout.h> |
8264deb81 netfilter: nf_con... |
224 225 |
static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], struct net *net, void *data) |
509784623 netfilter: add ct... |
226 227 |
{ unsigned int *timeout = data; |
a95a7774d netfilter: conntr... |
228 |
struct nf_icmp_net *in = nf_icmpv6_pernet(net); |
509784623 netfilter: add ct... |
229 |
|
c779e8496 netfilter: conntr... |
230 231 |
if (!timeout) timeout = icmpv6_get_timeouts(net); |
509784623 netfilter: add ct... |
232 233 234 235 236 |
if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) { *timeout = ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ; } else { /* Set default ICMPv6 timeout. */ |
8264deb81 netfilter: nf_con... |
237 |
*timeout = in->timeout; |
509784623 netfilter: add ct... |
238 239 240 241 242 243 244 245 |
} return 0; } static int icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) { const unsigned int *timeout = data; |
e549a6b3a netfilter: ipv6: ... |
246 247 |
if (nla_put_be32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ))) goto nla_put_failure; |
509784623 netfilter: add ct... |
248 249 250 251 252 253 254 255 256 257 |
return 0; nla_put_failure: return -ENOSPC; } static const struct nla_policy icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = { [CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 }, }; |
a874752a1 netfilter: conntr... |
258 |
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
509784623 netfilter: add ct... |
259 |
|
2a389de86 netfilter: conntr... |
260 |
void nf_conntrack_icmpv6_init_net(struct net *net) |
8fc027816 netfilter: nf_ct_... |
261 |
{ |
a95a7774d netfilter: conntr... |
262 |
struct nf_icmp_net *in = nf_icmpv6_pernet(net); |
8fc027816 netfilter: nf_ct_... |
263 264 |
in->timeout = nf_ct_icmpv6_timeout; |
08911475d netfilter: nf_con... |
265 |
} |
9dae47aba netfilter: conntr... |
266 |
const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 = |
9fb9cbb10 [NETFILTER]: Add ... |
267 |
{ |
605dcad6c [NETFILTER]: nf_c... |
268 |
.l4proto = IPPROTO_ICMPV6, |
07a936260 ipv6: use IS_ENAB... |
269 |
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
fdf708322 [NETFILTER]: nfne... |
270 |
.tuple_to_nlattr = icmpv6_tuple_to_nlattr, |
a400c30ed netfilter: nf_con... |
271 |
.nlattr_tuple_size = icmpv6_nlattr_tuple_size, |
fdf708322 [NETFILTER]: nfne... |
272 |
.nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
f73e924cd [NETFILTER]: ctne... |
273 |
.nla_policy = icmpv6_nla_policy, |
c1d10adb4 [NETFILTER]: Add ... |
274 |
#endif |
a874752a1 netfilter: conntr... |
275 |
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
509784623 netfilter: add ct... |
276 277 278 279 280 281 282 |
.ctnl_timeout = { .nlattr_to_obj = icmpv6_timeout_nlattr_to_obj, .obj_to_nlattr = icmpv6_timeout_obj_to_nlattr, .nlattr_max = CTA_TIMEOUT_ICMP_MAX, .obj_size = sizeof(unsigned int), .nla_policy = icmpv6_timeout_nla_policy, }, |
a874752a1 netfilter: conntr... |
283 |
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
9fb9cbb10 [NETFILTER]: Add ... |
284 |
}; |