Commit 83d213fd9d1a56108584cd812333462caa39a747
Committed by
Pablo Neira Ayuso
1 parent
9976fc6e6e
netfilter: conntrack: deconstify packet callback skb pointer
Only two protocols need the ->error() function: icmp and icmpv6. This is because icmp error mssages might be RELATED to an existing connection (e.g. PMTUD, port unreachable and the like), and their ->error() handlers do this. The error callback is already optional, so remove it for udp and call them from ->packet() instead. As the error() callback can call checksum functions that write to skb->csum*, the const qualifier has to be removed as well. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 9 changed files with 95 additions and 64 deletions Inline Diff
- include/net/netfilter/nf_conntrack_l4proto.h
- net/netfilter/nf_conntrack_proto_dccp.c
- net/netfilter/nf_conntrack_proto_generic.c
- net/netfilter/nf_conntrack_proto_gre.c
- net/netfilter/nf_conntrack_proto_icmp.c
- net/netfilter/nf_conntrack_proto_icmpv6.c
- net/netfilter/nf_conntrack_proto_sctp.c
- net/netfilter/nf_conntrack_proto_tcp.c
- net/netfilter/nf_conntrack_proto_udp.c
include/net/netfilter/nf_conntrack_l4proto.h
1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | 2 | /* |
3 | * Header for use in defining a given L4 protocol for connection tracking. | 3 | * Header for use in defining a given L4 protocol for connection tracking. |
4 | * | 4 | * |
5 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | 5 | * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> |
6 | * - generalized L3 protocol dependent part. | 6 | * - generalized L3 protocol dependent part. |
7 | * | 7 | * |
8 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h | 8 | * Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef _NF_CONNTRACK_L4PROTO_H | 11 | #ifndef _NF_CONNTRACK_L4PROTO_H |
12 | #define _NF_CONNTRACK_L4PROTO_H | 12 | #define _NF_CONNTRACK_L4PROTO_H |
13 | #include <linux/netlink.h> | 13 | #include <linux/netlink.h> |
14 | #include <net/netlink.h> | 14 | #include <net/netlink.h> |
15 | #include <net/netfilter/nf_conntrack.h> | 15 | #include <net/netfilter/nf_conntrack.h> |
16 | #include <net/netns/generic.h> | 16 | #include <net/netns/generic.h> |
17 | 17 | ||
18 | struct seq_file; | 18 | struct seq_file; |
19 | 19 | ||
20 | struct nf_conntrack_l4proto { | 20 | struct nf_conntrack_l4proto { |
21 | /* L3 Protocol number. */ | 21 | /* L3 Protocol number. */ |
22 | u_int16_t l3proto; | 22 | u_int16_t l3proto; |
23 | 23 | ||
24 | /* L4 Protocol number. */ | 24 | /* L4 Protocol number. */ |
25 | u_int8_t l4proto; | 25 | u_int8_t l4proto; |
26 | 26 | ||
27 | /* Resolve clashes on insertion races. */ | 27 | /* Resolve clashes on insertion races. */ |
28 | bool allow_clash; | 28 | bool allow_clash; |
29 | 29 | ||
30 | /* protoinfo nlattr size, closes a hole */ | 30 | /* protoinfo nlattr size, closes a hole */ |
31 | u16 nlattr_size; | 31 | u16 nlattr_size; |
32 | 32 | ||
33 | /* Try to fill in the third arg: dataoff is offset past network protocol | 33 | /* Try to fill in the third arg: dataoff is offset past network protocol |
34 | hdr. Return true if possible. */ | 34 | hdr. Return true if possible. */ |
35 | bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff, | 35 | bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff, |
36 | struct net *net, struct nf_conntrack_tuple *tuple); | 36 | struct net *net, struct nf_conntrack_tuple *tuple); |
37 | 37 | ||
38 | /* Invert the per-proto part of the tuple: ie. turn xmit into reply. | 38 | /* Invert the per-proto part of the tuple: ie. turn xmit into reply. |
39 | * Only used by icmp, most protocols use a generic version. | 39 | * Only used by icmp, most protocols use a generic version. |
40 | */ | 40 | */ |
41 | bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, | 41 | bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, |
42 | const struct nf_conntrack_tuple *orig); | 42 | const struct nf_conntrack_tuple *orig); |
43 | 43 | ||
44 | /* Returns verdict for packet, or -1 for invalid. */ | 44 | /* Returns verdict for packet, or -1 for invalid. */ |
45 | int (*packet)(struct nf_conn *ct, | 45 | int (*packet)(struct nf_conn *ct, |
46 | const struct sk_buff *skb, | 46 | struct sk_buff *skb, |
47 | unsigned int dataoff, | 47 | unsigned int dataoff, |
48 | enum ip_conntrack_info ctinfo, | 48 | enum ip_conntrack_info ctinfo, |
49 | const struct nf_hook_state *state); | 49 | const struct nf_hook_state *state); |
50 | 50 | ||
51 | /* Called when a conntrack entry is destroyed */ | 51 | /* Called when a conntrack entry is destroyed */ |
52 | void (*destroy)(struct nf_conn *ct); | 52 | void (*destroy)(struct nf_conn *ct); |
53 | 53 | ||
54 | int (*error)(struct nf_conn *tmpl, struct sk_buff *skb, | 54 | int (*error)(struct nf_conn *tmpl, struct sk_buff *skb, |
55 | unsigned int dataoff, | 55 | unsigned int dataoff, |
56 | const struct nf_hook_state *state); | 56 | const struct nf_hook_state *state); |
57 | 57 | ||
58 | /* called by gc worker if table is full */ | 58 | /* called by gc worker if table is full */ |
59 | bool (*can_early_drop)(const struct nf_conn *ct); | 59 | bool (*can_early_drop)(const struct nf_conn *ct); |
60 | 60 | ||
61 | /* convert protoinfo to nfnetink attributes */ | 61 | /* convert protoinfo to nfnetink attributes */ |
62 | int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, | 62 | int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, |
63 | struct nf_conn *ct); | 63 | struct nf_conn *ct); |
64 | 64 | ||
65 | /* convert nfnetlink attributes to protoinfo */ | 65 | /* convert nfnetlink attributes to protoinfo */ |
66 | int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); | 66 | int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); |
67 | 67 | ||
68 | int (*tuple_to_nlattr)(struct sk_buff *skb, | 68 | int (*tuple_to_nlattr)(struct sk_buff *skb, |
69 | const struct nf_conntrack_tuple *t); | 69 | const struct nf_conntrack_tuple *t); |
70 | /* Calculate tuple nlattr size */ | 70 | /* Calculate tuple nlattr size */ |
71 | unsigned int (*nlattr_tuple_size)(void); | 71 | unsigned int (*nlattr_tuple_size)(void); |
72 | int (*nlattr_to_tuple)(struct nlattr *tb[], | 72 | int (*nlattr_to_tuple)(struct nlattr *tb[], |
73 | struct nf_conntrack_tuple *t); | 73 | struct nf_conntrack_tuple *t); |
74 | const struct nla_policy *nla_policy; | 74 | const struct nla_policy *nla_policy; |
75 | 75 | ||
76 | struct { | 76 | struct { |
77 | int (*nlattr_to_obj)(struct nlattr *tb[], | 77 | int (*nlattr_to_obj)(struct nlattr *tb[], |
78 | struct net *net, void *data); | 78 | struct net *net, void *data); |
79 | int (*obj_to_nlattr)(struct sk_buff *skb, const void *data); | 79 | int (*obj_to_nlattr)(struct sk_buff *skb, const void *data); |
80 | 80 | ||
81 | u16 obj_size; | 81 | u16 obj_size; |
82 | u16 nlattr_max; | 82 | u16 nlattr_max; |
83 | const struct nla_policy *nla_policy; | 83 | const struct nla_policy *nla_policy; |
84 | } ctnl_timeout; | 84 | } ctnl_timeout; |
85 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 85 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
86 | /* Print out the private part of the conntrack. */ | 86 | /* Print out the private part of the conntrack. */ |
87 | void (*print_conntrack)(struct seq_file *s, struct nf_conn *); | 87 | void (*print_conntrack)(struct seq_file *s, struct nf_conn *); |
88 | #endif | 88 | #endif |
89 | unsigned int *net_id; | 89 | unsigned int *net_id; |
90 | /* Init l4proto pernet data */ | 90 | /* Init l4proto pernet data */ |
91 | int (*init_net)(struct net *net, u_int16_t proto); | 91 | int (*init_net)(struct net *net, u_int16_t proto); |
92 | 92 | ||
93 | /* Return the per-net protocol part. */ | 93 | /* Return the per-net protocol part. */ |
94 | struct nf_proto_net *(*get_net_proto)(struct net *net); | 94 | struct nf_proto_net *(*get_net_proto)(struct net *net); |
95 | 95 | ||
96 | /* Module (if any) which this is connected to. */ | 96 | /* Module (if any) which this is connected to. */ |
97 | struct module *me; | 97 | struct module *me; |
98 | }; | 98 | }; |
99 | 99 | ||
100 | /* Existing built-in generic protocol */ | 100 | /* Existing built-in generic protocol */ |
101 | extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; | 101 | extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; |
102 | 102 | ||
103 | #define MAX_NF_CT_PROTO 256 | 103 | #define MAX_NF_CT_PROTO 256 |
104 | 104 | ||
105 | const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u_int16_t l3proto, | 105 | const struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u_int16_t l3proto, |
106 | u_int8_t l4proto); | 106 | u_int8_t l4proto); |
107 | 107 | ||
108 | const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u_int16_t l3proto, | 108 | const struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u_int16_t l3proto, |
109 | u_int8_t l4proto); | 109 | u_int8_t l4proto); |
110 | void nf_ct_l4proto_put(const struct nf_conntrack_l4proto *p); | 110 | void nf_ct_l4proto_put(const struct nf_conntrack_l4proto *p); |
111 | 111 | ||
112 | /* Protocol pernet registration. */ | 112 | /* Protocol pernet registration. */ |
113 | int nf_ct_l4proto_pernet_register_one(struct net *net, | 113 | int nf_ct_l4proto_pernet_register_one(struct net *net, |
114 | const struct nf_conntrack_l4proto *proto); | 114 | const struct nf_conntrack_l4proto *proto); |
115 | void nf_ct_l4proto_pernet_unregister_one(struct net *net, | 115 | void nf_ct_l4proto_pernet_unregister_one(struct net *net, |
116 | const struct nf_conntrack_l4proto *proto); | 116 | const struct nf_conntrack_l4proto *proto); |
117 | int nf_ct_l4proto_pernet_register(struct net *net, | 117 | int nf_ct_l4proto_pernet_register(struct net *net, |
118 | const struct nf_conntrack_l4proto *const proto[], | 118 | const struct nf_conntrack_l4proto *const proto[], |
119 | unsigned int num_proto); | 119 | unsigned int num_proto); |
120 | void nf_ct_l4proto_pernet_unregister(struct net *net, | 120 | void nf_ct_l4proto_pernet_unregister(struct net *net, |
121 | const struct nf_conntrack_l4proto *const proto[], | 121 | const struct nf_conntrack_l4proto *const proto[], |
122 | unsigned int num_proto); | 122 | unsigned int num_proto); |
123 | 123 | ||
124 | /* Protocol global registration. */ | 124 | /* Protocol global registration. */ |
125 | int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *proto); | 125 | int nf_ct_l4proto_register_one(const struct nf_conntrack_l4proto *proto); |
126 | void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *proto); | 126 | void nf_ct_l4proto_unregister_one(const struct nf_conntrack_l4proto *proto); |
127 | 127 | ||
128 | /* Generic netlink helpers */ | 128 | /* Generic netlink helpers */ |
129 | int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, | 129 | int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, |
130 | const struct nf_conntrack_tuple *tuple); | 130 | const struct nf_conntrack_tuple *tuple); |
131 | int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], | 131 | int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], |
132 | struct nf_conntrack_tuple *t); | 132 | struct nf_conntrack_tuple *t); |
133 | unsigned int nf_ct_port_nlattr_tuple_size(void); | 133 | unsigned int nf_ct_port_nlattr_tuple_size(void); |
134 | extern const struct nla_policy nf_ct_port_nla_policy[]; | 134 | extern const struct nla_policy nf_ct_port_nla_policy[]; |
135 | 135 | ||
136 | #ifdef CONFIG_SYSCTL | 136 | #ifdef CONFIG_SYSCTL |
137 | __printf(3, 4) __cold | 137 | __printf(3, 4) __cold |
138 | void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, | 138 | void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, |
139 | const struct nf_conn *ct, | 139 | const struct nf_conn *ct, |
140 | const char *fmt, ...); | 140 | const char *fmt, ...); |
141 | __printf(5, 6) __cold | 141 | __printf(5, 6) __cold |
142 | void nf_l4proto_log_invalid(const struct sk_buff *skb, | 142 | void nf_l4proto_log_invalid(const struct sk_buff *skb, |
143 | struct net *net, | 143 | struct net *net, |
144 | u16 pf, u8 protonum, | 144 | u16 pf, u8 protonum, |
145 | const char *fmt, ...); | 145 | const char *fmt, ...); |
146 | #else | 146 | #else |
147 | static inline __printf(5, 6) __cold | 147 | static inline __printf(5, 6) __cold |
148 | void nf_l4proto_log_invalid(const struct sk_buff *skb, struct net *net, | 148 | void nf_l4proto_log_invalid(const struct sk_buff *skb, struct net *net, |
149 | u16 pf, u8 protonum, const char *fmt, ...) {} | 149 | u16 pf, u8 protonum, const char *fmt, ...) {} |
150 | static inline __printf(3, 4) __cold | 150 | static inline __printf(3, 4) __cold |
151 | void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, | 151 | void nf_ct_l4proto_log_invalid(const struct sk_buff *skb, |
152 | const struct nf_conn *ct, | 152 | const struct nf_conn *ct, |
153 | const char *fmt, ...) { } | 153 | const char *fmt, ...) { } |
154 | #endif /* CONFIG_SYSCTL */ | 154 | #endif /* CONFIG_SYSCTL */ |
155 | 155 | ||
156 | #endif /*_NF_CONNTRACK_PROTOCOL_H*/ | 156 | #endif /*_NF_CONNTRACK_PROTOCOL_H*/ |
157 | 157 |
net/netfilter/nf_conntrack_proto_dccp.c
1 | /* | 1 | /* |
2 | * DCCP connection tracking protocol helper | 2 | * DCCP connection tracking protocol helper |
3 | * | 3 | * |
4 | * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net> | 4 | * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/sysctl.h> | 13 | #include <linux/sysctl.h> |
14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/dccp.h> | 16 | #include <linux/dccp.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | 18 | ||
19 | #include <net/net_namespace.h> | 19 | #include <net/net_namespace.h> |
20 | #include <net/netns/generic.h> | 20 | #include <net/netns/generic.h> |
21 | 21 | ||
22 | #include <linux/netfilter/nfnetlink_conntrack.h> | 22 | #include <linux/netfilter/nfnetlink_conntrack.h> |
23 | #include <net/netfilter/nf_conntrack.h> | 23 | #include <net/netfilter/nf_conntrack.h> |
24 | #include <net/netfilter/nf_conntrack_l4proto.h> | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
25 | #include <net/netfilter/nf_conntrack_ecache.h> | 25 | #include <net/netfilter/nf_conntrack_ecache.h> |
26 | #include <net/netfilter/nf_conntrack_timeout.h> | 26 | #include <net/netfilter/nf_conntrack_timeout.h> |
27 | #include <net/netfilter/nf_log.h> | 27 | #include <net/netfilter/nf_log.h> |
28 | 28 | ||
29 | /* Timeouts are based on values from RFC4340: | 29 | /* Timeouts are based on values from RFC4340: |
30 | * | 30 | * |
31 | * - REQUEST: | 31 | * - REQUEST: |
32 | * | 32 | * |
33 | * 8.1.2. Client Request | 33 | * 8.1.2. Client Request |
34 | * | 34 | * |
35 | * A client MAY give up on its DCCP-Requests after some time | 35 | * A client MAY give up on its DCCP-Requests after some time |
36 | * (3 minutes, for example). | 36 | * (3 minutes, for example). |
37 | * | 37 | * |
38 | * - RESPOND: | 38 | * - RESPOND: |
39 | * | 39 | * |
40 | * 8.1.3. Server Response | 40 | * 8.1.3. Server Response |
41 | * | 41 | * |
42 | * It MAY also leave the RESPOND state for CLOSED after a timeout of | 42 | * It MAY also leave the RESPOND state for CLOSED after a timeout of |
43 | * not less than 4MSL (8 minutes); | 43 | * not less than 4MSL (8 minutes); |
44 | * | 44 | * |
45 | * - PARTOPEN: | 45 | * - PARTOPEN: |
46 | * | 46 | * |
47 | * 8.1.5. Handshake Completion | 47 | * 8.1.5. Handshake Completion |
48 | * | 48 | * |
49 | * If the client remains in PARTOPEN for more than 4MSL (8 minutes), | 49 | * If the client remains in PARTOPEN for more than 4MSL (8 minutes), |
50 | * it SHOULD reset the connection with Reset Code 2, "Aborted". | 50 | * it SHOULD reset the connection with Reset Code 2, "Aborted". |
51 | * | 51 | * |
52 | * - OPEN: | 52 | * - OPEN: |
53 | * | 53 | * |
54 | * The DCCP timestamp overflows after 11.9 hours. If the connection | 54 | * The DCCP timestamp overflows after 11.9 hours. If the connection |
55 | * stays idle this long the sequence number won't be recognized | 55 | * stays idle this long the sequence number won't be recognized |
56 | * as valid anymore. | 56 | * as valid anymore. |
57 | * | 57 | * |
58 | * - CLOSEREQ/CLOSING: | 58 | * - CLOSEREQ/CLOSING: |
59 | * | 59 | * |
60 | * 8.3. Termination | 60 | * 8.3. Termination |
61 | * | 61 | * |
62 | * The retransmission timer should initially be set to go off in two | 62 | * The retransmission timer should initially be set to go off in two |
63 | * round-trip times and should back off to not less than once every | 63 | * round-trip times and should back off to not less than once every |
64 | * 64 seconds ... | 64 | * 64 seconds ... |
65 | * | 65 | * |
66 | * - TIMEWAIT: | 66 | * - TIMEWAIT: |
67 | * | 67 | * |
68 | * 4.3. States | 68 | * 4.3. States |
69 | * | 69 | * |
70 | * A server or client socket remains in this state for 2MSL (4 minutes) | 70 | * A server or client socket remains in this state for 2MSL (4 minutes) |
71 | * after the connection has been town down, ... | 71 | * after the connection has been town down, ... |
72 | */ | 72 | */ |
73 | 73 | ||
74 | #define DCCP_MSL (2 * 60 * HZ) | 74 | #define DCCP_MSL (2 * 60 * HZ) |
75 | 75 | ||
76 | static const char * const dccp_state_names[] = { | 76 | static const char * const dccp_state_names[] = { |
77 | [CT_DCCP_NONE] = "NONE", | 77 | [CT_DCCP_NONE] = "NONE", |
78 | [CT_DCCP_REQUEST] = "REQUEST", | 78 | [CT_DCCP_REQUEST] = "REQUEST", |
79 | [CT_DCCP_RESPOND] = "RESPOND", | 79 | [CT_DCCP_RESPOND] = "RESPOND", |
80 | [CT_DCCP_PARTOPEN] = "PARTOPEN", | 80 | [CT_DCCP_PARTOPEN] = "PARTOPEN", |
81 | [CT_DCCP_OPEN] = "OPEN", | 81 | [CT_DCCP_OPEN] = "OPEN", |
82 | [CT_DCCP_CLOSEREQ] = "CLOSEREQ", | 82 | [CT_DCCP_CLOSEREQ] = "CLOSEREQ", |
83 | [CT_DCCP_CLOSING] = "CLOSING", | 83 | [CT_DCCP_CLOSING] = "CLOSING", |
84 | [CT_DCCP_TIMEWAIT] = "TIMEWAIT", | 84 | [CT_DCCP_TIMEWAIT] = "TIMEWAIT", |
85 | [CT_DCCP_IGNORE] = "IGNORE", | 85 | [CT_DCCP_IGNORE] = "IGNORE", |
86 | [CT_DCCP_INVALID] = "INVALID", | 86 | [CT_DCCP_INVALID] = "INVALID", |
87 | }; | 87 | }; |
88 | 88 | ||
89 | #define sNO CT_DCCP_NONE | 89 | #define sNO CT_DCCP_NONE |
90 | #define sRQ CT_DCCP_REQUEST | 90 | #define sRQ CT_DCCP_REQUEST |
91 | #define sRS CT_DCCP_RESPOND | 91 | #define sRS CT_DCCP_RESPOND |
92 | #define sPO CT_DCCP_PARTOPEN | 92 | #define sPO CT_DCCP_PARTOPEN |
93 | #define sOP CT_DCCP_OPEN | 93 | #define sOP CT_DCCP_OPEN |
94 | #define sCR CT_DCCP_CLOSEREQ | 94 | #define sCR CT_DCCP_CLOSEREQ |
95 | #define sCG CT_DCCP_CLOSING | 95 | #define sCG CT_DCCP_CLOSING |
96 | #define sTW CT_DCCP_TIMEWAIT | 96 | #define sTW CT_DCCP_TIMEWAIT |
97 | #define sIG CT_DCCP_IGNORE | 97 | #define sIG CT_DCCP_IGNORE |
98 | #define sIV CT_DCCP_INVALID | 98 | #define sIV CT_DCCP_INVALID |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * DCCP state transition table | 101 | * DCCP state transition table |
102 | * | 102 | * |
103 | * The assumption is the same as for TCP tracking: | 103 | * The assumption is the same as for TCP tracking: |
104 | * | 104 | * |
105 | * We are the man in the middle. All the packets go through us but might | 105 | * We are the man in the middle. All the packets go through us but might |
106 | * get lost in transit to the destination. It is assumed that the destination | 106 | * get lost in transit to the destination. It is assumed that the destination |
107 | * can't receive segments we haven't seen. | 107 | * can't receive segments we haven't seen. |
108 | * | 108 | * |
109 | * The following states exist: | 109 | * The following states exist: |
110 | * | 110 | * |
111 | * NONE: Initial state, expecting Request | 111 | * NONE: Initial state, expecting Request |
112 | * REQUEST: Request seen, waiting for Response from server | 112 | * REQUEST: Request seen, waiting for Response from server |
113 | * RESPOND: Response from server seen, waiting for Ack from client | 113 | * RESPOND: Response from server seen, waiting for Ack from client |
114 | * PARTOPEN: Ack after Response seen, waiting for packet other than Response, | 114 | * PARTOPEN: Ack after Response seen, waiting for packet other than Response, |
115 | * Reset or Sync from server | 115 | * Reset or Sync from server |
116 | * OPEN: Packet other than Response, Reset or Sync seen | 116 | * OPEN: Packet other than Response, Reset or Sync seen |
117 | * CLOSEREQ: CloseReq from server seen, expecting Close from client | 117 | * CLOSEREQ: CloseReq from server seen, expecting Close from client |
118 | * CLOSING: Close seen, expecting Reset | 118 | * CLOSING: Close seen, expecting Reset |
119 | * TIMEWAIT: Reset seen | 119 | * TIMEWAIT: Reset seen |
120 | * IGNORE: Not determinable whether packet is valid | 120 | * IGNORE: Not determinable whether packet is valid |
121 | * | 121 | * |
122 | * Some states exist only on one side of the connection: REQUEST, RESPOND, | 122 | * Some states exist only on one side of the connection: REQUEST, RESPOND, |
123 | * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to | 123 | * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to |
124 | * the one it was in before. | 124 | * the one it was in before. |
125 | * | 125 | * |
126 | * Packets are marked as ignored (sIG) if we don't know if they're valid | 126 | * Packets are marked as ignored (sIG) if we don't know if they're valid |
127 | * (for example a reincarnation of a connection we didn't notice is dead | 127 | * (for example a reincarnation of a connection we didn't notice is dead |
128 | * already) and the server may send back a connection closing Reset or a | 128 | * already) and the server may send back a connection closing Reset or a |
129 | * Response. They're also used for Sync/SyncAck packets, which we don't | 129 | * Response. They're also used for Sync/SyncAck packets, which we don't |
130 | * care about. | 130 | * care about. |
131 | */ | 131 | */ |
132 | static const u_int8_t | 132 | static const u_int8_t |
133 | dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = { | 133 | dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = { |
134 | [CT_DCCP_ROLE_CLIENT] = { | 134 | [CT_DCCP_ROLE_CLIENT] = { |
135 | [DCCP_PKT_REQUEST] = { | 135 | [DCCP_PKT_REQUEST] = { |
136 | /* | 136 | /* |
137 | * sNO -> sRQ Regular Request | 137 | * sNO -> sRQ Regular Request |
138 | * sRQ -> sRQ Retransmitted Request or reincarnation | 138 | * sRQ -> sRQ Retransmitted Request or reincarnation |
139 | * sRS -> sRS Retransmitted Request (apparently Response | 139 | * sRS -> sRS Retransmitted Request (apparently Response |
140 | * got lost after we saw it) or reincarnation | 140 | * got lost after we saw it) or reincarnation |
141 | * sPO -> sIG Ignore, conntrack might be out of sync | 141 | * sPO -> sIG Ignore, conntrack might be out of sync |
142 | * sOP -> sIG Ignore, conntrack might be out of sync | 142 | * sOP -> sIG Ignore, conntrack might be out of sync |
143 | * sCR -> sIG Ignore, conntrack might be out of sync | 143 | * sCR -> sIG Ignore, conntrack might be out of sync |
144 | * sCG -> sIG Ignore, conntrack might be out of sync | 144 | * sCG -> sIG Ignore, conntrack might be out of sync |
145 | * sTW -> sRQ Reincarnation | 145 | * sTW -> sRQ Reincarnation |
146 | * | 146 | * |
147 | * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */ | 147 | * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */ |
148 | sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ, | 148 | sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ, |
149 | }, | 149 | }, |
150 | [DCCP_PKT_RESPONSE] = { | 150 | [DCCP_PKT_RESPONSE] = { |
151 | /* | 151 | /* |
152 | * sNO -> sIV Invalid | 152 | * sNO -> sIV Invalid |
153 | * sRQ -> sIG Ignore, might be response to ignored Request | 153 | * sRQ -> sIG Ignore, might be response to ignored Request |
154 | * sRS -> sIG Ignore, might be response to ignored Request | 154 | * sRS -> sIG Ignore, might be response to ignored Request |
155 | * sPO -> sIG Ignore, might be response to ignored Request | 155 | * sPO -> sIG Ignore, might be response to ignored Request |
156 | * sOP -> sIG Ignore, might be response to ignored Request | 156 | * sOP -> sIG Ignore, might be response to ignored Request |
157 | * sCR -> sIG Ignore, might be response to ignored Request | 157 | * sCR -> sIG Ignore, might be response to ignored Request |
158 | * sCG -> sIG Ignore, might be response to ignored Request | 158 | * sCG -> sIG Ignore, might be response to ignored Request |
159 | * sTW -> sIV Invalid, reincarnation in reverse direction | 159 | * sTW -> sIV Invalid, reincarnation in reverse direction |
160 | * goes through sRQ | 160 | * goes through sRQ |
161 | * | 161 | * |
162 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 162 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
163 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV, | 163 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV, |
164 | }, | 164 | }, |
165 | [DCCP_PKT_ACK] = { | 165 | [DCCP_PKT_ACK] = { |
166 | /* | 166 | /* |
167 | * sNO -> sIV No connection | 167 | * sNO -> sIV No connection |
168 | * sRQ -> sIV No connection | 168 | * sRQ -> sIV No connection |
169 | * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) | 169 | * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) |
170 | * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN | 170 | * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN |
171 | * sOP -> sOP Regular ACK, remain in OPEN | 171 | * sOP -> sOP Regular ACK, remain in OPEN |
172 | * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.) | 172 | * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.) |
173 | * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) | 173 | * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) |
174 | * sTW -> sIV | 174 | * sTW -> sIV |
175 | * | 175 | * |
176 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 176 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
177 | sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV | 177 | sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV |
178 | }, | 178 | }, |
179 | [DCCP_PKT_DATA] = { | 179 | [DCCP_PKT_DATA] = { |
180 | /* | 180 | /* |
181 | * sNO -> sIV No connection | 181 | * sNO -> sIV No connection |
182 | * sRQ -> sIV No connection | 182 | * sRQ -> sIV No connection |
183 | * sRS -> sIV No connection | 183 | * sRS -> sIV No connection |
184 | * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.) | 184 | * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.) |
185 | * sOP -> sOP Regular Data packet | 185 | * sOP -> sOP Regular Data packet |
186 | * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.) | 186 | * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.) |
187 | * sCG -> sCG Data in CLOSING MAY be processed (8.3.) | 187 | * sCG -> sCG Data in CLOSING MAY be processed (8.3.) |
188 | * sTW -> sIV | 188 | * sTW -> sIV |
189 | * | 189 | * |
190 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 190 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
191 | sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV, | 191 | sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV, |
192 | }, | 192 | }, |
193 | [DCCP_PKT_DATAACK] = { | 193 | [DCCP_PKT_DATAACK] = { |
194 | /* | 194 | /* |
195 | * sNO -> sIV No connection | 195 | * sNO -> sIV No connection |
196 | * sRQ -> sIV No connection | 196 | * sRQ -> sIV No connection |
197 | * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) | 197 | * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) |
198 | * sPO -> sPO Remain in PARTOPEN state | 198 | * sPO -> sPO Remain in PARTOPEN state |
199 | * sOP -> sOP Regular DataAck packet in OPEN state | 199 | * sOP -> sOP Regular DataAck packet in OPEN state |
200 | * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.) | 200 | * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.) |
201 | * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.) | 201 | * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.) |
202 | * sTW -> sIV | 202 | * sTW -> sIV |
203 | * | 203 | * |
204 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 204 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
205 | sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV | 205 | sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV |
206 | }, | 206 | }, |
207 | [DCCP_PKT_CLOSEREQ] = { | 207 | [DCCP_PKT_CLOSEREQ] = { |
208 | /* | 208 | /* |
209 | * CLOSEREQ may only be sent by the server. | 209 | * CLOSEREQ may only be sent by the server. |
210 | * | 210 | * |
211 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 211 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
212 | sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV | 212 | sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV |
213 | }, | 213 | }, |
214 | [DCCP_PKT_CLOSE] = { | 214 | [DCCP_PKT_CLOSE] = { |
215 | /* | 215 | /* |
216 | * sNO -> sIV No connection | 216 | * sNO -> sIV No connection |
217 | * sRQ -> sIV No connection | 217 | * sRQ -> sIV No connection |
218 | * sRS -> sIV No connection | 218 | * sRS -> sIV No connection |
219 | * sPO -> sCG Client-initiated close | 219 | * sPO -> sCG Client-initiated close |
220 | * sOP -> sCG Client-initiated close | 220 | * sOP -> sCG Client-initiated close |
221 | * sCR -> sCG Close in response to CloseReq (8.3.) | 221 | * sCR -> sCG Close in response to CloseReq (8.3.) |
222 | * sCG -> sCG Retransmit | 222 | * sCG -> sCG Retransmit |
223 | * sTW -> sIV Late retransmit, already in TIME_WAIT | 223 | * sTW -> sIV Late retransmit, already in TIME_WAIT |
224 | * | 224 | * |
225 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 225 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
226 | sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV | 226 | sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV |
227 | }, | 227 | }, |
228 | [DCCP_PKT_RESET] = { | 228 | [DCCP_PKT_RESET] = { |
229 | /* | 229 | /* |
230 | * sNO -> sIV No connection | 230 | * sNO -> sIV No connection |
231 | * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.) | 231 | * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.) |
232 | * sRS -> sTW Response received without Request | 232 | * sRS -> sTW Response received without Request |
233 | * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.) | 233 | * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.) |
234 | * sOP -> sTW Connection reset | 234 | * sOP -> sTW Connection reset |
235 | * sCR -> sTW Connection reset | 235 | * sCR -> sTW Connection reset |
236 | * sCG -> sTW Connection reset | 236 | * sCG -> sTW Connection reset |
237 | * sTW -> sIG Ignore (don't refresh timer) | 237 | * sTW -> sIG Ignore (don't refresh timer) |
238 | * | 238 | * |
239 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 239 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
240 | sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG | 240 | sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG |
241 | }, | 241 | }, |
242 | [DCCP_PKT_SYNC] = { | 242 | [DCCP_PKT_SYNC] = { |
243 | /* | 243 | /* |
244 | * We currently ignore Sync packets | 244 | * We currently ignore Sync packets |
245 | * | 245 | * |
246 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 246 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
247 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, | 247 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, |
248 | }, | 248 | }, |
249 | [DCCP_PKT_SYNCACK] = { | 249 | [DCCP_PKT_SYNCACK] = { |
250 | /* | 250 | /* |
251 | * We currently ignore SyncAck packets | 251 | * We currently ignore SyncAck packets |
252 | * | 252 | * |
253 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 253 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
254 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, | 254 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, |
255 | }, | 255 | }, |
256 | }, | 256 | }, |
257 | [CT_DCCP_ROLE_SERVER] = { | 257 | [CT_DCCP_ROLE_SERVER] = { |
258 | [DCCP_PKT_REQUEST] = { | 258 | [DCCP_PKT_REQUEST] = { |
259 | /* | 259 | /* |
260 | * sNO -> sIV Invalid | 260 | * sNO -> sIV Invalid |
261 | * sRQ -> sIG Ignore, conntrack might be out of sync | 261 | * sRQ -> sIG Ignore, conntrack might be out of sync |
262 | * sRS -> sIG Ignore, conntrack might be out of sync | 262 | * sRS -> sIG Ignore, conntrack might be out of sync |
263 | * sPO -> sIG Ignore, conntrack might be out of sync | 263 | * sPO -> sIG Ignore, conntrack might be out of sync |
264 | * sOP -> sIG Ignore, conntrack might be out of sync | 264 | * sOP -> sIG Ignore, conntrack might be out of sync |
265 | * sCR -> sIG Ignore, conntrack might be out of sync | 265 | * sCR -> sIG Ignore, conntrack might be out of sync |
266 | * sCG -> sIG Ignore, conntrack might be out of sync | 266 | * sCG -> sIG Ignore, conntrack might be out of sync |
267 | * sTW -> sRQ Reincarnation, must reverse roles | 267 | * sTW -> sRQ Reincarnation, must reverse roles |
268 | * | 268 | * |
269 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 269 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
270 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ | 270 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ |
271 | }, | 271 | }, |
272 | [DCCP_PKT_RESPONSE] = { | 272 | [DCCP_PKT_RESPONSE] = { |
273 | /* | 273 | /* |
274 | * sNO -> sIV Response without Request | 274 | * sNO -> sIV Response without Request |
275 | * sRQ -> sRS Response to clients Request | 275 | * sRQ -> sRS Response to clients Request |
276 | * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT) | 276 | * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT) |
277 | * sPO -> sIG Response to an ignored Request or late retransmit | 277 | * sPO -> sIG Response to an ignored Request or late retransmit |
278 | * sOP -> sIG Ignore, might be response to ignored Request | 278 | * sOP -> sIG Ignore, might be response to ignored Request |
279 | * sCR -> sIG Ignore, might be response to ignored Request | 279 | * sCR -> sIG Ignore, might be response to ignored Request |
280 | * sCG -> sIG Ignore, might be response to ignored Request | 280 | * sCG -> sIG Ignore, might be response to ignored Request |
281 | * sTW -> sIV Invalid, Request from client in sTW moves to sRQ | 281 | * sTW -> sIV Invalid, Request from client in sTW moves to sRQ |
282 | * | 282 | * |
283 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 283 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
284 | sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV | 284 | sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV |
285 | }, | 285 | }, |
286 | [DCCP_PKT_ACK] = { | 286 | [DCCP_PKT_ACK] = { |
287 | /* | 287 | /* |
288 | * sNO -> sIV No connection | 288 | * sNO -> sIV No connection |
289 | * sRQ -> sIV No connection | 289 | * sRQ -> sIV No connection |
290 | * sRS -> sIV No connection | 290 | * sRS -> sIV No connection |
291 | * sPO -> sOP Enter OPEN state (8.1.5.) | 291 | * sPO -> sOP Enter OPEN state (8.1.5.) |
292 | * sOP -> sOP Regular Ack in OPEN state | 292 | * sOP -> sOP Regular Ack in OPEN state |
293 | * sCR -> sIV Waiting for Close from client | 293 | * sCR -> sIV Waiting for Close from client |
294 | * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) | 294 | * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) |
295 | * sTW -> sIV | 295 | * sTW -> sIV |
296 | * | 296 | * |
297 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 297 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
298 | sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV | 298 | sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV |
299 | }, | 299 | }, |
300 | [DCCP_PKT_DATA] = { | 300 | [DCCP_PKT_DATA] = { |
301 | /* | 301 | /* |
302 | * sNO -> sIV No connection | 302 | * sNO -> sIV No connection |
303 | * sRQ -> sIV No connection | 303 | * sRQ -> sIV No connection |
304 | * sRS -> sIV No connection | 304 | * sRS -> sIV No connection |
305 | * sPO -> sOP Enter OPEN state (8.1.5.) | 305 | * sPO -> sOP Enter OPEN state (8.1.5.) |
306 | * sOP -> sOP Regular Data packet in OPEN state | 306 | * sOP -> sOP Regular Data packet in OPEN state |
307 | * sCR -> sIV Waiting for Close from client | 307 | * sCR -> sIV Waiting for Close from client |
308 | * sCG -> sCG Data in CLOSING MAY be processed (8.3.) | 308 | * sCG -> sCG Data in CLOSING MAY be processed (8.3.) |
309 | * sTW -> sIV | 309 | * sTW -> sIV |
310 | * | 310 | * |
311 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 311 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
312 | sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV | 312 | sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV |
313 | }, | 313 | }, |
314 | [DCCP_PKT_DATAACK] = { | 314 | [DCCP_PKT_DATAACK] = { |
315 | /* | 315 | /* |
316 | * sNO -> sIV No connection | 316 | * sNO -> sIV No connection |
317 | * sRQ -> sIV No connection | 317 | * sRQ -> sIV No connection |
318 | * sRS -> sIV No connection | 318 | * sRS -> sIV No connection |
319 | * sPO -> sOP Enter OPEN state (8.1.5.) | 319 | * sPO -> sOP Enter OPEN state (8.1.5.) |
320 | * sOP -> sOP Regular DataAck in OPEN state | 320 | * sOP -> sOP Regular DataAck in OPEN state |
321 | * sCR -> sIV Waiting for Close from client | 321 | * sCR -> sIV Waiting for Close from client |
322 | * sCG -> sCG Data in CLOSING MAY be processed (8.3.) | 322 | * sCG -> sCG Data in CLOSING MAY be processed (8.3.) |
323 | * sTW -> sIV | 323 | * sTW -> sIV |
324 | * | 324 | * |
325 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 325 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
326 | sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV | 326 | sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV |
327 | }, | 327 | }, |
328 | [DCCP_PKT_CLOSEREQ] = { | 328 | [DCCP_PKT_CLOSEREQ] = { |
329 | /* | 329 | /* |
330 | * sNO -> sIV No connection | 330 | * sNO -> sIV No connection |
331 | * sRQ -> sIV No connection | 331 | * sRQ -> sIV No connection |
332 | * sRS -> sIV No connection | 332 | * sRS -> sIV No connection |
333 | * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.) | 333 | * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.) |
334 | * sOP -> sCR CloseReq in OPEN state | 334 | * sOP -> sCR CloseReq in OPEN state |
335 | * sCR -> sCR Retransmit | 335 | * sCR -> sCR Retransmit |
336 | * sCG -> sCR Simultaneous close, client sends another Close | 336 | * sCG -> sCR Simultaneous close, client sends another Close |
337 | * sTW -> sIV Already closed | 337 | * sTW -> sIV Already closed |
338 | * | 338 | * |
339 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 339 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
340 | sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV | 340 | sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV |
341 | }, | 341 | }, |
342 | [DCCP_PKT_CLOSE] = { | 342 | [DCCP_PKT_CLOSE] = { |
343 | /* | 343 | /* |
344 | * sNO -> sIV No connection | 344 | * sNO -> sIV No connection |
345 | * sRQ -> sIV No connection | 345 | * sRQ -> sIV No connection |
346 | * sRS -> sIV No connection | 346 | * sRS -> sIV No connection |
347 | * sPO -> sOP -> sCG Move direcly to CLOSING | 347 | * sPO -> sOP -> sCG Move direcly to CLOSING |
348 | * sOP -> sCG Move to CLOSING | 348 | * sOP -> sCG Move to CLOSING |
349 | * sCR -> sIV Close after CloseReq is invalid | 349 | * sCR -> sIV Close after CloseReq is invalid |
350 | * sCG -> sCG Retransmit | 350 | * sCG -> sCG Retransmit |
351 | * sTW -> sIV Already closed | 351 | * sTW -> sIV Already closed |
352 | * | 352 | * |
353 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 353 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
354 | sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV | 354 | sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV |
355 | }, | 355 | }, |
356 | [DCCP_PKT_RESET] = { | 356 | [DCCP_PKT_RESET] = { |
357 | /* | 357 | /* |
358 | * sNO -> sIV No connection | 358 | * sNO -> sIV No connection |
359 | * sRQ -> sTW Reset in response to Request | 359 | * sRQ -> sTW Reset in response to Request |
360 | * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.) | 360 | * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.) |
361 | * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.) | 361 | * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.) |
362 | * sOP -> sTW | 362 | * sOP -> sTW |
363 | * sCR -> sTW | 363 | * sCR -> sTW |
364 | * sCG -> sTW | 364 | * sCG -> sTW |
365 | * sTW -> sIG Ignore (don't refresh timer) | 365 | * sTW -> sIG Ignore (don't refresh timer) |
366 | * | 366 | * |
367 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */ | 367 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */ |
368 | sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG | 368 | sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG |
369 | }, | 369 | }, |
370 | [DCCP_PKT_SYNC] = { | 370 | [DCCP_PKT_SYNC] = { |
371 | /* | 371 | /* |
372 | * We currently ignore Sync packets | 372 | * We currently ignore Sync packets |
373 | * | 373 | * |
374 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 374 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
375 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, | 375 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, |
376 | }, | 376 | }, |
377 | [DCCP_PKT_SYNCACK] = { | 377 | [DCCP_PKT_SYNCACK] = { |
378 | /* | 378 | /* |
379 | * We currently ignore SyncAck packets | 379 | * We currently ignore SyncAck packets |
380 | * | 380 | * |
381 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ | 381 | * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ |
382 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, | 382 | sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIG, |
383 | }, | 383 | }, |
384 | }, | 384 | }, |
385 | }; | 385 | }; |
386 | 386 | ||
387 | static inline struct nf_dccp_net *dccp_pernet(struct net *net) | 387 | static inline struct nf_dccp_net *dccp_pernet(struct net *net) |
388 | { | 388 | { |
389 | return &net->ct.nf_ct_proto.dccp; | 389 | return &net->ct.nf_ct_proto.dccp; |
390 | } | 390 | } |
391 | 391 | ||
392 | static noinline bool | 392 | static noinline bool |
393 | dccp_new(struct nf_conn *ct, const struct sk_buff *skb, | 393 | dccp_new(struct nf_conn *ct, const struct sk_buff *skb, |
394 | const struct dccp_hdr *dh) | 394 | const struct dccp_hdr *dh) |
395 | { | 395 | { |
396 | struct net *net = nf_ct_net(ct); | 396 | struct net *net = nf_ct_net(ct); |
397 | struct nf_dccp_net *dn; | 397 | struct nf_dccp_net *dn; |
398 | const char *msg; | 398 | const char *msg; |
399 | u_int8_t state; | 399 | u_int8_t state; |
400 | 400 | ||
401 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; | 401 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; |
402 | switch (state) { | 402 | switch (state) { |
403 | default: | 403 | default: |
404 | dn = dccp_pernet(net); | 404 | dn = dccp_pernet(net); |
405 | if (dn->dccp_loose == 0) { | 405 | if (dn->dccp_loose == 0) { |
406 | msg = "not picking up existing connection "; | 406 | msg = "not picking up existing connection "; |
407 | goto out_invalid; | 407 | goto out_invalid; |
408 | } | 408 | } |
409 | case CT_DCCP_REQUEST: | 409 | case CT_DCCP_REQUEST: |
410 | break; | 410 | break; |
411 | case CT_DCCP_INVALID: | 411 | case CT_DCCP_INVALID: |
412 | msg = "invalid state transition "; | 412 | msg = "invalid state transition "; |
413 | goto out_invalid; | 413 | goto out_invalid; |
414 | } | 414 | } |
415 | 415 | ||
416 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; | 416 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; |
417 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; | 417 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; |
418 | ct->proto.dccp.state = CT_DCCP_NONE; | 418 | ct->proto.dccp.state = CT_DCCP_NONE; |
419 | ct->proto.dccp.last_pkt = DCCP_PKT_REQUEST; | 419 | ct->proto.dccp.last_pkt = DCCP_PKT_REQUEST; |
420 | ct->proto.dccp.last_dir = IP_CT_DIR_ORIGINAL; | 420 | ct->proto.dccp.last_dir = IP_CT_DIR_ORIGINAL; |
421 | ct->proto.dccp.handshake_seq = 0; | 421 | ct->proto.dccp.handshake_seq = 0; |
422 | return true; | 422 | return true; |
423 | 423 | ||
424 | out_invalid: | 424 | out_invalid: |
425 | nf_ct_l4proto_log_invalid(skb, ct, "%s", msg); | 425 | nf_ct_l4proto_log_invalid(skb, ct, "%s", msg); |
426 | return false; | 426 | return false; |
427 | } | 427 | } |
428 | 428 | ||
429 | static u64 dccp_ack_seq(const struct dccp_hdr *dh) | 429 | static u64 dccp_ack_seq(const struct dccp_hdr *dh) |
430 | { | 430 | { |
431 | const struct dccp_hdr_ack_bits *dhack; | 431 | const struct dccp_hdr_ack_bits *dhack; |
432 | 432 | ||
433 | dhack = (void *)dh + __dccp_basic_hdr_len(dh); | 433 | dhack = (void *)dh + __dccp_basic_hdr_len(dh); |
434 | return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + | 434 | return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + |
435 | ntohl(dhack->dccph_ack_nr_low); | 435 | ntohl(dhack->dccph_ack_nr_low); |
436 | } | 436 | } |
437 | 437 | ||
438 | static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, | 438 | static int dccp_packet(struct nf_conn *ct, struct sk_buff *skb, |
439 | unsigned int dataoff, enum ip_conntrack_info ctinfo, | 439 | unsigned int dataoff, enum ip_conntrack_info ctinfo, |
440 | const struct nf_hook_state *state) | 440 | const struct nf_hook_state *state) |
441 | { | 441 | { |
442 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 442 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
443 | struct dccp_hdr _dh, *dh; | 443 | struct dccp_hdr _dh, *dh; |
444 | u_int8_t type, old_state, new_state; | 444 | u_int8_t type, old_state, new_state; |
445 | enum ct_dccp_roles role; | 445 | enum ct_dccp_roles role; |
446 | unsigned int *timeouts; | 446 | unsigned int *timeouts; |
447 | 447 | ||
448 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); | 448 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); |
449 | if (!dh) | 449 | if (!dh) |
450 | return NF_DROP; | 450 | return NF_DROP; |
451 | 451 | ||
452 | type = dh->dccph_type; | 452 | type = dh->dccph_type; |
453 | if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh)) | 453 | if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh)) |
454 | return -NF_ACCEPT; | 454 | return -NF_ACCEPT; |
455 | 455 | ||
456 | if (type == DCCP_PKT_RESET && | 456 | if (type == DCCP_PKT_RESET && |
457 | !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | 457 | !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
458 | /* Tear down connection immediately if only reply is a RESET */ | 458 | /* Tear down connection immediately if only reply is a RESET */ |
459 | nf_ct_kill_acct(ct, ctinfo, skb); | 459 | nf_ct_kill_acct(ct, ctinfo, skb); |
460 | return NF_ACCEPT; | 460 | return NF_ACCEPT; |
461 | } | 461 | } |
462 | 462 | ||
463 | spin_lock_bh(&ct->lock); | 463 | spin_lock_bh(&ct->lock); |
464 | 464 | ||
465 | role = ct->proto.dccp.role[dir]; | 465 | role = ct->proto.dccp.role[dir]; |
466 | old_state = ct->proto.dccp.state; | 466 | old_state = ct->proto.dccp.state; |
467 | new_state = dccp_state_table[role][type][old_state]; | 467 | new_state = dccp_state_table[role][type][old_state]; |
468 | 468 | ||
469 | switch (new_state) { | 469 | switch (new_state) { |
470 | case CT_DCCP_REQUEST: | 470 | case CT_DCCP_REQUEST: |
471 | if (old_state == CT_DCCP_TIMEWAIT && | 471 | if (old_state == CT_DCCP_TIMEWAIT && |
472 | role == CT_DCCP_ROLE_SERVER) { | 472 | role == CT_DCCP_ROLE_SERVER) { |
473 | /* Reincarnation in the reverse direction: reopen and | 473 | /* Reincarnation in the reverse direction: reopen and |
474 | * reverse client/server roles. */ | 474 | * reverse client/server roles. */ |
475 | ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT; | 475 | ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT; |
476 | ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER; | 476 | ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER; |
477 | } | 477 | } |
478 | break; | 478 | break; |
479 | case CT_DCCP_RESPOND: | 479 | case CT_DCCP_RESPOND: |
480 | if (old_state == CT_DCCP_REQUEST) | 480 | if (old_state == CT_DCCP_REQUEST) |
481 | ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); | 481 | ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); |
482 | break; | 482 | break; |
483 | case CT_DCCP_PARTOPEN: | 483 | case CT_DCCP_PARTOPEN: |
484 | if (old_state == CT_DCCP_RESPOND && | 484 | if (old_state == CT_DCCP_RESPOND && |
485 | type == DCCP_PKT_ACK && | 485 | type == DCCP_PKT_ACK && |
486 | dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq) | 486 | dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq) |
487 | set_bit(IPS_ASSURED_BIT, &ct->status); | 487 | set_bit(IPS_ASSURED_BIT, &ct->status); |
488 | break; | 488 | break; |
489 | case CT_DCCP_IGNORE: | 489 | case CT_DCCP_IGNORE: |
490 | /* | 490 | /* |
491 | * Connection tracking might be out of sync, so we ignore | 491 | * Connection tracking might be out of sync, so we ignore |
492 | * packets that might establish a new connection and resync | 492 | * packets that might establish a new connection and resync |
493 | * if the server responds with a valid Response. | 493 | * if the server responds with a valid Response. |
494 | */ | 494 | */ |
495 | if (ct->proto.dccp.last_dir == !dir && | 495 | if (ct->proto.dccp.last_dir == !dir && |
496 | ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST && | 496 | ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST && |
497 | type == DCCP_PKT_RESPONSE) { | 497 | type == DCCP_PKT_RESPONSE) { |
498 | ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT; | 498 | ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT; |
499 | ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER; | 499 | ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER; |
500 | ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); | 500 | ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); |
501 | new_state = CT_DCCP_RESPOND; | 501 | new_state = CT_DCCP_RESPOND; |
502 | break; | 502 | break; |
503 | } | 503 | } |
504 | ct->proto.dccp.last_dir = dir; | 504 | ct->proto.dccp.last_dir = dir; |
505 | ct->proto.dccp.last_pkt = type; | 505 | ct->proto.dccp.last_pkt = type; |
506 | 506 | ||
507 | spin_unlock_bh(&ct->lock); | 507 | spin_unlock_bh(&ct->lock); |
508 | nf_ct_l4proto_log_invalid(skb, ct, "%s", "invalid packet"); | 508 | nf_ct_l4proto_log_invalid(skb, ct, "%s", "invalid packet"); |
509 | return NF_ACCEPT; | 509 | return NF_ACCEPT; |
510 | case CT_DCCP_INVALID: | 510 | case CT_DCCP_INVALID: |
511 | spin_unlock_bh(&ct->lock); | 511 | spin_unlock_bh(&ct->lock); |
512 | nf_ct_l4proto_log_invalid(skb, ct, "%s", "invalid state transition"); | 512 | nf_ct_l4proto_log_invalid(skb, ct, "%s", "invalid state transition"); |
513 | return -NF_ACCEPT; | 513 | return -NF_ACCEPT; |
514 | } | 514 | } |
515 | 515 | ||
516 | ct->proto.dccp.last_dir = dir; | 516 | ct->proto.dccp.last_dir = dir; |
517 | ct->proto.dccp.last_pkt = type; | 517 | ct->proto.dccp.last_pkt = type; |
518 | ct->proto.dccp.state = new_state; | 518 | ct->proto.dccp.state = new_state; |
519 | spin_unlock_bh(&ct->lock); | 519 | spin_unlock_bh(&ct->lock); |
520 | 520 | ||
521 | if (new_state != old_state) | 521 | if (new_state != old_state) |
522 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); | 522 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); |
523 | 523 | ||
524 | timeouts = nf_ct_timeout_lookup(ct); | 524 | timeouts = nf_ct_timeout_lookup(ct); |
525 | if (!timeouts) | 525 | if (!timeouts) |
526 | timeouts = dccp_pernet(nf_ct_net(ct))->dccp_timeout; | 526 | timeouts = dccp_pernet(nf_ct_net(ct))->dccp_timeout; |
527 | nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); | 527 | nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); |
528 | 528 | ||
529 | return NF_ACCEPT; | 529 | return NF_ACCEPT; |
530 | } | 530 | } |
531 | 531 | ||
532 | static int dccp_error(struct nf_conn *tmpl, | 532 | static int dccp_error(struct nf_conn *tmpl, |
533 | struct sk_buff *skb, unsigned int dataoff, | 533 | struct sk_buff *skb, unsigned int dataoff, |
534 | const struct nf_hook_state *state) | 534 | const struct nf_hook_state *state) |
535 | { | 535 | { |
536 | struct dccp_hdr _dh, *dh; | 536 | struct dccp_hdr _dh, *dh; |
537 | unsigned int dccp_len = skb->len - dataoff; | 537 | unsigned int dccp_len = skb->len - dataoff; |
538 | unsigned int cscov; | 538 | unsigned int cscov; |
539 | const char *msg; | 539 | const char *msg; |
540 | 540 | ||
541 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); | 541 | dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); |
542 | if (dh == NULL) { | 542 | if (dh == NULL) { |
543 | msg = "nf_ct_dccp: short packet "; | 543 | msg = "nf_ct_dccp: short packet "; |
544 | goto out_invalid; | 544 | goto out_invalid; |
545 | } | 545 | } |
546 | 546 | ||
547 | if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || | 547 | if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || |
548 | dh->dccph_doff * 4 > dccp_len) { | 548 | dh->dccph_doff * 4 > dccp_len) { |
549 | msg = "nf_ct_dccp: truncated/malformed packet "; | 549 | msg = "nf_ct_dccp: truncated/malformed packet "; |
550 | goto out_invalid; | 550 | goto out_invalid; |
551 | } | 551 | } |
552 | 552 | ||
553 | cscov = dccp_len; | 553 | cscov = dccp_len; |
554 | if (dh->dccph_cscov) { | 554 | if (dh->dccph_cscov) { |
555 | cscov = (dh->dccph_cscov - 1) * 4; | 555 | cscov = (dh->dccph_cscov - 1) * 4; |
556 | if (cscov > dccp_len) { | 556 | if (cscov > dccp_len) { |
557 | msg = "nf_ct_dccp: bad checksum coverage "; | 557 | msg = "nf_ct_dccp: bad checksum coverage "; |
558 | goto out_invalid; | 558 | goto out_invalid; |
559 | } | 559 | } |
560 | } | 560 | } |
561 | 561 | ||
562 | if (state->hook == NF_INET_PRE_ROUTING && | 562 | if (state->hook == NF_INET_PRE_ROUTING && |
563 | state->net->ct.sysctl_checksum && | 563 | state->net->ct.sysctl_checksum && |
564 | nf_checksum_partial(skb, state->hook, dataoff, cscov, | 564 | nf_checksum_partial(skb, state->hook, dataoff, cscov, |
565 | IPPROTO_DCCP, state->pf)) { | 565 | IPPROTO_DCCP, state->pf)) { |
566 | msg = "nf_ct_dccp: bad checksum "; | 566 | msg = "nf_ct_dccp: bad checksum "; |
567 | goto out_invalid; | 567 | goto out_invalid; |
568 | } | 568 | } |
569 | 569 | ||
570 | if (dh->dccph_type >= DCCP_PKT_INVALID) { | 570 | if (dh->dccph_type >= DCCP_PKT_INVALID) { |
571 | msg = "nf_ct_dccp: reserved packet type "; | 571 | msg = "nf_ct_dccp: reserved packet type "; |
572 | goto out_invalid; | 572 | goto out_invalid; |
573 | } | 573 | } |
574 | 574 | ||
575 | return NF_ACCEPT; | 575 | return NF_ACCEPT; |
576 | 576 | ||
577 | out_invalid: | 577 | out_invalid: |
578 | nf_l4proto_log_invalid(skb, state->net, state->pf, | 578 | nf_l4proto_log_invalid(skb, state->net, state->pf, |
579 | IPPROTO_DCCP, "%s", msg); | 579 | IPPROTO_DCCP, "%s", msg); |
580 | return -NF_ACCEPT; | 580 | return -NF_ACCEPT; |
581 | } | 581 | } |
582 | 582 | ||
583 | static bool dccp_can_early_drop(const struct nf_conn *ct) | 583 | static bool dccp_can_early_drop(const struct nf_conn *ct) |
584 | { | 584 | { |
585 | switch (ct->proto.dccp.state) { | 585 | switch (ct->proto.dccp.state) { |
586 | case CT_DCCP_CLOSEREQ: | 586 | case CT_DCCP_CLOSEREQ: |
587 | case CT_DCCP_CLOSING: | 587 | case CT_DCCP_CLOSING: |
588 | case CT_DCCP_TIMEWAIT: | 588 | case CT_DCCP_TIMEWAIT: |
589 | return true; | 589 | return true; |
590 | default: | 590 | default: |
591 | break; | 591 | break; |
592 | } | 592 | } |
593 | 593 | ||
594 | return false; | 594 | return false; |
595 | } | 595 | } |
596 | 596 | ||
597 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 597 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
598 | static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct) | 598 | static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct) |
599 | { | 599 | { |
600 | seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); | 600 | seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); |
601 | } | 601 | } |
602 | #endif | 602 | #endif |
603 | 603 | ||
604 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 604 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
605 | static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, | 605 | static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, |
606 | struct nf_conn *ct) | 606 | struct nf_conn *ct) |
607 | { | 607 | { |
608 | struct nlattr *nest_parms; | 608 | struct nlattr *nest_parms; |
609 | 609 | ||
610 | spin_lock_bh(&ct->lock); | 610 | spin_lock_bh(&ct->lock); |
611 | nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); | 611 | nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); |
612 | if (!nest_parms) | 612 | if (!nest_parms) |
613 | goto nla_put_failure; | 613 | goto nla_put_failure; |
614 | if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) || | 614 | if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) || |
615 | nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE, | 615 | nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE, |
616 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) || | 616 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) || |
617 | nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, | 617 | nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, |
618 | cpu_to_be64(ct->proto.dccp.handshake_seq), | 618 | cpu_to_be64(ct->proto.dccp.handshake_seq), |
619 | CTA_PROTOINFO_DCCP_PAD)) | 619 | CTA_PROTOINFO_DCCP_PAD)) |
620 | goto nla_put_failure; | 620 | goto nla_put_failure; |
621 | nla_nest_end(skb, nest_parms); | 621 | nla_nest_end(skb, nest_parms); |
622 | spin_unlock_bh(&ct->lock); | 622 | spin_unlock_bh(&ct->lock); |
623 | return 0; | 623 | return 0; |
624 | 624 | ||
625 | nla_put_failure: | 625 | nla_put_failure: |
626 | spin_unlock_bh(&ct->lock); | 626 | spin_unlock_bh(&ct->lock); |
627 | return -1; | 627 | return -1; |
628 | } | 628 | } |
629 | 629 | ||
630 | static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { | 630 | static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { |
631 | [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, | 631 | [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, |
632 | [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 }, | 632 | [CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 }, |
633 | [CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 }, | 633 | [CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ] = { .type = NLA_U64 }, |
634 | [CTA_PROTOINFO_DCCP_PAD] = { .type = NLA_UNSPEC }, | 634 | [CTA_PROTOINFO_DCCP_PAD] = { .type = NLA_UNSPEC }, |
635 | }; | 635 | }; |
636 | 636 | ||
637 | #define DCCP_NLATTR_SIZE ( \ | 637 | #define DCCP_NLATTR_SIZE ( \ |
638 | NLA_ALIGN(NLA_HDRLEN + 1) + \ | 638 | NLA_ALIGN(NLA_HDRLEN + 1) + \ |
639 | NLA_ALIGN(NLA_HDRLEN + 1) + \ | 639 | NLA_ALIGN(NLA_HDRLEN + 1) + \ |
640 | NLA_ALIGN(NLA_HDRLEN + sizeof(u64)) + \ | 640 | NLA_ALIGN(NLA_HDRLEN + sizeof(u64)) + \ |
641 | NLA_ALIGN(NLA_HDRLEN + 0)) | 641 | NLA_ALIGN(NLA_HDRLEN + 0)) |
642 | 642 | ||
643 | static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) | 643 | static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) |
644 | { | 644 | { |
645 | struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; | 645 | struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; |
646 | struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1]; | 646 | struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1]; |
647 | int err; | 647 | int err; |
648 | 648 | ||
649 | if (!attr) | 649 | if (!attr) |
650 | return 0; | 650 | return 0; |
651 | 651 | ||
652 | err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr, | 652 | err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr, |
653 | dccp_nla_policy, NULL); | 653 | dccp_nla_policy, NULL); |
654 | if (err < 0) | 654 | if (err < 0) |
655 | return err; | 655 | return err; |
656 | 656 | ||
657 | if (!tb[CTA_PROTOINFO_DCCP_STATE] || | 657 | if (!tb[CTA_PROTOINFO_DCCP_STATE] || |
658 | !tb[CTA_PROTOINFO_DCCP_ROLE] || | 658 | !tb[CTA_PROTOINFO_DCCP_ROLE] || |
659 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX || | 659 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX || |
660 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) { | 660 | nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) { |
661 | return -EINVAL; | 661 | return -EINVAL; |
662 | } | 662 | } |
663 | 663 | ||
664 | spin_lock_bh(&ct->lock); | 664 | spin_lock_bh(&ct->lock); |
665 | ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); | 665 | ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); |
666 | if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) { | 666 | if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) { |
667 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; | 667 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; |
668 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; | 668 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; |
669 | } else { | 669 | } else { |
670 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER; | 670 | ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER; |
671 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT; | 671 | ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT; |
672 | } | 672 | } |
673 | if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) { | 673 | if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ]) { |
674 | ct->proto.dccp.handshake_seq = | 674 | ct->proto.dccp.handshake_seq = |
675 | be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); | 675 | be64_to_cpu(nla_get_be64(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ])); |
676 | } | 676 | } |
677 | spin_unlock_bh(&ct->lock); | 677 | spin_unlock_bh(&ct->lock); |
678 | return 0; | 678 | return 0; |
679 | } | 679 | } |
680 | #endif | 680 | #endif |
681 | 681 | ||
682 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 682 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
683 | 683 | ||
684 | #include <linux/netfilter/nfnetlink.h> | 684 | #include <linux/netfilter/nfnetlink.h> |
685 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 685 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
686 | 686 | ||
687 | static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], | 687 | static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], |
688 | struct net *net, void *data) | 688 | struct net *net, void *data) |
689 | { | 689 | { |
690 | struct nf_dccp_net *dn = dccp_pernet(net); | 690 | struct nf_dccp_net *dn = dccp_pernet(net); |
691 | unsigned int *timeouts = data; | 691 | unsigned int *timeouts = data; |
692 | int i; | 692 | int i; |
693 | 693 | ||
694 | /* set default DCCP timeouts. */ | 694 | /* set default DCCP timeouts. */ |
695 | for (i=0; i<CT_DCCP_MAX; i++) | 695 | for (i=0; i<CT_DCCP_MAX; i++) |
696 | timeouts[i] = dn->dccp_timeout[i]; | 696 | timeouts[i] = dn->dccp_timeout[i]; |
697 | 697 | ||
698 | /* there's a 1:1 mapping between attributes and protocol states. */ | 698 | /* there's a 1:1 mapping between attributes and protocol states. */ |
699 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { | 699 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { |
700 | if (tb[i]) { | 700 | if (tb[i]) { |
701 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; | 701 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; |
702 | } | 702 | } |
703 | } | 703 | } |
704 | 704 | ||
705 | timeouts[CTA_TIMEOUT_DCCP_UNSPEC] = timeouts[CTA_TIMEOUT_DCCP_REQUEST]; | 705 | timeouts[CTA_TIMEOUT_DCCP_UNSPEC] = timeouts[CTA_TIMEOUT_DCCP_REQUEST]; |
706 | return 0; | 706 | return 0; |
707 | } | 707 | } |
708 | 708 | ||
709 | static int | 709 | static int |
710 | dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 710 | dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
711 | { | 711 | { |
712 | const unsigned int *timeouts = data; | 712 | const unsigned int *timeouts = data; |
713 | int i; | 713 | int i; |
714 | 714 | ||
715 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { | 715 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { |
716 | if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ))) | 716 | if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ))) |
717 | goto nla_put_failure; | 717 | goto nla_put_failure; |
718 | } | 718 | } |
719 | return 0; | 719 | return 0; |
720 | 720 | ||
721 | nla_put_failure: | 721 | nla_put_failure: |
722 | return -ENOSPC; | 722 | return -ENOSPC; |
723 | } | 723 | } |
724 | 724 | ||
725 | static const struct nla_policy | 725 | static const struct nla_policy |
726 | dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = { | 726 | dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = { |
727 | [CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 }, | 727 | [CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 }, |
728 | [CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 }, | 728 | [CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 }, |
729 | [CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 }, | 729 | [CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 }, |
730 | [CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 }, | 730 | [CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 }, |
731 | [CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 }, | 731 | [CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 }, |
732 | [CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 }, | 732 | [CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 }, |
733 | [CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 }, | 733 | [CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 }, |
734 | }; | 734 | }; |
735 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 735 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
736 | 736 | ||
737 | #ifdef CONFIG_SYSCTL | 737 | #ifdef CONFIG_SYSCTL |
738 | /* template, data assigned later */ | 738 | /* template, data assigned later */ |
739 | static struct ctl_table dccp_sysctl_table[] = { | 739 | static struct ctl_table dccp_sysctl_table[] = { |
740 | { | 740 | { |
741 | .procname = "nf_conntrack_dccp_timeout_request", | 741 | .procname = "nf_conntrack_dccp_timeout_request", |
742 | .maxlen = sizeof(unsigned int), | 742 | .maxlen = sizeof(unsigned int), |
743 | .mode = 0644, | 743 | .mode = 0644, |
744 | .proc_handler = proc_dointvec_jiffies, | 744 | .proc_handler = proc_dointvec_jiffies, |
745 | }, | 745 | }, |
746 | { | 746 | { |
747 | .procname = "nf_conntrack_dccp_timeout_respond", | 747 | .procname = "nf_conntrack_dccp_timeout_respond", |
748 | .maxlen = sizeof(unsigned int), | 748 | .maxlen = sizeof(unsigned int), |
749 | .mode = 0644, | 749 | .mode = 0644, |
750 | .proc_handler = proc_dointvec_jiffies, | 750 | .proc_handler = proc_dointvec_jiffies, |
751 | }, | 751 | }, |
752 | { | 752 | { |
753 | .procname = "nf_conntrack_dccp_timeout_partopen", | 753 | .procname = "nf_conntrack_dccp_timeout_partopen", |
754 | .maxlen = sizeof(unsigned int), | 754 | .maxlen = sizeof(unsigned int), |
755 | .mode = 0644, | 755 | .mode = 0644, |
756 | .proc_handler = proc_dointvec_jiffies, | 756 | .proc_handler = proc_dointvec_jiffies, |
757 | }, | 757 | }, |
758 | { | 758 | { |
759 | .procname = "nf_conntrack_dccp_timeout_open", | 759 | .procname = "nf_conntrack_dccp_timeout_open", |
760 | .maxlen = sizeof(unsigned int), | 760 | .maxlen = sizeof(unsigned int), |
761 | .mode = 0644, | 761 | .mode = 0644, |
762 | .proc_handler = proc_dointvec_jiffies, | 762 | .proc_handler = proc_dointvec_jiffies, |
763 | }, | 763 | }, |
764 | { | 764 | { |
765 | .procname = "nf_conntrack_dccp_timeout_closereq", | 765 | .procname = "nf_conntrack_dccp_timeout_closereq", |
766 | .maxlen = sizeof(unsigned int), | 766 | .maxlen = sizeof(unsigned int), |
767 | .mode = 0644, | 767 | .mode = 0644, |
768 | .proc_handler = proc_dointvec_jiffies, | 768 | .proc_handler = proc_dointvec_jiffies, |
769 | }, | 769 | }, |
770 | { | 770 | { |
771 | .procname = "nf_conntrack_dccp_timeout_closing", | 771 | .procname = "nf_conntrack_dccp_timeout_closing", |
772 | .maxlen = sizeof(unsigned int), | 772 | .maxlen = sizeof(unsigned int), |
773 | .mode = 0644, | 773 | .mode = 0644, |
774 | .proc_handler = proc_dointvec_jiffies, | 774 | .proc_handler = proc_dointvec_jiffies, |
775 | }, | 775 | }, |
776 | { | 776 | { |
777 | .procname = "nf_conntrack_dccp_timeout_timewait", | 777 | .procname = "nf_conntrack_dccp_timeout_timewait", |
778 | .maxlen = sizeof(unsigned int), | 778 | .maxlen = sizeof(unsigned int), |
779 | .mode = 0644, | 779 | .mode = 0644, |
780 | .proc_handler = proc_dointvec_jiffies, | 780 | .proc_handler = proc_dointvec_jiffies, |
781 | }, | 781 | }, |
782 | { | 782 | { |
783 | .procname = "nf_conntrack_dccp_loose", | 783 | .procname = "nf_conntrack_dccp_loose", |
784 | .maxlen = sizeof(int), | 784 | .maxlen = sizeof(int), |
785 | .mode = 0644, | 785 | .mode = 0644, |
786 | .proc_handler = proc_dointvec, | 786 | .proc_handler = proc_dointvec, |
787 | }, | 787 | }, |
788 | { } | 788 | { } |
789 | }; | 789 | }; |
790 | #endif /* CONFIG_SYSCTL */ | 790 | #endif /* CONFIG_SYSCTL */ |
791 | 791 | ||
792 | static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn, | 792 | static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn, |
793 | struct nf_dccp_net *dn) | 793 | struct nf_dccp_net *dn) |
794 | { | 794 | { |
795 | #ifdef CONFIG_SYSCTL | 795 | #ifdef CONFIG_SYSCTL |
796 | if (pn->ctl_table) | 796 | if (pn->ctl_table) |
797 | return 0; | 797 | return 0; |
798 | 798 | ||
799 | pn->ctl_table = kmemdup(dccp_sysctl_table, | 799 | pn->ctl_table = kmemdup(dccp_sysctl_table, |
800 | sizeof(dccp_sysctl_table), | 800 | sizeof(dccp_sysctl_table), |
801 | GFP_KERNEL); | 801 | GFP_KERNEL); |
802 | if (!pn->ctl_table) | 802 | if (!pn->ctl_table) |
803 | return -ENOMEM; | 803 | return -ENOMEM; |
804 | 804 | ||
805 | pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST]; | 805 | pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST]; |
806 | pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND]; | 806 | pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND]; |
807 | pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN]; | 807 | pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN]; |
808 | pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN]; | 808 | pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN]; |
809 | pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ]; | 809 | pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ]; |
810 | pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING]; | 810 | pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING]; |
811 | pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT]; | 811 | pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT]; |
812 | pn->ctl_table[7].data = &dn->dccp_loose; | 812 | pn->ctl_table[7].data = &dn->dccp_loose; |
813 | 813 | ||
814 | /* Don't export sysctls to unprivileged users */ | 814 | /* Don't export sysctls to unprivileged users */ |
815 | if (net->user_ns != &init_user_ns) | 815 | if (net->user_ns != &init_user_ns) |
816 | pn->ctl_table[0].procname = NULL; | 816 | pn->ctl_table[0].procname = NULL; |
817 | #endif | 817 | #endif |
818 | return 0; | 818 | return 0; |
819 | } | 819 | } |
820 | 820 | ||
821 | static int dccp_init_net(struct net *net, u_int16_t proto) | 821 | static int dccp_init_net(struct net *net, u_int16_t proto) |
822 | { | 822 | { |
823 | struct nf_dccp_net *dn = dccp_pernet(net); | 823 | struct nf_dccp_net *dn = dccp_pernet(net); |
824 | struct nf_proto_net *pn = &dn->pn; | 824 | struct nf_proto_net *pn = &dn->pn; |
825 | 825 | ||
826 | if (!pn->users) { | 826 | if (!pn->users) { |
827 | /* default values */ | 827 | /* default values */ |
828 | dn->dccp_loose = 1; | 828 | dn->dccp_loose = 1; |
829 | dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; | 829 | dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; |
830 | dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL; | 830 | dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL; |
831 | dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL; | 831 | dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL; |
832 | dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ; | 832 | dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ; |
833 | dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; | 833 | dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; |
834 | dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; | 834 | dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; |
835 | dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; | 835 | dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; |
836 | 836 | ||
837 | /* timeouts[0] is unused, make it same as SYN_SENT so | 837 | /* timeouts[0] is unused, make it same as SYN_SENT so |
838 | * ->timeouts[0] contains 'new' timeout, like udp or icmp. | 838 | * ->timeouts[0] contains 'new' timeout, like udp or icmp. |
839 | */ | 839 | */ |
840 | dn->dccp_timeout[CT_DCCP_NONE] = dn->dccp_timeout[CT_DCCP_REQUEST]; | 840 | dn->dccp_timeout[CT_DCCP_NONE] = dn->dccp_timeout[CT_DCCP_REQUEST]; |
841 | } | 841 | } |
842 | 842 | ||
843 | return dccp_kmemdup_sysctl_table(net, pn, dn); | 843 | return dccp_kmemdup_sysctl_table(net, pn, dn); |
844 | } | 844 | } |
845 | 845 | ||
846 | static struct nf_proto_net *dccp_get_net_proto(struct net *net) | 846 | static struct nf_proto_net *dccp_get_net_proto(struct net *net) |
847 | { | 847 | { |
848 | return &net->ct.nf_ct_proto.dccp.pn; | 848 | return &net->ct.nf_ct_proto.dccp.pn; |
849 | } | 849 | } |
850 | 850 | ||
851 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = { | 851 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp4 = { |
852 | .l3proto = AF_INET, | 852 | .l3proto = AF_INET, |
853 | .l4proto = IPPROTO_DCCP, | 853 | .l4proto = IPPROTO_DCCP, |
854 | .packet = dccp_packet, | 854 | .packet = dccp_packet, |
855 | .error = dccp_error, | 855 | .error = dccp_error, |
856 | .can_early_drop = dccp_can_early_drop, | 856 | .can_early_drop = dccp_can_early_drop, |
857 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 857 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
858 | .print_conntrack = dccp_print_conntrack, | 858 | .print_conntrack = dccp_print_conntrack, |
859 | #endif | 859 | #endif |
860 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 860 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
861 | .nlattr_size = DCCP_NLATTR_SIZE, | 861 | .nlattr_size = DCCP_NLATTR_SIZE, |
862 | .to_nlattr = dccp_to_nlattr, | 862 | .to_nlattr = dccp_to_nlattr, |
863 | .from_nlattr = nlattr_to_dccp, | 863 | .from_nlattr = nlattr_to_dccp, |
864 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 864 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
865 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 865 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
866 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 866 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
867 | .nla_policy = nf_ct_port_nla_policy, | 867 | .nla_policy = nf_ct_port_nla_policy, |
868 | #endif | 868 | #endif |
869 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 869 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
870 | .ctnl_timeout = { | 870 | .ctnl_timeout = { |
871 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, | 871 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, |
872 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, | 872 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, |
873 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, | 873 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, |
874 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, | 874 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, |
875 | .nla_policy = dccp_timeout_nla_policy, | 875 | .nla_policy = dccp_timeout_nla_policy, |
876 | }, | 876 | }, |
877 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 877 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
878 | .init_net = dccp_init_net, | 878 | .init_net = dccp_init_net, |
879 | .get_net_proto = dccp_get_net_proto, | 879 | .get_net_proto = dccp_get_net_proto, |
880 | }; | 880 | }; |
881 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp4); | 881 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp4); |
882 | 882 | ||
883 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 = { | 883 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_dccp6 = { |
884 | .l3proto = AF_INET6, | 884 | .l3proto = AF_INET6, |
885 | .l4proto = IPPROTO_DCCP, | 885 | .l4proto = IPPROTO_DCCP, |
886 | .packet = dccp_packet, | 886 | .packet = dccp_packet, |
887 | .error = dccp_error, | 887 | .error = dccp_error, |
888 | .can_early_drop = dccp_can_early_drop, | 888 | .can_early_drop = dccp_can_early_drop, |
889 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 889 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
890 | .print_conntrack = dccp_print_conntrack, | 890 | .print_conntrack = dccp_print_conntrack, |
891 | #endif | 891 | #endif |
892 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 892 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
893 | .nlattr_size = DCCP_NLATTR_SIZE, | 893 | .nlattr_size = DCCP_NLATTR_SIZE, |
894 | .to_nlattr = dccp_to_nlattr, | 894 | .to_nlattr = dccp_to_nlattr, |
895 | .from_nlattr = nlattr_to_dccp, | 895 | .from_nlattr = nlattr_to_dccp, |
896 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 896 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
897 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 897 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
898 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 898 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
899 | .nla_policy = nf_ct_port_nla_policy, | 899 | .nla_policy = nf_ct_port_nla_policy, |
900 | #endif | 900 | #endif |
901 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 901 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
902 | .ctnl_timeout = { | 902 | .ctnl_timeout = { |
903 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, | 903 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, |
904 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, | 904 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, |
905 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, | 905 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, |
906 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, | 906 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, |
907 | .nla_policy = dccp_timeout_nla_policy, | 907 | .nla_policy = dccp_timeout_nla_policy, |
908 | }, | 908 | }, |
909 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 909 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
910 | .init_net = dccp_init_net, | 910 | .init_net = dccp_init_net, |
911 | .get_net_proto = dccp_get_net_proto, | 911 | .get_net_proto = dccp_get_net_proto, |
912 | }; | 912 | }; |
913 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp6); | 913 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_dccp6); |
914 | 914 |
net/netfilter/nf_conntrack_proto_generic.c
1 | /* (C) 1999-2001 Paul `Rusty' Russell | 1 | /* (C) 1999-2001 Paul `Rusty' Russell |
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/jiffies.h> | 10 | #include <linux/jiffies.h> |
11 | #include <linux/timer.h> | 11 | #include <linux/timer.h> |
12 | #include <linux/netfilter.h> | 12 | #include <linux/netfilter.h> |
13 | #include <net/netfilter/nf_conntrack_l4proto.h> | 13 | #include <net/netfilter/nf_conntrack_l4proto.h> |
14 | #include <net/netfilter/nf_conntrack_timeout.h> | 14 | #include <net/netfilter/nf_conntrack_timeout.h> |
15 | 15 | ||
16 | static const unsigned int nf_ct_generic_timeout = 600*HZ; | 16 | static const unsigned int nf_ct_generic_timeout = 600*HZ; |
17 | 17 | ||
18 | static bool nf_generic_should_process(u8 proto) | 18 | static bool nf_generic_should_process(u8 proto) |
19 | { | 19 | { |
20 | switch (proto) { | 20 | switch (proto) { |
21 | #ifdef CONFIG_NF_CT_PROTO_GRE_MODULE | 21 | #ifdef CONFIG_NF_CT_PROTO_GRE_MODULE |
22 | case IPPROTO_GRE: | 22 | case IPPROTO_GRE: |
23 | return false; | 23 | return false; |
24 | #endif | 24 | #endif |
25 | default: | 25 | default: |
26 | return true; | 26 | return true; |
27 | } | 27 | } |
28 | } | 28 | } |
29 | 29 | ||
30 | static inline struct nf_generic_net *generic_pernet(struct net *net) | 30 | static inline struct nf_generic_net *generic_pernet(struct net *net) |
31 | { | 31 | { |
32 | return &net->ct.nf_ct_proto.generic; | 32 | return &net->ct.nf_ct_proto.generic; |
33 | } | 33 | } |
34 | 34 | ||
35 | static bool generic_pkt_to_tuple(const struct sk_buff *skb, | 35 | static bool generic_pkt_to_tuple(const struct sk_buff *skb, |
36 | unsigned int dataoff, | 36 | unsigned int dataoff, |
37 | struct net *net, struct nf_conntrack_tuple *tuple) | 37 | struct net *net, struct nf_conntrack_tuple *tuple) |
38 | { | 38 | { |
39 | tuple->src.u.all = 0; | 39 | tuple->src.u.all = 0; |
40 | tuple->dst.u.all = 0; | 40 | tuple->dst.u.all = 0; |
41 | 41 | ||
42 | return true; | 42 | return true; |
43 | } | 43 | } |
44 | 44 | ||
45 | /* Returns verdict for packet, or -1 for invalid. */ | 45 | /* Returns verdict for packet, or -1 for invalid. */ |
46 | static int generic_packet(struct nf_conn *ct, | 46 | static int generic_packet(struct nf_conn *ct, |
47 | const struct sk_buff *skb, | 47 | struct sk_buff *skb, |
48 | unsigned int dataoff, | 48 | unsigned int dataoff, |
49 | enum ip_conntrack_info ctinfo, | 49 | enum ip_conntrack_info ctinfo, |
50 | const struct nf_hook_state *state) | 50 | const struct nf_hook_state *state) |
51 | { | 51 | { |
52 | const unsigned int *timeout = nf_ct_timeout_lookup(ct); | 52 | const unsigned int *timeout = nf_ct_timeout_lookup(ct); |
53 | 53 | ||
54 | if (!nf_generic_should_process(nf_ct_protonum(ct))) { | 54 | if (!nf_generic_should_process(nf_ct_protonum(ct))) { |
55 | pr_warn_once("conntrack: generic helper won't handle protocol %d. Please consider loading the specific helper module.\n", | 55 | pr_warn_once("conntrack: generic helper won't handle protocol %d. Please consider loading the specific helper module.\n", |
56 | nf_ct_protonum(ct)); | 56 | nf_ct_protonum(ct)); |
57 | return -NF_ACCEPT; | 57 | return -NF_ACCEPT; |
58 | } | 58 | } |
59 | 59 | ||
60 | if (!timeout) | 60 | if (!timeout) |
61 | timeout = &generic_pernet(nf_ct_net(ct))->timeout; | 61 | timeout = &generic_pernet(nf_ct_net(ct))->timeout; |
62 | 62 | ||
63 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); | 63 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
64 | return NF_ACCEPT; | 64 | return NF_ACCEPT; |
65 | } | 65 | } |
66 | 66 | ||
67 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 67 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
68 | 68 | ||
69 | #include <linux/netfilter/nfnetlink.h> | 69 | #include <linux/netfilter/nfnetlink.h> |
70 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 70 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
71 | 71 | ||
72 | static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], | 72 | static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], |
73 | struct net *net, void *data) | 73 | struct net *net, void *data) |
74 | { | 74 | { |
75 | struct nf_generic_net *gn = generic_pernet(net); | 75 | struct nf_generic_net *gn = generic_pernet(net); |
76 | unsigned int *timeout = data; | 76 | unsigned int *timeout = data; |
77 | 77 | ||
78 | if (!timeout) | 78 | if (!timeout) |
79 | timeout = &gn->timeout; | 79 | timeout = &gn->timeout; |
80 | 80 | ||
81 | if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT]) | 81 | if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT]) |
82 | *timeout = | 82 | *timeout = |
83 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ; | 83 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ; |
84 | else { | 84 | else { |
85 | /* Set default generic timeout. */ | 85 | /* Set default generic timeout. */ |
86 | *timeout = gn->timeout; | 86 | *timeout = gn->timeout; |
87 | } | 87 | } |
88 | 88 | ||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | static int | 92 | static int |
93 | generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 93 | generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
94 | { | 94 | { |
95 | const unsigned int *timeout = data; | 95 | const unsigned int *timeout = data; |
96 | 96 | ||
97 | if (nla_put_be32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ))) | 97 | if (nla_put_be32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ))) |
98 | goto nla_put_failure; | 98 | goto nla_put_failure; |
99 | 99 | ||
100 | return 0; | 100 | return 0; |
101 | 101 | ||
102 | nla_put_failure: | 102 | nla_put_failure: |
103 | return -ENOSPC; | 103 | return -ENOSPC; |
104 | } | 104 | } |
105 | 105 | ||
106 | static const struct nla_policy | 106 | static const struct nla_policy |
107 | generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = { | 107 | generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = { |
108 | [CTA_TIMEOUT_GENERIC_TIMEOUT] = { .type = NLA_U32 }, | 108 | [CTA_TIMEOUT_GENERIC_TIMEOUT] = { .type = NLA_U32 }, |
109 | }; | 109 | }; |
110 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 110 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
111 | 111 | ||
112 | #ifdef CONFIG_SYSCTL | 112 | #ifdef CONFIG_SYSCTL |
113 | static struct ctl_table generic_sysctl_table[] = { | 113 | static struct ctl_table generic_sysctl_table[] = { |
114 | { | 114 | { |
115 | .procname = "nf_conntrack_generic_timeout", | 115 | .procname = "nf_conntrack_generic_timeout", |
116 | .maxlen = sizeof(unsigned int), | 116 | .maxlen = sizeof(unsigned int), |
117 | .mode = 0644, | 117 | .mode = 0644, |
118 | .proc_handler = proc_dointvec_jiffies, | 118 | .proc_handler = proc_dointvec_jiffies, |
119 | }, | 119 | }, |
120 | { } | 120 | { } |
121 | }; | 121 | }; |
122 | #endif /* CONFIG_SYSCTL */ | 122 | #endif /* CONFIG_SYSCTL */ |
123 | 123 | ||
124 | static int generic_kmemdup_sysctl_table(struct nf_proto_net *pn, | 124 | static int generic_kmemdup_sysctl_table(struct nf_proto_net *pn, |
125 | struct nf_generic_net *gn) | 125 | struct nf_generic_net *gn) |
126 | { | 126 | { |
127 | #ifdef CONFIG_SYSCTL | 127 | #ifdef CONFIG_SYSCTL |
128 | pn->ctl_table = kmemdup(generic_sysctl_table, | 128 | pn->ctl_table = kmemdup(generic_sysctl_table, |
129 | sizeof(generic_sysctl_table), | 129 | sizeof(generic_sysctl_table), |
130 | GFP_KERNEL); | 130 | GFP_KERNEL); |
131 | if (!pn->ctl_table) | 131 | if (!pn->ctl_table) |
132 | return -ENOMEM; | 132 | return -ENOMEM; |
133 | 133 | ||
134 | pn->ctl_table[0].data = &gn->timeout; | 134 | pn->ctl_table[0].data = &gn->timeout; |
135 | #endif | 135 | #endif |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | static int generic_init_net(struct net *net, u_int16_t proto) | 139 | static int generic_init_net(struct net *net, u_int16_t proto) |
140 | { | 140 | { |
141 | struct nf_generic_net *gn = generic_pernet(net); | 141 | struct nf_generic_net *gn = generic_pernet(net); |
142 | struct nf_proto_net *pn = &gn->pn; | 142 | struct nf_proto_net *pn = &gn->pn; |
143 | 143 | ||
144 | gn->timeout = nf_ct_generic_timeout; | 144 | gn->timeout = nf_ct_generic_timeout; |
145 | 145 | ||
146 | return generic_kmemdup_sysctl_table(pn, gn); | 146 | return generic_kmemdup_sysctl_table(pn, gn); |
147 | } | 147 | } |
148 | 148 | ||
149 | static struct nf_proto_net *generic_get_net_proto(struct net *net) | 149 | static struct nf_proto_net *generic_get_net_proto(struct net *net) |
150 | { | 150 | { |
151 | return &net->ct.nf_ct_proto.generic.pn; | 151 | return &net->ct.nf_ct_proto.generic.pn; |
152 | } | 152 | } |
153 | 153 | ||
154 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic = | 154 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic = |
155 | { | 155 | { |
156 | .l3proto = PF_UNSPEC, | 156 | .l3proto = PF_UNSPEC, |
157 | .l4proto = 255, | 157 | .l4proto = 255, |
158 | .pkt_to_tuple = generic_pkt_to_tuple, | 158 | .pkt_to_tuple = generic_pkt_to_tuple, |
159 | .packet = generic_packet, | 159 | .packet = generic_packet, |
160 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 160 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
161 | .ctnl_timeout = { | 161 | .ctnl_timeout = { |
162 | .nlattr_to_obj = generic_timeout_nlattr_to_obj, | 162 | .nlattr_to_obj = generic_timeout_nlattr_to_obj, |
163 | .obj_to_nlattr = generic_timeout_obj_to_nlattr, | 163 | .obj_to_nlattr = generic_timeout_obj_to_nlattr, |
164 | .nlattr_max = CTA_TIMEOUT_GENERIC_MAX, | 164 | .nlattr_max = CTA_TIMEOUT_GENERIC_MAX, |
165 | .obj_size = sizeof(unsigned int), | 165 | .obj_size = sizeof(unsigned int), |
166 | .nla_policy = generic_timeout_nla_policy, | 166 | .nla_policy = generic_timeout_nla_policy, |
167 | }, | 167 | }, |
168 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 168 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
169 | .init_net = generic_init_net, | 169 | .init_net = generic_init_net, |
170 | .get_net_proto = generic_get_net_proto, | 170 | .get_net_proto = generic_get_net_proto, |
171 | }; | 171 | }; |
172 | 172 |
net/netfilter/nf_conntrack_proto_gre.c
1 | /* | 1 | /* |
2 | * ip_conntrack_proto_gre.c - Version 3.0 | 2 | * ip_conntrack_proto_gre.c - Version 3.0 |
3 | * | 3 | * |
4 | * Connection tracking protocol helper module for GRE. | 4 | * Connection tracking protocol helper module for GRE. |
5 | * | 5 | * |
6 | * GRE is a generic encapsulation protocol, which is generally not very | 6 | * GRE is a generic encapsulation protocol, which is generally not very |
7 | * suited for NAT, as it has no protocol-specific part as port numbers. | 7 | * suited for NAT, as it has no protocol-specific part as port numbers. |
8 | * | 8 | * |
9 | * It has an optional key field, which may help us distinguishing two | 9 | * It has an optional key field, which may help us distinguishing two |
10 | * connections between the same two hosts. | 10 | * connections between the same two hosts. |
11 | * | 11 | * |
12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 | 12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 |
13 | * | 13 | * |
14 | * PPTP is built on top of a modified version of GRE, and has a mandatory | 14 | * PPTP is built on top of a modified version of GRE, and has a mandatory |
15 | * field called "CallID", which serves us for the same purpose as the key | 15 | * field called "CallID", which serves us for the same purpose as the key |
16 | * field in plain GRE. | 16 | * field in plain GRE. |
17 | * | 17 | * |
18 | * Documentation about PPTP can be found in RFC 2637 | 18 | * Documentation about PPTP can be found in RFC 2637 |
19 | * | 19 | * |
20 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | 20 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> |
21 | * | 21 | * |
22 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | 22 | * Development of this code funded by Astaro AG (http://www.astaro.com/) |
23 | * | 23 | * |
24 | * (C) 2006-2012 Patrick McHardy <kaber@trash.net> | 24 | * (C) 2006-2012 Patrick McHardy <kaber@trash.net> |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
30 | #include <linux/list.h> | 30 | #include <linux/list.h> |
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/in.h> | 32 | #include <linux/in.h> |
33 | #include <linux/netdevice.h> | 33 | #include <linux/netdevice.h> |
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <net/dst.h> | 36 | #include <net/dst.h> |
37 | #include <net/net_namespace.h> | 37 | #include <net/net_namespace.h> |
38 | #include <net/netns/generic.h> | 38 | #include <net/netns/generic.h> |
39 | #include <net/netfilter/nf_conntrack_l4proto.h> | 39 | #include <net/netfilter/nf_conntrack_l4proto.h> |
40 | #include <net/netfilter/nf_conntrack_helper.h> | 40 | #include <net/netfilter/nf_conntrack_helper.h> |
41 | #include <net/netfilter/nf_conntrack_core.h> | 41 | #include <net/netfilter/nf_conntrack_core.h> |
42 | #include <net/netfilter/nf_conntrack_timeout.h> | 42 | #include <net/netfilter/nf_conntrack_timeout.h> |
43 | #include <linux/netfilter/nf_conntrack_proto_gre.h> | 43 | #include <linux/netfilter/nf_conntrack_proto_gre.h> |
44 | #include <linux/netfilter/nf_conntrack_pptp.h> | 44 | #include <linux/netfilter/nf_conntrack_pptp.h> |
45 | 45 | ||
46 | enum grep_conntrack { | 46 | enum grep_conntrack { |
47 | GRE_CT_UNREPLIED, | 47 | GRE_CT_UNREPLIED, |
48 | GRE_CT_REPLIED, | 48 | GRE_CT_REPLIED, |
49 | GRE_CT_MAX | 49 | GRE_CT_MAX |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static const unsigned int gre_timeouts[GRE_CT_MAX] = { | 52 | static const unsigned int gre_timeouts[GRE_CT_MAX] = { |
53 | [GRE_CT_UNREPLIED] = 30*HZ, | 53 | [GRE_CT_UNREPLIED] = 30*HZ, |
54 | [GRE_CT_REPLIED] = 180*HZ, | 54 | [GRE_CT_REPLIED] = 180*HZ, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static unsigned int proto_gre_net_id __read_mostly; | 57 | static unsigned int proto_gre_net_id __read_mostly; |
58 | struct netns_proto_gre { | 58 | struct netns_proto_gre { |
59 | struct nf_proto_net nf; | 59 | struct nf_proto_net nf; |
60 | rwlock_t keymap_lock; | 60 | rwlock_t keymap_lock; |
61 | struct list_head keymap_list; | 61 | struct list_head keymap_list; |
62 | unsigned int gre_timeouts[GRE_CT_MAX]; | 62 | unsigned int gre_timeouts[GRE_CT_MAX]; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | static inline struct netns_proto_gre *gre_pernet(struct net *net) | 65 | static inline struct netns_proto_gre *gre_pernet(struct net *net) |
66 | { | 66 | { |
67 | return net_generic(net, proto_gre_net_id); | 67 | return net_generic(net, proto_gre_net_id); |
68 | } | 68 | } |
69 | 69 | ||
70 | static void nf_ct_gre_keymap_flush(struct net *net) | 70 | static void nf_ct_gre_keymap_flush(struct net *net) |
71 | { | 71 | { |
72 | struct netns_proto_gre *net_gre = gre_pernet(net); | 72 | struct netns_proto_gre *net_gre = gre_pernet(net); |
73 | struct nf_ct_gre_keymap *km, *tmp; | 73 | struct nf_ct_gre_keymap *km, *tmp; |
74 | 74 | ||
75 | write_lock_bh(&net_gre->keymap_lock); | 75 | write_lock_bh(&net_gre->keymap_lock); |
76 | list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) { | 76 | list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) { |
77 | list_del(&km->list); | 77 | list_del(&km->list); |
78 | kfree(km); | 78 | kfree(km); |
79 | } | 79 | } |
80 | write_unlock_bh(&net_gre->keymap_lock); | 80 | write_unlock_bh(&net_gre->keymap_lock); |
81 | } | 81 | } |
82 | 82 | ||
83 | static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, | 83 | static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km, |
84 | const struct nf_conntrack_tuple *t) | 84 | const struct nf_conntrack_tuple *t) |
85 | { | 85 | { |
86 | return km->tuple.src.l3num == t->src.l3num && | 86 | return km->tuple.src.l3num == t->src.l3num && |
87 | !memcmp(&km->tuple.src.u3, &t->src.u3, sizeof(t->src.u3)) && | 87 | !memcmp(&km->tuple.src.u3, &t->src.u3, sizeof(t->src.u3)) && |
88 | !memcmp(&km->tuple.dst.u3, &t->dst.u3, sizeof(t->dst.u3)) && | 88 | !memcmp(&km->tuple.dst.u3, &t->dst.u3, sizeof(t->dst.u3)) && |
89 | km->tuple.dst.protonum == t->dst.protonum && | 89 | km->tuple.dst.protonum == t->dst.protonum && |
90 | km->tuple.dst.u.all == t->dst.u.all; | 90 | km->tuple.dst.u.all == t->dst.u.all; |
91 | } | 91 | } |
92 | 92 | ||
93 | /* look up the source key for a given tuple */ | 93 | /* look up the source key for a given tuple */ |
94 | static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t) | 94 | static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t) |
95 | { | 95 | { |
96 | struct netns_proto_gre *net_gre = gre_pernet(net); | 96 | struct netns_proto_gre *net_gre = gre_pernet(net); |
97 | struct nf_ct_gre_keymap *km; | 97 | struct nf_ct_gre_keymap *km; |
98 | __be16 key = 0; | 98 | __be16 key = 0; |
99 | 99 | ||
100 | read_lock_bh(&net_gre->keymap_lock); | 100 | read_lock_bh(&net_gre->keymap_lock); |
101 | list_for_each_entry(km, &net_gre->keymap_list, list) { | 101 | list_for_each_entry(km, &net_gre->keymap_list, list) { |
102 | if (gre_key_cmpfn(km, t)) { | 102 | if (gre_key_cmpfn(km, t)) { |
103 | key = km->tuple.src.u.gre.key; | 103 | key = km->tuple.src.u.gre.key; |
104 | break; | 104 | break; |
105 | } | 105 | } |
106 | } | 106 | } |
107 | read_unlock_bh(&net_gre->keymap_lock); | 107 | read_unlock_bh(&net_gre->keymap_lock); |
108 | 108 | ||
109 | pr_debug("lookup src key 0x%x for ", key); | 109 | pr_debug("lookup src key 0x%x for ", key); |
110 | nf_ct_dump_tuple(t); | 110 | nf_ct_dump_tuple(t); |
111 | 111 | ||
112 | return key; | 112 | return key; |
113 | } | 113 | } |
114 | 114 | ||
115 | /* add a single keymap entry, associate with specified master ct */ | 115 | /* add a single keymap entry, associate with specified master ct */ |
116 | int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, | 116 | int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, |
117 | struct nf_conntrack_tuple *t) | 117 | struct nf_conntrack_tuple *t) |
118 | { | 118 | { |
119 | struct net *net = nf_ct_net(ct); | 119 | struct net *net = nf_ct_net(ct); |
120 | struct netns_proto_gre *net_gre = gre_pernet(net); | 120 | struct netns_proto_gre *net_gre = gre_pernet(net); |
121 | struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct); | 121 | struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct); |
122 | struct nf_ct_gre_keymap **kmp, *km; | 122 | struct nf_ct_gre_keymap **kmp, *km; |
123 | 123 | ||
124 | kmp = &ct_pptp_info->keymap[dir]; | 124 | kmp = &ct_pptp_info->keymap[dir]; |
125 | if (*kmp) { | 125 | if (*kmp) { |
126 | /* check whether it's a retransmission */ | 126 | /* check whether it's a retransmission */ |
127 | read_lock_bh(&net_gre->keymap_lock); | 127 | read_lock_bh(&net_gre->keymap_lock); |
128 | list_for_each_entry(km, &net_gre->keymap_list, list) { | 128 | list_for_each_entry(km, &net_gre->keymap_list, list) { |
129 | if (gre_key_cmpfn(km, t) && km == *kmp) { | 129 | if (gre_key_cmpfn(km, t) && km == *kmp) { |
130 | read_unlock_bh(&net_gre->keymap_lock); | 130 | read_unlock_bh(&net_gre->keymap_lock); |
131 | return 0; | 131 | return 0; |
132 | } | 132 | } |
133 | } | 133 | } |
134 | read_unlock_bh(&net_gre->keymap_lock); | 134 | read_unlock_bh(&net_gre->keymap_lock); |
135 | pr_debug("trying to override keymap_%s for ct %p\n", | 135 | pr_debug("trying to override keymap_%s for ct %p\n", |
136 | dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); | 136 | dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct); |
137 | return -EEXIST; | 137 | return -EEXIST; |
138 | } | 138 | } |
139 | 139 | ||
140 | km = kmalloc(sizeof(*km), GFP_ATOMIC); | 140 | km = kmalloc(sizeof(*km), GFP_ATOMIC); |
141 | if (!km) | 141 | if (!km) |
142 | return -ENOMEM; | 142 | return -ENOMEM; |
143 | memcpy(&km->tuple, t, sizeof(*t)); | 143 | memcpy(&km->tuple, t, sizeof(*t)); |
144 | *kmp = km; | 144 | *kmp = km; |
145 | 145 | ||
146 | pr_debug("adding new entry %p: ", km); | 146 | pr_debug("adding new entry %p: ", km); |
147 | nf_ct_dump_tuple(&km->tuple); | 147 | nf_ct_dump_tuple(&km->tuple); |
148 | 148 | ||
149 | write_lock_bh(&net_gre->keymap_lock); | 149 | write_lock_bh(&net_gre->keymap_lock); |
150 | list_add_tail(&km->list, &net_gre->keymap_list); | 150 | list_add_tail(&km->list, &net_gre->keymap_list); |
151 | write_unlock_bh(&net_gre->keymap_lock); | 151 | write_unlock_bh(&net_gre->keymap_lock); |
152 | 152 | ||
153 | return 0; | 153 | return 0; |
154 | } | 154 | } |
155 | EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add); | 155 | EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add); |
156 | 156 | ||
157 | /* destroy the keymap entries associated with specified master ct */ | 157 | /* destroy the keymap entries associated with specified master ct */ |
158 | void nf_ct_gre_keymap_destroy(struct nf_conn *ct) | 158 | void nf_ct_gre_keymap_destroy(struct nf_conn *ct) |
159 | { | 159 | { |
160 | struct net *net = nf_ct_net(ct); | 160 | struct net *net = nf_ct_net(ct); |
161 | struct netns_proto_gre *net_gre = gre_pernet(net); | 161 | struct netns_proto_gre *net_gre = gre_pernet(net); |
162 | struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct); | 162 | struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct); |
163 | enum ip_conntrack_dir dir; | 163 | enum ip_conntrack_dir dir; |
164 | 164 | ||
165 | pr_debug("entering for ct %p\n", ct); | 165 | pr_debug("entering for ct %p\n", ct); |
166 | 166 | ||
167 | write_lock_bh(&net_gre->keymap_lock); | 167 | write_lock_bh(&net_gre->keymap_lock); |
168 | for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { | 168 | for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) { |
169 | if (ct_pptp_info->keymap[dir]) { | 169 | if (ct_pptp_info->keymap[dir]) { |
170 | pr_debug("removing %p from list\n", | 170 | pr_debug("removing %p from list\n", |
171 | ct_pptp_info->keymap[dir]); | 171 | ct_pptp_info->keymap[dir]); |
172 | list_del(&ct_pptp_info->keymap[dir]->list); | 172 | list_del(&ct_pptp_info->keymap[dir]->list); |
173 | kfree(ct_pptp_info->keymap[dir]); | 173 | kfree(ct_pptp_info->keymap[dir]); |
174 | ct_pptp_info->keymap[dir] = NULL; | 174 | ct_pptp_info->keymap[dir] = NULL; |
175 | } | 175 | } |
176 | } | 176 | } |
177 | write_unlock_bh(&net_gre->keymap_lock); | 177 | write_unlock_bh(&net_gre->keymap_lock); |
178 | } | 178 | } |
179 | EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); | 179 | EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); |
180 | 180 | ||
181 | /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ | 181 | /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ |
182 | 182 | ||
183 | /* gre hdr info to tuple */ | 183 | /* gre hdr info to tuple */ |
184 | static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, | 184 | static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, |
185 | struct net *net, struct nf_conntrack_tuple *tuple) | 185 | struct net *net, struct nf_conntrack_tuple *tuple) |
186 | { | 186 | { |
187 | const struct pptp_gre_header *pgrehdr; | 187 | const struct pptp_gre_header *pgrehdr; |
188 | struct pptp_gre_header _pgrehdr; | 188 | struct pptp_gre_header _pgrehdr; |
189 | __be16 srckey; | 189 | __be16 srckey; |
190 | const struct gre_base_hdr *grehdr; | 190 | const struct gre_base_hdr *grehdr; |
191 | struct gre_base_hdr _grehdr; | 191 | struct gre_base_hdr _grehdr; |
192 | 192 | ||
193 | /* first only delinearize old RFC1701 GRE header */ | 193 | /* first only delinearize old RFC1701 GRE header */ |
194 | grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); | 194 | grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); |
195 | if (!grehdr || (grehdr->flags & GRE_VERSION) != GRE_VERSION_1) { | 195 | if (!grehdr || (grehdr->flags & GRE_VERSION) != GRE_VERSION_1) { |
196 | /* try to behave like "nf_conntrack_proto_generic" */ | 196 | /* try to behave like "nf_conntrack_proto_generic" */ |
197 | tuple->src.u.all = 0; | 197 | tuple->src.u.all = 0; |
198 | tuple->dst.u.all = 0; | 198 | tuple->dst.u.all = 0; |
199 | return true; | 199 | return true; |
200 | } | 200 | } |
201 | 201 | ||
202 | /* PPTP header is variable length, only need up to the call_id field */ | 202 | /* PPTP header is variable length, only need up to the call_id field */ |
203 | pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); | 203 | pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); |
204 | if (!pgrehdr) | 204 | if (!pgrehdr) |
205 | return true; | 205 | return true; |
206 | 206 | ||
207 | if (grehdr->protocol != GRE_PROTO_PPP) { | 207 | if (grehdr->protocol != GRE_PROTO_PPP) { |
208 | pr_debug("Unsupported GRE proto(0x%x)\n", ntohs(grehdr->protocol)); | 208 | pr_debug("Unsupported GRE proto(0x%x)\n", ntohs(grehdr->protocol)); |
209 | return false; | 209 | return false; |
210 | } | 210 | } |
211 | 211 | ||
212 | tuple->dst.u.gre.key = pgrehdr->call_id; | 212 | tuple->dst.u.gre.key = pgrehdr->call_id; |
213 | srckey = gre_keymap_lookup(net, tuple); | 213 | srckey = gre_keymap_lookup(net, tuple); |
214 | tuple->src.u.gre.key = srckey; | 214 | tuple->src.u.gre.key = srckey; |
215 | 215 | ||
216 | return true; | 216 | return true; |
217 | } | 217 | } |
218 | 218 | ||
219 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 219 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
220 | /* print private data for conntrack */ | 220 | /* print private data for conntrack */ |
221 | static void gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) | 221 | static void gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) |
222 | { | 222 | { |
223 | seq_printf(s, "timeout=%u, stream_timeout=%u ", | 223 | seq_printf(s, "timeout=%u, stream_timeout=%u ", |
224 | (ct->proto.gre.timeout / HZ), | 224 | (ct->proto.gre.timeout / HZ), |
225 | (ct->proto.gre.stream_timeout / HZ)); | 225 | (ct->proto.gre.stream_timeout / HZ)); |
226 | } | 226 | } |
227 | #endif | 227 | #endif |
228 | 228 | ||
229 | static unsigned int *gre_get_timeouts(struct net *net) | 229 | static unsigned int *gre_get_timeouts(struct net *net) |
230 | { | 230 | { |
231 | return gre_pernet(net)->gre_timeouts; | 231 | return gre_pernet(net)->gre_timeouts; |
232 | } | 232 | } |
233 | 233 | ||
234 | /* Returns verdict for packet, and may modify conntrack */ | 234 | /* Returns verdict for packet, and may modify conntrack */ |
235 | static int gre_packet(struct nf_conn *ct, | 235 | static int gre_packet(struct nf_conn *ct, |
236 | const struct sk_buff *skb, | 236 | struct sk_buff *skb, |
237 | unsigned int dataoff, | 237 | unsigned int dataoff, |
238 | enum ip_conntrack_info ctinfo, | 238 | enum ip_conntrack_info ctinfo, |
239 | const struct nf_hook_state *state) | 239 | const struct nf_hook_state *state) |
240 | { | 240 | { |
241 | if (!nf_ct_is_confirmed(ct)) { | 241 | if (!nf_ct_is_confirmed(ct)) { |
242 | unsigned int *timeouts = nf_ct_timeout_lookup(ct); | 242 | unsigned int *timeouts = nf_ct_timeout_lookup(ct); |
243 | 243 | ||
244 | if (!timeouts) | 244 | if (!timeouts) |
245 | timeouts = gre_get_timeouts(nf_ct_net(ct)); | 245 | timeouts = gre_get_timeouts(nf_ct_net(ct)); |
246 | 246 | ||
247 | /* initialize to sane value. Ideally a conntrack helper | 247 | /* initialize to sane value. Ideally a conntrack helper |
248 | * (e.g. in case of pptp) is increasing them */ | 248 | * (e.g. in case of pptp) is increasing them */ |
249 | ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED]; | 249 | ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED]; |
250 | ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED]; | 250 | ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED]; |
251 | } | 251 | } |
252 | 252 | ||
253 | /* If we've seen traffic both ways, this is a GRE connection. | 253 | /* If we've seen traffic both ways, this is a GRE connection. |
254 | * Extend timeout. */ | 254 | * Extend timeout. */ |
255 | if (ct->status & IPS_SEEN_REPLY) { | 255 | if (ct->status & IPS_SEEN_REPLY) { |
256 | nf_ct_refresh_acct(ct, ctinfo, skb, | 256 | nf_ct_refresh_acct(ct, ctinfo, skb, |
257 | ct->proto.gre.stream_timeout); | 257 | ct->proto.gre.stream_timeout); |
258 | /* Also, more likely to be important, and not a probe. */ | 258 | /* Also, more likely to be important, and not a probe. */ |
259 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) | 259 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) |
260 | nf_conntrack_event_cache(IPCT_ASSURED, ct); | 260 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
261 | } else | 261 | } else |
262 | nf_ct_refresh_acct(ct, ctinfo, skb, | 262 | nf_ct_refresh_acct(ct, ctinfo, skb, |
263 | ct->proto.gre.timeout); | 263 | ct->proto.gre.timeout); |
264 | 264 | ||
265 | return NF_ACCEPT; | 265 | return NF_ACCEPT; |
266 | } | 266 | } |
267 | 267 | ||
268 | /* Called when a conntrack entry has already been removed from the hashes | 268 | /* Called when a conntrack entry has already been removed from the hashes |
269 | * and is about to be deleted from memory */ | 269 | * and is about to be deleted from memory */ |
270 | static void gre_destroy(struct nf_conn *ct) | 270 | static void gre_destroy(struct nf_conn *ct) |
271 | { | 271 | { |
272 | struct nf_conn *master = ct->master; | 272 | struct nf_conn *master = ct->master; |
273 | pr_debug(" entering\n"); | 273 | pr_debug(" entering\n"); |
274 | 274 | ||
275 | if (!master) | 275 | if (!master) |
276 | pr_debug("no master !?!\n"); | 276 | pr_debug("no master !?!\n"); |
277 | else | 277 | else |
278 | nf_ct_gre_keymap_destroy(master); | 278 | nf_ct_gre_keymap_destroy(master); |
279 | } | 279 | } |
280 | 280 | ||
281 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 281 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
282 | 282 | ||
283 | #include <linux/netfilter/nfnetlink.h> | 283 | #include <linux/netfilter/nfnetlink.h> |
284 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 284 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
285 | 285 | ||
286 | static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], | 286 | static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], |
287 | struct net *net, void *data) | 287 | struct net *net, void *data) |
288 | { | 288 | { |
289 | unsigned int *timeouts = data; | 289 | unsigned int *timeouts = data; |
290 | struct netns_proto_gre *net_gre = gre_pernet(net); | 290 | struct netns_proto_gre *net_gre = gre_pernet(net); |
291 | 291 | ||
292 | if (!timeouts) | 292 | if (!timeouts) |
293 | timeouts = gre_get_timeouts(net); | 293 | timeouts = gre_get_timeouts(net); |
294 | /* set default timeouts for GRE. */ | 294 | /* set default timeouts for GRE. */ |
295 | timeouts[GRE_CT_UNREPLIED] = net_gre->gre_timeouts[GRE_CT_UNREPLIED]; | 295 | timeouts[GRE_CT_UNREPLIED] = net_gre->gre_timeouts[GRE_CT_UNREPLIED]; |
296 | timeouts[GRE_CT_REPLIED] = net_gre->gre_timeouts[GRE_CT_REPLIED]; | 296 | timeouts[GRE_CT_REPLIED] = net_gre->gre_timeouts[GRE_CT_REPLIED]; |
297 | 297 | ||
298 | if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) { | 298 | if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) { |
299 | timeouts[GRE_CT_UNREPLIED] = | 299 | timeouts[GRE_CT_UNREPLIED] = |
300 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ; | 300 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ; |
301 | } | 301 | } |
302 | if (tb[CTA_TIMEOUT_GRE_REPLIED]) { | 302 | if (tb[CTA_TIMEOUT_GRE_REPLIED]) { |
303 | timeouts[GRE_CT_REPLIED] = | 303 | timeouts[GRE_CT_REPLIED] = |
304 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ; | 304 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ; |
305 | } | 305 | } |
306 | return 0; | 306 | return 0; |
307 | } | 307 | } |
308 | 308 | ||
309 | static int | 309 | static int |
310 | gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 310 | gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
311 | { | 311 | { |
312 | const unsigned int *timeouts = data; | 312 | const unsigned int *timeouts = data; |
313 | 313 | ||
314 | if (nla_put_be32(skb, CTA_TIMEOUT_GRE_UNREPLIED, | 314 | if (nla_put_be32(skb, CTA_TIMEOUT_GRE_UNREPLIED, |
315 | htonl(timeouts[GRE_CT_UNREPLIED] / HZ)) || | 315 | htonl(timeouts[GRE_CT_UNREPLIED] / HZ)) || |
316 | nla_put_be32(skb, CTA_TIMEOUT_GRE_REPLIED, | 316 | nla_put_be32(skb, CTA_TIMEOUT_GRE_REPLIED, |
317 | htonl(timeouts[GRE_CT_REPLIED] / HZ))) | 317 | htonl(timeouts[GRE_CT_REPLIED] / HZ))) |
318 | goto nla_put_failure; | 318 | goto nla_put_failure; |
319 | return 0; | 319 | return 0; |
320 | 320 | ||
321 | nla_put_failure: | 321 | nla_put_failure: |
322 | return -ENOSPC; | 322 | return -ENOSPC; |
323 | } | 323 | } |
324 | 324 | ||
325 | static const struct nla_policy | 325 | static const struct nla_policy |
326 | gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = { | 326 | gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = { |
327 | [CTA_TIMEOUT_GRE_UNREPLIED] = { .type = NLA_U32 }, | 327 | [CTA_TIMEOUT_GRE_UNREPLIED] = { .type = NLA_U32 }, |
328 | [CTA_TIMEOUT_GRE_REPLIED] = { .type = NLA_U32 }, | 328 | [CTA_TIMEOUT_GRE_REPLIED] = { .type = NLA_U32 }, |
329 | }; | 329 | }; |
330 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 330 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
331 | 331 | ||
332 | static int gre_init_net(struct net *net, u_int16_t proto) | 332 | static int gre_init_net(struct net *net, u_int16_t proto) |
333 | { | 333 | { |
334 | struct netns_proto_gre *net_gre = gre_pernet(net); | 334 | struct netns_proto_gre *net_gre = gre_pernet(net); |
335 | int i; | 335 | int i; |
336 | 336 | ||
337 | rwlock_init(&net_gre->keymap_lock); | 337 | rwlock_init(&net_gre->keymap_lock); |
338 | INIT_LIST_HEAD(&net_gre->keymap_list); | 338 | INIT_LIST_HEAD(&net_gre->keymap_list); |
339 | for (i = 0; i < GRE_CT_MAX; i++) | 339 | for (i = 0; i < GRE_CT_MAX; i++) |
340 | net_gre->gre_timeouts[i] = gre_timeouts[i]; | 340 | net_gre->gre_timeouts[i] = gre_timeouts[i]; |
341 | 341 | ||
342 | return 0; | 342 | return 0; |
343 | } | 343 | } |
344 | 344 | ||
345 | /* protocol helper struct */ | 345 | /* protocol helper struct */ |
346 | static const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = { | 346 | static const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = { |
347 | .l3proto = AF_INET, | 347 | .l3proto = AF_INET, |
348 | .l4proto = IPPROTO_GRE, | 348 | .l4proto = IPPROTO_GRE, |
349 | .pkt_to_tuple = gre_pkt_to_tuple, | 349 | .pkt_to_tuple = gre_pkt_to_tuple, |
350 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 350 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
351 | .print_conntrack = gre_print_conntrack, | 351 | .print_conntrack = gre_print_conntrack, |
352 | #endif | 352 | #endif |
353 | .packet = gre_packet, | 353 | .packet = gre_packet, |
354 | .destroy = gre_destroy, | 354 | .destroy = gre_destroy, |
355 | .me = THIS_MODULE, | 355 | .me = THIS_MODULE, |
356 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 356 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
357 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 357 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
358 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 358 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
359 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 359 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
360 | .nla_policy = nf_ct_port_nla_policy, | 360 | .nla_policy = nf_ct_port_nla_policy, |
361 | #endif | 361 | #endif |
362 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 362 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
363 | .ctnl_timeout = { | 363 | .ctnl_timeout = { |
364 | .nlattr_to_obj = gre_timeout_nlattr_to_obj, | 364 | .nlattr_to_obj = gre_timeout_nlattr_to_obj, |
365 | .obj_to_nlattr = gre_timeout_obj_to_nlattr, | 365 | .obj_to_nlattr = gre_timeout_obj_to_nlattr, |
366 | .nlattr_max = CTA_TIMEOUT_GRE_MAX, | 366 | .nlattr_max = CTA_TIMEOUT_GRE_MAX, |
367 | .obj_size = sizeof(unsigned int) * GRE_CT_MAX, | 367 | .obj_size = sizeof(unsigned int) * GRE_CT_MAX, |
368 | .nla_policy = gre_timeout_nla_policy, | 368 | .nla_policy = gre_timeout_nla_policy, |
369 | }, | 369 | }, |
370 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 370 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
371 | .net_id = &proto_gre_net_id, | 371 | .net_id = &proto_gre_net_id, |
372 | .init_net = gre_init_net, | 372 | .init_net = gre_init_net, |
373 | }; | 373 | }; |
374 | 374 | ||
375 | static int proto_gre_net_init(struct net *net) | 375 | static int proto_gre_net_init(struct net *net) |
376 | { | 376 | { |
377 | int ret = 0; | 377 | int ret = 0; |
378 | 378 | ||
379 | ret = nf_ct_l4proto_pernet_register_one(net, | 379 | ret = nf_ct_l4proto_pernet_register_one(net, |
380 | &nf_conntrack_l4proto_gre4); | 380 | &nf_conntrack_l4proto_gre4); |
381 | if (ret < 0) | 381 | if (ret < 0) |
382 | pr_err("nf_conntrack_gre4: pernet registration failed.\n"); | 382 | pr_err("nf_conntrack_gre4: pernet registration failed.\n"); |
383 | return ret; | 383 | return ret; |
384 | } | 384 | } |
385 | 385 | ||
386 | static void proto_gre_net_exit(struct net *net) | 386 | static void proto_gre_net_exit(struct net *net) |
387 | { | 387 | { |
388 | nf_ct_l4proto_pernet_unregister_one(net, &nf_conntrack_l4proto_gre4); | 388 | nf_ct_l4proto_pernet_unregister_one(net, &nf_conntrack_l4proto_gre4); |
389 | nf_ct_gre_keymap_flush(net); | 389 | nf_ct_gre_keymap_flush(net); |
390 | } | 390 | } |
391 | 391 | ||
392 | static struct pernet_operations proto_gre_net_ops = { | 392 | static struct pernet_operations proto_gre_net_ops = { |
393 | .init = proto_gre_net_init, | 393 | .init = proto_gre_net_init, |
394 | .exit = proto_gre_net_exit, | 394 | .exit = proto_gre_net_exit, |
395 | .id = &proto_gre_net_id, | 395 | .id = &proto_gre_net_id, |
396 | .size = sizeof(struct netns_proto_gre), | 396 | .size = sizeof(struct netns_proto_gre), |
397 | }; | 397 | }; |
398 | 398 | ||
399 | static int __init nf_ct_proto_gre_init(void) | 399 | static int __init nf_ct_proto_gre_init(void) |
400 | { | 400 | { |
401 | int ret; | 401 | int ret; |
402 | 402 | ||
403 | ret = register_pernet_subsys(&proto_gre_net_ops); | 403 | ret = register_pernet_subsys(&proto_gre_net_ops); |
404 | if (ret < 0) | 404 | if (ret < 0) |
405 | goto out_pernet; | 405 | goto out_pernet; |
406 | ret = nf_ct_l4proto_register_one(&nf_conntrack_l4proto_gre4); | 406 | ret = nf_ct_l4proto_register_one(&nf_conntrack_l4proto_gre4); |
407 | if (ret < 0) | 407 | if (ret < 0) |
408 | goto out_gre4; | 408 | goto out_gre4; |
409 | 409 | ||
410 | return 0; | 410 | return 0; |
411 | out_gre4: | 411 | out_gre4: |
412 | unregister_pernet_subsys(&proto_gre_net_ops); | 412 | unregister_pernet_subsys(&proto_gre_net_ops); |
413 | out_pernet: | 413 | out_pernet: |
414 | return ret; | 414 | return ret; |
415 | } | 415 | } |
416 | 416 | ||
417 | static void __exit nf_ct_proto_gre_fini(void) | 417 | static void __exit nf_ct_proto_gre_fini(void) |
418 | { | 418 | { |
419 | nf_ct_l4proto_unregister_one(&nf_conntrack_l4proto_gre4); | 419 | nf_ct_l4proto_unregister_one(&nf_conntrack_l4proto_gre4); |
420 | unregister_pernet_subsys(&proto_gre_net_ops); | 420 | unregister_pernet_subsys(&proto_gre_net_ops); |
421 | } | 421 | } |
422 | 422 | ||
423 | module_init(nf_ct_proto_gre_init); | 423 | module_init(nf_ct_proto_gre_init); |
424 | module_exit(nf_ct_proto_gre_fini); | 424 | module_exit(nf_ct_proto_gre_fini); |
425 | 425 | ||
426 | MODULE_LICENSE("GPL"); | 426 | MODULE_LICENSE("GPL"); |
427 | 427 |
net/netfilter/nf_conntrack_proto_icmp.c
1 | /* (C) 1999-2001 Paul `Rusty' Russell | 1 | /* (C) 1999-2001 Paul `Rusty' Russell |
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> |
3 | * (C) 2006-2010 Patrick McHardy <kaber@trash.net> | 3 | * (C) 2006-2010 Patrick McHardy <kaber@trash.net> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <linux/timer.h> | 11 | #include <linux/timer.h> |
12 | #include <linux/netfilter.h> | 12 | #include <linux/netfilter.h> |
13 | #include <linux/in.h> | 13 | #include <linux/in.h> |
14 | #include <linux/icmp.h> | 14 | #include <linux/icmp.h> |
15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
16 | #include <net/ip.h> | 16 | #include <net/ip.h> |
17 | #include <net/checksum.h> | 17 | #include <net/checksum.h> |
18 | #include <linux/netfilter_ipv4.h> | 18 | #include <linux/netfilter_ipv4.h> |
19 | #include <net/netfilter/nf_conntrack_tuple.h> | 19 | #include <net/netfilter/nf_conntrack_tuple.h> |
20 | #include <net/netfilter/nf_conntrack_l4proto.h> | 20 | #include <net/netfilter/nf_conntrack_l4proto.h> |
21 | #include <net/netfilter/nf_conntrack_core.h> | 21 | #include <net/netfilter/nf_conntrack_core.h> |
22 | #include <net/netfilter/nf_conntrack_timeout.h> | 22 | #include <net/netfilter/nf_conntrack_timeout.h> |
23 | #include <net/netfilter/nf_conntrack_zones.h> | 23 | #include <net/netfilter/nf_conntrack_zones.h> |
24 | #include <net/netfilter/nf_log.h> | 24 | #include <net/netfilter/nf_log.h> |
25 | 25 | ||
26 | static const unsigned int nf_ct_icmp_timeout = 30*HZ; | 26 | static const unsigned int nf_ct_icmp_timeout = 30*HZ; |
27 | 27 | ||
28 | static inline struct nf_icmp_net *icmp_pernet(struct net *net) | 28 | static inline struct nf_icmp_net *icmp_pernet(struct net *net) |
29 | { | 29 | { |
30 | return &net->ct.nf_ct_proto.icmp; | 30 | return &net->ct.nf_ct_proto.icmp; |
31 | } | 31 | } |
32 | 32 | ||
33 | static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, | 33 | static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, |
34 | struct net *net, struct nf_conntrack_tuple *tuple) | 34 | struct net *net, struct nf_conntrack_tuple *tuple) |
35 | { | 35 | { |
36 | const struct icmphdr *hp; | 36 | const struct icmphdr *hp; |
37 | struct icmphdr _hdr; | 37 | struct icmphdr _hdr; |
38 | 38 | ||
39 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | 39 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); |
40 | if (hp == NULL) | 40 | if (hp == NULL) |
41 | return false; | 41 | return false; |
42 | 42 | ||
43 | tuple->dst.u.icmp.type = hp->type; | 43 | tuple->dst.u.icmp.type = hp->type; |
44 | tuple->src.u.icmp.id = hp->un.echo.id; | 44 | tuple->src.u.icmp.id = hp->un.echo.id; |
45 | tuple->dst.u.icmp.code = hp->code; | 45 | tuple->dst.u.icmp.code = hp->code; |
46 | 46 | ||
47 | return true; | 47 | return true; |
48 | } | 48 | } |
49 | 49 | ||
50 | /* Add 1; spaces filled with 0. */ | 50 | /* Add 1; spaces filled with 0. */ |
51 | static const u_int8_t invmap[] = { | 51 | static const u_int8_t invmap[] = { |
52 | [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | 52 | [ICMP_ECHO] = ICMP_ECHOREPLY + 1, |
53 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | 53 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, |
54 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | 54 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, |
55 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | 55 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, |
56 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | 56 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, |
57 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | 57 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, |
58 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | 58 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, |
59 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 | 59 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple, | 62 | static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple, |
63 | const struct nf_conntrack_tuple *orig) | 63 | const struct nf_conntrack_tuple *orig) |
64 | { | 64 | { |
65 | if (orig->dst.u.icmp.type >= sizeof(invmap) || | 65 | if (orig->dst.u.icmp.type >= sizeof(invmap) || |
66 | !invmap[orig->dst.u.icmp.type]) | 66 | !invmap[orig->dst.u.icmp.type]) |
67 | return false; | 67 | return false; |
68 | 68 | ||
69 | tuple->src.u.icmp.id = orig->src.u.icmp.id; | 69 | tuple->src.u.icmp.id = orig->src.u.icmp.id; |
70 | tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; | 70 | tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; |
71 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; | 71 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; |
72 | return true; | 72 | return true; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* Returns verdict for packet, or -1 for invalid. */ | 75 | /* Returns verdict for packet, or -1 for invalid. */ |
76 | static int icmp_packet(struct nf_conn *ct, | 76 | static int icmp_packet(struct nf_conn *ct, |
77 | const struct sk_buff *skb, | 77 | struct sk_buff *skb, |
78 | unsigned int dataoff, | 78 | unsigned int dataoff, |
79 | enum ip_conntrack_info ctinfo, | 79 | enum ip_conntrack_info ctinfo, |
80 | const struct nf_hook_state *state) | 80 | const struct nf_hook_state *state) |
81 | { | 81 | { |
82 | /* Do not immediately delete the connection after the first | 82 | /* Do not immediately delete the connection after the first |
83 | successful reply to avoid excessive conntrackd traffic | 83 | successful reply to avoid excessive conntrackd traffic |
84 | and also to handle correctly ICMP echo reply duplicates. */ | 84 | and also to handle correctly ICMP echo reply duplicates. */ |
85 | unsigned int *timeout = nf_ct_timeout_lookup(ct); | 85 | unsigned int *timeout = nf_ct_timeout_lookup(ct); |
86 | static const u_int8_t valid_new[] = { | 86 | static const u_int8_t valid_new[] = { |
87 | [ICMP_ECHO] = 1, | 87 | [ICMP_ECHO] = 1, |
88 | [ICMP_TIMESTAMP] = 1, | 88 | [ICMP_TIMESTAMP] = 1, |
89 | [ICMP_INFO_REQUEST] = 1, | 89 | [ICMP_INFO_REQUEST] = 1, |
90 | [ICMP_ADDRESS] = 1 | 90 | [ICMP_ADDRESS] = 1 |
91 | }; | 91 | }; |
92 | 92 | ||
93 | if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) || | 93 | if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) || |
94 | !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) { | 94 | !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) { |
95 | /* Can't create a new ICMP `conn' with this. */ | 95 | /* Can't create a new ICMP `conn' with this. */ |
96 | pr_debug("icmp: can't create new conn with type %u\n", | 96 | pr_debug("icmp: can't create new conn with type %u\n", |
97 | ct->tuplehash[0].tuple.dst.u.icmp.type); | 97 | ct->tuplehash[0].tuple.dst.u.icmp.type); |
98 | nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); | 98 | nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); |
99 | return -NF_ACCEPT; | 99 | return -NF_ACCEPT; |
100 | } | 100 | } |
101 | 101 | ||
102 | if (!timeout) | 102 | if (!timeout) |
103 | timeout = &icmp_pernet(nf_ct_net(ct))->timeout; | 103 | timeout = &icmp_pernet(nf_ct_net(ct))->timeout; |
104 | 104 | ||
105 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); | 105 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
106 | return NF_ACCEPT; | 106 | return NF_ACCEPT; |
107 | } | 107 | } |
108 | 108 | ||
109 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ | 109 | /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ |
110 | static int | 110 | static int |
111 | icmp_error_message(struct nf_conn *tmpl, struct sk_buff *skb, | 111 | icmp_error_message(struct nf_conn *tmpl, struct sk_buff *skb, |
112 | const struct nf_hook_state *state) | 112 | const struct nf_hook_state *state) |
113 | { | 113 | { |
114 | struct nf_conntrack_tuple innertuple, origtuple; | 114 | struct nf_conntrack_tuple innertuple, origtuple; |
115 | const struct nf_conntrack_l4proto *innerproto; | 115 | const struct nf_conntrack_l4proto *innerproto; |
116 | const struct nf_conntrack_tuple_hash *h; | 116 | const struct nf_conntrack_tuple_hash *h; |
117 | const struct nf_conntrack_zone *zone; | 117 | const struct nf_conntrack_zone *zone; |
118 | enum ip_conntrack_info ctinfo; | 118 | enum ip_conntrack_info ctinfo; |
119 | struct nf_conntrack_zone tmp; | 119 | struct nf_conntrack_zone tmp; |
120 | 120 | ||
121 | WARN_ON(skb_nfct(skb)); | 121 | WARN_ON(skb_nfct(skb)); |
122 | zone = nf_ct_zone_tmpl(tmpl, skb, &tmp); | 122 | zone = nf_ct_zone_tmpl(tmpl, skb, &tmp); |
123 | 123 | ||
124 | /* Are they talking about one of our connections? */ | 124 | /* Are they talking about one of our connections? */ |
125 | if (!nf_ct_get_tuplepr(skb, | 125 | if (!nf_ct_get_tuplepr(skb, |
126 | skb_network_offset(skb) + ip_hdrlen(skb) | 126 | skb_network_offset(skb) + ip_hdrlen(skb) |
127 | + sizeof(struct icmphdr), | 127 | + sizeof(struct icmphdr), |
128 | PF_INET, state->net, &origtuple)) { | 128 | PF_INET, state->net, &origtuple)) { |
129 | pr_debug("icmp_error_message: failed to get tuple\n"); | 129 | pr_debug("icmp_error_message: failed to get tuple\n"); |
130 | return -NF_ACCEPT; | 130 | return -NF_ACCEPT; |
131 | } | 131 | } |
132 | 132 | ||
133 | /* rcu_read_lock()ed by nf_hook_thresh */ | 133 | /* rcu_read_lock()ed by nf_hook_thresh */ |
134 | innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum); | 134 | innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum); |
135 | 135 | ||
136 | /* Ordinarily, we'd expect the inverted tupleproto, but it's | 136 | /* Ordinarily, we'd expect the inverted tupleproto, but it's |
137 | been preserved inside the ICMP. */ | 137 | been preserved inside the ICMP. */ |
138 | if (!nf_ct_invert_tuple(&innertuple, &origtuple, innerproto)) { | 138 | if (!nf_ct_invert_tuple(&innertuple, &origtuple, innerproto)) { |
139 | pr_debug("icmp_error_message: no match\n"); | 139 | pr_debug("icmp_error_message: no match\n"); |
140 | return -NF_ACCEPT; | 140 | return -NF_ACCEPT; |
141 | } | 141 | } |
142 | 142 | ||
143 | ctinfo = IP_CT_RELATED; | 143 | ctinfo = IP_CT_RELATED; |
144 | 144 | ||
145 | h = nf_conntrack_find_get(state->net, zone, &innertuple); | 145 | h = nf_conntrack_find_get(state->net, zone, &innertuple); |
146 | if (!h) { | 146 | if (!h) { |
147 | pr_debug("icmp_error_message: no match\n"); | 147 | pr_debug("icmp_error_message: no match\n"); |
148 | return -NF_ACCEPT; | 148 | return -NF_ACCEPT; |
149 | } | 149 | } |
150 | 150 | ||
151 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) | 151 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) |
152 | ctinfo += IP_CT_IS_REPLY; | 152 | ctinfo += IP_CT_IS_REPLY; |
153 | 153 | ||
154 | /* Update skb to refer to this connection */ | 154 | /* Update skb to refer to this connection */ |
155 | nf_ct_set(skb, nf_ct_tuplehash_to_ctrack(h), ctinfo); | 155 | nf_ct_set(skb, nf_ct_tuplehash_to_ctrack(h), ctinfo); |
156 | return NF_ACCEPT; | 156 | return NF_ACCEPT; |
157 | } | 157 | } |
158 | 158 | ||
159 | static void icmp_error_log(const struct sk_buff *skb, | 159 | static void icmp_error_log(const struct sk_buff *skb, |
160 | const struct nf_hook_state *state, | 160 | const struct nf_hook_state *state, |
161 | const char *msg) | 161 | const char *msg) |
162 | { | 162 | { |
163 | nf_l4proto_log_invalid(skb, state->net, state->pf, | 163 | nf_l4proto_log_invalid(skb, state->net, state->pf, |
164 | IPPROTO_ICMP, "%s", msg); | 164 | IPPROTO_ICMP, "%s", msg); |
165 | } | 165 | } |
166 | 166 | ||
167 | /* Small and modified version of icmp_rcv */ | 167 | /* Small and modified version of icmp_rcv */ |
168 | static int | 168 | static int |
169 | icmp_error(struct nf_conn *tmpl, | 169 | icmp_error(struct nf_conn *tmpl, |
170 | struct sk_buff *skb, unsigned int dataoff, | 170 | struct sk_buff *skb, unsigned int dataoff, |
171 | const struct nf_hook_state *state) | 171 | const struct nf_hook_state *state) |
172 | { | 172 | { |
173 | const struct icmphdr *icmph; | 173 | const struct icmphdr *icmph; |
174 | struct icmphdr _ih; | 174 | struct icmphdr _ih; |
175 | 175 | ||
176 | /* Not enough header? */ | 176 | /* Not enough header? */ |
177 | icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih); | 177 | icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih); |
178 | if (icmph == NULL) { | 178 | if (icmph == NULL) { |
179 | icmp_error_log(skb, state, "short packet"); | 179 | icmp_error_log(skb, state, "short packet"); |
180 | return -NF_ACCEPT; | 180 | return -NF_ACCEPT; |
181 | } | 181 | } |
182 | 182 | ||
183 | /* See ip_conntrack_proto_tcp.c */ | 183 | /* See ip_conntrack_proto_tcp.c */ |
184 | if (state->net->ct.sysctl_checksum && | 184 | if (state->net->ct.sysctl_checksum && |
185 | state->hook == NF_INET_PRE_ROUTING && | 185 | state->hook == NF_INET_PRE_ROUTING && |
186 | nf_ip_checksum(skb, state->hook, dataoff, 0)) { | 186 | nf_ip_checksum(skb, state->hook, dataoff, 0)) { |
187 | icmp_error_log(skb, state, "bad hw icmp checksum"); | 187 | icmp_error_log(skb, state, "bad hw icmp checksum"); |
188 | return -NF_ACCEPT; | 188 | return -NF_ACCEPT; |
189 | } | 189 | } |
190 | 190 | ||
191 | /* | 191 | /* |
192 | * 18 is the highest 'known' ICMP type. Anything else is a mystery | 192 | * 18 is the highest 'known' ICMP type. Anything else is a mystery |
193 | * | 193 | * |
194 | * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently | 194 | * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently |
195 | * discarded. | 195 | * discarded. |
196 | */ | 196 | */ |
197 | if (icmph->type > NR_ICMP_TYPES) { | 197 | if (icmph->type > NR_ICMP_TYPES) { |
198 | icmp_error_log(skb, state, "invalid icmp type"); | 198 | icmp_error_log(skb, state, "invalid icmp type"); |
199 | return -NF_ACCEPT; | 199 | return -NF_ACCEPT; |
200 | } | 200 | } |
201 | 201 | ||
202 | /* Need to track icmp error message? */ | 202 | /* Need to track icmp error message? */ |
203 | if (icmph->type != ICMP_DEST_UNREACH && | 203 | if (icmph->type != ICMP_DEST_UNREACH && |
204 | icmph->type != ICMP_SOURCE_QUENCH && | 204 | icmph->type != ICMP_SOURCE_QUENCH && |
205 | icmph->type != ICMP_TIME_EXCEEDED && | 205 | icmph->type != ICMP_TIME_EXCEEDED && |
206 | icmph->type != ICMP_PARAMETERPROB && | 206 | icmph->type != ICMP_PARAMETERPROB && |
207 | icmph->type != ICMP_REDIRECT) | 207 | icmph->type != ICMP_REDIRECT) |
208 | return NF_ACCEPT; | 208 | return NF_ACCEPT; |
209 | 209 | ||
210 | return icmp_error_message(tmpl, skb, state); | 210 | return icmp_error_message(tmpl, skb, state); |
211 | } | 211 | } |
212 | 212 | ||
213 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 213 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
214 | 214 | ||
215 | #include <linux/netfilter/nfnetlink.h> | 215 | #include <linux/netfilter/nfnetlink.h> |
216 | #include <linux/netfilter/nfnetlink_conntrack.h> | 216 | #include <linux/netfilter/nfnetlink_conntrack.h> |
217 | 217 | ||
218 | static int icmp_tuple_to_nlattr(struct sk_buff *skb, | 218 | static int icmp_tuple_to_nlattr(struct sk_buff *skb, |
219 | const struct nf_conntrack_tuple *t) | 219 | const struct nf_conntrack_tuple *t) |
220 | { | 220 | { |
221 | if (nla_put_be16(skb, CTA_PROTO_ICMP_ID, t->src.u.icmp.id) || | 221 | if (nla_put_be16(skb, CTA_PROTO_ICMP_ID, t->src.u.icmp.id) || |
222 | nla_put_u8(skb, CTA_PROTO_ICMP_TYPE, t->dst.u.icmp.type) || | 222 | nla_put_u8(skb, CTA_PROTO_ICMP_TYPE, t->dst.u.icmp.type) || |
223 | nla_put_u8(skb, CTA_PROTO_ICMP_CODE, t->dst.u.icmp.code)) | 223 | nla_put_u8(skb, CTA_PROTO_ICMP_CODE, t->dst.u.icmp.code)) |
224 | goto nla_put_failure; | 224 | goto nla_put_failure; |
225 | return 0; | 225 | return 0; |
226 | 226 | ||
227 | nla_put_failure: | 227 | nla_put_failure: |
228 | return -1; | 228 | return -1; |
229 | } | 229 | } |
230 | 230 | ||
231 | static const struct nla_policy icmp_nla_policy[CTA_PROTO_MAX+1] = { | 231 | static const struct nla_policy icmp_nla_policy[CTA_PROTO_MAX+1] = { |
232 | [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 }, | 232 | [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 }, |
233 | [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 }, | 233 | [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 }, |
234 | [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 }, | 234 | [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 }, |
235 | }; | 235 | }; |
236 | 236 | ||
237 | static int icmp_nlattr_to_tuple(struct nlattr *tb[], | 237 | static int icmp_nlattr_to_tuple(struct nlattr *tb[], |
238 | struct nf_conntrack_tuple *tuple) | 238 | struct nf_conntrack_tuple *tuple) |
239 | { | 239 | { |
240 | if (!tb[CTA_PROTO_ICMP_TYPE] || | 240 | if (!tb[CTA_PROTO_ICMP_TYPE] || |
241 | !tb[CTA_PROTO_ICMP_CODE] || | 241 | !tb[CTA_PROTO_ICMP_CODE] || |
242 | !tb[CTA_PROTO_ICMP_ID]) | 242 | !tb[CTA_PROTO_ICMP_ID]) |
243 | return -EINVAL; | 243 | return -EINVAL; |
244 | 244 | ||
245 | tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]); | 245 | tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]); |
246 | tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]); | 246 | tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]); |
247 | tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]); | 247 | tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]); |
248 | 248 | ||
249 | if (tuple->dst.u.icmp.type >= sizeof(invmap) || | 249 | if (tuple->dst.u.icmp.type >= sizeof(invmap) || |
250 | !invmap[tuple->dst.u.icmp.type]) | 250 | !invmap[tuple->dst.u.icmp.type]) |
251 | return -EINVAL; | 251 | return -EINVAL; |
252 | 252 | ||
253 | return 0; | 253 | return 0; |
254 | } | 254 | } |
255 | 255 | ||
256 | static unsigned int icmp_nlattr_tuple_size(void) | 256 | static unsigned int icmp_nlattr_tuple_size(void) |
257 | { | 257 | { |
258 | static unsigned int size __read_mostly; | 258 | static unsigned int size __read_mostly; |
259 | 259 | ||
260 | if (!size) | 260 | if (!size) |
261 | size = nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1); | 261 | size = nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1); |
262 | 262 | ||
263 | return size; | 263 | return size; |
264 | } | 264 | } |
265 | #endif | 265 | #endif |
266 | 266 | ||
267 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 267 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
268 | 268 | ||
269 | #include <linux/netfilter/nfnetlink.h> | 269 | #include <linux/netfilter/nfnetlink.h> |
270 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 270 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
271 | 271 | ||
272 | static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], | 272 | static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], |
273 | struct net *net, void *data) | 273 | struct net *net, void *data) |
274 | { | 274 | { |
275 | unsigned int *timeout = data; | 275 | unsigned int *timeout = data; |
276 | struct nf_icmp_net *in = icmp_pernet(net); | 276 | struct nf_icmp_net *in = icmp_pernet(net); |
277 | 277 | ||
278 | if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) { | 278 | if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) { |
279 | if (!timeout) | 279 | if (!timeout) |
280 | timeout = &in->timeout; | 280 | timeout = &in->timeout; |
281 | *timeout = | 281 | *timeout = |
282 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ; | 282 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ; |
283 | } else if (timeout) { | 283 | } else if (timeout) { |
284 | /* Set default ICMP timeout. */ | 284 | /* Set default ICMP timeout. */ |
285 | *timeout = in->timeout; | 285 | *timeout = in->timeout; |
286 | } | 286 | } |
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | 289 | ||
290 | static int | 290 | static int |
291 | icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 291 | icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
292 | { | 292 | { |
293 | const unsigned int *timeout = data; | 293 | const unsigned int *timeout = data; |
294 | 294 | ||
295 | if (nla_put_be32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ))) | 295 | if (nla_put_be32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ))) |
296 | goto nla_put_failure; | 296 | goto nla_put_failure; |
297 | return 0; | 297 | return 0; |
298 | 298 | ||
299 | nla_put_failure: | 299 | nla_put_failure: |
300 | return -ENOSPC; | 300 | return -ENOSPC; |
301 | } | 301 | } |
302 | 302 | ||
303 | static const struct nla_policy | 303 | static const struct nla_policy |
304 | icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = { | 304 | icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = { |
305 | [CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 }, | 305 | [CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 }, |
306 | }; | 306 | }; |
307 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 307 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
308 | 308 | ||
309 | #ifdef CONFIG_SYSCTL | 309 | #ifdef CONFIG_SYSCTL |
310 | static struct ctl_table icmp_sysctl_table[] = { | 310 | static struct ctl_table icmp_sysctl_table[] = { |
311 | { | 311 | { |
312 | .procname = "nf_conntrack_icmp_timeout", | 312 | .procname = "nf_conntrack_icmp_timeout", |
313 | .maxlen = sizeof(unsigned int), | 313 | .maxlen = sizeof(unsigned int), |
314 | .mode = 0644, | 314 | .mode = 0644, |
315 | .proc_handler = proc_dointvec_jiffies, | 315 | .proc_handler = proc_dointvec_jiffies, |
316 | }, | 316 | }, |
317 | { } | 317 | { } |
318 | }; | 318 | }; |
319 | #endif /* CONFIG_SYSCTL */ | 319 | #endif /* CONFIG_SYSCTL */ |
320 | 320 | ||
321 | static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn, | 321 | static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn, |
322 | struct nf_icmp_net *in) | 322 | struct nf_icmp_net *in) |
323 | { | 323 | { |
324 | #ifdef CONFIG_SYSCTL | 324 | #ifdef CONFIG_SYSCTL |
325 | pn->ctl_table = kmemdup(icmp_sysctl_table, | 325 | pn->ctl_table = kmemdup(icmp_sysctl_table, |
326 | sizeof(icmp_sysctl_table), | 326 | sizeof(icmp_sysctl_table), |
327 | GFP_KERNEL); | 327 | GFP_KERNEL); |
328 | if (!pn->ctl_table) | 328 | if (!pn->ctl_table) |
329 | return -ENOMEM; | 329 | return -ENOMEM; |
330 | 330 | ||
331 | pn->ctl_table[0].data = &in->timeout; | 331 | pn->ctl_table[0].data = &in->timeout; |
332 | #endif | 332 | #endif |
333 | return 0; | 333 | return 0; |
334 | } | 334 | } |
335 | 335 | ||
336 | static int icmp_init_net(struct net *net, u_int16_t proto) | 336 | static int icmp_init_net(struct net *net, u_int16_t proto) |
337 | { | 337 | { |
338 | struct nf_icmp_net *in = icmp_pernet(net); | 338 | struct nf_icmp_net *in = icmp_pernet(net); |
339 | struct nf_proto_net *pn = &in->pn; | 339 | struct nf_proto_net *pn = &in->pn; |
340 | 340 | ||
341 | in->timeout = nf_ct_icmp_timeout; | 341 | in->timeout = nf_ct_icmp_timeout; |
342 | 342 | ||
343 | return icmp_kmemdup_sysctl_table(pn, in); | 343 | return icmp_kmemdup_sysctl_table(pn, in); |
344 | } | 344 | } |
345 | 345 | ||
346 | static struct nf_proto_net *icmp_get_net_proto(struct net *net) | 346 | static struct nf_proto_net *icmp_get_net_proto(struct net *net) |
347 | { | 347 | { |
348 | return &net->ct.nf_ct_proto.icmp.pn; | 348 | return &net->ct.nf_ct_proto.icmp.pn; |
349 | } | 349 | } |
350 | 350 | ||
351 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = | 351 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp = |
352 | { | 352 | { |
353 | .l3proto = PF_INET, | 353 | .l3proto = PF_INET, |
354 | .l4proto = IPPROTO_ICMP, | 354 | .l4proto = IPPROTO_ICMP, |
355 | .pkt_to_tuple = icmp_pkt_to_tuple, | 355 | .pkt_to_tuple = icmp_pkt_to_tuple, |
356 | .invert_tuple = icmp_invert_tuple, | 356 | .invert_tuple = icmp_invert_tuple, |
357 | .packet = icmp_packet, | 357 | .packet = icmp_packet, |
358 | .error = icmp_error, | 358 | .error = icmp_error, |
359 | .destroy = NULL, | 359 | .destroy = NULL, |
360 | .me = NULL, | 360 | .me = NULL, |
361 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 361 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
362 | .tuple_to_nlattr = icmp_tuple_to_nlattr, | 362 | .tuple_to_nlattr = icmp_tuple_to_nlattr, |
363 | .nlattr_tuple_size = icmp_nlattr_tuple_size, | 363 | .nlattr_tuple_size = icmp_nlattr_tuple_size, |
364 | .nlattr_to_tuple = icmp_nlattr_to_tuple, | 364 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
365 | .nla_policy = icmp_nla_policy, | 365 | .nla_policy = icmp_nla_policy, |
366 | #endif | 366 | #endif |
367 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 367 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
368 | .ctnl_timeout = { | 368 | .ctnl_timeout = { |
369 | .nlattr_to_obj = icmp_timeout_nlattr_to_obj, | 369 | .nlattr_to_obj = icmp_timeout_nlattr_to_obj, |
370 | .obj_to_nlattr = icmp_timeout_obj_to_nlattr, | 370 | .obj_to_nlattr = icmp_timeout_obj_to_nlattr, |
371 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, | 371 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, |
372 | .obj_size = sizeof(unsigned int), | 372 | .obj_size = sizeof(unsigned int), |
373 | .nla_policy = icmp_timeout_nla_policy, | 373 | .nla_policy = icmp_timeout_nla_policy, |
374 | }, | 374 | }, |
375 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 375 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
376 | .init_net = icmp_init_net, | 376 | .init_net = icmp_init_net, |
377 | .get_net_proto = icmp_get_net_proto, | 377 | .get_net_proto = icmp_get_net_proto, |
378 | }; | 378 | }; |
379 | 379 |
net/netfilter/nf_conntrack_proto_icmpv6.c
1 | /* | 1 | /* |
2 | * Copyright (C)2003,2004 USAGI/WIDE Project | 2 | * Copyright (C)2003,2004 USAGI/WIDE Project |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * Author: | 8 | * Author: |
9 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | 9 | * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/timer.h> | 13 | #include <linux/timer.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/netfilter.h> | 15 | #include <linux/netfilter.h> |
16 | #include <linux/in6.h> | 16 | #include <linux/in6.h> |
17 | #include <linux/icmpv6.h> | 17 | #include <linux/icmpv6.h> |
18 | #include <linux/ipv6.h> | 18 | #include <linux/ipv6.h> |
19 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
20 | #include <net/ip6_checksum.h> | 20 | #include <net/ip6_checksum.h> |
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/netfilter_ipv6.h> | 22 | #include <linux/netfilter_ipv6.h> |
23 | #include <net/netfilter/nf_conntrack_tuple.h> | 23 | #include <net/netfilter/nf_conntrack_tuple.h> |
24 | #include <net/netfilter/nf_conntrack_l4proto.h> | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
25 | #include <net/netfilter/nf_conntrack_core.h> | 25 | #include <net/netfilter/nf_conntrack_core.h> |
26 | #include <net/netfilter/nf_conntrack_timeout.h> | 26 | #include <net/netfilter/nf_conntrack_timeout.h> |
27 | #include <net/netfilter/nf_conntrack_zones.h> | 27 | #include <net/netfilter/nf_conntrack_zones.h> |
28 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | 28 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> |
29 | #include <net/netfilter/nf_log.h> | 29 | #include <net/netfilter/nf_log.h> |
30 | 30 | ||
31 | static const unsigned int nf_ct_icmpv6_timeout = 30*HZ; | 31 | static const unsigned int nf_ct_icmpv6_timeout = 30*HZ; |
32 | 32 | ||
33 | static inline struct nf_icmp_net *icmpv6_pernet(struct net *net) | 33 | static inline struct nf_icmp_net *icmpv6_pernet(struct net *net) |
34 | { | 34 | { |
35 | return &net->ct.nf_ct_proto.icmpv6; | 35 | return &net->ct.nf_ct_proto.icmpv6; |
36 | } | 36 | } |
37 | 37 | ||
38 | static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb, | 38 | static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb, |
39 | unsigned int dataoff, | 39 | unsigned int dataoff, |
40 | struct net *net, | 40 | struct net *net, |
41 | struct nf_conntrack_tuple *tuple) | 41 | struct nf_conntrack_tuple *tuple) |
42 | { | 42 | { |
43 | const struct icmp6hdr *hp; | 43 | const struct icmp6hdr *hp; |
44 | struct icmp6hdr _hdr; | 44 | struct icmp6hdr _hdr; |
45 | 45 | ||
46 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | 46 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); |
47 | if (hp == NULL) | 47 | if (hp == NULL) |
48 | return false; | 48 | return false; |
49 | tuple->dst.u.icmp.type = hp->icmp6_type; | 49 | tuple->dst.u.icmp.type = hp->icmp6_type; |
50 | tuple->src.u.icmp.id = hp->icmp6_identifier; | 50 | tuple->src.u.icmp.id = hp->icmp6_identifier; |
51 | tuple->dst.u.icmp.code = hp->icmp6_code; | 51 | tuple->dst.u.icmp.code = hp->icmp6_code; |
52 | 52 | ||
53 | return true; | 53 | return true; |
54 | } | 54 | } |
55 | 55 | ||
56 | /* Add 1; spaces filled with 0. */ | 56 | /* Add 1; spaces filled with 0. */ |
57 | static const u_int8_t invmap[] = { | 57 | static const u_int8_t invmap[] = { |
58 | [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, | 58 | [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, |
59 | [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, | 59 | [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, |
60 | [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_REPLY + 1, | 60 | [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_REPLY + 1, |
61 | [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_QUERY + 1 | 61 | [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_QUERY + 1 |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static const u_int8_t noct_valid_new[] = { | 64 | static const u_int8_t noct_valid_new[] = { |
65 | [ICMPV6_MGM_QUERY - 130] = 1, | 65 | [ICMPV6_MGM_QUERY - 130] = 1, |
66 | [ICMPV6_MGM_REPORT - 130] = 1, | 66 | [ICMPV6_MGM_REPORT - 130] = 1, |
67 | [ICMPV6_MGM_REDUCTION - 130] = 1, | 67 | [ICMPV6_MGM_REDUCTION - 130] = 1, |
68 | [NDISC_ROUTER_SOLICITATION - 130] = 1, | 68 | [NDISC_ROUTER_SOLICITATION - 130] = 1, |
69 | [NDISC_ROUTER_ADVERTISEMENT - 130] = 1, | 69 | [NDISC_ROUTER_ADVERTISEMENT - 130] = 1, |
70 | [NDISC_NEIGHBOUR_SOLICITATION - 130] = 1, | 70 | [NDISC_NEIGHBOUR_SOLICITATION - 130] = 1, |
71 | [NDISC_NEIGHBOUR_ADVERTISEMENT - 130] = 1, | 71 | [NDISC_NEIGHBOUR_ADVERTISEMENT - 130] = 1, |
72 | [ICMPV6_MLD2_REPORT - 130] = 1 | 72 | [ICMPV6_MLD2_REPORT - 130] = 1 |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, | 75 | static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, |
76 | const struct nf_conntrack_tuple *orig) | 76 | const struct nf_conntrack_tuple *orig) |
77 | { | 77 | { |
78 | int type = orig->dst.u.icmp.type - 128; | 78 | int type = orig->dst.u.icmp.type - 128; |
79 | if (type < 0 || type >= sizeof(invmap) || !invmap[type]) | 79 | if (type < 0 || type >= sizeof(invmap) || !invmap[type]) |
80 | return false; | 80 | return false; |
81 | 81 | ||
82 | tuple->src.u.icmp.id = orig->src.u.icmp.id; | 82 | tuple->src.u.icmp.id = orig->src.u.icmp.id; |
83 | tuple->dst.u.icmp.type = invmap[type] - 1; | 83 | tuple->dst.u.icmp.type = invmap[type] - 1; |
84 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; | 84 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; |
85 | return true; | 85 | return true; |
86 | } | 86 | } |
87 | 87 | ||
88 | static unsigned int *icmpv6_get_timeouts(struct net *net) | 88 | static unsigned int *icmpv6_get_timeouts(struct net *net) |
89 | { | 89 | { |
90 | return &icmpv6_pernet(net)->timeout; | 90 | return &icmpv6_pernet(net)->timeout; |
91 | } | 91 | } |
92 | 92 | ||
93 | /* Returns verdict for packet, or -1 for invalid. */ | 93 | /* Returns verdict for packet, or -1 for invalid. */ |
94 | static int icmpv6_packet(struct nf_conn *ct, | 94 | static int icmpv6_packet(struct nf_conn *ct, |
95 | const struct sk_buff *skb, | 95 | struct sk_buff *skb, |
96 | unsigned int dataoff, | 96 | unsigned int dataoff, |
97 | enum ip_conntrack_info ctinfo, | 97 | enum ip_conntrack_info ctinfo, |
98 | const struct nf_hook_state *state) | 98 | const struct nf_hook_state *state) |
99 | { | 99 | { |
100 | unsigned int *timeout = nf_ct_timeout_lookup(ct); | 100 | unsigned int *timeout = nf_ct_timeout_lookup(ct); |
101 | static const u8 valid_new[] = { | 101 | static const u8 valid_new[] = { |
102 | [ICMPV6_ECHO_REQUEST - 128] = 1, | 102 | [ICMPV6_ECHO_REQUEST - 128] = 1, |
103 | [ICMPV6_NI_QUERY - 128] = 1 | 103 | [ICMPV6_NI_QUERY - 128] = 1 |
104 | }; | 104 | }; |
105 | 105 | ||
106 | if (!nf_ct_is_confirmed(ct)) { | 106 | if (!nf_ct_is_confirmed(ct)) { |
107 | int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128; | 107 | int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128; |
108 | 108 | ||
109 | if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) { | 109 | if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) { |
110 | /* Can't create a new ICMPv6 `conn' with this. */ | 110 | /* Can't create a new ICMPv6 `conn' with this. */ |
111 | pr_debug("icmpv6: can't create new conn with type %u\n", | 111 | pr_debug("icmpv6: can't create new conn with type %u\n", |
112 | type + 128); | 112 | type + 128); |
113 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); | 113 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); |
114 | return -NF_ACCEPT; | 114 | return -NF_ACCEPT; |
115 | } | 115 | } |
116 | } | 116 | } |
117 | 117 | ||
118 | if (!timeout) | 118 | if (!timeout) |
119 | timeout = icmpv6_get_timeouts(nf_ct_net(ct)); | 119 | timeout = icmpv6_get_timeouts(nf_ct_net(ct)); |
120 | 120 | ||
121 | /* Do not immediately delete the connection after the first | 121 | /* Do not immediately delete the connection after the first |
122 | successful reply to avoid excessive conntrackd traffic | 122 | successful reply to avoid excessive conntrackd traffic |
123 | and also to handle correctly ICMP echo reply duplicates. */ | 123 | and also to handle correctly ICMP echo reply duplicates. */ |
124 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); | 124 | nf_ct_refresh_acct(ct, ctinfo, skb, *timeout); |
125 | 125 | ||
126 | return NF_ACCEPT; | 126 | return NF_ACCEPT; |
127 | } | 127 | } |
128 | 128 | ||
129 | static int | 129 | static int |
130 | icmpv6_error_message(struct net *net, struct nf_conn *tmpl, | 130 | icmpv6_error_message(struct net *net, struct nf_conn *tmpl, |
131 | struct sk_buff *skb, | 131 | struct sk_buff *skb, |
132 | unsigned int icmp6off) | 132 | unsigned int icmp6off) |
133 | { | 133 | { |
134 | struct nf_conntrack_tuple intuple, origtuple; | 134 | struct nf_conntrack_tuple intuple, origtuple; |
135 | const struct nf_conntrack_tuple_hash *h; | 135 | const struct nf_conntrack_tuple_hash *h; |
136 | const struct nf_conntrack_l4proto *inproto; | 136 | const struct nf_conntrack_l4proto *inproto; |
137 | enum ip_conntrack_info ctinfo; | 137 | enum ip_conntrack_info ctinfo; |
138 | struct nf_conntrack_zone tmp; | 138 | struct nf_conntrack_zone tmp; |
139 | 139 | ||
140 | WARN_ON(skb_nfct(skb)); | 140 | WARN_ON(skb_nfct(skb)); |
141 | 141 | ||
142 | /* Are they talking about one of our connections? */ | 142 | /* Are they talking about one of our connections? */ |
143 | if (!nf_ct_get_tuplepr(skb, | 143 | if (!nf_ct_get_tuplepr(skb, |
144 | skb_network_offset(skb) | 144 | skb_network_offset(skb) |
145 | + sizeof(struct ipv6hdr) | 145 | + sizeof(struct ipv6hdr) |
146 | + sizeof(struct icmp6hdr), | 146 | + sizeof(struct icmp6hdr), |
147 | PF_INET6, net, &origtuple)) { | 147 | PF_INET6, net, &origtuple)) { |
148 | pr_debug("icmpv6_error: Can't get tuple\n"); | 148 | pr_debug("icmpv6_error: Can't get tuple\n"); |
149 | return -NF_ACCEPT; | 149 | return -NF_ACCEPT; |
150 | } | 150 | } |
151 | 151 | ||
152 | /* rcu_read_lock()ed by nf_hook_thresh */ | 152 | /* rcu_read_lock()ed by nf_hook_thresh */ |
153 | inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum); | 153 | inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum); |
154 | 154 | ||
155 | /* Ordinarily, we'd expect the inverted tupleproto, but it's | 155 | /* Ordinarily, we'd expect the inverted tupleproto, but it's |
156 | been preserved inside the ICMP. */ | 156 | been preserved inside the ICMP. */ |
157 | if (!nf_ct_invert_tuple(&intuple, &origtuple, inproto)) { | 157 | if (!nf_ct_invert_tuple(&intuple, &origtuple, inproto)) { |
158 | pr_debug("icmpv6_error: Can't invert tuple\n"); | 158 | pr_debug("icmpv6_error: Can't invert tuple\n"); |
159 | return -NF_ACCEPT; | 159 | return -NF_ACCEPT; |
160 | } | 160 | } |
161 | 161 | ||
162 | ctinfo = IP_CT_RELATED; | 162 | ctinfo = IP_CT_RELATED; |
163 | 163 | ||
164 | h = nf_conntrack_find_get(net, nf_ct_zone_tmpl(tmpl, skb, &tmp), | 164 | h = nf_conntrack_find_get(net, nf_ct_zone_tmpl(tmpl, skb, &tmp), |
165 | &intuple); | 165 | &intuple); |
166 | if (!h) { | 166 | if (!h) { |
167 | pr_debug("icmpv6_error: no match\n"); | 167 | pr_debug("icmpv6_error: no match\n"); |
168 | return -NF_ACCEPT; | 168 | return -NF_ACCEPT; |
169 | } else { | 169 | } else { |
170 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) | 170 | if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) |
171 | ctinfo += IP_CT_IS_REPLY; | 171 | ctinfo += IP_CT_IS_REPLY; |
172 | } | 172 | } |
173 | 173 | ||
174 | /* Update skb to refer to this connection */ | 174 | /* Update skb to refer to this connection */ |
175 | nf_ct_set(skb, nf_ct_tuplehash_to_ctrack(h), ctinfo); | 175 | nf_ct_set(skb, nf_ct_tuplehash_to_ctrack(h), ctinfo); |
176 | return NF_ACCEPT; | 176 | return NF_ACCEPT; |
177 | } | 177 | } |
178 | 178 | ||
179 | static void icmpv6_error_log(const struct sk_buff *skb, | 179 | static void icmpv6_error_log(const struct sk_buff *skb, |
180 | const struct nf_hook_state *state, | 180 | const struct nf_hook_state *state, |
181 | const char *msg) | 181 | const char *msg) |
182 | { | 182 | { |
183 | nf_l4proto_log_invalid(skb, state->net, state->pf, | 183 | nf_l4proto_log_invalid(skb, state->net, state->pf, |
184 | IPPROTO_ICMPV6, "%s", msg); | 184 | IPPROTO_ICMPV6, "%s", msg); |
185 | } | 185 | } |
186 | 186 | ||
187 | static int | 187 | static int |
188 | icmpv6_error(struct nf_conn *tmpl, | 188 | icmpv6_error(struct nf_conn *tmpl, |
189 | struct sk_buff *skb, | 189 | struct sk_buff *skb, |
190 | unsigned int dataoff, | 190 | unsigned int dataoff, |
191 | const struct nf_hook_state *state) | 191 | const struct nf_hook_state *state) |
192 | { | 192 | { |
193 | const struct icmp6hdr *icmp6h; | 193 | const struct icmp6hdr *icmp6h; |
194 | struct icmp6hdr _ih; | 194 | struct icmp6hdr _ih; |
195 | int type; | 195 | int type; |
196 | 196 | ||
197 | icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); | 197 | icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); |
198 | if (icmp6h == NULL) { | 198 | if (icmp6h == NULL) { |
199 | icmpv6_error_log(skb, state, "short packet"); | 199 | icmpv6_error_log(skb, state, "short packet"); |
200 | return -NF_ACCEPT; | 200 | return -NF_ACCEPT; |
201 | } | 201 | } |
202 | 202 | ||
203 | if (state->hook == NF_INET_PRE_ROUTING && | 203 | if (state->hook == NF_INET_PRE_ROUTING && |
204 | state->net->ct.sysctl_checksum && | 204 | state->net->ct.sysctl_checksum && |
205 | nf_ip6_checksum(skb, state->hook, dataoff, IPPROTO_ICMPV6)) { | 205 | nf_ip6_checksum(skb, state->hook, dataoff, IPPROTO_ICMPV6)) { |
206 | icmpv6_error_log(skb, state, "ICMPv6 checksum failed"); | 206 | icmpv6_error_log(skb, state, "ICMPv6 checksum failed"); |
207 | return -NF_ACCEPT; | 207 | return -NF_ACCEPT; |
208 | } | 208 | } |
209 | 209 | ||
210 | type = icmp6h->icmp6_type - 130; | 210 | type = icmp6h->icmp6_type - 130; |
211 | if (type >= 0 && type < sizeof(noct_valid_new) && | 211 | if (type >= 0 && type < sizeof(noct_valid_new) && |
212 | noct_valid_new[type]) { | 212 | noct_valid_new[type]) { |
213 | nf_ct_set(skb, NULL, IP_CT_UNTRACKED); | 213 | nf_ct_set(skb, NULL, IP_CT_UNTRACKED); |
214 | return NF_ACCEPT; | 214 | return NF_ACCEPT; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* is not error message ? */ | 217 | /* is not error message ? */ |
218 | if (icmp6h->icmp6_type >= 128) | 218 | if (icmp6h->icmp6_type >= 128) |
219 | return NF_ACCEPT; | 219 | return NF_ACCEPT; |
220 | 220 | ||
221 | return icmpv6_error_message(state->net, tmpl, skb, dataoff); | 221 | return icmpv6_error_message(state->net, tmpl, skb, dataoff); |
222 | } | 222 | } |
223 | 223 | ||
224 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 224 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
225 | 225 | ||
226 | #include <linux/netfilter/nfnetlink.h> | 226 | #include <linux/netfilter/nfnetlink.h> |
227 | #include <linux/netfilter/nfnetlink_conntrack.h> | 227 | #include <linux/netfilter/nfnetlink_conntrack.h> |
228 | static int icmpv6_tuple_to_nlattr(struct sk_buff *skb, | 228 | static int icmpv6_tuple_to_nlattr(struct sk_buff *skb, |
229 | const struct nf_conntrack_tuple *t) | 229 | const struct nf_conntrack_tuple *t) |
230 | { | 230 | { |
231 | if (nla_put_be16(skb, CTA_PROTO_ICMPV6_ID, t->src.u.icmp.id) || | 231 | if (nla_put_be16(skb, CTA_PROTO_ICMPV6_ID, t->src.u.icmp.id) || |
232 | nla_put_u8(skb, CTA_PROTO_ICMPV6_TYPE, t->dst.u.icmp.type) || | 232 | nla_put_u8(skb, CTA_PROTO_ICMPV6_TYPE, t->dst.u.icmp.type) || |
233 | nla_put_u8(skb, CTA_PROTO_ICMPV6_CODE, t->dst.u.icmp.code)) | 233 | nla_put_u8(skb, CTA_PROTO_ICMPV6_CODE, t->dst.u.icmp.code)) |
234 | goto nla_put_failure; | 234 | goto nla_put_failure; |
235 | return 0; | 235 | return 0; |
236 | 236 | ||
237 | nla_put_failure: | 237 | nla_put_failure: |
238 | return -1; | 238 | return -1; |
239 | } | 239 | } |
240 | 240 | ||
241 | static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = { | 241 | static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = { |
242 | [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 }, | 242 | [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 }, |
243 | [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 }, | 243 | [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 }, |
244 | [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 }, | 244 | [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 }, |
245 | }; | 245 | }; |
246 | 246 | ||
247 | static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], | 247 | static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], |
248 | struct nf_conntrack_tuple *tuple) | 248 | struct nf_conntrack_tuple *tuple) |
249 | { | 249 | { |
250 | if (!tb[CTA_PROTO_ICMPV6_TYPE] || | 250 | if (!tb[CTA_PROTO_ICMPV6_TYPE] || |
251 | !tb[CTA_PROTO_ICMPV6_CODE] || | 251 | !tb[CTA_PROTO_ICMPV6_CODE] || |
252 | !tb[CTA_PROTO_ICMPV6_ID]) | 252 | !tb[CTA_PROTO_ICMPV6_ID]) |
253 | return -EINVAL; | 253 | return -EINVAL; |
254 | 254 | ||
255 | tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); | 255 | tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); |
256 | tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); | 256 | tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); |
257 | tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); | 257 | tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); |
258 | 258 | ||
259 | if (tuple->dst.u.icmp.type < 128 || | 259 | if (tuple->dst.u.icmp.type < 128 || |
260 | tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || | 260 | tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || |
261 | !invmap[tuple->dst.u.icmp.type - 128]) | 261 | !invmap[tuple->dst.u.icmp.type - 128]) |
262 | return -EINVAL; | 262 | return -EINVAL; |
263 | 263 | ||
264 | return 0; | 264 | return 0; |
265 | } | 265 | } |
266 | 266 | ||
267 | static unsigned int icmpv6_nlattr_tuple_size(void) | 267 | static unsigned int icmpv6_nlattr_tuple_size(void) |
268 | { | 268 | { |
269 | static unsigned int size __read_mostly; | 269 | static unsigned int size __read_mostly; |
270 | 270 | ||
271 | if (!size) | 271 | if (!size) |
272 | size = nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1); | 272 | size = nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1); |
273 | 273 | ||
274 | return size; | 274 | return size; |
275 | } | 275 | } |
276 | #endif | 276 | #endif |
277 | 277 | ||
278 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 278 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
279 | 279 | ||
280 | #include <linux/netfilter/nfnetlink.h> | 280 | #include <linux/netfilter/nfnetlink.h> |
281 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 281 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
282 | 282 | ||
283 | static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], | 283 | static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], |
284 | struct net *net, void *data) | 284 | struct net *net, void *data) |
285 | { | 285 | { |
286 | unsigned int *timeout = data; | 286 | unsigned int *timeout = data; |
287 | struct nf_icmp_net *in = icmpv6_pernet(net); | 287 | struct nf_icmp_net *in = icmpv6_pernet(net); |
288 | 288 | ||
289 | if (!timeout) | 289 | if (!timeout) |
290 | timeout = icmpv6_get_timeouts(net); | 290 | timeout = icmpv6_get_timeouts(net); |
291 | if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) { | 291 | if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) { |
292 | *timeout = | 292 | *timeout = |
293 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ; | 293 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ; |
294 | } else { | 294 | } else { |
295 | /* Set default ICMPv6 timeout. */ | 295 | /* Set default ICMPv6 timeout. */ |
296 | *timeout = in->timeout; | 296 | *timeout = in->timeout; |
297 | } | 297 | } |
298 | return 0; | 298 | return 0; |
299 | } | 299 | } |
300 | 300 | ||
301 | static int | 301 | static int |
302 | icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 302 | icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
303 | { | 303 | { |
304 | const unsigned int *timeout = data; | 304 | const unsigned int *timeout = data; |
305 | 305 | ||
306 | if (nla_put_be32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ))) | 306 | if (nla_put_be32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ))) |
307 | goto nla_put_failure; | 307 | goto nla_put_failure; |
308 | return 0; | 308 | return 0; |
309 | 309 | ||
310 | nla_put_failure: | 310 | nla_put_failure: |
311 | return -ENOSPC; | 311 | return -ENOSPC; |
312 | } | 312 | } |
313 | 313 | ||
314 | static const struct nla_policy | 314 | static const struct nla_policy |
315 | icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = { | 315 | icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = { |
316 | [CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 }, | 316 | [CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 }, |
317 | }; | 317 | }; |
318 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 318 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
319 | 319 | ||
320 | #ifdef CONFIG_SYSCTL | 320 | #ifdef CONFIG_SYSCTL |
321 | static struct ctl_table icmpv6_sysctl_table[] = { | 321 | static struct ctl_table icmpv6_sysctl_table[] = { |
322 | { | 322 | { |
323 | .procname = "nf_conntrack_icmpv6_timeout", | 323 | .procname = "nf_conntrack_icmpv6_timeout", |
324 | .maxlen = sizeof(unsigned int), | 324 | .maxlen = sizeof(unsigned int), |
325 | .mode = 0644, | 325 | .mode = 0644, |
326 | .proc_handler = proc_dointvec_jiffies, | 326 | .proc_handler = proc_dointvec_jiffies, |
327 | }, | 327 | }, |
328 | { } | 328 | { } |
329 | }; | 329 | }; |
330 | #endif /* CONFIG_SYSCTL */ | 330 | #endif /* CONFIG_SYSCTL */ |
331 | 331 | ||
332 | static int icmpv6_kmemdup_sysctl_table(struct nf_proto_net *pn, | 332 | static int icmpv6_kmemdup_sysctl_table(struct nf_proto_net *pn, |
333 | struct nf_icmp_net *in) | 333 | struct nf_icmp_net *in) |
334 | { | 334 | { |
335 | #ifdef CONFIG_SYSCTL | 335 | #ifdef CONFIG_SYSCTL |
336 | pn->ctl_table = kmemdup(icmpv6_sysctl_table, | 336 | pn->ctl_table = kmemdup(icmpv6_sysctl_table, |
337 | sizeof(icmpv6_sysctl_table), | 337 | sizeof(icmpv6_sysctl_table), |
338 | GFP_KERNEL); | 338 | GFP_KERNEL); |
339 | if (!pn->ctl_table) | 339 | if (!pn->ctl_table) |
340 | return -ENOMEM; | 340 | return -ENOMEM; |
341 | 341 | ||
342 | pn->ctl_table[0].data = &in->timeout; | 342 | pn->ctl_table[0].data = &in->timeout; |
343 | #endif | 343 | #endif |
344 | return 0; | 344 | return 0; |
345 | } | 345 | } |
346 | 346 | ||
347 | static int icmpv6_init_net(struct net *net, u_int16_t proto) | 347 | static int icmpv6_init_net(struct net *net, u_int16_t proto) |
348 | { | 348 | { |
349 | struct nf_icmp_net *in = icmpv6_pernet(net); | 349 | struct nf_icmp_net *in = icmpv6_pernet(net); |
350 | struct nf_proto_net *pn = &in->pn; | 350 | struct nf_proto_net *pn = &in->pn; |
351 | 351 | ||
352 | in->timeout = nf_ct_icmpv6_timeout; | 352 | in->timeout = nf_ct_icmpv6_timeout; |
353 | 353 | ||
354 | return icmpv6_kmemdup_sysctl_table(pn, in); | 354 | return icmpv6_kmemdup_sysctl_table(pn, in); |
355 | } | 355 | } |
356 | 356 | ||
357 | static struct nf_proto_net *icmpv6_get_net_proto(struct net *net) | 357 | static struct nf_proto_net *icmpv6_get_net_proto(struct net *net) |
358 | { | 358 | { |
359 | return &net->ct.nf_ct_proto.icmpv6.pn; | 359 | return &net->ct.nf_ct_proto.icmpv6.pn; |
360 | } | 360 | } |
361 | 361 | ||
362 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 = | 362 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 = |
363 | { | 363 | { |
364 | .l3proto = PF_INET6, | 364 | .l3proto = PF_INET6, |
365 | .l4proto = IPPROTO_ICMPV6, | 365 | .l4proto = IPPROTO_ICMPV6, |
366 | .pkt_to_tuple = icmpv6_pkt_to_tuple, | 366 | .pkt_to_tuple = icmpv6_pkt_to_tuple, |
367 | .invert_tuple = icmpv6_invert_tuple, | 367 | .invert_tuple = icmpv6_invert_tuple, |
368 | .packet = icmpv6_packet, | 368 | .packet = icmpv6_packet, |
369 | .error = icmpv6_error, | 369 | .error = icmpv6_error, |
370 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 370 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
371 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, | 371 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, |
372 | .nlattr_tuple_size = icmpv6_nlattr_tuple_size, | 372 | .nlattr_tuple_size = icmpv6_nlattr_tuple_size, |
373 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, | 373 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
374 | .nla_policy = icmpv6_nla_policy, | 374 | .nla_policy = icmpv6_nla_policy, |
375 | #endif | 375 | #endif |
376 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 376 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
377 | .ctnl_timeout = { | 377 | .ctnl_timeout = { |
378 | .nlattr_to_obj = icmpv6_timeout_nlattr_to_obj, | 378 | .nlattr_to_obj = icmpv6_timeout_nlattr_to_obj, |
379 | .obj_to_nlattr = icmpv6_timeout_obj_to_nlattr, | 379 | .obj_to_nlattr = icmpv6_timeout_obj_to_nlattr, |
380 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, | 380 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, |
381 | .obj_size = sizeof(unsigned int), | 381 | .obj_size = sizeof(unsigned int), |
382 | .nla_policy = icmpv6_timeout_nla_policy, | 382 | .nla_policy = icmpv6_timeout_nla_policy, |
383 | }, | 383 | }, |
384 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 384 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
385 | .init_net = icmpv6_init_net, | 385 | .init_net = icmpv6_init_net, |
386 | .get_net_proto = icmpv6_get_net_proto, | 386 | .get_net_proto = icmpv6_get_net_proto, |
387 | }; | 387 | }; |
388 | 388 |
net/netfilter/nf_conntrack_proto_sctp.c
1 | /* | 1 | /* |
2 | * Connection tracking protocol helper module for SCTP. | 2 | * Connection tracking protocol helper module for SCTP. |
3 | * | 3 | * |
4 | * Copyright (c) 2004 Kiran Kumar Immidi <immidi_kiran@yahoo.com> | 4 | * Copyright (c) 2004 Kiran Kumar Immidi <immidi_kiran@yahoo.com> |
5 | * Copyright (c) 2004-2012 Patrick McHardy <kaber@trash.net> | 5 | * Copyright (c) 2004-2012 Patrick McHardy <kaber@trash.net> |
6 | * | 6 | * |
7 | * SCTP is defined in RFC 2960. References to various sections in this code | 7 | * SCTP is defined in RFC 2960. References to various sections in this code |
8 | * are to this RFC. | 8 | * are to this RFC. |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
16 | #include <linux/timer.h> | 16 | #include <linux/timer.h> |
17 | #include <linux/netfilter.h> | 17 | #include <linux/netfilter.h> |
18 | #include <linux/in.h> | 18 | #include <linux/in.h> |
19 | #include <linux/ip.h> | 19 | #include <linux/ip.h> |
20 | #include <linux/sctp.h> | 20 | #include <linux/sctp.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <net/sctp/checksum.h> | 25 | #include <net/sctp/checksum.h> |
26 | 26 | ||
27 | #include <net/netfilter/nf_log.h> | 27 | #include <net/netfilter/nf_log.h> |
28 | #include <net/netfilter/nf_conntrack.h> | 28 | #include <net/netfilter/nf_conntrack.h> |
29 | #include <net/netfilter/nf_conntrack_l4proto.h> | 29 | #include <net/netfilter/nf_conntrack_l4proto.h> |
30 | #include <net/netfilter/nf_conntrack_ecache.h> | 30 | #include <net/netfilter/nf_conntrack_ecache.h> |
31 | #include <net/netfilter/nf_conntrack_timeout.h> | 31 | #include <net/netfilter/nf_conntrack_timeout.h> |
32 | 32 | ||
33 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | 33 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more |
34 | closely. They're more complex. --RR | 34 | closely. They're more complex. --RR |
35 | 35 | ||
36 | And so for me for SCTP :D -Kiran */ | 36 | And so for me for SCTP :D -Kiran */ |
37 | 37 | ||
38 | static const char *const sctp_conntrack_names[] = { | 38 | static const char *const sctp_conntrack_names[] = { |
39 | "NONE", | 39 | "NONE", |
40 | "CLOSED", | 40 | "CLOSED", |
41 | "COOKIE_WAIT", | 41 | "COOKIE_WAIT", |
42 | "COOKIE_ECHOED", | 42 | "COOKIE_ECHOED", |
43 | "ESTABLISHED", | 43 | "ESTABLISHED", |
44 | "SHUTDOWN_SENT", | 44 | "SHUTDOWN_SENT", |
45 | "SHUTDOWN_RECD", | 45 | "SHUTDOWN_RECD", |
46 | "SHUTDOWN_ACK_SENT", | 46 | "SHUTDOWN_ACK_SENT", |
47 | "HEARTBEAT_SENT", | 47 | "HEARTBEAT_SENT", |
48 | "HEARTBEAT_ACKED", | 48 | "HEARTBEAT_ACKED", |
49 | }; | 49 | }; |
50 | 50 | ||
51 | #define SECS * HZ | 51 | #define SECS * HZ |
52 | #define MINS * 60 SECS | 52 | #define MINS * 60 SECS |
53 | #define HOURS * 60 MINS | 53 | #define HOURS * 60 MINS |
54 | #define DAYS * 24 HOURS | 54 | #define DAYS * 24 HOURS |
55 | 55 | ||
56 | static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = { | 56 | static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = { |
57 | [SCTP_CONNTRACK_CLOSED] = 10 SECS, | 57 | [SCTP_CONNTRACK_CLOSED] = 10 SECS, |
58 | [SCTP_CONNTRACK_COOKIE_WAIT] = 3 SECS, | 58 | [SCTP_CONNTRACK_COOKIE_WAIT] = 3 SECS, |
59 | [SCTP_CONNTRACK_COOKIE_ECHOED] = 3 SECS, | 59 | [SCTP_CONNTRACK_COOKIE_ECHOED] = 3 SECS, |
60 | [SCTP_CONNTRACK_ESTABLISHED] = 5 DAYS, | 60 | [SCTP_CONNTRACK_ESTABLISHED] = 5 DAYS, |
61 | [SCTP_CONNTRACK_SHUTDOWN_SENT] = 300 SECS / 1000, | 61 | [SCTP_CONNTRACK_SHUTDOWN_SENT] = 300 SECS / 1000, |
62 | [SCTP_CONNTRACK_SHUTDOWN_RECD] = 300 SECS / 1000, | 62 | [SCTP_CONNTRACK_SHUTDOWN_RECD] = 300 SECS / 1000, |
63 | [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = 3 SECS, | 63 | [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = 3 SECS, |
64 | [SCTP_CONNTRACK_HEARTBEAT_SENT] = 30 SECS, | 64 | [SCTP_CONNTRACK_HEARTBEAT_SENT] = 30 SECS, |
65 | [SCTP_CONNTRACK_HEARTBEAT_ACKED] = 210 SECS, | 65 | [SCTP_CONNTRACK_HEARTBEAT_ACKED] = 210 SECS, |
66 | }; | 66 | }; |
67 | 67 | ||
68 | #define sNO SCTP_CONNTRACK_NONE | 68 | #define sNO SCTP_CONNTRACK_NONE |
69 | #define sCL SCTP_CONNTRACK_CLOSED | 69 | #define sCL SCTP_CONNTRACK_CLOSED |
70 | #define sCW SCTP_CONNTRACK_COOKIE_WAIT | 70 | #define sCW SCTP_CONNTRACK_COOKIE_WAIT |
71 | #define sCE SCTP_CONNTRACK_COOKIE_ECHOED | 71 | #define sCE SCTP_CONNTRACK_COOKIE_ECHOED |
72 | #define sES SCTP_CONNTRACK_ESTABLISHED | 72 | #define sES SCTP_CONNTRACK_ESTABLISHED |
73 | #define sSS SCTP_CONNTRACK_SHUTDOWN_SENT | 73 | #define sSS SCTP_CONNTRACK_SHUTDOWN_SENT |
74 | #define sSR SCTP_CONNTRACK_SHUTDOWN_RECD | 74 | #define sSR SCTP_CONNTRACK_SHUTDOWN_RECD |
75 | #define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT | 75 | #define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT |
76 | #define sHS SCTP_CONNTRACK_HEARTBEAT_SENT | 76 | #define sHS SCTP_CONNTRACK_HEARTBEAT_SENT |
77 | #define sHA SCTP_CONNTRACK_HEARTBEAT_ACKED | 77 | #define sHA SCTP_CONNTRACK_HEARTBEAT_ACKED |
78 | #define sIV SCTP_CONNTRACK_MAX | 78 | #define sIV SCTP_CONNTRACK_MAX |
79 | 79 | ||
80 | /* | 80 | /* |
81 | These are the descriptions of the states: | 81 | These are the descriptions of the states: |
82 | 82 | ||
83 | NOTE: These state names are tantalizingly similar to the states of an | 83 | NOTE: These state names are tantalizingly similar to the states of an |
84 | SCTP endpoint. But the interpretation of the states is a little different, | 84 | SCTP endpoint. But the interpretation of the states is a little different, |
85 | considering that these are the states of the connection and not of an end | 85 | considering that these are the states of the connection and not of an end |
86 | point. Please note the subtleties. -Kiran | 86 | point. Please note the subtleties. -Kiran |
87 | 87 | ||
88 | NONE - Nothing so far. | 88 | NONE - Nothing so far. |
89 | COOKIE WAIT - We have seen an INIT chunk in the original direction, or also | 89 | COOKIE WAIT - We have seen an INIT chunk in the original direction, or also |
90 | an INIT_ACK chunk in the reply direction. | 90 | an INIT_ACK chunk in the reply direction. |
91 | COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction. | 91 | COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction. |
92 | ESTABLISHED - We have seen a COOKIE_ACK in the reply direction. | 92 | ESTABLISHED - We have seen a COOKIE_ACK in the reply direction. |
93 | SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction. | 93 | SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction. |
94 | SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin. | 94 | SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin. |
95 | SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite | 95 | SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite |
96 | to that of the SHUTDOWN chunk. | 96 | to that of the SHUTDOWN chunk. |
97 | CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of | 97 | CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of |
98 | the SHUTDOWN chunk. Connection is closed. | 98 | the SHUTDOWN chunk. Connection is closed. |
99 | HEARTBEAT_SENT - We have seen a HEARTBEAT in a new flow. | 99 | HEARTBEAT_SENT - We have seen a HEARTBEAT in a new flow. |
100 | HEARTBEAT_ACKED - We have seen a HEARTBEAT-ACK in the direction opposite to | 100 | HEARTBEAT_ACKED - We have seen a HEARTBEAT-ACK in the direction opposite to |
101 | that of the HEARTBEAT chunk. Secondary connection is | 101 | that of the HEARTBEAT chunk. Secondary connection is |
102 | established. | 102 | established. |
103 | */ | 103 | */ |
104 | 104 | ||
105 | /* TODO | 105 | /* TODO |
106 | - I have assumed that the first INIT is in the original direction. | 106 | - I have assumed that the first INIT is in the original direction. |
107 | This messes things when an INIT comes in the reply direction in CLOSED | 107 | This messes things when an INIT comes in the reply direction in CLOSED |
108 | state. | 108 | state. |
109 | - Check the error type in the reply dir before transitioning from | 109 | - Check the error type in the reply dir before transitioning from |
110 | cookie echoed to closed. | 110 | cookie echoed to closed. |
111 | - Sec 5.2.4 of RFC 2960 | 111 | - Sec 5.2.4 of RFC 2960 |
112 | - Full Multi Homing support. | 112 | - Full Multi Homing support. |
113 | */ | 113 | */ |
114 | 114 | ||
115 | /* SCTP conntrack state transitions */ | 115 | /* SCTP conntrack state transitions */ |
116 | static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { | 116 | static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { |
117 | { | 117 | { |
118 | /* ORIGINAL */ | 118 | /* ORIGINAL */ |
119 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ | 119 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ |
120 | /* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA, sCW, sHA}, | 120 | /* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA, sCW, sHA}, |
121 | /* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA}, | 121 | /* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA}, |
122 | /* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, | 122 | /* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, |
123 | /* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL, sSS}, | 123 | /* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL, sSS}, |
124 | /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA, sHA}, | 124 | /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA, sHA}, |
125 | /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't have Stale cookie*/ | 125 | /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't have Stale cookie*/ |
126 | /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* 5.2.4 - Big TODO */ | 126 | /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* 5.2.4 - Big TODO */ |
127 | /* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't come in orig dir */ | 127 | /* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA},/* Can't come in orig dir */ |
128 | /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL, sHA}, | 128 | /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL, sHA}, |
129 | /* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, | 129 | /* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, |
130 | /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA} | 130 | /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA} |
131 | }, | 131 | }, |
132 | { | 132 | { |
133 | /* REPLY */ | 133 | /* REPLY */ |
134 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ | 134 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA */ |
135 | /* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* INIT in sCL Big TODO */ | 135 | /* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* INIT in sCL Big TODO */ |
136 | /* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA}, | 136 | /* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA}, |
137 | /* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV, sCL}, | 137 | /* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV, sCL}, |
138 | /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV, sSR}, | 138 | /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV, sSR}, |
139 | /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV, sHA}, | 139 | /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV, sHA}, |
140 | /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV, sHA}, | 140 | /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV, sHA}, |
141 | /* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* Can't come in reply dir */ | 141 | /* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA},/* Can't come in reply dir */ |
142 | /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV, sHA}, | 142 | /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV, sHA}, |
143 | /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV, sHA}, | 143 | /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV, sHA}, |
144 | /* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, | 144 | /* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA}, |
145 | /* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHA, sHA} | 145 | /* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHA, sHA} |
146 | } | 146 | } |
147 | }; | 147 | }; |
148 | 148 | ||
149 | static inline struct nf_sctp_net *sctp_pernet(struct net *net) | 149 | static inline struct nf_sctp_net *sctp_pernet(struct net *net) |
150 | { | 150 | { |
151 | return &net->ct.nf_ct_proto.sctp; | 151 | return &net->ct.nf_ct_proto.sctp; |
152 | } | 152 | } |
153 | 153 | ||
154 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 154 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
155 | /* Print out the private part of the conntrack. */ | 155 | /* Print out the private part of the conntrack. */ |
156 | static void sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct) | 156 | static void sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct) |
157 | { | 157 | { |
158 | seq_printf(s, "%s ", sctp_conntrack_names[ct->proto.sctp.state]); | 158 | seq_printf(s, "%s ", sctp_conntrack_names[ct->proto.sctp.state]); |
159 | } | 159 | } |
160 | #endif | 160 | #endif |
161 | 161 | ||
162 | #define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) \ | 162 | #define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) \ |
163 | for ((offset) = (dataoff) + sizeof(struct sctphdr), (count) = 0; \ | 163 | for ((offset) = (dataoff) + sizeof(struct sctphdr), (count) = 0; \ |
164 | (offset) < (skb)->len && \ | 164 | (offset) < (skb)->len && \ |
165 | ((sch) = skb_header_pointer((skb), (offset), sizeof(_sch), &(_sch))); \ | 165 | ((sch) = skb_header_pointer((skb), (offset), sizeof(_sch), &(_sch))); \ |
166 | (offset) += (ntohs((sch)->length) + 3) & ~3, (count)++) | 166 | (offset) += (ntohs((sch)->length) + 3) & ~3, (count)++) |
167 | 167 | ||
168 | /* Some validity checks to make sure the chunks are fine */ | 168 | /* Some validity checks to make sure the chunks are fine */ |
169 | static int do_basic_checks(struct nf_conn *ct, | 169 | static int do_basic_checks(struct nf_conn *ct, |
170 | const struct sk_buff *skb, | 170 | const struct sk_buff *skb, |
171 | unsigned int dataoff, | 171 | unsigned int dataoff, |
172 | unsigned long *map) | 172 | unsigned long *map) |
173 | { | 173 | { |
174 | u_int32_t offset, count; | 174 | u_int32_t offset, count; |
175 | struct sctp_chunkhdr _sch, *sch; | 175 | struct sctp_chunkhdr _sch, *sch; |
176 | int flag; | 176 | int flag; |
177 | 177 | ||
178 | flag = 0; | 178 | flag = 0; |
179 | 179 | ||
180 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { | 180 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { |
181 | pr_debug("Chunk Num: %d Type: %d\n", count, sch->type); | 181 | pr_debug("Chunk Num: %d Type: %d\n", count, sch->type); |
182 | 182 | ||
183 | if (sch->type == SCTP_CID_INIT || | 183 | if (sch->type == SCTP_CID_INIT || |
184 | sch->type == SCTP_CID_INIT_ACK || | 184 | sch->type == SCTP_CID_INIT_ACK || |
185 | sch->type == SCTP_CID_SHUTDOWN_COMPLETE) | 185 | sch->type == SCTP_CID_SHUTDOWN_COMPLETE) |
186 | flag = 1; | 186 | flag = 1; |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Cookie Ack/Echo chunks not the first OR | 189 | * Cookie Ack/Echo chunks not the first OR |
190 | * Init / Init Ack / Shutdown compl chunks not the only chunks | 190 | * Init / Init Ack / Shutdown compl chunks not the only chunks |
191 | * OR zero-length. | 191 | * OR zero-length. |
192 | */ | 192 | */ |
193 | if (((sch->type == SCTP_CID_COOKIE_ACK || | 193 | if (((sch->type == SCTP_CID_COOKIE_ACK || |
194 | sch->type == SCTP_CID_COOKIE_ECHO || | 194 | sch->type == SCTP_CID_COOKIE_ECHO || |
195 | flag) && | 195 | flag) && |
196 | count != 0) || !sch->length) { | 196 | count != 0) || !sch->length) { |
197 | pr_debug("Basic checks failed\n"); | 197 | pr_debug("Basic checks failed\n"); |
198 | return 1; | 198 | return 1; |
199 | } | 199 | } |
200 | 200 | ||
201 | if (map) | 201 | if (map) |
202 | set_bit(sch->type, map); | 202 | set_bit(sch->type, map); |
203 | } | 203 | } |
204 | 204 | ||
205 | pr_debug("Basic checks passed\n"); | 205 | pr_debug("Basic checks passed\n"); |
206 | return count == 0; | 206 | return count == 0; |
207 | } | 207 | } |
208 | 208 | ||
209 | static int sctp_new_state(enum ip_conntrack_dir dir, | 209 | static int sctp_new_state(enum ip_conntrack_dir dir, |
210 | enum sctp_conntrack cur_state, | 210 | enum sctp_conntrack cur_state, |
211 | int chunk_type) | 211 | int chunk_type) |
212 | { | 212 | { |
213 | int i; | 213 | int i; |
214 | 214 | ||
215 | pr_debug("Chunk type: %d\n", chunk_type); | 215 | pr_debug("Chunk type: %d\n", chunk_type); |
216 | 216 | ||
217 | switch (chunk_type) { | 217 | switch (chunk_type) { |
218 | case SCTP_CID_INIT: | 218 | case SCTP_CID_INIT: |
219 | pr_debug("SCTP_CID_INIT\n"); | 219 | pr_debug("SCTP_CID_INIT\n"); |
220 | i = 0; | 220 | i = 0; |
221 | break; | 221 | break; |
222 | case SCTP_CID_INIT_ACK: | 222 | case SCTP_CID_INIT_ACK: |
223 | pr_debug("SCTP_CID_INIT_ACK\n"); | 223 | pr_debug("SCTP_CID_INIT_ACK\n"); |
224 | i = 1; | 224 | i = 1; |
225 | break; | 225 | break; |
226 | case SCTP_CID_ABORT: | 226 | case SCTP_CID_ABORT: |
227 | pr_debug("SCTP_CID_ABORT\n"); | 227 | pr_debug("SCTP_CID_ABORT\n"); |
228 | i = 2; | 228 | i = 2; |
229 | break; | 229 | break; |
230 | case SCTP_CID_SHUTDOWN: | 230 | case SCTP_CID_SHUTDOWN: |
231 | pr_debug("SCTP_CID_SHUTDOWN\n"); | 231 | pr_debug("SCTP_CID_SHUTDOWN\n"); |
232 | i = 3; | 232 | i = 3; |
233 | break; | 233 | break; |
234 | case SCTP_CID_SHUTDOWN_ACK: | 234 | case SCTP_CID_SHUTDOWN_ACK: |
235 | pr_debug("SCTP_CID_SHUTDOWN_ACK\n"); | 235 | pr_debug("SCTP_CID_SHUTDOWN_ACK\n"); |
236 | i = 4; | 236 | i = 4; |
237 | break; | 237 | break; |
238 | case SCTP_CID_ERROR: | 238 | case SCTP_CID_ERROR: |
239 | pr_debug("SCTP_CID_ERROR\n"); | 239 | pr_debug("SCTP_CID_ERROR\n"); |
240 | i = 5; | 240 | i = 5; |
241 | break; | 241 | break; |
242 | case SCTP_CID_COOKIE_ECHO: | 242 | case SCTP_CID_COOKIE_ECHO: |
243 | pr_debug("SCTP_CID_COOKIE_ECHO\n"); | 243 | pr_debug("SCTP_CID_COOKIE_ECHO\n"); |
244 | i = 6; | 244 | i = 6; |
245 | break; | 245 | break; |
246 | case SCTP_CID_COOKIE_ACK: | 246 | case SCTP_CID_COOKIE_ACK: |
247 | pr_debug("SCTP_CID_COOKIE_ACK\n"); | 247 | pr_debug("SCTP_CID_COOKIE_ACK\n"); |
248 | i = 7; | 248 | i = 7; |
249 | break; | 249 | break; |
250 | case SCTP_CID_SHUTDOWN_COMPLETE: | 250 | case SCTP_CID_SHUTDOWN_COMPLETE: |
251 | pr_debug("SCTP_CID_SHUTDOWN_COMPLETE\n"); | 251 | pr_debug("SCTP_CID_SHUTDOWN_COMPLETE\n"); |
252 | i = 8; | 252 | i = 8; |
253 | break; | 253 | break; |
254 | case SCTP_CID_HEARTBEAT: | 254 | case SCTP_CID_HEARTBEAT: |
255 | pr_debug("SCTP_CID_HEARTBEAT"); | 255 | pr_debug("SCTP_CID_HEARTBEAT"); |
256 | i = 9; | 256 | i = 9; |
257 | break; | 257 | break; |
258 | case SCTP_CID_HEARTBEAT_ACK: | 258 | case SCTP_CID_HEARTBEAT_ACK: |
259 | pr_debug("SCTP_CID_HEARTBEAT_ACK"); | 259 | pr_debug("SCTP_CID_HEARTBEAT_ACK"); |
260 | i = 10; | 260 | i = 10; |
261 | break; | 261 | break; |
262 | default: | 262 | default: |
263 | /* Other chunks like DATA or SACK do not change the state */ | 263 | /* Other chunks like DATA or SACK do not change the state */ |
264 | pr_debug("Unknown chunk type, Will stay in %s\n", | 264 | pr_debug("Unknown chunk type, Will stay in %s\n", |
265 | sctp_conntrack_names[cur_state]); | 265 | sctp_conntrack_names[cur_state]); |
266 | return cur_state; | 266 | return cur_state; |
267 | } | 267 | } |
268 | 268 | ||
269 | pr_debug("dir: %d cur_state: %s chunk_type: %d new_state: %s\n", | 269 | pr_debug("dir: %d cur_state: %s chunk_type: %d new_state: %s\n", |
270 | dir, sctp_conntrack_names[cur_state], chunk_type, | 270 | dir, sctp_conntrack_names[cur_state], chunk_type, |
271 | sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]); | 271 | sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]); |
272 | 272 | ||
273 | return sctp_conntracks[dir][i][cur_state]; | 273 | return sctp_conntracks[dir][i][cur_state]; |
274 | } | 274 | } |
275 | 275 | ||
276 | /* Don't need lock here: this conntrack not in circulation yet */ | 276 | /* Don't need lock here: this conntrack not in circulation yet */ |
277 | static noinline bool | 277 | static noinline bool |
278 | sctp_new(struct nf_conn *ct, const struct sk_buff *skb, | 278 | sctp_new(struct nf_conn *ct, const struct sk_buff *skb, |
279 | const struct sctphdr *sh, unsigned int dataoff) | 279 | const struct sctphdr *sh, unsigned int dataoff) |
280 | { | 280 | { |
281 | enum sctp_conntrack new_state; | 281 | enum sctp_conntrack new_state; |
282 | const struct sctp_chunkhdr *sch; | 282 | const struct sctp_chunkhdr *sch; |
283 | struct sctp_chunkhdr _sch; | 283 | struct sctp_chunkhdr _sch; |
284 | u32 offset, count; | 284 | u32 offset, count; |
285 | 285 | ||
286 | memset(&ct->proto.sctp, 0, sizeof(ct->proto.sctp)); | 286 | memset(&ct->proto.sctp, 0, sizeof(ct->proto.sctp)); |
287 | new_state = SCTP_CONNTRACK_MAX; | 287 | new_state = SCTP_CONNTRACK_MAX; |
288 | for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) { | 288 | for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) { |
289 | new_state = sctp_new_state(IP_CT_DIR_ORIGINAL, | 289 | new_state = sctp_new_state(IP_CT_DIR_ORIGINAL, |
290 | SCTP_CONNTRACK_NONE, sch->type); | 290 | SCTP_CONNTRACK_NONE, sch->type); |
291 | 291 | ||
292 | /* Invalid: delete conntrack */ | 292 | /* Invalid: delete conntrack */ |
293 | if (new_state == SCTP_CONNTRACK_NONE || | 293 | if (new_state == SCTP_CONNTRACK_NONE || |
294 | new_state == SCTP_CONNTRACK_MAX) { | 294 | new_state == SCTP_CONNTRACK_MAX) { |
295 | pr_debug("nf_conntrack_sctp: invalid new deleting.\n"); | 295 | pr_debug("nf_conntrack_sctp: invalid new deleting.\n"); |
296 | return false; | 296 | return false; |
297 | } | 297 | } |
298 | 298 | ||
299 | /* Copy the vtag into the state info */ | 299 | /* Copy the vtag into the state info */ |
300 | if (sch->type == SCTP_CID_INIT) { | 300 | if (sch->type == SCTP_CID_INIT) { |
301 | struct sctp_inithdr _inithdr, *ih; | 301 | struct sctp_inithdr _inithdr, *ih; |
302 | /* Sec 8.5.1 (A) */ | 302 | /* Sec 8.5.1 (A) */ |
303 | if (sh->vtag) | 303 | if (sh->vtag) |
304 | return false; | 304 | return false; |
305 | 305 | ||
306 | ih = skb_header_pointer(skb, offset + sizeof(_sch), | 306 | ih = skb_header_pointer(skb, offset + sizeof(_sch), |
307 | sizeof(_inithdr), &_inithdr); | 307 | sizeof(_inithdr), &_inithdr); |
308 | if (!ih) | 308 | if (!ih) |
309 | return false; | 309 | return false; |
310 | 310 | ||
311 | pr_debug("Setting vtag %x for new conn\n", | 311 | pr_debug("Setting vtag %x for new conn\n", |
312 | ih->init_tag); | 312 | ih->init_tag); |
313 | 313 | ||
314 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag; | 314 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag; |
315 | } else if (sch->type == SCTP_CID_HEARTBEAT) { | 315 | } else if (sch->type == SCTP_CID_HEARTBEAT) { |
316 | pr_debug("Setting vtag %x for secondary conntrack\n", | 316 | pr_debug("Setting vtag %x for secondary conntrack\n", |
317 | sh->vtag); | 317 | sh->vtag); |
318 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag; | 318 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag; |
319 | } else { | 319 | } else { |
320 | /* If it is a shutdown ack OOTB packet, we expect a return | 320 | /* If it is a shutdown ack OOTB packet, we expect a return |
321 | shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ | 321 | shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ |
322 | pr_debug("Setting vtag %x for new conn OOTB\n", | 322 | pr_debug("Setting vtag %x for new conn OOTB\n", |
323 | sh->vtag); | 323 | sh->vtag); |
324 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; | 324 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; |
325 | } | 325 | } |
326 | 326 | ||
327 | ct->proto.sctp.state = new_state; | 327 | ct->proto.sctp.state = new_state; |
328 | } | 328 | } |
329 | 329 | ||
330 | return true; | 330 | return true; |
331 | } | 331 | } |
332 | 332 | ||
333 | /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ | 333 | /* Returns verdict for packet, or -NF_ACCEPT for invalid. */ |
334 | static int sctp_packet(struct nf_conn *ct, | 334 | static int sctp_packet(struct nf_conn *ct, |
335 | const struct sk_buff *skb, | 335 | struct sk_buff *skb, |
336 | unsigned int dataoff, | 336 | unsigned int dataoff, |
337 | enum ip_conntrack_info ctinfo, | 337 | enum ip_conntrack_info ctinfo, |
338 | const struct nf_hook_state *state) | 338 | const struct nf_hook_state *state) |
339 | { | 339 | { |
340 | enum sctp_conntrack new_state, old_state; | 340 | enum sctp_conntrack new_state, old_state; |
341 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 341 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
342 | const struct sctphdr *sh; | 342 | const struct sctphdr *sh; |
343 | struct sctphdr _sctph; | 343 | struct sctphdr _sctph; |
344 | const struct sctp_chunkhdr *sch; | 344 | const struct sctp_chunkhdr *sch; |
345 | struct sctp_chunkhdr _sch; | 345 | struct sctp_chunkhdr _sch; |
346 | u_int32_t offset, count; | 346 | u_int32_t offset, count; |
347 | unsigned int *timeouts; | 347 | unsigned int *timeouts; |
348 | unsigned long map[256 / sizeof(unsigned long)] = { 0 }; | 348 | unsigned long map[256 / sizeof(unsigned long)] = { 0 }; |
349 | 349 | ||
350 | sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); | 350 | sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); |
351 | if (sh == NULL) | 351 | if (sh == NULL) |
352 | goto out; | 352 | goto out; |
353 | 353 | ||
354 | if (do_basic_checks(ct, skb, dataoff, map) != 0) | 354 | if (do_basic_checks(ct, skb, dataoff, map) != 0) |
355 | goto out; | 355 | goto out; |
356 | 356 | ||
357 | if (!nf_ct_is_confirmed(ct)) { | 357 | if (!nf_ct_is_confirmed(ct)) { |
358 | /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ | 358 | /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ |
359 | if (test_bit(SCTP_CID_ABORT, map) || | 359 | if (test_bit(SCTP_CID_ABORT, map) || |
360 | test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) || | 360 | test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) || |
361 | test_bit(SCTP_CID_COOKIE_ACK, map)) | 361 | test_bit(SCTP_CID_COOKIE_ACK, map)) |
362 | return -NF_ACCEPT; | 362 | return -NF_ACCEPT; |
363 | 363 | ||
364 | if (!sctp_new(ct, skb, sh, dataoff)) | 364 | if (!sctp_new(ct, skb, sh, dataoff)) |
365 | return -NF_ACCEPT; | 365 | return -NF_ACCEPT; |
366 | } | 366 | } |
367 | 367 | ||
368 | /* Check the verification tag (Sec 8.5) */ | 368 | /* Check the verification tag (Sec 8.5) */ |
369 | if (!test_bit(SCTP_CID_INIT, map) && | 369 | if (!test_bit(SCTP_CID_INIT, map) && |
370 | !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) && | 370 | !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) && |
371 | !test_bit(SCTP_CID_COOKIE_ECHO, map) && | 371 | !test_bit(SCTP_CID_COOKIE_ECHO, map) && |
372 | !test_bit(SCTP_CID_ABORT, map) && | 372 | !test_bit(SCTP_CID_ABORT, map) && |
373 | !test_bit(SCTP_CID_SHUTDOWN_ACK, map) && | 373 | !test_bit(SCTP_CID_SHUTDOWN_ACK, map) && |
374 | !test_bit(SCTP_CID_HEARTBEAT, map) && | 374 | !test_bit(SCTP_CID_HEARTBEAT, map) && |
375 | !test_bit(SCTP_CID_HEARTBEAT_ACK, map) && | 375 | !test_bit(SCTP_CID_HEARTBEAT_ACK, map) && |
376 | sh->vtag != ct->proto.sctp.vtag[dir]) { | 376 | sh->vtag != ct->proto.sctp.vtag[dir]) { |
377 | pr_debug("Verification tag check failed\n"); | 377 | pr_debug("Verification tag check failed\n"); |
378 | goto out; | 378 | goto out; |
379 | } | 379 | } |
380 | 380 | ||
381 | old_state = new_state = SCTP_CONNTRACK_NONE; | 381 | old_state = new_state = SCTP_CONNTRACK_NONE; |
382 | spin_lock_bh(&ct->lock); | 382 | spin_lock_bh(&ct->lock); |
383 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { | 383 | for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { |
384 | /* Special cases of Verification tag check (Sec 8.5.1) */ | 384 | /* Special cases of Verification tag check (Sec 8.5.1) */ |
385 | if (sch->type == SCTP_CID_INIT) { | 385 | if (sch->type == SCTP_CID_INIT) { |
386 | /* Sec 8.5.1 (A) */ | 386 | /* Sec 8.5.1 (A) */ |
387 | if (sh->vtag != 0) | 387 | if (sh->vtag != 0) |
388 | goto out_unlock; | 388 | goto out_unlock; |
389 | } else if (sch->type == SCTP_CID_ABORT) { | 389 | } else if (sch->type == SCTP_CID_ABORT) { |
390 | /* Sec 8.5.1 (B) */ | 390 | /* Sec 8.5.1 (B) */ |
391 | if (sh->vtag != ct->proto.sctp.vtag[dir] && | 391 | if (sh->vtag != ct->proto.sctp.vtag[dir] && |
392 | sh->vtag != ct->proto.sctp.vtag[!dir]) | 392 | sh->vtag != ct->proto.sctp.vtag[!dir]) |
393 | goto out_unlock; | 393 | goto out_unlock; |
394 | } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { | 394 | } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { |
395 | /* Sec 8.5.1 (C) */ | 395 | /* Sec 8.5.1 (C) */ |
396 | if (sh->vtag != ct->proto.sctp.vtag[dir] && | 396 | if (sh->vtag != ct->proto.sctp.vtag[dir] && |
397 | sh->vtag != ct->proto.sctp.vtag[!dir] && | 397 | sh->vtag != ct->proto.sctp.vtag[!dir] && |
398 | sch->flags & SCTP_CHUNK_FLAG_T) | 398 | sch->flags & SCTP_CHUNK_FLAG_T) |
399 | goto out_unlock; | 399 | goto out_unlock; |
400 | } else if (sch->type == SCTP_CID_COOKIE_ECHO) { | 400 | } else if (sch->type == SCTP_CID_COOKIE_ECHO) { |
401 | /* Sec 8.5.1 (D) */ | 401 | /* Sec 8.5.1 (D) */ |
402 | if (sh->vtag != ct->proto.sctp.vtag[dir]) | 402 | if (sh->vtag != ct->proto.sctp.vtag[dir]) |
403 | goto out_unlock; | 403 | goto out_unlock; |
404 | } else if (sch->type == SCTP_CID_HEARTBEAT || | 404 | } else if (sch->type == SCTP_CID_HEARTBEAT || |
405 | sch->type == SCTP_CID_HEARTBEAT_ACK) { | 405 | sch->type == SCTP_CID_HEARTBEAT_ACK) { |
406 | if (ct->proto.sctp.vtag[dir] == 0) { | 406 | if (ct->proto.sctp.vtag[dir] == 0) { |
407 | pr_debug("Setting vtag %x for dir %d\n", | 407 | pr_debug("Setting vtag %x for dir %d\n", |
408 | sh->vtag, dir); | 408 | sh->vtag, dir); |
409 | ct->proto.sctp.vtag[dir] = sh->vtag; | 409 | ct->proto.sctp.vtag[dir] = sh->vtag; |
410 | } else if (sh->vtag != ct->proto.sctp.vtag[dir]) { | 410 | } else if (sh->vtag != ct->proto.sctp.vtag[dir]) { |
411 | pr_debug("Verification tag check failed\n"); | 411 | pr_debug("Verification tag check failed\n"); |
412 | goto out_unlock; | 412 | goto out_unlock; |
413 | } | 413 | } |
414 | } | 414 | } |
415 | 415 | ||
416 | old_state = ct->proto.sctp.state; | 416 | old_state = ct->proto.sctp.state; |
417 | new_state = sctp_new_state(dir, old_state, sch->type); | 417 | new_state = sctp_new_state(dir, old_state, sch->type); |
418 | 418 | ||
419 | /* Invalid */ | 419 | /* Invalid */ |
420 | if (new_state == SCTP_CONNTRACK_MAX) { | 420 | if (new_state == SCTP_CONNTRACK_MAX) { |
421 | pr_debug("nf_conntrack_sctp: Invalid dir=%i ctype=%u " | 421 | pr_debug("nf_conntrack_sctp: Invalid dir=%i ctype=%u " |
422 | "conntrack=%u\n", | 422 | "conntrack=%u\n", |
423 | dir, sch->type, old_state); | 423 | dir, sch->type, old_state); |
424 | goto out_unlock; | 424 | goto out_unlock; |
425 | } | 425 | } |
426 | 426 | ||
427 | /* If it is an INIT or an INIT ACK note down the vtag */ | 427 | /* If it is an INIT or an INIT ACK note down the vtag */ |
428 | if (sch->type == SCTP_CID_INIT || | 428 | if (sch->type == SCTP_CID_INIT || |
429 | sch->type == SCTP_CID_INIT_ACK) { | 429 | sch->type == SCTP_CID_INIT_ACK) { |
430 | struct sctp_inithdr _inithdr, *ih; | 430 | struct sctp_inithdr _inithdr, *ih; |
431 | 431 | ||
432 | ih = skb_header_pointer(skb, offset + sizeof(_sch), | 432 | ih = skb_header_pointer(skb, offset + sizeof(_sch), |
433 | sizeof(_inithdr), &_inithdr); | 433 | sizeof(_inithdr), &_inithdr); |
434 | if (ih == NULL) | 434 | if (ih == NULL) |
435 | goto out_unlock; | 435 | goto out_unlock; |
436 | pr_debug("Setting vtag %x for dir %d\n", | 436 | pr_debug("Setting vtag %x for dir %d\n", |
437 | ih->init_tag, !dir); | 437 | ih->init_tag, !dir); |
438 | ct->proto.sctp.vtag[!dir] = ih->init_tag; | 438 | ct->proto.sctp.vtag[!dir] = ih->init_tag; |
439 | } | 439 | } |
440 | 440 | ||
441 | ct->proto.sctp.state = new_state; | 441 | ct->proto.sctp.state = new_state; |
442 | if (old_state != new_state) | 442 | if (old_state != new_state) |
443 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); | 443 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); |
444 | } | 444 | } |
445 | spin_unlock_bh(&ct->lock); | 445 | spin_unlock_bh(&ct->lock); |
446 | 446 | ||
447 | timeouts = nf_ct_timeout_lookup(ct); | 447 | timeouts = nf_ct_timeout_lookup(ct); |
448 | if (!timeouts) | 448 | if (!timeouts) |
449 | timeouts = sctp_pernet(nf_ct_net(ct))->timeouts; | 449 | timeouts = sctp_pernet(nf_ct_net(ct))->timeouts; |
450 | 450 | ||
451 | nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); | 451 | nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]); |
452 | 452 | ||
453 | if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && | 453 | if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && |
454 | dir == IP_CT_DIR_REPLY && | 454 | dir == IP_CT_DIR_REPLY && |
455 | new_state == SCTP_CONNTRACK_ESTABLISHED) { | 455 | new_state == SCTP_CONNTRACK_ESTABLISHED) { |
456 | pr_debug("Setting assured bit\n"); | 456 | pr_debug("Setting assured bit\n"); |
457 | set_bit(IPS_ASSURED_BIT, &ct->status); | 457 | set_bit(IPS_ASSURED_BIT, &ct->status); |
458 | nf_conntrack_event_cache(IPCT_ASSURED, ct); | 458 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
459 | } | 459 | } |
460 | 460 | ||
461 | return NF_ACCEPT; | 461 | return NF_ACCEPT; |
462 | 462 | ||
463 | out_unlock: | 463 | out_unlock: |
464 | spin_unlock_bh(&ct->lock); | 464 | spin_unlock_bh(&ct->lock); |
465 | out: | 465 | out: |
466 | return -NF_ACCEPT; | 466 | return -NF_ACCEPT; |
467 | } | 467 | } |
468 | 468 | ||
469 | static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb, | 469 | static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb, |
470 | unsigned int dataoff, | 470 | unsigned int dataoff, |
471 | const struct nf_hook_state *state) | 471 | const struct nf_hook_state *state) |
472 | { | 472 | { |
473 | const struct sctphdr *sh; | 473 | const struct sctphdr *sh; |
474 | const char *logmsg; | 474 | const char *logmsg; |
475 | 475 | ||
476 | if (skb->len < dataoff + sizeof(struct sctphdr)) { | 476 | if (skb->len < dataoff + sizeof(struct sctphdr)) { |
477 | logmsg = "nf_ct_sctp: short packet "; | 477 | logmsg = "nf_ct_sctp: short packet "; |
478 | goto out_invalid; | 478 | goto out_invalid; |
479 | } | 479 | } |
480 | if (state->hook == NF_INET_PRE_ROUTING && | 480 | if (state->hook == NF_INET_PRE_ROUTING && |
481 | state->net->ct.sysctl_checksum && | 481 | state->net->ct.sysctl_checksum && |
482 | skb->ip_summed == CHECKSUM_NONE) { | 482 | skb->ip_summed == CHECKSUM_NONE) { |
483 | if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { | 483 | if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { |
484 | logmsg = "nf_ct_sctp: failed to read header "; | 484 | logmsg = "nf_ct_sctp: failed to read header "; |
485 | goto out_invalid; | 485 | goto out_invalid; |
486 | } | 486 | } |
487 | sh = (const struct sctphdr *)(skb->data + dataoff); | 487 | sh = (const struct sctphdr *)(skb->data + dataoff); |
488 | if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { | 488 | if (sh->checksum != sctp_compute_cksum(skb, dataoff)) { |
489 | logmsg = "nf_ct_sctp: bad CRC "; | 489 | logmsg = "nf_ct_sctp: bad CRC "; |
490 | goto out_invalid; | 490 | goto out_invalid; |
491 | } | 491 | } |
492 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 492 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
493 | } | 493 | } |
494 | return NF_ACCEPT; | 494 | return NF_ACCEPT; |
495 | out_invalid: | 495 | out_invalid: |
496 | nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); | 496 | nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg); |
497 | return -NF_ACCEPT; | 497 | return -NF_ACCEPT; |
498 | } | 498 | } |
499 | 499 | ||
500 | static bool sctp_can_early_drop(const struct nf_conn *ct) | 500 | static bool sctp_can_early_drop(const struct nf_conn *ct) |
501 | { | 501 | { |
502 | switch (ct->proto.sctp.state) { | 502 | switch (ct->proto.sctp.state) { |
503 | case SCTP_CONNTRACK_SHUTDOWN_SENT: | 503 | case SCTP_CONNTRACK_SHUTDOWN_SENT: |
504 | case SCTP_CONNTRACK_SHUTDOWN_RECD: | 504 | case SCTP_CONNTRACK_SHUTDOWN_RECD: |
505 | case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT: | 505 | case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT: |
506 | return true; | 506 | return true; |
507 | default: | 507 | default: |
508 | break; | 508 | break; |
509 | } | 509 | } |
510 | 510 | ||
511 | return false; | 511 | return false; |
512 | } | 512 | } |
513 | 513 | ||
514 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 514 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
515 | 515 | ||
516 | #include <linux/netfilter/nfnetlink.h> | 516 | #include <linux/netfilter/nfnetlink.h> |
517 | #include <linux/netfilter/nfnetlink_conntrack.h> | 517 | #include <linux/netfilter/nfnetlink_conntrack.h> |
518 | 518 | ||
519 | static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, | 519 | static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, |
520 | struct nf_conn *ct) | 520 | struct nf_conn *ct) |
521 | { | 521 | { |
522 | struct nlattr *nest_parms; | 522 | struct nlattr *nest_parms; |
523 | 523 | ||
524 | spin_lock_bh(&ct->lock); | 524 | spin_lock_bh(&ct->lock); |
525 | nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED); | 525 | nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED); |
526 | if (!nest_parms) | 526 | if (!nest_parms) |
527 | goto nla_put_failure; | 527 | goto nla_put_failure; |
528 | 528 | ||
529 | if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state) || | 529 | if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state) || |
530 | nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, | 530 | nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, |
531 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]) || | 531 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]) || |
532 | nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_REPLY, | 532 | nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_REPLY, |
533 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY])) | 533 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY])) |
534 | goto nla_put_failure; | 534 | goto nla_put_failure; |
535 | 535 | ||
536 | spin_unlock_bh(&ct->lock); | 536 | spin_unlock_bh(&ct->lock); |
537 | 537 | ||
538 | nla_nest_end(skb, nest_parms); | 538 | nla_nest_end(skb, nest_parms); |
539 | 539 | ||
540 | return 0; | 540 | return 0; |
541 | 541 | ||
542 | nla_put_failure: | 542 | nla_put_failure: |
543 | spin_unlock_bh(&ct->lock); | 543 | spin_unlock_bh(&ct->lock); |
544 | return -1; | 544 | return -1; |
545 | } | 545 | } |
546 | 546 | ||
547 | static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { | 547 | static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = { |
548 | [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 }, | 548 | [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 }, |
549 | [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 }, | 549 | [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 }, |
550 | [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 }, | 550 | [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 }, |
551 | }; | 551 | }; |
552 | 552 | ||
553 | #define SCTP_NLATTR_SIZE ( \ | 553 | #define SCTP_NLATTR_SIZE ( \ |
554 | NLA_ALIGN(NLA_HDRLEN + 1) + \ | 554 | NLA_ALIGN(NLA_HDRLEN + 1) + \ |
555 | NLA_ALIGN(NLA_HDRLEN + 4) + \ | 555 | NLA_ALIGN(NLA_HDRLEN + 4) + \ |
556 | NLA_ALIGN(NLA_HDRLEN + 4)) | 556 | NLA_ALIGN(NLA_HDRLEN + 4)) |
557 | 557 | ||
558 | static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) | 558 | static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) |
559 | { | 559 | { |
560 | struct nlattr *attr = cda[CTA_PROTOINFO_SCTP]; | 560 | struct nlattr *attr = cda[CTA_PROTOINFO_SCTP]; |
561 | struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1]; | 561 | struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1]; |
562 | int err; | 562 | int err; |
563 | 563 | ||
564 | /* updates may not contain the internal protocol info, skip parsing */ | 564 | /* updates may not contain the internal protocol info, skip parsing */ |
565 | if (!attr) | 565 | if (!attr) |
566 | return 0; | 566 | return 0; |
567 | 567 | ||
568 | err = nla_parse_nested(tb, CTA_PROTOINFO_SCTP_MAX, attr, | 568 | err = nla_parse_nested(tb, CTA_PROTOINFO_SCTP_MAX, attr, |
569 | sctp_nla_policy, NULL); | 569 | sctp_nla_policy, NULL); |
570 | if (err < 0) | 570 | if (err < 0) |
571 | return err; | 571 | return err; |
572 | 572 | ||
573 | if (!tb[CTA_PROTOINFO_SCTP_STATE] || | 573 | if (!tb[CTA_PROTOINFO_SCTP_STATE] || |
574 | !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] || | 574 | !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] || |
575 | !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) | 575 | !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]) |
576 | return -EINVAL; | 576 | return -EINVAL; |
577 | 577 | ||
578 | spin_lock_bh(&ct->lock); | 578 | spin_lock_bh(&ct->lock); |
579 | ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); | 579 | ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]); |
580 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = | 580 | ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = |
581 | nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]); | 581 | nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]); |
582 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = | 582 | ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = |
583 | nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]); | 583 | nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]); |
584 | spin_unlock_bh(&ct->lock); | 584 | spin_unlock_bh(&ct->lock); |
585 | 585 | ||
586 | return 0; | 586 | return 0; |
587 | } | 587 | } |
588 | #endif | 588 | #endif |
589 | 589 | ||
590 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 590 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
591 | 591 | ||
592 | #include <linux/netfilter/nfnetlink.h> | 592 | #include <linux/netfilter/nfnetlink.h> |
593 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 593 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
594 | 594 | ||
595 | static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], | 595 | static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], |
596 | struct net *net, void *data) | 596 | struct net *net, void *data) |
597 | { | 597 | { |
598 | unsigned int *timeouts = data; | 598 | unsigned int *timeouts = data; |
599 | struct nf_sctp_net *sn = sctp_pernet(net); | 599 | struct nf_sctp_net *sn = sctp_pernet(net); |
600 | int i; | 600 | int i; |
601 | 601 | ||
602 | /* set default SCTP timeouts. */ | 602 | /* set default SCTP timeouts. */ |
603 | for (i=0; i<SCTP_CONNTRACK_MAX; i++) | 603 | for (i=0; i<SCTP_CONNTRACK_MAX; i++) |
604 | timeouts[i] = sn->timeouts[i]; | 604 | timeouts[i] = sn->timeouts[i]; |
605 | 605 | ||
606 | /* there's a 1:1 mapping between attributes and protocol states. */ | 606 | /* there's a 1:1 mapping between attributes and protocol states. */ |
607 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { | 607 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { |
608 | if (tb[i]) { | 608 | if (tb[i]) { |
609 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; | 609 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; |
610 | } | 610 | } |
611 | } | 611 | } |
612 | 612 | ||
613 | timeouts[CTA_TIMEOUT_SCTP_UNSPEC] = timeouts[CTA_TIMEOUT_SCTP_CLOSED]; | 613 | timeouts[CTA_TIMEOUT_SCTP_UNSPEC] = timeouts[CTA_TIMEOUT_SCTP_CLOSED]; |
614 | return 0; | 614 | return 0; |
615 | } | 615 | } |
616 | 616 | ||
617 | static int | 617 | static int |
618 | sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 618 | sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
619 | { | 619 | { |
620 | const unsigned int *timeouts = data; | 620 | const unsigned int *timeouts = data; |
621 | int i; | 621 | int i; |
622 | 622 | ||
623 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { | 623 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { |
624 | if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ))) | 624 | if (nla_put_be32(skb, i, htonl(timeouts[i] / HZ))) |
625 | goto nla_put_failure; | 625 | goto nla_put_failure; |
626 | } | 626 | } |
627 | return 0; | 627 | return 0; |
628 | 628 | ||
629 | nla_put_failure: | 629 | nla_put_failure: |
630 | return -ENOSPC; | 630 | return -ENOSPC; |
631 | } | 631 | } |
632 | 632 | ||
633 | static const struct nla_policy | 633 | static const struct nla_policy |
634 | sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = { | 634 | sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = { |
635 | [CTA_TIMEOUT_SCTP_CLOSED] = { .type = NLA_U32 }, | 635 | [CTA_TIMEOUT_SCTP_CLOSED] = { .type = NLA_U32 }, |
636 | [CTA_TIMEOUT_SCTP_COOKIE_WAIT] = { .type = NLA_U32 }, | 636 | [CTA_TIMEOUT_SCTP_COOKIE_WAIT] = { .type = NLA_U32 }, |
637 | [CTA_TIMEOUT_SCTP_COOKIE_ECHOED] = { .type = NLA_U32 }, | 637 | [CTA_TIMEOUT_SCTP_COOKIE_ECHOED] = { .type = NLA_U32 }, |
638 | [CTA_TIMEOUT_SCTP_ESTABLISHED] = { .type = NLA_U32 }, | 638 | [CTA_TIMEOUT_SCTP_ESTABLISHED] = { .type = NLA_U32 }, |
639 | [CTA_TIMEOUT_SCTP_SHUTDOWN_SENT] = { .type = NLA_U32 }, | 639 | [CTA_TIMEOUT_SCTP_SHUTDOWN_SENT] = { .type = NLA_U32 }, |
640 | [CTA_TIMEOUT_SCTP_SHUTDOWN_RECD] = { .type = NLA_U32 }, | 640 | [CTA_TIMEOUT_SCTP_SHUTDOWN_RECD] = { .type = NLA_U32 }, |
641 | [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { .type = NLA_U32 }, | 641 | [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { .type = NLA_U32 }, |
642 | [CTA_TIMEOUT_SCTP_HEARTBEAT_SENT] = { .type = NLA_U32 }, | 642 | [CTA_TIMEOUT_SCTP_HEARTBEAT_SENT] = { .type = NLA_U32 }, |
643 | [CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED] = { .type = NLA_U32 }, | 643 | [CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED] = { .type = NLA_U32 }, |
644 | }; | 644 | }; |
645 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 645 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
646 | 646 | ||
647 | 647 | ||
648 | #ifdef CONFIG_SYSCTL | 648 | #ifdef CONFIG_SYSCTL |
649 | static struct ctl_table sctp_sysctl_table[] = { | 649 | static struct ctl_table sctp_sysctl_table[] = { |
650 | { | 650 | { |
651 | .procname = "nf_conntrack_sctp_timeout_closed", | 651 | .procname = "nf_conntrack_sctp_timeout_closed", |
652 | .maxlen = sizeof(unsigned int), | 652 | .maxlen = sizeof(unsigned int), |
653 | .mode = 0644, | 653 | .mode = 0644, |
654 | .proc_handler = proc_dointvec_jiffies, | 654 | .proc_handler = proc_dointvec_jiffies, |
655 | }, | 655 | }, |
656 | { | 656 | { |
657 | .procname = "nf_conntrack_sctp_timeout_cookie_wait", | 657 | .procname = "nf_conntrack_sctp_timeout_cookie_wait", |
658 | .maxlen = sizeof(unsigned int), | 658 | .maxlen = sizeof(unsigned int), |
659 | .mode = 0644, | 659 | .mode = 0644, |
660 | .proc_handler = proc_dointvec_jiffies, | 660 | .proc_handler = proc_dointvec_jiffies, |
661 | }, | 661 | }, |
662 | { | 662 | { |
663 | .procname = "nf_conntrack_sctp_timeout_cookie_echoed", | 663 | .procname = "nf_conntrack_sctp_timeout_cookie_echoed", |
664 | .maxlen = sizeof(unsigned int), | 664 | .maxlen = sizeof(unsigned int), |
665 | .mode = 0644, | 665 | .mode = 0644, |
666 | .proc_handler = proc_dointvec_jiffies, | 666 | .proc_handler = proc_dointvec_jiffies, |
667 | }, | 667 | }, |
668 | { | 668 | { |
669 | .procname = "nf_conntrack_sctp_timeout_established", | 669 | .procname = "nf_conntrack_sctp_timeout_established", |
670 | .maxlen = sizeof(unsigned int), | 670 | .maxlen = sizeof(unsigned int), |
671 | .mode = 0644, | 671 | .mode = 0644, |
672 | .proc_handler = proc_dointvec_jiffies, | 672 | .proc_handler = proc_dointvec_jiffies, |
673 | }, | 673 | }, |
674 | { | 674 | { |
675 | .procname = "nf_conntrack_sctp_timeout_shutdown_sent", | 675 | .procname = "nf_conntrack_sctp_timeout_shutdown_sent", |
676 | .maxlen = sizeof(unsigned int), | 676 | .maxlen = sizeof(unsigned int), |
677 | .mode = 0644, | 677 | .mode = 0644, |
678 | .proc_handler = proc_dointvec_jiffies, | 678 | .proc_handler = proc_dointvec_jiffies, |
679 | }, | 679 | }, |
680 | { | 680 | { |
681 | .procname = "nf_conntrack_sctp_timeout_shutdown_recd", | 681 | .procname = "nf_conntrack_sctp_timeout_shutdown_recd", |
682 | .maxlen = sizeof(unsigned int), | 682 | .maxlen = sizeof(unsigned int), |
683 | .mode = 0644, | 683 | .mode = 0644, |
684 | .proc_handler = proc_dointvec_jiffies, | 684 | .proc_handler = proc_dointvec_jiffies, |
685 | }, | 685 | }, |
686 | { | 686 | { |
687 | .procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent", | 687 | .procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent", |
688 | .maxlen = sizeof(unsigned int), | 688 | .maxlen = sizeof(unsigned int), |
689 | .mode = 0644, | 689 | .mode = 0644, |
690 | .proc_handler = proc_dointvec_jiffies, | 690 | .proc_handler = proc_dointvec_jiffies, |
691 | }, | 691 | }, |
692 | { | 692 | { |
693 | .procname = "nf_conntrack_sctp_timeout_heartbeat_sent", | 693 | .procname = "nf_conntrack_sctp_timeout_heartbeat_sent", |
694 | .maxlen = sizeof(unsigned int), | 694 | .maxlen = sizeof(unsigned int), |
695 | .mode = 0644, | 695 | .mode = 0644, |
696 | .proc_handler = proc_dointvec_jiffies, | 696 | .proc_handler = proc_dointvec_jiffies, |
697 | }, | 697 | }, |
698 | { | 698 | { |
699 | .procname = "nf_conntrack_sctp_timeout_heartbeat_acked", | 699 | .procname = "nf_conntrack_sctp_timeout_heartbeat_acked", |
700 | .maxlen = sizeof(unsigned int), | 700 | .maxlen = sizeof(unsigned int), |
701 | .mode = 0644, | 701 | .mode = 0644, |
702 | .proc_handler = proc_dointvec_jiffies, | 702 | .proc_handler = proc_dointvec_jiffies, |
703 | }, | 703 | }, |
704 | { } | 704 | { } |
705 | }; | 705 | }; |
706 | #endif | 706 | #endif |
707 | 707 | ||
708 | static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn, | 708 | static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn, |
709 | struct nf_sctp_net *sn) | 709 | struct nf_sctp_net *sn) |
710 | { | 710 | { |
711 | #ifdef CONFIG_SYSCTL | 711 | #ifdef CONFIG_SYSCTL |
712 | if (pn->ctl_table) | 712 | if (pn->ctl_table) |
713 | return 0; | 713 | return 0; |
714 | 714 | ||
715 | pn->ctl_table = kmemdup(sctp_sysctl_table, | 715 | pn->ctl_table = kmemdup(sctp_sysctl_table, |
716 | sizeof(sctp_sysctl_table), | 716 | sizeof(sctp_sysctl_table), |
717 | GFP_KERNEL); | 717 | GFP_KERNEL); |
718 | if (!pn->ctl_table) | 718 | if (!pn->ctl_table) |
719 | return -ENOMEM; | 719 | return -ENOMEM; |
720 | 720 | ||
721 | pn->ctl_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED]; | 721 | pn->ctl_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED]; |
722 | pn->ctl_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT]; | 722 | pn->ctl_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT]; |
723 | pn->ctl_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED]; | 723 | pn->ctl_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED]; |
724 | pn->ctl_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED]; | 724 | pn->ctl_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED]; |
725 | pn->ctl_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT]; | 725 | pn->ctl_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT]; |
726 | pn->ctl_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD]; | 726 | pn->ctl_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD]; |
727 | pn->ctl_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT]; | 727 | pn->ctl_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT]; |
728 | pn->ctl_table[7].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_SENT]; | 728 | pn->ctl_table[7].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_SENT]; |
729 | pn->ctl_table[8].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_ACKED]; | 729 | pn->ctl_table[8].data = &sn->timeouts[SCTP_CONNTRACK_HEARTBEAT_ACKED]; |
730 | #endif | 730 | #endif |
731 | return 0; | 731 | return 0; |
732 | } | 732 | } |
733 | 733 | ||
734 | static int sctp_init_net(struct net *net, u_int16_t proto) | 734 | static int sctp_init_net(struct net *net, u_int16_t proto) |
735 | { | 735 | { |
736 | struct nf_sctp_net *sn = sctp_pernet(net); | 736 | struct nf_sctp_net *sn = sctp_pernet(net); |
737 | struct nf_proto_net *pn = &sn->pn; | 737 | struct nf_proto_net *pn = &sn->pn; |
738 | 738 | ||
739 | if (!pn->users) { | 739 | if (!pn->users) { |
740 | int i; | 740 | int i; |
741 | 741 | ||
742 | for (i = 0; i < SCTP_CONNTRACK_MAX; i++) | 742 | for (i = 0; i < SCTP_CONNTRACK_MAX; i++) |
743 | sn->timeouts[i] = sctp_timeouts[i]; | 743 | sn->timeouts[i] = sctp_timeouts[i]; |
744 | 744 | ||
745 | /* timeouts[0] is unused, init it so ->timeouts[0] contains | 745 | /* timeouts[0] is unused, init it so ->timeouts[0] contains |
746 | * 'new' timeout, like udp or icmp. | 746 | * 'new' timeout, like udp or icmp. |
747 | */ | 747 | */ |
748 | sn->timeouts[0] = sctp_timeouts[SCTP_CONNTRACK_CLOSED]; | 748 | sn->timeouts[0] = sctp_timeouts[SCTP_CONNTRACK_CLOSED]; |
749 | } | 749 | } |
750 | 750 | ||
751 | return sctp_kmemdup_sysctl_table(pn, sn); | 751 | return sctp_kmemdup_sysctl_table(pn, sn); |
752 | } | 752 | } |
753 | 753 | ||
754 | static struct nf_proto_net *sctp_get_net_proto(struct net *net) | 754 | static struct nf_proto_net *sctp_get_net_proto(struct net *net) |
755 | { | 755 | { |
756 | return &net->ct.nf_ct_proto.sctp.pn; | 756 | return &net->ct.nf_ct_proto.sctp.pn; |
757 | } | 757 | } |
758 | 758 | ||
759 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = { | 759 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = { |
760 | .l3proto = PF_INET, | 760 | .l3proto = PF_INET, |
761 | .l4proto = IPPROTO_SCTP, | 761 | .l4proto = IPPROTO_SCTP, |
762 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 762 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
763 | .print_conntrack = sctp_print_conntrack, | 763 | .print_conntrack = sctp_print_conntrack, |
764 | #endif | 764 | #endif |
765 | .packet = sctp_packet, | 765 | .packet = sctp_packet, |
766 | .error = sctp_error, | 766 | .error = sctp_error, |
767 | .can_early_drop = sctp_can_early_drop, | 767 | .can_early_drop = sctp_can_early_drop, |
768 | .me = THIS_MODULE, | 768 | .me = THIS_MODULE, |
769 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 769 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
770 | .nlattr_size = SCTP_NLATTR_SIZE, | 770 | .nlattr_size = SCTP_NLATTR_SIZE, |
771 | .to_nlattr = sctp_to_nlattr, | 771 | .to_nlattr = sctp_to_nlattr, |
772 | .from_nlattr = nlattr_to_sctp, | 772 | .from_nlattr = nlattr_to_sctp, |
773 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 773 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
774 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 774 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
775 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 775 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
776 | .nla_policy = nf_ct_port_nla_policy, | 776 | .nla_policy = nf_ct_port_nla_policy, |
777 | #endif | 777 | #endif |
778 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 778 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
779 | .ctnl_timeout = { | 779 | .ctnl_timeout = { |
780 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, | 780 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, |
781 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, | 781 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, |
782 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, | 782 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, |
783 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, | 783 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, |
784 | .nla_policy = sctp_timeout_nla_policy, | 784 | .nla_policy = sctp_timeout_nla_policy, |
785 | }, | 785 | }, |
786 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 786 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
787 | .init_net = sctp_init_net, | 787 | .init_net = sctp_init_net, |
788 | .get_net_proto = sctp_get_net_proto, | 788 | .get_net_proto = sctp_get_net_proto, |
789 | }; | 789 | }; |
790 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp4); | 790 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp4); |
791 | 791 | ||
792 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = { | 792 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = { |
793 | .l3proto = PF_INET6, | 793 | .l3proto = PF_INET6, |
794 | .l4proto = IPPROTO_SCTP, | 794 | .l4proto = IPPROTO_SCTP, |
795 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 795 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
796 | .print_conntrack = sctp_print_conntrack, | 796 | .print_conntrack = sctp_print_conntrack, |
797 | #endif | 797 | #endif |
798 | .packet = sctp_packet, | 798 | .packet = sctp_packet, |
799 | .error = sctp_error, | 799 | .error = sctp_error, |
800 | .can_early_drop = sctp_can_early_drop, | 800 | .can_early_drop = sctp_can_early_drop, |
801 | .me = THIS_MODULE, | 801 | .me = THIS_MODULE, |
802 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 802 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
803 | .nlattr_size = SCTP_NLATTR_SIZE, | 803 | .nlattr_size = SCTP_NLATTR_SIZE, |
804 | .to_nlattr = sctp_to_nlattr, | 804 | .to_nlattr = sctp_to_nlattr, |
805 | .from_nlattr = nlattr_to_sctp, | 805 | .from_nlattr = nlattr_to_sctp, |
806 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 806 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
807 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 807 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
808 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 808 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
809 | .nla_policy = nf_ct_port_nla_policy, | 809 | .nla_policy = nf_ct_port_nla_policy, |
810 | #endif | 810 | #endif |
811 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 811 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
812 | .ctnl_timeout = { | 812 | .ctnl_timeout = { |
813 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, | 813 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, |
814 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, | 814 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, |
815 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, | 815 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, |
816 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, | 816 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, |
817 | .nla_policy = sctp_timeout_nla_policy, | 817 | .nla_policy = sctp_timeout_nla_policy, |
818 | }, | 818 | }, |
819 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 819 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
820 | .init_net = sctp_init_net, | 820 | .init_net = sctp_init_net, |
821 | .get_net_proto = sctp_get_net_proto, | 821 | .get_net_proto = sctp_get_net_proto, |
822 | }; | 822 | }; |
823 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp6); | 823 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_sctp6); |
824 | 824 |
net/netfilter/nf_conntrack_proto_tcp.c
1 | /* (C) 1999-2001 Paul `Rusty' Russell | 1 | /* (C) 1999-2001 Paul `Rusty' Russell |
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> |
3 | * (C) 2002-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 3 | * (C) 2002-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> |
4 | * (C) 2006-2012 Patrick McHardy <kaber@trash.net> | 4 | * (C) 2006-2012 Patrick McHardy <kaber@trash.net> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/timer.h> | 12 | #include <linux/timer.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/in.h> | 14 | #include <linux/in.h> |
15 | #include <linux/tcp.h> | 15 | #include <linux/tcp.h> |
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
18 | #include <linux/ipv6.h> | 18 | #include <linux/ipv6.h> |
19 | #include <net/ip6_checksum.h> | 19 | #include <net/ip6_checksum.h> |
20 | #include <asm/unaligned.h> | 20 | #include <asm/unaligned.h> |
21 | 21 | ||
22 | #include <net/tcp.h> | 22 | #include <net/tcp.h> |
23 | 23 | ||
24 | #include <linux/netfilter.h> | 24 | #include <linux/netfilter.h> |
25 | #include <linux/netfilter_ipv4.h> | 25 | #include <linux/netfilter_ipv4.h> |
26 | #include <linux/netfilter_ipv6.h> | 26 | #include <linux/netfilter_ipv6.h> |
27 | #include <net/netfilter/nf_conntrack.h> | 27 | #include <net/netfilter/nf_conntrack.h> |
28 | #include <net/netfilter/nf_conntrack_l4proto.h> | 28 | #include <net/netfilter/nf_conntrack_l4proto.h> |
29 | #include <net/netfilter/nf_conntrack_ecache.h> | 29 | #include <net/netfilter/nf_conntrack_ecache.h> |
30 | #include <net/netfilter/nf_conntrack_seqadj.h> | 30 | #include <net/netfilter/nf_conntrack_seqadj.h> |
31 | #include <net/netfilter/nf_conntrack_synproxy.h> | 31 | #include <net/netfilter/nf_conntrack_synproxy.h> |
32 | #include <net/netfilter/nf_conntrack_timeout.h> | 32 | #include <net/netfilter/nf_conntrack_timeout.h> |
33 | #include <net/netfilter/nf_log.h> | 33 | #include <net/netfilter/nf_log.h> |
34 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 34 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
35 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 35 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
36 | 36 | ||
37 | /* "Be conservative in what you do, | 37 | /* "Be conservative in what you do, |
38 | be liberal in what you accept from others." | 38 | be liberal in what you accept from others." |
39 | If it's non-zero, we mark only out of window RST segments as INVALID. */ | 39 | If it's non-zero, we mark only out of window RST segments as INVALID. */ |
40 | static int nf_ct_tcp_be_liberal __read_mostly = 0; | 40 | static int nf_ct_tcp_be_liberal __read_mostly = 0; |
41 | 41 | ||
42 | /* If it is set to zero, we disable picking up already established | 42 | /* If it is set to zero, we disable picking up already established |
43 | connections. */ | 43 | connections. */ |
44 | static int nf_ct_tcp_loose __read_mostly = 1; | 44 | static int nf_ct_tcp_loose __read_mostly = 1; |
45 | 45 | ||
46 | /* Max number of the retransmitted packets without receiving an (acceptable) | 46 | /* Max number of the retransmitted packets without receiving an (acceptable) |
47 | ACK from the destination. If this number is reached, a shorter timer | 47 | ACK from the destination. If this number is reached, a shorter timer |
48 | will be started. */ | 48 | will be started. */ |
49 | static int nf_ct_tcp_max_retrans __read_mostly = 3; | 49 | static int nf_ct_tcp_max_retrans __read_mostly = 3; |
50 | 50 | ||
51 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | 51 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more |
52 | closely. They're more complex. --RR */ | 52 | closely. They're more complex. --RR */ |
53 | 53 | ||
54 | static const char *const tcp_conntrack_names[] = { | 54 | static const char *const tcp_conntrack_names[] = { |
55 | "NONE", | 55 | "NONE", |
56 | "SYN_SENT", | 56 | "SYN_SENT", |
57 | "SYN_RECV", | 57 | "SYN_RECV", |
58 | "ESTABLISHED", | 58 | "ESTABLISHED", |
59 | "FIN_WAIT", | 59 | "FIN_WAIT", |
60 | "CLOSE_WAIT", | 60 | "CLOSE_WAIT", |
61 | "LAST_ACK", | 61 | "LAST_ACK", |
62 | "TIME_WAIT", | 62 | "TIME_WAIT", |
63 | "CLOSE", | 63 | "CLOSE", |
64 | "SYN_SENT2", | 64 | "SYN_SENT2", |
65 | }; | 65 | }; |
66 | 66 | ||
67 | #define SECS * HZ | 67 | #define SECS * HZ |
68 | #define MINS * 60 SECS | 68 | #define MINS * 60 SECS |
69 | #define HOURS * 60 MINS | 69 | #define HOURS * 60 MINS |
70 | #define DAYS * 24 HOURS | 70 | #define DAYS * 24 HOURS |
71 | 71 | ||
72 | static const unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] = { | 72 | static const unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] = { |
73 | [TCP_CONNTRACK_SYN_SENT] = 2 MINS, | 73 | [TCP_CONNTRACK_SYN_SENT] = 2 MINS, |
74 | [TCP_CONNTRACK_SYN_RECV] = 60 SECS, | 74 | [TCP_CONNTRACK_SYN_RECV] = 60 SECS, |
75 | [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, | 75 | [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, |
76 | [TCP_CONNTRACK_FIN_WAIT] = 2 MINS, | 76 | [TCP_CONNTRACK_FIN_WAIT] = 2 MINS, |
77 | [TCP_CONNTRACK_CLOSE_WAIT] = 60 SECS, | 77 | [TCP_CONNTRACK_CLOSE_WAIT] = 60 SECS, |
78 | [TCP_CONNTRACK_LAST_ACK] = 30 SECS, | 78 | [TCP_CONNTRACK_LAST_ACK] = 30 SECS, |
79 | [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, | 79 | [TCP_CONNTRACK_TIME_WAIT] = 2 MINS, |
80 | [TCP_CONNTRACK_CLOSE] = 10 SECS, | 80 | [TCP_CONNTRACK_CLOSE] = 10 SECS, |
81 | [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, | 81 | [TCP_CONNTRACK_SYN_SENT2] = 2 MINS, |
82 | /* RFC1122 says the R2 limit should be at least 100 seconds. | 82 | /* RFC1122 says the R2 limit should be at least 100 seconds. |
83 | Linux uses 15 packets as limit, which corresponds | 83 | Linux uses 15 packets as limit, which corresponds |
84 | to ~13-30min depending on RTO. */ | 84 | to ~13-30min depending on RTO. */ |
85 | [TCP_CONNTRACK_RETRANS] = 5 MINS, | 85 | [TCP_CONNTRACK_RETRANS] = 5 MINS, |
86 | [TCP_CONNTRACK_UNACK] = 5 MINS, | 86 | [TCP_CONNTRACK_UNACK] = 5 MINS, |
87 | }; | 87 | }; |
88 | 88 | ||
89 | #define sNO TCP_CONNTRACK_NONE | 89 | #define sNO TCP_CONNTRACK_NONE |
90 | #define sSS TCP_CONNTRACK_SYN_SENT | 90 | #define sSS TCP_CONNTRACK_SYN_SENT |
91 | #define sSR TCP_CONNTRACK_SYN_RECV | 91 | #define sSR TCP_CONNTRACK_SYN_RECV |
92 | #define sES TCP_CONNTRACK_ESTABLISHED | 92 | #define sES TCP_CONNTRACK_ESTABLISHED |
93 | #define sFW TCP_CONNTRACK_FIN_WAIT | 93 | #define sFW TCP_CONNTRACK_FIN_WAIT |
94 | #define sCW TCP_CONNTRACK_CLOSE_WAIT | 94 | #define sCW TCP_CONNTRACK_CLOSE_WAIT |
95 | #define sLA TCP_CONNTRACK_LAST_ACK | 95 | #define sLA TCP_CONNTRACK_LAST_ACK |
96 | #define sTW TCP_CONNTRACK_TIME_WAIT | 96 | #define sTW TCP_CONNTRACK_TIME_WAIT |
97 | #define sCL TCP_CONNTRACK_CLOSE | 97 | #define sCL TCP_CONNTRACK_CLOSE |
98 | #define sS2 TCP_CONNTRACK_SYN_SENT2 | 98 | #define sS2 TCP_CONNTRACK_SYN_SENT2 |
99 | #define sIV TCP_CONNTRACK_MAX | 99 | #define sIV TCP_CONNTRACK_MAX |
100 | #define sIG TCP_CONNTRACK_IGNORE | 100 | #define sIG TCP_CONNTRACK_IGNORE |
101 | 101 | ||
102 | /* What TCP flags are set from RST/SYN/FIN/ACK. */ | 102 | /* What TCP flags are set from RST/SYN/FIN/ACK. */ |
103 | enum tcp_bit_set { | 103 | enum tcp_bit_set { |
104 | TCP_SYN_SET, | 104 | TCP_SYN_SET, |
105 | TCP_SYNACK_SET, | 105 | TCP_SYNACK_SET, |
106 | TCP_FIN_SET, | 106 | TCP_FIN_SET, |
107 | TCP_ACK_SET, | 107 | TCP_ACK_SET, |
108 | TCP_RST_SET, | 108 | TCP_RST_SET, |
109 | TCP_NONE_SET, | 109 | TCP_NONE_SET, |
110 | }; | 110 | }; |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * The TCP state transition table needs a few words... | 113 | * The TCP state transition table needs a few words... |
114 | * | 114 | * |
115 | * We are the man in the middle. All the packets go through us | 115 | * We are the man in the middle. All the packets go through us |
116 | * but might get lost in transit to the destination. | 116 | * but might get lost in transit to the destination. |
117 | * It is assumed that the destinations can't receive segments | 117 | * It is assumed that the destinations can't receive segments |
118 | * we haven't seen. | 118 | * we haven't seen. |
119 | * | 119 | * |
120 | * The checked segment is in window, but our windows are *not* | 120 | * The checked segment is in window, but our windows are *not* |
121 | * equivalent with the ones of the sender/receiver. We always | 121 | * equivalent with the ones of the sender/receiver. We always |
122 | * try to guess the state of the current sender. | 122 | * try to guess the state of the current sender. |
123 | * | 123 | * |
124 | * The meaning of the states are: | 124 | * The meaning of the states are: |
125 | * | 125 | * |
126 | * NONE: initial state | 126 | * NONE: initial state |
127 | * SYN_SENT: SYN-only packet seen | 127 | * SYN_SENT: SYN-only packet seen |
128 | * SYN_SENT2: SYN-only packet seen from reply dir, simultaneous open | 128 | * SYN_SENT2: SYN-only packet seen from reply dir, simultaneous open |
129 | * SYN_RECV: SYN-ACK packet seen | 129 | * SYN_RECV: SYN-ACK packet seen |
130 | * ESTABLISHED: ACK packet seen | 130 | * ESTABLISHED: ACK packet seen |
131 | * FIN_WAIT: FIN packet seen | 131 | * FIN_WAIT: FIN packet seen |
132 | * CLOSE_WAIT: ACK seen (after FIN) | 132 | * CLOSE_WAIT: ACK seen (after FIN) |
133 | * LAST_ACK: FIN seen (after FIN) | 133 | * LAST_ACK: FIN seen (after FIN) |
134 | * TIME_WAIT: last ACK seen | 134 | * TIME_WAIT: last ACK seen |
135 | * CLOSE: closed connection (RST) | 135 | * CLOSE: closed connection (RST) |
136 | * | 136 | * |
137 | * Packets marked as IGNORED (sIG): | 137 | * Packets marked as IGNORED (sIG): |
138 | * if they may be either invalid or valid | 138 | * if they may be either invalid or valid |
139 | * and the receiver may send back a connection | 139 | * and the receiver may send back a connection |
140 | * closing RST or a SYN/ACK. | 140 | * closing RST or a SYN/ACK. |
141 | * | 141 | * |
142 | * Packets marked as INVALID (sIV): | 142 | * Packets marked as INVALID (sIV): |
143 | * if we regard them as truly invalid packets | 143 | * if we regard them as truly invalid packets |
144 | */ | 144 | */ |
145 | static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | 145 | static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { |
146 | { | 146 | { |
147 | /* ORIGINAL */ | 147 | /* ORIGINAL */ |
148 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 148 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
149 | /*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sS2 }, | 149 | /*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sS2 }, |
150 | /* | 150 | /* |
151 | * sNO -> sSS Initialize a new connection | 151 | * sNO -> sSS Initialize a new connection |
152 | * sSS -> sSS Retransmitted SYN | 152 | * sSS -> sSS Retransmitted SYN |
153 | * sS2 -> sS2 Late retransmitted SYN | 153 | * sS2 -> sS2 Late retransmitted SYN |
154 | * sSR -> sIG | 154 | * sSR -> sIG |
155 | * sES -> sIG Error: SYNs in window outside the SYN_SENT state | 155 | * sES -> sIG Error: SYNs in window outside the SYN_SENT state |
156 | * are errors. Receiver will reply with RST | 156 | * are errors. Receiver will reply with RST |
157 | * and close the connection. | 157 | * and close the connection. |
158 | * Or we are not in sync and hold a dead connection. | 158 | * Or we are not in sync and hold a dead connection. |
159 | * sFW -> sIG | 159 | * sFW -> sIG |
160 | * sCW -> sIG | 160 | * sCW -> sIG |
161 | * sLA -> sIG | 161 | * sLA -> sIG |
162 | * sTW -> sSS Reopened connection (RFC 1122). | 162 | * sTW -> sSS Reopened connection (RFC 1122). |
163 | * sCL -> sSS | 163 | * sCL -> sSS |
164 | */ | 164 | */ |
165 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 165 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
166 | /*synack*/ { sIV, sIV, sSR, sIV, sIV, sIV, sIV, sIV, sIV, sSR }, | 166 | /*synack*/ { sIV, sIV, sSR, sIV, sIV, sIV, sIV, sIV, sIV, sSR }, |
167 | /* | 167 | /* |
168 | * sNO -> sIV Too late and no reason to do anything | 168 | * sNO -> sIV Too late and no reason to do anything |
169 | * sSS -> sIV Client can't send SYN and then SYN/ACK | 169 | * sSS -> sIV Client can't send SYN and then SYN/ACK |
170 | * sS2 -> sSR SYN/ACK sent to SYN2 in simultaneous open | 170 | * sS2 -> sSR SYN/ACK sent to SYN2 in simultaneous open |
171 | * sSR -> sSR Late retransmitted SYN/ACK in simultaneous open | 171 | * sSR -> sSR Late retransmitted SYN/ACK in simultaneous open |
172 | * sES -> sIV Invalid SYN/ACK packets sent by the client | 172 | * sES -> sIV Invalid SYN/ACK packets sent by the client |
173 | * sFW -> sIV | 173 | * sFW -> sIV |
174 | * sCW -> sIV | 174 | * sCW -> sIV |
175 | * sLA -> sIV | 175 | * sLA -> sIV |
176 | * sTW -> sIV | 176 | * sTW -> sIV |
177 | * sCL -> sIV | 177 | * sCL -> sIV |
178 | */ | 178 | */ |
179 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 179 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
180 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, | 180 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, |
181 | /* | 181 | /* |
182 | * sNO -> sIV Too late and no reason to do anything... | 182 | * sNO -> sIV Too late and no reason to do anything... |
183 | * sSS -> sIV Client migth not send FIN in this state: | 183 | * sSS -> sIV Client migth not send FIN in this state: |
184 | * we enforce waiting for a SYN/ACK reply first. | 184 | * we enforce waiting for a SYN/ACK reply first. |
185 | * sS2 -> sIV | 185 | * sS2 -> sIV |
186 | * sSR -> sFW Close started. | 186 | * sSR -> sFW Close started. |
187 | * sES -> sFW | 187 | * sES -> sFW |
188 | * sFW -> sLA FIN seen in both directions, waiting for | 188 | * sFW -> sLA FIN seen in both directions, waiting for |
189 | * the last ACK. | 189 | * the last ACK. |
190 | * Migth be a retransmitted FIN as well... | 190 | * Migth be a retransmitted FIN as well... |
191 | * sCW -> sLA | 191 | * sCW -> sLA |
192 | * sLA -> sLA Retransmitted FIN. Remain in the same state. | 192 | * sLA -> sLA Retransmitted FIN. Remain in the same state. |
193 | * sTW -> sTW | 193 | * sTW -> sTW |
194 | * sCL -> sCL | 194 | * sCL -> sCL |
195 | */ | 195 | */ |
196 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 196 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
197 | /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | 197 | /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, |
198 | /* | 198 | /* |
199 | * sNO -> sES Assumed. | 199 | * sNO -> sES Assumed. |
200 | * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. | 200 | * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. |
201 | * sS2 -> sIV | 201 | * sS2 -> sIV |
202 | * sSR -> sES Established state is reached. | 202 | * sSR -> sES Established state is reached. |
203 | * sES -> sES :-) | 203 | * sES -> sES :-) |
204 | * sFW -> sCW Normal close request answered by ACK. | 204 | * sFW -> sCW Normal close request answered by ACK. |
205 | * sCW -> sCW | 205 | * sCW -> sCW |
206 | * sLA -> sTW Last ACK detected (RFC5961 challenged) | 206 | * sLA -> sTW Last ACK detected (RFC5961 challenged) |
207 | * sTW -> sTW Retransmitted last ACK. Remain in the same state. | 207 | * sTW -> sTW Retransmitted last ACK. Remain in the same state. |
208 | * sCL -> sCL | 208 | * sCL -> sCL |
209 | */ | 209 | */ |
210 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 210 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
211 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, | 211 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, |
212 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } | 212 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } |
213 | }, | 213 | }, |
214 | { | 214 | { |
215 | /* REPLY */ | 215 | /* REPLY */ |
216 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 216 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
217 | /*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sSS, sIV, sS2 }, | 217 | /*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sSS, sIV, sS2 }, |
218 | /* | 218 | /* |
219 | * sNO -> sIV Never reached. | 219 | * sNO -> sIV Never reached. |
220 | * sSS -> sS2 Simultaneous open | 220 | * sSS -> sS2 Simultaneous open |
221 | * sS2 -> sS2 Retransmitted simultaneous SYN | 221 | * sS2 -> sS2 Retransmitted simultaneous SYN |
222 | * sSR -> sIV Invalid SYN packets sent by the server | 222 | * sSR -> sIV Invalid SYN packets sent by the server |
223 | * sES -> sIV | 223 | * sES -> sIV |
224 | * sFW -> sIV | 224 | * sFW -> sIV |
225 | * sCW -> sIV | 225 | * sCW -> sIV |
226 | * sLA -> sIV | 226 | * sLA -> sIV |
227 | * sTW -> sSS Reopened connection, but server may have switched role | 227 | * sTW -> sSS Reopened connection, but server may have switched role |
228 | * sCL -> sIV | 228 | * sCL -> sIV |
229 | */ | 229 | */ |
230 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 230 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
231 | /*synack*/ { sIV, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, | 231 | /*synack*/ { sIV, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, |
232 | /* | 232 | /* |
233 | * sSS -> sSR Standard open. | 233 | * sSS -> sSR Standard open. |
234 | * sS2 -> sSR Simultaneous open | 234 | * sS2 -> sSR Simultaneous open |
235 | * sSR -> sIG Retransmitted SYN/ACK, ignore it. | 235 | * sSR -> sIG Retransmitted SYN/ACK, ignore it. |
236 | * sES -> sIG Late retransmitted SYN/ACK? | 236 | * sES -> sIG Late retransmitted SYN/ACK? |
237 | * sFW -> sIG Might be SYN/ACK answering ignored SYN | 237 | * sFW -> sIG Might be SYN/ACK answering ignored SYN |
238 | * sCW -> sIG | 238 | * sCW -> sIG |
239 | * sLA -> sIG | 239 | * sLA -> sIG |
240 | * sTW -> sIG | 240 | * sTW -> sIG |
241 | * sCL -> sIG | 241 | * sCL -> sIG |
242 | */ | 242 | */ |
243 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 243 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
244 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, | 244 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, |
245 | /* | 245 | /* |
246 | * sSS -> sIV Server might not send FIN in this state. | 246 | * sSS -> sIV Server might not send FIN in this state. |
247 | * sS2 -> sIV | 247 | * sS2 -> sIV |
248 | * sSR -> sFW Close started. | 248 | * sSR -> sFW Close started. |
249 | * sES -> sFW | 249 | * sES -> sFW |
250 | * sFW -> sLA FIN seen in both directions. | 250 | * sFW -> sLA FIN seen in both directions. |
251 | * sCW -> sLA | 251 | * sCW -> sLA |
252 | * sLA -> sLA Retransmitted FIN. | 252 | * sLA -> sLA Retransmitted FIN. |
253 | * sTW -> sTW | 253 | * sTW -> sTW |
254 | * sCL -> sCL | 254 | * sCL -> sCL |
255 | */ | 255 | */ |
256 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 256 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
257 | /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIG }, | 257 | /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIG }, |
258 | /* | 258 | /* |
259 | * sSS -> sIG Might be a half-open connection. | 259 | * sSS -> sIG Might be a half-open connection. |
260 | * sS2 -> sIG | 260 | * sS2 -> sIG |
261 | * sSR -> sSR Might answer late resent SYN. | 261 | * sSR -> sSR Might answer late resent SYN. |
262 | * sES -> sES :-) | 262 | * sES -> sES :-) |
263 | * sFW -> sCW Normal close request answered by ACK. | 263 | * sFW -> sCW Normal close request answered by ACK. |
264 | * sCW -> sCW | 264 | * sCW -> sCW |
265 | * sLA -> sTW Last ACK detected (RFC5961 challenged) | 265 | * sLA -> sTW Last ACK detected (RFC5961 challenged) |
266 | * sTW -> sTW Retransmitted last ACK. | 266 | * sTW -> sTW Retransmitted last ACK. |
267 | * sCL -> sCL | 267 | * sCL -> sCL |
268 | */ | 268 | */ |
269 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ | 269 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sS2 */ |
270 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, | 270 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, |
271 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } | 271 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } |
272 | } | 272 | } |
273 | }; | 273 | }; |
274 | 274 | ||
275 | static inline struct nf_tcp_net *tcp_pernet(struct net *net) | 275 | static inline struct nf_tcp_net *tcp_pernet(struct net *net) |
276 | { | 276 | { |
277 | return &net->ct.nf_ct_proto.tcp; | 277 | return &net->ct.nf_ct_proto.tcp; |
278 | } | 278 | } |
279 | 279 | ||
280 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 280 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
281 | /* Print out the private part of the conntrack. */ | 281 | /* Print out the private part of the conntrack. */ |
282 | static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct) | 282 | static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct) |
283 | { | 283 | { |
284 | if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) | 284 | if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) |
285 | return; | 285 | return; |
286 | 286 | ||
287 | seq_printf(s, "%s ", tcp_conntrack_names[ct->proto.tcp.state]); | 287 | seq_printf(s, "%s ", tcp_conntrack_names[ct->proto.tcp.state]); |
288 | } | 288 | } |
289 | #endif | 289 | #endif |
290 | 290 | ||
291 | static unsigned int get_conntrack_index(const struct tcphdr *tcph) | 291 | static unsigned int get_conntrack_index(const struct tcphdr *tcph) |
292 | { | 292 | { |
293 | if (tcph->rst) return TCP_RST_SET; | 293 | if (tcph->rst) return TCP_RST_SET; |
294 | else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET); | 294 | else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET); |
295 | else if (tcph->fin) return TCP_FIN_SET; | 295 | else if (tcph->fin) return TCP_FIN_SET; |
296 | else if (tcph->ack) return TCP_ACK_SET; | 296 | else if (tcph->ack) return TCP_ACK_SET; |
297 | else return TCP_NONE_SET; | 297 | else return TCP_NONE_SET; |
298 | } | 298 | } |
299 | 299 | ||
300 | /* TCP connection tracking based on 'Real Stateful TCP Packet Filtering | 300 | /* TCP connection tracking based on 'Real Stateful TCP Packet Filtering |
301 | in IP Filter' by Guido van Rooij. | 301 | in IP Filter' by Guido van Rooij. |
302 | 302 | ||
303 | http://www.sane.nl/events/sane2000/papers.html | 303 | http://www.sane.nl/events/sane2000/papers.html |
304 | http://www.darkart.com/mirrors/www.obfuscation.org/ipf/ | 304 | http://www.darkart.com/mirrors/www.obfuscation.org/ipf/ |
305 | 305 | ||
306 | The boundaries and the conditions are changed according to RFC793: | 306 | The boundaries and the conditions are changed according to RFC793: |
307 | the packet must intersect the window (i.e. segments may be | 307 | the packet must intersect the window (i.e. segments may be |
308 | after the right or before the left edge) and thus receivers may ACK | 308 | after the right or before the left edge) and thus receivers may ACK |
309 | segments after the right edge of the window. | 309 | segments after the right edge of the window. |
310 | 310 | ||
311 | td_maxend = max(sack + max(win,1)) seen in reply packets | 311 | td_maxend = max(sack + max(win,1)) seen in reply packets |
312 | td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets | 312 | td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets |
313 | td_maxwin += seq + len - sender.td_maxend | 313 | td_maxwin += seq + len - sender.td_maxend |
314 | if seq + len > sender.td_maxend | 314 | if seq + len > sender.td_maxend |
315 | td_end = max(seq + len) seen in sent packets | 315 | td_end = max(seq + len) seen in sent packets |
316 | 316 | ||
317 | I. Upper bound for valid data: seq <= sender.td_maxend | 317 | I. Upper bound for valid data: seq <= sender.td_maxend |
318 | II. Lower bound for valid data: seq + len >= sender.td_end - receiver.td_maxwin | 318 | II. Lower bound for valid data: seq + len >= sender.td_end - receiver.td_maxwin |
319 | III. Upper bound for valid (s)ack: sack <= receiver.td_end | 319 | III. Upper bound for valid (s)ack: sack <= receiver.td_end |
320 | IV. Lower bound for valid (s)ack: sack >= receiver.td_end - MAXACKWINDOW | 320 | IV. Lower bound for valid (s)ack: sack >= receiver.td_end - MAXACKWINDOW |
321 | 321 | ||
322 | where sack is the highest right edge of sack block found in the packet | 322 | where sack is the highest right edge of sack block found in the packet |
323 | or ack in the case of packet without SACK option. | 323 | or ack in the case of packet without SACK option. |
324 | 324 | ||
325 | The upper bound limit for a valid (s)ack is not ignored - | 325 | The upper bound limit for a valid (s)ack is not ignored - |
326 | we doesn't have to deal with fragments. | 326 | we doesn't have to deal with fragments. |
327 | */ | 327 | */ |
328 | 328 | ||
329 | static inline __u32 segment_seq_plus_len(__u32 seq, | 329 | static inline __u32 segment_seq_plus_len(__u32 seq, |
330 | size_t len, | 330 | size_t len, |
331 | unsigned int dataoff, | 331 | unsigned int dataoff, |
332 | const struct tcphdr *tcph) | 332 | const struct tcphdr *tcph) |
333 | { | 333 | { |
334 | /* XXX Should I use payload length field in IP/IPv6 header ? | 334 | /* XXX Should I use payload length field in IP/IPv6 header ? |
335 | * - YK */ | 335 | * - YK */ |
336 | return (seq + len - dataoff - tcph->doff*4 | 336 | return (seq + len - dataoff - tcph->doff*4 |
337 | + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0)); | 337 | + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0)); |
338 | } | 338 | } |
339 | 339 | ||
340 | /* Fixme: what about big packets? */ | 340 | /* Fixme: what about big packets? */ |
341 | #define MAXACKWINCONST 66000 | 341 | #define MAXACKWINCONST 66000 |
342 | #define MAXACKWINDOW(sender) \ | 342 | #define MAXACKWINDOW(sender) \ |
343 | ((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \ | 343 | ((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \ |
344 | : MAXACKWINCONST) | 344 | : MAXACKWINCONST) |
345 | 345 | ||
346 | /* | 346 | /* |
347 | * Simplified tcp_parse_options routine from tcp_input.c | 347 | * Simplified tcp_parse_options routine from tcp_input.c |
348 | */ | 348 | */ |
349 | static void tcp_options(const struct sk_buff *skb, | 349 | static void tcp_options(const struct sk_buff *skb, |
350 | unsigned int dataoff, | 350 | unsigned int dataoff, |
351 | const struct tcphdr *tcph, | 351 | const struct tcphdr *tcph, |
352 | struct ip_ct_tcp_state *state) | 352 | struct ip_ct_tcp_state *state) |
353 | { | 353 | { |
354 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; | 354 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; |
355 | const unsigned char *ptr; | 355 | const unsigned char *ptr; |
356 | int length = (tcph->doff*4) - sizeof(struct tcphdr); | 356 | int length = (tcph->doff*4) - sizeof(struct tcphdr); |
357 | 357 | ||
358 | if (!length) | 358 | if (!length) |
359 | return; | 359 | return; |
360 | 360 | ||
361 | ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr), | 361 | ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr), |
362 | length, buff); | 362 | length, buff); |
363 | BUG_ON(ptr == NULL); | 363 | BUG_ON(ptr == NULL); |
364 | 364 | ||
365 | state->td_scale = | 365 | state->td_scale = |
366 | state->flags = 0; | 366 | state->flags = 0; |
367 | 367 | ||
368 | while (length > 0) { | 368 | while (length > 0) { |
369 | int opcode=*ptr++; | 369 | int opcode=*ptr++; |
370 | int opsize; | 370 | int opsize; |
371 | 371 | ||
372 | switch (opcode) { | 372 | switch (opcode) { |
373 | case TCPOPT_EOL: | 373 | case TCPOPT_EOL: |
374 | return; | 374 | return; |
375 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ | 375 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ |
376 | length--; | 376 | length--; |
377 | continue; | 377 | continue; |
378 | default: | 378 | default: |
379 | if (length < 2) | 379 | if (length < 2) |
380 | return; | 380 | return; |
381 | opsize=*ptr++; | 381 | opsize=*ptr++; |
382 | if (opsize < 2) /* "silly options" */ | 382 | if (opsize < 2) /* "silly options" */ |
383 | return; | 383 | return; |
384 | if (opsize > length) | 384 | if (opsize > length) |
385 | return; /* don't parse partial options */ | 385 | return; /* don't parse partial options */ |
386 | 386 | ||
387 | if (opcode == TCPOPT_SACK_PERM | 387 | if (opcode == TCPOPT_SACK_PERM |
388 | && opsize == TCPOLEN_SACK_PERM) | 388 | && opsize == TCPOLEN_SACK_PERM) |
389 | state->flags |= IP_CT_TCP_FLAG_SACK_PERM; | 389 | state->flags |= IP_CT_TCP_FLAG_SACK_PERM; |
390 | else if (opcode == TCPOPT_WINDOW | 390 | else if (opcode == TCPOPT_WINDOW |
391 | && opsize == TCPOLEN_WINDOW) { | 391 | && opsize == TCPOLEN_WINDOW) { |
392 | state->td_scale = *(u_int8_t *)ptr; | 392 | state->td_scale = *(u_int8_t *)ptr; |
393 | 393 | ||
394 | if (state->td_scale > TCP_MAX_WSCALE) | 394 | if (state->td_scale > TCP_MAX_WSCALE) |
395 | state->td_scale = TCP_MAX_WSCALE; | 395 | state->td_scale = TCP_MAX_WSCALE; |
396 | 396 | ||
397 | state->flags |= | 397 | state->flags |= |
398 | IP_CT_TCP_FLAG_WINDOW_SCALE; | 398 | IP_CT_TCP_FLAG_WINDOW_SCALE; |
399 | } | 399 | } |
400 | ptr += opsize - 2; | 400 | ptr += opsize - 2; |
401 | length -= opsize; | 401 | length -= opsize; |
402 | } | 402 | } |
403 | } | 403 | } |
404 | } | 404 | } |
405 | 405 | ||
406 | static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, | 406 | static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, |
407 | const struct tcphdr *tcph, __u32 *sack) | 407 | const struct tcphdr *tcph, __u32 *sack) |
408 | { | 408 | { |
409 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; | 409 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; |
410 | const unsigned char *ptr; | 410 | const unsigned char *ptr; |
411 | int length = (tcph->doff*4) - sizeof(struct tcphdr); | 411 | int length = (tcph->doff*4) - sizeof(struct tcphdr); |
412 | __u32 tmp; | 412 | __u32 tmp; |
413 | 413 | ||
414 | if (!length) | 414 | if (!length) |
415 | return; | 415 | return; |
416 | 416 | ||
417 | ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr), | 417 | ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr), |
418 | length, buff); | 418 | length, buff); |
419 | BUG_ON(ptr == NULL); | 419 | BUG_ON(ptr == NULL); |
420 | 420 | ||
421 | /* Fast path for timestamp-only option */ | 421 | /* Fast path for timestamp-only option */ |
422 | if (length == TCPOLEN_TSTAMP_ALIGNED | 422 | if (length == TCPOLEN_TSTAMP_ALIGNED |
423 | && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24) | 423 | && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24) |
424 | | (TCPOPT_NOP << 16) | 424 | | (TCPOPT_NOP << 16) |
425 | | (TCPOPT_TIMESTAMP << 8) | 425 | | (TCPOPT_TIMESTAMP << 8) |
426 | | TCPOLEN_TIMESTAMP)) | 426 | | TCPOLEN_TIMESTAMP)) |
427 | return; | 427 | return; |
428 | 428 | ||
429 | while (length > 0) { | 429 | while (length > 0) { |
430 | int opcode = *ptr++; | 430 | int opcode = *ptr++; |
431 | int opsize, i; | 431 | int opsize, i; |
432 | 432 | ||
433 | switch (opcode) { | 433 | switch (opcode) { |
434 | case TCPOPT_EOL: | 434 | case TCPOPT_EOL: |
435 | return; | 435 | return; |
436 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ | 436 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ |
437 | length--; | 437 | length--; |
438 | continue; | 438 | continue; |
439 | default: | 439 | default: |
440 | if (length < 2) | 440 | if (length < 2) |
441 | return; | 441 | return; |
442 | opsize = *ptr++; | 442 | opsize = *ptr++; |
443 | if (opsize < 2) /* "silly options" */ | 443 | if (opsize < 2) /* "silly options" */ |
444 | return; | 444 | return; |
445 | if (opsize > length) | 445 | if (opsize > length) |
446 | return; /* don't parse partial options */ | 446 | return; /* don't parse partial options */ |
447 | 447 | ||
448 | if (opcode == TCPOPT_SACK | 448 | if (opcode == TCPOPT_SACK |
449 | && opsize >= (TCPOLEN_SACK_BASE | 449 | && opsize >= (TCPOLEN_SACK_BASE |
450 | + TCPOLEN_SACK_PERBLOCK) | 450 | + TCPOLEN_SACK_PERBLOCK) |
451 | && !((opsize - TCPOLEN_SACK_BASE) | 451 | && !((opsize - TCPOLEN_SACK_BASE) |
452 | % TCPOLEN_SACK_PERBLOCK)) { | 452 | % TCPOLEN_SACK_PERBLOCK)) { |
453 | for (i = 0; | 453 | for (i = 0; |
454 | i < (opsize - TCPOLEN_SACK_BASE); | 454 | i < (opsize - TCPOLEN_SACK_BASE); |
455 | i += TCPOLEN_SACK_PERBLOCK) { | 455 | i += TCPOLEN_SACK_PERBLOCK) { |
456 | tmp = get_unaligned_be32((__be32 *)(ptr+i)+1); | 456 | tmp = get_unaligned_be32((__be32 *)(ptr+i)+1); |
457 | 457 | ||
458 | if (after(tmp, *sack)) | 458 | if (after(tmp, *sack)) |
459 | *sack = tmp; | 459 | *sack = tmp; |
460 | } | 460 | } |
461 | return; | 461 | return; |
462 | } | 462 | } |
463 | ptr += opsize - 2; | 463 | ptr += opsize - 2; |
464 | length -= opsize; | 464 | length -= opsize; |
465 | } | 465 | } |
466 | } | 466 | } |
467 | } | 467 | } |
468 | 468 | ||
469 | static bool tcp_in_window(const struct nf_conn *ct, | 469 | static bool tcp_in_window(const struct nf_conn *ct, |
470 | struct ip_ct_tcp *state, | 470 | struct ip_ct_tcp *state, |
471 | enum ip_conntrack_dir dir, | 471 | enum ip_conntrack_dir dir, |
472 | unsigned int index, | 472 | unsigned int index, |
473 | const struct sk_buff *skb, | 473 | const struct sk_buff *skb, |
474 | unsigned int dataoff, | 474 | unsigned int dataoff, |
475 | const struct tcphdr *tcph) | 475 | const struct tcphdr *tcph) |
476 | { | 476 | { |
477 | struct net *net = nf_ct_net(ct); | 477 | struct net *net = nf_ct_net(ct); |
478 | struct nf_tcp_net *tn = tcp_pernet(net); | 478 | struct nf_tcp_net *tn = tcp_pernet(net); |
479 | struct ip_ct_tcp_state *sender = &state->seen[dir]; | 479 | struct ip_ct_tcp_state *sender = &state->seen[dir]; |
480 | struct ip_ct_tcp_state *receiver = &state->seen[!dir]; | 480 | struct ip_ct_tcp_state *receiver = &state->seen[!dir]; |
481 | const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; | 481 | const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; |
482 | __u32 seq, ack, sack, end, win, swin; | 482 | __u32 seq, ack, sack, end, win, swin; |
483 | s32 receiver_offset; | 483 | s32 receiver_offset; |
484 | bool res, in_recv_win; | 484 | bool res, in_recv_win; |
485 | 485 | ||
486 | /* | 486 | /* |
487 | * Get the required data from the packet. | 487 | * Get the required data from the packet. |
488 | */ | 488 | */ |
489 | seq = ntohl(tcph->seq); | 489 | seq = ntohl(tcph->seq); |
490 | ack = sack = ntohl(tcph->ack_seq); | 490 | ack = sack = ntohl(tcph->ack_seq); |
491 | win = ntohs(tcph->window); | 491 | win = ntohs(tcph->window); |
492 | end = segment_seq_plus_len(seq, skb->len, dataoff, tcph); | 492 | end = segment_seq_plus_len(seq, skb->len, dataoff, tcph); |
493 | 493 | ||
494 | if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) | 494 | if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) |
495 | tcp_sack(skb, dataoff, tcph, &sack); | 495 | tcp_sack(skb, dataoff, tcph, &sack); |
496 | 496 | ||
497 | /* Take into account NAT sequence number mangling */ | 497 | /* Take into account NAT sequence number mangling */ |
498 | receiver_offset = nf_ct_seq_offset(ct, !dir, ack - 1); | 498 | receiver_offset = nf_ct_seq_offset(ct, !dir, ack - 1); |
499 | ack -= receiver_offset; | 499 | ack -= receiver_offset; |
500 | sack -= receiver_offset; | 500 | sack -= receiver_offset; |
501 | 501 | ||
502 | pr_debug("tcp_in_window: START\n"); | 502 | pr_debug("tcp_in_window: START\n"); |
503 | pr_debug("tcp_in_window: "); | 503 | pr_debug("tcp_in_window: "); |
504 | nf_ct_dump_tuple(tuple); | 504 | nf_ct_dump_tuple(tuple); |
505 | pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", | 505 | pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", |
506 | seq, ack, receiver_offset, sack, receiver_offset, win, end); | 506 | seq, ack, receiver_offset, sack, receiver_offset, win, end); |
507 | pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " | 507 | pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " |
508 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | 508 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", |
509 | sender->td_end, sender->td_maxend, sender->td_maxwin, | 509 | sender->td_end, sender->td_maxend, sender->td_maxwin, |
510 | sender->td_scale, | 510 | sender->td_scale, |
511 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | 511 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, |
512 | receiver->td_scale); | 512 | receiver->td_scale); |
513 | 513 | ||
514 | if (sender->td_maxwin == 0) { | 514 | if (sender->td_maxwin == 0) { |
515 | /* | 515 | /* |
516 | * Initialize sender data. | 516 | * Initialize sender data. |
517 | */ | 517 | */ |
518 | if (tcph->syn) { | 518 | if (tcph->syn) { |
519 | /* | 519 | /* |
520 | * SYN-ACK in reply to a SYN | 520 | * SYN-ACK in reply to a SYN |
521 | * or SYN from reply direction in simultaneous open. | 521 | * or SYN from reply direction in simultaneous open. |
522 | */ | 522 | */ |
523 | sender->td_end = | 523 | sender->td_end = |
524 | sender->td_maxend = end; | 524 | sender->td_maxend = end; |
525 | sender->td_maxwin = (win == 0 ? 1 : win); | 525 | sender->td_maxwin = (win == 0 ? 1 : win); |
526 | 526 | ||
527 | tcp_options(skb, dataoff, tcph, sender); | 527 | tcp_options(skb, dataoff, tcph, sender); |
528 | /* | 528 | /* |
529 | * RFC 1323: | 529 | * RFC 1323: |
530 | * Both sides must send the Window Scale option | 530 | * Both sides must send the Window Scale option |
531 | * to enable window scaling in either direction. | 531 | * to enable window scaling in either direction. |
532 | */ | 532 | */ |
533 | if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE | 533 | if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE |
534 | && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) | 534 | && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) |
535 | sender->td_scale = | 535 | sender->td_scale = |
536 | receiver->td_scale = 0; | 536 | receiver->td_scale = 0; |
537 | if (!tcph->ack) | 537 | if (!tcph->ack) |
538 | /* Simultaneous open */ | 538 | /* Simultaneous open */ |
539 | return true; | 539 | return true; |
540 | } else { | 540 | } else { |
541 | /* | 541 | /* |
542 | * We are in the middle of a connection, | 542 | * We are in the middle of a connection, |
543 | * its history is lost for us. | 543 | * its history is lost for us. |
544 | * Let's try to use the data from the packet. | 544 | * Let's try to use the data from the packet. |
545 | */ | 545 | */ |
546 | sender->td_end = end; | 546 | sender->td_end = end; |
547 | swin = win << sender->td_scale; | 547 | swin = win << sender->td_scale; |
548 | sender->td_maxwin = (swin == 0 ? 1 : swin); | 548 | sender->td_maxwin = (swin == 0 ? 1 : swin); |
549 | sender->td_maxend = end + sender->td_maxwin; | 549 | sender->td_maxend = end + sender->td_maxwin; |
550 | /* | 550 | /* |
551 | * We haven't seen traffic in the other direction yet | 551 | * We haven't seen traffic in the other direction yet |
552 | * but we have to tweak window tracking to pass III | 552 | * but we have to tweak window tracking to pass III |
553 | * and IV until that happens. | 553 | * and IV until that happens. |
554 | */ | 554 | */ |
555 | if (receiver->td_maxwin == 0) | 555 | if (receiver->td_maxwin == 0) |
556 | receiver->td_end = receiver->td_maxend = sack; | 556 | receiver->td_end = receiver->td_maxend = sack; |
557 | } | 557 | } |
558 | } else if (((state->state == TCP_CONNTRACK_SYN_SENT | 558 | } else if (((state->state == TCP_CONNTRACK_SYN_SENT |
559 | && dir == IP_CT_DIR_ORIGINAL) | 559 | && dir == IP_CT_DIR_ORIGINAL) |
560 | || (state->state == TCP_CONNTRACK_SYN_RECV | 560 | || (state->state == TCP_CONNTRACK_SYN_RECV |
561 | && dir == IP_CT_DIR_REPLY)) | 561 | && dir == IP_CT_DIR_REPLY)) |
562 | && after(end, sender->td_end)) { | 562 | && after(end, sender->td_end)) { |
563 | /* | 563 | /* |
564 | * RFC 793: "if a TCP is reinitialized ... then it need | 564 | * RFC 793: "if a TCP is reinitialized ... then it need |
565 | * not wait at all; it must only be sure to use sequence | 565 | * not wait at all; it must only be sure to use sequence |
566 | * numbers larger than those recently used." | 566 | * numbers larger than those recently used." |
567 | */ | 567 | */ |
568 | sender->td_end = | 568 | sender->td_end = |
569 | sender->td_maxend = end; | 569 | sender->td_maxend = end; |
570 | sender->td_maxwin = (win == 0 ? 1 : win); | 570 | sender->td_maxwin = (win == 0 ? 1 : win); |
571 | 571 | ||
572 | tcp_options(skb, dataoff, tcph, sender); | 572 | tcp_options(skb, dataoff, tcph, sender); |
573 | } | 573 | } |
574 | 574 | ||
575 | if (!(tcph->ack)) { | 575 | if (!(tcph->ack)) { |
576 | /* | 576 | /* |
577 | * If there is no ACK, just pretend it was set and OK. | 577 | * If there is no ACK, just pretend it was set and OK. |
578 | */ | 578 | */ |
579 | ack = sack = receiver->td_end; | 579 | ack = sack = receiver->td_end; |
580 | } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == | 580 | } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == |
581 | (TCP_FLAG_ACK|TCP_FLAG_RST)) | 581 | (TCP_FLAG_ACK|TCP_FLAG_RST)) |
582 | && (ack == 0)) { | 582 | && (ack == 0)) { |
583 | /* | 583 | /* |
584 | * Broken TCP stacks, that set ACK in RST packets as well | 584 | * Broken TCP stacks, that set ACK in RST packets as well |
585 | * with zero ack value. | 585 | * with zero ack value. |
586 | */ | 586 | */ |
587 | ack = sack = receiver->td_end; | 587 | ack = sack = receiver->td_end; |
588 | } | 588 | } |
589 | 589 | ||
590 | if (tcph->rst && seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT) | 590 | if (tcph->rst && seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT) |
591 | /* | 591 | /* |
592 | * RST sent answering SYN. | 592 | * RST sent answering SYN. |
593 | */ | 593 | */ |
594 | seq = end = sender->td_end; | 594 | seq = end = sender->td_end; |
595 | 595 | ||
596 | pr_debug("tcp_in_window: "); | 596 | pr_debug("tcp_in_window: "); |
597 | nf_ct_dump_tuple(tuple); | 597 | nf_ct_dump_tuple(tuple); |
598 | pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", | 598 | pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", |
599 | seq, ack, receiver_offset, sack, receiver_offset, win, end); | 599 | seq, ack, receiver_offset, sack, receiver_offset, win, end); |
600 | pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " | 600 | pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " |
601 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | 601 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", |
602 | sender->td_end, sender->td_maxend, sender->td_maxwin, | 602 | sender->td_end, sender->td_maxend, sender->td_maxwin, |
603 | sender->td_scale, | 603 | sender->td_scale, |
604 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | 604 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, |
605 | receiver->td_scale); | 605 | receiver->td_scale); |
606 | 606 | ||
607 | /* Is the ending sequence in the receive window (if available)? */ | 607 | /* Is the ending sequence in the receive window (if available)? */ |
608 | in_recv_win = !receiver->td_maxwin || | 608 | in_recv_win = !receiver->td_maxwin || |
609 | after(end, sender->td_end - receiver->td_maxwin - 1); | 609 | after(end, sender->td_end - receiver->td_maxwin - 1); |
610 | 610 | ||
611 | pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", | 611 | pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", |
612 | before(seq, sender->td_maxend + 1), | 612 | before(seq, sender->td_maxend + 1), |
613 | (in_recv_win ? 1 : 0), | 613 | (in_recv_win ? 1 : 0), |
614 | before(sack, receiver->td_end + 1), | 614 | before(sack, receiver->td_end + 1), |
615 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); | 615 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); |
616 | 616 | ||
617 | if (before(seq, sender->td_maxend + 1) && | 617 | if (before(seq, sender->td_maxend + 1) && |
618 | in_recv_win && | 618 | in_recv_win && |
619 | before(sack, receiver->td_end + 1) && | 619 | before(sack, receiver->td_end + 1) && |
620 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { | 620 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { |
621 | /* | 621 | /* |
622 | * Take into account window scaling (RFC 1323). | 622 | * Take into account window scaling (RFC 1323). |
623 | */ | 623 | */ |
624 | if (!tcph->syn) | 624 | if (!tcph->syn) |
625 | win <<= sender->td_scale; | 625 | win <<= sender->td_scale; |
626 | 626 | ||
627 | /* | 627 | /* |
628 | * Update sender data. | 628 | * Update sender data. |
629 | */ | 629 | */ |
630 | swin = win + (sack - ack); | 630 | swin = win + (sack - ack); |
631 | if (sender->td_maxwin < swin) | 631 | if (sender->td_maxwin < swin) |
632 | sender->td_maxwin = swin; | 632 | sender->td_maxwin = swin; |
633 | if (after(end, sender->td_end)) { | 633 | if (after(end, sender->td_end)) { |
634 | sender->td_end = end; | 634 | sender->td_end = end; |
635 | sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; | 635 | sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; |
636 | } | 636 | } |
637 | if (tcph->ack) { | 637 | if (tcph->ack) { |
638 | if (!(sender->flags & IP_CT_TCP_FLAG_MAXACK_SET)) { | 638 | if (!(sender->flags & IP_CT_TCP_FLAG_MAXACK_SET)) { |
639 | sender->td_maxack = ack; | 639 | sender->td_maxack = ack; |
640 | sender->flags |= IP_CT_TCP_FLAG_MAXACK_SET; | 640 | sender->flags |= IP_CT_TCP_FLAG_MAXACK_SET; |
641 | } else if (after(ack, sender->td_maxack)) | 641 | } else if (after(ack, sender->td_maxack)) |
642 | sender->td_maxack = ack; | 642 | sender->td_maxack = ack; |
643 | } | 643 | } |
644 | 644 | ||
645 | /* | 645 | /* |
646 | * Update receiver data. | 646 | * Update receiver data. |
647 | */ | 647 | */ |
648 | if (receiver->td_maxwin != 0 && after(end, sender->td_maxend)) | 648 | if (receiver->td_maxwin != 0 && after(end, sender->td_maxend)) |
649 | receiver->td_maxwin += end - sender->td_maxend; | 649 | receiver->td_maxwin += end - sender->td_maxend; |
650 | if (after(sack + win, receiver->td_maxend - 1)) { | 650 | if (after(sack + win, receiver->td_maxend - 1)) { |
651 | receiver->td_maxend = sack + win; | 651 | receiver->td_maxend = sack + win; |
652 | if (win == 0) | 652 | if (win == 0) |
653 | receiver->td_maxend++; | 653 | receiver->td_maxend++; |
654 | } | 654 | } |
655 | if (ack == receiver->td_end) | 655 | if (ack == receiver->td_end) |
656 | receiver->flags &= ~IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; | 656 | receiver->flags &= ~IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; |
657 | 657 | ||
658 | /* | 658 | /* |
659 | * Check retransmissions. | 659 | * Check retransmissions. |
660 | */ | 660 | */ |
661 | if (index == TCP_ACK_SET) { | 661 | if (index == TCP_ACK_SET) { |
662 | if (state->last_dir == dir | 662 | if (state->last_dir == dir |
663 | && state->last_seq == seq | 663 | && state->last_seq == seq |
664 | && state->last_ack == ack | 664 | && state->last_ack == ack |
665 | && state->last_end == end | 665 | && state->last_end == end |
666 | && state->last_win == win) | 666 | && state->last_win == win) |
667 | state->retrans++; | 667 | state->retrans++; |
668 | else { | 668 | else { |
669 | state->last_dir = dir; | 669 | state->last_dir = dir; |
670 | state->last_seq = seq; | 670 | state->last_seq = seq; |
671 | state->last_ack = ack; | 671 | state->last_ack = ack; |
672 | state->last_end = end; | 672 | state->last_end = end; |
673 | state->last_win = win; | 673 | state->last_win = win; |
674 | state->retrans = 0; | 674 | state->retrans = 0; |
675 | } | 675 | } |
676 | } | 676 | } |
677 | res = true; | 677 | res = true; |
678 | } else { | 678 | } else { |
679 | res = false; | 679 | res = false; |
680 | if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || | 680 | if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || |
681 | tn->tcp_be_liberal) | 681 | tn->tcp_be_liberal) |
682 | res = true; | 682 | res = true; |
683 | if (!res) { | 683 | if (!res) { |
684 | nf_ct_l4proto_log_invalid(skb, ct, | 684 | nf_ct_l4proto_log_invalid(skb, ct, |
685 | "%s", | 685 | "%s", |
686 | before(seq, sender->td_maxend + 1) ? | 686 | before(seq, sender->td_maxend + 1) ? |
687 | in_recv_win ? | 687 | in_recv_win ? |
688 | before(sack, receiver->td_end + 1) ? | 688 | before(sack, receiver->td_end + 1) ? |
689 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" | 689 | after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" |
690 | : "ACK is under the lower bound (possible overly delayed ACK)" | 690 | : "ACK is under the lower bound (possible overly delayed ACK)" |
691 | : "ACK is over the upper bound (ACKed data not seen yet)" | 691 | : "ACK is over the upper bound (ACKed data not seen yet)" |
692 | : "SEQ is under the lower bound (already ACKed data retransmitted)" | 692 | : "SEQ is under the lower bound (already ACKed data retransmitted)" |
693 | : "SEQ is over the upper bound (over the window of the receiver)"); | 693 | : "SEQ is over the upper bound (over the window of the receiver)"); |
694 | } | 694 | } |
695 | } | 695 | } |
696 | 696 | ||
697 | pr_debug("tcp_in_window: res=%u sender end=%u maxend=%u maxwin=%u " | 697 | pr_debug("tcp_in_window: res=%u sender end=%u maxend=%u maxwin=%u " |
698 | "receiver end=%u maxend=%u maxwin=%u\n", | 698 | "receiver end=%u maxend=%u maxwin=%u\n", |
699 | res, sender->td_end, sender->td_maxend, sender->td_maxwin, | 699 | res, sender->td_end, sender->td_maxend, sender->td_maxwin, |
700 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin); | 700 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin); |
701 | 701 | ||
702 | return res; | 702 | return res; |
703 | } | 703 | } |
704 | 704 | ||
705 | /* table of valid flag combinations - PUSH, ECE and CWR are always valid */ | 705 | /* table of valid flag combinations - PUSH, ECE and CWR are always valid */ |
706 | static const u8 tcp_valid_flags[(TCPHDR_FIN|TCPHDR_SYN|TCPHDR_RST|TCPHDR_ACK| | 706 | static const u8 tcp_valid_flags[(TCPHDR_FIN|TCPHDR_SYN|TCPHDR_RST|TCPHDR_ACK| |
707 | TCPHDR_URG) + 1] = | 707 | TCPHDR_URG) + 1] = |
708 | { | 708 | { |
709 | [TCPHDR_SYN] = 1, | 709 | [TCPHDR_SYN] = 1, |
710 | [TCPHDR_SYN|TCPHDR_URG] = 1, | 710 | [TCPHDR_SYN|TCPHDR_URG] = 1, |
711 | [TCPHDR_SYN|TCPHDR_ACK] = 1, | 711 | [TCPHDR_SYN|TCPHDR_ACK] = 1, |
712 | [TCPHDR_RST] = 1, | 712 | [TCPHDR_RST] = 1, |
713 | [TCPHDR_RST|TCPHDR_ACK] = 1, | 713 | [TCPHDR_RST|TCPHDR_ACK] = 1, |
714 | [TCPHDR_FIN|TCPHDR_ACK] = 1, | 714 | [TCPHDR_FIN|TCPHDR_ACK] = 1, |
715 | [TCPHDR_FIN|TCPHDR_ACK|TCPHDR_URG] = 1, | 715 | [TCPHDR_FIN|TCPHDR_ACK|TCPHDR_URG] = 1, |
716 | [TCPHDR_ACK] = 1, | 716 | [TCPHDR_ACK] = 1, |
717 | [TCPHDR_ACK|TCPHDR_URG] = 1, | 717 | [TCPHDR_ACK|TCPHDR_URG] = 1, |
718 | }; | 718 | }; |
719 | 719 | ||
720 | static void tcp_error_log(const struct sk_buff *skb, | 720 | static void tcp_error_log(const struct sk_buff *skb, |
721 | const struct nf_hook_state *state, | 721 | const struct nf_hook_state *state, |
722 | const char *msg) | 722 | const char *msg) |
723 | { | 723 | { |
724 | nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_TCP, "%s", msg); | 724 | nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_TCP, "%s", msg); |
725 | } | 725 | } |
726 | 726 | ||
727 | /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ | 727 | /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ |
728 | static int tcp_error(struct nf_conn *tmpl, | 728 | static int tcp_error(struct nf_conn *tmpl, |
729 | struct sk_buff *skb, | 729 | struct sk_buff *skb, |
730 | unsigned int dataoff, | 730 | unsigned int dataoff, |
731 | const struct nf_hook_state *state) | 731 | const struct nf_hook_state *state) |
732 | { | 732 | { |
733 | const struct tcphdr *th; | 733 | const struct tcphdr *th; |
734 | struct tcphdr _tcph; | 734 | struct tcphdr _tcph; |
735 | unsigned int tcplen = skb->len - dataoff; | 735 | unsigned int tcplen = skb->len - dataoff; |
736 | u_int8_t tcpflags; | 736 | u_int8_t tcpflags; |
737 | 737 | ||
738 | /* Smaller that minimal TCP header? */ | 738 | /* Smaller that minimal TCP header? */ |
739 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); | 739 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); |
740 | if (th == NULL) { | 740 | if (th == NULL) { |
741 | tcp_error_log(skb, state, "short packet"); | 741 | tcp_error_log(skb, state, "short packet"); |
742 | return -NF_ACCEPT; | 742 | return -NF_ACCEPT; |
743 | } | 743 | } |
744 | 744 | ||
745 | /* Not whole TCP header or malformed packet */ | 745 | /* Not whole TCP header or malformed packet */ |
746 | if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { | 746 | if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { |
747 | tcp_error_log(skb, state, "truncated packet"); | 747 | tcp_error_log(skb, state, "truncated packet"); |
748 | return -NF_ACCEPT; | 748 | return -NF_ACCEPT; |
749 | } | 749 | } |
750 | 750 | ||
751 | /* Checksum invalid? Ignore. | 751 | /* Checksum invalid? Ignore. |
752 | * We skip checking packets on the outgoing path | 752 | * We skip checking packets on the outgoing path |
753 | * because the checksum is assumed to be correct. | 753 | * because the checksum is assumed to be correct. |
754 | */ | 754 | */ |
755 | /* FIXME: Source route IP option packets --RR */ | 755 | /* FIXME: Source route IP option packets --RR */ |
756 | if (state->net->ct.sysctl_checksum && | 756 | if (state->net->ct.sysctl_checksum && |
757 | state->hook == NF_INET_PRE_ROUTING && | 757 | state->hook == NF_INET_PRE_ROUTING && |
758 | nf_checksum(skb, state->hook, dataoff, IPPROTO_TCP, state->pf)) { | 758 | nf_checksum(skb, state->hook, dataoff, IPPROTO_TCP, state->pf)) { |
759 | tcp_error_log(skb, state, "bad checksum"); | 759 | tcp_error_log(skb, state, "bad checksum"); |
760 | return -NF_ACCEPT; | 760 | return -NF_ACCEPT; |
761 | } | 761 | } |
762 | 762 | ||
763 | /* Check TCP flags. */ | 763 | /* Check TCP flags. */ |
764 | tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH)); | 764 | tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH)); |
765 | if (!tcp_valid_flags[tcpflags]) { | 765 | if (!tcp_valid_flags[tcpflags]) { |
766 | tcp_error_log(skb, state, "invalid tcp flag combination"); | 766 | tcp_error_log(skb, state, "invalid tcp flag combination"); |
767 | return -NF_ACCEPT; | 767 | return -NF_ACCEPT; |
768 | } | 768 | } |
769 | 769 | ||
770 | return NF_ACCEPT; | 770 | return NF_ACCEPT; |
771 | } | 771 | } |
772 | 772 | ||
773 | static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, | 773 | static noinline bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, |
774 | unsigned int dataoff, | 774 | unsigned int dataoff, |
775 | const struct tcphdr *th) | 775 | const struct tcphdr *th) |
776 | { | 776 | { |
777 | enum tcp_conntrack new_state; | 777 | enum tcp_conntrack new_state; |
778 | struct net *net = nf_ct_net(ct); | 778 | struct net *net = nf_ct_net(ct); |
779 | const struct nf_tcp_net *tn = tcp_pernet(net); | 779 | const struct nf_tcp_net *tn = tcp_pernet(net); |
780 | const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0]; | 780 | const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0]; |
781 | const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1]; | 781 | const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1]; |
782 | 782 | ||
783 | /* Don't need lock here: this conntrack not in circulation yet */ | 783 | /* Don't need lock here: this conntrack not in circulation yet */ |
784 | new_state = tcp_conntracks[0][get_conntrack_index(th)][TCP_CONNTRACK_NONE]; | 784 | new_state = tcp_conntracks[0][get_conntrack_index(th)][TCP_CONNTRACK_NONE]; |
785 | 785 | ||
786 | /* Invalid: delete conntrack */ | 786 | /* Invalid: delete conntrack */ |
787 | if (new_state >= TCP_CONNTRACK_MAX) { | 787 | if (new_state >= TCP_CONNTRACK_MAX) { |
788 | pr_debug("nf_ct_tcp: invalid new deleting.\n"); | 788 | pr_debug("nf_ct_tcp: invalid new deleting.\n"); |
789 | return false; | 789 | return false; |
790 | } | 790 | } |
791 | 791 | ||
792 | if (new_state == TCP_CONNTRACK_SYN_SENT) { | 792 | if (new_state == TCP_CONNTRACK_SYN_SENT) { |
793 | memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); | 793 | memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); |
794 | /* SYN packet */ | 794 | /* SYN packet */ |
795 | ct->proto.tcp.seen[0].td_end = | 795 | ct->proto.tcp.seen[0].td_end = |
796 | segment_seq_plus_len(ntohl(th->seq), skb->len, | 796 | segment_seq_plus_len(ntohl(th->seq), skb->len, |
797 | dataoff, th); | 797 | dataoff, th); |
798 | ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); | 798 | ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); |
799 | if (ct->proto.tcp.seen[0].td_maxwin == 0) | 799 | if (ct->proto.tcp.seen[0].td_maxwin == 0) |
800 | ct->proto.tcp.seen[0].td_maxwin = 1; | 800 | ct->proto.tcp.seen[0].td_maxwin = 1; |
801 | ct->proto.tcp.seen[0].td_maxend = | 801 | ct->proto.tcp.seen[0].td_maxend = |
802 | ct->proto.tcp.seen[0].td_end; | 802 | ct->proto.tcp.seen[0].td_end; |
803 | 803 | ||
804 | tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]); | 804 | tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]); |
805 | } else if (tn->tcp_loose == 0) { | 805 | } else if (tn->tcp_loose == 0) { |
806 | /* Don't try to pick up connections. */ | 806 | /* Don't try to pick up connections. */ |
807 | return false; | 807 | return false; |
808 | } else { | 808 | } else { |
809 | memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); | 809 | memset(&ct->proto.tcp, 0, sizeof(ct->proto.tcp)); |
810 | /* | 810 | /* |
811 | * We are in the middle of a connection, | 811 | * We are in the middle of a connection, |
812 | * its history is lost for us. | 812 | * its history is lost for us. |
813 | * Let's try to use the data from the packet. | 813 | * Let's try to use the data from the packet. |
814 | */ | 814 | */ |
815 | ct->proto.tcp.seen[0].td_end = | 815 | ct->proto.tcp.seen[0].td_end = |
816 | segment_seq_plus_len(ntohl(th->seq), skb->len, | 816 | segment_seq_plus_len(ntohl(th->seq), skb->len, |
817 | dataoff, th); | 817 | dataoff, th); |
818 | ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); | 818 | ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window); |
819 | if (ct->proto.tcp.seen[0].td_maxwin == 0) | 819 | if (ct->proto.tcp.seen[0].td_maxwin == 0) |
820 | ct->proto.tcp.seen[0].td_maxwin = 1; | 820 | ct->proto.tcp.seen[0].td_maxwin = 1; |
821 | ct->proto.tcp.seen[0].td_maxend = | 821 | ct->proto.tcp.seen[0].td_maxend = |
822 | ct->proto.tcp.seen[0].td_end + | 822 | ct->proto.tcp.seen[0].td_end + |
823 | ct->proto.tcp.seen[0].td_maxwin; | 823 | ct->proto.tcp.seen[0].td_maxwin; |
824 | 824 | ||
825 | /* We assume SACK and liberal window checking to handle | 825 | /* We assume SACK and liberal window checking to handle |
826 | * window scaling */ | 826 | * window scaling */ |
827 | ct->proto.tcp.seen[0].flags = | 827 | ct->proto.tcp.seen[0].flags = |
828 | ct->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | | 828 | ct->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | |
829 | IP_CT_TCP_FLAG_BE_LIBERAL; | 829 | IP_CT_TCP_FLAG_BE_LIBERAL; |
830 | } | 830 | } |
831 | 831 | ||
832 | /* tcp_packet will set them */ | 832 | /* tcp_packet will set them */ |
833 | ct->proto.tcp.last_index = TCP_NONE_SET; | 833 | ct->proto.tcp.last_index = TCP_NONE_SET; |
834 | 834 | ||
835 | pr_debug("%s: sender end=%u maxend=%u maxwin=%u scale=%i " | 835 | pr_debug("%s: sender end=%u maxend=%u maxwin=%u scale=%i " |
836 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | 836 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", |
837 | __func__, | 837 | __func__, |
838 | sender->td_end, sender->td_maxend, sender->td_maxwin, | 838 | sender->td_end, sender->td_maxend, sender->td_maxwin, |
839 | sender->td_scale, | 839 | sender->td_scale, |
840 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | 840 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, |
841 | receiver->td_scale); | 841 | receiver->td_scale); |
842 | return true; | 842 | return true; |
843 | } | 843 | } |
844 | 844 | ||
845 | /* Returns verdict for packet, or -1 for invalid. */ | 845 | /* Returns verdict for packet, or -1 for invalid. */ |
846 | static int tcp_packet(struct nf_conn *ct, | 846 | static int tcp_packet(struct nf_conn *ct, |
847 | const struct sk_buff *skb, | 847 | struct sk_buff *skb, |
848 | unsigned int dataoff, | 848 | unsigned int dataoff, |
849 | enum ip_conntrack_info ctinfo, | 849 | enum ip_conntrack_info ctinfo, |
850 | const struct nf_hook_state *state) | 850 | const struct nf_hook_state *state) |
851 | { | 851 | { |
852 | struct net *net = nf_ct_net(ct); | 852 | struct net *net = nf_ct_net(ct); |
853 | struct nf_tcp_net *tn = tcp_pernet(net); | 853 | struct nf_tcp_net *tn = tcp_pernet(net); |
854 | struct nf_conntrack_tuple *tuple; | 854 | struct nf_conntrack_tuple *tuple; |
855 | enum tcp_conntrack new_state, old_state; | 855 | enum tcp_conntrack new_state, old_state; |
856 | unsigned int index, *timeouts; | 856 | unsigned int index, *timeouts; |
857 | enum ip_conntrack_dir dir; | 857 | enum ip_conntrack_dir dir; |
858 | const struct tcphdr *th; | 858 | const struct tcphdr *th; |
859 | struct tcphdr _tcph; | 859 | struct tcphdr _tcph; |
860 | unsigned long timeout; | 860 | unsigned long timeout; |
861 | 861 | ||
862 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); | 862 | th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); |
863 | if (th == NULL) | 863 | if (th == NULL) |
864 | return -NF_ACCEPT; | 864 | return -NF_ACCEPT; |
865 | 865 | ||
866 | if (!nf_ct_is_confirmed(ct) && !tcp_new(ct, skb, dataoff, th)) | 866 | if (!nf_ct_is_confirmed(ct) && !tcp_new(ct, skb, dataoff, th)) |
867 | return -NF_ACCEPT; | 867 | return -NF_ACCEPT; |
868 | 868 | ||
869 | spin_lock_bh(&ct->lock); | 869 | spin_lock_bh(&ct->lock); |
870 | old_state = ct->proto.tcp.state; | 870 | old_state = ct->proto.tcp.state; |
871 | dir = CTINFO2DIR(ctinfo); | 871 | dir = CTINFO2DIR(ctinfo); |
872 | index = get_conntrack_index(th); | 872 | index = get_conntrack_index(th); |
873 | new_state = tcp_conntracks[dir][index][old_state]; | 873 | new_state = tcp_conntracks[dir][index][old_state]; |
874 | tuple = &ct->tuplehash[dir].tuple; | 874 | tuple = &ct->tuplehash[dir].tuple; |
875 | 875 | ||
876 | switch (new_state) { | 876 | switch (new_state) { |
877 | case TCP_CONNTRACK_SYN_SENT: | 877 | case TCP_CONNTRACK_SYN_SENT: |
878 | if (old_state < TCP_CONNTRACK_TIME_WAIT) | 878 | if (old_state < TCP_CONNTRACK_TIME_WAIT) |
879 | break; | 879 | break; |
880 | /* RFC 1122: "When a connection is closed actively, | 880 | /* RFC 1122: "When a connection is closed actively, |
881 | * it MUST linger in TIME-WAIT state for a time 2xMSL | 881 | * it MUST linger in TIME-WAIT state for a time 2xMSL |
882 | * (Maximum Segment Lifetime). However, it MAY accept | 882 | * (Maximum Segment Lifetime). However, it MAY accept |
883 | * a new SYN from the remote TCP to reopen the connection | 883 | * a new SYN from the remote TCP to reopen the connection |
884 | * directly from TIME-WAIT state, if..." | 884 | * directly from TIME-WAIT state, if..." |
885 | * We ignore the conditions because we are in the | 885 | * We ignore the conditions because we are in the |
886 | * TIME-WAIT state anyway. | 886 | * TIME-WAIT state anyway. |
887 | * | 887 | * |
888 | * Handle aborted connections: we and the server | 888 | * Handle aborted connections: we and the server |
889 | * think there is an existing connection but the client | 889 | * think there is an existing connection but the client |
890 | * aborts it and starts a new one. | 890 | * aborts it and starts a new one. |
891 | */ | 891 | */ |
892 | if (((ct->proto.tcp.seen[dir].flags | 892 | if (((ct->proto.tcp.seen[dir].flags |
893 | | ct->proto.tcp.seen[!dir].flags) | 893 | | ct->proto.tcp.seen[!dir].flags) |
894 | & IP_CT_TCP_FLAG_CLOSE_INIT) | 894 | & IP_CT_TCP_FLAG_CLOSE_INIT) |
895 | || (ct->proto.tcp.last_dir == dir | 895 | || (ct->proto.tcp.last_dir == dir |
896 | && ct->proto.tcp.last_index == TCP_RST_SET)) { | 896 | && ct->proto.tcp.last_index == TCP_RST_SET)) { |
897 | /* Attempt to reopen a closed/aborted connection. | 897 | /* Attempt to reopen a closed/aborted connection. |
898 | * Delete this connection and look up again. */ | 898 | * Delete this connection and look up again. */ |
899 | spin_unlock_bh(&ct->lock); | 899 | spin_unlock_bh(&ct->lock); |
900 | 900 | ||
901 | /* Only repeat if we can actually remove the timer. | 901 | /* Only repeat if we can actually remove the timer. |
902 | * Destruction may already be in progress in process | 902 | * Destruction may already be in progress in process |
903 | * context and we must give it a chance to terminate. | 903 | * context and we must give it a chance to terminate. |
904 | */ | 904 | */ |
905 | if (nf_ct_kill(ct)) | 905 | if (nf_ct_kill(ct)) |
906 | return -NF_REPEAT; | 906 | return -NF_REPEAT; |
907 | return NF_DROP; | 907 | return NF_DROP; |
908 | } | 908 | } |
909 | /* Fall through */ | 909 | /* Fall through */ |
910 | case TCP_CONNTRACK_IGNORE: | 910 | case TCP_CONNTRACK_IGNORE: |
911 | /* Ignored packets: | 911 | /* Ignored packets: |
912 | * | 912 | * |
913 | * Our connection entry may be out of sync, so ignore | 913 | * Our connection entry may be out of sync, so ignore |
914 | * packets which may signal the real connection between | 914 | * packets which may signal the real connection between |
915 | * the client and the server. | 915 | * the client and the server. |
916 | * | 916 | * |
917 | * a) SYN in ORIGINAL | 917 | * a) SYN in ORIGINAL |
918 | * b) SYN/ACK in REPLY | 918 | * b) SYN/ACK in REPLY |
919 | * c) ACK in reply direction after initial SYN in original. | 919 | * c) ACK in reply direction after initial SYN in original. |
920 | * | 920 | * |
921 | * If the ignored packet is invalid, the receiver will send | 921 | * If the ignored packet is invalid, the receiver will send |
922 | * a RST we'll catch below. | 922 | * a RST we'll catch below. |
923 | */ | 923 | */ |
924 | if (index == TCP_SYNACK_SET | 924 | if (index == TCP_SYNACK_SET |
925 | && ct->proto.tcp.last_index == TCP_SYN_SET | 925 | && ct->proto.tcp.last_index == TCP_SYN_SET |
926 | && ct->proto.tcp.last_dir != dir | 926 | && ct->proto.tcp.last_dir != dir |
927 | && ntohl(th->ack_seq) == ct->proto.tcp.last_end) { | 927 | && ntohl(th->ack_seq) == ct->proto.tcp.last_end) { |
928 | /* b) This SYN/ACK acknowledges a SYN that we earlier | 928 | /* b) This SYN/ACK acknowledges a SYN that we earlier |
929 | * ignored as invalid. This means that the client and | 929 | * ignored as invalid. This means that the client and |
930 | * the server are both in sync, while the firewall is | 930 | * the server are both in sync, while the firewall is |
931 | * not. We get in sync from the previously annotated | 931 | * not. We get in sync from the previously annotated |
932 | * values. | 932 | * values. |
933 | */ | 933 | */ |
934 | old_state = TCP_CONNTRACK_SYN_SENT; | 934 | old_state = TCP_CONNTRACK_SYN_SENT; |
935 | new_state = TCP_CONNTRACK_SYN_RECV; | 935 | new_state = TCP_CONNTRACK_SYN_RECV; |
936 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_end = | 936 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_end = |
937 | ct->proto.tcp.last_end; | 937 | ct->proto.tcp.last_end; |
938 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxend = | 938 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxend = |
939 | ct->proto.tcp.last_end; | 939 | ct->proto.tcp.last_end; |
940 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxwin = | 940 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxwin = |
941 | ct->proto.tcp.last_win == 0 ? | 941 | ct->proto.tcp.last_win == 0 ? |
942 | 1 : ct->proto.tcp.last_win; | 942 | 1 : ct->proto.tcp.last_win; |
943 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale = | 943 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale = |
944 | ct->proto.tcp.last_wscale; | 944 | ct->proto.tcp.last_wscale; |
945 | ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; | 945 | ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; |
946 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = | 946 | ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags = |
947 | ct->proto.tcp.last_flags; | 947 | ct->proto.tcp.last_flags; |
948 | memset(&ct->proto.tcp.seen[dir], 0, | 948 | memset(&ct->proto.tcp.seen[dir], 0, |
949 | sizeof(struct ip_ct_tcp_state)); | 949 | sizeof(struct ip_ct_tcp_state)); |
950 | break; | 950 | break; |
951 | } | 951 | } |
952 | ct->proto.tcp.last_index = index; | 952 | ct->proto.tcp.last_index = index; |
953 | ct->proto.tcp.last_dir = dir; | 953 | ct->proto.tcp.last_dir = dir; |
954 | ct->proto.tcp.last_seq = ntohl(th->seq); | 954 | ct->proto.tcp.last_seq = ntohl(th->seq); |
955 | ct->proto.tcp.last_end = | 955 | ct->proto.tcp.last_end = |
956 | segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); | 956 | segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); |
957 | ct->proto.tcp.last_win = ntohs(th->window); | 957 | ct->proto.tcp.last_win = ntohs(th->window); |
958 | 958 | ||
959 | /* a) This is a SYN in ORIGINAL. The client and the server | 959 | /* a) This is a SYN in ORIGINAL. The client and the server |
960 | * may be in sync but we are not. In that case, we annotate | 960 | * may be in sync but we are not. In that case, we annotate |
961 | * the TCP options and let the packet go through. If it is a | 961 | * the TCP options and let the packet go through. If it is a |
962 | * valid SYN packet, the server will reply with a SYN/ACK, and | 962 | * valid SYN packet, the server will reply with a SYN/ACK, and |
963 | * then we'll get in sync. Otherwise, the server potentially | 963 | * then we'll get in sync. Otherwise, the server potentially |
964 | * responds with a challenge ACK if implementing RFC5961. | 964 | * responds with a challenge ACK if implementing RFC5961. |
965 | */ | 965 | */ |
966 | if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) { | 966 | if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) { |
967 | struct ip_ct_tcp_state seen = {}; | 967 | struct ip_ct_tcp_state seen = {}; |
968 | 968 | ||
969 | ct->proto.tcp.last_flags = | 969 | ct->proto.tcp.last_flags = |
970 | ct->proto.tcp.last_wscale = 0; | 970 | ct->proto.tcp.last_wscale = 0; |
971 | tcp_options(skb, dataoff, th, &seen); | 971 | tcp_options(skb, dataoff, th, &seen); |
972 | if (seen.flags & IP_CT_TCP_FLAG_WINDOW_SCALE) { | 972 | if (seen.flags & IP_CT_TCP_FLAG_WINDOW_SCALE) { |
973 | ct->proto.tcp.last_flags |= | 973 | ct->proto.tcp.last_flags |= |
974 | IP_CT_TCP_FLAG_WINDOW_SCALE; | 974 | IP_CT_TCP_FLAG_WINDOW_SCALE; |
975 | ct->proto.tcp.last_wscale = seen.td_scale; | 975 | ct->proto.tcp.last_wscale = seen.td_scale; |
976 | } | 976 | } |
977 | if (seen.flags & IP_CT_TCP_FLAG_SACK_PERM) { | 977 | if (seen.flags & IP_CT_TCP_FLAG_SACK_PERM) { |
978 | ct->proto.tcp.last_flags |= | 978 | ct->proto.tcp.last_flags |= |
979 | IP_CT_TCP_FLAG_SACK_PERM; | 979 | IP_CT_TCP_FLAG_SACK_PERM; |
980 | } | 980 | } |
981 | /* Mark the potential for RFC5961 challenge ACK, | 981 | /* Mark the potential for RFC5961 challenge ACK, |
982 | * this pose a special problem for LAST_ACK state | 982 | * this pose a special problem for LAST_ACK state |
983 | * as ACK is intrepretated as ACKing last FIN. | 983 | * as ACK is intrepretated as ACKing last FIN. |
984 | */ | 984 | */ |
985 | if (old_state == TCP_CONNTRACK_LAST_ACK) | 985 | if (old_state == TCP_CONNTRACK_LAST_ACK) |
986 | ct->proto.tcp.last_flags |= | 986 | ct->proto.tcp.last_flags |= |
987 | IP_CT_EXP_CHALLENGE_ACK; | 987 | IP_CT_EXP_CHALLENGE_ACK; |
988 | } | 988 | } |
989 | spin_unlock_bh(&ct->lock); | 989 | spin_unlock_bh(&ct->lock); |
990 | nf_ct_l4proto_log_invalid(skb, ct, "invalid packet ignored in " | 990 | nf_ct_l4proto_log_invalid(skb, ct, "invalid packet ignored in " |
991 | "state %s ", tcp_conntrack_names[old_state]); | 991 | "state %s ", tcp_conntrack_names[old_state]); |
992 | return NF_ACCEPT; | 992 | return NF_ACCEPT; |
993 | case TCP_CONNTRACK_MAX: | 993 | case TCP_CONNTRACK_MAX: |
994 | /* Special case for SYN proxy: when the SYN to the server or | 994 | /* Special case for SYN proxy: when the SYN to the server or |
995 | * the SYN/ACK from the server is lost, the client may transmit | 995 | * the SYN/ACK from the server is lost, the client may transmit |
996 | * a keep-alive packet while in SYN_SENT state. This needs to | 996 | * a keep-alive packet while in SYN_SENT state. This needs to |
997 | * be associated with the original conntrack entry in order to | 997 | * be associated with the original conntrack entry in order to |
998 | * generate a new SYN with the correct sequence number. | 998 | * generate a new SYN with the correct sequence number. |
999 | */ | 999 | */ |
1000 | if (nfct_synproxy(ct) && old_state == TCP_CONNTRACK_SYN_SENT && | 1000 | if (nfct_synproxy(ct) && old_state == TCP_CONNTRACK_SYN_SENT && |
1001 | index == TCP_ACK_SET && dir == IP_CT_DIR_ORIGINAL && | 1001 | index == TCP_ACK_SET && dir == IP_CT_DIR_ORIGINAL && |
1002 | ct->proto.tcp.last_dir == IP_CT_DIR_ORIGINAL && | 1002 | ct->proto.tcp.last_dir == IP_CT_DIR_ORIGINAL && |
1003 | ct->proto.tcp.seen[dir].td_end - 1 == ntohl(th->seq)) { | 1003 | ct->proto.tcp.seen[dir].td_end - 1 == ntohl(th->seq)) { |
1004 | pr_debug("nf_ct_tcp: SYN proxy client keep alive\n"); | 1004 | pr_debug("nf_ct_tcp: SYN proxy client keep alive\n"); |
1005 | spin_unlock_bh(&ct->lock); | 1005 | spin_unlock_bh(&ct->lock); |
1006 | return NF_ACCEPT; | 1006 | return NF_ACCEPT; |
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | /* Invalid packet */ | 1009 | /* Invalid packet */ |
1010 | pr_debug("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", | 1010 | pr_debug("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", |
1011 | dir, get_conntrack_index(th), old_state); | 1011 | dir, get_conntrack_index(th), old_state); |
1012 | spin_unlock_bh(&ct->lock); | 1012 | spin_unlock_bh(&ct->lock); |
1013 | nf_ct_l4proto_log_invalid(skb, ct, "invalid state"); | 1013 | nf_ct_l4proto_log_invalid(skb, ct, "invalid state"); |
1014 | return -NF_ACCEPT; | 1014 | return -NF_ACCEPT; |
1015 | case TCP_CONNTRACK_TIME_WAIT: | 1015 | case TCP_CONNTRACK_TIME_WAIT: |
1016 | /* RFC5961 compliance cause stack to send "challenge-ACK" | 1016 | /* RFC5961 compliance cause stack to send "challenge-ACK" |
1017 | * e.g. in response to spurious SYNs. Conntrack MUST | 1017 | * e.g. in response to spurious SYNs. Conntrack MUST |
1018 | * not believe this ACK is acking last FIN. | 1018 | * not believe this ACK is acking last FIN. |
1019 | */ | 1019 | */ |
1020 | if (old_state == TCP_CONNTRACK_LAST_ACK && | 1020 | if (old_state == TCP_CONNTRACK_LAST_ACK && |
1021 | index == TCP_ACK_SET && | 1021 | index == TCP_ACK_SET && |
1022 | ct->proto.tcp.last_dir != dir && | 1022 | ct->proto.tcp.last_dir != dir && |
1023 | ct->proto.tcp.last_index == TCP_SYN_SET && | 1023 | ct->proto.tcp.last_index == TCP_SYN_SET && |
1024 | (ct->proto.tcp.last_flags & IP_CT_EXP_CHALLENGE_ACK)) { | 1024 | (ct->proto.tcp.last_flags & IP_CT_EXP_CHALLENGE_ACK)) { |
1025 | /* Detected RFC5961 challenge ACK */ | 1025 | /* Detected RFC5961 challenge ACK */ |
1026 | ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; | 1026 | ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK; |
1027 | spin_unlock_bh(&ct->lock); | 1027 | spin_unlock_bh(&ct->lock); |
1028 | nf_ct_l4proto_log_invalid(skb, ct, "challenge-ack ignored"); | 1028 | nf_ct_l4proto_log_invalid(skb, ct, "challenge-ack ignored"); |
1029 | return NF_ACCEPT; /* Don't change state */ | 1029 | return NF_ACCEPT; /* Don't change state */ |
1030 | } | 1030 | } |
1031 | break; | 1031 | break; |
1032 | case TCP_CONNTRACK_SYN_SENT2: | 1032 | case TCP_CONNTRACK_SYN_SENT2: |
1033 | /* tcp_conntracks table is not smart enough to handle | 1033 | /* tcp_conntracks table is not smart enough to handle |
1034 | * simultaneous open. | 1034 | * simultaneous open. |
1035 | */ | 1035 | */ |
1036 | ct->proto.tcp.last_flags |= IP_CT_TCP_SIMULTANEOUS_OPEN; | 1036 | ct->proto.tcp.last_flags |= IP_CT_TCP_SIMULTANEOUS_OPEN; |
1037 | break; | 1037 | break; |
1038 | case TCP_CONNTRACK_SYN_RECV: | 1038 | case TCP_CONNTRACK_SYN_RECV: |
1039 | if (dir == IP_CT_DIR_REPLY && index == TCP_ACK_SET && | 1039 | if (dir == IP_CT_DIR_REPLY && index == TCP_ACK_SET && |
1040 | ct->proto.tcp.last_flags & IP_CT_TCP_SIMULTANEOUS_OPEN) | 1040 | ct->proto.tcp.last_flags & IP_CT_TCP_SIMULTANEOUS_OPEN) |
1041 | new_state = TCP_CONNTRACK_ESTABLISHED; | 1041 | new_state = TCP_CONNTRACK_ESTABLISHED; |
1042 | break; | 1042 | break; |
1043 | case TCP_CONNTRACK_CLOSE: | 1043 | case TCP_CONNTRACK_CLOSE: |
1044 | if (index == TCP_RST_SET | 1044 | if (index == TCP_RST_SET |
1045 | && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) | 1045 | && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET) |
1046 | && before(ntohl(th->seq), ct->proto.tcp.seen[!dir].td_maxack)) { | 1046 | && before(ntohl(th->seq), ct->proto.tcp.seen[!dir].td_maxack)) { |
1047 | /* Invalid RST */ | 1047 | /* Invalid RST */ |
1048 | spin_unlock_bh(&ct->lock); | 1048 | spin_unlock_bh(&ct->lock); |
1049 | nf_ct_l4proto_log_invalid(skb, ct, "invalid rst"); | 1049 | nf_ct_l4proto_log_invalid(skb, ct, "invalid rst"); |
1050 | return -NF_ACCEPT; | 1050 | return -NF_ACCEPT; |
1051 | } | 1051 | } |
1052 | if (index == TCP_RST_SET | 1052 | if (index == TCP_RST_SET |
1053 | && ((test_bit(IPS_SEEN_REPLY_BIT, &ct->status) | 1053 | && ((test_bit(IPS_SEEN_REPLY_BIT, &ct->status) |
1054 | && ct->proto.tcp.last_index == TCP_SYN_SET) | 1054 | && ct->proto.tcp.last_index == TCP_SYN_SET) |
1055 | || (!test_bit(IPS_ASSURED_BIT, &ct->status) | 1055 | || (!test_bit(IPS_ASSURED_BIT, &ct->status) |
1056 | && ct->proto.tcp.last_index == TCP_ACK_SET)) | 1056 | && ct->proto.tcp.last_index == TCP_ACK_SET)) |
1057 | && ntohl(th->ack_seq) == ct->proto.tcp.last_end) { | 1057 | && ntohl(th->ack_seq) == ct->proto.tcp.last_end) { |
1058 | /* RST sent to invalid SYN or ACK we had let through | 1058 | /* RST sent to invalid SYN or ACK we had let through |
1059 | * at a) and c) above: | 1059 | * at a) and c) above: |
1060 | * | 1060 | * |
1061 | * a) SYN was in window then | 1061 | * a) SYN was in window then |
1062 | * c) we hold a half-open connection. | 1062 | * c) we hold a half-open connection. |
1063 | * | 1063 | * |
1064 | * Delete our connection entry. | 1064 | * Delete our connection entry. |
1065 | * We skip window checking, because packet might ACK | 1065 | * We skip window checking, because packet might ACK |
1066 | * segments we ignored. */ | 1066 | * segments we ignored. */ |
1067 | goto in_window; | 1067 | goto in_window; |
1068 | } | 1068 | } |
1069 | /* Just fall through */ | 1069 | /* Just fall through */ |
1070 | default: | 1070 | default: |
1071 | /* Keep compilers happy. */ | 1071 | /* Keep compilers happy. */ |
1072 | break; | 1072 | break; |
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | if (!tcp_in_window(ct, &ct->proto.tcp, dir, index, | 1075 | if (!tcp_in_window(ct, &ct->proto.tcp, dir, index, |
1076 | skb, dataoff, th)) { | 1076 | skb, dataoff, th)) { |
1077 | spin_unlock_bh(&ct->lock); | 1077 | spin_unlock_bh(&ct->lock); |
1078 | return -NF_ACCEPT; | 1078 | return -NF_ACCEPT; |
1079 | } | 1079 | } |
1080 | in_window: | 1080 | in_window: |
1081 | /* From now on we have got in-window packets */ | 1081 | /* From now on we have got in-window packets */ |
1082 | ct->proto.tcp.last_index = index; | 1082 | ct->proto.tcp.last_index = index; |
1083 | ct->proto.tcp.last_dir = dir; | 1083 | ct->proto.tcp.last_dir = dir; |
1084 | 1084 | ||
1085 | pr_debug("tcp_conntracks: "); | 1085 | pr_debug("tcp_conntracks: "); |
1086 | nf_ct_dump_tuple(tuple); | 1086 | nf_ct_dump_tuple(tuple); |
1087 | pr_debug("syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n", | 1087 | pr_debug("syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n", |
1088 | (th->syn ? 1 : 0), (th->ack ? 1 : 0), | 1088 | (th->syn ? 1 : 0), (th->ack ? 1 : 0), |
1089 | (th->fin ? 1 : 0), (th->rst ? 1 : 0), | 1089 | (th->fin ? 1 : 0), (th->rst ? 1 : 0), |
1090 | old_state, new_state); | 1090 | old_state, new_state); |
1091 | 1091 | ||
1092 | ct->proto.tcp.state = new_state; | 1092 | ct->proto.tcp.state = new_state; |
1093 | if (old_state != new_state | 1093 | if (old_state != new_state |
1094 | && new_state == TCP_CONNTRACK_FIN_WAIT) | 1094 | && new_state == TCP_CONNTRACK_FIN_WAIT) |
1095 | ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; | 1095 | ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; |
1096 | 1096 | ||
1097 | timeouts = nf_ct_timeout_lookup(ct); | 1097 | timeouts = nf_ct_timeout_lookup(ct); |
1098 | if (!timeouts) | 1098 | if (!timeouts) |
1099 | timeouts = tn->timeouts; | 1099 | timeouts = tn->timeouts; |
1100 | 1100 | ||
1101 | if (ct->proto.tcp.retrans >= tn->tcp_max_retrans && | 1101 | if (ct->proto.tcp.retrans >= tn->tcp_max_retrans && |
1102 | timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) | 1102 | timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) |
1103 | timeout = timeouts[TCP_CONNTRACK_RETRANS]; | 1103 | timeout = timeouts[TCP_CONNTRACK_RETRANS]; |
1104 | else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & | 1104 | else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & |
1105 | IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && | 1105 | IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && |
1106 | timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) | 1106 | timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) |
1107 | timeout = timeouts[TCP_CONNTRACK_UNACK]; | 1107 | timeout = timeouts[TCP_CONNTRACK_UNACK]; |
1108 | else if (ct->proto.tcp.last_win == 0 && | 1108 | else if (ct->proto.tcp.last_win == 0 && |
1109 | timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) | 1109 | timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) |
1110 | timeout = timeouts[TCP_CONNTRACK_RETRANS]; | 1110 | timeout = timeouts[TCP_CONNTRACK_RETRANS]; |
1111 | else | 1111 | else |
1112 | timeout = timeouts[new_state]; | 1112 | timeout = timeouts[new_state]; |
1113 | spin_unlock_bh(&ct->lock); | 1113 | spin_unlock_bh(&ct->lock); |
1114 | 1114 | ||
1115 | if (new_state != old_state) | 1115 | if (new_state != old_state) |
1116 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); | 1116 | nf_conntrack_event_cache(IPCT_PROTOINFO, ct); |
1117 | 1117 | ||
1118 | if (!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | 1118 | if (!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
1119 | /* If only reply is a RST, we can consider ourselves not to | 1119 | /* If only reply is a RST, we can consider ourselves not to |
1120 | have an established connection: this is a fairly common | 1120 | have an established connection: this is a fairly common |
1121 | problem case, so we can delete the conntrack | 1121 | problem case, so we can delete the conntrack |
1122 | immediately. --RR */ | 1122 | immediately. --RR */ |
1123 | if (th->rst) { | 1123 | if (th->rst) { |
1124 | nf_ct_kill_acct(ct, ctinfo, skb); | 1124 | nf_ct_kill_acct(ct, ctinfo, skb); |
1125 | return NF_ACCEPT; | 1125 | return NF_ACCEPT; |
1126 | } | 1126 | } |
1127 | /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection | 1127 | /* ESTABLISHED without SEEN_REPLY, i.e. mid-connection |
1128 | * pickup with loose=1. Avoid large ESTABLISHED timeout. | 1128 | * pickup with loose=1. Avoid large ESTABLISHED timeout. |
1129 | */ | 1129 | */ |
1130 | if (new_state == TCP_CONNTRACK_ESTABLISHED && | 1130 | if (new_state == TCP_CONNTRACK_ESTABLISHED && |
1131 | timeout > timeouts[TCP_CONNTRACK_UNACK]) | 1131 | timeout > timeouts[TCP_CONNTRACK_UNACK]) |
1132 | timeout = timeouts[TCP_CONNTRACK_UNACK]; | 1132 | timeout = timeouts[TCP_CONNTRACK_UNACK]; |
1133 | } else if (!test_bit(IPS_ASSURED_BIT, &ct->status) | 1133 | } else if (!test_bit(IPS_ASSURED_BIT, &ct->status) |
1134 | && (old_state == TCP_CONNTRACK_SYN_RECV | 1134 | && (old_state == TCP_CONNTRACK_SYN_RECV |
1135 | || old_state == TCP_CONNTRACK_ESTABLISHED) | 1135 | || old_state == TCP_CONNTRACK_ESTABLISHED) |
1136 | && new_state == TCP_CONNTRACK_ESTABLISHED) { | 1136 | && new_state == TCP_CONNTRACK_ESTABLISHED) { |
1137 | /* Set ASSURED if we see see valid ack in ESTABLISHED | 1137 | /* Set ASSURED if we see see valid ack in ESTABLISHED |
1138 | after SYN_RECV or a valid answer for a picked up | 1138 | after SYN_RECV or a valid answer for a picked up |
1139 | connection. */ | 1139 | connection. */ |
1140 | set_bit(IPS_ASSURED_BIT, &ct->status); | 1140 | set_bit(IPS_ASSURED_BIT, &ct->status); |
1141 | nf_conntrack_event_cache(IPCT_ASSURED, ct); | 1141 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
1142 | } | 1142 | } |
1143 | nf_ct_refresh_acct(ct, ctinfo, skb, timeout); | 1143 | nf_ct_refresh_acct(ct, ctinfo, skb, timeout); |
1144 | 1144 | ||
1145 | return NF_ACCEPT; | 1145 | return NF_ACCEPT; |
1146 | } | 1146 | } |
1147 | 1147 | ||
1148 | static bool tcp_can_early_drop(const struct nf_conn *ct) | 1148 | static bool tcp_can_early_drop(const struct nf_conn *ct) |
1149 | { | 1149 | { |
1150 | switch (ct->proto.tcp.state) { | 1150 | switch (ct->proto.tcp.state) { |
1151 | case TCP_CONNTRACK_FIN_WAIT: | 1151 | case TCP_CONNTRACK_FIN_WAIT: |
1152 | case TCP_CONNTRACK_LAST_ACK: | 1152 | case TCP_CONNTRACK_LAST_ACK: |
1153 | case TCP_CONNTRACK_TIME_WAIT: | 1153 | case TCP_CONNTRACK_TIME_WAIT: |
1154 | case TCP_CONNTRACK_CLOSE: | 1154 | case TCP_CONNTRACK_CLOSE: |
1155 | case TCP_CONNTRACK_CLOSE_WAIT: | 1155 | case TCP_CONNTRACK_CLOSE_WAIT: |
1156 | return true; | 1156 | return true; |
1157 | default: | 1157 | default: |
1158 | break; | 1158 | break; |
1159 | } | 1159 | } |
1160 | 1160 | ||
1161 | return false; | 1161 | return false; |
1162 | } | 1162 | } |
1163 | 1163 | ||
1164 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 1164 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
1165 | 1165 | ||
1166 | #include <linux/netfilter/nfnetlink.h> | 1166 | #include <linux/netfilter/nfnetlink.h> |
1167 | #include <linux/netfilter/nfnetlink_conntrack.h> | 1167 | #include <linux/netfilter/nfnetlink_conntrack.h> |
1168 | 1168 | ||
1169 | static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, | 1169 | static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, |
1170 | struct nf_conn *ct) | 1170 | struct nf_conn *ct) |
1171 | { | 1171 | { |
1172 | struct nlattr *nest_parms; | 1172 | struct nlattr *nest_parms; |
1173 | struct nf_ct_tcp_flags tmp = {}; | 1173 | struct nf_ct_tcp_flags tmp = {}; |
1174 | 1174 | ||
1175 | spin_lock_bh(&ct->lock); | 1175 | spin_lock_bh(&ct->lock); |
1176 | nest_parms = nla_nest_start(skb, CTA_PROTOINFO_TCP | NLA_F_NESTED); | 1176 | nest_parms = nla_nest_start(skb, CTA_PROTOINFO_TCP | NLA_F_NESTED); |
1177 | if (!nest_parms) | 1177 | if (!nest_parms) |
1178 | goto nla_put_failure; | 1178 | goto nla_put_failure; |
1179 | 1179 | ||
1180 | if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state) || | 1180 | if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state) || |
1181 | nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, | 1181 | nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, |
1182 | ct->proto.tcp.seen[0].td_scale) || | 1182 | ct->proto.tcp.seen[0].td_scale) || |
1183 | nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY, | 1183 | nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY, |
1184 | ct->proto.tcp.seen[1].td_scale)) | 1184 | ct->proto.tcp.seen[1].td_scale)) |
1185 | goto nla_put_failure; | 1185 | goto nla_put_failure; |
1186 | 1186 | ||
1187 | tmp.flags = ct->proto.tcp.seen[0].flags; | 1187 | tmp.flags = ct->proto.tcp.seen[0].flags; |
1188 | if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, | 1188 | if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, |
1189 | sizeof(struct nf_ct_tcp_flags), &tmp)) | 1189 | sizeof(struct nf_ct_tcp_flags), &tmp)) |
1190 | goto nla_put_failure; | 1190 | goto nla_put_failure; |
1191 | 1191 | ||
1192 | tmp.flags = ct->proto.tcp.seen[1].flags; | 1192 | tmp.flags = ct->proto.tcp.seen[1].flags; |
1193 | if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY, | 1193 | if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY, |
1194 | sizeof(struct nf_ct_tcp_flags), &tmp)) | 1194 | sizeof(struct nf_ct_tcp_flags), &tmp)) |
1195 | goto nla_put_failure; | 1195 | goto nla_put_failure; |
1196 | spin_unlock_bh(&ct->lock); | 1196 | spin_unlock_bh(&ct->lock); |
1197 | 1197 | ||
1198 | nla_nest_end(skb, nest_parms); | 1198 | nla_nest_end(skb, nest_parms); |
1199 | 1199 | ||
1200 | return 0; | 1200 | return 0; |
1201 | 1201 | ||
1202 | nla_put_failure: | 1202 | nla_put_failure: |
1203 | spin_unlock_bh(&ct->lock); | 1203 | spin_unlock_bh(&ct->lock); |
1204 | return -1; | 1204 | return -1; |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = { | 1207 | static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = { |
1208 | [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 }, | 1208 | [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 }, |
1209 | [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 }, | 1209 | [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 }, |
1210 | [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 }, | 1210 | [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 }, |
1211 | [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .len = sizeof(struct nf_ct_tcp_flags) }, | 1211 | [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .len = sizeof(struct nf_ct_tcp_flags) }, |
1212 | [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .len = sizeof(struct nf_ct_tcp_flags) }, | 1212 | [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .len = sizeof(struct nf_ct_tcp_flags) }, |
1213 | }; | 1213 | }; |
1214 | 1214 | ||
1215 | #define TCP_NLATTR_SIZE ( \ | 1215 | #define TCP_NLATTR_SIZE ( \ |
1216 | NLA_ALIGN(NLA_HDRLEN + 1) + \ | 1216 | NLA_ALIGN(NLA_HDRLEN + 1) + \ |
1217 | NLA_ALIGN(NLA_HDRLEN + 1) + \ | 1217 | NLA_ALIGN(NLA_HDRLEN + 1) + \ |
1218 | NLA_ALIGN(NLA_HDRLEN + sizeof(sizeof(struct nf_ct_tcp_flags))) + \ | 1218 | NLA_ALIGN(NLA_HDRLEN + sizeof(sizeof(struct nf_ct_tcp_flags))) + \ |
1219 | NLA_ALIGN(NLA_HDRLEN + sizeof(sizeof(struct nf_ct_tcp_flags)))) | 1219 | NLA_ALIGN(NLA_HDRLEN + sizeof(sizeof(struct nf_ct_tcp_flags)))) |
1220 | 1220 | ||
1221 | static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) | 1221 | static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) |
1222 | { | 1222 | { |
1223 | struct nlattr *pattr = cda[CTA_PROTOINFO_TCP]; | 1223 | struct nlattr *pattr = cda[CTA_PROTOINFO_TCP]; |
1224 | struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; | 1224 | struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1]; |
1225 | int err; | 1225 | int err; |
1226 | 1226 | ||
1227 | /* updates could not contain anything about the private | 1227 | /* updates could not contain anything about the private |
1228 | * protocol info, in that case skip the parsing */ | 1228 | * protocol info, in that case skip the parsing */ |
1229 | if (!pattr) | 1229 | if (!pattr) |
1230 | return 0; | 1230 | return 0; |
1231 | 1231 | ||
1232 | err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, pattr, | 1232 | err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, pattr, |
1233 | tcp_nla_policy, NULL); | 1233 | tcp_nla_policy, NULL); |
1234 | if (err < 0) | 1234 | if (err < 0) |
1235 | return err; | 1235 | return err; |
1236 | 1236 | ||
1237 | if (tb[CTA_PROTOINFO_TCP_STATE] && | 1237 | if (tb[CTA_PROTOINFO_TCP_STATE] && |
1238 | nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]) >= TCP_CONNTRACK_MAX) | 1238 | nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]) >= TCP_CONNTRACK_MAX) |
1239 | return -EINVAL; | 1239 | return -EINVAL; |
1240 | 1240 | ||
1241 | spin_lock_bh(&ct->lock); | 1241 | spin_lock_bh(&ct->lock); |
1242 | if (tb[CTA_PROTOINFO_TCP_STATE]) | 1242 | if (tb[CTA_PROTOINFO_TCP_STATE]) |
1243 | ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); | 1243 | ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); |
1244 | 1244 | ||
1245 | if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) { | 1245 | if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) { |
1246 | struct nf_ct_tcp_flags *attr = | 1246 | struct nf_ct_tcp_flags *attr = |
1247 | nla_data(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]); | 1247 | nla_data(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]); |
1248 | ct->proto.tcp.seen[0].flags &= ~attr->mask; | 1248 | ct->proto.tcp.seen[0].flags &= ~attr->mask; |
1249 | ct->proto.tcp.seen[0].flags |= attr->flags & attr->mask; | 1249 | ct->proto.tcp.seen[0].flags |= attr->flags & attr->mask; |
1250 | } | 1250 | } |
1251 | 1251 | ||
1252 | if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]) { | 1252 | if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]) { |
1253 | struct nf_ct_tcp_flags *attr = | 1253 | struct nf_ct_tcp_flags *attr = |
1254 | nla_data(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]); | 1254 | nla_data(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]); |
1255 | ct->proto.tcp.seen[1].flags &= ~attr->mask; | 1255 | ct->proto.tcp.seen[1].flags &= ~attr->mask; |
1256 | ct->proto.tcp.seen[1].flags |= attr->flags & attr->mask; | 1256 | ct->proto.tcp.seen[1].flags |= attr->flags & attr->mask; |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] && | 1259 | if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] && |
1260 | tb[CTA_PROTOINFO_TCP_WSCALE_REPLY] && | 1260 | tb[CTA_PROTOINFO_TCP_WSCALE_REPLY] && |
1261 | ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_WINDOW_SCALE && | 1261 | ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_WINDOW_SCALE && |
1262 | ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_WINDOW_SCALE) { | 1262 | ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_WINDOW_SCALE) { |
1263 | ct->proto.tcp.seen[0].td_scale = | 1263 | ct->proto.tcp.seen[0].td_scale = |
1264 | nla_get_u8(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]); | 1264 | nla_get_u8(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]); |
1265 | ct->proto.tcp.seen[1].td_scale = | 1265 | ct->proto.tcp.seen[1].td_scale = |
1266 | nla_get_u8(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]); | 1266 | nla_get_u8(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]); |
1267 | } | 1267 | } |
1268 | spin_unlock_bh(&ct->lock); | 1268 | spin_unlock_bh(&ct->lock); |
1269 | 1269 | ||
1270 | return 0; | 1270 | return 0; |
1271 | } | 1271 | } |
1272 | 1272 | ||
1273 | static unsigned int tcp_nlattr_tuple_size(void) | 1273 | static unsigned int tcp_nlattr_tuple_size(void) |
1274 | { | 1274 | { |
1275 | static unsigned int size __read_mostly; | 1275 | static unsigned int size __read_mostly; |
1276 | 1276 | ||
1277 | if (!size) | 1277 | if (!size) |
1278 | size = nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | 1278 | size = nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); |
1279 | 1279 | ||
1280 | return size; | 1280 | return size; |
1281 | } | 1281 | } |
1282 | #endif | 1282 | #endif |
1283 | 1283 | ||
1284 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 1284 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
1285 | 1285 | ||
1286 | #include <linux/netfilter/nfnetlink.h> | 1286 | #include <linux/netfilter/nfnetlink.h> |
1287 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 1287 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
1288 | 1288 | ||
1289 | static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], | 1289 | static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], |
1290 | struct net *net, void *data) | 1290 | struct net *net, void *data) |
1291 | { | 1291 | { |
1292 | struct nf_tcp_net *tn = tcp_pernet(net); | 1292 | struct nf_tcp_net *tn = tcp_pernet(net); |
1293 | unsigned int *timeouts = data; | 1293 | unsigned int *timeouts = data; |
1294 | int i; | 1294 | int i; |
1295 | 1295 | ||
1296 | if (!timeouts) | 1296 | if (!timeouts) |
1297 | timeouts = tn->timeouts; | 1297 | timeouts = tn->timeouts; |
1298 | /* set default TCP timeouts. */ | 1298 | /* set default TCP timeouts. */ |
1299 | for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++) | 1299 | for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++) |
1300 | timeouts[i] = tn->timeouts[i]; | 1300 | timeouts[i] = tn->timeouts[i]; |
1301 | 1301 | ||
1302 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) { | 1302 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) { |
1303 | timeouts[TCP_CONNTRACK_SYN_SENT] = | 1303 | timeouts[TCP_CONNTRACK_SYN_SENT] = |
1304 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ; | 1304 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ; |
1305 | } | 1305 | } |
1306 | 1306 | ||
1307 | if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) { | 1307 | if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) { |
1308 | timeouts[TCP_CONNTRACK_SYN_RECV] = | 1308 | timeouts[TCP_CONNTRACK_SYN_RECV] = |
1309 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ; | 1309 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ; |
1310 | } | 1310 | } |
1311 | if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) { | 1311 | if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) { |
1312 | timeouts[TCP_CONNTRACK_ESTABLISHED] = | 1312 | timeouts[TCP_CONNTRACK_ESTABLISHED] = |
1313 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ; | 1313 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ; |
1314 | } | 1314 | } |
1315 | if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) { | 1315 | if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) { |
1316 | timeouts[TCP_CONNTRACK_FIN_WAIT] = | 1316 | timeouts[TCP_CONNTRACK_FIN_WAIT] = |
1317 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ; | 1317 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ; |
1318 | } | 1318 | } |
1319 | if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) { | 1319 | if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) { |
1320 | timeouts[TCP_CONNTRACK_CLOSE_WAIT] = | 1320 | timeouts[TCP_CONNTRACK_CLOSE_WAIT] = |
1321 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ; | 1321 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ; |
1322 | } | 1322 | } |
1323 | if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) { | 1323 | if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) { |
1324 | timeouts[TCP_CONNTRACK_LAST_ACK] = | 1324 | timeouts[TCP_CONNTRACK_LAST_ACK] = |
1325 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ; | 1325 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ; |
1326 | } | 1326 | } |
1327 | if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) { | 1327 | if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) { |
1328 | timeouts[TCP_CONNTRACK_TIME_WAIT] = | 1328 | timeouts[TCP_CONNTRACK_TIME_WAIT] = |
1329 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ; | 1329 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ; |
1330 | } | 1330 | } |
1331 | if (tb[CTA_TIMEOUT_TCP_CLOSE]) { | 1331 | if (tb[CTA_TIMEOUT_TCP_CLOSE]) { |
1332 | timeouts[TCP_CONNTRACK_CLOSE] = | 1332 | timeouts[TCP_CONNTRACK_CLOSE] = |
1333 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ; | 1333 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ; |
1334 | } | 1334 | } |
1335 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) { | 1335 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) { |
1336 | timeouts[TCP_CONNTRACK_SYN_SENT2] = | 1336 | timeouts[TCP_CONNTRACK_SYN_SENT2] = |
1337 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ; | 1337 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ; |
1338 | } | 1338 | } |
1339 | if (tb[CTA_TIMEOUT_TCP_RETRANS]) { | 1339 | if (tb[CTA_TIMEOUT_TCP_RETRANS]) { |
1340 | timeouts[TCP_CONNTRACK_RETRANS] = | 1340 | timeouts[TCP_CONNTRACK_RETRANS] = |
1341 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ; | 1341 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ; |
1342 | } | 1342 | } |
1343 | if (tb[CTA_TIMEOUT_TCP_UNACK]) { | 1343 | if (tb[CTA_TIMEOUT_TCP_UNACK]) { |
1344 | timeouts[TCP_CONNTRACK_UNACK] = | 1344 | timeouts[TCP_CONNTRACK_UNACK] = |
1345 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ; | 1345 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ; |
1346 | } | 1346 | } |
1347 | 1347 | ||
1348 | timeouts[CTA_TIMEOUT_TCP_UNSPEC] = timeouts[CTA_TIMEOUT_TCP_SYN_SENT]; | 1348 | timeouts[CTA_TIMEOUT_TCP_UNSPEC] = timeouts[CTA_TIMEOUT_TCP_SYN_SENT]; |
1349 | return 0; | 1349 | return 0; |
1350 | } | 1350 | } |
1351 | 1351 | ||
1352 | static int | 1352 | static int |
1353 | tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 1353 | tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
1354 | { | 1354 | { |
1355 | const unsigned int *timeouts = data; | 1355 | const unsigned int *timeouts = data; |
1356 | 1356 | ||
1357 | if (nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_SENT, | 1357 | if (nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_SENT, |
1358 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ)) || | 1358 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ)) || |
1359 | nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_RECV, | 1359 | nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_RECV, |
1360 | htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ)) || | 1360 | htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ)) || |
1361 | nla_put_be32(skb, CTA_TIMEOUT_TCP_ESTABLISHED, | 1361 | nla_put_be32(skb, CTA_TIMEOUT_TCP_ESTABLISHED, |
1362 | htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ)) || | 1362 | htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ)) || |
1363 | nla_put_be32(skb, CTA_TIMEOUT_TCP_FIN_WAIT, | 1363 | nla_put_be32(skb, CTA_TIMEOUT_TCP_FIN_WAIT, |
1364 | htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ)) || | 1364 | htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ)) || |
1365 | nla_put_be32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT, | 1365 | nla_put_be32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT, |
1366 | htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ)) || | 1366 | htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ)) || |
1367 | nla_put_be32(skb, CTA_TIMEOUT_TCP_LAST_ACK, | 1367 | nla_put_be32(skb, CTA_TIMEOUT_TCP_LAST_ACK, |
1368 | htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ)) || | 1368 | htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ)) || |
1369 | nla_put_be32(skb, CTA_TIMEOUT_TCP_TIME_WAIT, | 1369 | nla_put_be32(skb, CTA_TIMEOUT_TCP_TIME_WAIT, |
1370 | htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ)) || | 1370 | htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ)) || |
1371 | nla_put_be32(skb, CTA_TIMEOUT_TCP_CLOSE, | 1371 | nla_put_be32(skb, CTA_TIMEOUT_TCP_CLOSE, |
1372 | htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ)) || | 1372 | htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ)) || |
1373 | nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_SENT2, | 1373 | nla_put_be32(skb, CTA_TIMEOUT_TCP_SYN_SENT2, |
1374 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ)) || | 1374 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ)) || |
1375 | nla_put_be32(skb, CTA_TIMEOUT_TCP_RETRANS, | 1375 | nla_put_be32(skb, CTA_TIMEOUT_TCP_RETRANS, |
1376 | htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ)) || | 1376 | htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ)) || |
1377 | nla_put_be32(skb, CTA_TIMEOUT_TCP_UNACK, | 1377 | nla_put_be32(skb, CTA_TIMEOUT_TCP_UNACK, |
1378 | htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ))) | 1378 | htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ))) |
1379 | goto nla_put_failure; | 1379 | goto nla_put_failure; |
1380 | return 0; | 1380 | return 0; |
1381 | 1381 | ||
1382 | nla_put_failure: | 1382 | nla_put_failure: |
1383 | return -ENOSPC; | 1383 | return -ENOSPC; |
1384 | } | 1384 | } |
1385 | 1385 | ||
1386 | static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = { | 1386 | static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = { |
1387 | [CTA_TIMEOUT_TCP_SYN_SENT] = { .type = NLA_U32 }, | 1387 | [CTA_TIMEOUT_TCP_SYN_SENT] = { .type = NLA_U32 }, |
1388 | [CTA_TIMEOUT_TCP_SYN_RECV] = { .type = NLA_U32 }, | 1388 | [CTA_TIMEOUT_TCP_SYN_RECV] = { .type = NLA_U32 }, |
1389 | [CTA_TIMEOUT_TCP_ESTABLISHED] = { .type = NLA_U32 }, | 1389 | [CTA_TIMEOUT_TCP_ESTABLISHED] = { .type = NLA_U32 }, |
1390 | [CTA_TIMEOUT_TCP_FIN_WAIT] = { .type = NLA_U32 }, | 1390 | [CTA_TIMEOUT_TCP_FIN_WAIT] = { .type = NLA_U32 }, |
1391 | [CTA_TIMEOUT_TCP_CLOSE_WAIT] = { .type = NLA_U32 }, | 1391 | [CTA_TIMEOUT_TCP_CLOSE_WAIT] = { .type = NLA_U32 }, |
1392 | [CTA_TIMEOUT_TCP_LAST_ACK] = { .type = NLA_U32 }, | 1392 | [CTA_TIMEOUT_TCP_LAST_ACK] = { .type = NLA_U32 }, |
1393 | [CTA_TIMEOUT_TCP_TIME_WAIT] = { .type = NLA_U32 }, | 1393 | [CTA_TIMEOUT_TCP_TIME_WAIT] = { .type = NLA_U32 }, |
1394 | [CTA_TIMEOUT_TCP_CLOSE] = { .type = NLA_U32 }, | 1394 | [CTA_TIMEOUT_TCP_CLOSE] = { .type = NLA_U32 }, |
1395 | [CTA_TIMEOUT_TCP_SYN_SENT2] = { .type = NLA_U32 }, | 1395 | [CTA_TIMEOUT_TCP_SYN_SENT2] = { .type = NLA_U32 }, |
1396 | [CTA_TIMEOUT_TCP_RETRANS] = { .type = NLA_U32 }, | 1396 | [CTA_TIMEOUT_TCP_RETRANS] = { .type = NLA_U32 }, |
1397 | [CTA_TIMEOUT_TCP_UNACK] = { .type = NLA_U32 }, | 1397 | [CTA_TIMEOUT_TCP_UNACK] = { .type = NLA_U32 }, |
1398 | }; | 1398 | }; |
1399 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 1399 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
1400 | 1400 | ||
1401 | #ifdef CONFIG_SYSCTL | 1401 | #ifdef CONFIG_SYSCTL |
1402 | static struct ctl_table tcp_sysctl_table[] = { | 1402 | static struct ctl_table tcp_sysctl_table[] = { |
1403 | { | 1403 | { |
1404 | .procname = "nf_conntrack_tcp_timeout_syn_sent", | 1404 | .procname = "nf_conntrack_tcp_timeout_syn_sent", |
1405 | .maxlen = sizeof(unsigned int), | 1405 | .maxlen = sizeof(unsigned int), |
1406 | .mode = 0644, | 1406 | .mode = 0644, |
1407 | .proc_handler = proc_dointvec_jiffies, | 1407 | .proc_handler = proc_dointvec_jiffies, |
1408 | }, | 1408 | }, |
1409 | { | 1409 | { |
1410 | .procname = "nf_conntrack_tcp_timeout_syn_recv", | 1410 | .procname = "nf_conntrack_tcp_timeout_syn_recv", |
1411 | .maxlen = sizeof(unsigned int), | 1411 | .maxlen = sizeof(unsigned int), |
1412 | .mode = 0644, | 1412 | .mode = 0644, |
1413 | .proc_handler = proc_dointvec_jiffies, | 1413 | .proc_handler = proc_dointvec_jiffies, |
1414 | }, | 1414 | }, |
1415 | { | 1415 | { |
1416 | .procname = "nf_conntrack_tcp_timeout_established", | 1416 | .procname = "nf_conntrack_tcp_timeout_established", |
1417 | .maxlen = sizeof(unsigned int), | 1417 | .maxlen = sizeof(unsigned int), |
1418 | .mode = 0644, | 1418 | .mode = 0644, |
1419 | .proc_handler = proc_dointvec_jiffies, | 1419 | .proc_handler = proc_dointvec_jiffies, |
1420 | }, | 1420 | }, |
1421 | { | 1421 | { |
1422 | .procname = "nf_conntrack_tcp_timeout_fin_wait", | 1422 | .procname = "nf_conntrack_tcp_timeout_fin_wait", |
1423 | .maxlen = sizeof(unsigned int), | 1423 | .maxlen = sizeof(unsigned int), |
1424 | .mode = 0644, | 1424 | .mode = 0644, |
1425 | .proc_handler = proc_dointvec_jiffies, | 1425 | .proc_handler = proc_dointvec_jiffies, |
1426 | }, | 1426 | }, |
1427 | { | 1427 | { |
1428 | .procname = "nf_conntrack_tcp_timeout_close_wait", | 1428 | .procname = "nf_conntrack_tcp_timeout_close_wait", |
1429 | .maxlen = sizeof(unsigned int), | 1429 | .maxlen = sizeof(unsigned int), |
1430 | .mode = 0644, | 1430 | .mode = 0644, |
1431 | .proc_handler = proc_dointvec_jiffies, | 1431 | .proc_handler = proc_dointvec_jiffies, |
1432 | }, | 1432 | }, |
1433 | { | 1433 | { |
1434 | .procname = "nf_conntrack_tcp_timeout_last_ack", | 1434 | .procname = "nf_conntrack_tcp_timeout_last_ack", |
1435 | .maxlen = sizeof(unsigned int), | 1435 | .maxlen = sizeof(unsigned int), |
1436 | .mode = 0644, | 1436 | .mode = 0644, |
1437 | .proc_handler = proc_dointvec_jiffies, | 1437 | .proc_handler = proc_dointvec_jiffies, |
1438 | }, | 1438 | }, |
1439 | { | 1439 | { |
1440 | .procname = "nf_conntrack_tcp_timeout_time_wait", | 1440 | .procname = "nf_conntrack_tcp_timeout_time_wait", |
1441 | .maxlen = sizeof(unsigned int), | 1441 | .maxlen = sizeof(unsigned int), |
1442 | .mode = 0644, | 1442 | .mode = 0644, |
1443 | .proc_handler = proc_dointvec_jiffies, | 1443 | .proc_handler = proc_dointvec_jiffies, |
1444 | }, | 1444 | }, |
1445 | { | 1445 | { |
1446 | .procname = "nf_conntrack_tcp_timeout_close", | 1446 | .procname = "nf_conntrack_tcp_timeout_close", |
1447 | .maxlen = sizeof(unsigned int), | 1447 | .maxlen = sizeof(unsigned int), |
1448 | .mode = 0644, | 1448 | .mode = 0644, |
1449 | .proc_handler = proc_dointvec_jiffies, | 1449 | .proc_handler = proc_dointvec_jiffies, |
1450 | }, | 1450 | }, |
1451 | { | 1451 | { |
1452 | .procname = "nf_conntrack_tcp_timeout_max_retrans", | 1452 | .procname = "nf_conntrack_tcp_timeout_max_retrans", |
1453 | .maxlen = sizeof(unsigned int), | 1453 | .maxlen = sizeof(unsigned int), |
1454 | .mode = 0644, | 1454 | .mode = 0644, |
1455 | .proc_handler = proc_dointvec_jiffies, | 1455 | .proc_handler = proc_dointvec_jiffies, |
1456 | }, | 1456 | }, |
1457 | { | 1457 | { |
1458 | .procname = "nf_conntrack_tcp_timeout_unacknowledged", | 1458 | .procname = "nf_conntrack_tcp_timeout_unacknowledged", |
1459 | .maxlen = sizeof(unsigned int), | 1459 | .maxlen = sizeof(unsigned int), |
1460 | .mode = 0644, | 1460 | .mode = 0644, |
1461 | .proc_handler = proc_dointvec_jiffies, | 1461 | .proc_handler = proc_dointvec_jiffies, |
1462 | }, | 1462 | }, |
1463 | { | 1463 | { |
1464 | .procname = "nf_conntrack_tcp_loose", | 1464 | .procname = "nf_conntrack_tcp_loose", |
1465 | .maxlen = sizeof(unsigned int), | 1465 | .maxlen = sizeof(unsigned int), |
1466 | .mode = 0644, | 1466 | .mode = 0644, |
1467 | .proc_handler = proc_dointvec, | 1467 | .proc_handler = proc_dointvec, |
1468 | }, | 1468 | }, |
1469 | { | 1469 | { |
1470 | .procname = "nf_conntrack_tcp_be_liberal", | 1470 | .procname = "nf_conntrack_tcp_be_liberal", |
1471 | .maxlen = sizeof(unsigned int), | 1471 | .maxlen = sizeof(unsigned int), |
1472 | .mode = 0644, | 1472 | .mode = 0644, |
1473 | .proc_handler = proc_dointvec, | 1473 | .proc_handler = proc_dointvec, |
1474 | }, | 1474 | }, |
1475 | { | 1475 | { |
1476 | .procname = "nf_conntrack_tcp_max_retrans", | 1476 | .procname = "nf_conntrack_tcp_max_retrans", |
1477 | .maxlen = sizeof(unsigned int), | 1477 | .maxlen = sizeof(unsigned int), |
1478 | .mode = 0644, | 1478 | .mode = 0644, |
1479 | .proc_handler = proc_dointvec, | 1479 | .proc_handler = proc_dointvec, |
1480 | }, | 1480 | }, |
1481 | { } | 1481 | { } |
1482 | }; | 1482 | }; |
1483 | #endif /* CONFIG_SYSCTL */ | 1483 | #endif /* CONFIG_SYSCTL */ |
1484 | 1484 | ||
1485 | static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn, | 1485 | static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn, |
1486 | struct nf_tcp_net *tn) | 1486 | struct nf_tcp_net *tn) |
1487 | { | 1487 | { |
1488 | #ifdef CONFIG_SYSCTL | 1488 | #ifdef CONFIG_SYSCTL |
1489 | if (pn->ctl_table) | 1489 | if (pn->ctl_table) |
1490 | return 0; | 1490 | return 0; |
1491 | 1491 | ||
1492 | pn->ctl_table = kmemdup(tcp_sysctl_table, | 1492 | pn->ctl_table = kmemdup(tcp_sysctl_table, |
1493 | sizeof(tcp_sysctl_table), | 1493 | sizeof(tcp_sysctl_table), |
1494 | GFP_KERNEL); | 1494 | GFP_KERNEL); |
1495 | if (!pn->ctl_table) | 1495 | if (!pn->ctl_table) |
1496 | return -ENOMEM; | 1496 | return -ENOMEM; |
1497 | 1497 | ||
1498 | pn->ctl_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT]; | 1498 | pn->ctl_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT]; |
1499 | pn->ctl_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV]; | 1499 | pn->ctl_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV]; |
1500 | pn->ctl_table[2].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED]; | 1500 | pn->ctl_table[2].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED]; |
1501 | pn->ctl_table[3].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT]; | 1501 | pn->ctl_table[3].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT]; |
1502 | pn->ctl_table[4].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT]; | 1502 | pn->ctl_table[4].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT]; |
1503 | pn->ctl_table[5].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK]; | 1503 | pn->ctl_table[5].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK]; |
1504 | pn->ctl_table[6].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT]; | 1504 | pn->ctl_table[6].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT]; |
1505 | pn->ctl_table[7].data = &tn->timeouts[TCP_CONNTRACK_CLOSE]; | 1505 | pn->ctl_table[7].data = &tn->timeouts[TCP_CONNTRACK_CLOSE]; |
1506 | pn->ctl_table[8].data = &tn->timeouts[TCP_CONNTRACK_RETRANS]; | 1506 | pn->ctl_table[8].data = &tn->timeouts[TCP_CONNTRACK_RETRANS]; |
1507 | pn->ctl_table[9].data = &tn->timeouts[TCP_CONNTRACK_UNACK]; | 1507 | pn->ctl_table[9].data = &tn->timeouts[TCP_CONNTRACK_UNACK]; |
1508 | pn->ctl_table[10].data = &tn->tcp_loose; | 1508 | pn->ctl_table[10].data = &tn->tcp_loose; |
1509 | pn->ctl_table[11].data = &tn->tcp_be_liberal; | 1509 | pn->ctl_table[11].data = &tn->tcp_be_liberal; |
1510 | pn->ctl_table[12].data = &tn->tcp_max_retrans; | 1510 | pn->ctl_table[12].data = &tn->tcp_max_retrans; |
1511 | #endif | 1511 | #endif |
1512 | return 0; | 1512 | return 0; |
1513 | } | 1513 | } |
1514 | 1514 | ||
1515 | static int tcp_init_net(struct net *net, u_int16_t proto) | 1515 | static int tcp_init_net(struct net *net, u_int16_t proto) |
1516 | { | 1516 | { |
1517 | struct nf_tcp_net *tn = tcp_pernet(net); | 1517 | struct nf_tcp_net *tn = tcp_pernet(net); |
1518 | struct nf_proto_net *pn = &tn->pn; | 1518 | struct nf_proto_net *pn = &tn->pn; |
1519 | 1519 | ||
1520 | if (!pn->users) { | 1520 | if (!pn->users) { |
1521 | int i; | 1521 | int i; |
1522 | 1522 | ||
1523 | for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++) | 1523 | for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++) |
1524 | tn->timeouts[i] = tcp_timeouts[i]; | 1524 | tn->timeouts[i] = tcp_timeouts[i]; |
1525 | 1525 | ||
1526 | /* timeouts[0] is unused, make it same as SYN_SENT so | 1526 | /* timeouts[0] is unused, make it same as SYN_SENT so |
1527 | * ->timeouts[0] contains 'new' timeout, like udp or icmp. | 1527 | * ->timeouts[0] contains 'new' timeout, like udp or icmp. |
1528 | */ | 1528 | */ |
1529 | tn->timeouts[0] = tcp_timeouts[TCP_CONNTRACK_SYN_SENT]; | 1529 | tn->timeouts[0] = tcp_timeouts[TCP_CONNTRACK_SYN_SENT]; |
1530 | tn->tcp_loose = nf_ct_tcp_loose; | 1530 | tn->tcp_loose = nf_ct_tcp_loose; |
1531 | tn->tcp_be_liberal = nf_ct_tcp_be_liberal; | 1531 | tn->tcp_be_liberal = nf_ct_tcp_be_liberal; |
1532 | tn->tcp_max_retrans = nf_ct_tcp_max_retrans; | 1532 | tn->tcp_max_retrans = nf_ct_tcp_max_retrans; |
1533 | } | 1533 | } |
1534 | 1534 | ||
1535 | return tcp_kmemdup_sysctl_table(pn, tn); | 1535 | return tcp_kmemdup_sysctl_table(pn, tn); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | static struct nf_proto_net *tcp_get_net_proto(struct net *net) | 1538 | static struct nf_proto_net *tcp_get_net_proto(struct net *net) |
1539 | { | 1539 | { |
1540 | return &net->ct.nf_ct_proto.tcp.pn; | 1540 | return &net->ct.nf_ct_proto.tcp.pn; |
1541 | } | 1541 | } |
1542 | 1542 | ||
1543 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 = | 1543 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 = |
1544 | { | 1544 | { |
1545 | .l3proto = PF_INET, | 1545 | .l3proto = PF_INET, |
1546 | .l4proto = IPPROTO_TCP, | 1546 | .l4proto = IPPROTO_TCP, |
1547 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 1547 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
1548 | .print_conntrack = tcp_print_conntrack, | 1548 | .print_conntrack = tcp_print_conntrack, |
1549 | #endif | 1549 | #endif |
1550 | .packet = tcp_packet, | 1550 | .packet = tcp_packet, |
1551 | .error = tcp_error, | 1551 | .error = tcp_error, |
1552 | .can_early_drop = tcp_can_early_drop, | 1552 | .can_early_drop = tcp_can_early_drop, |
1553 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 1553 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
1554 | .to_nlattr = tcp_to_nlattr, | 1554 | .to_nlattr = tcp_to_nlattr, |
1555 | .from_nlattr = nlattr_to_tcp, | 1555 | .from_nlattr = nlattr_to_tcp, |
1556 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 1556 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1557 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 1557 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1558 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | 1558 | .nlattr_tuple_size = tcp_nlattr_tuple_size, |
1559 | .nlattr_size = TCP_NLATTR_SIZE, | 1559 | .nlattr_size = TCP_NLATTR_SIZE, |
1560 | .nla_policy = nf_ct_port_nla_policy, | 1560 | .nla_policy = nf_ct_port_nla_policy, |
1561 | #endif | 1561 | #endif |
1562 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 1562 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
1563 | .ctnl_timeout = { | 1563 | .ctnl_timeout = { |
1564 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, | 1564 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, |
1565 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, | 1565 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, |
1566 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, | 1566 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, |
1567 | .obj_size = sizeof(unsigned int) * | 1567 | .obj_size = sizeof(unsigned int) * |
1568 | TCP_CONNTRACK_TIMEOUT_MAX, | 1568 | TCP_CONNTRACK_TIMEOUT_MAX, |
1569 | .nla_policy = tcp_timeout_nla_policy, | 1569 | .nla_policy = tcp_timeout_nla_policy, |
1570 | }, | 1570 | }, |
1571 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 1571 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
1572 | .init_net = tcp_init_net, | 1572 | .init_net = tcp_init_net, |
1573 | .get_net_proto = tcp_get_net_proto, | 1573 | .get_net_proto = tcp_get_net_proto, |
1574 | }; | 1574 | }; |
1575 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4); | 1575 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4); |
1576 | 1576 | ||
1577 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 = | 1577 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 = |
1578 | { | 1578 | { |
1579 | .l3proto = PF_INET6, | 1579 | .l3proto = PF_INET6, |
1580 | .l4proto = IPPROTO_TCP, | 1580 | .l4proto = IPPROTO_TCP, |
1581 | #ifdef CONFIG_NF_CONNTRACK_PROCFS | 1581 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
1582 | .print_conntrack = tcp_print_conntrack, | 1582 | .print_conntrack = tcp_print_conntrack, |
1583 | #endif | 1583 | #endif |
1584 | .packet = tcp_packet, | 1584 | .packet = tcp_packet, |
1585 | .error = tcp_error, | 1585 | .error = tcp_error, |
1586 | .can_early_drop = tcp_can_early_drop, | 1586 | .can_early_drop = tcp_can_early_drop, |
1587 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 1587 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
1588 | .nlattr_size = TCP_NLATTR_SIZE, | 1588 | .nlattr_size = TCP_NLATTR_SIZE, |
1589 | .to_nlattr = tcp_to_nlattr, | 1589 | .to_nlattr = tcp_to_nlattr, |
1590 | .from_nlattr = nlattr_to_tcp, | 1590 | .from_nlattr = nlattr_to_tcp, |
1591 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 1591 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1592 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 1592 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1593 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | 1593 | .nlattr_tuple_size = tcp_nlattr_tuple_size, |
1594 | .nla_policy = nf_ct_port_nla_policy, | 1594 | .nla_policy = nf_ct_port_nla_policy, |
1595 | #endif | 1595 | #endif |
1596 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 1596 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
1597 | .ctnl_timeout = { | 1597 | .ctnl_timeout = { |
1598 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, | 1598 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, |
1599 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, | 1599 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, |
1600 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, | 1600 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, |
1601 | .obj_size = sizeof(unsigned int) * | 1601 | .obj_size = sizeof(unsigned int) * |
1602 | TCP_CONNTRACK_TIMEOUT_MAX, | 1602 | TCP_CONNTRACK_TIMEOUT_MAX, |
1603 | .nla_policy = tcp_timeout_nla_policy, | 1603 | .nla_policy = tcp_timeout_nla_policy, |
1604 | }, | 1604 | }, |
1605 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 1605 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
1606 | .init_net = tcp_init_net, | 1606 | .init_net = tcp_init_net, |
1607 | .get_net_proto = tcp_get_net_proto, | 1607 | .get_net_proto = tcp_get_net_proto, |
1608 | }; | 1608 | }; |
1609 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); | 1609 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6); |
1610 | 1610 |
net/netfilter/nf_conntrack_proto_udp.c
1 | /* (C) 1999-2001 Paul `Rusty' Russell | 1 | /* (C) 1999-2001 Paul `Rusty' Russell |
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | 2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> |
3 | * (C) 2006-2012 Patrick McHardy <kaber@trash.net> | 3 | * (C) 2006-2012 Patrick McHardy <kaber@trash.net> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <linux/timer.h> | 11 | #include <linux/timer.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/udp.h> | 13 | #include <linux/udp.h> |
14 | #include <linux/seq_file.h> | 14 | #include <linux/seq_file.h> |
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/ipv6.h> | 16 | #include <linux/ipv6.h> |
17 | #include <net/ip6_checksum.h> | 17 | #include <net/ip6_checksum.h> |
18 | #include <net/checksum.h> | 18 | #include <net/checksum.h> |
19 | 19 | ||
20 | #include <linux/netfilter.h> | 20 | #include <linux/netfilter.h> |
21 | #include <linux/netfilter_ipv4.h> | 21 | #include <linux/netfilter_ipv4.h> |
22 | #include <linux/netfilter_ipv6.h> | 22 | #include <linux/netfilter_ipv6.h> |
23 | #include <net/netfilter/nf_conntrack_l4proto.h> | 23 | #include <net/netfilter/nf_conntrack_l4proto.h> |
24 | #include <net/netfilter/nf_conntrack_ecache.h> | 24 | #include <net/netfilter/nf_conntrack_ecache.h> |
25 | #include <net/netfilter/nf_conntrack_timeout.h> | 25 | #include <net/netfilter/nf_conntrack_timeout.h> |
26 | #include <net/netfilter/nf_log.h> | 26 | #include <net/netfilter/nf_log.h> |
27 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | 27 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> |
28 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 28 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
29 | 29 | ||
30 | static const unsigned int udp_timeouts[UDP_CT_MAX] = { | 30 | static const unsigned int udp_timeouts[UDP_CT_MAX] = { |
31 | [UDP_CT_UNREPLIED] = 30*HZ, | 31 | [UDP_CT_UNREPLIED] = 30*HZ, |
32 | [UDP_CT_REPLIED] = 180*HZ, | 32 | [UDP_CT_REPLIED] = 180*HZ, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | static inline struct nf_udp_net *udp_pernet(struct net *net) | 35 | static inline struct nf_udp_net *udp_pernet(struct net *net) |
36 | { | 36 | { |
37 | return &net->ct.nf_ct_proto.udp; | 37 | return &net->ct.nf_ct_proto.udp; |
38 | } | 38 | } |
39 | 39 | ||
40 | static unsigned int *udp_get_timeouts(struct net *net) | 40 | static unsigned int *udp_get_timeouts(struct net *net) |
41 | { | 41 | { |
42 | return udp_pernet(net)->timeouts; | 42 | return udp_pernet(net)->timeouts; |
43 | } | 43 | } |
44 | 44 | ||
45 | static void udp_error_log(const struct sk_buff *skb, | ||
46 | const struct nf_hook_state *state, | ||
47 | const char *msg) | ||
48 | { | ||
49 | nf_l4proto_log_invalid(skb, state->net, state->pf, | ||
50 | IPPROTO_UDP, "%s", msg); | ||
51 | } | ||
52 | |||
53 | static bool udp_error(struct sk_buff *skb, | ||
54 | unsigned int dataoff, | ||
55 | const struct nf_hook_state *state) | ||
56 | { | ||
57 | unsigned int udplen = skb->len - dataoff; | ||
58 | const struct udphdr *hdr; | ||
59 | struct udphdr _hdr; | ||
60 | |||
61 | /* Header is too small? */ | ||
62 | hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
63 | if (!hdr) { | ||
64 | udp_error_log(skb, state, "short packet"); | ||
65 | return true; | ||
66 | } | ||
67 | |||
68 | /* Truncated/malformed packets */ | ||
69 | if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { | ||
70 | udp_error_log(skb, state, "truncated/malformed packet"); | ||
71 | return true; | ||
72 | } | ||
73 | |||
74 | /* Packet with no checksum */ | ||
75 | if (!hdr->check) | ||
76 | return false; | ||
77 | |||
78 | /* Checksum invalid? Ignore. | ||
79 | * We skip checking packets on the outgoing path | ||
80 | * because the checksum is assumed to be correct. | ||
81 | * FIXME: Source route IP option packets --RR */ | ||
82 | if (state->hook == NF_INET_PRE_ROUTING && | ||
83 | state->net->ct.sysctl_checksum && | ||
84 | nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { | ||
85 | udp_error_log(skb, state, "bad checksum"); | ||
86 | return true; | ||
87 | } | ||
88 | |||
89 | return false; | ||
90 | } | ||
91 | |||
45 | /* Returns verdict for packet, and may modify conntracktype */ | 92 | /* Returns verdict for packet, and may modify conntracktype */ |
46 | static int udp_packet(struct nf_conn *ct, | 93 | static int udp_packet(struct nf_conn *ct, |
47 | const struct sk_buff *skb, | 94 | struct sk_buff *skb, |
48 | unsigned int dataoff, | 95 | unsigned int dataoff, |
49 | enum ip_conntrack_info ctinfo, | 96 | enum ip_conntrack_info ctinfo, |
50 | const struct nf_hook_state *state) | 97 | const struct nf_hook_state *state) |
51 | { | 98 | { |
52 | unsigned int *timeouts; | 99 | unsigned int *timeouts; |
53 | 100 | ||
101 | if (udp_error(skb, dataoff, state)) | ||
102 | return -NF_ACCEPT; | ||
103 | |||
54 | timeouts = nf_ct_timeout_lookup(ct); | 104 | timeouts = nf_ct_timeout_lookup(ct); |
55 | if (!timeouts) | 105 | if (!timeouts) |
56 | timeouts = udp_get_timeouts(nf_ct_net(ct)); | 106 | timeouts = udp_get_timeouts(nf_ct_net(ct)); |
57 | 107 | ||
58 | /* If we've seen traffic both ways, this is some kind of UDP | 108 | /* If we've seen traffic both ways, this is some kind of UDP |
59 | stream. Extend timeout. */ | 109 | stream. Extend timeout. */ |
60 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | 110 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
61 | nf_ct_refresh_acct(ct, ctinfo, skb, | 111 | nf_ct_refresh_acct(ct, ctinfo, skb, |
62 | timeouts[UDP_CT_REPLIED]); | 112 | timeouts[UDP_CT_REPLIED]); |
63 | /* Also, more likely to be important, and not a probe */ | 113 | /* Also, more likely to be important, and not a probe */ |
64 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) | 114 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) |
65 | nf_conntrack_event_cache(IPCT_ASSURED, ct); | 115 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
66 | } else { | 116 | } else { |
67 | nf_ct_refresh_acct(ct, ctinfo, skb, | 117 | nf_ct_refresh_acct(ct, ctinfo, skb, |
68 | timeouts[UDP_CT_UNREPLIED]); | 118 | timeouts[UDP_CT_UNREPLIED]); |
69 | } | 119 | } |
70 | return NF_ACCEPT; | 120 | return NF_ACCEPT; |
71 | } | 121 | } |
72 | 122 | ||
73 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE | 123 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE |
74 | static void udplite_error_log(const struct sk_buff *skb, | 124 | static void udplite_error_log(const struct sk_buff *skb, |
75 | const struct nf_hook_state *state, | 125 | const struct nf_hook_state *state, |
76 | const char *msg) | 126 | const char *msg) |
77 | { | 127 | { |
78 | nf_l4proto_log_invalid(skb, state->net, state->pf, | 128 | nf_l4proto_log_invalid(skb, state->net, state->pf, |
79 | IPPROTO_UDPLITE, "%s", msg); | 129 | IPPROTO_UDPLITE, "%s", msg); |
80 | } | 130 | } |
81 | 131 | ||
82 | static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb, | 132 | static bool udplite_error(struct sk_buff *skb, |
83 | unsigned int dataoff, | 133 | unsigned int dataoff, |
84 | const struct nf_hook_state *state) | 134 | const struct nf_hook_state *state) |
85 | { | 135 | { |
86 | unsigned int udplen = skb->len - dataoff; | 136 | unsigned int udplen = skb->len - dataoff; |
87 | const struct udphdr *hdr; | 137 | const struct udphdr *hdr; |
88 | struct udphdr _hdr; | 138 | struct udphdr _hdr; |
89 | unsigned int cscov; | 139 | unsigned int cscov; |
90 | 140 | ||
91 | /* Header is too small? */ | 141 | /* Header is too small? */ |
92 | hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | 142 | hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); |
93 | if (!hdr) { | 143 | if (!hdr) { |
94 | udplite_error_log(skb, state, "short packet"); | 144 | udplite_error_log(skb, state, "short packet"); |
95 | return -NF_ACCEPT; | 145 | return true; |
96 | } | 146 | } |
97 | 147 | ||
98 | cscov = ntohs(hdr->len); | 148 | cscov = ntohs(hdr->len); |
99 | if (cscov == 0) { | 149 | if (cscov == 0) { |
100 | cscov = udplen; | 150 | cscov = udplen; |
101 | } else if (cscov < sizeof(*hdr) || cscov > udplen) { | 151 | } else if (cscov < sizeof(*hdr) || cscov > udplen) { |
102 | udplite_error_log(skb, state, "invalid checksum coverage"); | 152 | udplite_error_log(skb, state, "invalid checksum coverage"); |
103 | return -NF_ACCEPT; | 153 | return true; |
104 | } | 154 | } |
105 | 155 | ||
106 | /* UDPLITE mandates checksums */ | 156 | /* UDPLITE mandates checksums */ |
107 | if (!hdr->check) { | 157 | if (!hdr->check) { |
108 | udplite_error_log(skb, state, "checksum missing"); | 158 | udplite_error_log(skb, state, "checksum missing"); |
109 | return -NF_ACCEPT; | 159 | return true; |
110 | } | 160 | } |
111 | 161 | ||
112 | /* Checksum invalid? Ignore. */ | 162 | /* Checksum invalid? Ignore. */ |
113 | if (state->hook == NF_INET_PRE_ROUTING && | 163 | if (state->hook == NF_INET_PRE_ROUTING && |
114 | state->net->ct.sysctl_checksum && | 164 | state->net->ct.sysctl_checksum && |
115 | nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP, | 165 | nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP, |
116 | state->pf)) { | 166 | state->pf)) { |
117 | udplite_error_log(skb, state, "bad checksum"); | 167 | udplite_error_log(skb, state, "bad checksum"); |
118 | return -NF_ACCEPT; | 168 | return true; |
119 | } | 169 | } |
120 | 170 | ||
121 | return NF_ACCEPT; | 171 | return false; |
122 | } | 172 | } |
123 | #endif | ||
124 | 173 | ||
125 | static void udp_error_log(const struct sk_buff *skb, | 174 | /* Returns verdict for packet, and may modify conntracktype */ |
126 | const struct nf_hook_state *state, | 175 | static int udplite_packet(struct nf_conn *ct, |
127 | const char *msg) | 176 | struct sk_buff *skb, |
177 | unsigned int dataoff, | ||
178 | enum ip_conntrack_info ctinfo, | ||
179 | const struct nf_hook_state *state) | ||
128 | { | 180 | { |
129 | nf_l4proto_log_invalid(skb, state->net, state->pf, | 181 | unsigned int *timeouts; |
130 | IPPROTO_UDP, "%s", msg); | ||
131 | } | ||
132 | 182 | ||
133 | static int udp_error(struct nf_conn *tmpl, struct sk_buff *skb, | 183 | if (udplite_error(skb, dataoff, state)) |
134 | unsigned int dataoff, | ||
135 | const struct nf_hook_state *state) | ||
136 | { | ||
137 | unsigned int udplen = skb->len - dataoff; | ||
138 | const struct udphdr *hdr; | ||
139 | struct udphdr _hdr; | ||
140 | |||
141 | /* Header is too small? */ | ||
142 | hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
143 | if (hdr == NULL) { | ||
144 | udp_error_log(skb, state, "short packet"); | ||
145 | return -NF_ACCEPT; | 184 | return -NF_ACCEPT; |
146 | } | ||
147 | 185 | ||
148 | /* Truncated/malformed packets */ | 186 | timeouts = nf_ct_timeout_lookup(ct); |
149 | if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { | 187 | if (!timeouts) |
150 | udp_error_log(skb, state, "truncated/malformed packet"); | 188 | timeouts = udp_get_timeouts(nf_ct_net(ct)); |
151 | return -NF_ACCEPT; | ||
152 | } | ||
153 | 189 | ||
154 | /* Packet with no checksum */ | 190 | /* If we've seen traffic both ways, this is some kind of UDP |
155 | if (!hdr->check) | 191 | stream. Extend timeout. */ |
156 | return NF_ACCEPT; | 192 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
157 | 193 | nf_ct_refresh_acct(ct, ctinfo, skb, | |
158 | /* Checksum invalid? Ignore. | 194 | timeouts[UDP_CT_REPLIED]); |
159 | * We skip checking packets on the outgoing path | 195 | /* Also, more likely to be important, and not a probe */ |
160 | * because the checksum is assumed to be correct. | 196 | if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) |
161 | * FIXME: Source route IP option packets --RR */ | 197 | nf_conntrack_event_cache(IPCT_ASSURED, ct); |
162 | if (state->net->ct.sysctl_checksum && state->hook == NF_INET_PRE_ROUTING && | 198 | } else { |
163 | nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) { | 199 | nf_ct_refresh_acct(ct, ctinfo, skb, |
164 | udp_error_log(skb, state, "bad checksum"); | 200 | timeouts[UDP_CT_UNREPLIED]); |
165 | return -NF_ACCEPT; | ||
166 | } | 201 | } |
167 | |||
168 | return NF_ACCEPT; | 202 | return NF_ACCEPT; |
169 | } | 203 | } |
204 | #endif | ||
170 | 205 | ||
171 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 206 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
172 | 207 | ||
173 | #include <linux/netfilter/nfnetlink.h> | 208 | #include <linux/netfilter/nfnetlink.h> |
174 | #include <linux/netfilter/nfnetlink_cttimeout.h> | 209 | #include <linux/netfilter/nfnetlink_cttimeout.h> |
175 | 210 | ||
176 | static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], | 211 | static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], |
177 | struct net *net, void *data) | 212 | struct net *net, void *data) |
178 | { | 213 | { |
179 | unsigned int *timeouts = data; | 214 | unsigned int *timeouts = data; |
180 | struct nf_udp_net *un = udp_pernet(net); | 215 | struct nf_udp_net *un = udp_pernet(net); |
181 | 216 | ||
182 | if (!timeouts) | 217 | if (!timeouts) |
183 | timeouts = un->timeouts; | 218 | timeouts = un->timeouts; |
184 | 219 | ||
185 | /* set default timeouts for UDP. */ | 220 | /* set default timeouts for UDP. */ |
186 | timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED]; | 221 | timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED]; |
187 | timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED]; | 222 | timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED]; |
188 | 223 | ||
189 | if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) { | 224 | if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) { |
190 | timeouts[UDP_CT_UNREPLIED] = | 225 | timeouts[UDP_CT_UNREPLIED] = |
191 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ; | 226 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ; |
192 | } | 227 | } |
193 | if (tb[CTA_TIMEOUT_UDP_REPLIED]) { | 228 | if (tb[CTA_TIMEOUT_UDP_REPLIED]) { |
194 | timeouts[UDP_CT_REPLIED] = | 229 | timeouts[UDP_CT_REPLIED] = |
195 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ; | 230 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ; |
196 | } | 231 | } |
197 | return 0; | 232 | return 0; |
198 | } | 233 | } |
199 | 234 | ||
200 | static int | 235 | static int |
201 | udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | 236 | udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) |
202 | { | 237 | { |
203 | const unsigned int *timeouts = data; | 238 | const unsigned int *timeouts = data; |
204 | 239 | ||
205 | if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED, | 240 | if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED, |
206 | htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) || | 241 | htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) || |
207 | nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED, | 242 | nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED, |
208 | htonl(timeouts[UDP_CT_REPLIED] / HZ))) | 243 | htonl(timeouts[UDP_CT_REPLIED] / HZ))) |
209 | goto nla_put_failure; | 244 | goto nla_put_failure; |
210 | return 0; | 245 | return 0; |
211 | 246 | ||
212 | nla_put_failure: | 247 | nla_put_failure: |
213 | return -ENOSPC; | 248 | return -ENOSPC; |
214 | } | 249 | } |
215 | 250 | ||
216 | static const struct nla_policy | 251 | static const struct nla_policy |
217 | udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = { | 252 | udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = { |
218 | [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 }, | 253 | [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 }, |
219 | [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 }, | 254 | [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 }, |
220 | }; | 255 | }; |
221 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 256 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
222 | 257 | ||
223 | #ifdef CONFIG_SYSCTL | 258 | #ifdef CONFIG_SYSCTL |
224 | static struct ctl_table udp_sysctl_table[] = { | 259 | static struct ctl_table udp_sysctl_table[] = { |
225 | { | 260 | { |
226 | .procname = "nf_conntrack_udp_timeout", | 261 | .procname = "nf_conntrack_udp_timeout", |
227 | .maxlen = sizeof(unsigned int), | 262 | .maxlen = sizeof(unsigned int), |
228 | .mode = 0644, | 263 | .mode = 0644, |
229 | .proc_handler = proc_dointvec_jiffies, | 264 | .proc_handler = proc_dointvec_jiffies, |
230 | }, | 265 | }, |
231 | { | 266 | { |
232 | .procname = "nf_conntrack_udp_timeout_stream", | 267 | .procname = "nf_conntrack_udp_timeout_stream", |
233 | .maxlen = sizeof(unsigned int), | 268 | .maxlen = sizeof(unsigned int), |
234 | .mode = 0644, | 269 | .mode = 0644, |
235 | .proc_handler = proc_dointvec_jiffies, | 270 | .proc_handler = proc_dointvec_jiffies, |
236 | }, | 271 | }, |
237 | { } | 272 | { } |
238 | }; | 273 | }; |
239 | #endif /* CONFIG_SYSCTL */ | 274 | #endif /* CONFIG_SYSCTL */ |
240 | 275 | ||
241 | static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn, | 276 | static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn, |
242 | struct nf_udp_net *un) | 277 | struct nf_udp_net *un) |
243 | { | 278 | { |
244 | #ifdef CONFIG_SYSCTL | 279 | #ifdef CONFIG_SYSCTL |
245 | if (pn->ctl_table) | 280 | if (pn->ctl_table) |
246 | return 0; | 281 | return 0; |
247 | pn->ctl_table = kmemdup(udp_sysctl_table, | 282 | pn->ctl_table = kmemdup(udp_sysctl_table, |
248 | sizeof(udp_sysctl_table), | 283 | sizeof(udp_sysctl_table), |
249 | GFP_KERNEL); | 284 | GFP_KERNEL); |
250 | if (!pn->ctl_table) | 285 | if (!pn->ctl_table) |
251 | return -ENOMEM; | 286 | return -ENOMEM; |
252 | pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED]; | 287 | pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED]; |
253 | pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED]; | 288 | pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED]; |
254 | #endif | 289 | #endif |
255 | return 0; | 290 | return 0; |
256 | } | 291 | } |
257 | 292 | ||
258 | static int udp_init_net(struct net *net, u_int16_t proto) | 293 | static int udp_init_net(struct net *net, u_int16_t proto) |
259 | { | 294 | { |
260 | struct nf_udp_net *un = udp_pernet(net); | 295 | struct nf_udp_net *un = udp_pernet(net); |
261 | struct nf_proto_net *pn = &un->pn; | 296 | struct nf_proto_net *pn = &un->pn; |
262 | 297 | ||
263 | if (!pn->users) { | 298 | if (!pn->users) { |
264 | int i; | 299 | int i; |
265 | 300 | ||
266 | for (i = 0; i < UDP_CT_MAX; i++) | 301 | for (i = 0; i < UDP_CT_MAX; i++) |
267 | un->timeouts[i] = udp_timeouts[i]; | 302 | un->timeouts[i] = udp_timeouts[i]; |
268 | } | 303 | } |
269 | 304 | ||
270 | return udp_kmemdup_sysctl_table(pn, un); | 305 | return udp_kmemdup_sysctl_table(pn, un); |
271 | } | 306 | } |
272 | 307 | ||
273 | static struct nf_proto_net *udp_get_net_proto(struct net *net) | 308 | static struct nf_proto_net *udp_get_net_proto(struct net *net) |
274 | { | 309 | { |
275 | return &net->ct.nf_ct_proto.udp.pn; | 310 | return &net->ct.nf_ct_proto.udp.pn; |
276 | } | 311 | } |
277 | 312 | ||
278 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 = | 313 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 = |
279 | { | 314 | { |
280 | .l3proto = PF_INET, | 315 | .l3proto = PF_INET, |
281 | .l4proto = IPPROTO_UDP, | 316 | .l4proto = IPPROTO_UDP, |
282 | .allow_clash = true, | 317 | .allow_clash = true, |
283 | .packet = udp_packet, | 318 | .packet = udp_packet, |
284 | .error = udp_error, | ||
285 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 319 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
286 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 320 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
287 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 321 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
288 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 322 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
289 | .nla_policy = nf_ct_port_nla_policy, | 323 | .nla_policy = nf_ct_port_nla_policy, |
290 | #endif | 324 | #endif |
291 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 325 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
292 | .ctnl_timeout = { | 326 | .ctnl_timeout = { |
293 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | 327 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, |
294 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | 328 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, |
295 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | 329 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, |
296 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | 330 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, |
297 | .nla_policy = udp_timeout_nla_policy, | 331 | .nla_policy = udp_timeout_nla_policy, |
298 | }, | 332 | }, |
299 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 333 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
300 | .init_net = udp_init_net, | 334 | .init_net = udp_init_net, |
301 | .get_net_proto = udp_get_net_proto, | 335 | .get_net_proto = udp_get_net_proto, |
302 | }; | 336 | }; |
303 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); | 337 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); |
304 | 338 | ||
305 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE | 339 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE |
306 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 = | 340 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 = |
307 | { | 341 | { |
308 | .l3proto = PF_INET, | 342 | .l3proto = PF_INET, |
309 | .l4proto = IPPROTO_UDPLITE, | 343 | .l4proto = IPPROTO_UDPLITE, |
310 | .allow_clash = true, | 344 | .allow_clash = true, |
311 | .packet = udp_packet, | 345 | .packet = udplite_packet, |
312 | .error = udplite_error, | ||
313 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 346 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
314 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 347 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
315 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 348 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
316 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 349 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
317 | .nla_policy = nf_ct_port_nla_policy, | 350 | .nla_policy = nf_ct_port_nla_policy, |
318 | #endif | 351 | #endif |
319 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 352 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
320 | .ctnl_timeout = { | 353 | .ctnl_timeout = { |
321 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | 354 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, |
322 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | 355 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, |
323 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | 356 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, |
324 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | 357 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, |
325 | .nla_policy = udp_timeout_nla_policy, | 358 | .nla_policy = udp_timeout_nla_policy, |
326 | }, | 359 | }, |
327 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 360 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
328 | .init_net = udp_init_net, | 361 | .init_net = udp_init_net, |
329 | .get_net_proto = udp_get_net_proto, | 362 | .get_net_proto = udp_get_net_proto, |
330 | }; | 363 | }; |
331 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4); | 364 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4); |
332 | #endif | 365 | #endif |
333 | 366 | ||
334 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 = | 367 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 = |
335 | { | 368 | { |
336 | .l3proto = PF_INET6, | 369 | .l3proto = PF_INET6, |
337 | .l4proto = IPPROTO_UDP, | 370 | .l4proto = IPPROTO_UDP, |
338 | .allow_clash = true, | 371 | .allow_clash = true, |
339 | .packet = udp_packet, | 372 | .packet = udp_packet, |
340 | .error = udp_error, | ||
341 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | 373 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
342 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 374 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
343 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 375 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
344 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 376 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
345 | .nla_policy = nf_ct_port_nla_policy, | 377 | .nla_policy = nf_ct_port_nla_policy, |
346 | #endif | 378 | #endif |
347 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 379 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
348 | .ctnl_timeout = { | 380 | .ctnl_timeout = { |
349 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | 381 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, |
350 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | 382 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, |
351 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | 383 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, |
352 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | 384 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, |
353 | .nla_policy = udp_timeout_nla_policy, | 385 | .nla_policy = udp_timeout_nla_policy, |
354 | }, | 386 | }, |
355 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 387 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
356 | .init_net = udp_init_net, | 388 | .init_net = udp_init_net, |
357 | .get_net_proto = udp_get_net_proto, | 389 | .get_net_proto = udp_get_net_proto, |
358 | }; | 390 | }; |
359 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); | 391 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); |
360 | 392 | ||
361 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE | 393 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE |
362 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 = | 394 | const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 = |
363 | { | 395 | { |
364 | .l3proto = PF_INET6, | 396 | .l3proto = PF_INET6, |
365 | .l4proto = IPPROTO_UDPLITE, | 397 | .l4proto = IPPROTO_UDPLITE, |
366 | .allow_clash = true, | 398 | .allow_clash = true, |