diff options
author | David S. Miller <davem@davemloft.net> | 2012-03-08 01:27:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-03-08 01:27:56 -0500 |
commit | c75a312d8b2c97943014261d71c6ef2622b6d0d9 (patch) | |
tree | 374a25ac277d787485dc9acf87710e28f50d52bb /net | |
parent | b4fb05ea402cb6930b40d3152d8acabc391b23e2 (diff) | |
parent | ace30d73ef09fd5f95b24c5c1c5aa11963981494 (diff) |
Merge branch 'master' of git://1984.lsi.us.es/net-next
Diffstat (limited to 'net')
41 files changed, 3083 insertions, 1353 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 74dfc9e5211f..fcc543cd987a 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -123,15 +123,6 @@ config IP_NF_TARGET_REJECT | |||
123 | 123 | ||
124 | To compile it as a module, choose M here. If unsure, say N. | 124 | To compile it as a module, choose M here. If unsure, say N. |
125 | 125 | ||
126 | config IP_NF_TARGET_LOG | ||
127 | tristate "LOG target support" | ||
128 | default m if NETFILTER_ADVANCED=n | ||
129 | help | ||
130 | This option adds a `LOG' target, which allows you to create rules in | ||
131 | any iptables table which records the packet header to the syslog. | ||
132 | |||
133 | To compile it as a module, choose M here. If unsure, say N. | ||
134 | |||
135 | config IP_NF_TARGET_ULOG | 126 | config IP_NF_TARGET_ULOG |
136 | tristate "ULOG target support" | 127 | tristate "ULOG target support" |
137 | default m if NETFILTER_ADVANCED=n | 128 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 213a462b739b..240b68469a7a 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -54,7 +54,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o | |||
54 | # targets | 54 | # targets |
55 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o | 55 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o |
56 | obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o | 56 | obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o |
57 | obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o | ||
58 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o | 57 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o |
59 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o | 58 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o |
60 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o | 59 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o |
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c deleted file mode 100644 index d76d6c9ed946..000000000000 --- a/net/ipv4/netfilter/ipt_LOG.c +++ /dev/null | |||
@@ -1,516 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for logging packets. | ||
3 | */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/if_arp.h> | ||
17 | #include <linux/ip.h> | ||
18 | #include <net/icmp.h> | ||
19 | #include <net/udp.h> | ||
20 | #include <net/tcp.h> | ||
21 | #include <net/route.h> | ||
22 | |||
23 | #include <linux/netfilter.h> | ||
24 | #include <linux/netfilter/x_tables.h> | ||
25 | #include <linux/netfilter_ipv4/ipt_LOG.h> | ||
26 | #include <net/netfilter/nf_log.h> | ||
27 | #include <net/netfilter/xt_log.h> | ||
28 | |||
29 | MODULE_LICENSE("GPL"); | ||
30 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
31 | MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog"); | ||
32 | |||
33 | /* One level of recursion won't kill us */ | ||
34 | static void dump_packet(struct sbuff *m, | ||
35 | const struct nf_loginfo *info, | ||
36 | const struct sk_buff *skb, | ||
37 | unsigned int iphoff) | ||
38 | { | ||
39 | struct iphdr _iph; | ||
40 | const struct iphdr *ih; | ||
41 | unsigned int logflags; | ||
42 | |||
43 | if (info->type == NF_LOG_TYPE_LOG) | ||
44 | logflags = info->u.log.logflags; | ||
45 | else | ||
46 | logflags = NF_LOG_MASK; | ||
47 | |||
48 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | ||
49 | if (ih == NULL) { | ||
50 | sb_add(m, "TRUNCATED"); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | /* Important fields: | ||
55 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ | ||
56 | /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ | ||
57 | sb_add(m, "SRC=%pI4 DST=%pI4 ", | ||
58 | &ih->saddr, &ih->daddr); | ||
59 | |||
60 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | ||
61 | sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | ||
62 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | ||
63 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | ||
64 | |||
65 | /* Max length: 6 "CE DF MF " */ | ||
66 | if (ntohs(ih->frag_off) & IP_CE) | ||
67 | sb_add(m, "CE "); | ||
68 | if (ntohs(ih->frag_off) & IP_DF) | ||
69 | sb_add(m, "DF "); | ||
70 | if (ntohs(ih->frag_off) & IP_MF) | ||
71 | sb_add(m, "MF "); | ||
72 | |||
73 | /* Max length: 11 "FRAG:65535 " */ | ||
74 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
75 | sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | ||
76 | |||
77 | if ((logflags & IPT_LOG_IPOPT) && | ||
78 | ih->ihl * 4 > sizeof(struct iphdr)) { | ||
79 | const unsigned char *op; | ||
80 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; | ||
81 | unsigned int i, optsize; | ||
82 | |||
83 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | ||
84 | op = skb_header_pointer(skb, iphoff+sizeof(_iph), | ||
85 | optsize, _opt); | ||
86 | if (op == NULL) { | ||
87 | sb_add(m, "TRUNCATED"); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
92 | sb_add(m, "OPT ("); | ||
93 | for (i = 0; i < optsize; i++) | ||
94 | sb_add(m, "%02X", op[i]); | ||
95 | sb_add(m, ") "); | ||
96 | } | ||
97 | |||
98 | switch (ih->protocol) { | ||
99 | case IPPROTO_TCP: { | ||
100 | struct tcphdr _tcph; | ||
101 | const struct tcphdr *th; | ||
102 | |||
103 | /* Max length: 10 "PROTO=TCP " */ | ||
104 | sb_add(m, "PROTO=TCP "); | ||
105 | |||
106 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
107 | break; | ||
108 | |||
109 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
110 | th = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
111 | sizeof(_tcph), &_tcph); | ||
112 | if (th == NULL) { | ||
113 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
114 | skb->len - iphoff - ih->ihl*4); | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
119 | sb_add(m, "SPT=%u DPT=%u ", | ||
120 | ntohs(th->source), ntohs(th->dest)); | ||
121 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
122 | if (logflags & IPT_LOG_TCPSEQ) | ||
123 | sb_add(m, "SEQ=%u ACK=%u ", | ||
124 | ntohl(th->seq), ntohl(th->ack_seq)); | ||
125 | /* Max length: 13 "WINDOW=65535 " */ | ||
126 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
127 | /* Max length: 9 "RES=0x3F " */ | ||
128 | sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); | ||
129 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
130 | if (th->cwr) | ||
131 | sb_add(m, "CWR "); | ||
132 | if (th->ece) | ||
133 | sb_add(m, "ECE "); | ||
134 | if (th->urg) | ||
135 | sb_add(m, "URG "); | ||
136 | if (th->ack) | ||
137 | sb_add(m, "ACK "); | ||
138 | if (th->psh) | ||
139 | sb_add(m, "PSH "); | ||
140 | if (th->rst) | ||
141 | sb_add(m, "RST "); | ||
142 | if (th->syn) | ||
143 | sb_add(m, "SYN "); | ||
144 | if (th->fin) | ||
145 | sb_add(m, "FIN "); | ||
146 | /* Max length: 11 "URGP=65535 " */ | ||
147 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
148 | |||
149 | if ((logflags & IPT_LOG_TCPOPT) && | ||
150 | th->doff * 4 > sizeof(struct tcphdr)) { | ||
151 | unsigned char _opt[4 * 15 - sizeof(struct tcphdr)]; | ||
152 | const unsigned char *op; | ||
153 | unsigned int i, optsize; | ||
154 | |||
155 | optsize = th->doff * 4 - sizeof(struct tcphdr); | ||
156 | op = skb_header_pointer(skb, | ||
157 | iphoff+ih->ihl*4+sizeof(_tcph), | ||
158 | optsize, _opt); | ||
159 | if (op == NULL) { | ||
160 | sb_add(m, "TRUNCATED"); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
165 | sb_add(m, "OPT ("); | ||
166 | for (i = 0; i < optsize; i++) | ||
167 | sb_add(m, "%02X", op[i]); | ||
168 | sb_add(m, ") "); | ||
169 | } | ||
170 | break; | ||
171 | } | ||
172 | case IPPROTO_UDP: | ||
173 | case IPPROTO_UDPLITE: { | ||
174 | struct udphdr _udph; | ||
175 | const struct udphdr *uh; | ||
176 | |||
177 | if (ih->protocol == IPPROTO_UDP) | ||
178 | /* Max length: 10 "PROTO=UDP " */ | ||
179 | sb_add(m, "PROTO=UDP " ); | ||
180 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
181 | sb_add(m, "PROTO=UDPLITE "); | ||
182 | |||
183 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
184 | break; | ||
185 | |||
186 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
187 | uh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
188 | sizeof(_udph), &_udph); | ||
189 | if (uh == NULL) { | ||
190 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
191 | skb->len - iphoff - ih->ihl*4); | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
196 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", | ||
197 | ntohs(uh->source), ntohs(uh->dest), | ||
198 | ntohs(uh->len)); | ||
199 | break; | ||
200 | } | ||
201 | case IPPROTO_ICMP: { | ||
202 | struct icmphdr _icmph; | ||
203 | const struct icmphdr *ich; | ||
204 | static const size_t required_len[NR_ICMP_TYPES+1] | ||
205 | = { [ICMP_ECHOREPLY] = 4, | ||
206 | [ICMP_DEST_UNREACH] | ||
207 | = 8 + sizeof(struct iphdr), | ||
208 | [ICMP_SOURCE_QUENCH] | ||
209 | = 8 + sizeof(struct iphdr), | ||
210 | [ICMP_REDIRECT] | ||
211 | = 8 + sizeof(struct iphdr), | ||
212 | [ICMP_ECHO] = 4, | ||
213 | [ICMP_TIME_EXCEEDED] | ||
214 | = 8 + sizeof(struct iphdr), | ||
215 | [ICMP_PARAMETERPROB] | ||
216 | = 8 + sizeof(struct iphdr), | ||
217 | [ICMP_TIMESTAMP] = 20, | ||
218 | [ICMP_TIMESTAMPREPLY] = 20, | ||
219 | [ICMP_ADDRESS] = 12, | ||
220 | [ICMP_ADDRESSREPLY] = 12 }; | ||
221 | |||
222 | /* Max length: 11 "PROTO=ICMP " */ | ||
223 | sb_add(m, "PROTO=ICMP "); | ||
224 | |||
225 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
226 | break; | ||
227 | |||
228 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
229 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
230 | sizeof(_icmph), &_icmph); | ||
231 | if (ich == NULL) { | ||
232 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
233 | skb->len - iphoff - ih->ihl*4); | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
238 | sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | ||
239 | |||
240 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
241 | if (ich->type <= NR_ICMP_TYPES && | ||
242 | required_len[ich->type] && | ||
243 | skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { | ||
244 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
245 | skb->len - iphoff - ih->ihl*4); | ||
246 | break; | ||
247 | } | ||
248 | |||
249 | switch (ich->type) { | ||
250 | case ICMP_ECHOREPLY: | ||
251 | case ICMP_ECHO: | ||
252 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
253 | sb_add(m, "ID=%u SEQ=%u ", | ||
254 | ntohs(ich->un.echo.id), | ||
255 | ntohs(ich->un.echo.sequence)); | ||
256 | break; | ||
257 | |||
258 | case ICMP_PARAMETERPROB: | ||
259 | /* Max length: 14 "PARAMETER=255 " */ | ||
260 | sb_add(m, "PARAMETER=%u ", | ||
261 | ntohl(ich->un.gateway) >> 24); | ||
262 | break; | ||
263 | case ICMP_REDIRECT: | ||
264 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | ||
265 | sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | ||
266 | /* Fall through */ | ||
267 | case ICMP_DEST_UNREACH: | ||
268 | case ICMP_SOURCE_QUENCH: | ||
269 | case ICMP_TIME_EXCEEDED: | ||
270 | /* Max length: 3+maxlen */ | ||
271 | if (!iphoff) { /* Only recurse once. */ | ||
272 | sb_add(m, "["); | ||
273 | dump_packet(m, info, skb, | ||
274 | iphoff + ih->ihl*4+sizeof(_icmph)); | ||
275 | sb_add(m, "] "); | ||
276 | } | ||
277 | |||
278 | /* Max length: 10 "MTU=65535 " */ | ||
279 | if (ich->type == ICMP_DEST_UNREACH && | ||
280 | ich->code == ICMP_FRAG_NEEDED) | ||
281 | sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); | ||
282 | } | ||
283 | break; | ||
284 | } | ||
285 | /* Max Length */ | ||
286 | case IPPROTO_AH: { | ||
287 | struct ip_auth_hdr _ahdr; | ||
288 | const struct ip_auth_hdr *ah; | ||
289 | |||
290 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
291 | break; | ||
292 | |||
293 | /* Max length: 9 "PROTO=AH " */ | ||
294 | sb_add(m, "PROTO=AH "); | ||
295 | |||
296 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
297 | ah = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
298 | sizeof(_ahdr), &_ahdr); | ||
299 | if (ah == NULL) { | ||
300 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
301 | skb->len - iphoff - ih->ihl*4); | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | /* Length: 15 "SPI=0xF1234567 " */ | ||
306 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
307 | break; | ||
308 | } | ||
309 | case IPPROTO_ESP: { | ||
310 | struct ip_esp_hdr _esph; | ||
311 | const struct ip_esp_hdr *eh; | ||
312 | |||
313 | /* Max length: 10 "PROTO=ESP " */ | ||
314 | sb_add(m, "PROTO=ESP "); | ||
315 | |||
316 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
317 | break; | ||
318 | |||
319 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
320 | eh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
321 | sizeof(_esph), &_esph); | ||
322 | if (eh == NULL) { | ||
323 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
324 | skb->len - iphoff - ih->ihl*4); | ||
325 | break; | ||
326 | } | ||
327 | |||
328 | /* Length: 15 "SPI=0xF1234567 " */ | ||
329 | sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); | ||
330 | break; | ||
331 | } | ||
332 | /* Max length: 10 "PROTO 255 " */ | ||
333 | default: | ||
334 | sb_add(m, "PROTO=%u ", ih->protocol); | ||
335 | } | ||
336 | |||
337 | /* Max length: 15 "UID=4294967295 " */ | ||
338 | if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) { | ||
339 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
340 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
341 | sb_add(m, "UID=%u GID=%u ", | ||
342 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
343 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
344 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
345 | } | ||
346 | |||
347 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
348 | if (!iphoff && skb->mark) | ||
349 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
350 | |||
351 | /* Proto Max log string length */ | ||
352 | /* IP: 40+46+6+11+127 = 230 */ | ||
353 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | ||
354 | /* UDP: 10+max(25,20) = 35 */ | ||
355 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
356 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | ||
357 | /* ESP: 10+max(25)+15 = 50 */ | ||
358 | /* AH: 9+max(25)+15 = 49 */ | ||
359 | /* unknown: 10 */ | ||
360 | |||
361 | /* (ICMP allows recursion one level deep) */ | ||
362 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | ||
363 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | ||
364 | } | ||
365 | |||
366 | static void dump_mac_header(struct sbuff *m, | ||
367 | const struct nf_loginfo *info, | ||
368 | const struct sk_buff *skb) | ||
369 | { | ||
370 | struct net_device *dev = skb->dev; | ||
371 | unsigned int logflags = 0; | ||
372 | |||
373 | if (info->type == NF_LOG_TYPE_LOG) | ||
374 | logflags = info->u.log.logflags; | ||
375 | |||
376 | if (!(logflags & IPT_LOG_MACDECODE)) | ||
377 | goto fallback; | ||
378 | |||
379 | switch (dev->type) { | ||
380 | case ARPHRD_ETHER: | ||
381 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
382 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
383 | ntohs(eth_hdr(skb)->h_proto)); | ||
384 | return; | ||
385 | default: | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | fallback: | ||
390 | sb_add(m, "MAC="); | ||
391 | if (dev->hard_header_len && | ||
392 | skb->mac_header != skb->network_header) { | ||
393 | const unsigned char *p = skb_mac_header(skb); | ||
394 | unsigned int i; | ||
395 | |||
396 | sb_add(m, "%02x", *p++); | ||
397 | for (i = 1; i < dev->hard_header_len; i++, p++) | ||
398 | sb_add(m, ":%02x", *p); | ||
399 | } | ||
400 | sb_add(m, " "); | ||
401 | } | ||
402 | |||
403 | static struct nf_loginfo default_loginfo = { | ||
404 | .type = NF_LOG_TYPE_LOG, | ||
405 | .u = { | ||
406 | .log = { | ||
407 | .level = 5, | ||
408 | .logflags = NF_LOG_MASK, | ||
409 | }, | ||
410 | }, | ||
411 | }; | ||
412 | |||
413 | static void | ||
414 | ipt_log_packet(u_int8_t pf, | ||
415 | unsigned int hooknum, | ||
416 | const struct sk_buff *skb, | ||
417 | const struct net_device *in, | ||
418 | const struct net_device *out, | ||
419 | const struct nf_loginfo *loginfo, | ||
420 | const char *prefix) | ||
421 | { | ||
422 | struct sbuff *m = sb_open(); | ||
423 | |||
424 | if (!loginfo) | ||
425 | loginfo = &default_loginfo; | ||
426 | |||
427 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | ||
428 | prefix, | ||
429 | in ? in->name : "", | ||
430 | out ? out->name : ""); | ||
431 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
432 | if (skb->nf_bridge) { | ||
433 | const struct net_device *physindev; | ||
434 | const struct net_device *physoutdev; | ||
435 | |||
436 | physindev = skb->nf_bridge->physindev; | ||
437 | if (physindev && in != physindev) | ||
438 | sb_add(m, "PHYSIN=%s ", physindev->name); | ||
439 | physoutdev = skb->nf_bridge->physoutdev; | ||
440 | if (physoutdev && out != physoutdev) | ||
441 | sb_add(m, "PHYSOUT=%s ", physoutdev->name); | ||
442 | } | ||
443 | #endif | ||
444 | |||
445 | if (in != NULL) | ||
446 | dump_mac_header(m, loginfo, skb); | ||
447 | |||
448 | dump_packet(m, loginfo, skb, 0); | ||
449 | |||
450 | sb_close(m); | ||
451 | } | ||
452 | |||
453 | static unsigned int | ||
454 | log_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
455 | { | ||
456 | const struct ipt_log_info *loginfo = par->targinfo; | ||
457 | struct nf_loginfo li; | ||
458 | |||
459 | li.type = NF_LOG_TYPE_LOG; | ||
460 | li.u.log.level = loginfo->level; | ||
461 | li.u.log.logflags = loginfo->logflags; | ||
462 | |||
463 | ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li, | ||
464 | loginfo->prefix); | ||
465 | return XT_CONTINUE; | ||
466 | } | ||
467 | |||
468 | static int log_tg_check(const struct xt_tgchk_param *par) | ||
469 | { | ||
470 | const struct ipt_log_info *loginfo = par->targinfo; | ||
471 | |||
472 | if (loginfo->level >= 8) { | ||
473 | pr_debug("level %u >= 8\n", loginfo->level); | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | ||
477 | pr_debug("prefix is not null-terminated\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static struct xt_target log_tg_reg __read_mostly = { | ||
484 | .name = "LOG", | ||
485 | .family = NFPROTO_IPV4, | ||
486 | .target = log_tg, | ||
487 | .targetsize = sizeof(struct ipt_log_info), | ||
488 | .checkentry = log_tg_check, | ||
489 | .me = THIS_MODULE, | ||
490 | }; | ||
491 | |||
492 | static struct nf_logger ipt_log_logger __read_mostly = { | ||
493 | .name = "ipt_LOG", | ||
494 | .logfn = &ipt_log_packet, | ||
495 | .me = THIS_MODULE, | ||
496 | }; | ||
497 | |||
498 | static int __init log_tg_init(void) | ||
499 | { | ||
500 | int ret; | ||
501 | |||
502 | ret = xt_register_target(&log_tg_reg); | ||
503 | if (ret < 0) | ||
504 | return ret; | ||
505 | nf_log_register(NFPROTO_IPV4, &ipt_log_logger); | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static void __exit log_tg_exit(void) | ||
510 | { | ||
511 | nf_log_unregister(&ipt_log_logger); | ||
512 | xt_unregister_target(&log_tg_reg); | ||
513 | } | ||
514 | |||
515 | module_init(log_tg_init); | ||
516 | module_exit(log_tg_exit); | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index ab5b27a2916f..7cbe9cb261c2 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -75,25 +75,31 @@ static int icmp_print_tuple(struct seq_file *s, | |||
75 | ntohs(tuple->src.u.icmp.id)); | 75 | ntohs(tuple->src.u.icmp.id)); |
76 | } | 76 | } |
77 | 77 | ||
78 | static unsigned int *icmp_get_timeouts(struct net *net) | ||
79 | { | ||
80 | return &nf_ct_icmp_timeout; | ||
81 | } | ||
82 | |||
78 | /* Returns verdict for packet, or -1 for invalid. */ | 83 | /* Returns verdict for packet, or -1 for invalid. */ |
79 | static int icmp_packet(struct nf_conn *ct, | 84 | static int icmp_packet(struct nf_conn *ct, |
80 | const struct sk_buff *skb, | 85 | const struct sk_buff *skb, |
81 | unsigned int dataoff, | 86 | unsigned int dataoff, |
82 | enum ip_conntrack_info ctinfo, | 87 | enum ip_conntrack_info ctinfo, |
83 | u_int8_t pf, | 88 | u_int8_t pf, |
84 | unsigned int hooknum) | 89 | unsigned int hooknum, |
90 | unsigned int *timeout) | ||
85 | { | 91 | { |
86 | /* Do not immediately delete the connection after the first | 92 | /* Do not immediately delete the connection after the first |
87 | successful reply to avoid excessive conntrackd traffic | 93 | successful reply to avoid excessive conntrackd traffic |
88 | and also to handle correctly ICMP echo reply duplicates. */ | 94 | and also to handle correctly ICMP echo reply duplicates. */ |
89 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); | 95 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
90 | 96 | ||
91 | return NF_ACCEPT; | 97 | return NF_ACCEPT; |
92 | } | 98 | } |
93 | 99 | ||
94 | /* Called when a new connection for this protocol found. */ | 100 | /* Called when a new connection for this protocol found. */ |
95 | static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, | 101 | static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, |
96 | unsigned int dataoff) | 102 | unsigned int dataoff, unsigned int *timeouts) |
97 | { | 103 | { |
98 | static const u_int8_t valid_new[] = { | 104 | static const u_int8_t valid_new[] = { |
99 | [ICMP_ECHO] = 1, | 105 | [ICMP_ECHO] = 1, |
@@ -263,6 +269,44 @@ static int icmp_nlattr_tuple_size(void) | |||
263 | } | 269 | } |
264 | #endif | 270 | #endif |
265 | 271 | ||
272 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
273 | |||
274 | #include <linux/netfilter/nfnetlink.h> | ||
275 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
276 | |||
277 | static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
278 | { | ||
279 | unsigned int *timeout = data; | ||
280 | |||
281 | if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) { | ||
282 | *timeout = | ||
283 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ; | ||
284 | } else { | ||
285 | /* Set default ICMP timeout. */ | ||
286 | *timeout = nf_ct_icmp_timeout; | ||
287 | } | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
293 | { | ||
294 | const unsigned int *timeout = data; | ||
295 | |||
296 | NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ)); | ||
297 | |||
298 | return 0; | ||
299 | |||
300 | nla_put_failure: | ||
301 | return -ENOSPC; | ||
302 | } | ||
303 | |||
304 | static const struct nla_policy | ||
305 | icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = { | ||
306 | [CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 }, | ||
307 | }; | ||
308 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
309 | |||
266 | #ifdef CONFIG_SYSCTL | 310 | #ifdef CONFIG_SYSCTL |
267 | static struct ctl_table_header *icmp_sysctl_header; | 311 | static struct ctl_table_header *icmp_sysctl_header; |
268 | static struct ctl_table icmp_sysctl_table[] = { | 312 | static struct ctl_table icmp_sysctl_table[] = { |
@@ -298,6 +342,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = | |||
298 | .invert_tuple = icmp_invert_tuple, | 342 | .invert_tuple = icmp_invert_tuple, |
299 | .print_tuple = icmp_print_tuple, | 343 | .print_tuple = icmp_print_tuple, |
300 | .packet = icmp_packet, | 344 | .packet = icmp_packet, |
345 | .get_timeouts = icmp_get_timeouts, | ||
301 | .new = icmp_new, | 346 | .new = icmp_new, |
302 | .error = icmp_error, | 347 | .error = icmp_error, |
303 | .destroy = NULL, | 348 | .destroy = NULL, |
@@ -308,6 +353,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = | |||
308 | .nlattr_to_tuple = icmp_nlattr_to_tuple, | 353 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
309 | .nla_policy = icmp_nla_policy, | 354 | .nla_policy = icmp_nla_policy, |
310 | #endif | 355 | #endif |
356 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
357 | .ctnl_timeout = { | ||
358 | .nlattr_to_obj = icmp_timeout_nlattr_to_obj, | ||
359 | .obj_to_nlattr = icmp_timeout_obj_to_nlattr, | ||
360 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, | ||
361 | .obj_size = sizeof(unsigned int), | ||
362 | .nla_policy = icmp_timeout_nla_policy, | ||
363 | }, | ||
364 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
311 | #ifdef CONFIG_SYSCTL | 365 | #ifdef CONFIG_SYSCTL |
312 | .ctl_table_header = &icmp_sysctl_header, | 366 | .ctl_table_header = &icmp_sysctl_header, |
313 | .ctl_table = icmp_sysctl_table, | 367 | .ctl_table = icmp_sysctl_table, |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index a708933dc230..abb52adf5acd 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -686,6 +686,11 @@ static struct pernet_operations nf_nat_net_ops = { | |||
686 | .exit = nf_nat_net_exit, | 686 | .exit = nf_nat_net_exit, |
687 | }; | 687 | }; |
688 | 688 | ||
689 | static struct nf_ct_helper_expectfn follow_master_nat = { | ||
690 | .name = "nat-follow-master", | ||
691 | .expectfn = nf_nat_follow_master, | ||
692 | }; | ||
693 | |||
689 | static int __init nf_nat_init(void) | 694 | static int __init nf_nat_init(void) |
690 | { | 695 | { |
691 | size_t i; | 696 | size_t i; |
@@ -717,6 +722,8 @@ static int __init nf_nat_init(void) | |||
717 | 722 | ||
718 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); | 723 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); |
719 | 724 | ||
725 | nf_ct_helper_expectfn_register(&follow_master_nat); | ||
726 | |||
720 | BUG_ON(nf_nat_seq_adjust_hook != NULL); | 727 | BUG_ON(nf_nat_seq_adjust_hook != NULL); |
721 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); | 728 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); |
722 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); | 729 | BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); |
@@ -736,6 +743,7 @@ static void __exit nf_nat_cleanup(void) | |||
736 | unregister_pernet_subsys(&nf_nat_net_ops); | 743 | unregister_pernet_subsys(&nf_nat_net_ops); |
737 | nf_ct_l3proto_put(l3proto); | 744 | nf_ct_l3proto_put(l3proto); |
738 | nf_ct_extend_unregister(&nat_extend); | 745 | nf_ct_extend_unregister(&nat_extend); |
746 | nf_ct_helper_expectfn_unregister(&follow_master_nat); | ||
739 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); | 747 | RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); |
740 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); | 748 | RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); |
741 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | 749 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); |
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index dc1dd912baf4..82536701e3a3 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c | |||
@@ -568,6 +568,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, | |||
568 | return 0; | 568 | return 0; |
569 | } | 569 | } |
570 | 570 | ||
571 | static struct nf_ct_helper_expectfn q931_nat = { | ||
572 | .name = "Q.931", | ||
573 | .expectfn = ip_nat_q931_expect, | ||
574 | }; | ||
575 | |||
576 | static struct nf_ct_helper_expectfn callforwarding_nat = { | ||
577 | .name = "callforwarding", | ||
578 | .expectfn = ip_nat_callforwarding_expect, | ||
579 | }; | ||
580 | |||
571 | /****************************************************************************/ | 581 | /****************************************************************************/ |
572 | static int __init init(void) | 582 | static int __init init(void) |
573 | { | 583 | { |
@@ -590,6 +600,8 @@ static int __init init(void) | |||
590 | RCU_INIT_POINTER(nat_h245_hook, nat_h245); | 600 | RCU_INIT_POINTER(nat_h245_hook, nat_h245); |
591 | RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); | 601 | RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); |
592 | RCU_INIT_POINTER(nat_q931_hook, nat_q931); | 602 | RCU_INIT_POINTER(nat_q931_hook, nat_q931); |
603 | nf_ct_helper_expectfn_register(&q931_nat); | ||
604 | nf_ct_helper_expectfn_register(&callforwarding_nat); | ||
593 | return 0; | 605 | return 0; |
594 | } | 606 | } |
595 | 607 | ||
@@ -605,6 +617,8 @@ static void __exit fini(void) | |||
605 | RCU_INIT_POINTER(nat_h245_hook, NULL); | 617 | RCU_INIT_POINTER(nat_h245_hook, NULL); |
606 | RCU_INIT_POINTER(nat_callforwarding_hook, NULL); | 618 | RCU_INIT_POINTER(nat_callforwarding_hook, NULL); |
607 | RCU_INIT_POINTER(nat_q931_hook, NULL); | 619 | RCU_INIT_POINTER(nat_q931_hook, NULL); |
620 | nf_ct_helper_expectfn_unregister(&q931_nat); | ||
621 | nf_ct_helper_expectfn_unregister(&callforwarding_nat); | ||
608 | synchronize_rcu(); | 622 | synchronize_rcu(); |
609 | } | 623 | } |
610 | 624 | ||
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index d0319f96269f..57932c43960e 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -526,6 +526,11 @@ err1: | |||
526 | return NF_DROP; | 526 | return NF_DROP; |
527 | } | 527 | } |
528 | 528 | ||
529 | static struct nf_ct_helper_expectfn sip_nat = { | ||
530 | .name = "sip", | ||
531 | .expectfn = ip_nat_sip_expected, | ||
532 | }; | ||
533 | |||
529 | static void __exit nf_nat_sip_fini(void) | 534 | static void __exit nf_nat_sip_fini(void) |
530 | { | 535 | { |
531 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); | 536 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); |
@@ -535,6 +540,7 @@ static void __exit nf_nat_sip_fini(void) | |||
535 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); | 540 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); |
536 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); | 541 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); |
537 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); | 542 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); |
543 | nf_ct_helper_expectfn_unregister(&sip_nat); | ||
538 | synchronize_rcu(); | 544 | synchronize_rcu(); |
539 | } | 545 | } |
540 | 546 | ||
@@ -554,6 +560,7 @@ static int __init nf_nat_sip_init(void) | |||
554 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); | 560 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); |
555 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); | 561 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); |
556 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); | 562 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); |
563 | nf_ct_helper_expectfn_register(&sip_nat); | ||
557 | return 0; | 564 | return 0; |
558 | } | 565 | } |
559 | 566 | ||
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 9a68fb5b9e77..d33cddd16fbb 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -154,15 +154,6 @@ config IP6_NF_TARGET_HL | |||
154 | (e.g. when running oldconfig). It selects | 154 | (e.g. when running oldconfig). It selects |
155 | CONFIG_NETFILTER_XT_TARGET_HL. | 155 | CONFIG_NETFILTER_XT_TARGET_HL. |
156 | 156 | ||
157 | config IP6_NF_TARGET_LOG | ||
158 | tristate "LOG target support" | ||
159 | default m if NETFILTER_ADVANCED=n | ||
160 | help | ||
161 | This option adds a `LOG' target, which allows you to create rules in | ||
162 | any iptables table which records the packet header to the syslog. | ||
163 | |||
164 | To compile it as a module, choose M here. If unsure, say N. | ||
165 | |||
166 | config IP6_NF_FILTER | 157 | config IP6_NF_FILTER |
167 | tristate "Packet filtering" | 158 | tristate "Packet filtering" |
168 | default m if NETFILTER_ADVANCED=n | 159 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 2eaed96db02c..d4dfd0a21097 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -31,5 +31,4 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o | |||
31 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 31 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
32 | 32 | ||
33 | # targets | 33 | # targets |
34 | obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o | ||
35 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o | 34 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c deleted file mode 100644 index e6af8d72f26b..000000000000 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ /dev/null | |||
@@ -1,527 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for logging packets. | ||
3 | */ | ||
4 | |||
5 | /* (C) 2001 Jan Rekorajski <baggins@pld.org.pl> | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/if_arp.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/icmpv6.h> | ||
19 | #include <net/udp.h> | ||
20 | #include <net/tcp.h> | ||
21 | #include <net/ipv6.h> | ||
22 | #include <linux/netfilter.h> | ||
23 | #include <linux/netfilter/x_tables.h> | ||
24 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
25 | #include <net/netfilter/nf_log.h> | ||
26 | #include <net/netfilter/xt_log.h> | ||
27 | |||
28 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); | ||
29 | MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | struct in_device; | ||
33 | #include <net/route.h> | ||
34 | #include <linux/netfilter_ipv6/ip6t_LOG.h> | ||
35 | |||
36 | /* One level of recursion won't kill us */ | ||
37 | static void dump_packet(struct sbuff *m, | ||
38 | const struct nf_loginfo *info, | ||
39 | const struct sk_buff *skb, unsigned int ip6hoff, | ||
40 | int recurse) | ||
41 | { | ||
42 | u_int8_t currenthdr; | ||
43 | int fragment; | ||
44 | struct ipv6hdr _ip6h; | ||
45 | const struct ipv6hdr *ih; | ||
46 | unsigned int ptr; | ||
47 | unsigned int hdrlen = 0; | ||
48 | unsigned int logflags; | ||
49 | |||
50 | if (info->type == NF_LOG_TYPE_LOG) | ||
51 | logflags = info->u.log.logflags; | ||
52 | else | ||
53 | logflags = NF_LOG_MASK; | ||
54 | |||
55 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | ||
56 | if (ih == NULL) { | ||
57 | sb_add(m, "TRUNCATED"); | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | ||
62 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | ||
63 | |||
64 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | ||
65 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | ||
66 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | ||
67 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | ||
68 | ih->hop_limit, | ||
69 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | ||
70 | |||
71 | fragment = 0; | ||
72 | ptr = ip6hoff + sizeof(struct ipv6hdr); | ||
73 | currenthdr = ih->nexthdr; | ||
74 | while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { | ||
75 | struct ipv6_opt_hdr _hdr; | ||
76 | const struct ipv6_opt_hdr *hp; | ||
77 | |||
78 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
79 | if (hp == NULL) { | ||
80 | sb_add(m, "TRUNCATED"); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | /* Max length: 48 "OPT (...) " */ | ||
85 | if (logflags & IP6T_LOG_IPOPT) | ||
86 | sb_add(m, "OPT ( "); | ||
87 | |||
88 | switch (currenthdr) { | ||
89 | case IPPROTO_FRAGMENT: { | ||
90 | struct frag_hdr _fhdr; | ||
91 | const struct frag_hdr *fh; | ||
92 | |||
93 | sb_add(m, "FRAG:"); | ||
94 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | ||
95 | &_fhdr); | ||
96 | if (fh == NULL) { | ||
97 | sb_add(m, "TRUNCATED "); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | /* Max length: 6 "65535 " */ | ||
102 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | ||
103 | |||
104 | /* Max length: 11 "INCOMPLETE " */ | ||
105 | if (fh->frag_off & htons(0x0001)) | ||
106 | sb_add(m, "INCOMPLETE "); | ||
107 | |||
108 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); | ||
109 | |||
110 | if (ntohs(fh->frag_off) & 0xFFF8) | ||
111 | fragment = 1; | ||
112 | |||
113 | hdrlen = 8; | ||
114 | |||
115 | break; | ||
116 | } | ||
117 | case IPPROTO_DSTOPTS: | ||
118 | case IPPROTO_ROUTING: | ||
119 | case IPPROTO_HOPOPTS: | ||
120 | if (fragment) { | ||
121 | if (logflags & IP6T_LOG_IPOPT) | ||
122 | sb_add(m, ")"); | ||
123 | return; | ||
124 | } | ||
125 | hdrlen = ipv6_optlen(hp); | ||
126 | break; | ||
127 | /* Max Length */ | ||
128 | case IPPROTO_AH: | ||
129 | if (logflags & IP6T_LOG_IPOPT) { | ||
130 | struct ip_auth_hdr _ahdr; | ||
131 | const struct ip_auth_hdr *ah; | ||
132 | |||
133 | /* Max length: 3 "AH " */ | ||
134 | sb_add(m, "AH "); | ||
135 | |||
136 | if (fragment) { | ||
137 | sb_add(m, ")"); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | ||
142 | &_ahdr); | ||
143 | if (ah == NULL) { | ||
144 | /* | ||
145 | * Max length: 26 "INCOMPLETE [65535 | ||
146 | * bytes] )" | ||
147 | */ | ||
148 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
149 | skb->len - ptr); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | /* Length: 15 "SPI=0xF1234567 */ | ||
154 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
155 | |||
156 | } | ||
157 | |||
158 | hdrlen = (hp->hdrlen+2)<<2; | ||
159 | break; | ||
160 | case IPPROTO_ESP: | ||
161 | if (logflags & IP6T_LOG_IPOPT) { | ||
162 | struct ip_esp_hdr _esph; | ||
163 | const struct ip_esp_hdr *eh; | ||
164 | |||
165 | /* Max length: 4 "ESP " */ | ||
166 | sb_add(m, "ESP "); | ||
167 | |||
168 | if (fragment) { | ||
169 | sb_add(m, ")"); | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Max length: 26 "INCOMPLETE [65535 bytes] )" | ||
175 | */ | ||
176 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | ||
177 | &_esph); | ||
178 | if (eh == NULL) { | ||
179 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
180 | skb->len - ptr); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | /* Length: 16 "SPI=0xF1234567 )" */ | ||
185 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi) ); | ||
186 | |||
187 | } | ||
188 | return; | ||
189 | default: | ||
190 | /* Max length: 20 "Unknown Ext Hdr 255" */ | ||
191 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); | ||
192 | return; | ||
193 | } | ||
194 | if (logflags & IP6T_LOG_IPOPT) | ||
195 | sb_add(m, ") "); | ||
196 | |||
197 | currenthdr = hp->nexthdr; | ||
198 | ptr += hdrlen; | ||
199 | } | ||
200 | |||
201 | switch (currenthdr) { | ||
202 | case IPPROTO_TCP: { | ||
203 | struct tcphdr _tcph; | ||
204 | const struct tcphdr *th; | ||
205 | |||
206 | /* Max length: 10 "PROTO=TCP " */ | ||
207 | sb_add(m, "PROTO=TCP "); | ||
208 | |||
209 | if (fragment) | ||
210 | break; | ||
211 | |||
212 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
213 | th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); | ||
214 | if (th == NULL) { | ||
215 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
220 | sb_add(m, "SPT=%u DPT=%u ", | ||
221 | ntohs(th->source), ntohs(th->dest)); | ||
222 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
223 | if (logflags & IP6T_LOG_TCPSEQ) | ||
224 | sb_add(m, "SEQ=%u ACK=%u ", | ||
225 | ntohl(th->seq), ntohl(th->ack_seq)); | ||
226 | /* Max length: 13 "WINDOW=65535 " */ | ||
227 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
228 | /* Max length: 9 "RES=0x3C " */ | ||
229 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); | ||
230 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
231 | if (th->cwr) | ||
232 | sb_add(m, "CWR "); | ||
233 | if (th->ece) | ||
234 | sb_add(m, "ECE "); | ||
235 | if (th->urg) | ||
236 | sb_add(m, "URG "); | ||
237 | if (th->ack) | ||
238 | sb_add(m, "ACK "); | ||
239 | if (th->psh) | ||
240 | sb_add(m, "PSH "); | ||
241 | if (th->rst) | ||
242 | sb_add(m, "RST "); | ||
243 | if (th->syn) | ||
244 | sb_add(m, "SYN "); | ||
245 | if (th->fin) | ||
246 | sb_add(m, "FIN "); | ||
247 | /* Max length: 11 "URGP=65535 " */ | ||
248 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
249 | |||
250 | if ((logflags & IP6T_LOG_TCPOPT) && | ||
251 | th->doff * 4 > sizeof(struct tcphdr)) { | ||
252 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | ||
253 | const u_int8_t *op; | ||
254 | unsigned int i; | ||
255 | unsigned int optsize = th->doff * 4 | ||
256 | - sizeof(struct tcphdr); | ||
257 | |||
258 | op = skb_header_pointer(skb, | ||
259 | ptr + sizeof(struct tcphdr), | ||
260 | optsize, _opt); | ||
261 | if (op == NULL) { | ||
262 | sb_add(m, "OPT (TRUNCATED)"); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
267 | sb_add(m, "OPT ("); | ||
268 | for (i =0; i < optsize; i++) | ||
269 | sb_add(m, "%02X", op[i]); | ||
270 | sb_add(m, ") "); | ||
271 | } | ||
272 | break; | ||
273 | } | ||
274 | case IPPROTO_UDP: | ||
275 | case IPPROTO_UDPLITE: { | ||
276 | struct udphdr _udph; | ||
277 | const struct udphdr *uh; | ||
278 | |||
279 | if (currenthdr == IPPROTO_UDP) | ||
280 | /* Max length: 10 "PROTO=UDP " */ | ||
281 | sb_add(m, "PROTO=UDP " ); | ||
282 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
283 | sb_add(m, "PROTO=UDPLITE "); | ||
284 | |||
285 | if (fragment) | ||
286 | break; | ||
287 | |||
288 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
289 | uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); | ||
290 | if (uh == NULL) { | ||
291 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
292 | return; | ||
293 | } | ||
294 | |||
295 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
296 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", | ||
297 | ntohs(uh->source), ntohs(uh->dest), | ||
298 | ntohs(uh->len)); | ||
299 | break; | ||
300 | } | ||
301 | case IPPROTO_ICMPV6: { | ||
302 | struct icmp6hdr _icmp6h; | ||
303 | const struct icmp6hdr *ic; | ||
304 | |||
305 | /* Max length: 13 "PROTO=ICMPv6 " */ | ||
306 | sb_add(m, "PROTO=ICMPv6 "); | ||
307 | |||
308 | if (fragment) | ||
309 | break; | ||
310 | |||
311 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
312 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | ||
313 | if (ic == NULL) { | ||
314 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
319 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | ||
320 | |||
321 | switch (ic->icmp6_type) { | ||
322 | case ICMPV6_ECHO_REQUEST: | ||
323 | case ICMPV6_ECHO_REPLY: | ||
324 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
325 | sb_add(m, "ID=%u SEQ=%u ", | ||
326 | ntohs(ic->icmp6_identifier), | ||
327 | ntohs(ic->icmp6_sequence)); | ||
328 | break; | ||
329 | case ICMPV6_MGM_QUERY: | ||
330 | case ICMPV6_MGM_REPORT: | ||
331 | case ICMPV6_MGM_REDUCTION: | ||
332 | break; | ||
333 | |||
334 | case ICMPV6_PARAMPROB: | ||
335 | /* Max length: 17 "POINTER=ffffffff " */ | ||
336 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); | ||
337 | /* Fall through */ | ||
338 | case ICMPV6_DEST_UNREACH: | ||
339 | case ICMPV6_PKT_TOOBIG: | ||
340 | case ICMPV6_TIME_EXCEED: | ||
341 | /* Max length: 3+maxlen */ | ||
342 | if (recurse) { | ||
343 | sb_add(m, "["); | ||
344 | dump_packet(m, info, skb, | ||
345 | ptr + sizeof(_icmp6h), 0); | ||
346 | sb_add(m, "] "); | ||
347 | } | ||
348 | |||
349 | /* Max length: 10 "MTU=65535 " */ | ||
350 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | ||
351 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); | ||
352 | } | ||
353 | break; | ||
354 | } | ||
355 | /* Max length: 10 "PROTO=255 " */ | ||
356 | default: | ||
357 | sb_add(m, "PROTO=%u ", currenthdr); | ||
358 | } | ||
359 | |||
360 | /* Max length: 15 "UID=4294967295 " */ | ||
361 | if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { | ||
362 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
363 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
364 | sb_add(m, "UID=%u GID=%u ", | ||
365 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
366 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
367 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
368 | } | ||
369 | |||
370 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
371 | if (!recurse && skb->mark) | ||
372 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
373 | } | ||
374 | |||
375 | static void dump_mac_header(struct sbuff *m, | ||
376 | const struct nf_loginfo *info, | ||
377 | const struct sk_buff *skb) | ||
378 | { | ||
379 | struct net_device *dev = skb->dev; | ||
380 | unsigned int logflags = 0; | ||
381 | |||
382 | if (info->type == NF_LOG_TYPE_LOG) | ||
383 | logflags = info->u.log.logflags; | ||
384 | |||
385 | if (!(logflags & IP6T_LOG_MACDECODE)) | ||
386 | goto fallback; | ||
387 | |||
388 | switch (dev->type) { | ||
389 | case ARPHRD_ETHER: | ||
390 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
392 | ntohs(eth_hdr(skb)->h_proto)); | ||
393 | return; | ||
394 | default: | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | fallback: | ||
399 | sb_add(m, "MAC="); | ||
400 | if (dev->hard_header_len && | ||
401 | skb->mac_header != skb->network_header) { | ||
402 | const unsigned char *p = skb_mac_header(skb); | ||
403 | unsigned int len = dev->hard_header_len; | ||
404 | unsigned int i; | ||
405 | |||
406 | if (dev->type == ARPHRD_SIT && | ||
407 | (p -= ETH_HLEN) < skb->head) | ||
408 | p = NULL; | ||
409 | |||
410 | if (p != NULL) { | ||
411 | sb_add(m, "%02x", *p++); | ||
412 | for (i = 1; i < len; i++) | ||
413 | sb_add(m, ":%02x", *p++); | ||
414 | } | ||
415 | sb_add(m, " "); | ||
416 | |||
417 | if (dev->type == ARPHRD_SIT) { | ||
418 | const struct iphdr *iph = | ||
419 | (struct iphdr *)skb_mac_header(skb); | ||
420 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); | ||
421 | } | ||
422 | } else | ||
423 | sb_add(m, " "); | ||
424 | } | ||
425 | |||
426 | static struct nf_loginfo default_loginfo = { | ||
427 | .type = NF_LOG_TYPE_LOG, | ||
428 | .u = { | ||
429 | .log = { | ||
430 | .level = 5, | ||
431 | .logflags = NF_LOG_MASK, | ||
432 | }, | ||
433 | }, | ||
434 | }; | ||
435 | |||
436 | static void | ||
437 | ip6t_log_packet(u_int8_t pf, | ||
438 | unsigned int hooknum, | ||
439 | const struct sk_buff *skb, | ||
440 | const struct net_device *in, | ||
441 | const struct net_device *out, | ||
442 | const struct nf_loginfo *loginfo, | ||
443 | const char *prefix) | ||
444 | { | ||
445 | struct sbuff *m = sb_open(); | ||
446 | |||
447 | if (!loginfo) | ||
448 | loginfo = &default_loginfo; | ||
449 | |||
450 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | ||
451 | prefix, | ||
452 | in ? in->name : "", | ||
453 | out ? out->name : ""); | ||
454 | |||
455 | if (in != NULL) | ||
456 | dump_mac_header(m, loginfo, skb); | ||
457 | |||
458 | dump_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
459 | |||
460 | sb_close(m); | ||
461 | } | ||
462 | |||
463 | static unsigned int | ||
464 | log_tg6(struct sk_buff *skb, const struct xt_action_param *par) | ||
465 | { | ||
466 | const struct ip6t_log_info *loginfo = par->targinfo; | ||
467 | struct nf_loginfo li; | ||
468 | |||
469 | li.type = NF_LOG_TYPE_LOG; | ||
470 | li.u.log.level = loginfo->level; | ||
471 | li.u.log.logflags = loginfo->logflags; | ||
472 | |||
473 | ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out, | ||
474 | &li, loginfo->prefix); | ||
475 | return XT_CONTINUE; | ||
476 | } | ||
477 | |||
478 | |||
479 | static int log_tg6_check(const struct xt_tgchk_param *par) | ||
480 | { | ||
481 | const struct ip6t_log_info *loginfo = par->targinfo; | ||
482 | |||
483 | if (loginfo->level >= 8) { | ||
484 | pr_debug("level %u >= 8\n", loginfo->level); | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | ||
488 | pr_debug("prefix not null-terminated\n"); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static struct xt_target log_tg6_reg __read_mostly = { | ||
495 | .name = "LOG", | ||
496 | .family = NFPROTO_IPV6, | ||
497 | .target = log_tg6, | ||
498 | .targetsize = sizeof(struct ip6t_log_info), | ||
499 | .checkentry = log_tg6_check, | ||
500 | .me = THIS_MODULE, | ||
501 | }; | ||
502 | |||
503 | static struct nf_logger ip6t_logger __read_mostly = { | ||
504 | .name = "ip6t_LOG", | ||
505 | .logfn = &ip6t_log_packet, | ||
506 | .me = THIS_MODULE, | ||
507 | }; | ||
508 | |||
509 | static int __init log_tg6_init(void) | ||
510 | { | ||
511 | int ret; | ||
512 | |||
513 | ret = xt_register_target(&log_tg6_reg); | ||
514 | if (ret < 0) | ||
515 | return ret; | ||
516 | nf_log_register(NFPROTO_IPV6, &ip6t_logger); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static void __exit log_tg6_exit(void) | ||
521 | { | ||
522 | nf_log_unregister(&ip6t_logger); | ||
523 | xt_unregister_target(&log_tg6_reg); | ||
524 | } | ||
525 | |||
526 | module_init(log_tg6_init); | ||
527 | module_exit(log_tg6_exit); | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 7c05e7eacbc6..92cc9f2931ae 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -88,25 +88,31 @@ static int icmpv6_print_tuple(struct seq_file *s, | |||
88 | ntohs(tuple->src.u.icmp.id)); | 88 | ntohs(tuple->src.u.icmp.id)); |
89 | } | 89 | } |
90 | 90 | ||
91 | static unsigned int *icmpv6_get_timeouts(struct net *net) | ||
92 | { | ||
93 | return &nf_ct_icmpv6_timeout; | ||
94 | } | ||
95 | |||
91 | /* Returns verdict for packet, or -1 for invalid. */ | 96 | /* Returns verdict for packet, or -1 for invalid. */ |
92 | static int icmpv6_packet(struct nf_conn *ct, | 97 | static int icmpv6_packet(struct nf_conn *ct, |
93 | const struct sk_buff *skb, | 98 | const struct sk_buff *skb, |
94 | unsigned int dataoff, | 99 | unsigned int dataoff, |
95 | enum ip_conntrack_info ctinfo, | 100 | enum ip_conntrack_info ctinfo, |
96 | u_int8_t pf, | 101 | u_int8_t pf, |
97 | unsigned int hooknum) | 102 | unsigned int hooknum, |
103 | unsigned int *timeout) | ||
98 | { | 104 | { |
99 | /* Do not immediately delete the connection after the first | 105 | /* Do not immediately delete the connection after the first |
100 | successful reply to avoid excessive conntrackd traffic | 106 | successful reply to avoid excessive conntrackd traffic |
101 | and also to handle correctly ICMP echo reply duplicates. */ | 107 | and also to handle correctly ICMP echo reply duplicates. */ |
102 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); | 108 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
103 | 109 | ||
104 | return NF_ACCEPT; | 110 | return NF_ACCEPT; |
105 | } | 111 | } |
106 | 112 | ||
107 | /* Called when a new connection for this protocol found. */ | 113 | /* Called when a new connection for this protocol found. */ |
108 | static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, | 114 | static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, |
109 | unsigned int dataoff) | 115 | unsigned int dataoff, unsigned int *timeouts) |
110 | { | 116 | { |
111 | static const u_int8_t valid_new[] = { | 117 | static const u_int8_t valid_new[] = { |
112 | [ICMPV6_ECHO_REQUEST - 128] = 1, | 118 | [ICMPV6_ECHO_REQUEST - 128] = 1, |
@@ -270,6 +276,44 @@ static int icmpv6_nlattr_tuple_size(void) | |||
270 | } | 276 | } |
271 | #endif | 277 | #endif |
272 | 278 | ||
279 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
280 | |||
281 | #include <linux/netfilter/nfnetlink.h> | ||
282 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
283 | |||
284 | static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
285 | { | ||
286 | unsigned int *timeout = data; | ||
287 | |||
288 | if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) { | ||
289 | *timeout = | ||
290 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ; | ||
291 | } else { | ||
292 | /* Set default ICMPv6 timeout. */ | ||
293 | *timeout = nf_ct_icmpv6_timeout; | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int | ||
299 | icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
300 | { | ||
301 | const unsigned int *timeout = data; | ||
302 | |||
303 | NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ)); | ||
304 | |||
305 | return 0; | ||
306 | |||
307 | nla_put_failure: | ||
308 | return -ENOSPC; | ||
309 | } | ||
310 | |||
311 | static const struct nla_policy | ||
312 | icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = { | ||
313 | [CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 }, | ||
314 | }; | ||
315 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
316 | |||
273 | #ifdef CONFIG_SYSCTL | 317 | #ifdef CONFIG_SYSCTL |
274 | static struct ctl_table_header *icmpv6_sysctl_header; | 318 | static struct ctl_table_header *icmpv6_sysctl_header; |
275 | static struct ctl_table icmpv6_sysctl_table[] = { | 319 | static struct ctl_table icmpv6_sysctl_table[] = { |
@@ -293,6 +337,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = | |||
293 | .invert_tuple = icmpv6_invert_tuple, | 337 | .invert_tuple = icmpv6_invert_tuple, |
294 | .print_tuple = icmpv6_print_tuple, | 338 | .print_tuple = icmpv6_print_tuple, |
295 | .packet = icmpv6_packet, | 339 | .packet = icmpv6_packet, |
340 | .get_timeouts = icmpv6_get_timeouts, | ||
296 | .new = icmpv6_new, | 341 | .new = icmpv6_new, |
297 | .error = icmpv6_error, | 342 | .error = icmpv6_error, |
298 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 343 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
@@ -301,6 +346,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = | |||
301 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, | 346 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
302 | .nla_policy = icmpv6_nla_policy, | 347 | .nla_policy = icmpv6_nla_policy, |
303 | #endif | 348 | #endif |
349 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
350 | .ctnl_timeout = { | ||
351 | .nlattr_to_obj = icmpv6_timeout_nlattr_to_obj, | ||
352 | .obj_to_nlattr = icmpv6_timeout_obj_to_nlattr, | ||
353 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, | ||
354 | .obj_size = sizeof(unsigned int), | ||
355 | .nla_policy = icmpv6_timeout_nla_policy, | ||
356 | }, | ||
357 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
304 | #ifdef CONFIG_SYSCTL | 358 | #ifdef CONFIG_SYSCTL |
305 | .ctl_table_header = &icmpv6_sysctl_header, | 359 | .ctl_table_header = &icmpv6_sysctl_header, |
306 | .ctl_table = icmpv6_sysctl_table, | 360 | .ctl_table = icmpv6_sysctl_table, |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f8ac4ef0b794..0c6f67e8f2e5 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -103,6 +103,16 @@ config NF_CONNTRACK_EVENTS | |||
103 | 103 | ||
104 | If unsure, say `N'. | 104 | If unsure, say `N'. |
105 | 105 | ||
106 | config NF_CONNTRACK_TIMEOUT | ||
107 | bool 'Connection tracking timeout' | ||
108 | depends on NETFILTER_ADVANCED | ||
109 | help | ||
110 | This option enables support for connection tracking timeout | ||
111 | extension. This allows you to attach timeout policies to flow | ||
112 | via the CT target. | ||
113 | |||
114 | If unsure, say `N'. | ||
115 | |||
106 | config NF_CONNTRACK_TIMESTAMP | 116 | config NF_CONNTRACK_TIMESTAMP |
107 | bool 'Connection tracking timestamping' | 117 | bool 'Connection tracking timestamping' |
108 | depends on NETFILTER_ADVANCED | 118 | depends on NETFILTER_ADVANCED |
@@ -314,6 +324,17 @@ config NF_CT_NETLINK | |||
314 | help | 324 | help |
315 | This option enables support for a netlink-based userspace interface | 325 | This option enables support for a netlink-based userspace interface |
316 | 326 | ||
327 | config NF_CT_NETLINK_TIMEOUT | ||
328 | tristate 'Connection tracking timeout tuning via Netlink' | ||
329 | select NETFILTER_NETLINK | ||
330 | depends on NETFILTER_ADVANCED | ||
331 | help | ||
332 | This option enables support for connection tracking timeout | ||
333 | fine-grain tuning. This allows you to attach specific timeout | ||
334 | policies to flows, instead of using the global timeout policy. | ||
335 | |||
336 | If unsure, say `N'. | ||
337 | |||
317 | endif # NF_CONNTRACK | 338 | endif # NF_CONNTRACK |
318 | 339 | ||
319 | # transparent proxy support | 340 | # transparent proxy support |
@@ -524,6 +545,15 @@ config NETFILTER_XT_TARGET_LED | |||
524 | For more information on the LEDs available on your system, see | 545 | For more information on the LEDs available on your system, see |
525 | Documentation/leds/leds-class.txt | 546 | Documentation/leds/leds-class.txt |
526 | 547 | ||
548 | config NETFILTER_XT_TARGET_LOG | ||
549 | tristate "LOG target support" | ||
550 | default m if NETFILTER_ADVANCED=n | ||
551 | help | ||
552 | This option adds a `LOG' target, which allows you to create rules in | ||
553 | any iptables table which records the packet header to the syslog. | ||
554 | |||
555 | To compile it as a module, choose M here. If unsure, say N. | ||
556 | |||
527 | config NETFILTER_XT_TARGET_MARK | 557 | config NETFILTER_XT_TARGET_MARK |
528 | tristate '"MARK" target support' | 558 | tristate '"MARK" target support' |
529 | depends on NETFILTER_ADVANCED | 559 | depends on NETFILTER_ADVANCED |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 40f4c3d636c5..ca3676586f51 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o | 1 | netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o |
2 | 2 | ||
3 | nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o | 3 | nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o |
4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o | ||
4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o | 5 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o |
5 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o | 6 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o |
6 | 7 | ||
@@ -22,6 +23,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o | |||
22 | 23 | ||
23 | # netlink interface for nf_conntrack | 24 | # netlink interface for nf_conntrack |
24 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o | 25 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o |
26 | obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o | ||
25 | 27 | ||
26 | # connection tracking helpers | 28 | # connection tracking helpers |
27 | nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o | 29 | nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o |
@@ -58,6 +60,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o | |||
58 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o | 60 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o |
59 | obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o | 61 | obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o |
60 | obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o | 62 | obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o |
63 | obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o | ||
61 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o | 64 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o |
62 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | 65 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
63 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o | 66 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index e3e73997c3be..a72a4dff0031 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c | |||
@@ -442,7 +442,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, | |||
442 | map->timeout = IPSET_NO_TIMEOUT; | 442 | map->timeout = IPSET_NO_TIMEOUT; |
443 | 443 | ||
444 | set->data = map; | 444 | set->data = map; |
445 | set->family = AF_INET; | 445 | set->family = NFPROTO_IPV4; |
446 | 446 | ||
447 | return true; | 447 | return true; |
448 | } | 448 | } |
@@ -550,7 +550,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { | |||
550 | .protocol = IPSET_PROTOCOL, | 550 | .protocol = IPSET_PROTOCOL, |
551 | .features = IPSET_TYPE_IP, | 551 | .features = IPSET_TYPE_IP, |
552 | .dimension = IPSET_DIM_ONE, | 552 | .dimension = IPSET_DIM_ONE, |
553 | .family = AF_INET, | 553 | .family = NFPROTO_IPV4, |
554 | .revision_min = 0, | 554 | .revision_min = 0, |
555 | .revision_max = 0, | 555 | .revision_max = 0, |
556 | .create = bitmap_ip_create, | 556 | .create = bitmap_ip_create, |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 56096f544978..81324c12c5be 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c | |||
@@ -543,7 +543,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, | |||
543 | map->timeout = IPSET_NO_TIMEOUT; | 543 | map->timeout = IPSET_NO_TIMEOUT; |
544 | 544 | ||
545 | set->data = map; | 545 | set->data = map; |
546 | set->family = AF_INET; | 546 | set->family = NFPROTO_IPV4; |
547 | 547 | ||
548 | return true; | 548 | return true; |
549 | } | 549 | } |
@@ -623,7 +623,7 @@ static struct ip_set_type bitmap_ipmac_type = { | |||
623 | .protocol = IPSET_PROTOCOL, | 623 | .protocol = IPSET_PROTOCOL, |
624 | .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, | 624 | .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, |
625 | .dimension = IPSET_DIM_TWO, | 625 | .dimension = IPSET_DIM_TWO, |
626 | .family = AF_INET, | 626 | .family = NFPROTO_IPV4, |
627 | .revision_min = 0, | 627 | .revision_min = 0, |
628 | .revision_max = 0, | 628 | .revision_max = 0, |
629 | .create = bitmap_ipmac_create, | 629 | .create = bitmap_ipmac_create, |
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 29ba93bb94be..382ec28ba72e 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c | |||
@@ -422,7 +422,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, | |||
422 | map->timeout = IPSET_NO_TIMEOUT; | 422 | map->timeout = IPSET_NO_TIMEOUT; |
423 | 423 | ||
424 | set->data = map; | 424 | set->data = map; |
425 | set->family = AF_UNSPEC; | 425 | set->family = NFPROTO_UNSPEC; |
426 | 426 | ||
427 | return true; | 427 | return true; |
428 | } | 428 | } |
@@ -483,7 +483,7 @@ static struct ip_set_type bitmap_port_type = { | |||
483 | .protocol = IPSET_PROTOCOL, | 483 | .protocol = IPSET_PROTOCOL, |
484 | .features = IPSET_TYPE_PORT, | 484 | .features = IPSET_TYPE_PORT, |
485 | .dimension = IPSET_DIM_ONE, | 485 | .dimension = IPSET_DIM_ONE, |
486 | .family = AF_UNSPEC, | 486 | .family = NFPROTO_UNSPEC, |
487 | .revision_min = 0, | 487 | .revision_min = 0, |
488 | .revision_max = 0, | 488 | .revision_max = 0, |
489 | .create = bitmap_port_create, | 489 | .create = bitmap_port_create, |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index e7f90e7082b4..e6c1c9605a58 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -69,7 +69,7 @@ find_set_type(const char *name, u8 family, u8 revision) | |||
69 | 69 | ||
70 | list_for_each_entry_rcu(type, &ip_set_type_list, list) | 70 | list_for_each_entry_rcu(type, &ip_set_type_list, list) |
71 | if (STREQ(type->name, name) && | 71 | if (STREQ(type->name, name) && |
72 | (type->family == family || type->family == AF_UNSPEC) && | 72 | (type->family == family || type->family == NFPROTO_UNSPEC) && |
73 | revision >= type->revision_min && | 73 | revision >= type->revision_min && |
74 | revision <= type->revision_max) | 74 | revision <= type->revision_max) |
75 | return type; | 75 | return type; |
@@ -149,7 +149,7 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, | |||
149 | rcu_read_lock(); | 149 | rcu_read_lock(); |
150 | list_for_each_entry_rcu(type, &ip_set_type_list, list) | 150 | list_for_each_entry_rcu(type, &ip_set_type_list, list) |
151 | if (STREQ(type->name, name) && | 151 | if (STREQ(type->name, name) && |
152 | (type->family == family || type->family == AF_UNSPEC)) { | 152 | (type->family == family || type->family == NFPROTO_UNSPEC)) { |
153 | found = true; | 153 | found = true; |
154 | if (type->revision_min < *min) | 154 | if (type->revision_min < *min) |
155 | *min = type->revision_min; | 155 | *min = type->revision_min; |
@@ -164,8 +164,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, | |||
164 | __find_set_type_minmax(name, family, min, max, true); | 164 | __find_set_type_minmax(name, family, min, max, true); |
165 | } | 165 | } |
166 | 166 | ||
167 | #define family_name(f) ((f) == AF_INET ? "inet" : \ | 167 | #define family_name(f) ((f) == NFPROTO_IPV4 ? "inet" : \ |
168 | (f) == AF_INET6 ? "inet6" : "any") | 168 | (f) == NFPROTO_IPV6 ? "inet6" : "any") |
169 | 169 | ||
170 | /* Register a set type structure. The type is identified by | 170 | /* Register a set type structure. The type is identified by |
171 | * the unique triple of name, family and revision. | 171 | * the unique triple of name, family and revision. |
@@ -354,7 +354,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, | |||
354 | pr_debug("set %s, index %u\n", set->name, index); | 354 | pr_debug("set %s, index %u\n", set->name, index); |
355 | 355 | ||
356 | if (opt->dim < set->type->dimension || | 356 | if (opt->dim < set->type->dimension || |
357 | !(opt->family == set->family || set->family == AF_UNSPEC)) | 357 | !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) |
358 | return 0; | 358 | return 0; |
359 | 359 | ||
360 | read_lock_bh(&set->lock); | 360 | read_lock_bh(&set->lock); |
@@ -387,7 +387,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, | |||
387 | pr_debug("set %s, index %u\n", set->name, index); | 387 | pr_debug("set %s, index %u\n", set->name, index); |
388 | 388 | ||
389 | if (opt->dim < set->type->dimension || | 389 | if (opt->dim < set->type->dimension || |
390 | !(opt->family == set->family || set->family == AF_UNSPEC)) | 390 | !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) |
391 | return 0; | 391 | return 0; |
392 | 392 | ||
393 | write_lock_bh(&set->lock); | 393 | write_lock_bh(&set->lock); |
@@ -410,7 +410,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, | |||
410 | pr_debug("set %s, index %u\n", set->name, index); | 410 | pr_debug("set %s, index %u\n", set->name, index); |
411 | 411 | ||
412 | if (opt->dim < set->type->dimension || | 412 | if (opt->dim < set->type->dimension || |
413 | !(opt->family == set->family || set->family == AF_UNSPEC)) | 413 | !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) |
414 | return 0; | 414 | return 0; |
415 | 415 | ||
416 | write_lock_bh(&set->lock); | 416 | write_lock_bh(&set->lock); |
@@ -575,7 +575,7 @@ start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, | |||
575 | return NULL; | 575 | return NULL; |
576 | 576 | ||
577 | nfmsg = nlmsg_data(nlh); | 577 | nfmsg = nlmsg_data(nlh); |
578 | nfmsg->nfgen_family = AF_INET; | 578 | nfmsg->nfgen_family = NFPROTO_IPV4; |
579 | nfmsg->version = NFNETLINK_V0; | 579 | nfmsg->version = NFNETLINK_V0; |
580 | nfmsg->res_id = 0; | 580 | nfmsg->res_id = 0; |
581 | 581 | ||
diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c index 1f03556666f4..6fdf88ae2353 100644 --- a/net/netfilter/ipset/ip_set_getport.c +++ b/net/netfilter/ipset/ip_set_getport.c | |||
@@ -136,10 +136,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) | |||
136 | u8 proto; | 136 | u8 proto; |
137 | 137 | ||
138 | switch (pf) { | 138 | switch (pf) { |
139 | case AF_INET: | 139 | case NFPROTO_IPV4: |
140 | ret = ip_set_get_ip4_port(skb, src, port, &proto); | 140 | ret = ip_set_get_ip4_port(skb, src, port, &proto); |
141 | break; | 141 | break; |
142 | case AF_INET6: | 142 | case NFPROTO_IPV6: |
143 | ret = ip_set_get_ip6_port(skb, src, port, &proto); | 143 | ret = ip_set_get_ip6_port(skb, src, port, &proto); |
144 | break; | 144 | break; |
145 | default: | 145 | default: |
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index 4015fcaf87bc..5139dea6019e 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c | |||
@@ -366,11 +366,11 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
366 | u8 netmask, hbits; | 366 | u8 netmask, hbits; |
367 | struct ip_set_hash *h; | 367 | struct ip_set_hash *h; |
368 | 368 | ||
369 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 369 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
370 | return -IPSET_ERR_INVALID_FAMILY; | 370 | return -IPSET_ERR_INVALID_FAMILY; |
371 | netmask = set->family == AF_INET ? 32 : 128; | 371 | netmask = set->family == NFPROTO_IPV4 ? 32 : 128; |
372 | pr_debug("Create set %s with family %s\n", | 372 | pr_debug("Create set %s with family %s\n", |
373 | set->name, set->family == AF_INET ? "inet" : "inet6"); | 373 | set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6"); |
374 | 374 | ||
375 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 375 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
376 | !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || | 376 | !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || |
@@ -389,8 +389,8 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
389 | if (tb[IPSET_ATTR_NETMASK]) { | 389 | if (tb[IPSET_ATTR_NETMASK]) { |
390 | netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); | 390 | netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); |
391 | 391 | ||
392 | if ((set->family == AF_INET && netmask > 32) || | 392 | if ((set->family == NFPROTO_IPV4 && netmask > 32) || |
393 | (set->family == AF_INET6 && netmask > 128) || | 393 | (set->family == NFPROTO_IPV6 && netmask > 128) || |
394 | netmask == 0) | 394 | netmask == 0) |
395 | return -IPSET_ERR_INVALID_NETMASK; | 395 | return -IPSET_ERR_INVALID_NETMASK; |
396 | } | 396 | } |
@@ -419,15 +419,15 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
419 | if (tb[IPSET_ATTR_TIMEOUT]) { | 419 | if (tb[IPSET_ATTR_TIMEOUT]) { |
420 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 420 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
421 | 421 | ||
422 | set->variant = set->family == AF_INET | 422 | set->variant = set->family == NFPROTO_IPV4 |
423 | ? &hash_ip4_tvariant : &hash_ip6_tvariant; | 423 | ? &hash_ip4_tvariant : &hash_ip6_tvariant; |
424 | 424 | ||
425 | if (set->family == AF_INET) | 425 | if (set->family == NFPROTO_IPV4) |
426 | hash_ip4_gc_init(set); | 426 | hash_ip4_gc_init(set); |
427 | else | 427 | else |
428 | hash_ip6_gc_init(set); | 428 | hash_ip6_gc_init(set); |
429 | } else { | 429 | } else { |
430 | set->variant = set->family == AF_INET | 430 | set->variant = set->family == NFPROTO_IPV4 |
431 | ? &hash_ip4_variant : &hash_ip6_variant; | 431 | ? &hash_ip4_variant : &hash_ip6_variant; |
432 | } | 432 | } |
433 | 433 | ||
@@ -443,7 +443,7 @@ static struct ip_set_type hash_ip_type __read_mostly = { | |||
443 | .protocol = IPSET_PROTOCOL, | 443 | .protocol = IPSET_PROTOCOL, |
444 | .features = IPSET_TYPE_IP, | 444 | .features = IPSET_TYPE_IP, |
445 | .dimension = IPSET_DIM_ONE, | 445 | .dimension = IPSET_DIM_ONE, |
446 | .family = AF_UNSPEC, | 446 | .family = NFPROTO_UNSPEC, |
447 | .revision_min = 0, | 447 | .revision_min = 0, |
448 | .revision_max = 0, | 448 | .revision_max = 0, |
449 | .create = hash_ip_create, | 449 | .create = hash_ip_create, |
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 37d667e3f6f8..9c27e249c171 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c | |||
@@ -450,7 +450,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
450 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; | 450 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; |
451 | u8 hbits; | 451 | u8 hbits; |
452 | 452 | ||
453 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 453 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
454 | return -IPSET_ERR_INVALID_FAMILY; | 454 | return -IPSET_ERR_INVALID_FAMILY; |
455 | 455 | ||
456 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 456 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
@@ -490,15 +490,15 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
490 | if (tb[IPSET_ATTR_TIMEOUT]) { | 490 | if (tb[IPSET_ATTR_TIMEOUT]) { |
491 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 491 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
492 | 492 | ||
493 | set->variant = set->family == AF_INET | 493 | set->variant = set->family == NFPROTO_IPV4 |
494 | ? &hash_ipport4_tvariant : &hash_ipport6_tvariant; | 494 | ? &hash_ipport4_tvariant : &hash_ipport6_tvariant; |
495 | 495 | ||
496 | if (set->family == AF_INET) | 496 | if (set->family == NFPROTO_IPV4) |
497 | hash_ipport4_gc_init(set); | 497 | hash_ipport4_gc_init(set); |
498 | else | 498 | else |
499 | hash_ipport6_gc_init(set); | 499 | hash_ipport6_gc_init(set); |
500 | } else { | 500 | } else { |
501 | set->variant = set->family == AF_INET | 501 | set->variant = set->family == NFPROTO_IPV4 |
502 | ? &hash_ipport4_variant : &hash_ipport6_variant; | 502 | ? &hash_ipport4_variant : &hash_ipport6_variant; |
503 | } | 503 | } |
504 | 504 | ||
@@ -514,7 +514,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = { | |||
514 | .protocol = IPSET_PROTOCOL, | 514 | .protocol = IPSET_PROTOCOL, |
515 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, | 515 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, |
516 | .dimension = IPSET_DIM_TWO, | 516 | .dimension = IPSET_DIM_TWO, |
517 | .family = AF_UNSPEC, | 517 | .family = NFPROTO_UNSPEC, |
518 | .revision_min = 0, | 518 | .revision_min = 0, |
519 | .revision_max = 1, /* SCTP and UDPLITE support added */ | 519 | .revision_max = 1, /* SCTP and UDPLITE support added */ |
520 | .create = hash_ipport_create, | 520 | .create = hash_ipport_create, |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index e69e2718fbe1..9134057c0728 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c | |||
@@ -468,7 +468,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
468 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; | 468 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; |
469 | u8 hbits; | 469 | u8 hbits; |
470 | 470 | ||
471 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 471 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
472 | return -IPSET_ERR_INVALID_FAMILY; | 472 | return -IPSET_ERR_INVALID_FAMILY; |
473 | 473 | ||
474 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 474 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
@@ -508,15 +508,15 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
508 | if (tb[IPSET_ATTR_TIMEOUT]) { | 508 | if (tb[IPSET_ATTR_TIMEOUT]) { |
509 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 509 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
510 | 510 | ||
511 | set->variant = set->family == AF_INET | 511 | set->variant = set->family == NFPROTO_IPV4 |
512 | ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant; | 512 | ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant; |
513 | 513 | ||
514 | if (set->family == AF_INET) | 514 | if (set->family == NFPROTO_IPV4) |
515 | hash_ipportip4_gc_init(set); | 515 | hash_ipportip4_gc_init(set); |
516 | else | 516 | else |
517 | hash_ipportip6_gc_init(set); | 517 | hash_ipportip6_gc_init(set); |
518 | } else { | 518 | } else { |
519 | set->variant = set->family == AF_INET | 519 | set->variant = set->family == NFPROTO_IPV4 |
520 | ? &hash_ipportip4_variant : &hash_ipportip6_variant; | 520 | ? &hash_ipportip4_variant : &hash_ipportip6_variant; |
521 | } | 521 | } |
522 | 522 | ||
@@ -532,7 +532,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { | |||
532 | .protocol = IPSET_PROTOCOL, | 532 | .protocol = IPSET_PROTOCOL, |
533 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, | 533 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, |
534 | .dimension = IPSET_DIM_THREE, | 534 | .dimension = IPSET_DIM_THREE, |
535 | .family = AF_UNSPEC, | 535 | .family = NFPROTO_UNSPEC, |
536 | .revision_min = 0, | 536 | .revision_min = 0, |
537 | .revision_max = 1, /* SCTP and UDPLITE support added */ | 537 | .revision_max = 1, /* SCTP and UDPLITE support added */ |
538 | .create = hash_ipportip_create, | 538 | .create = hash_ipportip_create, |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 64199b4e93c9..5d05e6969862 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -41,12 +41,19 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b); | |||
41 | 41 | ||
42 | /* The type variant functions: IPv4 */ | 42 | /* The type variant functions: IPv4 */ |
43 | 43 | ||
44 | /* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0 | ||
45 | * However this way we have to store internally cidr - 1, | ||
46 | * dancing back and forth. | ||
47 | */ | ||
48 | #define IP_SET_HASH_WITH_NETS_PACKED | ||
49 | |||
44 | /* Member elements without timeout */ | 50 | /* Member elements without timeout */ |
45 | struct hash_ipportnet4_elem { | 51 | struct hash_ipportnet4_elem { |
46 | __be32 ip; | 52 | __be32 ip; |
47 | __be32 ip2; | 53 | __be32 ip2; |
48 | __be16 port; | 54 | __be16 port; |
49 | u8 cidr; | 55 | u8 cidr:7; |
56 | u8 nomatch:1; | ||
50 | u8 proto; | 57 | u8 proto; |
51 | }; | 58 | }; |
52 | 59 | ||
@@ -55,7 +62,8 @@ struct hash_ipportnet4_telem { | |||
55 | __be32 ip; | 62 | __be32 ip; |
56 | __be32 ip2; | 63 | __be32 ip2; |
57 | __be16 port; | 64 | __be16 port; |
58 | u8 cidr; | 65 | u8 cidr:7; |
66 | u8 nomatch:1; | ||
59 | u8 proto; | 67 | u8 proto; |
60 | unsigned long timeout; | 68 | unsigned long timeout; |
61 | }; | 69 | }; |
@@ -86,10 +94,22 @@ hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst, | |||
86 | } | 94 | } |
87 | 95 | ||
88 | static inline void | 96 | static inline void |
97 | hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags) | ||
98 | { | ||
99 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | ||
100 | } | ||
101 | |||
102 | static inline bool | ||
103 | hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem) | ||
104 | { | ||
105 | return !elem->nomatch; | ||
106 | } | ||
107 | |||
108 | static inline void | ||
89 | hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr) | 109 | hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr) |
90 | { | 110 | { |
91 | elem->ip2 &= ip_set_netmask(cidr); | 111 | elem->ip2 &= ip_set_netmask(cidr); |
92 | elem->cidr = cidr; | 112 | elem->cidr = cidr - 1; |
93 | } | 113 | } |
94 | 114 | ||
95 | static inline void | 115 | static inline void |
@@ -102,11 +122,15 @@ static bool | |||
102 | hash_ipportnet4_data_list(struct sk_buff *skb, | 122 | hash_ipportnet4_data_list(struct sk_buff *skb, |
103 | const struct hash_ipportnet4_elem *data) | 123 | const struct hash_ipportnet4_elem *data) |
104 | { | 124 | { |
125 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
126 | |||
105 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); | 127 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); |
106 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2); | 128 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2); |
107 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); | 129 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); |
108 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); | 130 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); |
109 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 131 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
132 | if (flags) | ||
133 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
110 | return 0; | 134 | return 0; |
111 | 135 | ||
112 | nla_put_failure: | 136 | nla_put_failure: |
@@ -119,14 +143,17 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb, | |||
119 | { | 143 | { |
120 | const struct hash_ipportnet4_telem *tdata = | 144 | const struct hash_ipportnet4_telem *tdata = |
121 | (const struct hash_ipportnet4_telem *)data; | 145 | (const struct hash_ipportnet4_telem *)data; |
146 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
122 | 147 | ||
123 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); | 148 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); |
124 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2); | 149 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2); |
125 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); | 150 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); |
126 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); | 151 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); |
127 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 152 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
128 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 153 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
129 | htonl(ip_set_timeout_get(tdata->timeout))); | 154 | htonl(ip_set_timeout_get(tdata->timeout))); |
155 | if (flags) | ||
156 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
130 | 157 | ||
131 | return 0; | 158 | return 0; |
132 | 159 | ||
@@ -158,13 +185,11 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
158 | const struct ip_set_hash *h = set->data; | 185 | const struct ip_set_hash *h = set->data; |
159 | ipset_adtfn adtfn = set->variant->adt[adt]; | 186 | ipset_adtfn adtfn = set->variant->adt[adt]; |
160 | struct hash_ipportnet4_elem data = { | 187 | struct hash_ipportnet4_elem data = { |
161 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK | 188 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 |
162 | }; | 189 | }; |
163 | 190 | ||
164 | if (data.cidr == 0) | ||
165 | return -EINVAL; | ||
166 | if (adt == IPSET_TEST) | 191 | if (adt == IPSET_TEST) |
167 | data.cidr = HOST_MASK; | 192 | data.cidr = HOST_MASK - 1; |
168 | 193 | ||
169 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 194 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
170 | &data.port, &data.proto)) | 195 | &data.port, &data.proto)) |
@@ -172,7 +197,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
172 | 197 | ||
173 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip); | 198 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip); |
174 | ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2); | 199 | ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2); |
175 | data.ip2 &= ip_set_netmask(data.cidr); | 200 | data.ip2 &= ip_set_netmask(data.cidr + 1); |
176 | 201 | ||
177 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); | 202 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); |
178 | } | 203 | } |
@@ -183,17 +208,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
183 | { | 208 | { |
184 | const struct ip_set_hash *h = set->data; | 209 | const struct ip_set_hash *h = set->data; |
185 | ipset_adtfn adtfn = set->variant->adt[adt]; | 210 | ipset_adtfn adtfn = set->variant->adt[adt]; |
186 | struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; | 211 | struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 }; |
187 | u32 ip, ip_to = 0, p = 0, port, port_to; | 212 | u32 ip, ip_to = 0, p = 0, port, port_to; |
188 | u32 ip2_from = 0, ip2_to, ip2_last, ip2; | 213 | u32 ip2_from = 0, ip2_to, ip2_last, ip2; |
189 | u32 timeout = h->timeout; | 214 | u32 timeout = h->timeout; |
190 | bool with_ports = false; | 215 | bool with_ports = false; |
216 | u8 cidr; | ||
191 | int ret; | 217 | int ret; |
192 | 218 | ||
193 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || | 219 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || |
194 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | 220 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
195 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 221 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
196 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 222 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
223 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) | ||
197 | return -IPSET_ERR_PROTOCOL; | 224 | return -IPSET_ERR_PROTOCOL; |
198 | 225 | ||
199 | if (tb[IPSET_ATTR_LINENO]) | 226 | if (tb[IPSET_ATTR_LINENO]) |
@@ -208,9 +235,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
208 | return ret; | 235 | return ret; |
209 | 236 | ||
210 | if (tb[IPSET_ATTR_CIDR2]) { | 237 | if (tb[IPSET_ATTR_CIDR2]) { |
211 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | 238 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); |
212 | if (!data.cidr) | 239 | if (!cidr || cidr > HOST_MASK) |
213 | return -IPSET_ERR_INVALID_CIDR; | 240 | return -IPSET_ERR_INVALID_CIDR; |
241 | data.cidr = cidr - 1; | ||
214 | } | 242 | } |
215 | 243 | ||
216 | if (tb[IPSET_ATTR_PORT]) | 244 | if (tb[IPSET_ATTR_PORT]) |
@@ -236,12 +264,18 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
236 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 264 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
237 | } | 265 | } |
238 | 266 | ||
267 | if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { | ||
268 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
269 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
270 | flags |= (cadt_flags << 16); | ||
271 | } | ||
272 | |||
239 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; | 273 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; |
240 | if (adt == IPSET_TEST || | 274 | if (adt == IPSET_TEST || |
241 | !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports || | 275 | !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports || |
242 | tb[IPSET_ATTR_IP2_TO])) { | 276 | tb[IPSET_ATTR_IP2_TO])) { |
243 | data.ip = htonl(ip); | 277 | data.ip = htonl(ip); |
244 | data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr)); | 278 | data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr + 1)); |
245 | ret = adtfn(set, &data, timeout, flags); | 279 | ret = adtfn(set, &data, timeout, flags); |
246 | return ip_set_eexist(ret, flags) ? 0 : ret; | 280 | return ip_set_eexist(ret, flags) ? 0 : ret; |
247 | } | 281 | } |
@@ -275,7 +309,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
275 | if (ip2_from + UINT_MAX == ip2_to) | 309 | if (ip2_from + UINT_MAX == ip2_to) |
276 | return -IPSET_ERR_HASH_RANGE; | 310 | return -IPSET_ERR_HASH_RANGE; |
277 | } else { | 311 | } else { |
278 | ip_set_mask_from_to(ip2_from, ip2_to, data.cidr); | 312 | ip_set_mask_from_to(ip2_from, ip2_to, data.cidr + 1); |
279 | } | 313 | } |
280 | 314 | ||
281 | if (retried) | 315 | if (retried) |
@@ -290,7 +324,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
290 | while (!after(ip2, ip2_to)) { | 324 | while (!after(ip2, ip2_to)) { |
291 | data.ip2 = htonl(ip2); | 325 | data.ip2 = htonl(ip2); |
292 | ip2_last = ip_set_range_to_cidr(ip2, ip2_to, | 326 | ip2_last = ip_set_range_to_cidr(ip2, ip2_to, |
293 | &data.cidr); | 327 | &cidr); |
328 | data.cidr = cidr - 1; | ||
294 | ret = adtfn(set, &data, timeout, flags); | 329 | ret = adtfn(set, &data, timeout, flags); |
295 | 330 | ||
296 | if (ret && !ip_set_eexist(ret, flags)) | 331 | if (ret && !ip_set_eexist(ret, flags)) |
@@ -321,7 +356,8 @@ struct hash_ipportnet6_elem { | |||
321 | union nf_inet_addr ip; | 356 | union nf_inet_addr ip; |
322 | union nf_inet_addr ip2; | 357 | union nf_inet_addr ip2; |
323 | __be16 port; | 358 | __be16 port; |
324 | u8 cidr; | 359 | u8 cidr:7; |
360 | u8 nomatch:1; | ||
325 | u8 proto; | 361 | u8 proto; |
326 | }; | 362 | }; |
327 | 363 | ||
@@ -329,7 +365,8 @@ struct hash_ipportnet6_telem { | |||
329 | union nf_inet_addr ip; | 365 | union nf_inet_addr ip; |
330 | union nf_inet_addr ip2; | 366 | union nf_inet_addr ip2; |
331 | __be16 port; | 367 | __be16 port; |
332 | u8 cidr; | 368 | u8 cidr:7; |
369 | u8 nomatch:1; | ||
333 | u8 proto; | 370 | u8 proto; |
334 | unsigned long timeout; | 371 | unsigned long timeout; |
335 | }; | 372 | }; |
@@ -360,6 +397,18 @@ hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst, | |||
360 | } | 397 | } |
361 | 398 | ||
362 | static inline void | 399 | static inline void |
400 | hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags) | ||
401 | { | ||
402 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | ||
403 | } | ||
404 | |||
405 | static inline bool | ||
406 | hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem) | ||
407 | { | ||
408 | return !elem->nomatch; | ||
409 | } | ||
410 | |||
411 | static inline void | ||
363 | hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem) | 412 | hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem) |
364 | { | 413 | { |
365 | elem->proto = 0; | 414 | elem->proto = 0; |
@@ -378,18 +427,22 @@ static inline void | |||
378 | hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr) | 427 | hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr) |
379 | { | 428 | { |
380 | ip6_netmask(&elem->ip2, cidr); | 429 | ip6_netmask(&elem->ip2, cidr); |
381 | elem->cidr = cidr; | 430 | elem->cidr = cidr - 1; |
382 | } | 431 | } |
383 | 432 | ||
384 | static bool | 433 | static bool |
385 | hash_ipportnet6_data_list(struct sk_buff *skb, | 434 | hash_ipportnet6_data_list(struct sk_buff *skb, |
386 | const struct hash_ipportnet6_elem *data) | 435 | const struct hash_ipportnet6_elem *data) |
387 | { | 436 | { |
437 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
438 | |||
388 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); | 439 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); |
389 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); | 440 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); |
390 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); | 441 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); |
391 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); | 442 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); |
392 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 443 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
444 | if (flags) | ||
445 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
393 | return 0; | 446 | return 0; |
394 | 447 | ||
395 | nla_put_failure: | 448 | nla_put_failure: |
@@ -402,14 +455,17 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb, | |||
402 | { | 455 | { |
403 | const struct hash_ipportnet6_telem *e = | 456 | const struct hash_ipportnet6_telem *e = |
404 | (const struct hash_ipportnet6_telem *)data; | 457 | (const struct hash_ipportnet6_telem *)data; |
458 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
405 | 459 | ||
406 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); | 460 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); |
407 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); | 461 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); |
408 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); | 462 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); |
409 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); | 463 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr + 1); |
410 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 464 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
411 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 465 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
412 | htonl(ip_set_timeout_get(e->timeout))); | 466 | htonl(ip_set_timeout_get(e->timeout))); |
467 | if (flags) | ||
468 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
413 | return 0; | 469 | return 0; |
414 | 470 | ||
415 | nla_put_failure: | 471 | nla_put_failure: |
@@ -438,13 +494,11 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
438 | const struct ip_set_hash *h = set->data; | 494 | const struct ip_set_hash *h = set->data; |
439 | ipset_adtfn adtfn = set->variant->adt[adt]; | 495 | ipset_adtfn adtfn = set->variant->adt[adt]; |
440 | struct hash_ipportnet6_elem data = { | 496 | struct hash_ipportnet6_elem data = { |
441 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK | 497 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 |
442 | }; | 498 | }; |
443 | 499 | ||
444 | if (data.cidr == 0) | ||
445 | return -EINVAL; | ||
446 | if (adt == IPSET_TEST) | 500 | if (adt == IPSET_TEST) |
447 | data.cidr = HOST_MASK; | 501 | data.cidr = HOST_MASK - 1; |
448 | 502 | ||
449 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 503 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
450 | &data.port, &data.proto)) | 504 | &data.port, &data.proto)) |
@@ -452,7 +506,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
452 | 506 | ||
453 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6); | 507 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6); |
454 | ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6); | 508 | ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6); |
455 | ip6_netmask(&data.ip2, data.cidr); | 509 | ip6_netmask(&data.ip2, data.cidr + 1); |
456 | 510 | ||
457 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); | 511 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); |
458 | } | 512 | } |
@@ -463,16 +517,18 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
463 | { | 517 | { |
464 | const struct ip_set_hash *h = set->data; | 518 | const struct ip_set_hash *h = set->data; |
465 | ipset_adtfn adtfn = set->variant->adt[adt]; | 519 | ipset_adtfn adtfn = set->variant->adt[adt]; |
466 | struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; | 520 | struct hash_ipportnet6_elem data = { .cidr = HOST_MASK - 1 }; |
467 | u32 port, port_to; | 521 | u32 port, port_to; |
468 | u32 timeout = h->timeout; | 522 | u32 timeout = h->timeout; |
469 | bool with_ports = false; | 523 | bool with_ports = false; |
524 | u8 cidr; | ||
470 | int ret; | 525 | int ret; |
471 | 526 | ||
472 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || | 527 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || |
473 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | 528 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
474 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 529 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
475 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 530 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
531 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | ||
476 | tb[IPSET_ATTR_IP_TO] || | 532 | tb[IPSET_ATTR_IP_TO] || |
477 | tb[IPSET_ATTR_CIDR])) | 533 | tb[IPSET_ATTR_CIDR])) |
478 | return -IPSET_ERR_PROTOCOL; | 534 | return -IPSET_ERR_PROTOCOL; |
@@ -490,13 +546,14 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
490 | if (ret) | 546 | if (ret) |
491 | return ret; | 547 | return ret; |
492 | 548 | ||
493 | if (tb[IPSET_ATTR_CIDR2]) | 549 | if (tb[IPSET_ATTR_CIDR2]) { |
494 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | 550 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); |
495 | 551 | if (!cidr || cidr > HOST_MASK) | |
496 | if (!data.cidr) | 552 | return -IPSET_ERR_INVALID_CIDR; |
497 | return -IPSET_ERR_INVALID_CIDR; | 553 | data.cidr = cidr - 1; |
554 | } | ||
498 | 555 | ||
499 | ip6_netmask(&data.ip2, data.cidr); | 556 | ip6_netmask(&data.ip2, data.cidr + 1); |
500 | 557 | ||
501 | if (tb[IPSET_ATTR_PORT]) | 558 | if (tb[IPSET_ATTR_PORT]) |
502 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); | 559 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); |
@@ -521,6 +578,12 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
521 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 578 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
522 | } | 579 | } |
523 | 580 | ||
581 | if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { | ||
582 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
583 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
584 | flags |= (cadt_flags << 16); | ||
585 | } | ||
586 | |||
524 | if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { | 587 | if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { |
525 | ret = adtfn(set, &data, timeout, flags); | 588 | ret = adtfn(set, &data, timeout, flags); |
526 | return ip_set_eexist(ret, flags) ? 0 : ret; | 589 | return ip_set_eexist(ret, flags) ? 0 : ret; |
@@ -554,7 +617,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
554 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; | 617 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; |
555 | u8 hbits; | 618 | u8 hbits; |
556 | 619 | ||
557 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 620 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
558 | return -IPSET_ERR_INVALID_FAMILY; | 621 | return -IPSET_ERR_INVALID_FAMILY; |
559 | 622 | ||
560 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 623 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
@@ -573,7 +636,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
573 | 636 | ||
574 | h = kzalloc(sizeof(*h) | 637 | h = kzalloc(sizeof(*h) |
575 | + sizeof(struct ip_set_hash_nets) | 638 | + sizeof(struct ip_set_hash_nets) |
576 | * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); | 639 | * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); |
577 | if (!h) | 640 | if (!h) |
578 | return -ENOMEM; | 641 | return -ENOMEM; |
579 | 642 | ||
@@ -596,16 +659,16 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
596 | if (tb[IPSET_ATTR_TIMEOUT]) { | 659 | if (tb[IPSET_ATTR_TIMEOUT]) { |
597 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 660 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
598 | 661 | ||
599 | set->variant = set->family == AF_INET | 662 | set->variant = set->family == NFPROTO_IPV4 |
600 | ? &hash_ipportnet4_tvariant | 663 | ? &hash_ipportnet4_tvariant |
601 | : &hash_ipportnet6_tvariant; | 664 | : &hash_ipportnet6_tvariant; |
602 | 665 | ||
603 | if (set->family == AF_INET) | 666 | if (set->family == NFPROTO_IPV4) |
604 | hash_ipportnet4_gc_init(set); | 667 | hash_ipportnet4_gc_init(set); |
605 | else | 668 | else |
606 | hash_ipportnet6_gc_init(set); | 669 | hash_ipportnet6_gc_init(set); |
607 | } else { | 670 | } else { |
608 | set->variant = set->family == AF_INET | 671 | set->variant = set->family == NFPROTO_IPV4 |
609 | ? &hash_ipportnet4_variant : &hash_ipportnet6_variant; | 672 | ? &hash_ipportnet4_variant : &hash_ipportnet6_variant; |
610 | } | 673 | } |
611 | 674 | ||
@@ -621,10 +684,11 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
621 | .protocol = IPSET_PROTOCOL, | 684 | .protocol = IPSET_PROTOCOL, |
622 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, | 685 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, |
623 | .dimension = IPSET_DIM_THREE, | 686 | .dimension = IPSET_DIM_THREE, |
624 | .family = AF_UNSPEC, | 687 | .family = NFPROTO_UNSPEC, |
625 | .revision_min = 0, | 688 | .revision_min = 0, |
626 | /* 1 SCTP and UDPLITE support added */ | 689 | /* 1 SCTP and UDPLITE support added */ |
627 | .revision_max = 2, /* Range as input support for IPv4 added */ | 690 | /* 2 Range as input support for IPv4 added */ |
691 | .revision_max = 3, /* nomatch flag support added */ | ||
628 | .create = hash_ipportnet_create, | 692 | .create = hash_ipportnet_create, |
629 | .create_policy = { | 693 | .create_policy = { |
630 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 694 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
@@ -643,6 +707,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
643 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | 707 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
644 | [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, | 708 | [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, |
645 | [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, | 709 | [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, |
710 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
646 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | 711 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
647 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 712 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
648 | }, | 713 | }, |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 28988196775e..7c3d945517cf 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -43,7 +43,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b); | |||
43 | struct hash_net4_elem { | 43 | struct hash_net4_elem { |
44 | __be32 ip; | 44 | __be32 ip; |
45 | u16 padding0; | 45 | u16 padding0; |
46 | u8 padding1; | 46 | u8 nomatch; |
47 | u8 cidr; | 47 | u8 cidr; |
48 | }; | 48 | }; |
49 | 49 | ||
@@ -51,7 +51,7 @@ struct hash_net4_elem { | |||
51 | struct hash_net4_telem { | 51 | struct hash_net4_telem { |
52 | __be32 ip; | 52 | __be32 ip; |
53 | u16 padding0; | 53 | u16 padding0; |
54 | u8 padding1; | 54 | u8 nomatch; |
55 | u8 cidr; | 55 | u8 cidr; |
56 | unsigned long timeout; | 56 | unsigned long timeout; |
57 | }; | 57 | }; |
@@ -61,7 +61,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1, | |||
61 | const struct hash_net4_elem *ip2, | 61 | const struct hash_net4_elem *ip2, |
62 | u32 *multi) | 62 | u32 *multi) |
63 | { | 63 | { |
64 | return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; | 64 | return ip1->ip == ip2->ip && |
65 | ip1->cidr == ip2->cidr; | ||
65 | } | 66 | } |
66 | 67 | ||
67 | static inline bool | 68 | static inline bool |
@@ -76,6 +77,19 @@ hash_net4_data_copy(struct hash_net4_elem *dst, | |||
76 | { | 77 | { |
77 | dst->ip = src->ip; | 78 | dst->ip = src->ip; |
78 | dst->cidr = src->cidr; | 79 | dst->cidr = src->cidr; |
80 | dst->nomatch = src->nomatch; | ||
81 | } | ||
82 | |||
83 | static inline void | ||
84 | hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags) | ||
85 | { | ||
86 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | ||
87 | } | ||
88 | |||
89 | static inline bool | ||
90 | hash_net4_data_match(const struct hash_net4_elem *elem) | ||
91 | { | ||
92 | return !elem->nomatch; | ||
79 | } | 93 | } |
80 | 94 | ||
81 | static inline void | 95 | static inline void |
@@ -95,8 +109,12 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem) | |||
95 | static bool | 109 | static bool |
96 | hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) | 110 | hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) |
97 | { | 111 | { |
112 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
113 | |||
98 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); | 114 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); |
99 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 115 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); |
116 | if (flags) | ||
117 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
100 | return 0; | 118 | return 0; |
101 | 119 | ||
102 | nla_put_failure: | 120 | nla_put_failure: |
@@ -108,11 +126,14 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data) | |||
108 | { | 126 | { |
109 | const struct hash_net4_telem *tdata = | 127 | const struct hash_net4_telem *tdata = |
110 | (const struct hash_net4_telem *)data; | 128 | (const struct hash_net4_telem *)data; |
129 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
111 | 130 | ||
112 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); | 131 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); |
113 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr); | 132 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr); |
114 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 133 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
115 | htonl(ip_set_timeout_get(tdata->timeout))); | 134 | htonl(ip_set_timeout_get(tdata->timeout))); |
135 | if (flags) | ||
136 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
116 | 137 | ||
117 | return 0; | 138 | return 0; |
118 | 139 | ||
@@ -167,7 +188,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
167 | int ret; | 188 | int ret; |
168 | 189 | ||
169 | if (unlikely(!tb[IPSET_ATTR_IP] || | 190 | if (unlikely(!tb[IPSET_ATTR_IP] || |
170 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 191 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
192 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) | ||
171 | return -IPSET_ERR_PROTOCOL; | 193 | return -IPSET_ERR_PROTOCOL; |
172 | 194 | ||
173 | if (tb[IPSET_ATTR_LINENO]) | 195 | if (tb[IPSET_ATTR_LINENO]) |
@@ -179,7 +201,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
179 | 201 | ||
180 | if (tb[IPSET_ATTR_CIDR]) { | 202 | if (tb[IPSET_ATTR_CIDR]) { |
181 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 203 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
182 | if (!data.cidr) | 204 | if (!data.cidr || data.cidr > HOST_MASK) |
183 | return -IPSET_ERR_INVALID_CIDR; | 205 | return -IPSET_ERR_INVALID_CIDR; |
184 | } | 206 | } |
185 | 207 | ||
@@ -189,6 +211,12 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
189 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 211 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
190 | } | 212 | } |
191 | 213 | ||
214 | if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { | ||
215 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
216 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
217 | flags |= (cadt_flags << 16); | ||
218 | } | ||
219 | |||
192 | if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { | 220 | if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { |
193 | data.ip = htonl(ip & ip_set_hostmask(data.cidr)); | 221 | data.ip = htonl(ip & ip_set_hostmask(data.cidr)); |
194 | ret = adtfn(set, &data, timeout, flags); | 222 | ret = adtfn(set, &data, timeout, flags); |
@@ -236,14 +264,14 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b) | |||
236 | struct hash_net6_elem { | 264 | struct hash_net6_elem { |
237 | union nf_inet_addr ip; | 265 | union nf_inet_addr ip; |
238 | u16 padding0; | 266 | u16 padding0; |
239 | u8 padding1; | 267 | u8 nomatch; |
240 | u8 cidr; | 268 | u8 cidr; |
241 | }; | 269 | }; |
242 | 270 | ||
243 | struct hash_net6_telem { | 271 | struct hash_net6_telem { |
244 | union nf_inet_addr ip; | 272 | union nf_inet_addr ip; |
245 | u16 padding0; | 273 | u16 padding0; |
246 | u8 padding1; | 274 | u8 nomatch; |
247 | u8 cidr; | 275 | u8 cidr; |
248 | unsigned long timeout; | 276 | unsigned long timeout; |
249 | }; | 277 | }; |
@@ -269,6 +297,19 @@ hash_net6_data_copy(struct hash_net6_elem *dst, | |||
269 | { | 297 | { |
270 | dst->ip.in6 = src->ip.in6; | 298 | dst->ip.in6 = src->ip.in6; |
271 | dst->cidr = src->cidr; | 299 | dst->cidr = src->cidr; |
300 | dst->nomatch = src->nomatch; | ||
301 | } | ||
302 | |||
303 | static inline void | ||
304 | hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags) | ||
305 | { | ||
306 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | ||
307 | } | ||
308 | |||
309 | static inline bool | ||
310 | hash_net6_data_match(const struct hash_net6_elem *elem) | ||
311 | { | ||
312 | return !elem->nomatch; | ||
272 | } | 313 | } |
273 | 314 | ||
274 | static inline void | 315 | static inline void |
@@ -296,8 +337,12 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr) | |||
296 | static bool | 337 | static bool |
297 | hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) | 338 | hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) |
298 | { | 339 | { |
340 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
341 | |||
299 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); | 342 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); |
300 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 343 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); |
344 | if (flags) | ||
345 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
301 | return 0; | 346 | return 0; |
302 | 347 | ||
303 | nla_put_failure: | 348 | nla_put_failure: |
@@ -309,11 +354,14 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data) | |||
309 | { | 354 | { |
310 | const struct hash_net6_telem *e = | 355 | const struct hash_net6_telem *e = |
311 | (const struct hash_net6_telem *)data; | 356 | (const struct hash_net6_telem *)data; |
357 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
312 | 358 | ||
313 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); | 359 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); |
314 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr); | 360 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr); |
315 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 361 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
316 | htonl(ip_set_timeout_get(e->timeout))); | 362 | htonl(ip_set_timeout_get(e->timeout))); |
363 | if (flags) | ||
364 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
317 | return 0; | 365 | return 0; |
318 | 366 | ||
319 | nla_put_failure: | 367 | nla_put_failure: |
@@ -366,7 +414,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
366 | int ret; | 414 | int ret; |
367 | 415 | ||
368 | if (unlikely(!tb[IPSET_ATTR_IP] || | 416 | if (unlikely(!tb[IPSET_ATTR_IP] || |
369 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 417 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
418 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) | ||
370 | return -IPSET_ERR_PROTOCOL; | 419 | return -IPSET_ERR_PROTOCOL; |
371 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | 420 | if (unlikely(tb[IPSET_ATTR_IP_TO])) |
372 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 421 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -381,7 +430,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
381 | if (tb[IPSET_ATTR_CIDR]) | 430 | if (tb[IPSET_ATTR_CIDR]) |
382 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 431 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
383 | 432 | ||
384 | if (!data.cidr) | 433 | if (!data.cidr || data.cidr > HOST_MASK) |
385 | return -IPSET_ERR_INVALID_CIDR; | 434 | return -IPSET_ERR_INVALID_CIDR; |
386 | 435 | ||
387 | ip6_netmask(&data.ip, data.cidr); | 436 | ip6_netmask(&data.ip, data.cidr); |
@@ -392,6 +441,12 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
392 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 441 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
393 | } | 442 | } |
394 | 443 | ||
444 | if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { | ||
445 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
446 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
447 | flags |= (cadt_flags << 16); | ||
448 | } | ||
449 | |||
395 | ret = adtfn(set, &data, timeout, flags); | 450 | ret = adtfn(set, &data, timeout, flags); |
396 | 451 | ||
397 | return ip_set_eexist(ret, flags) ? 0 : ret; | 452 | return ip_set_eexist(ret, flags) ? 0 : ret; |
@@ -406,7 +461,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
406 | struct ip_set_hash *h; | 461 | struct ip_set_hash *h; |
407 | u8 hbits; | 462 | u8 hbits; |
408 | 463 | ||
409 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 464 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
410 | return -IPSET_ERR_INVALID_FAMILY; | 465 | return -IPSET_ERR_INVALID_FAMILY; |
411 | 466 | ||
412 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 467 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
@@ -425,7 +480,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
425 | 480 | ||
426 | h = kzalloc(sizeof(*h) | 481 | h = kzalloc(sizeof(*h) |
427 | + sizeof(struct ip_set_hash_nets) | 482 | + sizeof(struct ip_set_hash_nets) |
428 | * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); | 483 | * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); |
429 | if (!h) | 484 | if (!h) |
430 | return -ENOMEM; | 485 | return -ENOMEM; |
431 | 486 | ||
@@ -448,15 +503,15 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
448 | if (tb[IPSET_ATTR_TIMEOUT]) { | 503 | if (tb[IPSET_ATTR_TIMEOUT]) { |
449 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 504 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
450 | 505 | ||
451 | set->variant = set->family == AF_INET | 506 | set->variant = set->family == NFPROTO_IPV4 |
452 | ? &hash_net4_tvariant : &hash_net6_tvariant; | 507 | ? &hash_net4_tvariant : &hash_net6_tvariant; |
453 | 508 | ||
454 | if (set->family == AF_INET) | 509 | if (set->family == NFPROTO_IPV4) |
455 | hash_net4_gc_init(set); | 510 | hash_net4_gc_init(set); |
456 | else | 511 | else |
457 | hash_net6_gc_init(set); | 512 | hash_net6_gc_init(set); |
458 | } else { | 513 | } else { |
459 | set->variant = set->family == AF_INET | 514 | set->variant = set->family == NFPROTO_IPV4 |
460 | ? &hash_net4_variant : &hash_net6_variant; | 515 | ? &hash_net4_variant : &hash_net6_variant; |
461 | } | 516 | } |
462 | 517 | ||
@@ -472,9 +527,10 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
472 | .protocol = IPSET_PROTOCOL, | 527 | .protocol = IPSET_PROTOCOL, |
473 | .features = IPSET_TYPE_IP, | 528 | .features = IPSET_TYPE_IP, |
474 | .dimension = IPSET_DIM_ONE, | 529 | .dimension = IPSET_DIM_ONE, |
475 | .family = AF_UNSPEC, | 530 | .family = NFPROTO_UNSPEC, |
476 | .revision_min = 0, | 531 | .revision_min = 0, |
477 | .revision_max = 1, /* Range as input support for IPv4 added */ | 532 | /* = 1 Range as input support for IPv4 added */ |
533 | .revision_max = 2, /* nomatch flag support added */ | ||
478 | .create = hash_net_create, | 534 | .create = hash_net_create, |
479 | .create_policy = { | 535 | .create_policy = { |
480 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 536 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
@@ -488,6 +544,7 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
488 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | 544 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, |
489 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | 545 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
490 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | 546 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
547 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
491 | }, | 548 | }, |
492 | .me = THIS_MODULE, | 549 | .me = THIS_MODULE, |
493 | }; | 550 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index e13095deb50d..f24037ff4322 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
@@ -163,7 +163,8 @@ struct hash_netiface4_elem_hashed { | |||
163 | __be32 ip; | 163 | __be32 ip; |
164 | u8 physdev; | 164 | u8 physdev; |
165 | u8 cidr; | 165 | u8 cidr; |
166 | u16 padding; | 166 | u8 nomatch; |
167 | u8 padding; | ||
167 | }; | 168 | }; |
168 | 169 | ||
169 | #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) | 170 | #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) |
@@ -173,7 +174,8 @@ struct hash_netiface4_elem { | |||
173 | __be32 ip; | 174 | __be32 ip; |
174 | u8 physdev; | 175 | u8 physdev; |
175 | u8 cidr; | 176 | u8 cidr; |
176 | u16 padding; | 177 | u8 nomatch; |
178 | u8 padding; | ||
177 | const char *iface; | 179 | const char *iface; |
178 | }; | 180 | }; |
179 | 181 | ||
@@ -182,7 +184,8 @@ struct hash_netiface4_telem { | |||
182 | __be32 ip; | 184 | __be32 ip; |
183 | u8 physdev; | 185 | u8 physdev; |
184 | u8 cidr; | 186 | u8 cidr; |
185 | u16 padding; | 187 | u8 nomatch; |
188 | u8 padding; | ||
186 | const char *iface; | 189 | const char *iface; |
187 | unsigned long timeout; | 190 | unsigned long timeout; |
188 | }; | 191 | }; |
@@ -207,11 +210,25 @@ hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem) | |||
207 | 210 | ||
208 | static inline void | 211 | static inline void |
209 | hash_netiface4_data_copy(struct hash_netiface4_elem *dst, | 212 | hash_netiface4_data_copy(struct hash_netiface4_elem *dst, |
210 | const struct hash_netiface4_elem *src) { | 213 | const struct hash_netiface4_elem *src) |
214 | { | ||
211 | dst->ip = src->ip; | 215 | dst->ip = src->ip; |
212 | dst->cidr = src->cidr; | 216 | dst->cidr = src->cidr; |
213 | dst->physdev = src->physdev; | 217 | dst->physdev = src->physdev; |
214 | dst->iface = src->iface; | 218 | dst->iface = src->iface; |
219 | dst->nomatch = src->nomatch; | ||
220 | } | ||
221 | |||
222 | static inline void | ||
223 | hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags) | ||
224 | { | ||
225 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | ||
226 | } | ||
227 | |||
228 | static inline bool | ||
229 | hash_netiface4_data_match(const struct hash_netiface4_elem *elem) | ||
230 | { | ||
231 | return !elem->nomatch; | ||
215 | } | 232 | } |
216 | 233 | ||
217 | static inline void | 234 | static inline void |
@@ -233,11 +250,13 @@ hash_netiface4_data_list(struct sk_buff *skb, | |||
233 | { | 250 | { |
234 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; | 251 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; |
235 | 252 | ||
253 | if (data->nomatch) | ||
254 | flags |= IPSET_FLAG_NOMATCH; | ||
236 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); | 255 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); |
237 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 256 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); |
238 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); | 257 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); |
239 | if (flags) | 258 | if (flags) |
240 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); | 259 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); |
241 | return 0; | 260 | return 0; |
242 | 261 | ||
243 | nla_put_failure: | 262 | nla_put_failure: |
@@ -252,11 +271,13 @@ hash_netiface4_data_tlist(struct sk_buff *skb, | |||
252 | (const struct hash_netiface4_telem *)data; | 271 | (const struct hash_netiface4_telem *)data; |
253 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; | 272 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; |
254 | 273 | ||
274 | if (data->nomatch) | ||
275 | flags |= IPSET_FLAG_NOMATCH; | ||
255 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); | 276 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); |
256 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 277 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); |
257 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); | 278 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); |
258 | if (flags) | 279 | if (flags) |
259 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); | 280 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); |
260 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 281 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
261 | htonl(ip_set_timeout_get(tdata->timeout))); | 282 | htonl(ip_set_timeout_get(tdata->timeout))); |
262 | 283 | ||
@@ -361,7 +382,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
361 | 382 | ||
362 | if (tb[IPSET_ATTR_CIDR]) { | 383 | if (tb[IPSET_ATTR_CIDR]) { |
363 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 384 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
364 | if (!data.cidr) | 385 | if (!data.cidr || data.cidr > HOST_MASK) |
365 | return -IPSET_ERR_INVALID_CIDR; | 386 | return -IPSET_ERR_INVALID_CIDR; |
366 | } | 387 | } |
367 | 388 | ||
@@ -387,6 +408,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
387 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | 408 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); |
388 | if (cadt_flags & IPSET_FLAG_PHYSDEV) | 409 | if (cadt_flags & IPSET_FLAG_PHYSDEV) |
389 | data.physdev = 1; | 410 | data.physdev = 1; |
411 | if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH)) | ||
412 | flags |= (cadt_flags << 16); | ||
390 | } | 413 | } |
391 | 414 | ||
392 | if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { | 415 | if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { |
@@ -440,7 +463,8 @@ struct hash_netiface6_elem_hashed { | |||
440 | union nf_inet_addr ip; | 463 | union nf_inet_addr ip; |
441 | u8 physdev; | 464 | u8 physdev; |
442 | u8 cidr; | 465 | u8 cidr; |
443 | u16 padding; | 466 | u8 nomatch; |
467 | u8 padding; | ||
444 | }; | 468 | }; |
445 | 469 | ||
446 | #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) | 470 | #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) |
@@ -449,7 +473,8 @@ struct hash_netiface6_elem { | |||
449 | union nf_inet_addr ip; | 473 | union nf_inet_addr ip; |
450 | u8 physdev; | 474 | u8 physdev; |
451 | u8 cidr; | 475 | u8 cidr; |
452 | u16 padding; | 476 | u8 nomatch; |
477 | u8 padding; | ||
453 | const char *iface; | 478 | const char *iface; |
454 | }; | 479 | }; |
455 | 480 | ||
@@ -457,7 +482,8 @@ struct hash_netiface6_telem { | |||
457 | union nf_inet_addr ip; | 482 | union nf_inet_addr ip; |
458 | u8 physdev; | 483 | u8 physdev; |
459 | u8 cidr; | 484 | u8 cidr; |
460 | u16 padding; | 485 | u8 nomatch; |
486 | u8 padding; | ||
461 | const char *iface; | 487 | const char *iface; |
462 | unsigned long timeout; | 488 | unsigned long timeout; |
463 | }; | 489 | }; |
@@ -488,8 +514,21 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst, | |||
488 | } | 514 | } |
489 | 515 | ||
490 | static inline void | 516 | static inline void |
517 | hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags) | ||
518 | { | ||
519 | dst->nomatch = flags & IPSET_FLAG_NOMATCH; | ||
520 | } | ||
521 | |||
522 | static inline bool | ||
523 | hash_netiface6_data_match(const struct hash_netiface6_elem *elem) | ||
524 | { | ||
525 | return !elem->nomatch; | ||
526 | } | ||
527 | |||
528 | static inline void | ||
491 | hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem) | 529 | hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem) |
492 | { | 530 | { |
531 | elem->cidr = 0; | ||
493 | } | 532 | } |
494 | 533 | ||
495 | static inline void | 534 | static inline void |
@@ -514,11 +553,13 @@ hash_netiface6_data_list(struct sk_buff *skb, | |||
514 | { | 553 | { |
515 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; | 554 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; |
516 | 555 | ||
556 | if (data->nomatch) | ||
557 | flags |= IPSET_FLAG_NOMATCH; | ||
517 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); | 558 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); |
518 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 559 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); |
519 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); | 560 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); |
520 | if (flags) | 561 | if (flags) |
521 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); | 562 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); |
522 | return 0; | 563 | return 0; |
523 | 564 | ||
524 | nla_put_failure: | 565 | nla_put_failure: |
@@ -533,11 +574,13 @@ hash_netiface6_data_tlist(struct sk_buff *skb, | |||
533 | (const struct hash_netiface6_telem *)data; | 574 | (const struct hash_netiface6_telem *)data; |
534 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; | 575 | u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; |
535 | 576 | ||
577 | if (data->nomatch) | ||
578 | flags |= IPSET_FLAG_NOMATCH; | ||
536 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); | 579 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); |
537 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 580 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); |
538 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); | 581 | NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); |
539 | if (flags) | 582 | if (flags) |
540 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); | 583 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); |
541 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 584 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
542 | htonl(ip_set_timeout_get(e->timeout))); | 585 | htonl(ip_set_timeout_get(e->timeout))); |
543 | return 0; | 586 | return 0; |
@@ -636,7 +679,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
636 | 679 | ||
637 | if (tb[IPSET_ATTR_CIDR]) | 680 | if (tb[IPSET_ATTR_CIDR]) |
638 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 681 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
639 | if (!data.cidr) | 682 | if (!data.cidr || data.cidr > HOST_MASK) |
640 | return -IPSET_ERR_INVALID_CIDR; | 683 | return -IPSET_ERR_INVALID_CIDR; |
641 | ip6_netmask(&data.ip, data.cidr); | 684 | ip6_netmask(&data.ip, data.cidr); |
642 | 685 | ||
@@ -662,6 +705,8 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
662 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | 705 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); |
663 | if (cadt_flags & IPSET_FLAG_PHYSDEV) | 706 | if (cadt_flags & IPSET_FLAG_PHYSDEV) |
664 | data.physdev = 1; | 707 | data.physdev = 1; |
708 | if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH)) | ||
709 | flags |= (cadt_flags << 16); | ||
665 | } | 710 | } |
666 | 711 | ||
667 | ret = adtfn(set, &data, timeout, flags); | 712 | ret = adtfn(set, &data, timeout, flags); |
@@ -678,7 +723,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
678 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; | 723 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; |
679 | u8 hbits; | 724 | u8 hbits; |
680 | 725 | ||
681 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 726 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
682 | return -IPSET_ERR_INVALID_FAMILY; | 727 | return -IPSET_ERR_INVALID_FAMILY; |
683 | 728 | ||
684 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 729 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
@@ -697,7 +742,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
697 | 742 | ||
698 | h = kzalloc(sizeof(*h) | 743 | h = kzalloc(sizeof(*h) |
699 | + sizeof(struct ip_set_hash_nets) | 744 | + sizeof(struct ip_set_hash_nets) |
700 | * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); | 745 | * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); |
701 | if (!h) | 746 | if (!h) |
702 | return -ENOMEM; | 747 | return -ENOMEM; |
703 | 748 | ||
@@ -722,15 +767,15 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
722 | if (tb[IPSET_ATTR_TIMEOUT]) { | 767 | if (tb[IPSET_ATTR_TIMEOUT]) { |
723 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 768 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
724 | 769 | ||
725 | set->variant = set->family == AF_INET | 770 | set->variant = set->family == NFPROTO_IPV4 |
726 | ? &hash_netiface4_tvariant : &hash_netiface6_tvariant; | 771 | ? &hash_netiface4_tvariant : &hash_netiface6_tvariant; |
727 | 772 | ||
728 | if (set->family == AF_INET) | 773 | if (set->family == NFPROTO_IPV4) |
729 | hash_netiface4_gc_init(set); | 774 | hash_netiface4_gc_init(set); |
730 | else | 775 | else |
731 | hash_netiface6_gc_init(set); | 776 | hash_netiface6_gc_init(set); |
732 | } else { | 777 | } else { |
733 | set->variant = set->family == AF_INET | 778 | set->variant = set->family == NFPROTO_IPV4 |
734 | ? &hash_netiface4_variant : &hash_netiface6_variant; | 779 | ? &hash_netiface4_variant : &hash_netiface6_variant; |
735 | } | 780 | } |
736 | 781 | ||
@@ -746,8 +791,9 @@ static struct ip_set_type hash_netiface_type __read_mostly = { | |||
746 | .protocol = IPSET_PROTOCOL, | 791 | .protocol = IPSET_PROTOCOL, |
747 | .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE, | 792 | .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE, |
748 | .dimension = IPSET_DIM_TWO, | 793 | .dimension = IPSET_DIM_TWO, |
749 | .family = AF_UNSPEC, | 794 | .family = NFPROTO_UNSPEC, |
750 | .revision_min = 0, | 795 | .revision_min = 0, |
796 | .revision_max = 1, /* nomatch flag support added */ | ||
751 | .create = hash_netiface_create, | 797 | .create = hash_netiface_create, |
752 | .create_policy = { | 798 | .create_policy = { |
753 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 799 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 8f9de7207ec9..ce2e77100b64 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -40,12 +40,19 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b); | |||
40 | 40 | ||
41 | /* The type variant functions: IPv4 */ | 41 | /* The type variant functions: IPv4 */ |
42 | 42 | ||
43 | /* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0 | ||
44 | * However this way we have to store internally cidr - 1, | ||
45 | * dancing back and forth. | ||
46 | */ | ||
47 | #define IP_SET_HASH_WITH_NETS_PACKED | ||
48 | |||
43 | /* Member elements without timeout */ | 49 | /* Member elements without timeout */ |
44 | struct hash_netport4_elem { | 50 | struct hash_netport4_elem { |
45 | __be32 ip; | 51 | __be32 ip; |
46 | __be16 port; | 52 | __be16 port; |
47 | u8 proto; | 53 | u8 proto; |
48 | u8 cidr; | 54 | u8 cidr:7; |
55 | u8 nomatch:1; | ||
49 | }; | 56 | }; |
50 | 57 | ||
51 | /* Member elements with timeout support */ | 58 | /* Member elements with timeout support */ |
@@ -53,7 +60,8 @@ struct hash_netport4_telem { | |||
53 | __be32 ip; | 60 | __be32 ip; |
54 | __be16 port; | 61 | __be16 port; |
55 | u8 proto; | 62 | u8 proto; |
56 | u8 cidr; | 63 | u8 cidr:7; |
64 | u8 nomatch:1; | ||
57 | unsigned long timeout; | 65 | unsigned long timeout; |
58 | }; | 66 | }; |
59 | 67 | ||
@@ -82,13 +90,26 @@ hash_netport4_data_copy(struct hash_netport4_elem *dst, | |||
82 | dst->port = src->port; | 90 | dst->port = src->port; |
83 | dst->proto = src->proto; | 91 | dst->proto = src->proto; |
84 | dst->cidr = src->cidr; | 92 | dst->cidr = src->cidr; |
93 | dst->nomatch = src->nomatch; | ||
94 | } | ||
95 | |||
96 | static inline void | ||
97 | hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags) | ||
98 | { | ||
99 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | ||
100 | } | ||
101 | |||
102 | static inline bool | ||
103 | hash_netport4_data_match(const struct hash_netport4_elem *elem) | ||
104 | { | ||
105 | return !elem->nomatch; | ||
85 | } | 106 | } |
86 | 107 | ||
87 | static inline void | 108 | static inline void |
88 | hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr) | 109 | hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr) |
89 | { | 110 | { |
90 | elem->ip &= ip_set_netmask(cidr); | 111 | elem->ip &= ip_set_netmask(cidr); |
91 | elem->cidr = cidr; | 112 | elem->cidr = cidr - 1; |
92 | } | 113 | } |
93 | 114 | ||
94 | static inline void | 115 | static inline void |
@@ -101,10 +122,14 @@ static bool | |||
101 | hash_netport4_data_list(struct sk_buff *skb, | 122 | hash_netport4_data_list(struct sk_buff *skb, |
102 | const struct hash_netport4_elem *data) | 123 | const struct hash_netport4_elem *data) |
103 | { | 124 | { |
125 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
126 | |||
104 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); | 127 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); |
105 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); | 128 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); |
106 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 129 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); |
107 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 130 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
131 | if (flags) | ||
132 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
108 | return 0; | 133 | return 0; |
109 | 134 | ||
110 | nla_put_failure: | 135 | nla_put_failure: |
@@ -117,13 +142,16 @@ hash_netport4_data_tlist(struct sk_buff *skb, | |||
117 | { | 142 | { |
118 | const struct hash_netport4_telem *tdata = | 143 | const struct hash_netport4_telem *tdata = |
119 | (const struct hash_netport4_telem *)data; | 144 | (const struct hash_netport4_telem *)data; |
145 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
120 | 146 | ||
121 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); | 147 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); |
122 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); | 148 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); |
123 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 149 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); |
124 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 150 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
125 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 151 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
126 | htonl(ip_set_timeout_get(tdata->timeout))); | 152 | htonl(ip_set_timeout_get(tdata->timeout))); |
153 | if (flags) | ||
154 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
127 | 155 | ||
128 | return 0; | 156 | return 0; |
129 | 157 | ||
@@ -154,20 +182,18 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
154 | const struct ip_set_hash *h = set->data; | 182 | const struct ip_set_hash *h = set->data; |
155 | ipset_adtfn adtfn = set->variant->adt[adt]; | 183 | ipset_adtfn adtfn = set->variant->adt[adt]; |
156 | struct hash_netport4_elem data = { | 184 | struct hash_netport4_elem data = { |
157 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK | 185 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 |
158 | }; | 186 | }; |
159 | 187 | ||
160 | if (data.cidr == 0) | ||
161 | return -EINVAL; | ||
162 | if (adt == IPSET_TEST) | 188 | if (adt == IPSET_TEST) |
163 | data.cidr = HOST_MASK; | 189 | data.cidr = HOST_MASK - 1; |
164 | 190 | ||
165 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 191 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
166 | &data.port, &data.proto)) | 192 | &data.port, &data.proto)) |
167 | return -EINVAL; | 193 | return -EINVAL; |
168 | 194 | ||
169 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip); | 195 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip); |
170 | data.ip &= ip_set_netmask(data.cidr); | 196 | data.ip &= ip_set_netmask(data.cidr + 1); |
171 | 197 | ||
172 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); | 198 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); |
173 | } | 199 | } |
@@ -178,16 +204,18 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
178 | { | 204 | { |
179 | const struct ip_set_hash *h = set->data; | 205 | const struct ip_set_hash *h = set->data; |
180 | ipset_adtfn adtfn = set->variant->adt[adt]; | 206 | ipset_adtfn adtfn = set->variant->adt[adt]; |
181 | struct hash_netport4_elem data = { .cidr = HOST_MASK }; | 207 | struct hash_netport4_elem data = { .cidr = HOST_MASK - 1 }; |
182 | u32 port, port_to, p = 0, ip = 0, ip_to, last; | 208 | u32 port, port_to, p = 0, ip = 0, ip_to, last; |
183 | u32 timeout = h->timeout; | 209 | u32 timeout = h->timeout; |
184 | bool with_ports = false; | 210 | bool with_ports = false; |
211 | u8 cidr; | ||
185 | int ret; | 212 | int ret; |
186 | 213 | ||
187 | if (unlikely(!tb[IPSET_ATTR_IP] || | 214 | if (unlikely(!tb[IPSET_ATTR_IP] || |
188 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | 215 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
189 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 216 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
190 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 217 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
218 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) | ||
191 | return -IPSET_ERR_PROTOCOL; | 219 | return -IPSET_ERR_PROTOCOL; |
192 | 220 | ||
193 | if (tb[IPSET_ATTR_LINENO]) | 221 | if (tb[IPSET_ATTR_LINENO]) |
@@ -198,9 +226,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
198 | return ret; | 226 | return ret; |
199 | 227 | ||
200 | if (tb[IPSET_ATTR_CIDR]) { | 228 | if (tb[IPSET_ATTR_CIDR]) { |
201 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 229 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
202 | if (!data.cidr) | 230 | if (!cidr || cidr > HOST_MASK) |
203 | return -IPSET_ERR_INVALID_CIDR; | 231 | return -IPSET_ERR_INVALID_CIDR; |
232 | data.cidr = cidr - 1; | ||
204 | } | 233 | } |
205 | 234 | ||
206 | if (tb[IPSET_ATTR_PORT]) | 235 | if (tb[IPSET_ATTR_PORT]) |
@@ -227,8 +256,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
227 | } | 256 | } |
228 | 257 | ||
229 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; | 258 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; |
259 | |||
260 | if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { | ||
261 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
262 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
263 | flags |= (cadt_flags << 16); | ||
264 | } | ||
265 | |||
230 | if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) { | 266 | if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) { |
231 | data.ip = htonl(ip & ip_set_hostmask(data.cidr)); | 267 | data.ip = htonl(ip & ip_set_hostmask(data.cidr + 1)); |
232 | ret = adtfn(set, &data, timeout, flags); | 268 | ret = adtfn(set, &data, timeout, flags); |
233 | return ip_set_eexist(ret, flags) ? 0 : ret; | 269 | return ip_set_eexist(ret, flags) ? 0 : ret; |
234 | } | 270 | } |
@@ -248,14 +284,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
248 | if (ip + UINT_MAX == ip_to) | 284 | if (ip + UINT_MAX == ip_to) |
249 | return -IPSET_ERR_HASH_RANGE; | 285 | return -IPSET_ERR_HASH_RANGE; |
250 | } else { | 286 | } else { |
251 | ip_set_mask_from_to(ip, ip_to, data.cidr); | 287 | ip_set_mask_from_to(ip, ip_to, data.cidr + 1); |
252 | } | 288 | } |
253 | 289 | ||
254 | if (retried) | 290 | if (retried) |
255 | ip = h->next.ip; | 291 | ip = h->next.ip; |
256 | while (!after(ip, ip_to)) { | 292 | while (!after(ip, ip_to)) { |
257 | data.ip = htonl(ip); | 293 | data.ip = htonl(ip); |
258 | last = ip_set_range_to_cidr(ip, ip_to, &data.cidr); | 294 | last = ip_set_range_to_cidr(ip, ip_to, &cidr); |
295 | data.cidr = cidr - 1; | ||
259 | p = retried && ip == h->next.ip ? h->next.port : port; | 296 | p = retried && ip == h->next.ip ? h->next.port : port; |
260 | for (; p <= port_to; p++) { | 297 | for (; p <= port_to; p++) { |
261 | data.port = htons(p); | 298 | data.port = htons(p); |
@@ -288,14 +325,16 @@ struct hash_netport6_elem { | |||
288 | union nf_inet_addr ip; | 325 | union nf_inet_addr ip; |
289 | __be16 port; | 326 | __be16 port; |
290 | u8 proto; | 327 | u8 proto; |
291 | u8 cidr; | 328 | u8 cidr:7; |
329 | u8 nomatch:1; | ||
292 | }; | 330 | }; |
293 | 331 | ||
294 | struct hash_netport6_telem { | 332 | struct hash_netport6_telem { |
295 | union nf_inet_addr ip; | 333 | union nf_inet_addr ip; |
296 | __be16 port; | 334 | __be16 port; |
297 | u8 proto; | 335 | u8 proto; |
298 | u8 cidr; | 336 | u8 cidr:7; |
337 | u8 nomatch:1; | ||
299 | unsigned long timeout; | 338 | unsigned long timeout; |
300 | }; | 339 | }; |
301 | 340 | ||
@@ -324,6 +363,18 @@ hash_netport6_data_copy(struct hash_netport6_elem *dst, | |||
324 | } | 363 | } |
325 | 364 | ||
326 | static inline void | 365 | static inline void |
366 | hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags) | ||
367 | { | ||
368 | dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); | ||
369 | } | ||
370 | |||
371 | static inline bool | ||
372 | hash_netport6_data_match(const struct hash_netport6_elem *elem) | ||
373 | { | ||
374 | return !elem->nomatch; | ||
375 | } | ||
376 | |||
377 | static inline void | ||
327 | hash_netport6_data_zero_out(struct hash_netport6_elem *elem) | 378 | hash_netport6_data_zero_out(struct hash_netport6_elem *elem) |
328 | { | 379 | { |
329 | elem->proto = 0; | 380 | elem->proto = 0; |
@@ -342,17 +393,21 @@ static inline void | |||
342 | hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr) | 393 | hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr) |
343 | { | 394 | { |
344 | ip6_netmask(&elem->ip, cidr); | 395 | ip6_netmask(&elem->ip, cidr); |
345 | elem->cidr = cidr; | 396 | elem->cidr = cidr - 1; |
346 | } | 397 | } |
347 | 398 | ||
348 | static bool | 399 | static bool |
349 | hash_netport6_data_list(struct sk_buff *skb, | 400 | hash_netport6_data_list(struct sk_buff *skb, |
350 | const struct hash_netport6_elem *data) | 401 | const struct hash_netport6_elem *data) |
351 | { | 402 | { |
403 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
404 | |||
352 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); | 405 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); |
353 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); | 406 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); |
354 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 407 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); |
355 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 408 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
409 | if (flags) | ||
410 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
356 | return 0; | 411 | return 0; |
357 | 412 | ||
358 | nla_put_failure: | 413 | nla_put_failure: |
@@ -365,13 +420,16 @@ hash_netport6_data_tlist(struct sk_buff *skb, | |||
365 | { | 420 | { |
366 | const struct hash_netport6_telem *e = | 421 | const struct hash_netport6_telem *e = |
367 | (const struct hash_netport6_telem *)data; | 422 | (const struct hash_netport6_telem *)data; |
423 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
368 | 424 | ||
369 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); | 425 | NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); |
370 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); | 426 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); |
371 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); | 427 | NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr + 1); |
372 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); | 428 | NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); |
373 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | 429 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, |
374 | htonl(ip_set_timeout_get(e->timeout))); | 430 | htonl(ip_set_timeout_get(e->timeout))); |
431 | if (flags) | ||
432 | NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)); | ||
375 | return 0; | 433 | return 0; |
376 | 434 | ||
377 | nla_put_failure: | 435 | nla_put_failure: |
@@ -400,20 +458,18 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
400 | const struct ip_set_hash *h = set->data; | 458 | const struct ip_set_hash *h = set->data; |
401 | ipset_adtfn adtfn = set->variant->adt[adt]; | 459 | ipset_adtfn adtfn = set->variant->adt[adt]; |
402 | struct hash_netport6_elem data = { | 460 | struct hash_netport6_elem data = { |
403 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK | 461 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1, |
404 | }; | 462 | }; |
405 | 463 | ||
406 | if (data.cidr == 0) | ||
407 | return -EINVAL; | ||
408 | if (adt == IPSET_TEST) | 464 | if (adt == IPSET_TEST) |
409 | data.cidr = HOST_MASK; | 465 | data.cidr = HOST_MASK - 1; |
410 | 466 | ||
411 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 467 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
412 | &data.port, &data.proto)) | 468 | &data.port, &data.proto)) |
413 | return -EINVAL; | 469 | return -EINVAL; |
414 | 470 | ||
415 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6); | 471 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6); |
416 | ip6_netmask(&data.ip, data.cidr); | 472 | ip6_netmask(&data.ip, data.cidr + 1); |
417 | 473 | ||
418 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); | 474 | return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags); |
419 | } | 475 | } |
@@ -424,16 +480,18 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
424 | { | 480 | { |
425 | const struct ip_set_hash *h = set->data; | 481 | const struct ip_set_hash *h = set->data; |
426 | ipset_adtfn adtfn = set->variant->adt[adt]; | 482 | ipset_adtfn adtfn = set->variant->adt[adt]; |
427 | struct hash_netport6_elem data = { .cidr = HOST_MASK }; | 483 | struct hash_netport6_elem data = { .cidr = HOST_MASK - 1 }; |
428 | u32 port, port_to; | 484 | u32 port, port_to; |
429 | u32 timeout = h->timeout; | 485 | u32 timeout = h->timeout; |
430 | bool with_ports = false; | 486 | bool with_ports = false; |
487 | u8 cidr; | ||
431 | int ret; | 488 | int ret; |
432 | 489 | ||
433 | if (unlikely(!tb[IPSET_ATTR_IP] || | 490 | if (unlikely(!tb[IPSET_ATTR_IP] || |
434 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | 491 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
435 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 492 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
436 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | 493 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
494 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) | ||
437 | return -IPSET_ERR_PROTOCOL; | 495 | return -IPSET_ERR_PROTOCOL; |
438 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | 496 | if (unlikely(tb[IPSET_ATTR_IP_TO])) |
439 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 497 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -445,11 +503,13 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
445 | if (ret) | 503 | if (ret) |
446 | return ret; | 504 | return ret; |
447 | 505 | ||
448 | if (tb[IPSET_ATTR_CIDR]) | 506 | if (tb[IPSET_ATTR_CIDR]) { |
449 | data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 507 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
450 | if (!data.cidr) | 508 | if (!cidr || cidr > HOST_MASK) |
451 | return -IPSET_ERR_INVALID_CIDR; | 509 | return -IPSET_ERR_INVALID_CIDR; |
452 | ip6_netmask(&data.ip, data.cidr); | 510 | data.cidr = cidr - 1; |
511 | } | ||
512 | ip6_netmask(&data.ip, data.cidr + 1); | ||
453 | 513 | ||
454 | if (tb[IPSET_ATTR_PORT]) | 514 | if (tb[IPSET_ATTR_PORT]) |
455 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); | 515 | data.port = nla_get_be16(tb[IPSET_ATTR_PORT]); |
@@ -474,6 +534,12 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
474 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 534 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
475 | } | 535 | } |
476 | 536 | ||
537 | if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) { | ||
538 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
539 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
540 | flags |= (cadt_flags << 16); | ||
541 | } | ||
542 | |||
477 | if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { | 543 | if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { |
478 | ret = adtfn(set, &data, timeout, flags); | 544 | ret = adtfn(set, &data, timeout, flags); |
479 | return ip_set_eexist(ret, flags) ? 0 : ret; | 545 | return ip_set_eexist(ret, flags) ? 0 : ret; |
@@ -507,7 +573,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
507 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; | 573 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; |
508 | u8 hbits; | 574 | u8 hbits; |
509 | 575 | ||
510 | if (!(set->family == AF_INET || set->family == AF_INET6)) | 576 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
511 | return -IPSET_ERR_INVALID_FAMILY; | 577 | return -IPSET_ERR_INVALID_FAMILY; |
512 | 578 | ||
513 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || | 579 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || |
@@ -526,7 +592,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
526 | 592 | ||
527 | h = kzalloc(sizeof(*h) | 593 | h = kzalloc(sizeof(*h) |
528 | + sizeof(struct ip_set_hash_nets) | 594 | + sizeof(struct ip_set_hash_nets) |
529 | * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); | 595 | * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL); |
530 | if (!h) | 596 | if (!h) |
531 | return -ENOMEM; | 597 | return -ENOMEM; |
532 | 598 | ||
@@ -549,15 +615,15 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
549 | if (tb[IPSET_ATTR_TIMEOUT]) { | 615 | if (tb[IPSET_ATTR_TIMEOUT]) { |
550 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 616 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
551 | 617 | ||
552 | set->variant = set->family == AF_INET | 618 | set->variant = set->family == NFPROTO_IPV4 |
553 | ? &hash_netport4_tvariant : &hash_netport6_tvariant; | 619 | ? &hash_netport4_tvariant : &hash_netport6_tvariant; |
554 | 620 | ||
555 | if (set->family == AF_INET) | 621 | if (set->family == NFPROTO_IPV4) |
556 | hash_netport4_gc_init(set); | 622 | hash_netport4_gc_init(set); |
557 | else | 623 | else |
558 | hash_netport6_gc_init(set); | 624 | hash_netport6_gc_init(set); |
559 | } else { | 625 | } else { |
560 | set->variant = set->family == AF_INET | 626 | set->variant = set->family == NFPROTO_IPV4 |
561 | ? &hash_netport4_variant : &hash_netport6_variant; | 627 | ? &hash_netport4_variant : &hash_netport6_variant; |
562 | } | 628 | } |
563 | 629 | ||
@@ -573,10 +639,11 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
573 | .protocol = IPSET_PROTOCOL, | 639 | .protocol = IPSET_PROTOCOL, |
574 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, | 640 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, |
575 | .dimension = IPSET_DIM_TWO, | 641 | .dimension = IPSET_DIM_TWO, |
576 | .family = AF_UNSPEC, | 642 | .family = NFPROTO_UNSPEC, |
577 | .revision_min = 0, | 643 | .revision_min = 0, |
578 | /* 1 SCTP and UDPLITE support added */ | 644 | /* 1 SCTP and UDPLITE support added */ |
579 | .revision_max = 2, /* Range as input support for IPv4 added */ | 645 | /* 2, Range as input support for IPv4 added */ |
646 | .revision_max = 3, /* nomatch flag support added */ | ||
580 | .create = hash_netport_create, | 647 | .create = hash_netport_create, |
581 | .create_policy = { | 648 | .create_policy = { |
582 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 649 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
@@ -595,6 +662,7 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
595 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | 662 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
596 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | 663 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
597 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 664 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
665 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
598 | }, | 666 | }, |
599 | .me = THIS_MODULE, | 667 | .me = THIS_MODULE, |
600 | }; | 668 | }; |
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index 4d10819d462e..7e095f9005f0 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c | |||
@@ -575,7 +575,7 @@ static struct ip_set_type list_set_type __read_mostly = { | |||
575 | .protocol = IPSET_PROTOCOL, | 575 | .protocol = IPSET_PROTOCOL, |
576 | .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, | 576 | .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, |
577 | .dimension = IPSET_DIM_ONE, | 577 | .dimension = IPSET_DIM_ONE, |
578 | .family = AF_UNSPEC, | 578 | .family = NFPROTO_UNSPEC, |
579 | .revision_min = 0, | 579 | .revision_min = 0, |
580 | .revision_max = 0, | 580 | .revision_max = 0, |
581 | .create = list_set_create, | 581 | .create = list_set_create, |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index ed86a3be678e..81e2aa4ca1fe 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <net/netfilter/nf_conntrack_ecache.h> | 44 | #include <net/netfilter/nf_conntrack_ecache.h> |
45 | #include <net/netfilter/nf_conntrack_zones.h> | 45 | #include <net/netfilter/nf_conntrack_zones.h> |
46 | #include <net/netfilter/nf_conntrack_timestamp.h> | 46 | #include <net/netfilter/nf_conntrack_timestamp.h> |
47 | #include <net/netfilter/nf_conntrack_timeout.h> | ||
47 | #include <net/netfilter/nf_nat.h> | 48 | #include <net/netfilter/nf_nat.h> |
48 | #include <net/netfilter/nf_nat_core.h> | 49 | #include <net/netfilter/nf_nat_core.h> |
49 | 50 | ||
@@ -763,7 +764,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, | |||
763 | struct nf_conntrack_l3proto *l3proto, | 764 | struct nf_conntrack_l3proto *l3proto, |
764 | struct nf_conntrack_l4proto *l4proto, | 765 | struct nf_conntrack_l4proto *l4proto, |
765 | struct sk_buff *skb, | 766 | struct sk_buff *skb, |
766 | unsigned int dataoff, u32 hash) | 767 | unsigned int dataoff, u32 hash, |
768 | unsigned int *timeouts) | ||
767 | { | 769 | { |
768 | struct nf_conn *ct; | 770 | struct nf_conn *ct; |
769 | struct nf_conn_help *help; | 771 | struct nf_conn_help *help; |
@@ -782,7 +784,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, | |||
782 | if (IS_ERR(ct)) | 784 | if (IS_ERR(ct)) |
783 | return (struct nf_conntrack_tuple_hash *)ct; | 785 | return (struct nf_conntrack_tuple_hash *)ct; |
784 | 786 | ||
785 | if (!l4proto->new(ct, skb, dataoff)) { | 787 | if (!l4proto->new(ct, skb, dataoff, timeouts)) { |
786 | nf_conntrack_free(ct); | 788 | nf_conntrack_free(ct); |
787 | pr_debug("init conntrack: can't track with proto module\n"); | 789 | pr_debug("init conntrack: can't track with proto module\n"); |
788 | return NULL; | 790 | return NULL; |
@@ -848,7 +850,8 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, | |||
848 | struct nf_conntrack_l3proto *l3proto, | 850 | struct nf_conntrack_l3proto *l3proto, |
849 | struct nf_conntrack_l4proto *l4proto, | 851 | struct nf_conntrack_l4proto *l4proto, |
850 | int *set_reply, | 852 | int *set_reply, |
851 | enum ip_conntrack_info *ctinfo) | 853 | enum ip_conntrack_info *ctinfo, |
854 | unsigned int *timeouts) | ||
852 | { | 855 | { |
853 | struct nf_conntrack_tuple tuple; | 856 | struct nf_conntrack_tuple tuple; |
854 | struct nf_conntrack_tuple_hash *h; | 857 | struct nf_conntrack_tuple_hash *h; |
@@ -868,7 +871,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, | |||
868 | h = __nf_conntrack_find_get(net, zone, &tuple, hash); | 871 | h = __nf_conntrack_find_get(net, zone, &tuple, hash); |
869 | if (!h) { | 872 | if (!h) { |
870 | h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, | 873 | h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, |
871 | skb, dataoff, hash); | 874 | skb, dataoff, hash, timeouts); |
872 | if (!h) | 875 | if (!h) |
873 | return NULL; | 876 | return NULL; |
874 | if (IS_ERR(h)) | 877 | if (IS_ERR(h)) |
@@ -909,6 +912,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, | |||
909 | enum ip_conntrack_info ctinfo; | 912 | enum ip_conntrack_info ctinfo; |
910 | struct nf_conntrack_l3proto *l3proto; | 913 | struct nf_conntrack_l3proto *l3proto; |
911 | struct nf_conntrack_l4proto *l4proto; | 914 | struct nf_conntrack_l4proto *l4proto; |
915 | struct nf_conn_timeout *timeout_ext; | ||
916 | unsigned int *timeouts; | ||
912 | unsigned int dataoff; | 917 | unsigned int dataoff; |
913 | u_int8_t protonum; | 918 | u_int8_t protonum; |
914 | int set_reply = 0; | 919 | int set_reply = 0; |
@@ -955,8 +960,19 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, | |||
955 | goto out; | 960 | goto out; |
956 | } | 961 | } |
957 | 962 | ||
963 | /* Decide what timeout policy we want to apply to this flow. */ | ||
964 | if (tmpl) { | ||
965 | timeout_ext = nf_ct_timeout_find(tmpl); | ||
966 | if (timeout_ext) | ||
967 | timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); | ||
968 | else | ||
969 | timeouts = l4proto->get_timeouts(net); | ||
970 | } else | ||
971 | timeouts = l4proto->get_timeouts(net); | ||
972 | |||
958 | ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, | 973 | ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, |
959 | l3proto, l4proto, &set_reply, &ctinfo); | 974 | l3proto, l4proto, &set_reply, &ctinfo, |
975 | timeouts); | ||
960 | if (!ct) { | 976 | if (!ct) { |
961 | /* Not valid part of a connection */ | 977 | /* Not valid part of a connection */ |
962 | NF_CT_STAT_INC_ATOMIC(net, invalid); | 978 | NF_CT_STAT_INC_ATOMIC(net, invalid); |
@@ -973,7 +989,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, | |||
973 | 989 | ||
974 | NF_CT_ASSERT(skb->nfct); | 990 | NF_CT_ASSERT(skb->nfct); |
975 | 991 | ||
976 | ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum); | 992 | ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); |
977 | if (ret <= 0) { | 993 | if (ret <= 0) { |
978 | /* Invalid: inverse of the return code tells | 994 | /* Invalid: inverse of the return code tells |
979 | * the netfilter core what to do */ | 995 | * the netfilter core what to do */ |
@@ -1327,6 +1343,7 @@ static void nf_conntrack_cleanup_net(struct net *net) | |||
1327 | } | 1343 | } |
1328 | 1344 | ||
1329 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); | 1345 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); |
1346 | nf_conntrack_timeout_fini(net); | ||
1330 | nf_conntrack_ecache_fini(net); | 1347 | nf_conntrack_ecache_fini(net); |
1331 | nf_conntrack_tstamp_fini(net); | 1348 | nf_conntrack_tstamp_fini(net); |
1332 | nf_conntrack_acct_fini(net); | 1349 | nf_conntrack_acct_fini(net); |
@@ -1558,9 +1575,14 @@ static int nf_conntrack_init_net(struct net *net) | |||
1558 | ret = nf_conntrack_ecache_init(net); | 1575 | ret = nf_conntrack_ecache_init(net); |
1559 | if (ret < 0) | 1576 | if (ret < 0) |
1560 | goto err_ecache; | 1577 | goto err_ecache; |
1578 | ret = nf_conntrack_timeout_init(net); | ||
1579 | if (ret < 0) | ||
1580 | goto err_timeout; | ||
1561 | 1581 | ||
1562 | return 0; | 1582 | return 0; |
1563 | 1583 | ||
1584 | err_timeout: | ||
1585 | nf_conntrack_timeout_fini(net); | ||
1564 | err_ecache: | 1586 | err_ecache: |
1565 | nf_conntrack_tstamp_fini(net); | 1587 | nf_conntrack_tstamp_fini(net); |
1566 | err_tstamp: | 1588 | err_tstamp: |
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 14af6329bdda..5bd3047ddeec 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c | |||
@@ -32,9 +32,11 @@ static DEFINE_MUTEX(nf_ct_ecache_mutex); | |||
32 | void nf_ct_deliver_cached_events(struct nf_conn *ct) | 32 | void nf_ct_deliver_cached_events(struct nf_conn *ct) |
33 | { | 33 | { |
34 | struct net *net = nf_ct_net(ct); | 34 | struct net *net = nf_ct_net(ct); |
35 | unsigned long events; | 35 | unsigned long events, missed; |
36 | struct nf_ct_event_notifier *notify; | 36 | struct nf_ct_event_notifier *notify; |
37 | struct nf_conntrack_ecache *e; | 37 | struct nf_conntrack_ecache *e; |
38 | struct nf_ct_event item; | ||
39 | int ret; | ||
38 | 40 | ||
39 | rcu_read_lock(); | 41 | rcu_read_lock(); |
40 | notify = rcu_dereference(net->ct.nf_conntrack_event_cb); | 42 | notify = rcu_dereference(net->ct.nf_conntrack_event_cb); |
@@ -47,31 +49,32 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) | |||
47 | 49 | ||
48 | events = xchg(&e->cache, 0); | 50 | events = xchg(&e->cache, 0); |
49 | 51 | ||
50 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) { | 52 | if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events) |
51 | struct nf_ct_event item = { | 53 | goto out_unlock; |
52 | .ct = ct, | 54 | |
53 | .pid = 0, | 55 | /* We make a copy of the missed event cache without taking |
54 | .report = 0 | 56 | * the lock, thus we may send missed events twice. However, |
55 | }; | 57 | * this does not harm and it happens very rarely. */ |
56 | int ret; | 58 | missed = e->missed; |
57 | /* We make a copy of the missed event cache without taking | 59 | |
58 | * the lock, thus we may send missed events twice. However, | 60 | if (!((events | missed) & e->ctmask)) |
59 | * this does not harm and it happens very rarely. */ | 61 | goto out_unlock; |
60 | unsigned long missed = e->missed; | 62 | |
61 | 63 | item.ct = ct; | |
62 | if (!((events | missed) & e->ctmask)) | 64 | item.pid = 0; |
63 | goto out_unlock; | 65 | item.report = 0; |
64 | 66 | ||
65 | ret = notify->fcn(events | missed, &item); | 67 | ret = notify->fcn(events | missed, &item); |
66 | if (unlikely(ret < 0 || missed)) { | 68 | |
67 | spin_lock_bh(&ct->lock); | 69 | if (likely(ret >= 0 && !missed)) |
68 | if (ret < 0) | 70 | goto out_unlock; |
69 | e->missed |= events; | 71 | |
70 | else | 72 | spin_lock_bh(&ct->lock); |
71 | e->missed &= ~missed; | 73 | if (ret < 0) |
72 | spin_unlock_bh(&ct->lock); | 74 | e->missed |= events; |
73 | } | 75 | else |
74 | } | 76 | e->missed &= ~missed; |
77 | spin_unlock_bh(&ct->lock); | ||
75 | 78 | ||
76 | out_unlock: | 79 | out_unlock: |
77 | rcu_read_unlock(); | 80 | rcu_read_unlock(); |
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index bbe23baa19b6..436b7cb79ba4 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -181,6 +181,60 @@ void nf_ct_helper_destroy(struct nf_conn *ct) | |||
181 | } | 181 | } |
182 | } | 182 | } |
183 | 183 | ||
184 | static LIST_HEAD(nf_ct_helper_expectfn_list); | ||
185 | |||
186 | void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n) | ||
187 | { | ||
188 | spin_lock_bh(&nf_conntrack_lock); | ||
189 | list_add_rcu(&n->head, &nf_ct_helper_expectfn_list); | ||
190 | spin_unlock_bh(&nf_conntrack_lock); | ||
191 | } | ||
192 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register); | ||
193 | |||
194 | void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n) | ||
195 | { | ||
196 | spin_lock_bh(&nf_conntrack_lock); | ||
197 | list_del_rcu(&n->head); | ||
198 | spin_unlock_bh(&nf_conntrack_lock); | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister); | ||
201 | |||
202 | struct nf_ct_helper_expectfn * | ||
203 | nf_ct_helper_expectfn_find_by_name(const char *name) | ||
204 | { | ||
205 | struct nf_ct_helper_expectfn *cur; | ||
206 | bool found = false; | ||
207 | |||
208 | rcu_read_lock(); | ||
209 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { | ||
210 | if (!strcmp(cur->name, name)) { | ||
211 | found = true; | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | rcu_read_unlock(); | ||
216 | return found ? cur : NULL; | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name); | ||
219 | |||
220 | struct nf_ct_helper_expectfn * | ||
221 | nf_ct_helper_expectfn_find_by_symbol(const void *symbol) | ||
222 | { | ||
223 | struct nf_ct_helper_expectfn *cur; | ||
224 | bool found = false; | ||
225 | |||
226 | rcu_read_lock(); | ||
227 | list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) { | ||
228 | if (cur->expectfn == symbol) { | ||
229 | found = true; | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | rcu_read_unlock(); | ||
234 | return found ? cur : NULL; | ||
235 | } | ||
236 | EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol); | ||
237 | |||
184 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 238 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
185 | { | 239 | { |
186 | unsigned int h = helper_hash(&me->tuple); | 240 | unsigned int h = helper_hash(&me->tuple); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 04fb409623d2..c1ea64c6c70d 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -110,15 +110,16 @@ ctnetlink_dump_tuples(struct sk_buff *skb, | |||
110 | struct nf_conntrack_l3proto *l3proto; | 110 | struct nf_conntrack_l3proto *l3proto; |
111 | struct nf_conntrack_l4proto *l4proto; | 111 | struct nf_conntrack_l4proto *l4proto; |
112 | 112 | ||
113 | rcu_read_lock(); | ||
113 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | 114 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); |
114 | ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); | 115 | ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); |
115 | 116 | ||
116 | if (unlikely(ret < 0)) | 117 | if (ret >= 0) { |
117 | return ret; | 118 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, |
118 | 119 | tuple->dst.protonum); | |
119 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | 120 | ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); |
120 | ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); | 121 | } |
121 | 122 | rcu_read_unlock(); | |
122 | return ret; | 123 | return ret; |
123 | } | 124 | } |
124 | 125 | ||
@@ -712,9 +713,11 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
712 | struct hlist_nulls_node *n; | 713 | struct hlist_nulls_node *n; |
713 | struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); | 714 | struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); |
714 | u_int8_t l3proto = nfmsg->nfgen_family; | 715 | u_int8_t l3proto = nfmsg->nfgen_family; |
716 | int res; | ||
715 | #ifdef CONFIG_NF_CONNTRACK_MARK | 717 | #ifdef CONFIG_NF_CONNTRACK_MARK |
716 | const struct ctnetlink_dump_filter *filter = cb->data; | 718 | const struct ctnetlink_dump_filter *filter = cb->data; |
717 | #endif | 719 | #endif |
720 | |||
718 | spin_lock_bh(&nf_conntrack_lock); | 721 | spin_lock_bh(&nf_conntrack_lock); |
719 | last = (struct nf_conn *)cb->args[1]; | 722 | last = (struct nf_conn *)cb->args[1]; |
720 | for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) { | 723 | for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) { |
@@ -740,11 +743,14 @@ restart: | |||
740 | continue; | 743 | continue; |
741 | } | 744 | } |
742 | #endif | 745 | #endif |
743 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 746 | rcu_read_lock(); |
744 | cb->nlh->nlmsg_seq, | 747 | res = |
745 | NFNL_MSG_TYPE( | 748 | ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
746 | cb->nlh->nlmsg_type), | 749 | cb->nlh->nlmsg_seq, |
747 | ct) < 0) { | 750 | NFNL_MSG_TYPE(cb->nlh->nlmsg_type), |
751 | ct); | ||
752 | rcu_read_unlock(); | ||
753 | if (res < 0) { | ||
748 | nf_conntrack_get(&ct->ct_general); | 754 | nf_conntrack_get(&ct->ct_general); |
749 | cb->args[1] = (unsigned long)ct; | 755 | cb->args[1] = (unsigned long)ct; |
750 | goto out; | 756 | goto out; |
@@ -1649,14 +1655,16 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb, | |||
1649 | if (!nest_parms) | 1655 | if (!nest_parms) |
1650 | goto nla_put_failure; | 1656 | goto nla_put_failure; |
1651 | 1657 | ||
1658 | rcu_read_lock(); | ||
1652 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | 1659 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); |
1653 | ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); | 1660 | ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); |
1654 | 1661 | if (ret >= 0) { | |
1655 | if (unlikely(ret < 0)) | 1662 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, |
1656 | goto nla_put_failure; | 1663 | tuple->dst.protonum); |
1657 | |||
1658 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | ||
1659 | ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); | 1664 | ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); |
1665 | } | ||
1666 | rcu_read_unlock(); | ||
1667 | |||
1660 | if (unlikely(ret < 0)) | 1668 | if (unlikely(ret < 0)) |
1661 | goto nla_put_failure; | 1669 | goto nla_put_failure; |
1662 | 1670 | ||
@@ -1675,6 +1683,11 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
1675 | struct nf_conn *master = exp->master; | 1683 | struct nf_conn *master = exp->master; |
1676 | long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ; | 1684 | long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ; |
1677 | struct nf_conn_help *help; | 1685 | struct nf_conn_help *help; |
1686 | #ifdef CONFIG_NF_NAT_NEEDED | ||
1687 | struct nlattr *nest_parms; | ||
1688 | struct nf_conntrack_tuple nat_tuple = {}; | ||
1689 | #endif | ||
1690 | struct nf_ct_helper_expectfn *expfn; | ||
1678 | 1691 | ||
1679 | if (timeout < 0) | 1692 | if (timeout < 0) |
1680 | timeout = 0; | 1693 | timeout = 0; |
@@ -1688,9 +1701,29 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
1688 | CTA_EXPECT_MASTER) < 0) | 1701 | CTA_EXPECT_MASTER) < 0) |
1689 | goto nla_put_failure; | 1702 | goto nla_put_failure; |
1690 | 1703 | ||
1704 | #ifdef CONFIG_NF_NAT_NEEDED | ||
1705 | if (exp->saved_ip || exp->saved_proto.all) { | ||
1706 | nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED); | ||
1707 | if (!nest_parms) | ||
1708 | goto nla_put_failure; | ||
1709 | |||
1710 | NLA_PUT_BE32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)); | ||
1711 | |||
1712 | nat_tuple.src.l3num = nf_ct_l3num(master); | ||
1713 | nat_tuple.src.u3.ip = exp->saved_ip; | ||
1714 | nat_tuple.dst.protonum = nf_ct_protonum(master); | ||
1715 | nat_tuple.src.u = exp->saved_proto; | ||
1716 | |||
1717 | if (ctnetlink_exp_dump_tuple(skb, &nat_tuple, | ||
1718 | CTA_EXPECT_NAT_TUPLE) < 0) | ||
1719 | goto nla_put_failure; | ||
1720 | nla_nest_end(skb, nest_parms); | ||
1721 | } | ||
1722 | #endif | ||
1691 | NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); | 1723 | NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); |
1692 | NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); | 1724 | NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); |
1693 | NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); | 1725 | NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); |
1726 | NLA_PUT_BE32(skb, CTA_EXPECT_CLASS, htonl(exp->class)); | ||
1694 | help = nfct_help(master); | 1727 | help = nfct_help(master); |
1695 | if (help) { | 1728 | if (help) { |
1696 | struct nf_conntrack_helper *helper; | 1729 | struct nf_conntrack_helper *helper; |
@@ -1699,6 +1732,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
1699 | if (helper) | 1732 | if (helper) |
1700 | NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); | 1733 | NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); |
1701 | } | 1734 | } |
1735 | expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn); | ||
1736 | if (expfn != NULL) | ||
1737 | NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name); | ||
1702 | 1738 | ||
1703 | return 0; | 1739 | return 0; |
1704 | 1740 | ||
@@ -1856,6 +1892,9 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { | |||
1856 | [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, | 1892 | [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, |
1857 | [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, | 1893 | [CTA_EXPECT_ZONE] = { .type = NLA_U16 }, |
1858 | [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, | 1894 | [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, |
1895 | [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, | ||
1896 | [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, | ||
1897 | [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING }, | ||
1859 | }; | 1898 | }; |
1860 | 1899 | ||
1861 | static int | 1900 | static int |
@@ -2031,6 +2070,41 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, | |||
2031 | return -EOPNOTSUPP; | 2070 | return -EOPNOTSUPP; |
2032 | } | 2071 | } |
2033 | 2072 | ||
2073 | static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = { | ||
2074 | [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 }, | ||
2075 | [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED }, | ||
2076 | }; | ||
2077 | |||
2078 | static int | ||
2079 | ctnetlink_parse_expect_nat(const struct nlattr *attr, | ||
2080 | struct nf_conntrack_expect *exp, | ||
2081 | u_int8_t u3) | ||
2082 | { | ||
2083 | #ifdef CONFIG_NF_NAT_NEEDED | ||
2084 | struct nlattr *tb[CTA_EXPECT_NAT_MAX+1]; | ||
2085 | struct nf_conntrack_tuple nat_tuple = {}; | ||
2086 | int err; | ||
2087 | |||
2088 | nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy); | ||
2089 | |||
2090 | if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE]) | ||
2091 | return -EINVAL; | ||
2092 | |||
2093 | err = ctnetlink_parse_tuple((const struct nlattr * const *)tb, | ||
2094 | &nat_tuple, CTA_EXPECT_NAT_TUPLE, u3); | ||
2095 | if (err < 0) | ||
2096 | return err; | ||
2097 | |||
2098 | exp->saved_ip = nat_tuple.src.u3.ip; | ||
2099 | exp->saved_proto = nat_tuple.src.u; | ||
2100 | exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR])); | ||
2101 | |||
2102 | return 0; | ||
2103 | #else | ||
2104 | return -EOPNOTSUPP; | ||
2105 | #endif | ||
2106 | } | ||
2107 | |||
2034 | static int | 2108 | static int |
2035 | ctnetlink_create_expect(struct net *net, u16 zone, | 2109 | ctnetlink_create_expect(struct net *net, u16 zone, |
2036 | const struct nlattr * const cda[], | 2110 | const struct nlattr * const cda[], |
@@ -2042,6 +2116,8 @@ ctnetlink_create_expect(struct net *net, u16 zone, | |||
2042 | struct nf_conntrack_expect *exp; | 2116 | struct nf_conntrack_expect *exp; |
2043 | struct nf_conn *ct; | 2117 | struct nf_conn *ct; |
2044 | struct nf_conn_help *help; | 2118 | struct nf_conn_help *help; |
2119 | struct nf_conntrack_helper *helper = NULL; | ||
2120 | u_int32_t class = 0; | ||
2045 | int err = 0; | 2121 | int err = 0; |
2046 | 2122 | ||
2047 | /* caller guarantees that those three CTA_EXPECT_* exist */ | 2123 | /* caller guarantees that those three CTA_EXPECT_* exist */ |
@@ -2060,6 +2136,40 @@ ctnetlink_create_expect(struct net *net, u16 zone, | |||
2060 | if (!h) | 2136 | if (!h) |
2061 | return -ENOENT; | 2137 | return -ENOENT; |
2062 | ct = nf_ct_tuplehash_to_ctrack(h); | 2138 | ct = nf_ct_tuplehash_to_ctrack(h); |
2139 | |||
2140 | /* Look for helper of this expectation */ | ||
2141 | if (cda[CTA_EXPECT_HELP_NAME]) { | ||
2142 | const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); | ||
2143 | |||
2144 | helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), | ||
2145 | nf_ct_protonum(ct)); | ||
2146 | if (helper == NULL) { | ||
2147 | #ifdef CONFIG_MODULES | ||
2148 | if (request_module("nfct-helper-%s", helpname) < 0) { | ||
2149 | err = -EOPNOTSUPP; | ||
2150 | goto out; | ||
2151 | } | ||
2152 | |||
2153 | helper = __nf_conntrack_helper_find(helpname, | ||
2154 | nf_ct_l3num(ct), | ||
2155 | nf_ct_protonum(ct)); | ||
2156 | if (helper) { | ||
2157 | err = -EAGAIN; | ||
2158 | goto out; | ||
2159 | } | ||
2160 | #endif | ||
2161 | err = -EOPNOTSUPP; | ||
2162 | goto out; | ||
2163 | } | ||
2164 | } | ||
2165 | |||
2166 | if (cda[CTA_EXPECT_CLASS] && helper) { | ||
2167 | class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS])); | ||
2168 | if (class > helper->expect_class_max) { | ||
2169 | err = -EINVAL; | ||
2170 | goto out; | ||
2171 | } | ||
2172 | } | ||
2063 | exp = nf_ct_expect_alloc(ct); | 2173 | exp = nf_ct_expect_alloc(ct); |
2064 | if (!exp) { | 2174 | if (!exp) { |
2065 | err = -ENOMEM; | 2175 | err = -ENOMEM; |
@@ -2086,18 +2196,35 @@ ctnetlink_create_expect(struct net *net, u16 zone, | |||
2086 | } else | 2196 | } else |
2087 | exp->flags = 0; | 2197 | exp->flags = 0; |
2088 | } | 2198 | } |
2199 | if (cda[CTA_EXPECT_FN]) { | ||
2200 | const char *name = nla_data(cda[CTA_EXPECT_FN]); | ||
2201 | struct nf_ct_helper_expectfn *expfn; | ||
2202 | |||
2203 | expfn = nf_ct_helper_expectfn_find_by_name(name); | ||
2204 | if (expfn == NULL) { | ||
2205 | err = -EINVAL; | ||
2206 | goto err_out; | ||
2207 | } | ||
2208 | exp->expectfn = expfn->expectfn; | ||
2209 | } else | ||
2210 | exp->expectfn = NULL; | ||
2089 | 2211 | ||
2090 | exp->class = 0; | 2212 | exp->class = class; |
2091 | exp->expectfn = NULL; | ||
2092 | exp->master = ct; | 2213 | exp->master = ct; |
2093 | exp->helper = NULL; | 2214 | exp->helper = helper; |
2094 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); | 2215 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); |
2095 | memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); | 2216 | memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); |
2096 | exp->mask.src.u.all = mask.src.u.all; | 2217 | exp->mask.src.u.all = mask.src.u.all; |
2097 | 2218 | ||
2219 | if (cda[CTA_EXPECT_NAT]) { | ||
2220 | err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT], | ||
2221 | exp, u3); | ||
2222 | if (err < 0) | ||
2223 | goto err_out; | ||
2224 | } | ||
2098 | err = nf_ct_expect_related_report(exp, pid, report); | 2225 | err = nf_ct_expect_related_report(exp, pid, report); |
2226 | err_out: | ||
2099 | nf_ct_expect_put(exp); | 2227 | nf_ct_expect_put(exp); |
2100 | |||
2101 | out: | 2228 | out: |
2102 | nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); | 2229 | nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); |
2103 | return err; | 2230 | return err; |
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index d6dde6dc09e6..24fdce256cb0 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
@@ -423,7 +423,7 @@ static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv, | |||
423 | } | 423 | } |
424 | 424 | ||
425 | static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, | 425 | static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, |
426 | unsigned int dataoff) | 426 | unsigned int dataoff, unsigned int *timeouts) |
427 | { | 427 | { |
428 | struct net *net = nf_ct_net(ct); | 428 | struct net *net = nf_ct_net(ct); |
429 | struct dccp_net *dn; | 429 | struct dccp_net *dn; |
@@ -472,12 +472,17 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh) | |||
472 | ntohl(dhack->dccph_ack_nr_low); | 472 | ntohl(dhack->dccph_ack_nr_low); |
473 | } | 473 | } |
474 | 474 | ||
475 | static unsigned int *dccp_get_timeouts(struct net *net) | ||
476 | { | ||
477 | return dccp_pernet(net)->dccp_timeout; | ||
478 | } | ||
479 | |||
475 | static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | 480 | static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, |
476 | unsigned int dataoff, enum ip_conntrack_info ctinfo, | 481 | unsigned int dataoff, enum ip_conntrack_info ctinfo, |
477 | u_int8_t pf, unsigned int hooknum) | 482 | u_int8_t pf, unsigned int hooknum, |
483 | unsigned int *timeouts) | ||
478 | { | 484 | { |
479 | struct net *net = nf_ct_net(ct); | 485 | struct net *net = nf_ct_net(ct); |
480 | struct dccp_net *dn; | ||
481 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 486 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
482 | struct dccp_hdr _dh, *dh; | 487 | struct dccp_hdr _dh, *dh; |
483 | u_int8_t type, old_state, new_state; | 488 | u_int8_t type, old_state, new_state; |
@@ -559,8 +564,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | |||
559 | if (new_state != old_state) | 564 | if (new_state != old_state) |
560 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); | 565 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); |
561 | 566 | ||
562 | dn = dccp_pernet(net); | 567 | nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); |
563 | nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]); | ||
564 | 568 | ||
565 | return NF_ACCEPT; | 569 | return NF_ACCEPT; |
566 | } | 570 | } |
@@ -702,8 +706,60 @@ static int dccp_nlattr_size(void) | |||
702 | return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ | 706 | return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ |
703 | + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); | 707 | + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); |
704 | } | 708 | } |
709 | |||
705 | #endif | 710 | #endif |
706 | 711 | ||
712 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
713 | |||
714 | #include <linux/netfilter/nfnetlink.h> | ||
715 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
716 | |||
717 | static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
718 | { | ||
719 | struct dccp_net *dn = dccp_pernet(&init_net); | ||
720 | unsigned int *timeouts = data; | ||
721 | int i; | ||
722 | |||
723 | /* set default DCCP timeouts. */ | ||
724 | for (i=0; i<CT_DCCP_MAX; i++) | ||
725 | timeouts[i] = dn->dccp_timeout[i]; | ||
726 | |||
727 | /* there's a 1:1 mapping between attributes and protocol states. */ | ||
728 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { | ||
729 | if (tb[i]) { | ||
730 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; | ||
731 | } | ||
732 | } | ||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static int | ||
737 | dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
738 | { | ||
739 | const unsigned int *timeouts = data; | ||
740 | int i; | ||
741 | |||
742 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) | ||
743 | NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ)); | ||
744 | |||
745 | return 0; | ||
746 | |||
747 | nla_put_failure: | ||
748 | return -ENOSPC; | ||
749 | } | ||
750 | |||
751 | static const struct nla_policy | ||
752 | dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = { | ||
753 | [CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 }, | ||
754 | [CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 }, | ||
755 | [CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 }, | ||
756 | [CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 }, | ||
757 | [CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 }, | ||
758 | [CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 }, | ||
759 | [CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 }, | ||
760 | }; | ||
761 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
762 | |||
707 | #ifdef CONFIG_SYSCTL | 763 | #ifdef CONFIG_SYSCTL |
708 | /* template, data assigned later */ | 764 | /* template, data assigned later */ |
709 | static struct ctl_table dccp_sysctl_table[] = { | 765 | static struct ctl_table dccp_sysctl_table[] = { |
@@ -767,6 +823,7 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { | |||
767 | .invert_tuple = dccp_invert_tuple, | 823 | .invert_tuple = dccp_invert_tuple, |
768 | .new = dccp_new, | 824 | .new = dccp_new, |
769 | .packet = dccp_packet, | 825 | .packet = dccp_packet, |
826 | .get_timeouts = dccp_get_timeouts, | ||
770 | .error = dccp_error, | 827 | .error = dccp_error, |
771 | .print_tuple = dccp_print_tuple, | 828 | .print_tuple = dccp_print_tuple, |
772 | .print_conntrack = dccp_print_conntrack, | 829 | .print_conntrack = dccp_print_conntrack, |
@@ -779,6 +836,15 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { | |||
779 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 836 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
780 | .nla_policy = nf_ct_port_nla_policy, | 837 | .nla_policy = nf_ct_port_nla_policy, |
781 | #endif | 838 | #endif |
839 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
840 | .ctnl_timeout = { | ||
841 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, | ||
842 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, | ||
843 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, | ||
844 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, | ||
845 | .nla_policy = dccp_timeout_nla_policy, | ||
846 | }, | ||
847 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
782 | }; | 848 | }; |
783 | 849 | ||
784 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | 850 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { |
@@ -789,6 +855,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
789 | .invert_tuple = dccp_invert_tuple, | 855 | .invert_tuple = dccp_invert_tuple, |
790 | .new = dccp_new, | 856 | .new = dccp_new, |
791 | .packet = dccp_packet, | 857 | .packet = dccp_packet, |
858 | .get_timeouts = dccp_get_timeouts, | ||
792 | .error = dccp_error, | 859 | .error = dccp_error, |
793 | .print_tuple = dccp_print_tuple, | 860 | .print_tuple = dccp_print_tuple, |
794 | .print_conntrack = dccp_print_conntrack, | 861 | .print_conntrack = dccp_print_conntrack, |
@@ -801,6 +868,15 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
801 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 868 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
802 | .nla_policy = nf_ct_port_nla_policy, | 869 | .nla_policy = nf_ct_port_nla_policy, |
803 | #endif | 870 | #endif |
871 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
872 | .ctnl_timeout = { | ||
873 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, | ||
874 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, | ||
875 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, | ||
876 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, | ||
877 | .nla_policy = dccp_timeout_nla_policy, | ||
878 | }, | ||
879 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
804 | }; | 880 | }; |
805 | 881 | ||
806 | static __net_init int dccp_net_init(struct net *net) | 882 | static __net_init int dccp_net_init(struct net *net) |
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index e2091d0c7a2f..835e24c58f0d 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c | |||
@@ -40,25 +40,70 @@ static int generic_print_tuple(struct seq_file *s, | |||
40 | return 0; | 40 | return 0; |
41 | } | 41 | } |
42 | 42 | ||
43 | static unsigned int *generic_get_timeouts(struct net *net) | ||
44 | { | ||
45 | return &nf_ct_generic_timeout; | ||
46 | } | ||
47 | |||
43 | /* Returns verdict for packet, or -1 for invalid. */ | 48 | /* Returns verdict for packet, or -1 for invalid. */ |
44 | static int packet(struct nf_conn *ct, | 49 | static int generic_packet(struct nf_conn *ct, |
45 | const struct sk_buff *skb, | 50 | const struct sk_buff *skb, |
46 | unsigned int dataoff, | 51 | unsigned int dataoff, |
47 | enum ip_conntrack_info ctinfo, | 52 | enum ip_conntrack_info ctinfo, |
48 | u_int8_t pf, | 53 | u_int8_t pf, |
49 | unsigned int hooknum) | 54 | unsigned int hooknum, |
55 | unsigned int *timeout) | ||
50 | { | 56 | { |
51 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout); | 57 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
52 | return NF_ACCEPT; | 58 | return NF_ACCEPT; |
53 | } | 59 | } |
54 | 60 | ||
55 | /* Called when a new connection for this protocol found. */ | 61 | /* Called when a new connection for this protocol found. */ |
56 | static bool new(struct nf_conn *ct, const struct sk_buff *skb, | 62 | static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, |
57 | unsigned int dataoff) | 63 | unsigned int dataoff, unsigned int *timeouts) |
58 | { | 64 | { |
59 | return true; | 65 | return true; |
60 | } | 66 | } |
61 | 67 | ||
68 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
69 | |||
70 | #include <linux/netfilter/nfnetlink.h> | ||
71 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
72 | |||
73 | static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
74 | { | ||
75 | unsigned int *timeout = data; | ||
76 | |||
77 | if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT]) | ||
78 | *timeout = | ||
79 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ; | ||
80 | else { | ||
81 | /* Set default generic timeout. */ | ||
82 | *timeout = nf_ct_generic_timeout; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int | ||
89 | generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
90 | { | ||
91 | const unsigned int *timeout = data; | ||
92 | |||
93 | NLA_PUT_BE32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ)); | ||
94 | |||
95 | return 0; | ||
96 | |||
97 | nla_put_failure: | ||
98 | return -ENOSPC; | ||
99 | } | ||
100 | |||
101 | static const struct nla_policy | ||
102 | generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = { | ||
103 | [CTA_TIMEOUT_GENERIC_TIMEOUT] = { .type = NLA_U32 }, | ||
104 | }; | ||
105 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
106 | |||
62 | #ifdef CONFIG_SYSCTL | 107 | #ifdef CONFIG_SYSCTL |
63 | static struct ctl_table_header *generic_sysctl_header; | 108 | static struct ctl_table_header *generic_sysctl_header; |
64 | static struct ctl_table generic_sysctl_table[] = { | 109 | static struct ctl_table generic_sysctl_table[] = { |
@@ -93,8 +138,18 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = | |||
93 | .pkt_to_tuple = generic_pkt_to_tuple, | 138 | .pkt_to_tuple = generic_pkt_to_tuple, |
94 | .invert_tuple = generic_invert_tuple, | 139 | .invert_tuple = generic_invert_tuple, |
95 | .print_tuple = generic_print_tuple, | 140 | .print_tuple = generic_print_tuple, |
96 | .packet = packet, | 141 | .packet = generic_packet, |
97 | .new = new, | 142 | .get_timeouts = generic_get_timeouts, |
143 | .new = generic_new, | ||
144 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
145 | .ctnl_timeout = { | ||
146 | .nlattr_to_obj = generic_timeout_nlattr_to_obj, | ||
147 | .obj_to_nlattr = generic_timeout_obj_to_nlattr, | ||
148 | .nlattr_max = CTA_TIMEOUT_GENERIC_MAX, | ||
149 | .obj_size = sizeof(unsigned int), | ||
150 | .nla_policy = generic_timeout_nla_policy, | ||
151 | }, | ||
152 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
98 | #ifdef CONFIG_SYSCTL | 153 | #ifdef CONFIG_SYSCTL |
99 | .ctl_table_header = &generic_sysctl_header, | 154 | .ctl_table_header = &generic_sysctl_header, |
100 | .ctl_table = generic_sysctl_table, | 155 | .ctl_table = generic_sysctl_table, |
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index f0338791b822..659648c4b14a 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -41,8 +41,16 @@ | |||
41 | #include <linux/netfilter/nf_conntrack_proto_gre.h> | 41 | #include <linux/netfilter/nf_conntrack_proto_gre.h> |
42 | #include <linux/netfilter/nf_conntrack_pptp.h> | 42 | #include <linux/netfilter/nf_conntrack_pptp.h> |
43 | 43 | ||
44 | #define GRE_TIMEOUT (30 * HZ) | 44 | enum grep_conntrack { |
45 | #define GRE_STREAM_TIMEOUT (180 * HZ) | 45 | GRE_CT_UNREPLIED, |
46 | GRE_CT_REPLIED, | ||
47 | GRE_CT_MAX | ||
48 | }; | ||
49 | |||
50 | static unsigned int gre_timeouts[GRE_CT_MAX] = { | ||
51 | [GRE_CT_UNREPLIED] = 30*HZ, | ||
52 | [GRE_CT_REPLIED] = 180*HZ, | ||
53 | }; | ||
46 | 54 | ||
47 | static int proto_gre_net_id __read_mostly; | 55 | static int proto_gre_net_id __read_mostly; |
48 | struct netns_proto_gre { | 56 | struct netns_proto_gre { |
@@ -227,13 +235,19 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) | |||
227 | (ct->proto.gre.stream_timeout / HZ)); | 235 | (ct->proto.gre.stream_timeout / HZ)); |
228 | } | 236 | } |
229 | 237 | ||
238 | static unsigned int *gre_get_timeouts(struct net *net) | ||
239 | { | ||
240 | return gre_timeouts; | ||
241 | } | ||
242 | |||
230 | /* Returns verdict for packet, and may modify conntrack */ | 243 | /* Returns verdict for packet, and may modify conntrack */ |
231 | static int gre_packet(struct nf_conn *ct, | 244 | static int gre_packet(struct nf_conn *ct, |
232 | const struct sk_buff *skb, | 245 | const struct sk_buff *skb, |
233 | unsigned int dataoff, | 246 | unsigned int dataoff, |
234 | enum ip_conntrack_info ctinfo, | 247 | enum ip_conntrack_info ctinfo, |
235 | u_int8_t pf, | 248 | u_int8_t pf, |
236 | unsigned int hooknum) | 249 | unsigned int hooknum, |
250 | unsigned int *timeouts) | ||
237 | { | 251 | { |
238 | /* If we've seen traffic both ways, this is a GRE connection. | 252 | /* If we've seen traffic both ways, this is a GRE connection. |
239 | * Extend timeout. */ | 253 | * Extend timeout. */ |
@@ -252,15 +266,15 @@ static int gre_packet(struct nf_conn *ct, | |||
252 | 266 | ||
253 | /* Called when a new connection for this protocol found. */ | 267 | /* Called when a new connection for this protocol found. */ |
254 | static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, | 268 | static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, |
255 | unsigned int dataoff) | 269 | unsigned int dataoff, unsigned int *timeouts) |
256 | { | 270 | { |
257 | pr_debug(": "); | 271 | pr_debug(": "); |
258 | nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 272 | nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
259 | 273 | ||
260 | /* initialize to sane value. Ideally a conntrack helper | 274 | /* initialize to sane value. Ideally a conntrack helper |
261 | * (e.g. in case of pptp) is increasing them */ | 275 | * (e.g. in case of pptp) is increasing them */ |
262 | ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; | 276 | ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED]; |
263 | ct->proto.gre.timeout = GRE_TIMEOUT; | 277 | ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED]; |
264 | 278 | ||
265 | return true; | 279 | return true; |
266 | } | 280 | } |
@@ -278,6 +292,52 @@ static void gre_destroy(struct nf_conn *ct) | |||
278 | nf_ct_gre_keymap_destroy(master); | 292 | nf_ct_gre_keymap_destroy(master); |
279 | } | 293 | } |
280 | 294 | ||
295 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
296 | |||
297 | #include <linux/netfilter/nfnetlink.h> | ||
298 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
299 | |||
300 | static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
301 | { | ||
302 | unsigned int *timeouts = data; | ||
303 | |||
304 | /* set default timeouts for GRE. */ | ||
305 | timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED]; | ||
306 | timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED]; | ||
307 | |||
308 | if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) { | ||
309 | timeouts[GRE_CT_UNREPLIED] = | ||
310 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ; | ||
311 | } | ||
312 | if (tb[CTA_TIMEOUT_GRE_REPLIED]) { | ||
313 | timeouts[GRE_CT_REPLIED] = | ||
314 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ; | ||
315 | } | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int | ||
320 | gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
321 | { | ||
322 | const unsigned int *timeouts = data; | ||
323 | |||
324 | NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED, | ||
325 | htonl(timeouts[GRE_CT_UNREPLIED] / HZ)); | ||
326 | NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED, | ||
327 | htonl(timeouts[GRE_CT_REPLIED] / HZ)); | ||
328 | return 0; | ||
329 | |||
330 | nla_put_failure: | ||
331 | return -ENOSPC; | ||
332 | } | ||
333 | |||
334 | static const struct nla_policy | ||
335 | gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = { | ||
336 | [CTA_TIMEOUT_GRE_UNREPLIED] = { .type = NLA_U32 }, | ||
337 | [CTA_TIMEOUT_GRE_REPLIED] = { .type = NLA_U32 }, | ||
338 | }; | ||
339 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
340 | |||
281 | /* protocol helper struct */ | 341 | /* protocol helper struct */ |
282 | static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | 342 | static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { |
283 | .l3proto = AF_INET, | 343 | .l3proto = AF_INET, |
@@ -287,6 +347,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
287 | .invert_tuple = gre_invert_tuple, | 347 | .invert_tuple = gre_invert_tuple, |
288 | .print_tuple = gre_print_tuple, | 348 | .print_tuple = gre_print_tuple, |
289 | .print_conntrack = gre_print_conntrack, | 349 | .print_conntrack = gre_print_conntrack, |
350 | .get_timeouts = gre_get_timeouts, | ||
290 | .packet = gre_packet, | 351 | .packet = gre_packet, |
291 | .new = gre_new, | 352 | .new = gre_new, |
292 | .destroy = gre_destroy, | 353 | .destroy = gre_destroy, |
@@ -297,6 +358,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
297 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 358 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
298 | .nla_policy = nf_ct_port_nla_policy, | 359 | .nla_policy = nf_ct_port_nla_policy, |
299 | #endif | 360 | #endif |
361 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
362 | .ctnl_timeout = { | ||
363 | .nlattr_to_obj = gre_timeout_nlattr_to_obj, | ||
364 | .obj_to_nlattr = gre_timeout_obj_to_nlattr, | ||
365 | .nlattr_max = CTA_TIMEOUT_GRE_MAX, | ||
366 | .obj_size = sizeof(unsigned int) * GRE_CT_MAX, | ||
367 | .nla_policy = gre_timeout_nla_policy, | ||
368 | }, | ||
369 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
300 | }; | 370 | }; |
301 | 371 | ||
302 | static int proto_gre_net_init(struct net *net) | 372 | static int proto_gre_net_init(struct net *net) |
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index afa69136061a..72b5088592dc 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -279,13 +279,19 @@ static int sctp_new_state(enum ip_conntrack_dir dir, | |||
279 | return sctp_conntracks[dir][i][cur_state]; | 279 | return sctp_conntracks[dir][i][cur_state]; |
280 | } | 280 | } |
281 | 281 | ||
282 | static unsigned int *sctp_get_timeouts(struct net *net) | ||
283 | { | ||
284 | return sctp_timeouts; | ||
285 | } | ||
286 | |||
282 | /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ | 287 | /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ |
283 | static int sctp_packet(struct nf_conn *ct, | 288 | static int sctp_packet(struct nf_conn *ct, |
284 | const struct sk_buff *skb, | 289 | const struct sk_buff *skb, |
285 | unsigned int dataoff, | 290 | unsigned int dataoff, |
286 | enum ip_conntrack_info ctinfo, | 291 | enum ip_conntrack_info ctinfo, |
287 | u_int8_t pf, | 292 | u_int8_t pf, |
288 | unsigned int hooknum) | 293 | unsigned int hooknum, |
294 | unsigned int *timeouts) | ||
289 | { | 295 | { |
290 | enum sctp_conntrack new_state, old_state; | 296 | enum sctp_conntrack new_state, old_state; |
291 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 297 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
@@ -370,7 +376,7 @@ static int sctp_packet(struct nf_conn *ct, | |||
370 | } | 376 | } |
371 | spin_unlock_bh(&ct->lock); | 377 | spin_unlock_bh(&ct->lock); |
372 | 378 | ||
373 | nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]); | 379 | nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); |
374 | 380 | ||
375 | if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && | 381 | if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && |
376 | dir == IP_CT_DIR_REPLY && | 382 | dir == IP_CT_DIR_REPLY && |
@@ -390,7 +396,7 @@ out: | |||
390 | 396 | ||
391 | /* Called when a new connection for this protocol found. */ | 397 | /* Called when a new connection for this protocol found. */ |
392 | static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, | 398 | static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, |
393 | unsigned int dataoff) | 399 | unsigned int dataoff, unsigned int *timeouts) |
394 | { | 400 | { |
395 | enum sctp_conntrack new_state; | 401 | enum sctp_conntrack new_state; |
396 | const struct sctphdr *sh; | 402 | const struct sctphdr *sh; |
@@ -543,6 +549,57 @@ static int sctp_nlattr_size(void) | |||
543 | } | 549 | } |
544 | #endif | 550 | #endif |
545 | 551 | ||
552 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
553 | |||
554 | #include <linux/netfilter/nfnetlink.h> | ||
555 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
556 | |||
557 | static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
558 | { | ||
559 | unsigned int *timeouts = data; | ||
560 | int i; | ||
561 | |||
562 | /* set default SCTP timeouts. */ | ||
563 | for (i=0; i<SCTP_CONNTRACK_MAX; i++) | ||
564 | timeouts[i] = sctp_timeouts[i]; | ||
565 | |||
566 | /* there's a 1:1 mapping between attributes and protocol states. */ | ||
567 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { | ||
568 | if (tb[i]) { | ||
569 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; | ||
570 | } | ||
571 | } | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int | ||
576 | sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
577 | { | ||
578 | const unsigned int *timeouts = data; | ||
579 | int i; | ||
580 | |||
581 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) | ||
582 | NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ)); | ||
583 | |||
584 | return 0; | ||
585 | |||
586 | nla_put_failure: | ||
587 | return -ENOSPC; | ||
588 | } | ||
589 | |||
590 | static const struct nla_policy | ||
591 | sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = { | ||
592 | [CTA_TIMEOUT_SCTP_CLOSED] = { .type = NLA_U32 }, | ||
593 | [CTA_TIMEOUT_SCTP_COOKIE_WAIT] = { .type = NLA_U32 }, | ||
594 | [CTA_TIMEOUT_SCTP_COOKIE_ECHOED] = { .type = NLA_U32 }, | ||
595 | [CTA_TIMEOUT_SCTP_ESTABLISHED] = { .type = NLA_U32 }, | ||
596 | [CTA_TIMEOUT_SCTP_SHUTDOWN_SENT] = { .type = NLA_U32 }, | ||
597 | [CTA_TIMEOUT_SCTP_SHUTDOWN_RECD] = { .type = NLA_U32 }, | ||
598 | [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { .type = NLA_U32 }, | ||
599 | }; | ||
600 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
601 | |||
602 | |||
546 | #ifdef CONFIG_SYSCTL | 603 | #ifdef CONFIG_SYSCTL |
547 | static unsigned int sctp_sysctl_table_users; | 604 | static unsigned int sctp_sysctl_table_users; |
548 | static struct ctl_table_header *sctp_sysctl_header; | 605 | static struct ctl_table_header *sctp_sysctl_header; |
@@ -664,6 +721,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { | |||
664 | .print_tuple = sctp_print_tuple, | 721 | .print_tuple = sctp_print_tuple, |
665 | .print_conntrack = sctp_print_conntrack, | 722 | .print_conntrack = sctp_print_conntrack, |
666 | .packet = sctp_packet, | 723 | .packet = sctp_packet, |
724 | .get_timeouts = sctp_get_timeouts, | ||
667 | .new = sctp_new, | 725 | .new = sctp_new, |
668 | .me = THIS_MODULE, | 726 | .me = THIS_MODULE, |
669 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 727 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -675,6 +733,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { | |||
675 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 733 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
676 | .nla_policy = nf_ct_port_nla_policy, | 734 | .nla_policy = nf_ct_port_nla_policy, |
677 | #endif | 735 | #endif |
736 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
737 | .ctnl_timeout = { | ||
738 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, | ||
739 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, | ||
740 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, | ||
741 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, | ||
742 | .nla_policy = sctp_timeout_nla_policy, | ||
743 | }, | ||
744 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
678 | #ifdef CONFIG_SYSCTL | 745 | #ifdef CONFIG_SYSCTL |
679 | .ctl_table_users = &sctp_sysctl_table_users, | 746 | .ctl_table_users = &sctp_sysctl_table_users, |
680 | .ctl_table_header = &sctp_sysctl_header, | 747 | .ctl_table_header = &sctp_sysctl_header, |
@@ -694,6 +761,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { | |||
694 | .print_tuple = sctp_print_tuple, | 761 | .print_tuple = sctp_print_tuple, |
695 | .print_conntrack = sctp_print_conntrack, | 762 | .print_conntrack = sctp_print_conntrack, |
696 | .packet = sctp_packet, | 763 | .packet = sctp_packet, |
764 | .get_timeouts = sctp_get_timeouts, | ||
697 | .new = sctp_new, | 765 | .new = sctp_new, |
698 | .me = THIS_MODULE, | 766 | .me = THIS_MODULE, |
699 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 767 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -704,6 +772,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { | |||
704 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 772 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
705 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 773 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
706 | .nla_policy = nf_ct_port_nla_policy, | 774 | .nla_policy = nf_ct_port_nla_policy, |
775 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
776 | .ctnl_timeout = { | ||
777 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, | ||
778 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, | ||
779 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, | ||
780 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, | ||
781 | .nla_policy = sctp_timeout_nla_policy, | ||
782 | }, | ||
783 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
707 | #endif | 784 | #endif |
708 | #ifdef CONFIG_SYSCTL | 785 | #ifdef CONFIG_SYSCTL |
709 | .ctl_table_users = &sctp_sysctl_table_users, | 786 | .ctl_table_users = &sctp_sysctl_table_users, |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 97b9f3ebf28c..361eade62a09 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -64,13 +64,7 @@ static const char *const tcp_conntrack_names[] = { | |||
64 | #define HOURS * 60 MINS | 64 | #define HOURS * 60 MINS |
65 | #define DAYS * 24 HOURS | 65 | #define DAYS * 24 HOURS |
66 | 66 | ||
67 | /* RFC1122 says the R2 limit should be at least 100 seconds. | 67 | static unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] __read_mostly = { |
68 | Linux uses 15 packets as limit, which corresponds | ||
69 | to ~13-30min depending on RTO. */ | ||
70 | static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; | ||
71 | static unsigned int nf_ct_tcp_timeout_unacknowledged __read_mostly = 5 MINS; | ||
72 | |||
73 | static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { | ||
74 | [TCP_CONNTRACK_SYN_SENT] = 2 MINS, | 68 | [TCP_CONNTRACK_SYN_SENT] = 2 MINS, |
75 | [TCP_CONNTRACK_SYN_RECV] = 60 SECS, | 69 | [TCP_CONNTRACK_SYN_RECV] = 60 SECS, |
76 | [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, | 70 | [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, |
@@ -80,6 +74,11 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { | |||
80 | [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, | 74 | [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, |
81 | [TCP_CONNTRACK_CLOSE] = 10 SECS, | 75 | [TCP_CONNTRACK_CLOSE] = 10 SECS, |
82 | [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, | 76 | [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, |
77 | /* RFC1122 says the R2 limit should be at least 100 seconds. | ||
78 | Linux uses 15 packets as limit, which corresponds | ||
79 | to ~13-30min depending on RTO. */ | ||
80 | [TCP_CONNTRACK_RETRANS] = 5 MINS, | ||
81 | [TCP_CONNTRACK_UNACK] = 5 MINS, | ||
83 | }; | 82 | }; |
84 | 83 | ||
85 | #define sNO TCP_CONNTRACK_NONE | 84 | #define sNO TCP_CONNTRACK_NONE |
@@ -814,13 +813,19 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl, | |||
814 | return NF_ACCEPT; | 813 | return NF_ACCEPT; |
815 | } | 814 | } |
816 | 815 | ||
816 | static unsigned int *tcp_get_timeouts(struct net *net) | ||
817 | { | ||
818 | return tcp_timeouts; | ||
819 | } | ||
820 | |||
817 | /* Returns verdict for packet, or -1 for invalid. */ | 821 | /* Returns verdict for packet, or -1 for invalid. */ |
818 | static int tcp_packet(struct nf_conn *ct, | 822 | static int tcp_packet(struct nf_conn *ct, |
819 | const struct sk_buff *skb, | 823 | const struct sk_buff *skb, |
820 | unsigned int dataoff, | 824 | unsigned int dataoff, |
821 | enum ip_conntrack_info ctinfo, | 825 | enum ip_conntrack_info ctinfo, |
822 | u_int8_t pf, | 826 | u_int8_t pf, |
823 | unsigned int hooknum) | 827 | unsigned int hooknum, |
828 | unsigned int *timeouts) | ||
824 | { | 829 | { |
825 | struct net *net = nf_ct_net(ct); | 830 | struct net *net = nf_ct_net(ct); |
826 | struct nf_conntrack_tuple *tuple; | 831 | struct nf_conntrack_tuple *tuple; |
@@ -1015,14 +1020,14 @@ static int tcp_packet(struct nf_conn *ct, | |||
1015 | ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; | 1020 | ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; |
1016 | 1021 | ||
1017 | if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && | 1022 | if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && |
1018 | tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans) | 1023 | timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) |
1019 | timeout = nf_ct_tcp_timeout_max_retrans; | 1024 | timeout = timeouts[TCP_CONNTRACK_RETRANS]; |
1020 | else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & | 1025 | else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & |
1021 | IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && | 1026 | IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && |
1022 | tcp_timeouts[new_state] > nf_ct_tcp_timeout_unacknowledged) | 1027 | timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) |
1023 | timeout = nf_ct_tcp_timeout_unacknowledged; | 1028 | timeout = timeouts[TCP_CONNTRACK_UNACK]; |
1024 | else | 1029 | else |
1025 | timeout = tcp_timeouts[new_state]; | 1030 | timeout = timeouts[new_state]; |
1026 | spin_unlock_bh(&ct->lock); | 1031 | spin_unlock_bh(&ct->lock); |
1027 | 1032 | ||
1028 | if (new_state != old_state) | 1033 | if (new_state != old_state) |
@@ -1054,7 +1059,7 @@ static int tcp_packet(struct nf_conn *ct, | |||
1054 | 1059 | ||
1055 | /* Called when a new connection for this protocol found. */ | 1060 | /* Called when a new connection for this protocol found. */ |
1056 | static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, | 1061 | static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, |
1057 | unsigned int dataoff) | 1062 | unsigned int dataoff, unsigned int *timeouts) |
1058 | { | 1063 | { |
1059 | enum tcp_conntrack new_state; | 1064 | enum tcp_conntrack new_state; |
1060 | const struct tcphdr *th; | 1065 | const struct tcphdr *th; |
@@ -1239,6 +1244,113 @@ static int tcp_nlattr_tuple_size(void) | |||
1239 | } | 1244 | } |
1240 | #endif | 1245 | #endif |
1241 | 1246 | ||
1247 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
1248 | |||
1249 | #include <linux/netfilter/nfnetlink.h> | ||
1250 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
1251 | |||
1252 | static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
1253 | { | ||
1254 | unsigned int *timeouts = data; | ||
1255 | int i; | ||
1256 | |||
1257 | /* set default TCP timeouts. */ | ||
1258 | for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++) | ||
1259 | timeouts[i] = tcp_timeouts[i]; | ||
1260 | |||
1261 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) { | ||
1262 | timeouts[TCP_CONNTRACK_SYN_SENT] = | ||
1263 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ; | ||
1264 | } | ||
1265 | if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) { | ||
1266 | timeouts[TCP_CONNTRACK_SYN_RECV] = | ||
1267 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ; | ||
1268 | } | ||
1269 | if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) { | ||
1270 | timeouts[TCP_CONNTRACK_ESTABLISHED] = | ||
1271 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ; | ||
1272 | } | ||
1273 | if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) { | ||
1274 | timeouts[TCP_CONNTRACK_FIN_WAIT] = | ||
1275 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ; | ||
1276 | } | ||
1277 | if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) { | ||
1278 | timeouts[TCP_CONNTRACK_CLOSE_WAIT] = | ||
1279 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ; | ||
1280 | } | ||
1281 | if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) { | ||
1282 | timeouts[TCP_CONNTRACK_LAST_ACK] = | ||
1283 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ; | ||
1284 | } | ||
1285 | if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) { | ||
1286 | timeouts[TCP_CONNTRACK_TIME_WAIT] = | ||
1287 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ; | ||
1288 | } | ||
1289 | if (tb[CTA_TIMEOUT_TCP_CLOSE]) { | ||
1290 | timeouts[TCP_CONNTRACK_CLOSE] = | ||
1291 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ; | ||
1292 | } | ||
1293 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) { | ||
1294 | timeouts[TCP_CONNTRACK_SYN_SENT2] = | ||
1295 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ; | ||
1296 | } | ||
1297 | if (tb[CTA_TIMEOUT_TCP_RETRANS]) { | ||
1298 | timeouts[TCP_CONNTRACK_RETRANS] = | ||
1299 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ; | ||
1300 | } | ||
1301 | if (tb[CTA_TIMEOUT_TCP_UNACK]) { | ||
1302 | timeouts[TCP_CONNTRACK_UNACK] = | ||
1303 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ; | ||
1304 | } | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | static int | ||
1309 | tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
1310 | { | ||
1311 | const unsigned int *timeouts = data; | ||
1312 | |||
1313 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT, | ||
1314 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ)); | ||
1315 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_RECV, | ||
1316 | htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ)); | ||
1317 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_ESTABLISHED, | ||
1318 | htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ)); | ||
1319 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_FIN_WAIT, | ||
1320 | htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ)); | ||
1321 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT, | ||
1322 | htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ)); | ||
1323 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_LAST_ACK, | ||
1324 | htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ)); | ||
1325 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_TIME_WAIT, | ||
1326 | htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ)); | ||
1327 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE, | ||
1328 | htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ)); | ||
1329 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT2, | ||
1330 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ)); | ||
1331 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_RETRANS, | ||
1332 | htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ)); | ||
1333 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_UNACK, | ||
1334 | htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ)); | ||
1335 | return 0; | ||
1336 | |||
1337 | nla_put_failure: | ||
1338 | return -ENOSPC; | ||
1339 | } | ||
1340 | |||
1341 | static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = { | ||
1342 | [CTA_TIMEOUT_TCP_SYN_SENT] = { .type = NLA_U32 }, | ||
1343 | [CTA_TIMEOUT_TCP_SYN_RECV] = { .type = NLA_U32 }, | ||
1344 | [CTA_TIMEOUT_TCP_ESTABLISHED] = { .type = NLA_U32 }, | ||
1345 | [CTA_TIMEOUT_TCP_FIN_WAIT] = { .type = NLA_U32 }, | ||
1346 | [CTA_TIMEOUT_TCP_CLOSE_WAIT] = { .type = NLA_U32 }, | ||
1347 | [CTA_TIMEOUT_TCP_LAST_ACK] = { .type = NLA_U32 }, | ||
1348 | [CTA_TIMEOUT_TCP_TIME_WAIT] = { .type = NLA_U32 }, | ||
1349 | [CTA_TIMEOUT_TCP_CLOSE] = { .type = NLA_U32 }, | ||
1350 | [CTA_TIMEOUT_TCP_SYN_SENT2] = { .type = NLA_U32 }, | ||
1351 | }; | ||
1352 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
1353 | |||
1242 | #ifdef CONFIG_SYSCTL | 1354 | #ifdef CONFIG_SYSCTL |
1243 | static unsigned int tcp_sysctl_table_users; | 1355 | static unsigned int tcp_sysctl_table_users; |
1244 | static struct ctl_table_header *tcp_sysctl_header; | 1356 | static struct ctl_table_header *tcp_sysctl_header; |
@@ -1301,14 +1413,14 @@ static struct ctl_table tcp_sysctl_table[] = { | |||
1301 | }, | 1413 | }, |
1302 | { | 1414 | { |
1303 | .procname = "nf_conntrack_tcp_timeout_max_retrans", | 1415 | .procname = "nf_conntrack_tcp_timeout_max_retrans", |
1304 | .data = &nf_ct_tcp_timeout_max_retrans, | 1416 | .data = &tcp_timeouts[TCP_CONNTRACK_RETRANS], |
1305 | .maxlen = sizeof(unsigned int), | 1417 | .maxlen = sizeof(unsigned int), |
1306 | .mode = 0644, | 1418 | .mode = 0644, |
1307 | .proc_handler = proc_dointvec_jiffies, | 1419 | .proc_handler = proc_dointvec_jiffies, |
1308 | }, | 1420 | }, |
1309 | { | 1421 | { |
1310 | .procname = "nf_conntrack_tcp_timeout_unacknowledged", | 1422 | .procname = "nf_conntrack_tcp_timeout_unacknowledged", |
1311 | .data = &nf_ct_tcp_timeout_unacknowledged, | 1423 | .data = &tcp_timeouts[TCP_CONNTRACK_UNACK], |
1312 | .maxlen = sizeof(unsigned int), | 1424 | .maxlen = sizeof(unsigned int), |
1313 | .mode = 0644, | 1425 | .mode = 0644, |
1314 | .proc_handler = proc_dointvec_jiffies, | 1426 | .proc_handler = proc_dointvec_jiffies, |
@@ -1404,7 +1516,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = { | |||
1404 | }, | 1516 | }, |
1405 | { | 1517 | { |
1406 | .procname = "ip_conntrack_tcp_timeout_max_retrans", | 1518 | .procname = "ip_conntrack_tcp_timeout_max_retrans", |
1407 | .data = &nf_ct_tcp_timeout_max_retrans, | 1519 | .data = &tcp_timeouts[TCP_CONNTRACK_RETRANS], |
1408 | .maxlen = sizeof(unsigned int), | 1520 | .maxlen = sizeof(unsigned int), |
1409 | .mode = 0644, | 1521 | .mode = 0644, |
1410 | .proc_handler = proc_dointvec_jiffies, | 1522 | .proc_handler = proc_dointvec_jiffies, |
@@ -1445,6 +1557,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = | |||
1445 | .print_tuple = tcp_print_tuple, | 1557 | .print_tuple = tcp_print_tuple, |
1446 | .print_conntrack = tcp_print_conntrack, | 1558 | .print_conntrack = tcp_print_conntrack, |
1447 | .packet = tcp_packet, | 1559 | .packet = tcp_packet, |
1560 | .get_timeouts = tcp_get_timeouts, | ||
1448 | .new = tcp_new, | 1561 | .new = tcp_new, |
1449 | .error = tcp_error, | 1562 | .error = tcp_error, |
1450 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 1563 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -1456,6 +1569,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = | |||
1456 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | 1569 | .nlattr_tuple_size = tcp_nlattr_tuple_size, |
1457 | .nla_policy = nf_ct_port_nla_policy, | 1570 | .nla_policy = nf_ct_port_nla_policy, |
1458 | #endif | 1571 | #endif |
1572 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
1573 | .ctnl_timeout = { | ||
1574 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, | ||
1575 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, | ||
1576 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, | ||
1577 | .obj_size = sizeof(unsigned int) * | ||
1578 | TCP_CONNTRACK_TIMEOUT_MAX, | ||
1579 | .nla_policy = tcp_timeout_nla_policy, | ||
1580 | }, | ||
1581 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
1459 | #ifdef CONFIG_SYSCTL | 1582 | #ifdef CONFIG_SYSCTL |
1460 | .ctl_table_users = &tcp_sysctl_table_users, | 1583 | .ctl_table_users = &tcp_sysctl_table_users, |
1461 | .ctl_table_header = &tcp_sysctl_header, | 1584 | .ctl_table_header = &tcp_sysctl_header, |
@@ -1477,6 +1600,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = | |||
1477 | .print_tuple = tcp_print_tuple, | 1600 | .print_tuple = tcp_print_tuple, |
1478 | .print_conntrack = tcp_print_conntrack, | 1601 | .print_conntrack = tcp_print_conntrack, |
1479 | .packet = tcp_packet, | 1602 | .packet = tcp_packet, |
1603 | .get_timeouts = tcp_get_timeouts, | ||
1480 | .new = tcp_new, | 1604 | .new = tcp_new, |
1481 | .error = tcp_error, | 1605 | .error = tcp_error, |
1482 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 1606 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -1488,6 +1612,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = | |||
1488 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | 1612 | .nlattr_tuple_size = tcp_nlattr_tuple_size, |
1489 | .nla_policy = nf_ct_port_nla_policy, | 1613 | .nla_policy = nf_ct_port_nla_policy, |
1490 | #endif | 1614 | #endif |
1615 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
1616 | .ctnl_timeout = { | ||
1617 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, | ||
1618 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, | ||
1619 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, | ||
1620 | .obj_size = sizeof(unsigned int) * | ||
1621 | TCP_CONNTRACK_TIMEOUT_MAX, | ||
1622 | .nla_policy = tcp_timeout_nla_policy, | ||
1623 | }, | ||
1624 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
1491 | #ifdef CONFIG_SYSCTL | 1625 | #ifdef CONFIG_SYSCTL |
1492 | .ctl_table_users = &tcp_sysctl_table_users, | 1626 | .ctl_table_users = &tcp_sysctl_table_users, |
1493 | .ctl_table_header = &tcp_sysctl_header, | 1627 | .ctl_table_header = &tcp_sysctl_header, |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 5f35757fbff0..a9073dc1548d 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -25,8 +25,16 @@ | |||
25 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 25 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
26 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 26 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
27 | 27 | ||
28 | static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; | 28 | enum udp_conntrack { |
29 | static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; | 29 | UDP_CT_UNREPLIED, |
30 | UDP_CT_REPLIED, | ||
31 | UDP_CT_MAX | ||
32 | }; | ||
33 | |||
34 | static unsigned int udp_timeouts[UDP_CT_MAX] = { | ||
35 | [UDP_CT_UNREPLIED] = 30*HZ, | ||
36 | [UDP_CT_REPLIED] = 180*HZ, | ||
37 | }; | ||
30 | 38 | ||
31 | static bool udp_pkt_to_tuple(const struct sk_buff *skb, | 39 | static bool udp_pkt_to_tuple(const struct sk_buff *skb, |
32 | unsigned int dataoff, | 40 | unsigned int dataoff, |
@@ -63,30 +71,38 @@ static int udp_print_tuple(struct seq_file *s, | |||
63 | ntohs(tuple->dst.u.udp.port)); | 71 | ntohs(tuple->dst.u.udp.port)); |
64 | } | 72 | } |
65 | 73 | ||
74 | static unsigned int *udp_get_timeouts(struct net *net) | ||
75 | { | ||
76 | return udp_timeouts; | ||
77 | } | ||
78 | |||
66 | /* Returns verdict for packet, and may modify conntracktype */ | 79 | /* Returns verdict for packet, and may modify conntracktype */ |
67 | static int udp_packet(struct nf_conn *ct, | 80 | static int udp_packet(struct nf_conn *ct, |
68 | const struct sk_buff *skb, | 81 | const struct sk_buff *skb, |
69 | unsigned int dataoff, | 82 | unsigned int dataoff, |
70 | enum ip_conntrack_info ctinfo, | 83 | enum ip_conntrack_info ctinfo, |
71 | u_int8_t pf, | 84 | u_int8_t pf, |
72 | unsigned int hooknum) | 85 | unsigned int hooknum, |
86 | unsigned int *timeouts) | ||
73 | { | 87 | { |
74 | /* If we've seen traffic both ways, this is some kind of UDP | 88 | /* If we've seen traffic both ways, this is some kind of UDP |
75 | stream. Extend timeout. */ | 89 | stream. Extend timeout. */ |
76 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | 90 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
77 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream); | 91 | nf_ct_refresh_acct(ct, ctinfo, skb, |
92 | timeouts[UDP_CT_REPLIED]); | ||
78 | /* Also, more likely to be important, and not a probe */ | 93 | /* Also, more likely to be important, and not a probe */ |
79 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) | 94 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) |
80 | nf_conntrack_event_cache(IPCT_ASSURED, ct); | 95 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
81 | } else | 96 | } else { |
82 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout); | 97 | nf_ct_refresh_acct(ct, ctinfo, skb, |
83 | 98 | timeouts[UDP_CT_UNREPLIED]); | |
99 | } | ||
84 | return NF_ACCEPT; | 100 | return NF_ACCEPT; |
85 | } | 101 | } |
86 | 102 | ||
87 | /* Called when a new connection for this protocol found. */ | 103 | /* Called when a new connection for this protocol found. */ |
88 | static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, | 104 | static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, |
89 | unsigned int dataoff) | 105 | unsigned int dataoff, unsigned int *timeouts) |
90 | { | 106 | { |
91 | return true; | 107 | return true; |
92 | } | 108 | } |
@@ -136,20 +152,66 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, | |||
136 | return NF_ACCEPT; | 152 | return NF_ACCEPT; |
137 | } | 153 | } |
138 | 154 | ||
155 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
156 | |||
157 | #include <linux/netfilter/nfnetlink.h> | ||
158 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
159 | |||
160 | static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
161 | { | ||
162 | unsigned int *timeouts = data; | ||
163 | |||
164 | /* set default timeouts for UDP. */ | ||
165 | timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED]; | ||
166 | timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED]; | ||
167 | |||
168 | if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) { | ||
169 | timeouts[UDP_CT_UNREPLIED] = | ||
170 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ; | ||
171 | } | ||
172 | if (tb[CTA_TIMEOUT_UDP_REPLIED]) { | ||
173 | timeouts[UDP_CT_REPLIED] = | ||
174 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ; | ||
175 | } | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int | ||
180 | udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
181 | { | ||
182 | const unsigned int *timeouts = data; | ||
183 | |||
184 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_UNREPLIED, | ||
185 | htonl(timeouts[UDP_CT_UNREPLIED] / HZ)); | ||
186 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_REPLIED, | ||
187 | htonl(timeouts[UDP_CT_REPLIED] / HZ)); | ||
188 | return 0; | ||
189 | |||
190 | nla_put_failure: | ||
191 | return -ENOSPC; | ||
192 | } | ||
193 | |||
194 | static const struct nla_policy | ||
195 | udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = { | ||
196 | [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 }, | ||
197 | [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 }, | ||
198 | }; | ||
199 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
200 | |||
139 | #ifdef CONFIG_SYSCTL | 201 | #ifdef CONFIG_SYSCTL |
140 | static unsigned int udp_sysctl_table_users; | 202 | static unsigned int udp_sysctl_table_users; |
141 | static struct ctl_table_header *udp_sysctl_header; | 203 | static struct ctl_table_header *udp_sysctl_header; |
142 | static struct ctl_table udp_sysctl_table[] = { | 204 | static struct ctl_table udp_sysctl_table[] = { |
143 | { | 205 | { |
144 | .procname = "nf_conntrack_udp_timeout", | 206 | .procname = "nf_conntrack_udp_timeout", |
145 | .data = &nf_ct_udp_timeout, | 207 | .data = &udp_timeouts[UDP_CT_UNREPLIED], |
146 | .maxlen = sizeof(unsigned int), | 208 | .maxlen = sizeof(unsigned int), |
147 | .mode = 0644, | 209 | .mode = 0644, |
148 | .proc_handler = proc_dointvec_jiffies, | 210 | .proc_handler = proc_dointvec_jiffies, |
149 | }, | 211 | }, |
150 | { | 212 | { |
151 | .procname = "nf_conntrack_udp_timeout_stream", | 213 | .procname = "nf_conntrack_udp_timeout_stream", |
152 | .data = &nf_ct_udp_timeout_stream, | 214 | .data = &udp_timeouts[UDP_CT_REPLIED], |
153 | .maxlen = sizeof(unsigned int), | 215 | .maxlen = sizeof(unsigned int), |
154 | .mode = 0644, | 216 | .mode = 0644, |
155 | .proc_handler = proc_dointvec_jiffies, | 217 | .proc_handler = proc_dointvec_jiffies, |
@@ -160,14 +222,14 @@ static struct ctl_table udp_sysctl_table[] = { | |||
160 | static struct ctl_table udp_compat_sysctl_table[] = { | 222 | static struct ctl_table udp_compat_sysctl_table[] = { |
161 | { | 223 | { |
162 | .procname = "ip_conntrack_udp_timeout", | 224 | .procname = "ip_conntrack_udp_timeout", |
163 | .data = &nf_ct_udp_timeout, | 225 | .data = &udp_timeouts[UDP_CT_UNREPLIED], |
164 | .maxlen = sizeof(unsigned int), | 226 | .maxlen = sizeof(unsigned int), |
165 | .mode = 0644, | 227 | .mode = 0644, |
166 | .proc_handler = proc_dointvec_jiffies, | 228 | .proc_handler = proc_dointvec_jiffies, |
167 | }, | 229 | }, |
168 | { | 230 | { |
169 | .procname = "ip_conntrack_udp_timeout_stream", | 231 | .procname = "ip_conntrack_udp_timeout_stream", |
170 | .data = &nf_ct_udp_timeout_stream, | 232 | .data = &udp_timeouts[UDP_CT_REPLIED], |
171 | .maxlen = sizeof(unsigned int), | 233 | .maxlen = sizeof(unsigned int), |
172 | .mode = 0644, | 234 | .mode = 0644, |
173 | .proc_handler = proc_dointvec_jiffies, | 235 | .proc_handler = proc_dointvec_jiffies, |
@@ -186,6 +248,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = | |||
186 | .invert_tuple = udp_invert_tuple, | 248 | .invert_tuple = udp_invert_tuple, |
187 | .print_tuple = udp_print_tuple, | 249 | .print_tuple = udp_print_tuple, |
188 | .packet = udp_packet, | 250 | .packet = udp_packet, |
251 | .get_timeouts = udp_get_timeouts, | ||
189 | .new = udp_new, | 252 | .new = udp_new, |
190 | .error = udp_error, | 253 | .error = udp_error, |
191 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 254 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -194,6 +257,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = | |||
194 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 257 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
195 | .nla_policy = nf_ct_port_nla_policy, | 258 | .nla_policy = nf_ct_port_nla_policy, |
196 | #endif | 259 | #endif |
260 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
261 | .ctnl_timeout = { | ||
262 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | ||
263 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | ||
264 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | ||
265 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | ||
266 | .nla_policy = udp_timeout_nla_policy, | ||
267 | }, | ||
268 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
197 | #ifdef CONFIG_SYSCTL | 269 | #ifdef CONFIG_SYSCTL |
198 | .ctl_table_users = &udp_sysctl_table_users, | 270 | .ctl_table_users = &udp_sysctl_table_users, |
199 | .ctl_table_header = &udp_sysctl_header, | 271 | .ctl_table_header = &udp_sysctl_header, |
@@ -214,6 +286,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = | |||
214 | .invert_tuple = udp_invert_tuple, | 286 | .invert_tuple = udp_invert_tuple, |
215 | .print_tuple = udp_print_tuple, | 287 | .print_tuple = udp_print_tuple, |
216 | .packet = udp_packet, | 288 | .packet = udp_packet, |
289 | .get_timeouts = udp_get_timeouts, | ||
217 | .new = udp_new, | 290 | .new = udp_new, |
218 | .error = udp_error, | 291 | .error = udp_error, |
219 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 292 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -222,6 +295,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = | |||
222 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 295 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
223 | .nla_policy = nf_ct_port_nla_policy, | 296 | .nla_policy = nf_ct_port_nla_policy, |
224 | #endif | 297 | #endif |
298 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
299 | .ctnl_timeout = { | ||
300 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | ||
301 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | ||
302 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | ||
303 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | ||
304 | .nla_policy = udp_timeout_nla_policy, | ||
305 | }, | ||
306 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
225 | #ifdef CONFIG_SYSCTL | 307 | #ifdef CONFIG_SYSCTL |
226 | .ctl_table_users = &udp_sysctl_table_users, | 308 | .ctl_table_users = &udp_sysctl_table_users, |
227 | .ctl_table_header = &udp_sysctl_header, | 309 | .ctl_table_header = &udp_sysctl_header, |
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index f52ca1181013..e0606392cda0 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c | |||
@@ -24,8 +24,16 @@ | |||
24 | #include <net/netfilter/nf_conntrack_ecache.h> | 24 | #include <net/netfilter/nf_conntrack_ecache.h> |
25 | #include <net/netfilter/nf_log.h> | 25 | #include <net/netfilter/nf_log.h> |
26 | 26 | ||
27 | static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ; | 27 | enum udplite_conntrack { |
28 | static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ; | 28 | UDPLITE_CT_UNREPLIED, |
29 | UDPLITE_CT_REPLIED, | ||
30 | UDPLITE_CT_MAX | ||
31 | }; | ||
32 | |||
33 | static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = { | ||
34 | [UDPLITE_CT_UNREPLIED] = 30*HZ, | ||
35 | [UDPLITE_CT_REPLIED] = 180*HZ, | ||
36 | }; | ||
29 | 37 | ||
30 | static bool udplite_pkt_to_tuple(const struct sk_buff *skb, | 38 | static bool udplite_pkt_to_tuple(const struct sk_buff *skb, |
31 | unsigned int dataoff, | 39 | unsigned int dataoff, |
@@ -60,31 +68,38 @@ static int udplite_print_tuple(struct seq_file *s, | |||
60 | ntohs(tuple->dst.u.udp.port)); | 68 | ntohs(tuple->dst.u.udp.port)); |
61 | } | 69 | } |
62 | 70 | ||
71 | static unsigned int *udplite_get_timeouts(struct net *net) | ||
72 | { | ||
73 | return udplite_timeouts; | ||
74 | } | ||
75 | |||
63 | /* Returns verdict for packet, and may modify conntracktype */ | 76 | /* Returns verdict for packet, and may modify conntracktype */ |
64 | static int udplite_packet(struct nf_conn *ct, | 77 | static int udplite_packet(struct nf_conn *ct, |
65 | const struct sk_buff *skb, | 78 | const struct sk_buff *skb, |
66 | unsigned int dataoff, | 79 | unsigned int dataoff, |
67 | enum ip_conntrack_info ctinfo, | 80 | enum ip_conntrack_info ctinfo, |
68 | u_int8_t pf, | 81 | u_int8_t pf, |
69 | unsigned int hooknum) | 82 | unsigned int hooknum, |
83 | unsigned int *timeouts) | ||
70 | { | 84 | { |
71 | /* If we've seen traffic both ways, this is some kind of UDP | 85 | /* If we've seen traffic both ways, this is some kind of UDP |
72 | stream. Extend timeout. */ | 86 | stream. Extend timeout. */ |
73 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | 87 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
74 | nf_ct_refresh_acct(ct, ctinfo, skb, | 88 | nf_ct_refresh_acct(ct, ctinfo, skb, |
75 | nf_ct_udplite_timeout_stream); | 89 | timeouts[UDPLITE_CT_REPLIED]); |
76 | /* Also, more likely to be important, and not a probe */ | 90 | /* Also, more likely to be important, and not a probe */ |
77 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) | 91 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) |
78 | nf_conntrack_event_cache(IPCT_ASSURED, ct); | 92 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
79 | } else | 93 | } else { |
80 | nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout); | 94 | nf_ct_refresh_acct(ct, ctinfo, skb, |
81 | 95 | timeouts[UDPLITE_CT_UNREPLIED]); | |
96 | } | ||
82 | return NF_ACCEPT; | 97 | return NF_ACCEPT; |
83 | } | 98 | } |
84 | 99 | ||
85 | /* Called when a new connection for this protocol found. */ | 100 | /* Called when a new connection for this protocol found. */ |
86 | static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb, | 101 | static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb, |
87 | unsigned int dataoff) | 102 | unsigned int dataoff, unsigned int *timeouts) |
88 | { | 103 | { |
89 | return true; | 104 | return true; |
90 | } | 105 | } |
@@ -141,20 +156,66 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, | |||
141 | return NF_ACCEPT; | 156 | return NF_ACCEPT; |
142 | } | 157 | } |
143 | 158 | ||
159 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
160 | |||
161 | #include <linux/netfilter/nfnetlink.h> | ||
162 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
163 | |||
164 | static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
165 | { | ||
166 | unsigned int *timeouts = data; | ||
167 | |||
168 | /* set default timeouts for UDPlite. */ | ||
169 | timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED]; | ||
170 | timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED]; | ||
171 | |||
172 | if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) { | ||
173 | timeouts[UDPLITE_CT_UNREPLIED] = | ||
174 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ; | ||
175 | } | ||
176 | if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) { | ||
177 | timeouts[UDPLITE_CT_REPLIED] = | ||
178 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ; | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
185 | { | ||
186 | const unsigned int *timeouts = data; | ||
187 | |||
188 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED, | ||
189 | htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ)); | ||
190 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_REPLIED, | ||
191 | htonl(timeouts[UDPLITE_CT_REPLIED] / HZ)); | ||
192 | return 0; | ||
193 | |||
194 | nla_put_failure: | ||
195 | return -ENOSPC; | ||
196 | } | ||
197 | |||
198 | static const struct nla_policy | ||
199 | udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = { | ||
200 | [CTA_TIMEOUT_UDPLITE_UNREPLIED] = { .type = NLA_U32 }, | ||
201 | [CTA_TIMEOUT_UDPLITE_REPLIED] = { .type = NLA_U32 }, | ||
202 | }; | ||
203 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
204 | |||
144 | #ifdef CONFIG_SYSCTL | 205 | #ifdef CONFIG_SYSCTL |
145 | static unsigned int udplite_sysctl_table_users; | 206 | static unsigned int udplite_sysctl_table_users; |
146 | static struct ctl_table_header *udplite_sysctl_header; | 207 | static struct ctl_table_header *udplite_sysctl_header; |
147 | static struct ctl_table udplite_sysctl_table[] = { | 208 | static struct ctl_table udplite_sysctl_table[] = { |
148 | { | 209 | { |
149 | .procname = "nf_conntrack_udplite_timeout", | 210 | .procname = "nf_conntrack_udplite_timeout", |
150 | .data = &nf_ct_udplite_timeout, | 211 | .data = &udplite_timeouts[UDPLITE_CT_UNREPLIED], |
151 | .maxlen = sizeof(unsigned int), | 212 | .maxlen = sizeof(unsigned int), |
152 | .mode = 0644, | 213 | .mode = 0644, |
153 | .proc_handler = proc_dointvec_jiffies, | 214 | .proc_handler = proc_dointvec_jiffies, |
154 | }, | 215 | }, |
155 | { | 216 | { |
156 | .procname = "nf_conntrack_udplite_timeout_stream", | 217 | .procname = "nf_conntrack_udplite_timeout_stream", |
157 | .data = &nf_ct_udplite_timeout_stream, | 218 | .data = &udplite_timeouts[UDPLITE_CT_REPLIED], |
158 | .maxlen = sizeof(unsigned int), | 219 | .maxlen = sizeof(unsigned int), |
159 | .mode = 0644, | 220 | .mode = 0644, |
160 | .proc_handler = proc_dointvec_jiffies, | 221 | .proc_handler = proc_dointvec_jiffies, |
@@ -172,6 +233,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = | |||
172 | .invert_tuple = udplite_invert_tuple, | 233 | .invert_tuple = udplite_invert_tuple, |
173 | .print_tuple = udplite_print_tuple, | 234 | .print_tuple = udplite_print_tuple, |
174 | .packet = udplite_packet, | 235 | .packet = udplite_packet, |
236 | .get_timeouts = udplite_get_timeouts, | ||
175 | .new = udplite_new, | 237 | .new = udplite_new, |
176 | .error = udplite_error, | 238 | .error = udplite_error, |
177 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 239 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -180,6 +242,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = | |||
180 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 242 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
181 | .nla_policy = nf_ct_port_nla_policy, | 243 | .nla_policy = nf_ct_port_nla_policy, |
182 | #endif | 244 | #endif |
245 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
246 | .ctnl_timeout = { | ||
247 | .nlattr_to_obj = udplite_timeout_nlattr_to_obj, | ||
248 | .obj_to_nlattr = udplite_timeout_obj_to_nlattr, | ||
249 | .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX, | ||
250 | .obj_size = sizeof(unsigned int) * | ||
251 | CTA_TIMEOUT_UDPLITE_MAX, | ||
252 | .nla_policy = udplite_timeout_nla_policy, | ||
253 | }, | ||
254 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
183 | #ifdef CONFIG_SYSCTL | 255 | #ifdef CONFIG_SYSCTL |
184 | .ctl_table_users = &udplite_sysctl_table_users, | 256 | .ctl_table_users = &udplite_sysctl_table_users, |
185 | .ctl_table_header = &udplite_sysctl_header, | 257 | .ctl_table_header = &udplite_sysctl_header, |
@@ -196,6 +268,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = | |||
196 | .invert_tuple = udplite_invert_tuple, | 268 | .invert_tuple = udplite_invert_tuple, |
197 | .print_tuple = udplite_print_tuple, | 269 | .print_tuple = udplite_print_tuple, |
198 | .packet = udplite_packet, | 270 | .packet = udplite_packet, |
271 | .get_timeouts = udplite_get_timeouts, | ||
199 | .new = udplite_new, | 272 | .new = udplite_new, |
200 | .error = udplite_error, | 273 | .error = udplite_error, |
201 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 274 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
@@ -204,6 +277,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = | |||
204 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 277 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
205 | .nla_policy = nf_ct_port_nla_policy, | 278 | .nla_policy = nf_ct_port_nla_policy, |
206 | #endif | 279 | #endif |
280 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
281 | .ctnl_timeout = { | ||
282 | .nlattr_to_obj = udplite_timeout_nlattr_to_obj, | ||
283 | .obj_to_nlattr = udplite_timeout_obj_to_nlattr, | ||
284 | .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX, | ||
285 | .obj_size = sizeof(unsigned int) * | ||
286 | CTA_TIMEOUT_UDPLITE_MAX, | ||
287 | .nla_policy = udplite_timeout_nla_policy, | ||
288 | }, | ||
289 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
207 | #ifdef CONFIG_SYSCTL | 290 | #ifdef CONFIG_SYSCTL |
208 | .ctl_table_users = &udplite_sysctl_table_users, | 291 | .ctl_table_users = &udplite_sysctl_table_users, |
209 | .ctl_table_header = &udplite_sysctl_header, | 292 | .ctl_table_header = &udplite_sysctl_header, |
diff --git a/net/netfilter/nf_conntrack_timeout.c b/net/netfilter/nf_conntrack_timeout.c new file mode 100644 index 000000000000..a878ce5b252c --- /dev/null +++ b/net/netfilter/nf_conntrack_timeout.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> | ||
3 | * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation (or any later at your option). | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/netfilter.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/vmalloc.h> | ||
14 | #include <linux/stddef.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/percpu.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/export.h> | ||
21 | |||
22 | #include <net/netfilter/nf_conntrack.h> | ||
23 | #include <net/netfilter/nf_conntrack_core.h> | ||
24 | #include <net/netfilter/nf_conntrack_extend.h> | ||
25 | #include <net/netfilter/nf_conntrack_timeout.h> | ||
26 | |||
27 | struct ctnl_timeout * | ||
28 | (*nf_ct_timeout_find_get_hook)(const char *name) __read_mostly; | ||
29 | EXPORT_SYMBOL_GPL(nf_ct_timeout_find_get_hook); | ||
30 | |||
31 | void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout) __read_mostly; | ||
32 | EXPORT_SYMBOL_GPL(nf_ct_timeout_put_hook); | ||
33 | |||
34 | static struct nf_ct_ext_type timeout_extend __read_mostly = { | ||
35 | .len = sizeof(struct nf_conn_timeout), | ||
36 | .align = __alignof__(struct nf_conn_timeout), | ||
37 | .id = NF_CT_EXT_TIMEOUT, | ||
38 | }; | ||
39 | |||
40 | int nf_conntrack_timeout_init(struct net *net) | ||
41 | { | ||
42 | int ret = 0; | ||
43 | |||
44 | if (net_eq(net, &init_net)) { | ||
45 | ret = nf_ct_extend_register(&timeout_extend); | ||
46 | if (ret < 0) { | ||
47 | printk(KERN_ERR "nf_ct_timeout: Unable to register " | ||
48 | "timeout extension.\n"); | ||
49 | return ret; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | void nf_conntrack_timeout_fini(struct net *net) | ||
57 | { | ||
58 | if (net_eq(net, &init_net)) | ||
59 | nf_ct_extend_unregister(&timeout_extend); | ||
60 | } | ||
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c new file mode 100644 index 000000000000..fec29a43de4d --- /dev/null +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> | ||
3 | * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation (or any later at your option). | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/rculist.h> | ||
13 | #include <linux/rculist_nulls.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/timer.h> | ||
16 | #include <linux/security.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/netlink.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include <linux/netfilter.h> | ||
25 | #include <net/netlink.h> | ||
26 | #include <net/sock.h> | ||
27 | #include <net/netfilter/nf_conntrack.h> | ||
28 | #include <net/netfilter/nf_conntrack_core.h> | ||
29 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
30 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
31 | #include <net/netfilter/nf_conntrack_tuple.h> | ||
32 | #include <net/netfilter/nf_conntrack_timeout.h> | ||
33 | |||
34 | #include <linux/netfilter/nfnetlink.h> | ||
35 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
36 | |||
37 | MODULE_LICENSE("GPL"); | ||
38 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
39 | MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); | ||
40 | |||
41 | static LIST_HEAD(cttimeout_list); | ||
42 | |||
43 | static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { | ||
44 | [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING }, | ||
45 | [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, | ||
46 | [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, | ||
47 | [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, | ||
48 | }; | ||
49 | |||
50 | static int | ||
51 | ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, | ||
52 | struct nf_conntrack_l4proto *l4proto, | ||
53 | const struct nlattr *attr) | ||
54 | { | ||
55 | int ret = 0; | ||
56 | |||
57 | if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { | ||
58 | struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; | ||
59 | |||
60 | nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, | ||
61 | attr, l4proto->ctnl_timeout.nla_policy); | ||
62 | |||
63 | ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data); | ||
64 | } | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | static int | ||
69 | cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | ||
70 | const struct nlmsghdr *nlh, | ||
71 | const struct nlattr * const cda[]) | ||
72 | { | ||
73 | __u16 l3num; | ||
74 | __u8 l4num; | ||
75 | struct nf_conntrack_l4proto *l4proto; | ||
76 | struct ctnl_timeout *timeout, *matching = NULL; | ||
77 | char *name; | ||
78 | int ret; | ||
79 | |||
80 | if (!cda[CTA_TIMEOUT_NAME] || | ||
81 | !cda[CTA_TIMEOUT_L3PROTO] || | ||
82 | !cda[CTA_TIMEOUT_L4PROTO] || | ||
83 | !cda[CTA_TIMEOUT_DATA]) | ||
84 | return -EINVAL; | ||
85 | |||
86 | name = nla_data(cda[CTA_TIMEOUT_NAME]); | ||
87 | l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); | ||
88 | l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); | ||
89 | |||
90 | list_for_each_entry(timeout, &cttimeout_list, head) { | ||
91 | if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
92 | continue; | ||
93 | |||
94 | if (nlh->nlmsg_flags & NLM_F_EXCL) | ||
95 | return -EEXIST; | ||
96 | |||
97 | matching = timeout; | ||
98 | break; | ||
99 | } | ||
100 | |||
101 | l4proto = __nf_ct_l4proto_find(l3num, l4num); | ||
102 | |||
103 | /* This protocol is not supportted, skip. */ | ||
104 | if (l4proto->l4proto != l4num) | ||
105 | return -EOPNOTSUPP; | ||
106 | |||
107 | if (matching) { | ||
108 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | ||
109 | /* You cannot replace one timeout policy by another of | ||
110 | * different kind, sorry. | ||
111 | */ | ||
112 | if (matching->l3num != l3num || | ||
113 | matching->l4num != l4num) | ||
114 | return -EINVAL; | ||
115 | |||
116 | ret = ctnl_timeout_parse_policy(matching, l4proto, | ||
117 | cda[CTA_TIMEOUT_DATA]); | ||
118 | return ret; | ||
119 | } | ||
120 | return -EBUSY; | ||
121 | } | ||
122 | |||
123 | timeout = kzalloc(sizeof(struct ctnl_timeout) + | ||
124 | l4proto->ctnl_timeout.obj_size, GFP_KERNEL); | ||
125 | if (timeout == NULL) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | ret = ctnl_timeout_parse_policy(timeout, l4proto, | ||
129 | cda[CTA_TIMEOUT_DATA]); | ||
130 | if (ret < 0) | ||
131 | goto err; | ||
132 | |||
133 | strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); | ||
134 | timeout->l3num = l3num; | ||
135 | timeout->l4num = l4num; | ||
136 | atomic_set(&timeout->refcnt, 1); | ||
137 | list_add_tail_rcu(&timeout->head, &cttimeout_list); | ||
138 | |||
139 | return 0; | ||
140 | err: | ||
141 | kfree(timeout); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | static int | ||
146 | ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, | ||
147 | int event, struct ctnl_timeout *timeout) | ||
148 | { | ||
149 | struct nlmsghdr *nlh; | ||
150 | struct nfgenmsg *nfmsg; | ||
151 | unsigned int flags = pid ? NLM_F_MULTI : 0; | ||
152 | struct nf_conntrack_l4proto *l4proto; | ||
153 | |||
154 | event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; | ||
155 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); | ||
156 | if (nlh == NULL) | ||
157 | goto nlmsg_failure; | ||
158 | |||
159 | nfmsg = nlmsg_data(nlh); | ||
160 | nfmsg->nfgen_family = AF_UNSPEC; | ||
161 | nfmsg->version = NFNETLINK_V0; | ||
162 | nfmsg->res_id = 0; | ||
163 | |||
164 | NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); | ||
165 | NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); | ||
166 | NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); | ||
167 | NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, | ||
168 | htonl(atomic_read(&timeout->refcnt))); | ||
169 | |||
170 | l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); | ||
171 | |||
172 | /* If the timeout object does not match the layer 4 protocol tracker, | ||
173 | * then skip dumping the data part since we don't know how to | ||
174 | * interpret it. This may happen for UPDlite, SCTP and DCCP since | ||
175 | * you can unload the module. | ||
176 | */ | ||
177 | if (timeout->l4num != l4proto->l4proto) | ||
178 | goto out; | ||
179 | |||
180 | if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { | ||
181 | struct nlattr *nest_parms; | ||
182 | int ret; | ||
183 | |||
184 | nest_parms = nla_nest_start(skb, | ||
185 | CTA_TIMEOUT_DATA | NLA_F_NESTED); | ||
186 | if (!nest_parms) | ||
187 | goto nla_put_failure; | ||
188 | |||
189 | ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); | ||
190 | if (ret < 0) | ||
191 | goto nla_put_failure; | ||
192 | |||
193 | nla_nest_end(skb, nest_parms); | ||
194 | } | ||
195 | out: | ||
196 | nlmsg_end(skb, nlh); | ||
197 | return skb->len; | ||
198 | |||
199 | nlmsg_failure: | ||
200 | nla_put_failure: | ||
201 | nlmsg_cancel(skb, nlh); | ||
202 | return -1; | ||
203 | } | ||
204 | |||
205 | static int | ||
206 | ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
207 | { | ||
208 | struct ctnl_timeout *cur, *last; | ||
209 | |||
210 | if (cb->args[2]) | ||
211 | return 0; | ||
212 | |||
213 | last = (struct ctnl_timeout *)cb->args[1]; | ||
214 | if (cb->args[1]) | ||
215 | cb->args[1] = 0; | ||
216 | |||
217 | rcu_read_lock(); | ||
218 | list_for_each_entry_rcu(cur, &cttimeout_list, head) { | ||
219 | if (last && cur != last) | ||
220 | continue; | ||
221 | |||
222 | if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
223 | cb->nlh->nlmsg_seq, | ||
224 | NFNL_MSG_TYPE(cb->nlh->nlmsg_type), | ||
225 | IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) { | ||
226 | cb->args[1] = (unsigned long)cur; | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | if (!cb->args[1]) | ||
231 | cb->args[2] = 1; | ||
232 | rcu_read_unlock(); | ||
233 | return skb->len; | ||
234 | } | ||
235 | |||
236 | static int | ||
237 | cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb, | ||
238 | const struct nlmsghdr *nlh, | ||
239 | const struct nlattr * const cda[]) | ||
240 | { | ||
241 | int ret = -ENOENT; | ||
242 | char *name; | ||
243 | struct ctnl_timeout *cur; | ||
244 | |||
245 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
246 | struct netlink_dump_control c = { | ||
247 | .dump = ctnl_timeout_dump, | ||
248 | }; | ||
249 | return netlink_dump_start(ctnl, skb, nlh, &c); | ||
250 | } | ||
251 | |||
252 | if (!cda[CTA_TIMEOUT_NAME]) | ||
253 | return -EINVAL; | ||
254 | name = nla_data(cda[CTA_TIMEOUT_NAME]); | ||
255 | |||
256 | list_for_each_entry(cur, &cttimeout_list, head) { | ||
257 | struct sk_buff *skb2; | ||
258 | |||
259 | if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
260 | continue; | ||
261 | |||
262 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
263 | if (skb2 == NULL) { | ||
264 | ret = -ENOMEM; | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).pid, | ||
269 | nlh->nlmsg_seq, | ||
270 | NFNL_MSG_TYPE(nlh->nlmsg_type), | ||
271 | IPCTNL_MSG_TIMEOUT_NEW, cur); | ||
272 | if (ret <= 0) { | ||
273 | kfree_skb(skb2); | ||
274 | break; | ||
275 | } | ||
276 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, | ||
277 | MSG_DONTWAIT); | ||
278 | if (ret > 0) | ||
279 | ret = 0; | ||
280 | |||
281 | /* this avoids a loop in nfnetlink. */ | ||
282 | return ret == -EAGAIN ? -ENOBUFS : ret; | ||
283 | } | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | /* try to delete object, fail if it is still in use. */ | ||
288 | static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) | ||
289 | { | ||
290 | int ret = 0; | ||
291 | |||
292 | /* we want to avoid races with nf_ct_timeout_find_get. */ | ||
293 | if (atomic_dec_and_test(&timeout->refcnt)) { | ||
294 | /* We are protected by nfnl mutex. */ | ||
295 | list_del_rcu(&timeout->head); | ||
296 | kfree_rcu(timeout, rcu_head); | ||
297 | } else { | ||
298 | /* still in use, restore reference counter. */ | ||
299 | atomic_inc(&timeout->refcnt); | ||
300 | ret = -EBUSY; | ||
301 | } | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | static int | ||
306 | cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, | ||
307 | const struct nlmsghdr *nlh, | ||
308 | const struct nlattr * const cda[]) | ||
309 | { | ||
310 | char *name; | ||
311 | struct ctnl_timeout *cur; | ||
312 | int ret = -ENOENT; | ||
313 | |||
314 | if (!cda[CTA_TIMEOUT_NAME]) { | ||
315 | list_for_each_entry(cur, &cttimeout_list, head) | ||
316 | ctnl_timeout_try_del(cur); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | name = nla_data(cda[CTA_TIMEOUT_NAME]); | ||
321 | |||
322 | list_for_each_entry(cur, &cttimeout_list, head) { | ||
323 | if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
324 | continue; | ||
325 | |||
326 | ret = ctnl_timeout_try_del(cur); | ||
327 | if (ret < 0) | ||
328 | return ret; | ||
329 | |||
330 | break; | ||
331 | } | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
336 | static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) | ||
337 | { | ||
338 | struct ctnl_timeout *timeout, *matching = NULL; | ||
339 | |||
340 | rcu_read_lock(); | ||
341 | list_for_each_entry_rcu(timeout, &cttimeout_list, head) { | ||
342 | if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
343 | continue; | ||
344 | |||
345 | if (!try_module_get(THIS_MODULE)) | ||
346 | goto err; | ||
347 | |||
348 | if (!atomic_inc_not_zero(&timeout->refcnt)) { | ||
349 | module_put(THIS_MODULE); | ||
350 | goto err; | ||
351 | } | ||
352 | matching = timeout; | ||
353 | break; | ||
354 | } | ||
355 | err: | ||
356 | rcu_read_unlock(); | ||
357 | return matching; | ||
358 | } | ||
359 | |||
360 | static void ctnl_timeout_put(struct ctnl_timeout *timeout) | ||
361 | { | ||
362 | atomic_dec(&timeout->refcnt); | ||
363 | module_put(THIS_MODULE); | ||
364 | } | ||
365 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
366 | |||
367 | static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { | ||
368 | [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, | ||
369 | .attr_count = CTA_TIMEOUT_MAX, | ||
370 | .policy = cttimeout_nla_policy }, | ||
371 | [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, | ||
372 | .attr_count = CTA_TIMEOUT_MAX, | ||
373 | .policy = cttimeout_nla_policy }, | ||
374 | [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, | ||
375 | .attr_count = CTA_TIMEOUT_MAX, | ||
376 | .policy = cttimeout_nla_policy }, | ||
377 | }; | ||
378 | |||
379 | static const struct nfnetlink_subsystem cttimeout_subsys = { | ||
380 | .name = "conntrack_timeout", | ||
381 | .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT, | ||
382 | .cb_count = IPCTNL_MSG_TIMEOUT_MAX, | ||
383 | .cb = cttimeout_cb, | ||
384 | }; | ||
385 | |||
386 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT); | ||
387 | |||
388 | static int __init cttimeout_init(void) | ||
389 | { | ||
390 | int ret; | ||
391 | |||
392 | ret = nfnetlink_subsys_register(&cttimeout_subsys); | ||
393 | if (ret < 0) { | ||
394 | pr_err("cttimeout_init: cannot register cttimeout with " | ||
395 | "nfnetlink.\n"); | ||
396 | goto err_out; | ||
397 | } | ||
398 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
399 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get); | ||
400 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put); | ||
401 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
402 | return 0; | ||
403 | |||
404 | err_out: | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | static void __exit cttimeout_exit(void) | ||
409 | { | ||
410 | struct ctnl_timeout *cur, *tmp; | ||
411 | |||
412 | pr_info("cttimeout: unregistering from nfnetlink.\n"); | ||
413 | |||
414 | nfnetlink_subsys_unregister(&cttimeout_subsys); | ||
415 | list_for_each_entry_safe(cur, tmp, &cttimeout_list, head) { | ||
416 | list_del_rcu(&cur->head); | ||
417 | /* We are sure that our objects have no clients at this point, | ||
418 | * it's safe to release them all without checking refcnt. | ||
419 | */ | ||
420 | kfree_rcu(cur, rcu_head); | ||
421 | } | ||
422 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
423 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); | ||
424 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); | ||
425 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
426 | } | ||
427 | |||
428 | module_init(cttimeout_init); | ||
429 | module_exit(cttimeout_exit); | ||
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 0221d10de75a..b873445df444 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c | |||
@@ -16,10 +16,11 @@ | |||
16 | #include <net/netfilter/nf_conntrack.h> | 16 | #include <net/netfilter/nf_conntrack.h> |
17 | #include <net/netfilter/nf_conntrack_helper.h> | 17 | #include <net/netfilter/nf_conntrack_helper.h> |
18 | #include <net/netfilter/nf_conntrack_ecache.h> | 18 | #include <net/netfilter/nf_conntrack_ecache.h> |
19 | #include <net/netfilter/nf_conntrack_timeout.h> | ||
19 | #include <net/netfilter/nf_conntrack_zones.h> | 20 | #include <net/netfilter/nf_conntrack_zones.h> |
20 | 21 | ||
21 | static unsigned int xt_ct_target(struct sk_buff *skb, | 22 | static unsigned int xt_ct_target_v0(struct sk_buff *skb, |
22 | const struct xt_action_param *par) | 23 | const struct xt_action_param *par) |
23 | { | 24 | { |
24 | const struct xt_ct_target_info *info = par->targinfo; | 25 | const struct xt_ct_target_info *info = par->targinfo; |
25 | struct nf_conn *ct = info->ct; | 26 | struct nf_conn *ct = info->ct; |
@@ -35,6 +36,23 @@ static unsigned int xt_ct_target(struct sk_buff *skb, | |||
35 | return XT_CONTINUE; | 36 | return XT_CONTINUE; |
36 | } | 37 | } |
37 | 38 | ||
39 | static unsigned int xt_ct_target_v1(struct sk_buff *skb, | ||
40 | const struct xt_action_param *par) | ||
41 | { | ||
42 | const struct xt_ct_target_info_v1 *info = par->targinfo; | ||
43 | struct nf_conn *ct = info->ct; | ||
44 | |||
45 | /* Previously seen (loopback)? Ignore. */ | ||
46 | if (skb->nfct != NULL) | ||
47 | return XT_CONTINUE; | ||
48 | |||
49 | atomic_inc(&ct->ct_general.use); | ||
50 | skb->nfct = &ct->ct_general; | ||
51 | skb->nfctinfo = IP_CT_NEW; | ||
52 | |||
53 | return XT_CONTINUE; | ||
54 | } | ||
55 | |||
38 | static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) | 56 | static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) |
39 | { | 57 | { |
40 | if (par->family == NFPROTO_IPV4) { | 58 | if (par->family == NFPROTO_IPV4) { |
@@ -53,7 +71,7 @@ static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) | |||
53 | return 0; | 71 | return 0; |
54 | } | 72 | } |
55 | 73 | ||
56 | static int xt_ct_tg_check(const struct xt_tgchk_param *par) | 74 | static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) |
57 | { | 75 | { |
58 | struct xt_ct_target_info *info = par->targinfo; | 76 | struct xt_ct_target_info *info = par->targinfo; |
59 | struct nf_conntrack_tuple t; | 77 | struct nf_conntrack_tuple t; |
@@ -130,7 +148,137 @@ err1: | |||
130 | return ret; | 148 | return ret; |
131 | } | 149 | } |
132 | 150 | ||
133 | static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) | 151 | static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) |
152 | { | ||
153 | struct xt_ct_target_info_v1 *info = par->targinfo; | ||
154 | struct nf_conntrack_tuple t; | ||
155 | struct nf_conn_help *help; | ||
156 | struct nf_conn *ct; | ||
157 | int ret = 0; | ||
158 | u8 proto; | ||
159 | |||
160 | if (info->flags & ~XT_CT_NOTRACK) | ||
161 | return -EINVAL; | ||
162 | |||
163 | if (info->flags & XT_CT_NOTRACK) { | ||
164 | ct = nf_ct_untracked_get(); | ||
165 | atomic_inc(&ct->ct_general.use); | ||
166 | goto out; | ||
167 | } | ||
168 | |||
169 | #ifndef CONFIG_NF_CONNTRACK_ZONES | ||
170 | if (info->zone) | ||
171 | goto err1; | ||
172 | #endif | ||
173 | |||
174 | ret = nf_ct_l3proto_try_module_get(par->family); | ||
175 | if (ret < 0) | ||
176 | goto err1; | ||
177 | |||
178 | memset(&t, 0, sizeof(t)); | ||
179 | ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); | ||
180 | ret = PTR_ERR(ct); | ||
181 | if (IS_ERR(ct)) | ||
182 | goto err2; | ||
183 | |||
184 | ret = 0; | ||
185 | if ((info->ct_events || info->exp_events) && | ||
186 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, | ||
187 | GFP_KERNEL)) | ||
188 | goto err3; | ||
189 | |||
190 | if (info->helper[0]) { | ||
191 | ret = -ENOENT; | ||
192 | proto = xt_ct_find_proto(par); | ||
193 | if (!proto) { | ||
194 | pr_info("You must specify a L4 protocol, " | ||
195 | "and not use inversions on it.\n"); | ||
196 | goto err3; | ||
197 | } | ||
198 | |||
199 | ret = -ENOMEM; | ||
200 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); | ||
201 | if (help == NULL) | ||
202 | goto err3; | ||
203 | |||
204 | ret = -ENOENT; | ||
205 | help->helper = nf_conntrack_helper_try_module_get(info->helper, | ||
206 | par->family, | ||
207 | proto); | ||
208 | if (help->helper == NULL) { | ||
209 | pr_info("No such helper \"%s\"\n", info->helper); | ||
210 | goto err3; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
215 | if (info->timeout) { | ||
216 | typeof(nf_ct_timeout_find_get_hook) timeout_find_get; | ||
217 | struct ctnl_timeout *timeout; | ||
218 | struct nf_conn_timeout *timeout_ext; | ||
219 | |||
220 | timeout_find_get = | ||
221 | rcu_dereference(nf_ct_timeout_find_get_hook); | ||
222 | |||
223 | if (timeout_find_get) { | ||
224 | const struct ipt_entry *e = par->entryinfo; | ||
225 | |||
226 | if (e->ip.invflags & IPT_INV_PROTO) { | ||
227 | ret = -EINVAL; | ||
228 | pr_info("You cannot use inversion on " | ||
229 | "L4 protocol\n"); | ||
230 | goto err3; | ||
231 | } | ||
232 | timeout = timeout_find_get(info->timeout); | ||
233 | if (timeout == NULL) { | ||
234 | ret = -ENOENT; | ||
235 | pr_info("No such timeout policy \"%s\"\n", | ||
236 | info->timeout); | ||
237 | goto err3; | ||
238 | } | ||
239 | if (timeout->l3num != par->family) { | ||
240 | ret = -EINVAL; | ||
241 | pr_info("Timeout policy `%s' can only be " | ||
242 | "used by L3 protocol number %d\n", | ||
243 | info->timeout, timeout->l3num); | ||
244 | goto err3; | ||
245 | } | ||
246 | if (timeout->l4num != e->ip.proto) { | ||
247 | ret = -EINVAL; | ||
248 | pr_info("Timeout policy `%s' can only be " | ||
249 | "used by L4 protocol number %d\n", | ||
250 | info->timeout, timeout->l4num); | ||
251 | goto err3; | ||
252 | } | ||
253 | timeout_ext = nf_ct_timeout_ext_add(ct, timeout, | ||
254 | GFP_KERNEL); | ||
255 | if (timeout_ext == NULL) { | ||
256 | ret = -ENOMEM; | ||
257 | goto err3; | ||
258 | } | ||
259 | } else { | ||
260 | ret = -ENOENT; | ||
261 | pr_info("Timeout policy base is empty\n"); | ||
262 | goto err3; | ||
263 | } | ||
264 | } | ||
265 | #endif | ||
266 | |||
267 | __set_bit(IPS_TEMPLATE_BIT, &ct->status); | ||
268 | __set_bit(IPS_CONFIRMED_BIT, &ct->status); | ||
269 | out: | ||
270 | info->ct = ct; | ||
271 | return 0; | ||
272 | |||
273 | err3: | ||
274 | nf_conntrack_free(ct); | ||
275 | err2: | ||
276 | nf_ct_l3proto_module_put(par->family); | ||
277 | err1: | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) | ||
134 | { | 282 | { |
135 | struct xt_ct_target_info *info = par->targinfo; | 283 | struct xt_ct_target_info *info = par->targinfo; |
136 | struct nf_conn *ct = info->ct; | 284 | struct nf_conn *ct = info->ct; |
@@ -146,25 +294,67 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) | |||
146 | nf_ct_put(info->ct); | 294 | nf_ct_put(info->ct); |
147 | } | 295 | } |
148 | 296 | ||
149 | static struct xt_target xt_ct_tg __read_mostly = { | 297 | static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) |
150 | .name = "CT", | 298 | { |
151 | .family = NFPROTO_UNSPEC, | 299 | struct xt_ct_target_info_v1 *info = par->targinfo; |
152 | .targetsize = sizeof(struct xt_ct_target_info), | 300 | struct nf_conn *ct = info->ct; |
153 | .checkentry = xt_ct_tg_check, | 301 | struct nf_conn_help *help; |
154 | .destroy = xt_ct_tg_destroy, | 302 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
155 | .target = xt_ct_target, | 303 | struct nf_conn_timeout *timeout_ext; |
156 | .table = "raw", | 304 | typeof(nf_ct_timeout_put_hook) timeout_put; |
157 | .me = THIS_MODULE, | 305 | #endif |
306 | if (!nf_ct_is_untracked(ct)) { | ||
307 | help = nfct_help(ct); | ||
308 | if (help) | ||
309 | module_put(help->helper->me); | ||
310 | |||
311 | nf_ct_l3proto_module_put(par->family); | ||
312 | |||
313 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
314 | timeout_put = rcu_dereference(nf_ct_timeout_put_hook); | ||
315 | |||
316 | if (timeout_put) { | ||
317 | timeout_ext = nf_ct_timeout_find(ct); | ||
318 | if (timeout_ext) | ||
319 | timeout_put(timeout_ext->timeout); | ||
320 | } | ||
321 | #endif | ||
322 | } | ||
323 | nf_ct_put(info->ct); | ||
324 | } | ||
325 | |||
326 | static struct xt_target xt_ct_tg_reg[] __read_mostly = { | ||
327 | { | ||
328 | .name = "CT", | ||
329 | .family = NFPROTO_UNSPEC, | ||
330 | .targetsize = sizeof(struct xt_ct_target_info), | ||
331 | .checkentry = xt_ct_tg_check_v0, | ||
332 | .destroy = xt_ct_tg_destroy_v0, | ||
333 | .target = xt_ct_target_v0, | ||
334 | .table = "raw", | ||
335 | .me = THIS_MODULE, | ||
336 | }, | ||
337 | { | ||
338 | .name = "CT", | ||
339 | .family = NFPROTO_UNSPEC, | ||
340 | .revision = 1, | ||
341 | .targetsize = sizeof(struct xt_ct_target_info_v1), | ||
342 | .checkentry = xt_ct_tg_check_v1, | ||
343 | .destroy = xt_ct_tg_destroy_v1, | ||
344 | .target = xt_ct_target_v1, | ||
345 | .table = "raw", | ||
346 | .me = THIS_MODULE, | ||
347 | }, | ||
158 | }; | 348 | }; |
159 | 349 | ||
160 | static int __init xt_ct_tg_init(void) | 350 | static int __init xt_ct_tg_init(void) |
161 | { | 351 | { |
162 | return xt_register_target(&xt_ct_tg); | 352 | return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); |
163 | } | 353 | } |
164 | 354 | ||
165 | static void __exit xt_ct_tg_exit(void) | 355 | static void __exit xt_ct_tg_exit(void) |
166 | { | 356 | { |
167 | xt_unregister_target(&xt_ct_tg); | 357 | xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); |
168 | } | 358 | } |
169 | 359 | ||
170 | module_init(xt_ct_tg_init); | 360 | module_init(xt_ct_tg_init); |
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c new file mode 100644 index 000000000000..f99f8dee238b --- /dev/null +++ b/net/netfilter/xt_LOG.c | |||
@@ -0,0 +1,925 @@ | |||
1 | /* | ||
2 | * This is a module which is used for logging packets. | ||
3 | */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/if_arp.h> | ||
18 | #include <linux/ip.h> | ||
19 | #include <net/ipv6.h> | ||
20 | #include <net/icmp.h> | ||
21 | #include <net/udp.h> | ||
22 | #include <net/tcp.h> | ||
23 | #include <net/route.h> | ||
24 | |||
25 | #include <linux/netfilter.h> | ||
26 | #include <linux/netfilter/x_tables.h> | ||
27 | #include <linux/netfilter/xt_LOG.h> | ||
28 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
29 | #include <net/netfilter/nf_log.h> | ||
30 | #include <net/netfilter/xt_log.h> | ||
31 | |||
32 | static struct nf_loginfo default_loginfo = { | ||
33 | .type = NF_LOG_TYPE_LOG, | ||
34 | .u = { | ||
35 | .log = { | ||
36 | .level = 5, | ||
37 | .logflags = NF_LOG_MASK, | ||
38 | }, | ||
39 | }, | ||
40 | }; | ||
41 | |||
42 | static int dump_udp_header(struct sbuff *m, const struct sk_buff *skb, | ||
43 | u8 proto, int fragment, unsigned int offset) | ||
44 | { | ||
45 | struct udphdr _udph; | ||
46 | const struct udphdr *uh; | ||
47 | |||
48 | if (proto == IPPROTO_UDP) | ||
49 | /* Max length: 10 "PROTO=UDP " */ | ||
50 | sb_add(m, "PROTO=UDP "); | ||
51 | else /* Max length: 14 "PROTO=UDPLITE " */ | ||
52 | sb_add(m, "PROTO=UDPLITE "); | ||
53 | |||
54 | if (fragment) | ||
55 | goto out; | ||
56 | |||
57 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
58 | uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); | ||
59 | if (uh == NULL) { | ||
60 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
66 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), | ||
67 | ntohs(uh->len)); | ||
68 | |||
69 | out: | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int dump_tcp_header(struct sbuff *m, const struct sk_buff *skb, | ||
74 | u8 proto, int fragment, unsigned int offset, | ||
75 | unsigned int logflags) | ||
76 | { | ||
77 | struct tcphdr _tcph; | ||
78 | const struct tcphdr *th; | ||
79 | |||
80 | /* Max length: 10 "PROTO=TCP " */ | ||
81 | sb_add(m, "PROTO=TCP "); | ||
82 | |||
83 | if (fragment) | ||
84 | return 0; | ||
85 | |||
86 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
87 | th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); | ||
88 | if (th == NULL) { | ||
89 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); | ||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | ||
94 | sb_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); | ||
95 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | ||
96 | if (logflags & XT_LOG_TCPSEQ) | ||
97 | sb_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); | ||
98 | |||
99 | /* Max length: 13 "WINDOW=65535 " */ | ||
100 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); | ||
101 | /* Max length: 9 "RES=0x3C " */ | ||
102 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & | ||
103 | TCP_RESERVED_BITS) >> 22)); | ||
104 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | ||
105 | if (th->cwr) | ||
106 | sb_add(m, "CWR "); | ||
107 | if (th->ece) | ||
108 | sb_add(m, "ECE "); | ||
109 | if (th->urg) | ||
110 | sb_add(m, "URG "); | ||
111 | if (th->ack) | ||
112 | sb_add(m, "ACK "); | ||
113 | if (th->psh) | ||
114 | sb_add(m, "PSH "); | ||
115 | if (th->rst) | ||
116 | sb_add(m, "RST "); | ||
117 | if (th->syn) | ||
118 | sb_add(m, "SYN "); | ||
119 | if (th->fin) | ||
120 | sb_add(m, "FIN "); | ||
121 | /* Max length: 11 "URGP=65535 " */ | ||
122 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); | ||
123 | |||
124 | if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { | ||
125 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | ||
126 | const u_int8_t *op; | ||
127 | unsigned int i; | ||
128 | unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); | ||
129 | |||
130 | op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), | ||
131 | optsize, _opt); | ||
132 | if (op == NULL) { | ||
133 | sb_add(m, "OPT (TRUNCATED)"); | ||
134 | return 1; | ||
135 | } | ||
136 | |||
137 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
138 | sb_add(m, "OPT ("); | ||
139 | for (i = 0; i < optsize; i++) | ||
140 | sb_add(m, "%02X", op[i]); | ||
141 | |||
142 | sb_add(m, ") "); | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* One level of recursion won't kill us */ | ||
149 | static void dump_ipv4_packet(struct sbuff *m, | ||
150 | const struct nf_loginfo *info, | ||
151 | const struct sk_buff *skb, | ||
152 | unsigned int iphoff) | ||
153 | { | ||
154 | struct iphdr _iph; | ||
155 | const struct iphdr *ih; | ||
156 | unsigned int logflags; | ||
157 | |||
158 | if (info->type == NF_LOG_TYPE_LOG) | ||
159 | logflags = info->u.log.logflags; | ||
160 | else | ||
161 | logflags = NF_LOG_MASK; | ||
162 | |||
163 | ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); | ||
164 | if (ih == NULL) { | ||
165 | sb_add(m, "TRUNCATED"); | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | /* Important fields: | ||
170 | * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ | ||
171 | /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ | ||
172 | sb_add(m, "SRC=%pI4 DST=%pI4 ", | ||
173 | &ih->saddr, &ih->daddr); | ||
174 | |||
175 | /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ | ||
176 | sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", | ||
177 | ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, | ||
178 | ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); | ||
179 | |||
180 | /* Max length: 6 "CE DF MF " */ | ||
181 | if (ntohs(ih->frag_off) & IP_CE) | ||
182 | sb_add(m, "CE "); | ||
183 | if (ntohs(ih->frag_off) & IP_DF) | ||
184 | sb_add(m, "DF "); | ||
185 | if (ntohs(ih->frag_off) & IP_MF) | ||
186 | sb_add(m, "MF "); | ||
187 | |||
188 | /* Max length: 11 "FRAG:65535 " */ | ||
189 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
190 | sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); | ||
191 | |||
192 | if ((logflags & XT_LOG_IPOPT) && | ||
193 | ih->ihl * 4 > sizeof(struct iphdr)) { | ||
194 | const unsigned char *op; | ||
195 | unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; | ||
196 | unsigned int i, optsize; | ||
197 | |||
198 | optsize = ih->ihl * 4 - sizeof(struct iphdr); | ||
199 | op = skb_header_pointer(skb, iphoff+sizeof(_iph), | ||
200 | optsize, _opt); | ||
201 | if (op == NULL) { | ||
202 | sb_add(m, "TRUNCATED"); | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | ||
207 | sb_add(m, "OPT ("); | ||
208 | for (i = 0; i < optsize; i++) | ||
209 | sb_add(m, "%02X", op[i]); | ||
210 | sb_add(m, ") "); | ||
211 | } | ||
212 | |||
213 | switch (ih->protocol) { | ||
214 | case IPPROTO_TCP: | ||
215 | if (dump_tcp_header(m, skb, ih->protocol, | ||
216 | ntohs(ih->frag_off) & IP_OFFSET, | ||
217 | iphoff+ih->ihl*4, logflags)) | ||
218 | return; | ||
219 | break; | ||
220 | case IPPROTO_UDP: | ||
221 | case IPPROTO_UDPLITE: | ||
222 | if (dump_udp_header(m, skb, ih->protocol, | ||
223 | ntohs(ih->frag_off) & IP_OFFSET, | ||
224 | iphoff+ih->ihl*4)) | ||
225 | return; | ||
226 | break; | ||
227 | case IPPROTO_ICMP: { | ||
228 | struct icmphdr _icmph; | ||
229 | const struct icmphdr *ich; | ||
230 | static const size_t required_len[NR_ICMP_TYPES+1] | ||
231 | = { [ICMP_ECHOREPLY] = 4, | ||
232 | [ICMP_DEST_UNREACH] | ||
233 | = 8 + sizeof(struct iphdr), | ||
234 | [ICMP_SOURCE_QUENCH] | ||
235 | = 8 + sizeof(struct iphdr), | ||
236 | [ICMP_REDIRECT] | ||
237 | = 8 + sizeof(struct iphdr), | ||
238 | [ICMP_ECHO] = 4, | ||
239 | [ICMP_TIME_EXCEEDED] | ||
240 | = 8 + sizeof(struct iphdr), | ||
241 | [ICMP_PARAMETERPROB] | ||
242 | = 8 + sizeof(struct iphdr), | ||
243 | [ICMP_TIMESTAMP] = 20, | ||
244 | [ICMP_TIMESTAMPREPLY] = 20, | ||
245 | [ICMP_ADDRESS] = 12, | ||
246 | [ICMP_ADDRESSREPLY] = 12 }; | ||
247 | |||
248 | /* Max length: 11 "PROTO=ICMP " */ | ||
249 | sb_add(m, "PROTO=ICMP "); | ||
250 | |||
251 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
252 | break; | ||
253 | |||
254 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
255 | ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, | ||
256 | sizeof(_icmph), &_icmph); | ||
257 | if (ich == NULL) { | ||
258 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
259 | skb->len - iphoff - ih->ihl*4); | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
264 | sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code); | ||
265 | |||
266 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
267 | if (ich->type <= NR_ICMP_TYPES && | ||
268 | required_len[ich->type] && | ||
269 | skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { | ||
270 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
271 | skb->len - iphoff - ih->ihl*4); | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | switch (ich->type) { | ||
276 | case ICMP_ECHOREPLY: | ||
277 | case ICMP_ECHO: | ||
278 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
279 | sb_add(m, "ID=%u SEQ=%u ", | ||
280 | ntohs(ich->un.echo.id), | ||
281 | ntohs(ich->un.echo.sequence)); | ||
282 | break; | ||
283 | |||
284 | case ICMP_PARAMETERPROB: | ||
285 | /* Max length: 14 "PARAMETER=255 " */ | ||
286 | sb_add(m, "PARAMETER=%u ", | ||
287 | ntohl(ich->un.gateway) >> 24); | ||
288 | break; | ||
289 | case ICMP_REDIRECT: | ||
290 | /* Max length: 24 "GATEWAY=255.255.255.255 " */ | ||
291 | sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway); | ||
292 | /* Fall through */ | ||
293 | case ICMP_DEST_UNREACH: | ||
294 | case ICMP_SOURCE_QUENCH: | ||
295 | case ICMP_TIME_EXCEEDED: | ||
296 | /* Max length: 3+maxlen */ | ||
297 | if (!iphoff) { /* Only recurse once. */ | ||
298 | sb_add(m, "["); | ||
299 | dump_ipv4_packet(m, info, skb, | ||
300 | iphoff + ih->ihl*4+sizeof(_icmph)); | ||
301 | sb_add(m, "] "); | ||
302 | } | ||
303 | |||
304 | /* Max length: 10 "MTU=65535 " */ | ||
305 | if (ich->type == ICMP_DEST_UNREACH && | ||
306 | ich->code == ICMP_FRAG_NEEDED) | ||
307 | sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu)); | ||
308 | } | ||
309 | break; | ||
310 | } | ||
311 | /* Max Length */ | ||
312 | case IPPROTO_AH: { | ||
313 | struct ip_auth_hdr _ahdr; | ||
314 | const struct ip_auth_hdr *ah; | ||
315 | |||
316 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
317 | break; | ||
318 | |||
319 | /* Max length: 9 "PROTO=AH " */ | ||
320 | sb_add(m, "PROTO=AH "); | ||
321 | |||
322 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
323 | ah = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
324 | sizeof(_ahdr), &_ahdr); | ||
325 | if (ah == NULL) { | ||
326 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
327 | skb->len - iphoff - ih->ihl*4); | ||
328 | break; | ||
329 | } | ||
330 | |||
331 | /* Length: 15 "SPI=0xF1234567 " */ | ||
332 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
333 | break; | ||
334 | } | ||
335 | case IPPROTO_ESP: { | ||
336 | struct ip_esp_hdr _esph; | ||
337 | const struct ip_esp_hdr *eh; | ||
338 | |||
339 | /* Max length: 10 "PROTO=ESP " */ | ||
340 | sb_add(m, "PROTO=ESP "); | ||
341 | |||
342 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
343 | break; | ||
344 | |||
345 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
346 | eh = skb_header_pointer(skb, iphoff+ih->ihl*4, | ||
347 | sizeof(_esph), &_esph); | ||
348 | if (eh == NULL) { | ||
349 | sb_add(m, "INCOMPLETE [%u bytes] ", | ||
350 | skb->len - iphoff - ih->ihl*4); | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | /* Length: 15 "SPI=0xF1234567 " */ | ||
355 | sb_add(m, "SPI=0x%x ", ntohl(eh->spi)); | ||
356 | break; | ||
357 | } | ||
358 | /* Max length: 10 "PROTO 255 " */ | ||
359 | default: | ||
360 | sb_add(m, "PROTO=%u ", ih->protocol); | ||
361 | } | ||
362 | |||
363 | /* Max length: 15 "UID=4294967295 " */ | ||
364 | if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) { | ||
365 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
366 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
367 | sb_add(m, "UID=%u GID=%u ", | ||
368 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
369 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
370 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
371 | } | ||
372 | |||
373 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
374 | if (!iphoff && skb->mark) | ||
375 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
376 | |||
377 | /* Proto Max log string length */ | ||
378 | /* IP: 40+46+6+11+127 = 230 */ | ||
379 | /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ | ||
380 | /* UDP: 10+max(25,20) = 35 */ | ||
381 | /* UDPLITE: 14+max(25,20) = 39 */ | ||
382 | /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ | ||
383 | /* ESP: 10+max(25)+15 = 50 */ | ||
384 | /* AH: 9+max(25)+15 = 49 */ | ||
385 | /* unknown: 10 */ | ||
386 | |||
387 | /* (ICMP allows recursion one level deep) */ | ||
388 | /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ | ||
389 | /* maxlen = 230+ 91 + 230 + 252 = 803 */ | ||
390 | } | ||
391 | |||
392 | static void dump_ipv4_mac_header(struct sbuff *m, | ||
393 | const struct nf_loginfo *info, | ||
394 | const struct sk_buff *skb) | ||
395 | { | ||
396 | struct net_device *dev = skb->dev; | ||
397 | unsigned int logflags = 0; | ||
398 | |||
399 | if (info->type == NF_LOG_TYPE_LOG) | ||
400 | logflags = info->u.log.logflags; | ||
401 | |||
402 | if (!(logflags & XT_LOG_MACDECODE)) | ||
403 | goto fallback; | ||
404 | |||
405 | switch (dev->type) { | ||
406 | case ARPHRD_ETHER: | ||
407 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
408 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
409 | ntohs(eth_hdr(skb)->h_proto)); | ||
410 | return; | ||
411 | default: | ||
412 | break; | ||
413 | } | ||
414 | |||
415 | fallback: | ||
416 | sb_add(m, "MAC="); | ||
417 | if (dev->hard_header_len && | ||
418 | skb->mac_header != skb->network_header) { | ||
419 | const unsigned char *p = skb_mac_header(skb); | ||
420 | unsigned int i; | ||
421 | |||
422 | sb_add(m, "%02x", *p++); | ||
423 | for (i = 1; i < dev->hard_header_len; i++, p++) | ||
424 | sb_add(m, ":%02x", *p); | ||
425 | } | ||
426 | sb_add(m, " "); | ||
427 | } | ||
428 | |||
429 | static void | ||
430 | log_packet_common(struct sbuff *m, | ||
431 | u_int8_t pf, | ||
432 | unsigned int hooknum, | ||
433 | const struct sk_buff *skb, | ||
434 | const struct net_device *in, | ||
435 | const struct net_device *out, | ||
436 | const struct nf_loginfo *loginfo, | ||
437 | const char *prefix) | ||
438 | { | ||
439 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | ||
440 | prefix, | ||
441 | in ? in->name : "", | ||
442 | out ? out->name : ""); | ||
443 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
444 | if (skb->nf_bridge) { | ||
445 | const struct net_device *physindev; | ||
446 | const struct net_device *physoutdev; | ||
447 | |||
448 | physindev = skb->nf_bridge->physindev; | ||
449 | if (physindev && in != physindev) | ||
450 | sb_add(m, "PHYSIN=%s ", physindev->name); | ||
451 | physoutdev = skb->nf_bridge->physoutdev; | ||
452 | if (physoutdev && out != physoutdev) | ||
453 | sb_add(m, "PHYSOUT=%s ", physoutdev->name); | ||
454 | } | ||
455 | #endif | ||
456 | } | ||
457 | |||
458 | |||
459 | static void | ||
460 | ipt_log_packet(u_int8_t pf, | ||
461 | unsigned int hooknum, | ||
462 | const struct sk_buff *skb, | ||
463 | const struct net_device *in, | ||
464 | const struct net_device *out, | ||
465 | const struct nf_loginfo *loginfo, | ||
466 | const char *prefix) | ||
467 | { | ||
468 | struct sbuff *m = sb_open(); | ||
469 | |||
470 | if (!loginfo) | ||
471 | loginfo = &default_loginfo; | ||
472 | |||
473 | log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); | ||
474 | |||
475 | if (in != NULL) | ||
476 | dump_ipv4_mac_header(m, loginfo, skb); | ||
477 | |||
478 | dump_ipv4_packet(m, loginfo, skb, 0); | ||
479 | |||
480 | sb_close(m); | ||
481 | } | ||
482 | |||
483 | #if IS_ENABLED(CONFIG_IPV6) | ||
484 | /* One level of recursion won't kill us */ | ||
485 | static void dump_ipv6_packet(struct sbuff *m, | ||
486 | const struct nf_loginfo *info, | ||
487 | const struct sk_buff *skb, unsigned int ip6hoff, | ||
488 | int recurse) | ||
489 | { | ||
490 | u_int8_t currenthdr; | ||
491 | int fragment; | ||
492 | struct ipv6hdr _ip6h; | ||
493 | const struct ipv6hdr *ih; | ||
494 | unsigned int ptr; | ||
495 | unsigned int hdrlen = 0; | ||
496 | unsigned int logflags; | ||
497 | |||
498 | if (info->type == NF_LOG_TYPE_LOG) | ||
499 | logflags = info->u.log.logflags; | ||
500 | else | ||
501 | logflags = NF_LOG_MASK; | ||
502 | |||
503 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | ||
504 | if (ih == NULL) { | ||
505 | sb_add(m, "TRUNCATED"); | ||
506 | return; | ||
507 | } | ||
508 | |||
509 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | ||
510 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | ||
511 | |||
512 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | ||
513 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | ||
514 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | ||
515 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | ||
516 | ih->hop_limit, | ||
517 | (ntohl(*(__be32 *)ih) & 0x000fffff)); | ||
518 | |||
519 | fragment = 0; | ||
520 | ptr = ip6hoff + sizeof(struct ipv6hdr); | ||
521 | currenthdr = ih->nexthdr; | ||
522 | while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { | ||
523 | struct ipv6_opt_hdr _hdr; | ||
524 | const struct ipv6_opt_hdr *hp; | ||
525 | |||
526 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | ||
527 | if (hp == NULL) { | ||
528 | sb_add(m, "TRUNCATED"); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | /* Max length: 48 "OPT (...) " */ | ||
533 | if (logflags & XT_LOG_IPOPT) | ||
534 | sb_add(m, "OPT ( "); | ||
535 | |||
536 | switch (currenthdr) { | ||
537 | case IPPROTO_FRAGMENT: { | ||
538 | struct frag_hdr _fhdr; | ||
539 | const struct frag_hdr *fh; | ||
540 | |||
541 | sb_add(m, "FRAG:"); | ||
542 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | ||
543 | &_fhdr); | ||
544 | if (fh == NULL) { | ||
545 | sb_add(m, "TRUNCATED "); | ||
546 | return; | ||
547 | } | ||
548 | |||
549 | /* Max length: 6 "65535 " */ | ||
550 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); | ||
551 | |||
552 | /* Max length: 11 "INCOMPLETE " */ | ||
553 | if (fh->frag_off & htons(0x0001)) | ||
554 | sb_add(m, "INCOMPLETE "); | ||
555 | |||
556 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); | ||
557 | |||
558 | if (ntohs(fh->frag_off) & 0xFFF8) | ||
559 | fragment = 1; | ||
560 | |||
561 | hdrlen = 8; | ||
562 | |||
563 | break; | ||
564 | } | ||
565 | case IPPROTO_DSTOPTS: | ||
566 | case IPPROTO_ROUTING: | ||
567 | case IPPROTO_HOPOPTS: | ||
568 | if (fragment) { | ||
569 | if (logflags & XT_LOG_IPOPT) | ||
570 | sb_add(m, ")"); | ||
571 | return; | ||
572 | } | ||
573 | hdrlen = ipv6_optlen(hp); | ||
574 | break; | ||
575 | /* Max Length */ | ||
576 | case IPPROTO_AH: | ||
577 | if (logflags & XT_LOG_IPOPT) { | ||
578 | struct ip_auth_hdr _ahdr; | ||
579 | const struct ip_auth_hdr *ah; | ||
580 | |||
581 | /* Max length: 3 "AH " */ | ||
582 | sb_add(m, "AH "); | ||
583 | |||
584 | if (fragment) { | ||
585 | sb_add(m, ")"); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), | ||
590 | &_ahdr); | ||
591 | if (ah == NULL) { | ||
592 | /* | ||
593 | * Max length: 26 "INCOMPLETE [65535 | ||
594 | * bytes] )" | ||
595 | */ | ||
596 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
597 | skb->len - ptr); | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | /* Length: 15 "SPI=0xF1234567 */ | ||
602 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); | ||
603 | |||
604 | } | ||
605 | |||
606 | hdrlen = (hp->hdrlen+2)<<2; | ||
607 | break; | ||
608 | case IPPROTO_ESP: | ||
609 | if (logflags & XT_LOG_IPOPT) { | ||
610 | struct ip_esp_hdr _esph; | ||
611 | const struct ip_esp_hdr *eh; | ||
612 | |||
613 | /* Max length: 4 "ESP " */ | ||
614 | sb_add(m, "ESP "); | ||
615 | |||
616 | if (fragment) { | ||
617 | sb_add(m, ")"); | ||
618 | return; | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * Max length: 26 "INCOMPLETE [65535 bytes] )" | ||
623 | */ | ||
624 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | ||
625 | &_esph); | ||
626 | if (eh == NULL) { | ||
627 | sb_add(m, "INCOMPLETE [%u bytes] )", | ||
628 | skb->len - ptr); | ||
629 | return; | ||
630 | } | ||
631 | |||
632 | /* Length: 16 "SPI=0xF1234567 )" */ | ||
633 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi)); | ||
634 | |||
635 | } | ||
636 | return; | ||
637 | default: | ||
638 | /* Max length: 20 "Unknown Ext Hdr 255" */ | ||
639 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); | ||
640 | return; | ||
641 | } | ||
642 | if (logflags & XT_LOG_IPOPT) | ||
643 | sb_add(m, ") "); | ||
644 | |||
645 | currenthdr = hp->nexthdr; | ||
646 | ptr += hdrlen; | ||
647 | } | ||
648 | |||
649 | switch (currenthdr) { | ||
650 | case IPPROTO_TCP: | ||
651 | if (dump_tcp_header(m, skb, currenthdr, fragment, ptr, | ||
652 | logflags)) | ||
653 | return; | ||
654 | break; | ||
655 | case IPPROTO_UDP: | ||
656 | case IPPROTO_UDPLITE: | ||
657 | if (dump_udp_header(m, skb, currenthdr, fragment, ptr)) | ||
658 | return; | ||
659 | break; | ||
660 | case IPPROTO_ICMPV6: { | ||
661 | struct icmp6hdr _icmp6h; | ||
662 | const struct icmp6hdr *ic; | ||
663 | |||
664 | /* Max length: 13 "PROTO=ICMPv6 " */ | ||
665 | sb_add(m, "PROTO=ICMPv6 "); | ||
666 | |||
667 | if (fragment) | ||
668 | break; | ||
669 | |||
670 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | ||
671 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | ||
672 | if (ic == NULL) { | ||
673 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); | ||
674 | return; | ||
675 | } | ||
676 | |||
677 | /* Max length: 18 "TYPE=255 CODE=255 " */ | ||
678 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | ||
679 | |||
680 | switch (ic->icmp6_type) { | ||
681 | case ICMPV6_ECHO_REQUEST: | ||
682 | case ICMPV6_ECHO_REPLY: | ||
683 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | ||
684 | sb_add(m, "ID=%u SEQ=%u ", | ||
685 | ntohs(ic->icmp6_identifier), | ||
686 | ntohs(ic->icmp6_sequence)); | ||
687 | break; | ||
688 | case ICMPV6_MGM_QUERY: | ||
689 | case ICMPV6_MGM_REPORT: | ||
690 | case ICMPV6_MGM_REDUCTION: | ||
691 | break; | ||
692 | |||
693 | case ICMPV6_PARAMPROB: | ||
694 | /* Max length: 17 "POINTER=ffffffff " */ | ||
695 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); | ||
696 | /* Fall through */ | ||
697 | case ICMPV6_DEST_UNREACH: | ||
698 | case ICMPV6_PKT_TOOBIG: | ||
699 | case ICMPV6_TIME_EXCEED: | ||
700 | /* Max length: 3+maxlen */ | ||
701 | if (recurse) { | ||
702 | sb_add(m, "["); | ||
703 | dump_ipv6_packet(m, info, skb, | ||
704 | ptr + sizeof(_icmp6h), 0); | ||
705 | sb_add(m, "] "); | ||
706 | } | ||
707 | |||
708 | /* Max length: 10 "MTU=65535 " */ | ||
709 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | ||
710 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); | ||
711 | } | ||
712 | break; | ||
713 | } | ||
714 | /* Max length: 10 "PROTO=255 " */ | ||
715 | default: | ||
716 | sb_add(m, "PROTO=%u ", currenthdr); | ||
717 | } | ||
718 | |||
719 | /* Max length: 15 "UID=4294967295 " */ | ||
720 | if ((logflags & XT_LOG_UID) && recurse && skb->sk) { | ||
721 | read_lock_bh(&skb->sk->sk_callback_lock); | ||
722 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | ||
723 | sb_add(m, "UID=%u GID=%u ", | ||
724 | skb->sk->sk_socket->file->f_cred->fsuid, | ||
725 | skb->sk->sk_socket->file->f_cred->fsgid); | ||
726 | read_unlock_bh(&skb->sk->sk_callback_lock); | ||
727 | } | ||
728 | |||
729 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | ||
730 | if (!recurse && skb->mark) | ||
731 | sb_add(m, "MARK=0x%x ", skb->mark); | ||
732 | } | ||
733 | |||
734 | static void dump_ipv6_mac_header(struct sbuff *m, | ||
735 | const struct nf_loginfo *info, | ||
736 | const struct sk_buff *skb) | ||
737 | { | ||
738 | struct net_device *dev = skb->dev; | ||
739 | unsigned int logflags = 0; | ||
740 | |||
741 | if (info->type == NF_LOG_TYPE_LOG) | ||
742 | logflags = info->u.log.logflags; | ||
743 | |||
744 | if (!(logflags & XT_LOG_MACDECODE)) | ||
745 | goto fallback; | ||
746 | |||
747 | switch (dev->type) { | ||
748 | case ARPHRD_ETHER: | ||
749 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | ||
750 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | ||
751 | ntohs(eth_hdr(skb)->h_proto)); | ||
752 | return; | ||
753 | default: | ||
754 | break; | ||
755 | } | ||
756 | |||
757 | fallback: | ||
758 | sb_add(m, "MAC="); | ||
759 | if (dev->hard_header_len && | ||
760 | skb->mac_header != skb->network_header) { | ||
761 | const unsigned char *p = skb_mac_header(skb); | ||
762 | unsigned int len = dev->hard_header_len; | ||
763 | unsigned int i; | ||
764 | |||
765 | if (dev->type == ARPHRD_SIT) { | ||
766 | p -= ETH_HLEN; | ||
767 | |||
768 | if (p < skb->head) | ||
769 | p = NULL; | ||
770 | } | ||
771 | |||
772 | if (p != NULL) { | ||
773 | sb_add(m, "%02x", *p++); | ||
774 | for (i = 1; i < len; i++) | ||
775 | sb_add(m, ":%02x", *p++); | ||
776 | } | ||
777 | sb_add(m, " "); | ||
778 | |||
779 | if (dev->type == ARPHRD_SIT) { | ||
780 | const struct iphdr *iph = | ||
781 | (struct iphdr *)skb_mac_header(skb); | ||
782 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, | ||
783 | &iph->daddr); | ||
784 | } | ||
785 | } else | ||
786 | sb_add(m, " "); | ||
787 | } | ||
788 | |||
789 | static void | ||
790 | ip6t_log_packet(u_int8_t pf, | ||
791 | unsigned int hooknum, | ||
792 | const struct sk_buff *skb, | ||
793 | const struct net_device *in, | ||
794 | const struct net_device *out, | ||
795 | const struct nf_loginfo *loginfo, | ||
796 | const char *prefix) | ||
797 | { | ||
798 | struct sbuff *m = sb_open(); | ||
799 | |||
800 | if (!loginfo) | ||
801 | loginfo = &default_loginfo; | ||
802 | |||
803 | log_packet_common(m, pf, hooknum, skb, in, out, loginfo, prefix); | ||
804 | |||
805 | if (in != NULL) | ||
806 | dump_ipv6_mac_header(m, loginfo, skb); | ||
807 | |||
808 | dump_ipv6_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
809 | |||
810 | sb_close(m); | ||
811 | } | ||
812 | #endif | ||
813 | |||
814 | static unsigned int | ||
815 | log_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
816 | { | ||
817 | const struct xt_log_info *loginfo = par->targinfo; | ||
818 | struct nf_loginfo li; | ||
819 | |||
820 | li.type = NF_LOG_TYPE_LOG; | ||
821 | li.u.log.level = loginfo->level; | ||
822 | li.u.log.logflags = loginfo->logflags; | ||
823 | |||
824 | if (par->family == NFPROTO_IPV4) | ||
825 | ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, | ||
826 | par->out, &li, loginfo->prefix); | ||
827 | #if IS_ENABLED(CONFIG_IPV6) | ||
828 | else if (par->family == NFPROTO_IPV6) | ||
829 | ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, | ||
830 | par->out, &li, loginfo->prefix); | ||
831 | #endif | ||
832 | else | ||
833 | WARN_ON_ONCE(1); | ||
834 | |||
835 | return XT_CONTINUE; | ||
836 | } | ||
837 | |||
838 | static int log_tg_check(const struct xt_tgchk_param *par) | ||
839 | { | ||
840 | const struct xt_log_info *loginfo = par->targinfo; | ||
841 | |||
842 | if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6) | ||
843 | return -EINVAL; | ||
844 | |||
845 | if (loginfo->level >= 8) { | ||
846 | pr_debug("level %u >= 8\n", loginfo->level); | ||
847 | return -EINVAL; | ||
848 | } | ||
849 | |||
850 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | ||
851 | pr_debug("prefix is not null-terminated\n"); | ||
852 | return -EINVAL; | ||
853 | } | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static struct xt_target log_tg_regs[] __read_mostly = { | ||
859 | { | ||
860 | .name = "LOG", | ||
861 | .family = NFPROTO_IPV4, | ||
862 | .target = log_tg, | ||
863 | .targetsize = sizeof(struct xt_log_info), | ||
864 | .checkentry = log_tg_check, | ||
865 | .me = THIS_MODULE, | ||
866 | }, | ||
867 | #if IS_ENABLED(CONFIG_IPV6) | ||
868 | { | ||
869 | .name = "LOG", | ||
870 | .family = NFPROTO_IPV6, | ||
871 | .target = log_tg, | ||
872 | .targetsize = sizeof(struct xt_log_info), | ||
873 | .checkentry = log_tg_check, | ||
874 | .me = THIS_MODULE, | ||
875 | }, | ||
876 | #endif | ||
877 | }; | ||
878 | |||
879 | static struct nf_logger ipt_log_logger __read_mostly = { | ||
880 | .name = "ipt_LOG", | ||
881 | .logfn = &ipt_log_packet, | ||
882 | .me = THIS_MODULE, | ||
883 | }; | ||
884 | |||
885 | #if IS_ENABLED(CONFIG_IPV6) | ||
886 | static struct nf_logger ip6t_log_logger __read_mostly = { | ||
887 | .name = "ip6t_LOG", | ||
888 | .logfn = &ip6t_log_packet, | ||
889 | .me = THIS_MODULE, | ||
890 | }; | ||
891 | #endif | ||
892 | |||
893 | static int __init log_tg_init(void) | ||
894 | { | ||
895 | int ret; | ||
896 | |||
897 | ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); | ||
898 | if (ret < 0) | ||
899 | return ret; | ||
900 | |||
901 | nf_log_register(NFPROTO_IPV4, &ipt_log_logger); | ||
902 | #if IS_ENABLED(CONFIG_IPV6) | ||
903 | nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); | ||
904 | #endif | ||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | static void __exit log_tg_exit(void) | ||
909 | { | ||
910 | nf_log_unregister(&ipt_log_logger); | ||
911 | #if IS_ENABLED(CONFIG_IPV6) | ||
912 | nf_log_unregister(&ip6t_log_logger); | ||
913 | #endif | ||
914 | xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); | ||
915 | } | ||
916 | |||
917 | module_init(log_tg_init); | ||
918 | module_exit(log_tg_exit); | ||
919 | |||
920 | MODULE_LICENSE("GPL"); | ||
921 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | ||
922 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); | ||
923 | MODULE_DESCRIPTION("Xtables: IPv4/IPv6 packet logging"); | ||
924 | MODULE_ALIAS("ipt_LOG"); | ||
925 | MODULE_ALIAS("ip6t_LOG"); | ||