aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2007-12-18 01:28:00 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:58:50 -0500
commit13eae15a244bb29beaa47bf86a24fd29ca7f8a4c (patch)
tree27a1a1e6498033c5aa440ced5242016fd808c560
parent170080645dac61816455afad807ffeb326ce79e8 (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.h4
-rw-r--r--include/linux/netfilter/nfnetlink_conntrack.h10
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c3
-rw-r--r--net/netfilter/nf_conntrack_netlink.c124
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
134enum ip_conntrack_expect_events { 138enum 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
124enum 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
122enum ctattr_expect { 132enum 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
258static inline int
259dump_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
279nla_put_failure:
280 return -1;
281}
282
283static inline int
284ctnetlink_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
257static inline int 306static inline int
258ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) 307ctnetlink_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
993static inline int
994change_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
1021static int
1022ctnetlink_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
938static int 1052static int
939ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) 1053ctnetlink_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