Commit 83d213fd9d1a56108584cd812333462caa39a747
Committed by
Pablo Neira Ayuso
1 parent
9976fc6e6e
netfilter: conntrack: deconstify packet callback skb pointer
Only two protocols need the ->error() function: icmp and icmpv6. This is because icmp error mssages might be RELATED to an existing connection (e.g. PMTUD, port unreachable and the like), and their ->error() handlers do this. The error callback is already optional, so remove it for udp and call them from ->packet() instead. As the error() callback can call checksum functions that write to skb->csum*, the const qualifier has to be removed as well. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 9 changed files with 95 additions and 64 deletions Side-by-side Diff
- include/net/netfilter/nf_conntrack_l4proto.h
- net/netfilter/nf_conntrack_proto_dccp.c
- net/netfilter/nf_conntrack_proto_generic.c
- net/netfilter/nf_conntrack_proto_gre.c
- net/netfilter/nf_conntrack_proto_icmp.c
- net/netfilter/nf_conntrack_proto_icmpv6.c
- net/netfilter/nf_conntrack_proto_sctp.c
- net/netfilter/nf_conntrack_proto_tcp.c
- net/netfilter/nf_conntrack_proto_udp.c
include/net/netfilter/nf_conntrack_l4proto.h
net/netfilter/nf_conntrack_proto_dccp.c
... | ... | @@ -435,7 +435,7 @@ |
435 | 435 | ntohl(dhack->dccph_ack_nr_low); |
436 | 436 | } |
437 | 437 | |
438 | -static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | |
438 | +static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, | |
439 | 439 | unsigned int dataoff, enum ip_conntrack_info ctinfo, |
440 | 440 | const struct nf_hook_state *state) |
441 | 441 | { |
net/netfilter/nf_conntrack_proto_generic.c
... | ... | @@ -44,7 +44,7 @@ |
44 | 44 | |
45 | 45 | /* Returns verdict for packet, or -1 for invalid. */ |
46 | 46 | static int generic_packet(struct nf_conn *ct, |
47 | - const struct sk_buff *skb, | |
47 | + struct sk_buff *skb, | |
48 | 48 | unsigned int dataoff, |
49 | 49 | enum ip_conntrack_info ctinfo, |
50 | 50 | const struct nf_hook_state *state) |
net/netfilter/nf_conntrack_proto_gre.c
... | ... | @@ -233,7 +233,7 @@ |
233 | 233 | |
234 | 234 | /* Returns verdict for packet, and may modify conntrack */ |
235 | 235 | static int gre_packet(struct nf_conn *ct, |
236 | - const struct sk_buff *skb, | |
236 | + struct sk_buff *skb, | |
237 | 237 | unsigned int dataoff, |
238 | 238 | enum ip_conntrack_info ctinfo, |
239 | 239 | const struct nf_hook_state *state) |
net/netfilter/nf_conntrack_proto_icmp.c
... | ... | @@ -74,7 +74,7 @@ |
74 | 74 | |
75 | 75 | /* Returns verdict for packet, or -1 for invalid. */ |
76 | 76 | static int icmp_packet(struct nf_conn *ct, |
77 | - const struct sk_buff *skb, | |
77 | + struct sk_buff *skb, | |
78 | 78 | unsigned int dataoff, |
79 | 79 | enum ip_conntrack_info ctinfo, |
80 | 80 | const struct nf_hook_state *state) |
net/netfilter/nf_conntrack_proto_icmpv6.c
... | ... | @@ -92,10 +92,10 @@ |
92 | 92 | |
93 | 93 | /* Returns verdict for packet, or -1 for invalid. */ |
94 | 94 | static int icmpv6_packet(struct nf_conn *ct, |
95 | - const struct sk_buff *skb, | |
96 | - unsigned int dataoff, | |
97 | - enum ip_conntrack_info ctinfo, | |
98 | - const struct nf_hook_state *state) | |
95 | + struct sk_buff *skb, | |
96 | + unsigned int dataoff, | |
97 | + enum ip_conntrack_info ctinfo, | |
98 | + const struct nf_hook_state *state) | |
99 | 99 | { |
100 | 100 | unsigned int *timeout = nf_ct_timeout_lookup(ct); |
101 | 101 | static const u8 valid_new[] = { |
net/netfilter/nf_conntrack_proto_sctp.c
... | ... | @@ -332,7 +332,7 @@ |
332 | 332 | |
333 | 333 | /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ |
334 | 334 | static int sctp_packet(struct nf_conn *ct, |
335 | - const struct sk_buff *skb, | |
335 | + struct sk_buff *skb, | |
336 | 336 | unsigned int dataoff, |
337 | 337 | enum ip_conntrack_info ctinfo, |
338 | 338 | const struct nf_hook_state *state) |
net/netfilter/nf_conntrack_proto_tcp.c
... | ... | @@ -844,7 +844,7 @@ |
844 | 844 | |
845 | 845 | /* Returns verdict for packet, or -1 for invalid. */ |
846 | 846 | static int tcp_packet(struct nf_conn *ct, |
847 | - const struct sk_buff *skb, | |
847 | + struct sk_buff *skb, | |
848 | 848 | unsigned int dataoff, |
849 | 849 | enum ip_conntrack_info ctinfo, |
850 | 850 | const struct nf_hook_state *state) |
net/netfilter/nf_conntrack_proto_udp.c
... | ... | @@ -42,15 +42,65 @@ |
42 | 42 | return udp_pernet(net)->timeouts; |
43 | 43 | } |
44 | 44 | |
45 | +static void udp_error_log(const struct sk_buff *skb, | |
46 | + const struct nf_hook_state *state, | |
47 | + const char *msg) | |
48 | +{ | |
49 | + nf_l4proto_log_invalid(skb, state->net, state->pf, | |
50 | + IPPROTO_UDP, "%s", msg); | |
51 | +} | |
52 | + | |
53 | +static bool udp_error(struct sk_buff *skb, | |
54 | + unsigned int dataoff, | |
55 | + const struct nf_hook_state *state) | |
56 | +{ | |
57 | + unsigned int udplen = skb->len - dataoff; | |
58 | + const struct udphdr *hdr; | |
59 | + struct udphdr _hdr; | |
60 | + | |
61 | + /* Header is too small? */ | |
62 | + hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | |
63 | + if (!hdr) { | |
64 | + udp_error_log(skb, state, "short packet"); | |
65 | + return true; | |
66 | + } | |
67 | + | |
68 | + /* Truncated/malformed packets */ | |
69 | + if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { | |
70 | + udp_error_log(skb, state, "truncated/malformed packet"); | |
71 | + return true; | |
72 | + } | |
73 | + | |
74 | + /* Packet with no checksum */ | |
75 | + if (!hdr->check) | |
76 | + return false; | |
77 | + | |
78 | + /* Checksum invalid? Ignore. | |
79 | + * We skip checking packets on the outgoing path | |
80 | + * because the checksum is assumed to be correct. | |
81 | + * FIXME: Source route IP option packets --RR */ | |
82 | + if (state->hook == NF_INET_PRE_ROUTING && | |
83 | + state->net->ct.sysctl_checksum && | |
84 | + nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { | |
85 | + udp_error_log(skb, state, "bad checksum"); | |
86 | + return true; | |
87 | + } | |
88 | + | |
89 | + return false; | |
90 | +} | |
91 | + | |
45 | 92 | /* Returns verdict for packet, and may modify conntracktype */ |
46 | 93 | static int udp_packet(struct nf_conn *ct, |
47 | - const struct sk_buff *skb, | |
94 | + struct sk_buff *skb, | |
48 | 95 | unsigned int dataoff, |
49 | 96 | enum ip_conntrack_info ctinfo, |
50 | 97 | const struct nf_hook_state *state) |
51 | 98 | { |
52 | 99 | unsigned int *timeouts; |
53 | 100 | |
101 | + if (udp_error(skb, dataoff, state)) | |
102 | + return -NF_ACCEPT; | |
103 | + | |
54 | 104 | timeouts = nf_ct_timeout_lookup(ct); |
55 | 105 | if (!timeouts) |
56 | 106 | timeouts = udp_get_timeouts(nf_ct_net(ct)); |
... | ... | @@ -79,9 +129,9 @@ |
79 | 129 | IPPROTO_UDPLITE, "%s", msg); |
80 | 130 | } |
81 | 131 | |
82 | -static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, | |
83 | - unsigned int dataoff, | |
84 | - const struct nf_hook_state *state) | |
132 | +static bool udplite_error(struct sk_buff *skb, | |
133 | + unsigned int dataoff, | |
134 | + const struct nf_hook_state *state) | |
85 | 135 | { |
86 | 136 | unsigned int udplen = skb->len - dataoff; |
87 | 137 | const struct udphdr *hdr; |
... | ... | @@ -92,7 +142,7 @@ |
92 | 142 | hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); |
93 | 143 | if (!hdr) { |
94 | 144 | udplite_error_log(skb, state, "short packet"); |
95 | - return -NF_ACCEPT; | |
145 | + return true; | |
96 | 146 | } |
97 | 147 | |
98 | 148 | cscov = ntohs(hdr->len); |
99 | 149 | |
... | ... | @@ -100,13 +150,13 @@ |
100 | 150 | cscov = udplen; |
101 | 151 | } else if (cscov < sizeof(*hdr) || cscov > udplen) { |
102 | 152 | udplite_error_log(skb, state, "invalid checksum coverage"); |
103 | - return -NF_ACCEPT; | |
153 | + return true; | |
104 | 154 | } |
105 | 155 | |
106 | 156 | /* UDPLITE mandates checksums */ |
107 | 157 | if (!hdr->check) { |
108 | 158 | udplite_error_log(skb, state, "checksum missing"); |
109 | - return -NF_ACCEPT; | |
159 | + return true; | |
110 | 160 | } |
111 | 161 | |
112 | 162 | /* Checksum invalid? Ignore. */ |
113 | 163 | |
114 | 164 | |
115 | 165 | |
116 | 166 | |
117 | 167 | |
118 | 168 | |
119 | 169 | |
120 | 170 | |
121 | 171 | |
122 | 172 | |
... | ... | @@ -115,58 +165,43 @@ |
115 | 165 | nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP, |
116 | 166 | state->pf)) { |
117 | 167 | udplite_error_log(skb, state, "bad checksum"); |
118 | - return -NF_ACCEPT; | |
168 | + return true; | |
119 | 169 | } |
120 | 170 | |
121 | - return NF_ACCEPT; | |
171 | + return false; | |
122 | 172 | } |
123 | -#endif | |
124 | 173 | |
125 | -static void udp_error_log(const struct sk_buff *skb, | |
126 | - const struct nf_hook_state *state, | |
127 | - const char *msg) | |
174 | +/* Returns verdict for packet, and may modify conntracktype */ | |
175 | +static int udplite_packet(struct nf_conn *ct, | |
176 | + struct sk_buff *skb, | |
177 | + unsigned int dataoff, | |
178 | + enum ip_conntrack_info ctinfo, | |
179 | + const struct nf_hook_state *state) | |
128 | 180 | { |
129 | - nf_l4proto_log_invalid(skb, state->net, state->pf, | |
130 | - IPPROTO_UDP, "%s", msg); | |
131 | -} | |
181 | + unsigned int *timeouts; | |
132 | 182 | |
133 | -static int udp_error(struct nf_conn *tmpl, struct sk_buff *skb, | |
134 | - unsigned int dataoff, | |
135 | - const struct nf_hook_state *state) | |
136 | -{ | |
137 | - unsigned int udplen = skb->len - dataoff; | |
138 | - const struct udphdr *hdr; | |
139 | - struct udphdr _hdr; | |
140 | - | |
141 | - /* Header is too small? */ | |
142 | - hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | |
143 | - if (hdr == NULL) { | |
144 | - udp_error_log(skb, state, "short packet"); | |
183 | + if (udplite_error(skb, dataoff, state)) | |
145 | 184 | return -NF_ACCEPT; |
146 | - } | |
147 | 185 | |
148 | - /* Truncated/malformed packets */ | |
149 | - if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { | |
150 | - udp_error_log(skb, state, "truncated/malformed packet"); | |
151 | - return -NF_ACCEPT; | |
152 | - } | |
186 | + timeouts = nf_ct_timeout_lookup(ct); | |
187 | + if (!timeouts) | |
188 | + timeouts = udp_get_timeouts(nf_ct_net(ct)); | |
153 | 189 | |
154 | - /* Packet with no checksum */ | |
155 | - if (!hdr->check) | |
156 | - return NF_ACCEPT; | |
157 | - | |
158 | - /* Checksum invalid? Ignore. | |
159 | - * We skip checking packets on the outgoing path | |
160 | - * because the checksum is assumed to be correct. | |
161 | - * FIXME: Source route IP option packets --RR */ | |
162 | - if (state->net->ct.sysctl_checksum && state->hook == NF_INET_PRE_ROUTING && | |
163 | - nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { | |
164 | - udp_error_log(skb, state, "bad checksum"); | |
165 | - return -NF_ACCEPT; | |
190 | + /* If we've seen traffic both ways, this is some kind of UDP | |
191 | + stream. Extend timeout. */ | |
192 | + if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | |
193 | + nf_ct_refresh_acct(ct, ctinfo, skb, | |
194 | + timeouts[UDP_CT_REPLIED]); | |
195 | + /* Also, more likely to be important, and not a probe */ | |
196 | + if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) | |
197 | + nf_conntrack_event_cache(IPCT_ASSURED, ct); | |
198 | + } else { | |
199 | + nf_ct_refresh_acct(ct, ctinfo, skb, | |
200 | + timeouts[UDP_CT_UNREPLIED]); | |
166 | 201 | } |
167 | - | |
168 | 202 | return NF_ACCEPT; |
169 | 203 | } |
204 | +#endif | |
170 | 205 | |
171 | 206 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
172 | 207 | |
... | ... | @@ -281,7 +316,6 @@ |
281 | 316 | .l4proto = IPPROTO_UDP, |
282 | 317 | .allow_clash = true, |
283 | 318 | .packet = udp_packet, |
284 | - .error = udp_error, | |
285 | 319 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
286 | 320 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
287 | 321 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
... | ... | @@ -308,8 +342,7 @@ |
308 | 342 | .l3proto = PF_INET, |
309 | 343 | .l4proto = IPPROTO_UDPLITE, |
310 | 344 | .allow_clash = true, |
311 | - .packet = udp_packet, | |
312 | - .error = udplite_error, | |
345 | + .packet = udplite_packet, | |
313 | 346 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
314 | 347 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
315 | 348 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
... | ... | @@ -337,7 +370,6 @@ |
337 | 370 | .l4proto = IPPROTO_UDP, |
338 | 371 | .allow_clash = true, |
339 | 372 | .packet = udp_packet, |
340 | - .error = udp_error, | |
341 | 373 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
342 | 374 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
343 | 375 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
... | ... | @@ -364,8 +396,7 @@ |
364 | 396 | .l3proto = PF_INET6, |
365 | 397 | .l4proto = IPPROTO_UDPLITE, |
366 | 398 | .allow_clash = true, |
367 | - .packet = udp_packet, | |
368 | - .error = udplite_error, | |
399 | + .packet = udplite_packet, | |
369 | 400 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
370 | 401 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
371 | 402 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |