diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2007-12-18 01:28:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:58:50 -0500 |
commit | 13eae15a244bb29beaa47bf86a24fd29ca7f8a4c (patch) | |
tree | 27a1a1e6498033c5aa440ced5242016fd808c560 | |
parent | 170080645dac61816455afad807ffeb326ce79e8 (diff) |
[NETFILTER]: ctnetlink: add support for NAT sequence adjustments
The combination of NAT and helpers may produce TCP sequence adjustments.
In failover setups, this information needs to be replicated in order to
achieve a successful recovery of mangled, related connections. This patch is
particularly useful for conntrackd, see:
http://people.netfilter.org/pablo/conntrack-tools/
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter/nf_conntrack_common.h | 4 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink_conntrack.h | 10 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_helper.c | 3 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 124 |
4 files changed, 140 insertions, 1 deletions
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 9e0dae07861..19747e8f71c 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h | |||
@@ -129,6 +129,10 @@ enum ip_conntrack_events | |||
129 | /* Mark is set */ | 129 | /* Mark is set */ |
130 | IPCT_MARK_BIT = 12, | 130 | IPCT_MARK_BIT = 12, |
131 | IPCT_MARK = (1 << IPCT_MARK_BIT), | 131 | IPCT_MARK = (1 << IPCT_MARK_BIT), |
132 | |||
133 | /* NAT sequence adjustment */ | ||
134 | IPCT_NATSEQADJ_BIT = 13, | ||
135 | IPCT_NATSEQADJ = (1 << IPCT_NATSEQADJ_BIT), | ||
132 | }; | 136 | }; |
133 | 137 | ||
134 | enum ip_conntrack_expect_events { | 138 | enum ip_conntrack_expect_events { |
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 4affa3fe78e..c19d976b1b7 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h | |||
@@ -37,6 +37,8 @@ enum ctattr_type { | |||
37 | CTA_ID, | 37 | CTA_ID, |
38 | CTA_NAT_DST, | 38 | CTA_NAT_DST, |
39 | CTA_TUPLE_MASTER, | 39 | CTA_TUPLE_MASTER, |
40 | CTA_NAT_SEQ_ADJ_ORIG, | ||
41 | CTA_NAT_SEQ_ADJ_REPLY, | ||
40 | __CTA_MAX | 42 | __CTA_MAX |
41 | }; | 43 | }; |
42 | #define CTA_MAX (__CTA_MAX - 1) | 44 | #define CTA_MAX (__CTA_MAX - 1) |
@@ -119,6 +121,14 @@ enum ctattr_protonat { | |||
119 | }; | 121 | }; |
120 | #define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1) | 122 | #define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1) |
121 | 123 | ||
124 | enum ctattr_natseq { | ||
125 | CTA_NAT_SEQ_CORRECTION_POS, | ||
126 | CTA_NAT_SEQ_OFFSET_BEFORE, | ||
127 | CTA_NAT_SEQ_OFFSET_AFTER, | ||
128 | __CTA_NAT_SEQ_MAX | ||
129 | }; | ||
130 | #define CTA_NAT_SEQ_MAX (__CTA_NAT_SEQ_MAX - 1) | ||
131 | |||
122 | enum ctattr_expect { | 132 | enum ctattr_expect { |
123 | CTA_EXPECT_UNSPEC, | 133 | CTA_EXPECT_UNSPEC, |
124 | CTA_EXPECT_MASTER, | 134 | CTA_EXPECT_MASTER, |
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 53f79a310b4..d24f3d94739 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/netfilter_ipv4.h> | 20 | #include <linux/netfilter_ipv4.h> |
21 | #include <net/netfilter/nf_conntrack.h> | 21 | #include <net/netfilter/nf_conntrack.h> |
22 | #include <net/netfilter/nf_conntrack_helper.h> | 22 | #include <net/netfilter/nf_conntrack_helper.h> |
23 | #include <net/netfilter/nf_conntrack_ecache.h> | ||
23 | #include <net/netfilter/nf_conntrack_expect.h> | 24 | #include <net/netfilter/nf_conntrack_expect.h> |
24 | #include <net/netfilter/nf_nat.h> | 25 | #include <net/netfilter/nf_nat.h> |
25 | #include <net/netfilter/nf_nat_protocol.h> | 26 | #include <net/netfilter/nf_nat_protocol.h> |
@@ -191,6 +192,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, | |||
191 | /* Tell TCP window tracking about seq change */ | 192 | /* Tell TCP window tracking about seq change */ |
192 | nf_conntrack_tcp_update(skb, ip_hdrlen(skb), | 193 | nf_conntrack_tcp_update(skb, ip_hdrlen(skb), |
193 | ct, CTINFO2DIR(ctinfo)); | 194 | ct, CTINFO2DIR(ctinfo)); |
195 | |||
196 | nf_conntrack_event_cache(IPCT_NATSEQADJ, skb); | ||
194 | } | 197 | } |
195 | return 1; | 198 | return 1; |
196 | } | 199 | } |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index a15971e9923..d7da167ef1b 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -254,6 +254,55 @@ nla_put_failure: | |||
254 | #define ctnetlink_dump_mark(a, b) (0) | 254 | #define ctnetlink_dump_mark(a, b) (0) |
255 | #endif | 255 | #endif |
256 | 256 | ||
257 | #ifdef CONFIG_NF_NAT_NEEDED | ||
258 | static inline int | ||
259 | dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) | ||
260 | { | ||
261 | __be32 tmp; | ||
262 | struct nlattr *nest_parms; | ||
263 | |||
264 | nest_parms = nla_nest_start(skb, type | NLA_F_NESTED); | ||
265 | if (!nest_parms) | ||
266 | goto nla_put_failure; | ||
267 | |||
268 | tmp = htonl(natseq->correction_pos); | ||
269 | NLA_PUT(skb, CTA_NAT_SEQ_CORRECTION_POS, sizeof(tmp), &tmp); | ||
270 | tmp = htonl(natseq->offset_before); | ||
271 | NLA_PUT(skb, CTA_NAT_SEQ_OFFSET_BEFORE, sizeof(tmp), &tmp); | ||
272 | tmp = htonl(natseq->offset_after); | ||
273 | NLA_PUT(skb, CTA_NAT_SEQ_OFFSET_AFTER, sizeof(tmp), &tmp); | ||
274 | |||
275 | nla_nest_end(skb, nest_parms); | ||
276 | |||
277 | return 0; | ||
278 | |||
279 | nla_put_failure: | ||
280 | return -1; | ||
281 | } | ||
282 | |||
283 | static inline int | ||
284 | ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) | ||
285 | { | ||
286 | struct nf_nat_seq *natseq; | ||
287 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
288 | |||
289 | if (!(ct->status & IPS_SEQ_ADJUST) || !nat) | ||
290 | return 0; | ||
291 | |||
292 | natseq = &nat->seq[IP_CT_DIR_ORIGINAL]; | ||
293 | if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_ORIG) == -1) | ||
294 | return -1; | ||
295 | |||
296 | natseq = &nat->seq[IP_CT_DIR_REPLY]; | ||
297 | if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_REPLY) == -1) | ||
298 | return -1; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | #else | ||
303 | #define ctnetlink_dump_nat_seq_adj(a, b) (0) | ||
304 | #endif | ||
305 | |||
257 | static inline int | 306 | static inline int |
258 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) | 307 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) |
259 | { | 308 | { |
@@ -321,7 +370,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | |||
321 | ctnetlink_dump_helpinfo(skb, ct) < 0 || | 370 | ctnetlink_dump_helpinfo(skb, ct) < 0 || |
322 | ctnetlink_dump_mark(skb, ct) < 0 || | 371 | ctnetlink_dump_mark(skb, ct) < 0 || |
323 | ctnetlink_dump_id(skb, ct) < 0 || | 372 | ctnetlink_dump_id(skb, ct) < 0 || |
324 | ctnetlink_dump_use(skb, ct) < 0) | 373 | ctnetlink_dump_use(skb, ct) < 0 || |
374 | ctnetlink_dump_nat_seq_adj(skb, ct) < 0) | ||
325 | goto nla_put_failure; | 375 | goto nla_put_failure; |
326 | 376 | ||
327 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; | 377 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
@@ -424,6 +474,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
424 | (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | 474 | (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || |
425 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) | 475 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) |
426 | goto nla_put_failure; | 476 | goto nla_put_failure; |
477 | |||
478 | if (events & IPCT_NATSEQADJ && | ||
479 | ctnetlink_dump_nat_seq_adj(skb, ct) < 0) | ||
480 | goto nla_put_failure; | ||
427 | } | 481 | } |
428 | 482 | ||
429 | nlh->nlmsg_len = skb->tail - b; | 483 | nlh->nlmsg_len = skb->tail - b; |
@@ -935,6 +989,66 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) | |||
935 | return err; | 989 | return err; |
936 | } | 990 | } |
937 | 991 | ||
992 | #ifdef CONFIG_NF_NAT_NEEDED | ||
993 | static inline int | ||
994 | change_nat_seq_adj(struct nf_nat_seq *natseq, struct nlattr *attr) | ||
995 | { | ||
996 | struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; | ||
997 | |||
998 | nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, NULL); | ||
999 | |||
1000 | if (!cda[CTA_NAT_SEQ_CORRECTION_POS]) | ||
1001 | return -EINVAL; | ||
1002 | |||
1003 | natseq->correction_pos = | ||
1004 | ntohl(*(__be32 *)nla_data(cda[CTA_NAT_SEQ_CORRECTION_POS])); | ||
1005 | |||
1006 | if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE]) | ||
1007 | return -EINVAL; | ||
1008 | |||
1009 | natseq->offset_before = | ||
1010 | ntohl(*(__be32 *)nla_data(cda[CTA_NAT_SEQ_OFFSET_BEFORE])); | ||
1011 | |||
1012 | if (!cda[CTA_NAT_SEQ_OFFSET_AFTER]) | ||
1013 | return -EINVAL; | ||
1014 | |||
1015 | natseq->offset_after = | ||
1016 | ntohl(*(__be32 *)nla_data(cda[CTA_NAT_SEQ_OFFSET_AFTER])); | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static int | ||
1022 | ctnetlink_change_nat_seq_adj(struct nf_conn *ct, struct nlattr *cda[]) | ||
1023 | { | ||
1024 | int ret = 0; | ||
1025 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
1026 | |||
1027 | if (!nat) | ||
1028 | return 0; | ||
1029 | |||
1030 | if (cda[CTA_NAT_SEQ_ADJ_ORIG]) { | ||
1031 | ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_ORIGINAL], | ||
1032 | cda[CTA_NAT_SEQ_ADJ_ORIG]); | ||
1033 | if (ret < 0) | ||
1034 | return ret; | ||
1035 | |||
1036 | ct->status |= IPS_SEQ_ADJUST; | ||
1037 | } | ||
1038 | |||
1039 | if (cda[CTA_NAT_SEQ_ADJ_REPLY]) { | ||
1040 | ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_REPLY], | ||
1041 | cda[CTA_NAT_SEQ_ADJ_REPLY]); | ||
1042 | if (ret < 0) | ||
1043 | return ret; | ||
1044 | |||
1045 | ct->status |= IPS_SEQ_ADJUST; | ||
1046 | } | ||
1047 | |||
1048 | return 0; | ||
1049 | } | ||
1050 | #endif | ||
1051 | |||
938 | static int | 1052 | static int |
939 | ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) | 1053 | ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) |
940 | { | 1054 | { |
@@ -969,6 +1083,14 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) | |||
969 | ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK])); | 1083 | ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK])); |
970 | #endif | 1084 | #endif |
971 | 1085 | ||
1086 | #ifdef CONFIG_NF_NAT_NEEDED | ||
1087 | if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { | ||
1088 | err = ctnetlink_change_nat_seq_adj(ct, cda); | ||
1089 | if (err < 0) | ||
1090 | return err; | ||
1091 | } | ||
1092 | #endif | ||
1093 | |||
972 | return 0; | 1094 | return 0; |
973 | } | 1095 | } |
974 | 1096 | ||