This source file includes following definitions.
- icmp_pkt_to_tuple
- nf_conntrack_invert_icmp_tuple
- nf_conntrack_icmp_packet
- nf_conntrack_inet_error
- icmp_error_log
- nf_conntrack_icmpv4_error
- icmp_tuple_to_nlattr
- icmp_nlattr_to_tuple
- icmp_nlattr_tuple_size
- icmp_timeout_nlattr_to_obj
- icmp_timeout_obj_to_nlattr
- nf_conntrack_icmp_init_net
1
2
3
4
5
6
7 #include <linux/types.h>
8 #include <linux/timer.h>
9 #include <linux/netfilter.h>
10 #include <linux/in.h>
11 #include <linux/icmp.h>
12 #include <linux/seq_file.h>
13 #include <net/ip.h>
14 #include <net/checksum.h>
15 #include <linux/netfilter_ipv4.h>
16 #include <net/netfilter/nf_conntrack_tuple.h>
17 #include <net/netfilter/nf_conntrack_l4proto.h>
18 #include <net/netfilter/nf_conntrack_core.h>
19 #include <net/netfilter/nf_conntrack_timeout.h>
20 #include <net/netfilter/nf_conntrack_zones.h>
21 #include <net/netfilter/nf_log.h>
22
23 static const unsigned int nf_ct_icmp_timeout = 30*HZ;
24
25 bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
26 struct net *net, struct nf_conntrack_tuple *tuple)
27 {
28 const struct icmphdr *hp;
29 struct icmphdr _hdr;
30
31 hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
32 if (hp == NULL)
33 return false;
34
35 tuple->dst.u.icmp.type = hp->type;
36 tuple->src.u.icmp.id = hp->un.echo.id;
37 tuple->dst.u.icmp.code = hp->code;
38
39 return true;
40 }
41
42
43 static const u_int8_t invmap[] = {
44 [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
45 [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
46 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
47 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
48 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
49 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
50 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
51 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1
52 };
53
54 bool nf_conntrack_invert_icmp_tuple(struct nf_conntrack_tuple *tuple,
55 const struct nf_conntrack_tuple *orig)
56 {
57 if (orig->dst.u.icmp.type >= sizeof(invmap) ||
58 !invmap[orig->dst.u.icmp.type])
59 return false;
60
61 tuple->src.u.icmp.id = orig->src.u.icmp.id;
62 tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
63 tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
64 return true;
65 }
66
67
68 int nf_conntrack_icmp_packet(struct nf_conn *ct,
69 struct sk_buff *skb,
70 enum ip_conntrack_info ctinfo,
71 const struct nf_hook_state *state)
72 {
73
74
75
76 unsigned int *timeout = nf_ct_timeout_lookup(ct);
77 static const u_int8_t valid_new[] = {
78 [ICMP_ECHO] = 1,
79 [ICMP_TIMESTAMP] = 1,
80 [ICMP_INFO_REQUEST] = 1,
81 [ICMP_ADDRESS] = 1
82 };
83
84 if (state->pf != NFPROTO_IPV4)
85 return -NF_ACCEPT;
86
87 if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) ||
88 !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) {
89
90 pr_debug("icmp: can't create new conn with type %u\n",
91 ct->tuplehash[0].tuple.dst.u.icmp.type);
92 nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple);
93 return -NF_ACCEPT;
94 }
95
96 if (!timeout)
97 timeout = &nf_icmp_pernet(nf_ct_net(ct))->timeout;
98
99 nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
100 return NF_ACCEPT;
101 }
102
103
104 int nf_conntrack_inet_error(struct nf_conn *tmpl, struct sk_buff *skb,
105 unsigned int dataoff,
106 const struct nf_hook_state *state,
107 u8 l4proto, union nf_inet_addr *outer_daddr)
108 {
109 struct nf_conntrack_tuple innertuple, origtuple;
110 const struct nf_conntrack_tuple_hash *h;
111 const struct nf_conntrack_zone *zone;
112 enum ip_conntrack_info ctinfo;
113 struct nf_conntrack_zone tmp;
114 union nf_inet_addr *ct_daddr;
115 enum ip_conntrack_dir dir;
116 struct nf_conn *ct;
117
118 WARN_ON(skb_nfct(skb));
119 zone = nf_ct_zone_tmpl(tmpl, skb, &tmp);
120
121
122 if (!nf_ct_get_tuplepr(skb, dataoff,
123 state->pf, state->net, &origtuple))
124 return -NF_ACCEPT;
125
126
127
128 if (!nf_ct_invert_tuple(&innertuple, &origtuple))
129 return -NF_ACCEPT;
130
131 h = nf_conntrack_find_get(state->net, zone, &innertuple);
132 if (!h)
133 return -NF_ACCEPT;
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 ct = nf_ct_tuplehash_to_ctrack(h);
167 dir = NF_CT_DIRECTION(h);
168 ct_daddr = &ct->tuplehash[dir].tuple.dst.u3;
169 if (!nf_inet_addr_cmp(outer_daddr, ct_daddr)) {
170 if (state->pf == AF_INET) {
171 nf_l4proto_log_invalid(skb, state->net, state->pf,
172 l4proto,
173 "outer daddr %pI4 != inner %pI4",
174 &outer_daddr->ip, &ct_daddr->ip);
175 } else if (state->pf == AF_INET6) {
176 nf_l4proto_log_invalid(skb, state->net, state->pf,
177 l4proto,
178 "outer daddr %pI6 != inner %pI6",
179 &outer_daddr->ip6, &ct_daddr->ip6);
180 }
181 nf_ct_put(ct);
182 return -NF_ACCEPT;
183 }
184
185 ctinfo = IP_CT_RELATED;
186 if (dir == IP_CT_DIR_REPLY)
187 ctinfo += IP_CT_IS_REPLY;
188
189
190 nf_ct_set(skb, ct, ctinfo);
191 return NF_ACCEPT;
192 }
193
194 static void icmp_error_log(const struct sk_buff *skb,
195 const struct nf_hook_state *state,
196 const char *msg)
197 {
198 nf_l4proto_log_invalid(skb, state->net, state->pf,
199 IPPROTO_ICMP, "%s", msg);
200 }
201
202
203 int nf_conntrack_icmpv4_error(struct nf_conn *tmpl,
204 struct sk_buff *skb, unsigned int dataoff,
205 const struct nf_hook_state *state)
206 {
207 union nf_inet_addr outer_daddr;
208 const struct icmphdr *icmph;
209 struct icmphdr _ih;
210
211
212 icmph = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
213 if (icmph == NULL) {
214 icmp_error_log(skb, state, "short packet");
215 return -NF_ACCEPT;
216 }
217
218
219 if (state->net->ct.sysctl_checksum &&
220 state->hook == NF_INET_PRE_ROUTING &&
221 nf_ip_checksum(skb, state->hook, dataoff, IPPROTO_ICMP)) {
222 icmp_error_log(skb, state, "bad hw icmp checksum");
223 return -NF_ACCEPT;
224 }
225
226
227
228
229
230
231
232 if (icmph->type > NR_ICMP_TYPES) {
233 icmp_error_log(skb, state, "invalid icmp type");
234 return -NF_ACCEPT;
235 }
236
237
238 if (icmph->type != ICMP_DEST_UNREACH &&
239 icmph->type != ICMP_SOURCE_QUENCH &&
240 icmph->type != ICMP_TIME_EXCEEDED &&
241 icmph->type != ICMP_PARAMETERPROB &&
242 icmph->type != ICMP_REDIRECT)
243 return NF_ACCEPT;
244
245 memset(&outer_daddr, 0, sizeof(outer_daddr));
246 outer_daddr.ip = ip_hdr(skb)->daddr;
247
248 dataoff += sizeof(*icmph);
249 return nf_conntrack_inet_error(tmpl, skb, dataoff, state,
250 IPPROTO_ICMP, &outer_daddr);
251 }
252
253 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
254
255 #include <linux/netfilter/nfnetlink.h>
256 #include <linux/netfilter/nfnetlink_conntrack.h>
257
258 static int icmp_tuple_to_nlattr(struct sk_buff *skb,
259 const struct nf_conntrack_tuple *t)
260 {
261 if (nla_put_be16(skb, CTA_PROTO_ICMP_ID, t->src.u.icmp.id) ||
262 nla_put_u8(skb, CTA_PROTO_ICMP_TYPE, t->dst.u.icmp.type) ||
263 nla_put_u8(skb, CTA_PROTO_ICMP_CODE, t->dst.u.icmp.code))
264 goto nla_put_failure;
265 return 0;
266
267 nla_put_failure:
268 return -1;
269 }
270
271 static const struct nla_policy icmp_nla_policy[CTA_PROTO_MAX+1] = {
272 [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 },
273 [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 },
274 [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 },
275 };
276
277 static int icmp_nlattr_to_tuple(struct nlattr *tb[],
278 struct nf_conntrack_tuple *tuple)
279 {
280 if (!tb[CTA_PROTO_ICMP_TYPE] ||
281 !tb[CTA_PROTO_ICMP_CODE] ||
282 !tb[CTA_PROTO_ICMP_ID])
283 return -EINVAL;
284
285 tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]);
286 tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]);
287 tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]);
288
289 if (tuple->dst.u.icmp.type >= sizeof(invmap) ||
290 !invmap[tuple->dst.u.icmp.type])
291 return -EINVAL;
292
293 return 0;
294 }
295
296 static unsigned int icmp_nlattr_tuple_size(void)
297 {
298 static unsigned int size __read_mostly;
299
300 if (!size)
301 size = nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1);
302
303 return size;
304 }
305 #endif
306
307 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
308
309 #include <linux/netfilter/nfnetlink.h>
310 #include <linux/netfilter/nfnetlink_cttimeout.h>
311
312 static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[],
313 struct net *net, void *data)
314 {
315 unsigned int *timeout = data;
316 struct nf_icmp_net *in = nf_icmp_pernet(net);
317
318 if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
319 if (!timeout)
320 timeout = &in->timeout;
321 *timeout =
322 ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ;
323 } else if (timeout) {
324
325 *timeout = in->timeout;
326 }
327 return 0;
328 }
329
330 static int
331 icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
332 {
333 const unsigned int *timeout = data;
334
335 if (nla_put_be32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ)))
336 goto nla_put_failure;
337 return 0;
338
339 nla_put_failure:
340 return -ENOSPC;
341 }
342
343 static const struct nla_policy
344 icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = {
345 [CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 },
346 };
347 #endif
348
349 void nf_conntrack_icmp_init_net(struct net *net)
350 {
351 struct nf_icmp_net *in = nf_icmp_pernet(net);
352
353 in->timeout = nf_ct_icmp_timeout;
354 }
355
356 const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp =
357 {
358 .l4proto = IPPROTO_ICMP,
359 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
360 .tuple_to_nlattr = icmp_tuple_to_nlattr,
361 .nlattr_tuple_size = icmp_nlattr_tuple_size,
362 .nlattr_to_tuple = icmp_nlattr_to_tuple,
363 .nla_policy = icmp_nla_policy,
364 #endif
365 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
366 .ctnl_timeout = {
367 .nlattr_to_obj = icmp_timeout_nlattr_to_obj,
368 .obj_to_nlattr = icmp_timeout_obj_to_nlattr,
369 .nlattr_max = CTA_TIMEOUT_ICMP_MAX,
370 .obj_size = sizeof(unsigned int),
371 .nla_policy = icmp_timeout_nla_policy,
372 },
373 #endif
374 };