aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/ia64/kernel/setup.c2
-rw-r--r--arch/ia64/pci/pci.c2
-rw-r--r--drivers/video/aty/atyfb_base.c2
-rw-r--r--include/linux/netfilter/nfnetlink_conntrack.h5
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h6
-rw-r--r--include/net/ip.h1
-rw-r--r--include/net/netfilter/nf_conntrack.h31
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h2
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h15
-rw-r--r--include/net/netfilter/nf_conntrack_protocol.h26
-rw-r--r--net/ipv4/ip_output.c30
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c5
-rw-r--r--net/ipv4/ipvs/ip_vs_est.c1
-rw-r--r--net/ipv4/ipvs/ip_vs_sched.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_amanda.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_irc.c10
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netbios_ns.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c36
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_icmp.c47
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c26
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c17
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c2
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c10
-rw-r--r--net/ipv4/netfilter/ipt_recent.c20
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c74
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c97
-rw-r--r--net/ipv6/netfilter/ip6_tables.c124
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c2
-rw-r--r--net/ipv6/netfilter/ip6t_dst.c4
-rw-r--r--net/ipv6/netfilter/ip6t_esp.c2
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c2
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c4
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c2
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c47
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c77
-rw-r--r--net/netfilter/Kconfig7
-rw-r--r--net/netfilter/Makefile3
-rw-r--r--net/netfilter/nf_conntrack_core.c239
-rw-r--r--net/netfilter/nf_conntrack_ftp.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c1653
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c71
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c10
-rw-r--r--net/netfilter/nf_conntrack_standalone.c42
-rw-r--r--net/netfilter/nfnetlink_queue.c79
45 files changed, 2495 insertions, 349 deletions
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 088e5dded8dc..c33305d8e5eb 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -518,7 +518,7 @@ show_cpuinfo (struct seq_file *m, void *v)
518 char family[32], features[128], *cp, sep; 518 char family[32], features[128], *cp, sep;
519 struct cpuinfo_ia64 *c = v; 519 struct cpuinfo_ia64 *c = v;
520 unsigned long mask; 520 unsigned long mask;
521 unsigned int proc_freq; 521 unsigned long proc_freq;
522 int i; 522 int i;
523 523
524 mask = c->features; 524 mask = c->features;
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 20d76fae24e8..30dbc98bf0b3 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -700,7 +700,7 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
700 */ 700 */
701int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size) 701int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size)
702{ 702{
703 int ret = 0; 703 int ret = size;
704 704
705 switch (size) { 705 switch (size) {
706 case 1: 706 case 1:
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 08edbfcfca58..3fefdb0cbf07 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -403,7 +403,7 @@ static struct {
403 { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL }, 403 { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL },
404 { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL }, 404 { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL },
405 { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL }, 405 { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL },
406 { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 230, 83, 63, ATI_CHIP_264XL }, 406 { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 235, 83, 63, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL },
407 { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL }, 407 { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL },
408 { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL }, 408 { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL },
409 409
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index 116fcaced909..668ec946c8e2 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -64,6 +64,9 @@ enum ctattr_l4proto {
64 CTA_PROTO_ICMP_ID, 64 CTA_PROTO_ICMP_ID,
65 CTA_PROTO_ICMP_TYPE, 65 CTA_PROTO_ICMP_TYPE,
66 CTA_PROTO_ICMP_CODE, 66 CTA_PROTO_ICMP_CODE,
67 CTA_PROTO_ICMPV6_ID,
68 CTA_PROTO_ICMPV6_TYPE,
69 CTA_PROTO_ICMPV6_CODE,
67 __CTA_PROTO_MAX 70 __CTA_PROTO_MAX
68}; 71};
69#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1) 72#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
@@ -128,6 +131,4 @@ enum ctattr_help {
128}; 131};
129#define CTA_HELP_MAX (__CTA_HELP_MAX - 1) 132#define CTA_HELP_MAX (__CTA_HELP_MAX - 1)
130 133
131#define CTA_HELP_MAXNAMESIZE 32
132
133#endif /* _IPCONNTRACK_NETLINK_H */ 134#endif /* _IPCONNTRACK_NETLINK_H */
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 2efc046d9e94..c163ba31aab7 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -474,7 +474,11 @@ extern unsigned int ip6t_do_table(struct sk_buff **pskb,
474extern int ip6t_ext_hdr(u8 nexthdr); 474extern int ip6t_ext_hdr(u8 nexthdr);
475/* find specified header and get offset to it */ 475/* find specified header and get offset to it */
476extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 476extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
477 u8 target); 477 int target, unsigned short *fragoff);
478
479extern int ip6_masked_addrcmp(const struct in6_addr *addr1,
480 const struct in6_addr *mask,
481 const struct in6_addr *addr2);
478 482
479#define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) 483#define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))
480 484
diff --git a/include/net/ip.h b/include/net/ip.h
index f7e7fd728b67..7bb5804847f2 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -317,7 +317,6 @@ enum ip_defrag_users
317 IP_DEFRAG_CALL_RA_CHAIN, 317 IP_DEFRAG_CALL_RA_CHAIN,
318 IP_DEFRAG_CONNTRACK_IN, 318 IP_DEFRAG_CONNTRACK_IN,
319 IP_DEFRAG_CONNTRACK_OUT, 319 IP_DEFRAG_CONNTRACK_OUT,
320 IP_DEFRAG_NAT_OUT,
321 IP_DEFRAG_VS_IN, 320 IP_DEFRAG_VS_IN,
322 IP_DEFRAG_VS_OUT, 321 IP_DEFRAG_VS_OUT,
323 IP_DEFRAG_VS_FWD 322 IP_DEFRAG_VS_FWD
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index cc4825610795..64b82b74a650 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -94,6 +94,9 @@ struct nf_conn
94 /* Current number of expected connections */ 94 /* Current number of expected connections */
95 unsigned int expecting; 95 unsigned int expecting;
96 96
97 /* Unique ID that identifies this conntrack*/
98 unsigned int id;
99
97 /* Helper. if any */ 100 /* Helper. if any */
98 struct nf_conntrack_helper *helper; 101 struct nf_conntrack_helper *helper;
99 102
@@ -140,6 +143,9 @@ struct nf_conntrack_expect
140 /* Usage count. */ 143 /* Usage count. */
141 atomic_t use; 144 atomic_t use;
142 145
146 /* Unique ID */
147 unsigned int id;
148
143 /* Flags */ 149 /* Flags */
144 unsigned int flags; 150 unsigned int flags;
145 151
@@ -190,6 +196,31 @@ static inline void nf_ct_put(struct nf_conn *ct)
190 nf_conntrack_put(&ct->ct_general); 196 nf_conntrack_put(&ct->ct_general);
191} 197}
192 198
199extern struct nf_conntrack_tuple_hash *
200__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
201 const struct nf_conn *ignored_conntrack);
202
203extern void nf_conntrack_hash_insert(struct nf_conn *ct);
204
205extern struct nf_conntrack_expect *
206__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
207
208extern struct nf_conntrack_expect *
209nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
210
211extern void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
212
213extern void nf_ct_remove_expectations(struct nf_conn *ct);
214
215extern void nf_conntrack_flush(void);
216
217extern struct nf_conntrack_helper *
218nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
219extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
220
221extern struct nf_conntrack_helper *
222__nf_conntrack_helper_find_byname(const char *name);
223
193/* call to create an explicit dependency on nf_conntrack. */ 224/* call to create an explicit dependency on nf_conntrack. */
194extern void need_nf_conntrack(void); 225extern void need_nf_conntrack(void);
195 226
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 5a66b2a3a623..86ec8174ad02 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -33,6 +33,8 @@ struct nf_conntrack_helper
33 unsigned int protoff, 33 unsigned int protoff,
34 struct nf_conn *ct, 34 struct nf_conn *ct,
35 enum ip_conntrack_info conntrackinfo); 35 enum ip_conntrack_info conntrackinfo);
36
37 int (*to_nfattr)(struct sk_buff *skb, const struct nf_conn *ct);
36}; 38};
37 39
38extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); 40extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 01663e5b33df..67856eb93b43 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -14,6 +14,8 @@
14#include <linux/seq_file.h> 14#include <linux/seq_file.h>
15#include <net/netfilter/nf_conntrack.h> 15#include <net/netfilter/nf_conntrack.h>
16 16
17struct nfattr;
18
17struct nf_conntrack_l3proto 19struct nf_conntrack_l3proto
18{ 20{
19 /* Next pointer. */ 21 /* Next pointer. */
@@ -70,6 +72,12 @@ struct nf_conntrack_l3proto
70 72
71 u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple); 73 u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple);
72 74
75 int (*tuple_to_nfattr)(struct sk_buff *skb,
76 const struct nf_conntrack_tuple *t);
77
78 int (*nfattr_to_tuple)(struct nfattr *tb[],
79 struct nf_conntrack_tuple *t);
80
73 /* Module (if any) which this is connected to. */ 81 /* Module (if any) which this is connected to. */
74 struct module *me; 82 struct module *me;
75}; 83};
@@ -81,11 +89,16 @@ extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
81extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); 89extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
82 90
83static inline struct nf_conntrack_l3proto * 91static inline struct nf_conntrack_l3proto *
84nf_ct_find_l3proto(u_int16_t l3proto) 92__nf_ct_l3proto_find(u_int16_t l3proto)
85{ 93{
86 return nf_ct_l3protos[l3proto]; 94 return nf_ct_l3protos[l3proto];
87} 95}
88 96
97extern struct nf_conntrack_l3proto *
98nf_ct_l3proto_find_get(u_int16_t l3proto);
99
100extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
101
89/* Existing built-in protocols */ 102/* Existing built-in protocols */
90extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; 103extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
91extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; 104extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
diff --git a/include/net/netfilter/nf_conntrack_protocol.h b/include/net/netfilter/nf_conntrack_protocol.h
index b3afda35397a..1f33737fcea5 100644
--- a/include/net/netfilter/nf_conntrack_protocol.h
+++ b/include/net/netfilter/nf_conntrack_protocol.h
@@ -12,6 +12,7 @@
12#include <net/netfilter/nf_conntrack.h> 12#include <net/netfilter/nf_conntrack.h>
13 13
14struct seq_file; 14struct seq_file;
15struct nfattr;
15 16
16struct nf_conntrack_protocol 17struct nf_conntrack_protocol
17{ 18{
@@ -66,6 +67,18 @@ struct nf_conntrack_protocol
66 enum ip_conntrack_info *ctinfo, 67 enum ip_conntrack_info *ctinfo,
67 int pf, unsigned int hooknum); 68 int pf, unsigned int hooknum);
68 69
70 /* convert protoinfo to nfnetink attributes */
71 int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa,
72 const struct nf_conn *ct);
73
74 /* convert nfnetlink attributes to protoinfo */
75 int (*from_nfattr)(struct nfattr *tb[], struct nf_conn *ct);
76
77 int (*tuple_to_nfattr)(struct sk_buff *skb,
78 const struct nf_conntrack_tuple *t);
79 int (*nfattr_to_tuple)(struct nfattr *tb[],
80 struct nf_conntrack_tuple *t);
81
69 /* Module (if any) which this is connected to. */ 82 /* Module (if any) which this is connected to. */
70 struct module *me; 83 struct module *me;
71}; 84};
@@ -80,12 +93,23 @@ extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
80extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; 93extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
81 94
82extern struct nf_conntrack_protocol * 95extern struct nf_conntrack_protocol *
83nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol); 96__nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol);
97
98extern struct nf_conntrack_protocol *
99nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol);
100
101extern void nf_ct_proto_put(struct nf_conntrack_protocol *p);
84 102
85/* Protocol registration. */ 103/* Protocol registration. */
86extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto); 104extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto);
87extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto); 105extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto);
88 106
107/* Generic netlink helpers */
108extern int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb,
109 const struct nf_conntrack_tuple *tuple);
110extern int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[],
111 struct nf_conntrack_tuple *t);
112
89/* Log invalid packets */ 113/* Log invalid packets */
90extern unsigned int nf_ct_log_invalid; 114extern unsigned int nf_ct_log_invalid;
91 115
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 2a830de3a699..71da31818cfc 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -202,13 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb)
202 202
203static inline int ip_finish_output(struct sk_buff *skb) 203static inline int ip_finish_output(struct sk_buff *skb)
204{ 204{
205 struct net_device *dev = skb->dst->dev; 205 if (skb->len > dst_mtu(skb->dst) &&
206 206 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
207 skb->dev = dev; 207 return ip_fragment(skb, ip_finish_output2);
208 skb->protocol = htons(ETH_P_IP); 208 else
209 209 return ip_finish_output2(skb);
210 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
211 ip_finish_output2);
212} 210}
213 211
214int ip_mc_output(struct sk_buff *skb) 212int ip_mc_output(struct sk_buff *skb)
@@ -265,21 +263,21 @@ int ip_mc_output(struct sk_buff *skb)
265 newskb->dev, ip_dev_loopback_xmit); 263 newskb->dev, ip_dev_loopback_xmit);
266 } 264 }
267 265
268 if (skb->len > dst_mtu(&rt->u.dst)) 266 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev,
269 return ip_fragment(skb, ip_finish_output); 267 ip_finish_output);
270 else
271 return ip_finish_output(skb);
272} 268}
273 269
274int ip_output(struct sk_buff *skb) 270int ip_output(struct sk_buff *skb)
275{ 271{
272 struct net_device *dev = skb->dst->dev;
273
276 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); 274 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
277 275
278 if (skb->len > dst_mtu(skb->dst) && 276 skb->dev = dev;
279 !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) 277 skb->protocol = htons(ETH_P_IP);
280 return ip_fragment(skb, ip_finish_output); 278
281 else 279 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
282 return ip_finish_output(skb); 280 ip_finish_output);
283} 281}
284 282
285int ip_queue_xmit(struct sk_buff *skb, int ipfragok) 283int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 1aca94a9fd8b..3f47ad8e1cad 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -532,11 +532,8 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum,
532{ 532{
533 if (!((*pskb)->ipvs_property)) 533 if (!((*pskb)->ipvs_property))
534 return NF_ACCEPT; 534 return NF_ACCEPT;
535
536 /* The packet was sent from IPVS, exit this chain */ 535 /* The packet was sent from IPVS, exit this chain */
537 (*okfn)(*pskb); 536 return NF_STOP;
538
539 return NF_STOLEN;
540} 537}
541 538
542u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) 539u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
index e7004741ac73..c453e1e57f4b 100644
--- a/net/ipv4/ipvs/ip_vs_est.c
+++ b/net/ipv4/ipvs/ip_vs_est.c
@@ -18,6 +18,7 @@
18#include <linux/jiffies.h> 18#include <linux/jiffies.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/types.h> 20#include <linux/types.h>
21#include <linux/interrupt.h>
21 22
22#include <net/ip_vs.h> 23#include <net/ip_vs.h>
23 24
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c
index 0f7c56a225bd..8bc42b76223d 100644
--- a/net/ipv4/ipvs/ip_vs_sched.c
+++ b/net/ipv4/ipvs/ip_vs_sched.c
@@ -22,6 +22,7 @@
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/sched.h> 23#include <linux/sched.h>
24#include <linux/spinlock.h> 24#include <linux/spinlock.h>
25#include <linux/interrupt.h>
25#include <asm/string.h> 26#include <asm/string.h>
26#include <linux/kmod.h> 27#include <linux/kmod.h>
27 28
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
index 0366eedb4d70..84e4f79b7ffa 100644
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -36,7 +36,7 @@ static unsigned int master_timeout = 300;
36MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); 36MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
37MODULE_DESCRIPTION("Amanda connection tracking module"); 37MODULE_DESCRIPTION("Amanda connection tracking module");
38MODULE_LICENSE("GPL"); 38MODULE_LICENSE("GPL");
39module_param(master_timeout, int, 0600); 39module_param(master_timeout, uint, 0600);
40MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); 40MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
41 41
42static const char *conns[] = { "DATA ", "MESG ", "INDEX " }; 42static const char *conns[] = { "DATA ", "MESG ", "INDEX " };
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 68b173bcda60..e627e5856172 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -34,7 +34,7 @@ static int ports_c;
34module_param_array(ports, ushort, &ports_c, 0400); 34module_param_array(ports, ushort, &ports_c, 0400);
35 35
36static int loose; 36static int loose;
37module_param(loose, int, 0600); 37module_param(loose, bool, 0600);
38 38
39unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, 39unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
40 enum ip_conntrack_info ctinfo, 40 enum ip_conntrack_info ctinfo,
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index d7c40421d0d1..c51a2cf71b4b 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -36,7 +36,7 @@
36#define MAX_PORTS 8 36#define MAX_PORTS 8
37static unsigned short ports[MAX_PORTS]; 37static unsigned short ports[MAX_PORTS];
38static int ports_c; 38static int ports_c;
39static int max_dcc_channels = 8; 39static unsigned int max_dcc_channels = 8;
40static unsigned int dcc_timeout = 300; 40static unsigned int dcc_timeout = 300;
41/* This is slow, but it's simple. --RR */ 41/* This is slow, but it's simple. --RR */
42static char *irc_buffer; 42static char *irc_buffer;
@@ -54,9 +54,9 @@ MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
54MODULE_LICENSE("GPL"); 54MODULE_LICENSE("GPL");
55module_param_array(ports, ushort, &ports_c, 0400); 55module_param_array(ports, ushort, &ports_c, 0400);
56MODULE_PARM_DESC(ports, "port numbers of IRC servers"); 56MODULE_PARM_DESC(ports, "port numbers of IRC servers");
57module_param(max_dcc_channels, int, 0400); 57module_param(max_dcc_channels, uint, 0400);
58MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session"); 58MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
59module_param(dcc_timeout, int, 0400); 59module_param(dcc_timeout, uint, 0400);
60MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); 60MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
61 61
62static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; 62static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
@@ -254,10 +254,6 @@ static int __init init(void)
254 printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n"); 254 printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
255 return -EBUSY; 255 return -EBUSY;
256 } 256 }
257 if (dcc_timeout < 0) {
258 printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
259 return -EBUSY;
260 }
261 257
262 irc_buffer = kmalloc(65536, GFP_KERNEL); 258 irc_buffer = kmalloc(65536, GFP_KERNEL);
263 if (!irc_buffer) 259 if (!irc_buffer)
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
index 186646eb249f..4e68e16a2612 100644
--- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
@@ -37,7 +37,7 @@ MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
37MODULE_LICENSE("GPL"); 37MODULE_LICENSE("GPL");
38 38
39static unsigned int timeout = 3; 39static unsigned int timeout = 3;
40module_param(timeout, int, 0600); 40module_param(timeout, uint, 0400);
41MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); 41MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
42 42
43static int help(struct sk_buff **pskb, 43static int help(struct sk_buff **pskb,
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 91fe8f2e38ff..c9ebbe0d2d9c 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -79,6 +79,7 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
79 const struct ip_conntrack_tuple *tuple) 79 const struct ip_conntrack_tuple *tuple)
80{ 80{
81 struct nfattr *nest_parms; 81 struct nfattr *nest_parms;
82 int ret;
82 83
83 nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); 84 nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
84 NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); 85 NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
@@ -86,10 +87,10 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
86 NFA_NEST_END(skb, nest_parms); 87 NFA_NEST_END(skb, nest_parms);
87 88
88 nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); 89 nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
89 ctnetlink_dump_tuples_proto(skb, tuple); 90 ret = ctnetlink_dump_tuples_proto(skb, tuple);
90 NFA_NEST_END(skb, nest_parms); 91 NFA_NEST_END(skb, nest_parms);
91 92
92 return 0; 93 return ret;
93 94
94nfattr_failure: 95nfattr_failure:
95 return -1; 96 return -1;
@@ -160,7 +161,7 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
160 return 0; 161 return 0;
161 162
162 nest_helper = NFA_NEST(skb, CTA_HELP); 163 nest_helper = NFA_NEST(skb, CTA_HELP);
163 NFA_PUT(skb, CTA_HELP_NAME, CTA_HELP_MAXNAMESIZE, &ct->helper->name); 164 NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name);
164 165
165 if (ct->helper->to_nfattr) 166 if (ct->helper->to_nfattr)
166 ct->helper->to_nfattr(skb, ct); 167 ct->helper->to_nfattr(skb, ct);
@@ -229,7 +230,7 @@ nfattr_failure:
229static inline int 230static inline int
230ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) 231ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
231{ 232{
232 unsigned int use = htonl(atomic_read(&ct->ct_general.use)); 233 u_int32_t use = htonl(atomic_read(&ct->ct_general.use));
233 234
234 NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); 235 NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
235 return 0; 236 return 0;
@@ -311,29 +312,22 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
311 if (events & IPCT_DESTROY) { 312 if (events & IPCT_DESTROY) {
312 type = IPCTNL_MSG_CT_DELETE; 313 type = IPCTNL_MSG_CT_DELETE;
313 group = NFNLGRP_CONNTRACK_DESTROY; 314 group = NFNLGRP_CONNTRACK_DESTROY;
314 goto alloc_skb; 315 } else if (events & (IPCT_NEW | IPCT_RELATED)) {
315 }
316 if (events & (IPCT_NEW | IPCT_RELATED)) {
317 type = IPCTNL_MSG_CT_NEW; 316 type = IPCTNL_MSG_CT_NEW;
318 flags = NLM_F_CREATE|NLM_F_EXCL; 317 flags = NLM_F_CREATE|NLM_F_EXCL;
319 /* dump everything */ 318 /* dump everything */
320 events = ~0UL; 319 events = ~0UL;
321 group = NFNLGRP_CONNTRACK_NEW; 320 group = NFNLGRP_CONNTRACK_NEW;
322 goto alloc_skb; 321 } else if (events & (IPCT_STATUS |
323 }
324 if (events & (IPCT_STATUS |
325 IPCT_PROTOINFO | 322 IPCT_PROTOINFO |
326 IPCT_HELPER | 323 IPCT_HELPER |
327 IPCT_HELPINFO | 324 IPCT_HELPINFO |
328 IPCT_NATINFO)) { 325 IPCT_NATINFO)) {
329 type = IPCTNL_MSG_CT_NEW; 326 type = IPCTNL_MSG_CT_NEW;
330 group = NFNLGRP_CONNTRACK_UPDATE; 327 group = NFNLGRP_CONNTRACK_UPDATE;
331 goto alloc_skb; 328 } else
332 } 329 return NOTIFY_DONE;
333 330
334 return NOTIFY_DONE;
335
336alloc_skb:
337 /* FIXME: Check if there are any listeners before, don't hurt performance */ 331 /* FIXME: Check if there are any listeners before, don't hurt performance */
338 332
339 skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 333 skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
@@ -1037,6 +1031,11 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
1037 return err; 1031 return err;
1038 } 1032 }
1039 1033
1034#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1035 if (cda[CTA_MARK-1])
1036 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1037#endif
1038
1040 ct->helper = ip_conntrack_helper_find_get(rtuple); 1039 ct->helper = ip_conntrack_helper_find_get(rtuple);
1041 1040
1042 add_timer(&ct->timeout); 1041 add_timer(&ct->timeout);
@@ -1045,11 +1044,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
1045 if (ct->helper) 1044 if (ct->helper)
1046 ip_conntrack_helper_put(ct->helper); 1045 ip_conntrack_helper_put(ct->helper);
1047 1046
1048#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1049 if (cda[CTA_MARK-1])
1050 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1051#endif
1052
1053 DEBUGP("conntrack with id %u inserted\n", ct->id); 1047 DEBUGP("conntrack with id %u inserted\n", ct->id);
1054 return 0; 1048 return 0;
1055 1049
@@ -1209,7 +1203,6 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1209 unsigned int type; 1203 unsigned int type;
1210 unsigned char *b; 1204 unsigned char *b;
1211 int flags = 0; 1205 int flags = 0;
1212 u16 proto;
1213 1206
1214 if (events & IPEXP_NEW) { 1207 if (events & IPEXP_NEW) {
1215 type = IPCTNL_MSG_EXP_NEW; 1208 type = IPCTNL_MSG_EXP_NEW;
@@ -1236,7 +1229,6 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1236 goto nfattr_failure; 1229 goto nfattr_failure;
1237 1230
1238 nlh->nlmsg_len = skb->tail - b; 1231 nlh->nlmsg_len = skb->tail - b;
1239 proto = exp->tuple.dst.protonum;
1240 nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); 1232 nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
1241 return NOTIFY_DONE; 1233 return NOTIFY_DONE;
1242 1234
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index 5f9925db608e..30fc21d6165a 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -47,20 +47,21 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb,
47 return 1; 47 return 1;
48} 48}
49 49
50/* Add 1; spaces filled with 0. */
51static const u_int8_t invmap[] = {
52 [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
53 [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
54 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
55 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
56 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
57 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
58 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
59 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1
60};
61
50static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple, 62static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple,
51 const struct ip_conntrack_tuple *orig) 63 const struct ip_conntrack_tuple *orig)
52{ 64{
53 /* Add 1; spaces filled with 0. */
54 static const u_int8_t invmap[]
55 = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
56 [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
57 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
58 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
59 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
60 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
61 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
62 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
63
64 if (orig->dst.u.icmp.type >= sizeof(invmap) 65 if (orig->dst.u.icmp.type >= sizeof(invmap)
65 || !invmap[orig->dst.u.icmp.type]) 66 || !invmap[orig->dst.u.icmp.type])
66 return 0; 67 return 0;
@@ -110,17 +111,17 @@ static int icmp_packet(struct ip_conntrack *ct,
110 return NF_ACCEPT; 111 return NF_ACCEPT;
111} 112}
112 113
113static const u_int8_t valid_new[] = {
114 [ICMP_ECHO] = 1,
115 [ICMP_TIMESTAMP] = 1,
116 [ICMP_INFO_REQUEST] = 1,
117 [ICMP_ADDRESS] = 1
118};
119
120/* Called when a new connection for this protocol found. */ 114/* Called when a new connection for this protocol found. */
121static int icmp_new(struct ip_conntrack *conntrack, 115static int icmp_new(struct ip_conntrack *conntrack,
122 const struct sk_buff *skb) 116 const struct sk_buff *skb)
123{ 117{
118 static const u_int8_t valid_new[] = {
119 [ICMP_ECHO] = 1,
120 [ICMP_TIMESTAMP] = 1,
121 [ICMP_INFO_REQUEST] = 1,
122 [ICMP_ADDRESS] = 1
123 };
124
124 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) 125 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
125 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { 126 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
126 /* Can't create a new ICMP `conn' with this. */ 127 /* Can't create a new ICMP `conn' with this. */
@@ -279,10 +280,6 @@ static int icmp_tuple_to_nfattr(struct sk_buff *skb,
279 NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), 280 NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t),
280 &t->dst.u.icmp.code); 281 &t->dst.u.icmp.code);
281 282
282 if (t->dst.u.icmp.type >= sizeof(valid_new)
283 || !valid_new[t->dst.u.icmp.type])
284 return -EINVAL;
285
286 return 0; 283 return 0;
287 284
288nfattr_failure: 285nfattr_failure:
@@ -295,7 +292,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[],
295 if (!tb[CTA_PROTO_ICMP_TYPE-1] 292 if (!tb[CTA_PROTO_ICMP_TYPE-1]
296 || !tb[CTA_PROTO_ICMP_CODE-1] 293 || !tb[CTA_PROTO_ICMP_CODE-1]
297 || !tb[CTA_PROTO_ICMP_ID-1]) 294 || !tb[CTA_PROTO_ICMP_ID-1])
298 return -1; 295 return -EINVAL;
299 296
300 tuple->dst.u.icmp.type = 297 tuple->dst.u.icmp.type =
301 *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); 298 *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
@@ -304,6 +301,10 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[],
304 tuple->src.u.icmp.id = 301 tuple->src.u.icmp.id =
305 *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); 302 *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
306 303
304 if (tuple->dst.u.icmp.type >= sizeof(invmap)
305 || !invmap[tuple->dst.u.icmp.type])
306 return -EINVAL;
307
307 return 0; 308 return 0;
308} 309}
309#endif 310#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index a88bcc551244..7ba97783e741 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -451,30 +451,6 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum,
451 return NF_ACCEPT; 451 return NF_ACCEPT;
452} 452}
453 453
454static unsigned int ip_refrag(unsigned int hooknum,
455 struct sk_buff **pskb,
456 const struct net_device *in,
457 const struct net_device *out,
458 int (*okfn)(struct sk_buff *))
459{
460 struct rtable *rt = (struct rtable *)(*pskb)->dst;
461
462 /* We've seen it coming out the other side: confirm */
463 if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
464 return NF_DROP;
465
466 /* Local packets are never produced too large for their
467 interface. We degfragment them at LOCAL_OUT, however,
468 so we have to refragment them here. */
469 if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
470 !skb_shinfo(*pskb)->tso_size) {
471 /* No hook can be after us, so this should be OK. */
472 ip_fragment(*pskb, okfn);
473 return NF_STOLEN;
474 }
475 return NF_ACCEPT;
476}
477
478static unsigned int ip_conntrack_local(unsigned int hooknum, 454static unsigned int ip_conntrack_local(unsigned int hooknum,
479 struct sk_buff **pskb, 455 struct sk_buff **pskb,
480 const struct net_device *in, 456 const struct net_device *in,
@@ -544,7 +520,7 @@ static struct nf_hook_ops ip_conntrack_helper_in_ops = {
544 520
545/* Refragmenter; last chance. */ 521/* Refragmenter; last chance. */
546static struct nf_hook_ops ip_conntrack_out_ops = { 522static struct nf_hook_ops ip_conntrack_out_ops = {
547 .hook = ip_refrag, 523 .hook = ip_confirm,
548 .owner = THIS_MODULE, 524 .owner = THIS_MODULE,
549 .pf = PF_INET, 525 .pf = PF_INET,
550 .hooknum = NF_IP_POST_ROUTING, 526 .hooknum = NF_IP_POST_ROUTING,
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 30cd4e18c129..f04111f74e09 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -190,23 +190,6 @@ ip_nat_out(unsigned int hooknum,
190 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 190 || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
191 return NF_ACCEPT; 191 return NF_ACCEPT;
192 192
193 /* We can hit fragment here; forwarded packets get
194 defragmented by connection tracking coming in, then
195 fragmented (grr) by the forward code.
196
197 In future: If we have nfct != NULL, AND we have NAT
198 initialized, AND there is no helper, then we can do full
199 NAPT on the head, and IP-address-only NAT on the rest.
200
201 I'm starting to have nightmares about fragments. */
202
203 if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
204 *pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT);
205
206 if (!*pskb)
207 return NF_STOLEN;
208 }
209
210 return ip_nat_fn(hooknum, pskb, in, out, okfn); 193 return ip_nat_fn(hooknum, pskb, in, out, okfn);
211} 194}
212 195
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f057025a719e..6693526ae128 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -203,7 +203,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
203 sizeof(struct tcphdr), 0)); 203 sizeof(struct tcphdr), 0));
204 204
205 /* Adjust IP TTL, DF */ 205 /* Adjust IP TTL, DF */
206 nskb->nh.iph->ttl = MAXTTL; 206 nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
207 /* Set DF, id = 0 */ 207 /* Set DF, id = 0 */
208 nskb->nh.iph->frag_off = htons(IP_DF); 208 nskb->nh.iph->frag_off = htons(IP_DF);
209 nskb->nh.iph->id = 0; 209 nskb->nh.iph->id = 0;
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 2883ccd8a91d..38641cd06123 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -77,15 +77,15 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
77#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0) 77#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0)
78 78
79static unsigned int nlbufsiz = 4096; 79static unsigned int nlbufsiz = 4096;
80module_param(nlbufsiz, uint, 0600); /* FIXME: Check size < 128k --RR */ 80module_param(nlbufsiz, uint, 0400);
81MODULE_PARM_DESC(nlbufsiz, "netlink buffer size"); 81MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
82 82
83static unsigned int flushtimeout = 10; 83static unsigned int flushtimeout = 10;
84module_param(flushtimeout, int, 0600); 84module_param(flushtimeout, uint, 0600);
85MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)"); 85MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)");
86 86
87static unsigned int nflog = 1; 87static int nflog = 1;
88module_param(nflog, int, 0400); 88module_param(nflog, bool, 0400);
89MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); 89MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
90 90
91/* global data structures */ 91/* global data structures */
@@ -376,7 +376,7 @@ static int __init init(void)
376 376
377 DEBUGP("ipt_ULOG: init module\n"); 377 DEBUGP("ipt_ULOG: init module\n");
378 378
379 if (nlbufsiz >= 128*1024) { 379 if (nlbufsiz > 128*1024) {
380 printk("Netlink buffer has to be <= 128kB\n"); 380 printk("Netlink buffer has to be <= 128kB\n");
381 return -EINVAL; 381 return -EINVAL;
382 } 382 }
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 261cbb4d4c49..5ddccb18c65e 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -24,10 +24,10 @@
24#define HASH_LOG 9 24#define HASH_LOG 9
25 25
26/* Defaults, these can be overridden on the module command-line. */ 26/* Defaults, these can be overridden on the module command-line. */
27static int ip_list_tot = 100; 27static unsigned int ip_list_tot = 100;
28static int ip_pkt_list_tot = 20; 28static unsigned int ip_pkt_list_tot = 20;
29static int ip_list_hash_size = 0; 29static unsigned int ip_list_hash_size = 0;
30static int ip_list_perms = 0644; 30static unsigned int ip_list_perms = 0644;
31#ifdef DEBUG 31#ifdef DEBUG
32static int debug = 1; 32static int debug = 1;
33#endif 33#endif
@@ -38,13 +38,13 @@ KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. htt
38MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>"); 38MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>");
39MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER); 39MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER);
40MODULE_LICENSE("GPL"); 40MODULE_LICENSE("GPL");
41module_param(ip_list_tot, int, 0400); 41module_param(ip_list_tot, uint, 0400);
42module_param(ip_pkt_list_tot, int, 0400); 42module_param(ip_pkt_list_tot, uint, 0400);
43module_param(ip_list_hash_size, int, 0400); 43module_param(ip_list_hash_size, uint, 0400);
44module_param(ip_list_perms, int, 0400); 44module_param(ip_list_perms, uint, 0400);
45#ifdef DEBUG 45#ifdef DEBUG
46module_param(debug, int, 0600); 46module_param(debug, bool, 0600);
47MODULE_PARM_DESC(debug,"debugging level, defaults to 1"); 47MODULE_PARM_DESC(debug,"enable debugging output");
48#endif 48#endif
49MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list"); 49MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list");
50MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember"); 50MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember");
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 8202c1c0afad..9bdbb7793971 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -22,6 +22,7 @@
22#include <linux/skbuff.h> 22#include <linux/skbuff.h>
23#include <linux/icmp.h> 23#include <linux/icmp.h>
24#include <linux/sysctl.h> 24#include <linux/sysctl.h>
25#include <net/route.h>
25#include <net/ip.h> 26#include <net/ip.h>
26 27
27#include <linux/netfilter_ipv4.h> 28#include <linux/netfilter_ipv4.h>
@@ -180,30 +181,6 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
180 return NF_ACCEPT; 181 return NF_ACCEPT;
181} 182}
182 183
183static unsigned int ipv4_refrag(unsigned int hooknum,
184 struct sk_buff **pskb,
185 const struct net_device *in,
186 const struct net_device *out,
187 int (*okfn)(struct sk_buff *))
188{
189 struct rtable *rt = (struct rtable *)(*pskb)->dst;
190
191 /* We've seen it coming out the other side: confirm */
192 if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
193 return NF_DROP;
194
195 /* Local packets are never produced too large for their
196 interface. We degfragment them at LOCAL_OUT, however,
197 so we have to refragment them here. */
198 if ((*pskb)->len > dst_mtu(&rt->u.dst) &&
199 !skb_shinfo(*pskb)->tso_size) {
200 /* No hook can be after us, so this should be OK. */
201 ip_fragment(*pskb, okfn);
202 return NF_STOLEN;
203 }
204 return NF_ACCEPT;
205}
206
207static unsigned int ipv4_conntrack_in(unsigned int hooknum, 184static unsigned int ipv4_conntrack_in(unsigned int hooknum,
208 struct sk_buff **pskb, 185 struct sk_buff **pskb,
209 const struct net_device *in, 186 const struct net_device *in,
@@ -283,7 +260,7 @@ static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
283 260
284/* Refragmenter; last chance. */ 261/* Refragmenter; last chance. */
285static struct nf_hook_ops ipv4_conntrack_out_ops = { 262static struct nf_hook_ops ipv4_conntrack_out_ops = {
286 .hook = ipv4_refrag, 263 .hook = ipv4_confirm,
287 .owner = THIS_MODULE, 264 .owner = THIS_MODULE,
288 .pf = PF_INET, 265 .pf = PF_INET,
289 .hooknum = NF_IP_POST_ROUTING, 266 .hooknum = NF_IP_POST_ROUTING,
@@ -392,6 +369,48 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
392 return -ENOENT; 369 return -ENOENT;
393} 370}
394 371
372#if defined(CONFIG_NF_CT_NETLINK) || \
373 defined(CONFIG_NF_CT_NETLINK_MODULE)
374
375#include <linux/netfilter/nfnetlink.h>
376#include <linux/netfilter/nfnetlink_conntrack.h>
377
378static int ipv4_tuple_to_nfattr(struct sk_buff *skb,
379 const struct nf_conntrack_tuple *tuple)
380{
381 NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t),
382 &tuple->src.u3.ip);
383 NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t),
384 &tuple->dst.u3.ip);
385 return 0;
386
387nfattr_failure:
388 return -1;
389}
390
391static const size_t cta_min_ip[CTA_IP_MAX] = {
392 [CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
393 [CTA_IP_V4_DST-1] = sizeof(u_int32_t),
394};
395
396static int ipv4_nfattr_to_tuple(struct nfattr *tb[],
397 struct nf_conntrack_tuple *t)
398{
399 if (!tb[CTA_IP_V4_SRC-1] || !tb[CTA_IP_V4_DST-1])
400 return -EINVAL;
401
402 if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
403 return -EINVAL;
404
405 t->src.u3.ip =
406 *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
407 t->dst.u3.ip =
408 *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
409
410 return 0;
411}
412#endif
413
395static struct nf_sockopt_ops so_getorigdst = { 414static struct nf_sockopt_ops so_getorigdst = {
396 .pf = PF_INET, 415 .pf = PF_INET,
397 .get_optmin = SO_ORIGINAL_DST, 416 .get_optmin = SO_ORIGINAL_DST,
@@ -408,6 +427,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
408 .print_conntrack = ipv4_print_conntrack, 427 .print_conntrack = ipv4_print_conntrack,
409 .prepare = ipv4_prepare, 428 .prepare = ipv4_prepare,
410 .get_features = ipv4_get_features, 429 .get_features = ipv4_get_features,
430#if defined(CONFIG_NF_CT_NETLINK) || \
431 defined(CONFIG_NF_CT_NETLINK_MODULE)
432 .tuple_to_nfattr = ipv4_tuple_to_nfattr,
433 .nfattr_to_tuple = ipv4_nfattr_to_tuple,
434#endif
411 .me = THIS_MODULE, 435 .me = THIS_MODULE,
412}; 436};
413 437
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 7ddb5c08f7b8..52dc175be39a 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -50,20 +50,21 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb,
50 return 1; 50 return 1;
51} 51}
52 52
53/* Add 1; spaces filled with 0. */
54static const u_int8_t invmap[] = {
55 [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
56 [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
57 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
58 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
59 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
60 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
61 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
62 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1
63};
64
53static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple, 65static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
54 const struct nf_conntrack_tuple *orig) 66 const struct nf_conntrack_tuple *orig)
55{ 67{
56 /* Add 1; spaces filled with 0. */
57 static u_int8_t invmap[]
58 = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
59 [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
60 [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
61 [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
62 [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
63 [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
64 [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
65 [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
66
67 if (orig->dst.u.icmp.type >= sizeof(invmap) 68 if (orig->dst.u.icmp.type >= sizeof(invmap)
68 || !invmap[orig->dst.u.icmp.type]) 69 || !invmap[orig->dst.u.icmp.type])
69 return 0; 70 return 0;
@@ -120,11 +121,12 @@ static int icmp_packet(struct nf_conn *ct,
120static int icmp_new(struct nf_conn *conntrack, 121static int icmp_new(struct nf_conn *conntrack,
121 const struct sk_buff *skb, unsigned int dataoff) 122 const struct sk_buff *skb, unsigned int dataoff)
122{ 123{
123 static u_int8_t valid_new[] 124 static const u_int8_t valid_new[] = {
124 = { [ICMP_ECHO] = 1, 125 [ICMP_ECHO] = 1,
125 [ICMP_TIMESTAMP] = 1, 126 [ICMP_TIMESTAMP] = 1,
126 [ICMP_INFO_REQUEST] = 1, 127 [ICMP_INFO_REQUEST] = 1,
127 [ICMP_ADDRESS] = 1 }; 128 [ICMP_ADDRESS] = 1
129 };
128 130
129 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) 131 if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
130 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { 132 || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
@@ -168,7 +170,7 @@ icmp_error_message(struct sk_buff *skb,
168 return -NF_ACCEPT; 170 return -NF_ACCEPT;
169 } 171 }
170 172
171 innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol); 173 innerproto = __nf_ct_proto_find(PF_INET, inside->ip.protocol);
172 dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); 174 dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
173 /* Are they talking about one of our connections? */ 175 /* Are they talking about one of our connections? */
174 if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, 176 if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
@@ -281,6 +283,60 @@ checksum_skipped:
281 return icmp_error_message(skb, ctinfo, hooknum); 283 return icmp_error_message(skb, ctinfo, hooknum);
282} 284}
283 285
286#if defined(CONFIG_NF_CT_NETLINK) || \
287 defined(CONFIG_NF_CT_NETLINK_MODULE)
288
289#include <linux/netfilter/nfnetlink.h>
290#include <linux/netfilter/nfnetlink_conntrack.h>
291
292static int icmp_tuple_to_nfattr(struct sk_buff *skb,
293 const struct nf_conntrack_tuple *t)
294{
295 NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t),
296 &t->src.u.icmp.id);
297 NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
298 &t->dst.u.icmp.type);
299 NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t),
300 &t->dst.u.icmp.code);
301
302 return 0;
303
304nfattr_failure:
305 return -1;
306}
307
308static const size_t cta_min_proto[CTA_PROTO_MAX] = {
309 [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
310 [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t),
311 [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t)
312};
313
314static int icmp_nfattr_to_tuple(struct nfattr *tb[],
315 struct nf_conntrack_tuple *tuple)
316{
317 if (!tb[CTA_PROTO_ICMP_TYPE-1]
318 || !tb[CTA_PROTO_ICMP_CODE-1]
319 || !tb[CTA_PROTO_ICMP_ID-1])
320 return -EINVAL;
321
322 if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
323 return -EINVAL;
324
325 tuple->dst.u.icmp.type =
326 *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
327 tuple->dst.u.icmp.code =
328 *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
329 tuple->src.u.icmp.id =
330 *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
331
332 if (tuple->dst.u.icmp.type >= sizeof(invmap)
333 || !invmap[tuple->dst.u.icmp.type])
334 return -EINVAL;
335
336 return 0;
337}
338#endif
339
284struct nf_conntrack_protocol nf_conntrack_protocol_icmp = 340struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
285{ 341{
286 .list = { NULL, NULL }, 342 .list = { NULL, NULL },
@@ -295,7 +351,12 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
295 .new = icmp_new, 351 .new = icmp_new,
296 .error = icmp_error, 352 .error = icmp_error,
297 .destroy = NULL, 353 .destroy = NULL,
298 .me = NULL 354 .me = NULL,
355#if defined(CONFIG_NF_CT_NETLINK) || \
356 defined(CONFIG_NF_CT_NETLINK_MODULE)
357 .tuple_to_nfattr = icmp_tuple_to_nfattr,
358 .nfattr_to_tuple = icmp_nfattr_to_tuple,
359#endif
299}; 360};
300 361
301EXPORT_SYMBOL(nf_conntrack_protocol_icmp); 362EXPORT_SYMBOL(nf_conntrack_protocol_icmp);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index ea43ef1d94a7..925b42d48347 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -119,13 +119,14 @@ static LIST_HEAD(ip6t_tables);
119#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) 119#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
120#endif 120#endif
121 121
122static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask, 122int
123 struct in6_addr addr2) 123ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask,
124 const struct in6_addr *addr2)
124{ 125{
125 int i; 126 int i;
126 for( i = 0; i < 16; i++){ 127 for( i = 0; i < 16; i++){
127 if((addr1.s6_addr[i] & mask.s6_addr[i]) != 128 if((addr1->s6_addr[i] & mask->s6_addr[i]) !=
128 (addr2.s6_addr[i] & mask.s6_addr[i])) 129 (addr2->s6_addr[i] & mask->s6_addr[i]))
129 return 1; 130 return 1;
130 } 131 }
131 return 0; 132 return 0;
@@ -159,10 +160,10 @@ ip6_packet_match(const struct sk_buff *skb,
159 160
160#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) 161#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
161 162
162 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src), 163 if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk,
163 IP6T_INV_SRCIP) 164 &ip6info->src), IP6T_INV_SRCIP)
164 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst), 165 || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk,
165 IP6T_INV_DSTIP)) { 166 &ip6info->dst), IP6T_INV_DSTIP)) {
166 dprintf("Source or dest mismatch.\n"); 167 dprintf("Source or dest mismatch.\n");
167/* 168/*
168 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, 169 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
@@ -205,69 +206,21 @@ ip6_packet_match(const struct sk_buff *skb,
205 206
206 /* look for the desired protocol header */ 207 /* look for the desired protocol header */
207 if((ip6info->flags & IP6T_F_PROTO)) { 208 if((ip6info->flags & IP6T_F_PROTO)) {
208 u_int8_t currenthdr = ipv6->nexthdr; 209 int protohdr;
209 struct ipv6_opt_hdr _hdr, *hp; 210 unsigned short _frag_off;
210 u_int16_t ptr; /* Header offset in skb */
211 u_int16_t hdrlen; /* Header */
212 u_int16_t _fragoff = 0, *fp = NULL;
213
214 ptr = IPV6_HDR_LEN;
215
216 while (ip6t_ext_hdr(currenthdr)) {
217 /* Is there enough space for the next ext header? */
218 if (skb->len - ptr < IPV6_OPTHDR_LEN)
219 return 0;
220
221 /* NONE or ESP: there isn't protocol part */
222 /* If we want to count these packets in '-p all',
223 * we will change the return 0 to 1*/
224 if ((currenthdr == IPPROTO_NONE) ||
225 (currenthdr == IPPROTO_ESP))
226 break;
227 211
228 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); 212 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
229 BUG_ON(hp == NULL); 213 if (protohdr < 0)
230 214 return 0;
231 /* Size calculation */
232 if (currenthdr == IPPROTO_FRAGMENT) {
233 fp = skb_header_pointer(skb,
234 ptr+offsetof(struct frag_hdr,
235 frag_off),
236 sizeof(_fragoff),
237 &_fragoff);
238 if (fp == NULL)
239 return 0;
240
241 _fragoff = ntohs(*fp) & ~0x7;
242 hdrlen = 8;
243 } else if (currenthdr == IPPROTO_AH)
244 hdrlen = (hp->hdrlen+2)<<2;
245 else
246 hdrlen = ipv6_optlen(hp);
247
248 currenthdr = hp->nexthdr;
249 ptr += hdrlen;
250 /* ptr is too large */
251 if ( ptr > skb->len )
252 return 0;
253 if (_fragoff) {
254 if (ip6t_ext_hdr(currenthdr))
255 return 0;
256 break;
257 }
258 }
259
260 *protoff = ptr;
261 *fragoff = _fragoff;
262 215
263 /* currenthdr contains the protocol header */ 216 *fragoff = _frag_off;
264 217
265 dprintf("Packet protocol %hi ?= %s%hi.\n", 218 dprintf("Packet protocol %hi ?= %s%hi.\n",
266 currenthdr, 219 protohdr,
267 ip6info->invflags & IP6T_INV_PROTO ? "!":"", 220 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
268 ip6info->proto); 221 ip6info->proto);
269 222
270 if (ip6info->proto == currenthdr) { 223 if (ip6info->proto == protohdr) {
271 if(ip6info->invflags & IP6T_INV_PROTO) { 224 if(ip6info->invflags & IP6T_INV_PROTO) {
272 return 0; 225 return 0;
273 } 226 }
@@ -2098,26 +2051,39 @@ static void __exit fini(void)
2098} 2051}
2099 2052
2100/* 2053/*
2101 * find specified header up to transport protocol header. 2054 * find the offset to specified header or the protocol number of last header
2102 * If found target header, the offset to the header is set to *offset 2055 * if target < 0. "last header" is transport protocol header, ESP, or
2103 * and return 0. otherwise, return -1. 2056 * "No next header".
2057 *
2058 * If target header is found, its offset is set in *offset and return protocol
2059 * number. Otherwise, return -1.
2060 *
2061 * Note that non-1st fragment is special case that "the protocol number
2062 * of last header" is "next header" field in Fragment header. In this case,
2063 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
2064 * isn't NULL.
2104 * 2065 *
2105 * Notes: - non-1st Fragment Header isn't skipped.
2106 * - ESP header isn't skipped.
2107 * - The target header may be trancated.
2108 */ 2066 */
2109int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) 2067int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
2068 int target, unsigned short *fragoff)
2110{ 2069{
2111 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; 2070 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
2112 u8 nexthdr = skb->nh.ipv6h->nexthdr; 2071 u8 nexthdr = skb->nh.ipv6h->nexthdr;
2113 unsigned int len = skb->len - start; 2072 unsigned int len = skb->len - start;
2114 2073
2074 if (fragoff)
2075 *fragoff = 0;
2076
2115 while (nexthdr != target) { 2077 while (nexthdr != target) {
2116 struct ipv6_opt_hdr _hdr, *hp; 2078 struct ipv6_opt_hdr _hdr, *hp;
2117 unsigned int hdrlen; 2079 unsigned int hdrlen;
2118 2080
2119 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) 2081 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
2082 if (target < 0)
2083 break;
2120 return -1; 2084 return -1;
2085 }
2086
2121 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); 2087 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2122 if (hp == NULL) 2088 if (hp == NULL)
2123 return -1; 2089 return -1;
@@ -2131,8 +2097,17 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
2131 if (fp == NULL) 2097 if (fp == NULL)
2132 return -1; 2098 return -1;
2133 2099
2134 if (ntohs(*fp) & ~0x7) 2100 _frag_off = ntohs(*fp) & ~0x7;
2101 if (_frag_off) {
2102 if (target < 0 &&
2103 ((!ipv6_ext_hdr(hp->nexthdr)) ||
2104 nexthdr == NEXTHDR_NONE)) {
2105 if (fragoff)
2106 *fragoff = _frag_off;
2107 return hp->nexthdr;
2108 }
2135 return -1; 2109 return -1;
2110 }
2136 hdrlen = 8; 2111 hdrlen = 8;
2137 } else if (nexthdr == NEXTHDR_AUTH) 2112 } else if (nexthdr == NEXTHDR_AUTH)
2138 hdrlen = (hp->hdrlen + 2) << 2; 2113 hdrlen = (hp->hdrlen + 2) << 2;
@@ -2145,7 +2120,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
2145 } 2120 }
2146 2121
2147 *offset = start; 2122 *offset = start;
2148 return 0; 2123 return nexthdr;
2149} 2124}
2150 2125
2151EXPORT_SYMBOL(ip6t_register_table); 2126EXPORT_SYMBOL(ip6t_register_table);
@@ -2157,6 +2132,7 @@ EXPORT_SYMBOL(ip6t_register_target);
2157EXPORT_SYMBOL(ip6t_unregister_target); 2132EXPORT_SYMBOL(ip6t_unregister_target);
2158EXPORT_SYMBOL(ip6t_ext_hdr); 2133EXPORT_SYMBOL(ip6t_ext_hdr);
2159EXPORT_SYMBOL(ipv6_find_hdr); 2134EXPORT_SYMBOL(ipv6_find_hdr);
2135EXPORT_SYMBOL(ip6_masked_addrcmp);
2160 2136
2161module_init(init); 2137module_init(init);
2162module_exit(fini); 2138module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 268918d5deea..f5c1a7ff4a1f 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -54,7 +54,7 @@ match(const struct sk_buff *skb,
54 unsigned int ptr; 54 unsigned int ptr;
55 unsigned int hdrlen = 0; 55 unsigned int hdrlen = 0;
56 56
57 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) 57 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL) < 0)
58 return 0; 58 return 0;
59 59
60 ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); 60 ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c
index c450a635e54b..48cf5f9efc95 100644
--- a/net/ipv6/netfilter/ip6t_dst.c
+++ b/net/ipv6/netfilter/ip6t_dst.c
@@ -71,9 +71,9 @@ match(const struct sk_buff *skb,
71 unsigned int optlen; 71 unsigned int optlen;
72 72
73#if HOPBYHOP 73#if HOPBYHOP
74 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) 74 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0)
75#else 75#else
76 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) 76 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0)
77#endif 77#endif
78 return 0; 78 return 0;
79 79
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
index 65937de1b58c..e1828f6d0a40 100644
--- a/net/ipv6/netfilter/ip6t_esp.c
+++ b/net/ipv6/netfilter/ip6t_esp.c
@@ -56,7 +56,7 @@ match(const struct sk_buff *skb,
56 /* Make sure this isn't an evil packet */ 56 /* Make sure this isn't an evil packet */
57 /*DEBUGP("ipv6_esp entered \n");*/ 57 /*DEBUGP("ipv6_esp entered \n");*/
58 58
59 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) 59 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP, NULL) < 0)
60 return 0; 60 return 0;
61 61
62 eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); 62 eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp);
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index 085d5f8eea29..d1549b268669 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -52,7 +52,7 @@ match(const struct sk_buff *skb,
52 const struct ip6t_frag *fraginfo = matchinfo; 52 const struct ip6t_frag *fraginfo = matchinfo;
53 unsigned int ptr; 53 unsigned int ptr;
54 54
55 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) 55 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0)
56 return 0; 56 return 0;
57 57
58 fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); 58 fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 1d09485111d0..e3bc8e2700e7 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -71,9 +71,9 @@ match(const struct sk_buff *skb,
71 unsigned int optlen; 71 unsigned int optlen;
72 72
73#if HOPBYHOP 73#if HOPBYHOP
74 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) 74 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0)
75#else 75#else
76 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) 76 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0)
77#endif 77#endif
78 return 0; 78 return 0;
79 79
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index beb2fd5cebbb..c1e770e45543 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -58,7 +58,7 @@ match(const struct sk_buff *skb,
58 unsigned int ret = 0; 58 unsigned int ret = 0;
59 struct in6_addr *ap, _addr; 59 struct in6_addr *ap, _addr;
60 60
61 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) 61 if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0)
62 return 0; 62 return 0;
63 63
64 rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); 64 rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 753a3ae8502b..704fbbe74874 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -401,6 +401,48 @@ static ctl_table nf_ct_net_table[] = {
401}; 401};
402#endif 402#endif
403 403
404#if defined(CONFIG_NF_CT_NETLINK) || \
405 defined(CONFIG_NF_CT_NETLINK_MODULE)
406
407#include <linux/netfilter/nfnetlink.h>
408#include <linux/netfilter/nfnetlink_conntrack.h>
409
410static int ipv6_tuple_to_nfattr(struct sk_buff *skb,
411 const struct nf_conntrack_tuple *tuple)
412{
413 NFA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
414 &tuple->src.u3.ip6);
415 NFA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
416 &tuple->dst.u3.ip6);
417 return 0;
418
419nfattr_failure:
420 return -1;
421}
422
423static const size_t cta_min_ip[CTA_IP_MAX] = {
424 [CTA_IP_V6_SRC-1] = sizeof(u_int32_t)*4,
425 [CTA_IP_V6_DST-1] = sizeof(u_int32_t)*4,
426};
427
428static int ipv6_nfattr_to_tuple(struct nfattr *tb[],
429 struct nf_conntrack_tuple *t)
430{
431 if (!tb[CTA_IP_V6_SRC-1] || !tb[CTA_IP_V6_DST-1])
432 return -EINVAL;
433
434 if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
435 return -EINVAL;
436
437 memcpy(&t->src.u3.ip6, NFA_DATA(tb[CTA_IP_V6_SRC-1]),
438 sizeof(u_int32_t) * 4);
439 memcpy(&t->dst.u3.ip6, NFA_DATA(tb[CTA_IP_V6_DST-1]),
440 sizeof(u_int32_t) * 4);
441
442 return 0;
443}
444#endif
445
404struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { 446struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
405 .l3proto = PF_INET6, 447 .l3proto = PF_INET6,
406 .name = "ipv6", 448 .name = "ipv6",
@@ -409,6 +451,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
409 .print_tuple = ipv6_print_tuple, 451 .print_tuple = ipv6_print_tuple,
410 .print_conntrack = ipv6_print_conntrack, 452 .print_conntrack = ipv6_print_conntrack,
411 .prepare = ipv6_prepare, 453 .prepare = ipv6_prepare,
454#if defined(CONFIG_NF_CT_NETLINK) || \
455 defined(CONFIG_NF_CT_NETLINK_MODULE)
456 .tuple_to_nfattr = ipv6_tuple_to_nfattr,
457 .nfattr_to_tuple = ipv6_nfattr_to_tuple,
458#endif
412 .get_features = ipv6_get_features, 459 .get_features = ipv6_get_features,
413 .me = THIS_MODULE, 460 .me = THIS_MODULE,
414}; 461};
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index a7e03cfacd06..09945c333055 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -57,17 +57,17 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
57 return 1; 57 return 1;
58} 58}
59 59
60/* Add 1; spaces filled with 0. */
61static u_int8_t invmap[] = {
62 [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1,
63 [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1,
64 [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1,
65 [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1
66};
67
60static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, 68static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
61 const struct nf_conntrack_tuple *orig) 69 const struct nf_conntrack_tuple *orig)
62{ 70{
63 /* Add 1; spaces filled with 0. */
64 static u_int8_t invmap[] = {
65 [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1,
66 [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1,
67 [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1,
68 [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1
69 };
70
71 int type = orig->dst.u.icmp.type - 128; 71 int type = orig->dst.u.icmp.type - 128;
72 if (type < 0 || type >= sizeof(invmap) || !invmap[type]) 72 if (type < 0 || type >= sizeof(invmap) || !invmap[type])
73 return 0; 73 return 0;
@@ -185,7 +185,7 @@ icmpv6_error_message(struct sk_buff *skb,
185 return -NF_ACCEPT; 185 return -NF_ACCEPT;
186 } 186 }
187 187
188 inproto = nf_ct_find_proto(PF_INET6, inprotonum); 188 inproto = __nf_ct_proto_find(PF_INET6, inprotonum);
189 189
190 /* Are they talking about one of our connections? */ 190 /* Are they talking about one of our connections? */
191 if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, 191 if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
@@ -255,6 +255,60 @@ skipped:
255 return icmpv6_error_message(skb, dataoff, ctinfo, hooknum); 255 return icmpv6_error_message(skb, dataoff, ctinfo, hooknum);
256} 256}
257 257
258#if defined(CONFIG_NF_CT_NETLINK) || \
259 defined(CONFIG_NF_CT_NETLINK_MODULE)
260
261#include <linux/netfilter/nfnetlink.h>
262#include <linux/netfilter/nfnetlink_conntrack.h>
263static int icmpv6_tuple_to_nfattr(struct sk_buff *skb,
264 const struct nf_conntrack_tuple *t)
265{
266 NFA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t),
267 &t->src.u.icmp.id);
268 NFA_PUT(skb, CTA_PROTO_ICMPV6_TYPE, sizeof(u_int8_t),
269 &t->dst.u.icmp.type);
270 NFA_PUT(skb, CTA_PROTO_ICMPV6_CODE, sizeof(u_int8_t),
271 &t->dst.u.icmp.code);
272
273 return 0;
274
275nfattr_failure:
276 return -1;
277}
278
279static const size_t cta_min_proto[CTA_PROTO_MAX] = {
280 [CTA_PROTO_ICMPV6_TYPE-1] = sizeof(u_int8_t),
281 [CTA_PROTO_ICMPV6_CODE-1] = sizeof(u_int8_t),
282 [CTA_PROTO_ICMPV6_ID-1] = sizeof(u_int16_t)
283};
284
285static int icmpv6_nfattr_to_tuple(struct nfattr *tb[],
286 struct nf_conntrack_tuple *tuple)
287{
288 if (!tb[CTA_PROTO_ICMPV6_TYPE-1]
289 || !tb[CTA_PROTO_ICMPV6_CODE-1]
290 || !tb[CTA_PROTO_ICMPV6_ID-1])
291 return -EINVAL;
292
293 if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
294 return -EINVAL;
295
296 tuple->dst.u.icmp.type =
297 *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_TYPE-1]);
298 tuple->dst.u.icmp.code =
299 *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_CODE-1]);
300 tuple->src.u.icmp.id =
301 *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_ID-1]);
302
303 if (tuple->dst.u.icmp.type < 128
304 || tuple->dst.u.icmp.type - 128 >= sizeof(invmap)
305 || !invmap[tuple->dst.u.icmp.type - 128])
306 return -EINVAL;
307
308 return 0;
309}
310#endif
311
258struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = 312struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
259{ 313{
260 .l3proto = PF_INET6, 314 .l3proto = PF_INET6,
@@ -267,6 +321,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
267 .packet = icmpv6_packet, 321 .packet = icmpv6_packet,
268 .new = icmpv6_new, 322 .new = icmpv6_new,
269 .error = icmpv6_error, 323 .error = icmpv6_error,
324#if defined(CONFIG_NF_CT_NETLINK) || \
325 defined(CONFIG_NF_CT_NETLINK_MODULE)
326 .tuple_to_nfattr = icmpv6_tuple_to_nfattr,
327 .nfattr_to_tuple = icmpv6_nfattr_to_tuple,
328#endif
270}; 329};
271 330
272EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6); 331EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 794c41d19b28..7d55f9cbd853 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -95,4 +95,11 @@ config NF_CONNTRACK_FTP
95 95
96 To compile it as a module, choose M here. If unsure, say N. 96 To compile it as a module, choose M here. If unsure, say N.
97 97
98config NF_CT_NETLINK
99 tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
100 depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK
101 depends on NF_CONNTRACK!=y || NETFILTER_NETLINK!=m
102 help
103 This option enables support for a netlink-based userspace interface
104
98endmenu 105endmenu
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 55f019ad2c08..cb2183145c37 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -13,3 +13,6 @@ obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
13 13
14# SCTP protocol connection tracking 14# SCTP protocol connection tracking
15obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o 15obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
16
17# netlink interface for nf_conntrack
18obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index a7c7b490cf22..62bb509f05d4 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -82,6 +82,8 @@ unsigned int nf_ct_log_invalid;
82static LIST_HEAD(unconfirmed); 82static LIST_HEAD(unconfirmed);
83static int nf_conntrack_vmalloc; 83static int nf_conntrack_vmalloc;
84 84
85static unsigned int nf_conntrack_next_id = 1;
86static unsigned int nf_conntrack_expect_next_id = 1;
85#ifdef CONFIG_NF_CONNTRACK_EVENTS 87#ifdef CONFIG_NF_CONNTRACK_EVENTS
86struct notifier_block *nf_conntrack_chain; 88struct notifier_block *nf_conntrack_chain;
87struct notifier_block *nf_conntrack_expect_chain; 89struct notifier_block *nf_conntrack_expect_chain;
@@ -184,7 +186,7 @@ DECLARE_MUTEX(nf_ct_cache_mutex);
184 186
185extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; 187extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
186struct nf_conntrack_protocol * 188struct nf_conntrack_protocol *
187nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol) 189__nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol)
188{ 190{
189 if (unlikely(nf_ct_protos[l3proto] == NULL)) 191 if (unlikely(nf_ct_protos[l3proto] == NULL))
190 return &nf_conntrack_generic_protocol; 192 return &nf_conntrack_generic_protocol;
@@ -192,6 +194,50 @@ nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol)
192 return nf_ct_protos[l3proto][protocol]; 194 return nf_ct_protos[l3proto][protocol];
193} 195}
194 196
197/* this is guaranteed to always return a valid protocol helper, since
198 * it falls back to generic_protocol */
199struct nf_conntrack_protocol *
200nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol)
201{
202 struct nf_conntrack_protocol *p;
203
204 preempt_disable();
205 p = __nf_ct_proto_find(l3proto, protocol);
206 if (p) {
207 if (!try_module_get(p->me))
208 p = &nf_conntrack_generic_protocol;
209 }
210 preempt_enable();
211
212 return p;
213}
214
215void nf_ct_proto_put(struct nf_conntrack_protocol *p)
216{
217 module_put(p->me);
218}
219
220struct nf_conntrack_l3proto *
221nf_ct_l3proto_find_get(u_int16_t l3proto)
222{
223 struct nf_conntrack_l3proto *p;
224
225 preempt_disable();
226 p = __nf_ct_l3proto_find(l3proto);
227 if (p) {
228 if (!try_module_get(p->me))
229 p = &nf_conntrack_generic_l3proto;
230 }
231 preempt_enable();
232
233 return p;
234}
235
236void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p)
237{
238 module_put(p->me);
239}
240
195static int nf_conntrack_hash_rnd_initted; 241static int nf_conntrack_hash_rnd_initted;
196static unsigned int nf_conntrack_hash_rnd; 242static unsigned int nf_conntrack_hash_rnd;
197 243
@@ -384,7 +430,7 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
384} 430}
385 431
386/* nf_conntrack_expect helper functions */ 432/* nf_conntrack_expect helper functions */
387static void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) 433void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
388{ 434{
389 ASSERT_WRITE_LOCK(&nf_conntrack_lock); 435 ASSERT_WRITE_LOCK(&nf_conntrack_lock);
390 NF_CT_ASSERT(!timer_pending(&exp->timeout)); 436 NF_CT_ASSERT(!timer_pending(&exp->timeout));
@@ -404,6 +450,33 @@ static void expectation_timed_out(unsigned long ul_expect)
404 nf_conntrack_expect_put(exp); 450 nf_conntrack_expect_put(exp);
405} 451}
406 452
453struct nf_conntrack_expect *
454__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
455{
456 struct nf_conntrack_expect *i;
457
458 list_for_each_entry(i, &nf_conntrack_expect_list, list) {
459 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
460 atomic_inc(&i->use);
461 return i;
462 }
463 }
464 return NULL;
465}
466
467/* Just find a expectation corresponding to a tuple. */
468struct nf_conntrack_expect *
469nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
470{
471 struct nf_conntrack_expect *i;
472
473 read_lock_bh(&nf_conntrack_lock);
474 i = __nf_conntrack_expect_find(tuple);
475 read_unlock_bh(&nf_conntrack_lock);
476
477 return i;
478}
479
407/* If an expectation for this connection is found, it gets delete from 480/* If an expectation for this connection is found, it gets delete from
408 * global list then returned. */ 481 * global list then returned. */
409static struct nf_conntrack_expect * 482static struct nf_conntrack_expect *
@@ -432,7 +505,7 @@ find_expectation(const struct nf_conntrack_tuple *tuple)
432} 505}
433 506
434/* delete all expectations for this conntrack */ 507/* delete all expectations for this conntrack */
435static void remove_expectations(struct nf_conn *ct) 508void nf_ct_remove_expectations(struct nf_conn *ct)
436{ 509{
437 struct nf_conntrack_expect *i, *tmp; 510 struct nf_conntrack_expect *i, *tmp;
438 511
@@ -462,7 +535,7 @@ clean_from_lists(struct nf_conn *ct)
462 LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); 535 LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
463 536
464 /* Destroy all pending expectations */ 537 /* Destroy all pending expectations */
465 remove_expectations(ct); 538 nf_ct_remove_expectations(ct);
466} 539}
467 540
468static void 541static void
@@ -482,12 +555,11 @@ destroy_conntrack(struct nf_conntrack *nfct)
482 /* To make sure we don't get any weird locking issues here: 555 /* To make sure we don't get any weird locking issues here:
483 * destroy_conntrack() MUST NOT be called with a write lock 556 * destroy_conntrack() MUST NOT be called with a write lock
484 * to nf_conntrack_lock!!! -HW */ 557 * to nf_conntrack_lock!!! -HW */
485 l3proto = nf_ct_find_l3proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); 558 l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
486 if (l3proto && l3proto->destroy) 559 if (l3proto && l3proto->destroy)
487 l3proto->destroy(ct); 560 l3proto->destroy(ct);
488 561
489 proto = nf_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, 562 proto = __nf_ct_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
490 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
491 if (proto && proto->destroy) 563 if (proto && proto->destroy)
492 proto->destroy(ct); 564 proto->destroy(ct);
493 565
@@ -499,7 +571,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
499 * except TFTP can create an expectation on the first packet, 571 * except TFTP can create an expectation on the first packet,
500 * before connection is in the list, so we need to clean here, 572 * before connection is in the list, so we need to clean here,
501 * too. */ 573 * too. */
502 remove_expectations(ct); 574 nf_ct_remove_expectations(ct);
503 575
504 /* We overload first tuple to link into unconfirmed list. */ 576 /* We overload first tuple to link into unconfirmed list. */
505 if (!nf_ct_is_confirmed(ct)) { 577 if (!nf_ct_is_confirmed(ct)) {
@@ -540,7 +612,7 @@ conntrack_tuple_cmp(const struct nf_conntrack_tuple_hash *i,
540 && nf_ct_tuple_equal(tuple, &i->tuple); 612 && nf_ct_tuple_equal(tuple, &i->tuple);
541} 613}
542 614
543static struct nf_conntrack_tuple_hash * 615struct nf_conntrack_tuple_hash *
544__nf_conntrack_find(const struct nf_conntrack_tuple *tuple, 616__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
545 const struct nf_conn *ignored_conntrack) 617 const struct nf_conn *ignored_conntrack)
546{ 618{
@@ -575,6 +647,29 @@ nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
575 return h; 647 return h;
576} 648}
577 649
650static void __nf_conntrack_hash_insert(struct nf_conn *ct,
651 unsigned int hash,
652 unsigned int repl_hash)
653{
654 ct->id = ++nf_conntrack_next_id;
655 list_prepend(&nf_conntrack_hash[hash],
656 &ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
657 list_prepend(&nf_conntrack_hash[repl_hash],
658 &ct->tuplehash[IP_CT_DIR_REPLY].list);
659}
660
661void nf_conntrack_hash_insert(struct nf_conn *ct)
662{
663 unsigned int hash, repl_hash;
664
665 hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
666 repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
667
668 write_lock_bh(&nf_conntrack_lock);
669 __nf_conntrack_hash_insert(ct, hash, repl_hash);
670 write_unlock_bh(&nf_conntrack_lock);
671}
672
578/* Confirm a connection given skb; places it in hash table */ 673/* Confirm a connection given skb; places it in hash table */
579int 674int
580__nf_conntrack_confirm(struct sk_buff **pskb) 675__nf_conntrack_confirm(struct sk_buff **pskb)
@@ -621,10 +716,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
621 /* Remove from unconfirmed list */ 716 /* Remove from unconfirmed list */
622 list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); 717 list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
623 718
624 list_prepend(&nf_conntrack_hash[hash], 719 __nf_conntrack_hash_insert(ct, hash, repl_hash);
625 &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
626 list_prepend(&nf_conntrack_hash[repl_hash],
627 &ct->tuplehash[IP_CT_DIR_REPLY]);
628 /* Timer relative to confirmation time, not original 720 /* Timer relative to confirmation time, not original
629 setting time, otherwise we'd get timer wrap in 721 setting time, otherwise we'd get timer wrap in
630 weird delay cases. */ 722 weird delay cases. */
@@ -708,13 +800,41 @@ static inline int helper_cmp(const struct nf_conntrack_helper *i,
708} 800}
709 801
710static struct nf_conntrack_helper * 802static struct nf_conntrack_helper *
711nf_ct_find_helper(const struct nf_conntrack_tuple *tuple) 803__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
712{ 804{
713 return LIST_FIND(&helpers, helper_cmp, 805 return LIST_FIND(&helpers, helper_cmp,
714 struct nf_conntrack_helper *, 806 struct nf_conntrack_helper *,
715 tuple); 807 tuple);
716} 808}
717 809
810struct nf_conntrack_helper *
811nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple)
812{
813 struct nf_conntrack_helper *helper;
814
815 /* need nf_conntrack_lock to assure that helper exists until
816 * try_module_get() is called */
817 read_lock_bh(&nf_conntrack_lock);
818
819 helper = __nf_ct_helper_find(tuple);
820 if (helper) {
821 /* need to increase module usage count to assure helper will
822 * not go away while the caller is e.g. busy putting a
823 * conntrack in the hash that uses the helper */
824 if (!try_module_get(helper->me))
825 helper = NULL;
826 }
827
828 read_unlock_bh(&nf_conntrack_lock);
829
830 return helper;
831}
832
833void nf_ct_helper_put(struct nf_conntrack_helper *helper)
834{
835 module_put(helper->me);
836}
837
718static struct nf_conn * 838static struct nf_conn *
719__nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, 839__nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
720 const struct nf_conntrack_tuple *repl, 840 const struct nf_conntrack_tuple *repl,
@@ -744,7 +864,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
744 /* find features needed by this conntrack. */ 864 /* find features needed by this conntrack. */
745 features = l3proto->get_features(orig); 865 features = l3proto->get_features(orig);
746 read_lock_bh(&nf_conntrack_lock); 866 read_lock_bh(&nf_conntrack_lock);
747 if (nf_ct_find_helper(repl) != NULL) 867 if (__nf_ct_helper_find(repl) != NULL)
748 features |= NF_CT_F_HELP; 868 features |= NF_CT_F_HELP;
749 read_unlock_bh(&nf_conntrack_lock); 869 read_unlock_bh(&nf_conntrack_lock);
750 870
@@ -794,7 +914,7 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
794{ 914{
795 struct nf_conntrack_l3proto *l3proto; 915 struct nf_conntrack_l3proto *l3proto;
796 916
797 l3proto = nf_ct_find_l3proto(orig->src.l3num); 917 l3proto = __nf_ct_l3proto_find(orig->src.l3num);
798 return __nf_conntrack_alloc(orig, repl, l3proto); 918 return __nf_conntrack_alloc(orig, repl, l3proto);
799} 919}
800 920
@@ -853,7 +973,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
853 nf_conntrack_get(&conntrack->master->ct_general); 973 nf_conntrack_get(&conntrack->master->ct_general);
854 NF_CT_STAT_INC(expect_new); 974 NF_CT_STAT_INC(expect_new);
855 } else { 975 } else {
856 conntrack->helper = nf_ct_find_helper(&repl_tuple); 976 conntrack->helper = __nf_ct_helper_find(&repl_tuple);
857 977
858 NF_CT_STAT_INC(new); 978 NF_CT_STAT_INC(new);
859 } 979 }
@@ -947,13 +1067,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
947 return NF_ACCEPT; 1067 return NF_ACCEPT;
948 } 1068 }
949 1069
950 l3proto = nf_ct_find_l3proto((u_int16_t)pf); 1070 l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
951 if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) { 1071 if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) {
952 DEBUGP("not prepared to track yet or error occured\n"); 1072 DEBUGP("not prepared to track yet or error occured\n");
953 return -ret; 1073 return -ret;
954 } 1074 }
955 1075
956 proto = nf_ct_find_proto((u_int16_t)pf, protonum); 1076 proto = __nf_ct_proto_find((u_int16_t)pf, protonum);
957 1077
958 /* It may be an special packet, error, unclean... 1078 /* It may be an special packet, error, unclean...
959 * inverse of the return code tells to the netfilter 1079 * inverse of the return code tells to the netfilter
@@ -1002,9 +1122,9 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
1002 const struct nf_conntrack_tuple *orig) 1122 const struct nf_conntrack_tuple *orig)
1003{ 1123{
1004 return nf_ct_invert_tuple(inverse, orig, 1124 return nf_ct_invert_tuple(inverse, orig,
1005 nf_ct_find_l3proto(orig->src.l3num), 1125 __nf_ct_l3proto_find(orig->src.l3num),
1006 nf_ct_find_proto(orig->src.l3num, 1126 __nf_ct_proto_find(orig->src.l3num,
1007 orig->dst.protonum)); 1127 orig->dst.protonum));
1008} 1128}
1009 1129
1010/* Would two expected things clash? */ 1130/* Would two expected things clash? */
@@ -1096,6 +1216,7 @@ static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
1096 exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; 1216 exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ;
1097 add_timer(&exp->timeout); 1217 add_timer(&exp->timeout);
1098 1218
1219 exp->id = ++nf_conntrack_expect_next_id;
1099 atomic_inc(&exp->use); 1220 atomic_inc(&exp->use);
1100 NF_CT_STAT_INC(expect_create); 1221 NF_CT_STAT_INC(expect_create);
1101} 1222}
@@ -1129,6 +1250,7 @@ static inline int refresh_timer(struct nf_conntrack_expect *i)
1129int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) 1250int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
1130{ 1251{
1131 struct nf_conntrack_expect *i; 1252 struct nf_conntrack_expect *i;
1253 struct nf_conn *master = expect->master;
1132 int ret; 1254 int ret;
1133 1255
1134 DEBUGP("nf_conntrack_expect_related %p\n", related_to); 1256 DEBUGP("nf_conntrack_expect_related %p\n", related_to);
@@ -1149,9 +1271,9 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
1149 } 1271 }
1150 } 1272 }
1151 /* Will be over limit? */ 1273 /* Will be over limit? */
1152 if (expect->master->helper->max_expected && 1274 if (master->helper->max_expected &&
1153 expect->master->expecting >= expect->master->helper->max_expected) 1275 master->expecting >= master->helper->max_expected)
1154 evict_oldest_expect(expect->master); 1276 evict_oldest_expect(master);
1155 1277
1156 nf_conntrack_expect_insert(expect); 1278 nf_conntrack_expect_insert(expect);
1157 nf_conntrack_expect_event(IPEXP_NEW, expect); 1279 nf_conntrack_expect_event(IPEXP_NEW, expect);
@@ -1175,7 +1297,7 @@ void nf_conntrack_alter_reply(struct nf_conn *conntrack,
1175 1297
1176 conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; 1298 conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
1177 if (!conntrack->master && conntrack->expecting == 0) 1299 if (!conntrack->master && conntrack->expecting == 0)
1178 conntrack->helper = nf_ct_find_helper(newreply); 1300 conntrack->helper = __nf_ct_helper_find(newreply);
1179 write_unlock_bh(&nf_conntrack_lock); 1301 write_unlock_bh(&nf_conntrack_lock);
1180} 1302}
1181 1303
@@ -1200,6 +1322,19 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
1200 return 0; 1322 return 0;
1201} 1323}
1202 1324
1325struct nf_conntrack_helper *
1326__nf_conntrack_helper_find_byname(const char *name)
1327{
1328 struct nf_conntrack_helper *h;
1329
1330 list_for_each_entry(h, &helpers, list) {
1331 if (!strcmp(h->name, name))
1332 return h;
1333 }
1334
1335 return NULL;
1336}
1337
1203static inline int unhelp(struct nf_conntrack_tuple_hash *i, 1338static inline int unhelp(struct nf_conntrack_tuple_hash *i,
1204 const struct nf_conntrack_helper *me) 1339 const struct nf_conntrack_helper *me)
1205{ 1340{
@@ -1283,6 +1418,51 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
1283 nf_conntrack_event_cache(event, skb); 1418 nf_conntrack_event_cache(event, skb);
1284} 1419}
1285 1420
1421#if defined(CONFIG_NF_CT_NETLINK) || \
1422 defined(CONFIG_NF_CT_NETLINK_MODULE)
1423
1424#include <linux/netfilter/nfnetlink.h>
1425#include <linux/netfilter/nfnetlink_conntrack.h>
1426
1427/* Generic function for tcp/udp/sctp/dccp and alike. This needs to be
1428 * in ip_conntrack_core, since we don't want the protocols to autoload
1429 * or depend on ctnetlink */
1430int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb,
1431 const struct nf_conntrack_tuple *tuple)
1432{
1433 NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t),
1434 &tuple->src.u.tcp.port);
1435 NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t),
1436 &tuple->dst.u.tcp.port);
1437 return 0;
1438
1439nfattr_failure:
1440 return -1;
1441}
1442
1443static const size_t cta_min_proto[CTA_PROTO_MAX] = {
1444 [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t),
1445 [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t)
1446};
1447
1448int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[],
1449 struct nf_conntrack_tuple *t)
1450{
1451 if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1])
1452 return -EINVAL;
1453
1454 if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
1455 return -EINVAL;
1456
1457 t->src.u.tcp.port =
1458 *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
1459 t->dst.u.tcp.port =
1460 *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
1461
1462 return 0;
1463}
1464#endif
1465
1286/* Used by ipt_REJECT and ip6t_REJECT. */ 1466/* Used by ipt_REJECT and ip6t_REJECT. */
1287void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb) 1467void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
1288{ 1468{
@@ -1365,6 +1545,11 @@ static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size)
1365 get_order(sizeof(struct list_head) * size)); 1545 get_order(sizeof(struct list_head) * size));
1366} 1546}
1367 1547
1548void nf_conntrack_flush()
1549{
1550 nf_ct_iterate_cleanup(kill_all, NULL);
1551}
1552
1368/* Mishearing the voices in his head, our hero wonders how he's 1553/* Mishearing the voices in his head, our hero wonders how he's
1369 supposed to kill the mall. */ 1554 supposed to kill the mall. */
1370void nf_conntrack_cleanup(void) 1555void nf_conntrack_cleanup(void)
@@ -1378,7 +1563,7 @@ void nf_conntrack_cleanup(void)
1378 1563
1379 nf_ct_event_cache_flush(); 1564 nf_ct_event_cache_flush();
1380 i_see_dead_people: 1565 i_see_dead_people:
1381 nf_ct_iterate_cleanup(kill_all, NULL); 1566 nf_conntrack_flush();
1382 if (atomic_read(&nf_conntrack_count) != 0) { 1567 if (atomic_read(&nf_conntrack_count) != 0) {
1383 schedule(); 1568 schedule();
1384 goto i_see_dead_people; 1569 goto i_see_dead_people;
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 65080e269f27..d5a6eaf4a1de 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -44,7 +44,7 @@ static unsigned int ports_c;
44module_param_array(ports, ushort, &ports_c, 0400); 44module_param_array(ports, ushort, &ports_c, 0400);
45 45
46static int loose; 46static int loose;
47module_param(loose, int, 0600); 47module_param(loose, bool, 0600);
48 48
49unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, 49unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
50 enum ip_conntrack_info ctinfo, 50 enum ip_conntrack_info ctinfo,
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
new file mode 100644
index 000000000000..73ab16bc7d40
--- /dev/null
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -0,0 +1,1653 @@
1/* Connection tracking via netlink socket. Allows for user space
2 * protocol helpers and general trouble making from userspace.
3 *
4 * (C) 2001 by Jay Schulist <jschlst@samba.org>
5 * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
6 * (C) 2003 by Patrick Mchardy <kaber@trash.net>
7 * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
8 *
9 * I've reworked this stuff to use attributes instead of conntrack
10 * structures. 5.44 am. I need more tea. --pablo 05/07/11.
11 *
12 * Initial connection tracking via netlink development funded and
13 * generally made possible by Network Robots, Inc. (www.networkrobots.com)
14 *
15 * Further development of this code funded by Astaro AG (http://www.astaro.com)
16 *
17 * This software may be used and distributed according to the terms
18 * of the GNU General Public License, incorporated herein by reference.
19 *
20 * Derived from ip_conntrack_netlink.c: Port by Pablo Neira Ayuso (05/11/14)
21 */
22
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/types.h>
27#include <linux/timer.h>
28#include <linux/skbuff.h>
29#include <linux/errno.h>
30#include <linux/netlink.h>
31#include <linux/spinlock.h>
32#include <linux/notifier.h>
33
34#include <linux/netfilter.h>
35#include <net/netfilter/nf_conntrack.h>
36#include <net/netfilter/nf_conntrack_core.h>
37#include <net/netfilter/nf_conntrack_helper.h>
38#include <net/netfilter/nf_conntrack_l3proto.h>
39#include <net/netfilter/nf_conntrack_protocol.h>
40#include <linux/netfilter_ipv4/ip_nat_protocol.h>
41
42#include <linux/netfilter/nfnetlink.h>
43#include <linux/netfilter/nfnetlink_conntrack.h>
44
45MODULE_LICENSE("GPL");
46
47static char __initdata version[] = "0.92";
48
49#if 0
50#define DEBUGP printk
51#else
52#define DEBUGP(format, args...)
53#endif
54
55
56static inline int
57ctnetlink_dump_tuples_proto(struct sk_buff *skb,
58 const struct nf_conntrack_tuple *tuple)
59{
60 struct nf_conntrack_protocol *proto;
61 int ret = 0;
62
63 NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
64
65 /* If no protocol helper is found, this function will return the
66 * generic protocol helper, so proto won't *ever* be NULL */
67 proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum);
68 if (likely(proto->tuple_to_nfattr))
69 ret = proto->tuple_to_nfattr(skb, tuple);
70
71 nf_ct_proto_put(proto);
72
73 return ret;
74
75nfattr_failure:
76 return -1;
77}
78
79static inline int
80ctnetlink_dump_tuples(struct sk_buff *skb,
81 const struct nf_conntrack_tuple *tuple)
82{
83 struct nfattr *nest_parms;
84 struct nf_conntrack_l3proto *l3proto;
85 int ret = 0;
86
87 l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
88
89 nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
90 if (likely(l3proto->tuple_to_nfattr))
91 ret = l3proto->tuple_to_nfattr(skb, tuple);
92 NFA_NEST_END(skb, nest_parms);
93
94 nf_ct_l3proto_put(l3proto);
95
96 if (unlikely(ret < 0))
97 return ret;
98
99 nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
100 ret = ctnetlink_dump_tuples_proto(skb, tuple);
101 NFA_NEST_END(skb, nest_parms);
102
103 return ret;
104
105nfattr_failure:
106 return -1;
107}
108
109static inline int
110ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct)
111{
112 u_int32_t status = htonl((u_int32_t) ct->status);
113 NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
114 return 0;
115
116nfattr_failure:
117 return -1;
118}
119
120static inline int
121ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
122{
123 long timeout_l = ct->timeout.expires - jiffies;
124 u_int32_t timeout;
125
126 if (timeout_l < 0)
127 timeout = 0;
128 else
129 timeout = htonl(timeout_l / HZ);
130
131 NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
132 return 0;
133
134nfattr_failure:
135 return -1;
136}
137
138static inline int
139ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct)
140{
141 struct nf_conntrack_protocol *proto = nf_ct_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
142 struct nfattr *nest_proto;
143 int ret;
144
145 if (!proto->to_nfattr) {
146 nf_ct_proto_put(proto);
147 return 0;
148 }
149
150 nest_proto = NFA_NEST(skb, CTA_PROTOINFO);
151
152 ret = proto->to_nfattr(skb, nest_proto, ct);
153
154 nf_ct_proto_put(proto);
155
156 NFA_NEST_END(skb, nest_proto);
157
158 return ret;
159
160nfattr_failure:
161 return -1;
162}
163
164static inline int
165ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
166{
167 struct nfattr *nest_helper;
168
169 if (!ct->helper)
170 return 0;
171
172 nest_helper = NFA_NEST(skb, CTA_HELP);
173 NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name);
174
175 if (ct->helper->to_nfattr)
176 ct->helper->to_nfattr(skb, ct);
177
178 NFA_NEST_END(skb, nest_helper);
179
180 return 0;
181
182nfattr_failure:
183 return -1;
184}
185
186#ifdef CONFIG_NF_CT_ACCT
187static inline int
188ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
189 enum ip_conntrack_dir dir)
190{
191 enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
192 struct nfattr *nest_count = NFA_NEST(skb, type);
193 u_int32_t tmp;
194
195 tmp = htonl(ct->counters[dir].packets);
196 NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
197
198 tmp = htonl(ct->counters[dir].bytes);
199 NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
200
201 NFA_NEST_END(skb, nest_count);
202
203 return 0;
204
205nfattr_failure:
206 return -1;
207}
208#else
209#define ctnetlink_dump_counters(a, b, c) (0)
210#endif
211
212#ifdef CONFIG_NF_CONNTRACK_MARK
213static inline int
214ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
215{
216 u_int32_t mark = htonl(ct->mark);
217
218 NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
219 return 0;
220
221nfattr_failure:
222 return -1;
223}
224#else
225#define ctnetlink_dump_mark(a, b) (0)
226#endif
227
228static inline int
229ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
230{
231 u_int32_t id = htonl(ct->id);
232 NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
233 return 0;
234
235nfattr_failure:
236 return -1;
237}
238
239static inline int
240ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct)
241{
242 u_int32_t use = htonl(atomic_read(&ct->ct_general.use));
243
244 NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
245 return 0;
246
247nfattr_failure:
248 return -1;
249}
250
251#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)
252
253static int
254ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
255 int event, int nowait,
256 const struct nf_conn *ct)
257{
258 struct nlmsghdr *nlh;
259 struct nfgenmsg *nfmsg;
260 struct nfattr *nest_parms;
261 unsigned char *b;
262
263 b = skb->tail;
264
265 event |= NFNL_SUBSYS_CTNETLINK << 8;
266 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
267 nfmsg = NLMSG_DATA(nlh);
268
269 nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
270 nfmsg->nfgen_family =
271 ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
272 nfmsg->version = NFNETLINK_V0;
273 nfmsg->res_id = 0;
274
275 nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
276 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
277 goto nfattr_failure;
278 NFA_NEST_END(skb, nest_parms);
279
280 nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
281 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
282 goto nfattr_failure;
283 NFA_NEST_END(skb, nest_parms);
284
285 if (ctnetlink_dump_status(skb, ct) < 0 ||
286 ctnetlink_dump_timeout(skb, ct) < 0 ||
287 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
288 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
289 ctnetlink_dump_protoinfo(skb, ct) < 0 ||
290 ctnetlink_dump_helpinfo(skb, ct) < 0 ||
291 ctnetlink_dump_mark(skb, ct) < 0 ||
292 ctnetlink_dump_id(skb, ct) < 0 ||
293 ctnetlink_dump_use(skb, ct) < 0)
294 goto nfattr_failure;
295
296 nlh->nlmsg_len = skb->tail - b;
297 return skb->len;
298
299nlmsg_failure:
300nfattr_failure:
301 skb_trim(skb, b - skb->data);
302 return -1;
303}
304
305#ifdef CONFIG_NF_CONNTRACK_EVENTS
306static int ctnetlink_conntrack_event(struct notifier_block *this,
307 unsigned long events, void *ptr)
308{
309 struct nlmsghdr *nlh;
310 struct nfgenmsg *nfmsg;
311 struct nfattr *nest_parms;
312 struct nf_conn *ct = (struct nf_conn *)ptr;
313 struct sk_buff *skb;
314 unsigned int type;
315 unsigned char *b;
316 unsigned int flags = 0, group;
317
318 /* ignore our fake conntrack entry */
319 if (ct == &nf_conntrack_untracked)
320 return NOTIFY_DONE;
321
322 if (events & IPCT_DESTROY) {
323 type = IPCTNL_MSG_CT_DELETE;
324 group = NFNLGRP_CONNTRACK_DESTROY;
325 } else if (events & (IPCT_NEW | IPCT_RELATED)) {
326 type = IPCTNL_MSG_CT_NEW;
327 flags = NLM_F_CREATE|NLM_F_EXCL;
328 /* dump everything */
329 events = ~0UL;
330 group = NFNLGRP_CONNTRACK_NEW;
331 } else if (events & (IPCT_STATUS |
332 IPCT_PROTOINFO |
333 IPCT_HELPER |
334 IPCT_HELPINFO |
335 IPCT_NATINFO)) {
336 type = IPCTNL_MSG_CT_NEW;
337 group = NFNLGRP_CONNTRACK_UPDATE;
338 } else
339 return NOTIFY_DONE;
340
341 /* FIXME: Check if there are any listeners before, don't hurt performance */
342
343 skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
344 if (!skb)
345 return NOTIFY_DONE;
346
347 b = skb->tail;
348
349 type |= NFNL_SUBSYS_CTNETLINK << 8;
350 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
351 nfmsg = NLMSG_DATA(nlh);
352
353 nlh->nlmsg_flags = flags;
354 nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
355 nfmsg->version = NFNETLINK_V0;
356 nfmsg->res_id = 0;
357
358 nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
359 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
360 goto nfattr_failure;
361 NFA_NEST_END(skb, nest_parms);
362
363 nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
364 if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
365 goto nfattr_failure;
366 NFA_NEST_END(skb, nest_parms);
367
368 /* NAT stuff is now a status flag */
369 if ((events & IPCT_STATUS || events & IPCT_NATINFO)
370 && ctnetlink_dump_status(skb, ct) < 0)
371 goto nfattr_failure;
372 if (events & IPCT_REFRESH
373 && ctnetlink_dump_timeout(skb, ct) < 0)
374 goto nfattr_failure;
375 if (events & IPCT_PROTOINFO
376 && ctnetlink_dump_protoinfo(skb, ct) < 0)
377 goto nfattr_failure;
378 if (events & IPCT_HELPINFO
379 && ctnetlink_dump_helpinfo(skb, ct) < 0)
380 goto nfattr_failure;
381
382 if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
383 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
384 goto nfattr_failure;
385
386 nlh->nlmsg_len = skb->tail - b;
387 nfnetlink_send(skb, 0, group, 0);
388 return NOTIFY_DONE;
389
390nlmsg_failure:
391nfattr_failure:
392 kfree_skb(skb);
393 return NOTIFY_DONE;
394}
395#endif /* CONFIG_NF_CONNTRACK_EVENTS */
396
397static int ctnetlink_done(struct netlink_callback *cb)
398{
399 DEBUGP("entered %s\n", __FUNCTION__);
400 return 0;
401}
402
403#define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num
404
405static int
406ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
407{
408 struct nf_conn *ct = NULL;
409 struct nf_conntrack_tuple_hash *h;
410 struct list_head *i;
411 u_int32_t *id = (u_int32_t *) &cb->args[1];
412 struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
413 u_int8_t l3proto = nfmsg->nfgen_family;
414
415 DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
416 cb->args[0], *id);
417
418 read_lock_bh(&nf_conntrack_lock);
419 for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) {
420 list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
421 h = (struct nf_conntrack_tuple_hash *) i;
422 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
423 continue;
424 ct = nf_ct_tuplehash_to_ctrack(h);
425 /* Dump entries of a given L3 protocol number.
426 * If it is not specified, ie. l3proto == 0,
427 * then dump everything. */
428 if (l3proto && L3PROTO(ct) != l3proto)
429 continue;
430 if (ct->id <= *id)
431 continue;
432 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
433 cb->nlh->nlmsg_seq,
434 IPCTNL_MSG_CT_NEW,
435 1, ct) < 0)
436 goto out;
437 *id = ct->id;
438 }
439 }
440out:
441 read_unlock_bh(&nf_conntrack_lock);
442
443 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
444
445 return skb->len;
446}
447
448#ifdef CONFIG_NF_CT_ACCT
449static int
450ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb)
451{
452 struct nf_conn *ct = NULL;
453 struct nf_conntrack_tuple_hash *h;
454 struct list_head *i;
455 u_int32_t *id = (u_int32_t *) &cb->args[1];
456 struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
457 u_int8_t l3proto = nfmsg->nfgen_family;
458
459 DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__,
460 cb->args[0], *id);
461
462 write_lock_bh(&nf_conntrack_lock);
463 for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) {
464 list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
465 h = (struct nf_conntrack_tuple_hash *) i;
466 if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
467 continue;
468 ct = nf_ct_tuplehash_to_ctrack(h);
469 if (l3proto && L3PROTO(ct) != l3proto)
470 continue;
471 if (ct->id <= *id)
472 continue;
473 if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
474 cb->nlh->nlmsg_seq,
475 IPCTNL_MSG_CT_NEW,
476 1, ct) < 0)
477 goto out;
478 *id = ct->id;
479
480 memset(&ct->counters, 0, sizeof(ct->counters));
481 }
482 }
483out:
484 write_unlock_bh(&nf_conntrack_lock);
485
486 DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
487
488 return skb->len;
489}
490#endif
491
492static inline int
493ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple)
494{
495 struct nfattr *tb[CTA_IP_MAX];
496 struct nf_conntrack_l3proto *l3proto;
497 int ret = 0;
498
499 DEBUGP("entered %s\n", __FUNCTION__);
500
501 nfattr_parse_nested(tb, CTA_IP_MAX, attr);
502
503 l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
504
505 if (likely(l3proto->nfattr_to_tuple))
506 ret = l3proto->nfattr_to_tuple(tb, tuple);
507
508 nf_ct_l3proto_put(l3proto);
509
510 DEBUGP("leaving\n");
511
512 return ret;
513}
514
515static const size_t cta_min_proto[CTA_PROTO_MAX] = {
516 [CTA_PROTO_NUM-1] = sizeof(u_int8_t),
517};
518
519static inline int
520ctnetlink_parse_tuple_proto(struct nfattr *attr,
521 struct nf_conntrack_tuple *tuple)
522{
523 struct nfattr *tb[CTA_PROTO_MAX];
524 struct nf_conntrack_protocol *proto;
525 int ret = 0;
526
527 DEBUGP("entered %s\n", __FUNCTION__);
528
529 nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
530
531 if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
532 return -EINVAL;
533
534 if (!tb[CTA_PROTO_NUM-1])
535 return -EINVAL;
536 tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
537
538 proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum);
539
540 if (likely(proto->nfattr_to_tuple))
541 ret = proto->nfattr_to_tuple(tb, tuple);
542
543 nf_ct_proto_put(proto);
544
545 return ret;
546}
547
548static inline int
549ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
550 enum ctattr_tuple type, u_int8_t l3num)
551{
552 struct nfattr *tb[CTA_TUPLE_MAX];
553 int err;
554
555 DEBUGP("entered %s\n", __FUNCTION__);
556
557 memset(tuple, 0, sizeof(*tuple));
558
559 nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
560
561 if (!tb[CTA_TUPLE_IP-1])
562 return -EINVAL;
563
564 tuple->src.l3num = l3num;
565
566 err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple);
567 if (err < 0)
568 return err;
569
570 if (!tb[CTA_TUPLE_PROTO-1])
571 return -EINVAL;
572
573 err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple);
574 if (err < 0)
575 return err;
576
577 /* orig and expect tuples get DIR_ORIGINAL */
578 if (type == CTA_TUPLE_REPLY)
579 tuple->dst.dir = IP_CT_DIR_REPLY;
580 else
581 tuple->dst.dir = IP_CT_DIR_ORIGINAL;
582
583 NF_CT_DUMP_TUPLE(tuple);
584
585 DEBUGP("leaving\n");
586
587 return 0;
588}
589
590#ifdef CONFIG_IP_NF_NAT_NEEDED
591static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
592 [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t),
593 [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),
594};
595
596static int ctnetlink_parse_nat_proto(struct nfattr *attr,
597 const struct nf_conn *ct,
598 struct ip_nat_range *range)
599{
600 struct nfattr *tb[CTA_PROTONAT_MAX];
601 struct ip_nat_protocol *npt;
602
603 DEBUGP("entered %s\n", __FUNCTION__);
604
605 nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
606
607 if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
608 return -EINVAL;
609
610 npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
611
612 if (!npt->nfattr_to_range) {
613 ip_nat_proto_put(npt);
614 return 0;
615 }
616
617 /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
618 if (npt->nfattr_to_range(tb, range) > 0)
619 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
620
621 ip_nat_proto_put(npt);
622
623 DEBUGP("leaving\n");
624 return 0;
625}
626
627static const size_t cta_min_nat[CTA_NAT_MAX] = {
628 [CTA_NAT_MINIP-1] = sizeof(u_int32_t),
629 [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),
630};
631
632static inline int
633ctnetlink_parse_nat(struct nfattr *cda[],
634 const struct nf_conn *ct, struct ip_nat_range *range)
635{
636 struct nfattr *tb[CTA_NAT_MAX];
637 int err;
638
639 DEBUGP("entered %s\n", __FUNCTION__);
640
641 memset(range, 0, sizeof(*range));
642
643 nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
644
645 if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
646 return -EINVAL;
647
648 if (tb[CTA_NAT_MINIP-1])
649 range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
650
651 if (!tb[CTA_NAT_MAXIP-1])
652 range->max_ip = range->min_ip;
653 else
654 range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
655
656 if (range->min_ip)
657 range->flags |= IP_NAT_RANGE_MAP_IPS;
658
659 if (!tb[CTA_NAT_PROTO-1])
660 return 0;
661
662 err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
663 if (err < 0)
664 return err;
665
666 DEBUGP("leaving\n");
667 return 0;
668}
669#endif
670
671static inline int
672ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
673{
674 struct nfattr *tb[CTA_HELP_MAX];
675
676 DEBUGP("entered %s\n", __FUNCTION__);
677
678 nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
679
680 if (!tb[CTA_HELP_NAME-1])
681 return -EINVAL;
682
683 *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
684
685 return 0;
686}
687
688static const size_t cta_min[CTA_MAX] = {
689 [CTA_STATUS-1] = sizeof(u_int32_t),
690 [CTA_TIMEOUT-1] = sizeof(u_int32_t),
691 [CTA_MARK-1] = sizeof(u_int32_t),
692 [CTA_USE-1] = sizeof(u_int32_t),
693 [CTA_ID-1] = sizeof(u_int32_t)
694};
695
696static int
697ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
698 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
699{
700 struct nf_conntrack_tuple_hash *h;
701 struct nf_conntrack_tuple tuple;
702 struct nf_conn *ct;
703 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
704 u_int8_t u3 = nfmsg->nfgen_family;
705 int err = 0;
706
707 DEBUGP("entered %s\n", __FUNCTION__);
708
709 if (nfattr_bad_size(cda, CTA_MAX, cta_min))
710 return -EINVAL;
711
712 if (cda[CTA_TUPLE_ORIG-1])
713 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3);
714 else if (cda[CTA_TUPLE_REPLY-1])
715 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
716 else {
717 /* Flush the whole table */
718 nf_conntrack_flush();
719 return 0;
720 }
721
722 if (err < 0)
723 return err;
724
725 h = nf_conntrack_find_get(&tuple, NULL);
726 if (!h) {
727 DEBUGP("tuple not found in conntrack hash\n");
728 return -ENOENT;
729 }
730
731 ct = nf_ct_tuplehash_to_ctrack(h);
732
733 if (cda[CTA_ID-1]) {
734 u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
735 if (ct->id != id) {
736 nf_ct_put(ct);
737 return -ENOENT;
738 }
739 }
740 if (del_timer(&ct->timeout))
741 ct->timeout.function((unsigned long)ct);
742
743 nf_ct_put(ct);
744 DEBUGP("leaving\n");
745
746 return 0;
747}
748
749static int
750ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
751 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
752{
753 struct nf_conntrack_tuple_hash *h;
754 struct nf_conntrack_tuple tuple;
755 struct nf_conn *ct;
756 struct sk_buff *skb2 = NULL;
757 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
758 u_int8_t u3 = nfmsg->nfgen_family;
759 int err = 0;
760
761 DEBUGP("entered %s\n", __FUNCTION__);
762
763 if (nlh->nlmsg_flags & NLM_F_DUMP) {
764 u32 rlen;
765
766 if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==
767 IPCTNL_MSG_CT_GET_CTRZERO) {
768#ifdef CONFIG_NF_CT_ACCT
769 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
770 ctnetlink_dump_table_w,
771 ctnetlink_done)) != 0)
772 return -EINVAL;
773#else
774 return -ENOTSUPP;
775#endif
776 } else {
777 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
778 ctnetlink_dump_table,
779 ctnetlink_done)) != 0)
780 return -EINVAL;
781 }
782
783 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
784 if (rlen > skb->len)
785 rlen = skb->len;
786 skb_pull(skb, rlen);
787 return 0;
788 }
789
790 if (nfattr_bad_size(cda, CTA_MAX, cta_min))
791 return -EINVAL;
792
793 if (cda[CTA_TUPLE_ORIG-1])
794 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3);
795 else if (cda[CTA_TUPLE_REPLY-1])
796 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
797 else
798 return -EINVAL;
799
800 if (err < 0)
801 return err;
802
803 h = nf_conntrack_find_get(&tuple, NULL);
804 if (!h) {
805 DEBUGP("tuple not found in conntrack hash");
806 return -ENOENT;
807 }
808 DEBUGP("tuple found\n");
809 ct = nf_ct_tuplehash_to_ctrack(h);
810
811 err = -ENOMEM;
812 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
813 if (!skb2) {
814 nf_ct_put(ct);
815 return -ENOMEM;
816 }
817 NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
818
819 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
820 IPCTNL_MSG_CT_NEW, 1, ct);
821 nf_ct_put(ct);
822 if (err <= 0)
823 goto free;
824
825 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
826 if (err < 0)
827 goto out;
828
829 DEBUGP("leaving\n");
830 return 0;
831
832free:
833 kfree_skb(skb2);
834out:
835 return err;
836}
837
838static inline int
839ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[])
840{
841 unsigned long d;
842 unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
843 d = ct->status ^ status;
844
845 if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
846 /* unchangeable */
847 return -EINVAL;
848
849 if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
850 /* SEEN_REPLY bit can only be set */
851 return -EINVAL;
852
853
854 if (d & IPS_ASSURED && !(status & IPS_ASSURED))
855 /* ASSURED bit can only be set */
856 return -EINVAL;
857
858 if (cda[CTA_NAT-1]) {
859#ifndef CONFIG_IP_NF_NAT_NEEDED
860 return -EINVAL;
861#else
862 unsigned int hooknum;
863 struct ip_nat_range range;
864
865 if (ctnetlink_parse_nat(cda, ct, &range) < 0)
866 return -EINVAL;
867
868 DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n",
869 NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
870 htons(range.min.all), htons(range.max.all));
871
872 /* This is tricky but it works. ip_nat_setup_info needs the
873 * hook number as parameter, so let's do the correct
874 * conversion and run away */
875 if (status & IPS_SRC_NAT_DONE)
876 hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
877 else if (status & IPS_DST_NAT_DONE)
878 hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */
879 else
880 return -EINVAL; /* Missing NAT flags */
881
882 DEBUGP("NAT status: %lu\n",
883 status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
884
885 if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
886 return -EEXIST;
887 ip_nat_setup_info(ct, &range, hooknum);
888
889 DEBUGP("NAT status after setup_info: %lu\n",
890 ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
891#endif
892 }
893
894 /* Be careful here, modifying NAT bits can screw up things,
895 * so don't let users modify them directly if they don't pass
896 * ip_nat_range. */
897 ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
898 return 0;
899}
900
901
902static inline int
903ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
904{
905 struct nf_conntrack_helper *helper;
906 char *helpname;
907 int err;
908
909 DEBUGP("entered %s\n", __FUNCTION__);
910
911 /* don't change helper of sibling connections */
912 if (ct->master)
913 return -EINVAL;
914
915 err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);
916 if (err < 0)
917 return err;
918
919 helper = __nf_conntrack_helper_find_byname(helpname);
920 if (!helper) {
921 if (!strcmp(helpname, ""))
922 helper = NULL;
923 else
924 return -EINVAL;
925 }
926
927 if (ct->helper) {
928 if (!helper) {
929 /* we had a helper before ... */
930 nf_ct_remove_expectations(ct);
931 ct->helper = NULL;
932 } else {
933 /* need to zero data of old helper */
934 memset(&ct->help, 0, sizeof(ct->help));
935 }
936 }
937
938 ct->helper = helper;
939
940 return 0;
941}
942
943static inline int
944ctnetlink_change_timeout(struct nf_conn *ct, struct nfattr *cda[])
945{
946 u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
947
948 if (!del_timer(&ct->timeout))
949 return -ETIME;
950
951 ct->timeout.expires = jiffies + timeout * HZ;
952 add_timer(&ct->timeout);
953
954 return 0;
955}
956
957static inline int
958ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[])
959{
960 struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
961 struct nf_conntrack_protocol *proto;
962 u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
963 u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
964 int err = 0;
965
966 nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
967
968 proto = nf_ct_proto_find_get(l3num, npt);
969
970 if (proto->from_nfattr)
971 err = proto->from_nfattr(tb, ct);
972 nf_ct_proto_put(proto);
973
974 return err;
975}
976
977static int
978ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
979{
980 int err;
981
982 DEBUGP("entered %s\n", __FUNCTION__);
983
984 if (cda[CTA_HELP-1]) {
985 err = ctnetlink_change_helper(ct, cda);
986 if (err < 0)
987 return err;
988 }
989
990 if (cda[CTA_TIMEOUT-1]) {
991 err = ctnetlink_change_timeout(ct, cda);
992 if (err < 0)
993 return err;
994 }
995
996 if (cda[CTA_STATUS-1]) {
997 err = ctnetlink_change_status(ct, cda);
998 if (err < 0)
999 return err;
1000 }
1001
1002 if (cda[CTA_PROTOINFO-1]) {
1003 err = ctnetlink_change_protoinfo(ct, cda);
1004 if (err < 0)
1005 return err;
1006 }
1007
1008#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1009 if (cda[CTA_MARK-1])
1010 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1011#endif
1012
1013 DEBUGP("all done\n");
1014 return 0;
1015}
1016
1017static int
1018ctnetlink_create_conntrack(struct nfattr *cda[],
1019 struct nf_conntrack_tuple *otuple,
1020 struct nf_conntrack_tuple *rtuple)
1021{
1022 struct nf_conn *ct;
1023 int err = -EINVAL;
1024
1025 DEBUGP("entered %s\n", __FUNCTION__);
1026
1027 ct = nf_conntrack_alloc(otuple, rtuple);
1028 if (ct == NULL || IS_ERR(ct))
1029 return -ENOMEM;
1030
1031 if (!cda[CTA_TIMEOUT-1])
1032 goto err;
1033 ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
1034
1035 ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
1036 ct->status |= IPS_CONFIRMED;
1037
1038 err = ctnetlink_change_status(ct, cda);
1039 if (err < 0)
1040 goto err;
1041
1042 if (cda[CTA_PROTOINFO-1]) {
1043 err = ctnetlink_change_protoinfo(ct, cda);
1044 if (err < 0)
1045 return err;
1046 }
1047
1048#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
1049 if (cda[CTA_MARK-1])
1050 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1051#endif
1052
1053 ct->helper = nf_ct_helper_find_get(rtuple);
1054
1055 add_timer(&ct->timeout);
1056 nf_conntrack_hash_insert(ct);
1057
1058 if (ct->helper)
1059 nf_ct_helper_put(ct->helper);
1060
1061 DEBUGP("conntrack with id %u inserted\n", ct->id);
1062 return 0;
1063
1064err:
1065 nf_conntrack_free(ct);
1066 return err;
1067}
1068
1069static int
1070ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1071 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1072{
1073 struct nf_conntrack_tuple otuple, rtuple;
1074 struct nf_conntrack_tuple_hash *h = NULL;
1075 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
1076 u_int8_t u3 = nfmsg->nfgen_family;
1077 int err = 0;
1078
1079 DEBUGP("entered %s\n", __FUNCTION__);
1080
1081 if (nfattr_bad_size(cda, CTA_MAX, cta_min))
1082 return -EINVAL;
1083
1084 if (cda[CTA_TUPLE_ORIG-1]) {
1085 err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3);
1086 if (err < 0)
1087 return err;
1088 }
1089
1090 if (cda[CTA_TUPLE_REPLY-1]) {
1091 err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY, u3);
1092 if (err < 0)
1093 return err;
1094 }
1095
1096 write_lock_bh(&nf_conntrack_lock);
1097 if (cda[CTA_TUPLE_ORIG-1])
1098 h = __nf_conntrack_find(&otuple, NULL);
1099 else if (cda[CTA_TUPLE_REPLY-1])
1100 h = __nf_conntrack_find(&rtuple, NULL);
1101
1102 if (h == NULL) {
1103 write_unlock_bh(&nf_conntrack_lock);
1104 DEBUGP("no such conntrack, create new\n");
1105 err = -ENOENT;
1106 if (nlh->nlmsg_flags & NLM_F_CREATE)
1107 err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
1108 return err;
1109 }
1110 /* implicit 'else' */
1111
1112 /* we only allow nat config for new conntracks */
1113 if (cda[CTA_NAT-1]) {
1114 err = -EINVAL;
1115 goto out_unlock;
1116 }
1117
1118 /* We manipulate the conntrack inside the global conntrack table lock,
1119 * so there's no need to increase the refcount */
1120 DEBUGP("conntrack found\n");
1121 err = -EEXIST;
1122 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1123 err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda);
1124
1125out_unlock:
1126 write_unlock_bh(&nf_conntrack_lock);
1127 return err;
1128}
1129
1130/***********************************************************************
1131 * EXPECT
1132 ***********************************************************************/
1133
1134static inline int
1135ctnetlink_exp_dump_tuple(struct sk_buff *skb,
1136 const struct nf_conntrack_tuple *tuple,
1137 enum ctattr_expect type)
1138{
1139 struct nfattr *nest_parms = NFA_NEST(skb, type);
1140
1141 if (ctnetlink_dump_tuples(skb, tuple) < 0)
1142 goto nfattr_failure;
1143
1144 NFA_NEST_END(skb, nest_parms);
1145
1146 return 0;
1147
1148nfattr_failure:
1149 return -1;
1150}
1151
1152static inline int
1153ctnetlink_exp_dump_expect(struct sk_buff *skb,
1154 const struct nf_conntrack_expect *exp)
1155{
1156 struct nf_conn *master = exp->master;
1157 u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
1158 u_int32_t id = htonl(exp->id);
1159
1160 if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
1161 goto nfattr_failure;
1162 if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0)
1163 goto nfattr_failure;
1164 if (ctnetlink_exp_dump_tuple(skb,
1165 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
1166 CTA_EXPECT_MASTER) < 0)
1167 goto nfattr_failure;
1168
1169 NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
1170 NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
1171
1172 return 0;
1173
1174nfattr_failure:
1175 return -1;
1176}
1177
1178static int
1179ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
1180 int event,
1181 int nowait,
1182 const struct nf_conntrack_expect *exp)
1183{
1184 struct nlmsghdr *nlh;
1185 struct nfgenmsg *nfmsg;
1186 unsigned char *b;
1187
1188 b = skb->tail;
1189
1190 event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
1191 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
1192 nfmsg = NLMSG_DATA(nlh);
1193
1194 nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
1195 nfmsg->nfgen_family = exp->tuple.src.l3num;
1196 nfmsg->version = NFNETLINK_V0;
1197 nfmsg->res_id = 0;
1198
1199 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1200 goto nfattr_failure;
1201
1202 nlh->nlmsg_len = skb->tail - b;
1203 return skb->len;
1204
1205nlmsg_failure:
1206nfattr_failure:
1207 skb_trim(skb, b - skb->data);
1208 return -1;
1209}
1210
1211#ifdef CONFIG_NF_CONNTRACK_EVENTS
1212static int ctnetlink_expect_event(struct notifier_block *this,
1213 unsigned long events, void *ptr)
1214{
1215 struct nlmsghdr *nlh;
1216 struct nfgenmsg *nfmsg;
1217 struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr;
1218 struct sk_buff *skb;
1219 unsigned int type;
1220 unsigned char *b;
1221 int flags = 0;
1222
1223 if (events & IPEXP_NEW) {
1224 type = IPCTNL_MSG_EXP_NEW;
1225 flags = NLM_F_CREATE|NLM_F_EXCL;
1226 } else
1227 return NOTIFY_DONE;
1228
1229 skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
1230 if (!skb)
1231 return NOTIFY_DONE;
1232
1233 b = skb->tail;
1234
1235 type |= NFNL_SUBSYS_CTNETLINK << 8;
1236 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
1237 nfmsg = NLMSG_DATA(nlh);
1238
1239 nlh->nlmsg_flags = flags;
1240 nfmsg->nfgen_family = exp->tuple.src.l3num;
1241 nfmsg->version = NFNETLINK_V0;
1242 nfmsg->res_id = 0;
1243
1244 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1245 goto nfattr_failure;
1246
1247 nlh->nlmsg_len = skb->tail - b;
1248 nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
1249 return NOTIFY_DONE;
1250
1251nlmsg_failure:
1252nfattr_failure:
1253 kfree_skb(skb);
1254 return NOTIFY_DONE;
1255}
1256#endif
1257
1258static int
1259ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
1260{
1261 struct nf_conntrack_expect *exp = NULL;
1262 struct list_head *i;
1263 u_int32_t *id = (u_int32_t *) &cb->args[0];
1264 struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
1265 u_int8_t l3proto = nfmsg->nfgen_family;
1266
1267 DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
1268
1269 read_lock_bh(&nf_conntrack_lock);
1270 list_for_each_prev(i, &nf_conntrack_expect_list) {
1271 exp = (struct nf_conntrack_expect *) i;
1272 if (l3proto && exp->tuple.src.l3num != l3proto)
1273 continue;
1274 if (exp->id <= *id)
1275 continue;
1276 if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
1277 cb->nlh->nlmsg_seq,
1278 IPCTNL_MSG_EXP_NEW,
1279 1, exp) < 0)
1280 goto out;
1281 *id = exp->id;
1282 }
1283out:
1284 read_unlock_bh(&nf_conntrack_lock);
1285
1286 DEBUGP("leaving, last id=%llu\n", *id);
1287
1288 return skb->len;
1289}
1290
1291static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
1292 [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t),
1293 [CTA_EXPECT_ID-1] = sizeof(u_int32_t)
1294};
1295
1296static int
1297ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
1298 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1299{
1300 struct nf_conntrack_tuple tuple;
1301 struct nf_conntrack_expect *exp;
1302 struct sk_buff *skb2;
1303 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
1304 u_int8_t u3 = nfmsg->nfgen_family;
1305 int err = 0;
1306
1307 DEBUGP("entered %s\n", __FUNCTION__);
1308
1309 if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1310 return -EINVAL;
1311
1312 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1313 u32 rlen;
1314
1315 if ((*errp = netlink_dump_start(ctnl, skb, nlh,
1316 ctnetlink_exp_dump_table,
1317 ctnetlink_done)) != 0)
1318 return -EINVAL;
1319 rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1320 if (rlen > skb->len)
1321 rlen = skb->len;
1322 skb_pull(skb, rlen);
1323 return 0;
1324 }
1325
1326 if (cda[CTA_EXPECT_MASTER-1])
1327 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
1328 else
1329 return -EINVAL;
1330
1331 if (err < 0)
1332 return err;
1333
1334 exp = nf_conntrack_expect_find(&tuple);
1335 if (!exp)
1336 return -ENOENT;
1337
1338 if (cda[CTA_EXPECT_ID-1]) {
1339 u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1340 if (exp->id != ntohl(id)) {
1341 nf_conntrack_expect_put(exp);
1342 return -ENOENT;
1343 }
1344 }
1345
1346 err = -ENOMEM;
1347 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1348 if (!skb2)
1349 goto out;
1350 NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
1351
1352 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
1353 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1354 1, exp);
1355 if (err <= 0)
1356 goto free;
1357
1358 nf_conntrack_expect_put(exp);
1359
1360 return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
1361
1362free:
1363 kfree_skb(skb2);
1364out:
1365 nf_conntrack_expect_put(exp);
1366 return err;
1367}
1368
1369static int
1370ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1371 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1372{
1373 struct nf_conntrack_expect *exp, *tmp;
1374 struct nf_conntrack_tuple tuple;
1375 struct nf_conntrack_helper *h;
1376 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
1377 u_int8_t u3 = nfmsg->nfgen_family;
1378 int err;
1379
1380 if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1381 return -EINVAL;
1382
1383 if (cda[CTA_EXPECT_TUPLE-1]) {
1384 /* delete a single expect by tuple */
1385 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
1386 if (err < 0)
1387 return err;
1388
1389 /* bump usage count to 2 */
1390 exp = nf_conntrack_expect_find(&tuple);
1391 if (!exp)
1392 return -ENOENT;
1393
1394 if (cda[CTA_EXPECT_ID-1]) {
1395 u_int32_t id =
1396 *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
1397 if (exp->id != ntohl(id)) {
1398 nf_conntrack_expect_put(exp);
1399 return -ENOENT;
1400 }
1401 }
1402
1403 /* after list removal, usage count == 1 */
1404 nf_conntrack_unexpect_related(exp);
1405 /* have to put what we 'get' above.
1406 * after this line usage count == 0 */
1407 nf_conntrack_expect_put(exp);
1408 } else if (cda[CTA_EXPECT_HELP_NAME-1]) {
1409 char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
1410
1411 /* delete all expectations for this helper */
1412 write_lock_bh(&nf_conntrack_lock);
1413 h = __nf_conntrack_helper_find_byname(name);
1414 if (!h) {
1415 write_unlock_bh(&nf_conntrack_lock);
1416 return -EINVAL;
1417 }
1418 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
1419 list) {
1420 if (exp->master->helper == h
1421 && del_timer(&exp->timeout)) {
1422 nf_ct_unlink_expect(exp);
1423 nf_conntrack_expect_put(exp);
1424 }
1425 }
1426 write_unlock_bh(&nf_conntrack_lock);
1427 } else {
1428 /* This basically means we have to flush everything*/
1429 write_lock_bh(&nf_conntrack_lock);
1430 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
1431 list) {
1432 if (del_timer(&exp->timeout)) {
1433 nf_ct_unlink_expect(exp);
1434 nf_conntrack_expect_put(exp);
1435 }
1436 }
1437 write_unlock_bh(&nf_conntrack_lock);
1438 }
1439
1440 return 0;
1441}
1442static int
1443ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nfattr *cda[])
1444{
1445 return -EOPNOTSUPP;
1446}
1447
1448static int
1449ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
1450{
1451 struct nf_conntrack_tuple tuple, mask, master_tuple;
1452 struct nf_conntrack_tuple_hash *h = NULL;
1453 struct nf_conntrack_expect *exp;
1454 struct nf_conn *ct;
1455 int err = 0;
1456
1457 DEBUGP("entered %s\n", __FUNCTION__);
1458
1459 /* caller guarantees that those three CTA_EXPECT_* exist */
1460 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
1461 if (err < 0)
1462 return err;
1463 err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3);
1464 if (err < 0)
1465 return err;
1466 err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3);
1467 if (err < 0)
1468 return err;
1469
1470 /* Look for master conntrack of this expectation */
1471 h = nf_conntrack_find_get(&master_tuple, NULL);
1472 if (!h)
1473 return -ENOENT;
1474 ct = nf_ct_tuplehash_to_ctrack(h);
1475
1476 if (!ct->helper) {
1477 /* such conntrack hasn't got any helper, abort */
1478 err = -EINVAL;
1479 goto out;
1480 }
1481
1482 exp = nf_conntrack_expect_alloc(ct);
1483 if (!exp) {
1484 err = -ENOMEM;
1485 goto out;
1486 }
1487
1488 exp->expectfn = NULL;
1489 exp->flags = 0;
1490 exp->master = ct;
1491 memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
1492 memcpy(&exp->mask, &mask, sizeof(struct nf_conntrack_tuple));
1493
1494 err = nf_conntrack_expect_related(exp);
1495 nf_conntrack_expect_put(exp);
1496
1497out:
1498 nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
1499 return err;
1500}
1501
1502static int
1503ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1504 struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
1505{
1506 struct nf_conntrack_tuple tuple;
1507 struct nf_conntrack_expect *exp;
1508 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
1509 u_int8_t u3 = nfmsg->nfgen_family;
1510 int err = 0;
1511
1512 DEBUGP("entered %s\n", __FUNCTION__);
1513
1514 if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
1515 return -EINVAL;
1516
1517 if (!cda[CTA_EXPECT_TUPLE-1]
1518 || !cda[CTA_EXPECT_MASK-1]
1519 || !cda[CTA_EXPECT_MASTER-1])
1520 return -EINVAL;
1521
1522 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
1523 if (err < 0)
1524 return err;
1525
1526 write_lock_bh(&nf_conntrack_lock);
1527 exp = __nf_conntrack_expect_find(&tuple);
1528
1529 if (!exp) {
1530 write_unlock_bh(&nf_conntrack_lock);
1531 err = -ENOENT;
1532 if (nlh->nlmsg_flags & NLM_F_CREATE)
1533 err = ctnetlink_create_expect(cda, u3);
1534 return err;
1535 }
1536
1537 err = -EEXIST;
1538 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
1539 err = ctnetlink_change_expect(exp, cda);
1540 write_unlock_bh(&nf_conntrack_lock);
1541
1542 DEBUGP("leaving\n");
1543
1544 return err;
1545}
1546
1547#ifdef CONFIG_NF_CONNTRACK_EVENTS
1548static struct notifier_block ctnl_notifier = {
1549 .notifier_call = ctnetlink_conntrack_event,
1550};
1551
1552static struct notifier_block ctnl_notifier_exp = {
1553 .notifier_call = ctnetlink_expect_event,
1554};
1555#endif
1556
1557static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
1558 [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
1559 .attr_count = CTA_MAX, },
1560 [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
1561 .attr_count = CTA_MAX, },
1562 [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
1563 .attr_count = CTA_MAX, },
1564 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
1565 .attr_count = CTA_MAX, },
1566};
1567
1568static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
1569 [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
1570 .attr_count = CTA_EXPECT_MAX, },
1571 [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
1572 .attr_count = CTA_EXPECT_MAX, },
1573 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
1574 .attr_count = CTA_EXPECT_MAX, },
1575};
1576
1577static struct nfnetlink_subsystem ctnl_subsys = {
1578 .name = "conntrack",
1579 .subsys_id = NFNL_SUBSYS_CTNETLINK,
1580 .cb_count = IPCTNL_MSG_MAX,
1581 .cb = ctnl_cb,
1582};
1583
1584static struct nfnetlink_subsystem ctnl_exp_subsys = {
1585 .name = "conntrack_expect",
1586 .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP,
1587 .cb_count = IPCTNL_MSG_EXP_MAX,
1588 .cb = ctnl_exp_cb,
1589};
1590
1591MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
1592
1593static int __init ctnetlink_init(void)
1594{
1595 int ret;
1596
1597 printk("ctnetlink v%s: registering with nfnetlink.\n", version);
1598 ret = nfnetlink_subsys_register(&ctnl_subsys);
1599 if (ret < 0) {
1600 printk("ctnetlink_init: cannot register with nfnetlink.\n");
1601 goto err_out;
1602 }
1603
1604 ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
1605 if (ret < 0) {
1606 printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
1607 goto err_unreg_subsys;
1608 }
1609
1610#ifdef CONFIG_NF_CONNTRACK_EVENTS
1611 ret = nf_conntrack_register_notifier(&ctnl_notifier);
1612 if (ret < 0) {
1613 printk("ctnetlink_init: cannot register notifier.\n");
1614 goto err_unreg_exp_subsys;
1615 }
1616
1617 ret = nf_conntrack_expect_register_notifier(&ctnl_notifier_exp);
1618 if (ret < 0) {
1619 printk("ctnetlink_init: cannot expect register notifier.\n");
1620 goto err_unreg_notifier;
1621 }
1622#endif
1623
1624 return 0;
1625
1626#ifdef CONFIG_NF_CONNTRACK_EVENTS
1627err_unreg_notifier:
1628 nf_conntrack_unregister_notifier(&ctnl_notifier);
1629err_unreg_exp_subsys:
1630 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1631#endif
1632err_unreg_subsys:
1633 nfnetlink_subsys_unregister(&ctnl_subsys);
1634err_out:
1635 return ret;
1636}
1637
1638static void __exit ctnetlink_exit(void)
1639{
1640 printk("ctnetlink: unregistering from nfnetlink.\n");
1641
1642#ifdef CONFIG_NF_CONNTRACK_EVENTS
1643 nf_conntrack_unregister_notifier(&ctnl_notifier_exp);
1644 nf_conntrack_unregister_notifier(&ctnl_notifier);
1645#endif
1646
1647 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
1648 nfnetlink_subsys_unregister(&ctnl_subsys);
1649 return;
1650}
1651
1652module_init(ctnetlink_init);
1653module_exit(ctnetlink_exit);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 6035633d8225..6167137a5cb5 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -1147,6 +1147,63 @@ static int tcp_new(struct nf_conn *conntrack,
1147 receiver->td_scale); 1147 receiver->td_scale);
1148 return 1; 1148 return 1;
1149} 1149}
1150
1151#if defined(CONFIG_NF_CT_NETLINK) || \
1152 defined(CONFIG_NF_CT_NETLINK_MODULE)
1153
1154#include <linux/netfilter/nfnetlink.h>
1155#include <linux/netfilter/nfnetlink_conntrack.h>
1156
1157static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
1158 const struct nf_conn *ct)
1159{
1160 struct nfattr *nest_parms;
1161
1162 read_lock_bh(&tcp_lock);
1163 nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
1164 NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
1165 &ct->proto.tcp.state);
1166 read_unlock_bh(&tcp_lock);
1167
1168 NFA_NEST_END(skb, nest_parms);
1169
1170 return 0;
1171
1172nfattr_failure:
1173 read_unlock_bh(&tcp_lock);
1174 return -1;
1175}
1176
1177static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = {
1178 [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t),
1179};
1180
1181static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct)
1182{
1183 struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1];
1184 struct nfattr *tb[CTA_PROTOINFO_TCP_MAX];
1185
1186 /* updates could not contain anything about the private
1187 * protocol info, in that case skip the parsing */
1188 if (!attr)
1189 return 0;
1190
1191 nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
1192
1193 if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp))
1194 return -EINVAL;
1195
1196 if (!tb[CTA_PROTOINFO_TCP_STATE-1])
1197 return -EINVAL;
1198
1199 write_lock_bh(&tcp_lock);
1200 ct->proto.tcp.state =
1201 *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
1202 write_unlock_bh(&tcp_lock);
1203
1204 return 0;
1205}
1206#endif
1150 1207
1151struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = 1208struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
1152{ 1209{
@@ -1160,6 +1217,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
1160 .packet = tcp_packet, 1217 .packet = tcp_packet,
1161 .new = tcp_new, 1218 .new = tcp_new,
1162 .error = tcp_error4, 1219 .error = tcp_error4,
1220#if defined(CONFIG_NF_CT_NETLINK) || \
1221 defined(CONFIG_NF_CT_NETLINK_MODULE)
1222 .to_nfattr = tcp_to_nfattr,
1223 .from_nfattr = nfattr_to_tcp,
1224 .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
1225 .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
1226#endif
1163}; 1227};
1164 1228
1165struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = 1229struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
@@ -1174,6 +1238,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
1174 .packet = tcp_packet, 1238 .packet = tcp_packet,
1175 .new = tcp_new, 1239 .new = tcp_new,
1176 .error = tcp_error6, 1240 .error = tcp_error6,
1241#if defined(CONFIG_NF_CT_NETLINK) || \
1242 defined(CONFIG_NF_CT_NETLINK_MODULE)
1243 .to_nfattr = tcp_to_nfattr,
1244 .from_nfattr = nfattr_to_tcp,
1245 .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
1246 .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
1247#endif
1177}; 1248};
1178 1249
1179EXPORT_SYMBOL(nf_conntrack_protocol_tcp4); 1250EXPORT_SYMBOL(nf_conntrack_protocol_tcp4);
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 3cae7ce420dd..1a592a556182 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -196,6 +196,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
196 .packet = udp_packet, 196 .packet = udp_packet,
197 .new = udp_new, 197 .new = udp_new,
198 .error = udp_error4, 198 .error = udp_error4,
199#if defined(CONFIG_NF_CT_NETLINK) || \
200 defined(CONFIG_NF_CT_NETLINK_MODULE)
201 .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
202 .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
203#endif
199}; 204};
200 205
201struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = 206struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
@@ -210,6 +215,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
210 .packet = udp_packet, 215 .packet = udp_packet,
211 .new = udp_new, 216 .new = udp_new,
212 .error = udp_error6, 217 .error = udp_error6,
218#if defined(CONFIG_NF_CT_NETLINK) || \
219 defined(CONFIG_NF_CT_NETLINK_MODULE)
220 .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
221 .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
222#endif
213}; 223};
214 224
215EXPORT_SYMBOL(nf_conntrack_protocol_udp4); 225EXPORT_SYMBOL(nf_conntrack_protocol_udp4);
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 5af381f9fe3d..d17e42b28c79 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -161,14 +161,14 @@ static int ct_seq_show(struct seq_file *s, void *v)
161 if (NF_CT_DIRECTION(hash)) 161 if (NF_CT_DIRECTION(hash))
162 return 0; 162 return 0;
163 163
164 l3proto = nf_ct_find_l3proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] 164 l3proto = __nf_ct_l3proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
165 .tuple.src.l3num); 165 .tuple.src.l3num);
166 166
167 NF_CT_ASSERT(l3proto); 167 NF_CT_ASSERT(l3proto);
168 proto = nf_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] 168 proto = __nf_ct_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
169 .tuple.src.l3num, 169 .tuple.src.l3num,
170 conntrack->tuplehash[IP_CT_DIR_ORIGINAL] 170 conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
171 .tuple.dst.protonum); 171 .tuple.dst.protonum);
172 NF_CT_ASSERT(proto); 172 NF_CT_ASSERT(proto);
173 173
174 if (seq_printf(s, "%-8s %u %-8s %u %ld ", 174 if (seq_printf(s, "%-8s %u %-8s %u %ld ",
@@ -307,9 +307,9 @@ static int exp_seq_show(struct seq_file *s, void *v)
307 expect->tuple.src.l3num, 307 expect->tuple.src.l3num,
308 expect->tuple.dst.protonum); 308 expect->tuple.dst.protonum);
309 print_tuple(s, &expect->tuple, 309 print_tuple(s, &expect->tuple,
310 nf_ct_find_l3proto(expect->tuple.src.l3num), 310 __nf_ct_l3proto_find(expect->tuple.src.l3num),
311 nf_ct_find_proto(expect->tuple.src.l3num, 311 __nf_ct_proto_find(expect->tuple.src.l3num,
312 expect->tuple.dst.protonum)); 312 expect->tuple.dst.protonum));
313 return seq_putc(s, '\n'); 313 return seq_putc(s, '\n');
314} 314}
315 315
@@ -847,7 +847,11 @@ EXPORT_SYMBOL(nf_conntrack_helper_unregister);
847EXPORT_SYMBOL(nf_ct_iterate_cleanup); 847EXPORT_SYMBOL(nf_ct_iterate_cleanup);
848EXPORT_SYMBOL(__nf_ct_refresh_acct); 848EXPORT_SYMBOL(__nf_ct_refresh_acct);
849EXPORT_SYMBOL(nf_ct_protos); 849EXPORT_SYMBOL(nf_ct_protos);
850EXPORT_SYMBOL(nf_ct_find_proto); 850EXPORT_SYMBOL(__nf_ct_proto_find);
851EXPORT_SYMBOL(nf_ct_proto_find_get);
852EXPORT_SYMBOL(nf_ct_proto_put);
853EXPORT_SYMBOL(nf_ct_l3proto_find_get);
854EXPORT_SYMBOL(nf_ct_l3proto_put);
851EXPORT_SYMBOL(nf_ct_l3protos); 855EXPORT_SYMBOL(nf_ct_l3protos);
852EXPORT_SYMBOL(nf_conntrack_expect_alloc); 856EXPORT_SYMBOL(nf_conntrack_expect_alloc);
853EXPORT_SYMBOL(nf_conntrack_expect_put); 857EXPORT_SYMBOL(nf_conntrack_expect_put);
@@ -867,3 +871,21 @@ EXPORT_SYMBOL(nf_ct_get_tuple);
867EXPORT_SYMBOL(nf_ct_invert_tuple); 871EXPORT_SYMBOL(nf_ct_invert_tuple);
868EXPORT_SYMBOL(nf_conntrack_in); 872EXPORT_SYMBOL(nf_conntrack_in);
869EXPORT_SYMBOL(__nf_conntrack_attach); 873EXPORT_SYMBOL(__nf_conntrack_attach);
874EXPORT_SYMBOL(nf_conntrack_alloc);
875EXPORT_SYMBOL(nf_conntrack_free);
876EXPORT_SYMBOL(nf_conntrack_flush);
877EXPORT_SYMBOL(nf_ct_remove_expectations);
878EXPORT_SYMBOL(nf_ct_helper_find_get);
879EXPORT_SYMBOL(nf_ct_helper_put);
880EXPORT_SYMBOL(__nf_conntrack_helper_find_byname);
881EXPORT_SYMBOL(__nf_conntrack_find);
882EXPORT_SYMBOL(nf_ct_unlink_expect);
883EXPORT_SYMBOL(nf_conntrack_hash_insert);
884EXPORT_SYMBOL(__nf_conntrack_expect_find);
885EXPORT_SYMBOL(nf_conntrack_expect_find);
886EXPORT_SYMBOL(nf_conntrack_expect_list);
887#if defined(CONFIG_NF_CT_NETLINK) || \
888 defined(CONFIG_NF_CT_NETLINK_MODULE)
889EXPORT_SYMBOL(nf_ct_port_tuple_to_nfattr);
890EXPORT_SYMBOL(nf_ct_port_nfattr_to_tuple);
891#endif
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 55afdda3d940..18ed9c5d209c 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -345,6 +345,10 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
345 struct nfqnl_msg_packet_hdr pmsg; 345 struct nfqnl_msg_packet_hdr pmsg;
346 struct nlmsghdr *nlh; 346 struct nlmsghdr *nlh;
347 struct nfgenmsg *nfmsg; 347 struct nfgenmsg *nfmsg;
348 struct nf_info *entinf = entry->info;
349 struct sk_buff *entskb = entry->skb;
350 struct net_device *indev;
351 struct net_device *outdev;
348 unsigned int tmp_uint; 352 unsigned int tmp_uint;
349 353
350 QDEBUG("entered\n"); 354 QDEBUG("entered\n");
@@ -361,6 +365,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
361 + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw)) 365 + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw))
362 + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp)); 366 + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp));
363 367
368 outdev = entinf->outdev;
369
364 spin_lock_bh(&queue->lock); 370 spin_lock_bh(&queue->lock);
365 371
366 switch (queue->copy_mode) { 372 switch (queue->copy_mode) {
@@ -370,15 +376,15 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
370 break; 376 break;
371 377
372 case NFQNL_COPY_PACKET: 378 case NFQNL_COPY_PACKET:
373 if (entry->skb->ip_summed == CHECKSUM_HW && 379 if (entskb->ip_summed == CHECKSUM_HW &&
374 (*errp = skb_checksum_help(entry->skb, 380 (*errp = skb_checksum_help(entskb,
375 entry->info->outdev == NULL))) { 381 outdev == NULL))) {
376 spin_unlock_bh(&queue->lock); 382 spin_unlock_bh(&queue->lock);
377 return NULL; 383 return NULL;
378 } 384 }
379 if (queue->copy_range == 0 385 if (queue->copy_range == 0
380 || queue->copy_range > entry->skb->len) 386 || queue->copy_range > entskb->len)
381 data_len = entry->skb->len; 387 data_len = entskb->len;
382 else 388 else
383 data_len = queue->copy_range; 389 data_len = queue->copy_range;
384 390
@@ -402,29 +408,30 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
402 NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, 408 NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
403 sizeof(struct nfgenmsg)); 409 sizeof(struct nfgenmsg));
404 nfmsg = NLMSG_DATA(nlh); 410 nfmsg = NLMSG_DATA(nlh);
405 nfmsg->nfgen_family = entry->info->pf; 411 nfmsg->nfgen_family = entinf->pf;
406 nfmsg->version = NFNETLINK_V0; 412 nfmsg->version = NFNETLINK_V0;
407 nfmsg->res_id = htons(queue->queue_num); 413 nfmsg->res_id = htons(queue->queue_num);
408 414
409 pmsg.packet_id = htonl(entry->id); 415 pmsg.packet_id = htonl(entry->id);
410 pmsg.hw_protocol = htons(entry->skb->protocol); 416 pmsg.hw_protocol = htons(entskb->protocol);
411 pmsg.hook = entry->info->hook; 417 pmsg.hook = entinf->hook;
412 418
413 NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); 419 NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg);
414 420
415 if (entry->info->indev) { 421 indev = entinf->indev;
416 tmp_uint = htonl(entry->info->indev->ifindex); 422 if (indev) {
423 tmp_uint = htonl(indev->ifindex);
417#ifndef CONFIG_BRIDGE_NETFILTER 424#ifndef CONFIG_BRIDGE_NETFILTER
418 NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); 425 NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint);
419#else 426#else
420 if (entry->info->pf == PF_BRIDGE) { 427 if (entinf->pf == PF_BRIDGE) {
421 /* Case 1: indev is physical input device, we need to 428 /* Case 1: indev is physical input device, we need to
422 * look for bridge group (when called from 429 * look for bridge group (when called from
423 * netfilter_bridge) */ 430 * netfilter_bridge) */
424 NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), 431 NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint),
425 &tmp_uint); 432 &tmp_uint);
426 /* this is the bridge group "brX" */ 433 /* this is the bridge group "brX" */
427 tmp_uint = htonl(entry->info->indev->br_port->br->dev->ifindex); 434 tmp_uint = htonl(indev->br_port->br->dev->ifindex);
428 NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), 435 NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
429 &tmp_uint); 436 &tmp_uint);
430 } else { 437 } else {
@@ -432,9 +439,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
432 * physical device (when called from ipv4) */ 439 * physical device (when called from ipv4) */
433 NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), 440 NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
434 &tmp_uint); 441 &tmp_uint);
435 if (entry->skb->nf_bridge 442 if (entskb->nf_bridge
436 && entry->skb->nf_bridge->physindev) { 443 && entskb->nf_bridge->physindev) {
437 tmp_uint = htonl(entry->skb->nf_bridge->physindev->ifindex); 444 tmp_uint = htonl(entskb->nf_bridge->physindev->ifindex);
438 NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, 445 NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV,
439 sizeof(tmp_uint), &tmp_uint); 446 sizeof(tmp_uint), &tmp_uint);
440 } 447 }
@@ -442,19 +449,19 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
442#endif 449#endif
443 } 450 }
444 451
445 if (entry->info->outdev) { 452 if (outdev) {
446 tmp_uint = htonl(entry->info->outdev->ifindex); 453 tmp_uint = htonl(outdev->ifindex);
447#ifndef CONFIG_BRIDGE_NETFILTER 454#ifndef CONFIG_BRIDGE_NETFILTER
448 NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); 455 NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint);
449#else 456#else
450 if (entry->info->pf == PF_BRIDGE) { 457 if (entinf->pf == PF_BRIDGE) {
451 /* Case 1: outdev is physical output device, we need to 458 /* Case 1: outdev is physical output device, we need to
452 * look for bridge group (when called from 459 * look for bridge group (when called from
453 * netfilter_bridge) */ 460 * netfilter_bridge) */
454 NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), 461 NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint),
455 &tmp_uint); 462 &tmp_uint);
456 /* this is the bridge group "brX" */ 463 /* this is the bridge group "brX" */
457 tmp_uint = htonl(entry->info->outdev->br_port->br->dev->ifindex); 464 tmp_uint = htonl(outdev->br_port->br->dev->ifindex);
458 NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), 465 NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
459 &tmp_uint); 466 &tmp_uint);
460 } else { 467 } else {
@@ -462,9 +469,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
462 * physical output device (when called from ipv4) */ 469 * physical output device (when called from ipv4) */
463 NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), 470 NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
464 &tmp_uint); 471 &tmp_uint);
465 if (entry->skb->nf_bridge 472 if (entskb->nf_bridge
466 && entry->skb->nf_bridge->physoutdev) { 473 && entskb->nf_bridge->physoutdev) {
467 tmp_uint = htonl(entry->skb->nf_bridge->physoutdev->ifindex); 474 tmp_uint = htonl(entskb->nf_bridge->physoutdev->ifindex);
468 NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, 475 NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV,
469 sizeof(tmp_uint), &tmp_uint); 476 sizeof(tmp_uint), &tmp_uint);
470 } 477 }
@@ -472,27 +479,27 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
472#endif 479#endif
473 } 480 }
474 481
475 if (entry->skb->nfmark) { 482 if (entskb->nfmark) {
476 tmp_uint = htonl(entry->skb->nfmark); 483 tmp_uint = htonl(entskb->nfmark);
477 NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); 484 NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint);
478 } 485 }
479 486
480 if (entry->info->indev && entry->skb->dev 487 if (indev && entskb->dev
481 && entry->skb->dev->hard_header_parse) { 488 && entskb->dev->hard_header_parse) {
482 struct nfqnl_msg_packet_hw phw; 489 struct nfqnl_msg_packet_hw phw;
483 490
484 phw.hw_addrlen = 491 phw.hw_addrlen =
485 entry->skb->dev->hard_header_parse(entry->skb, 492 entskb->dev->hard_header_parse(entskb,
486 phw.hw_addr); 493 phw.hw_addr);
487 phw.hw_addrlen = htons(phw.hw_addrlen); 494 phw.hw_addrlen = htons(phw.hw_addrlen);
488 NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); 495 NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
489 } 496 }
490 497
491 if (entry->skb->tstamp.off_sec) { 498 if (entskb->tstamp.off_sec) {
492 struct nfqnl_msg_packet_timestamp ts; 499 struct nfqnl_msg_packet_timestamp ts;
493 500
494 ts.sec = cpu_to_be64(entry->skb->tstamp.off_sec); 501 ts.sec = cpu_to_be64(entskb->tstamp.off_sec);
495 ts.usec = cpu_to_be64(entry->skb->tstamp.off_usec); 502 ts.usec = cpu_to_be64(entskb->tstamp.off_usec);
496 503
497 NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); 504 NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
498 } 505 }
@@ -510,7 +517,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
510 nfa->nfa_type = NFQA_PAYLOAD; 517 nfa->nfa_type = NFQA_PAYLOAD;
511 nfa->nfa_len = size; 518 nfa->nfa_len = size;
512 519
513 if (skb_copy_bits(entry->skb, 0, NFA_DATA(nfa), data_len)) 520 if (skb_copy_bits(entskb, 0, NFA_DATA(nfa), data_len))
514 BUG(); 521 BUG();
515 } 522 }
516 523
@@ -667,12 +674,14 @@ nfqnl_set_mode(struct nfqnl_instance *queue,
667static int 674static int
668dev_cmp(struct nfqnl_queue_entry *entry, unsigned long ifindex) 675dev_cmp(struct nfqnl_queue_entry *entry, unsigned long ifindex)
669{ 676{
670 if (entry->info->indev) 677 struct nf_info *entinf = entry->info;
671 if (entry->info->indev->ifindex == ifindex) 678
679 if (entinf->indev)
680 if (entinf->indev->ifindex == ifindex)
672 return 1; 681 return 1;
673 682
674 if (entry->info->outdev) 683 if (entinf->outdev)
675 if (entry->info->outdev->ifindex == ifindex) 684 if (entinf->outdev->ifindex == ifindex)
676 return 1; 685 return 1;
677 686
678 return 0; 687 return 0;