aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-09-21 10:52:08 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-09-24 08:29:40 -0400
commit7be54ca4764bdead40bee7b645a72718c20ff2c8 (patch)
treeda27254d7fe7dd96555668d5369a0e2dcc9bc769
parent54eb3df3a7d01b6cd395bdc1098280f2f93fbec5 (diff)
netfilter: nf_ct_ftp: add sequence tracking pickup facility for injected entries
This patch allows the FTP helper to pickup the sequence tracking from the first packet seen. This is useful to fix the breakage of the first FTP command after the failover while using conntrackd to synchronize states. The seq_aft_nl_num field in struct nf_ct_ftp_info has been shrinked to 16-bits (enough for what it does), so we can use the remaining 16-bits to store the flags while using the same size for the private FTP helper data. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/linux/netfilter/nf_conntrack_ftp.h6
-rw-r--r--net/netfilter/nf_conntrack_ftp.c21
-rw-r--r--net/netfilter/nf_conntrack_netlink.c4
-rw-r--r--net/netfilter/nfnetlink_cthelper.c3
4 files changed, 31 insertions, 3 deletions
diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h
index 28f18df36525..8faf3f792d13 100644
--- a/include/linux/netfilter/nf_conntrack_ftp.h
+++ b/include/linux/netfilter/nf_conntrack_ftp.h
@@ -18,13 +18,17 @@ enum nf_ct_ftp_type {
18 18
19#define FTP_PORT 21 19#define FTP_PORT 21
20 20
21#define NF_CT_FTP_SEQ_PICKUP (1 << 0)
22
21#define NUM_SEQ_TO_REMEMBER 2 23#define NUM_SEQ_TO_REMEMBER 2
22/* This structure exists only once per master */ 24/* This structure exists only once per master */
23struct nf_ct_ftp_master { 25struct nf_ct_ftp_master {
24 /* Valid seq positions for cmd matching after newline */ 26 /* Valid seq positions for cmd matching after newline */
25 u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; 27 u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
26 /* 0 means seq_match_aft_nl not set */ 28 /* 0 means seq_match_aft_nl not set */
27 int seq_aft_nl_num[IP_CT_DIR_MAX]; 29 u_int16_t seq_aft_nl_num[IP_CT_DIR_MAX];
30 /* pickup sequence tracking, useful for conntrackd */
31 u_int16_t flags[IP_CT_DIR_MAX];
28}; 32};
29 33
30struct nf_conntrack_expect; 34struct nf_conntrack_expect;
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index f8cc26ad4456..1ce3befb7c8a 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -396,6 +396,12 @@ static int help(struct sk_buff *skb,
396 396
397 /* Look up to see if we're just after a \n. */ 397 /* Look up to see if we're just after a \n. */
398 if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) { 398 if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) {
399 /* We're picking up this, clear flags and let it continue */
400 if (unlikely(ct_ftp_info->flags[dir] & NF_CT_FTP_SEQ_PICKUP)) {
401 ct_ftp_info->flags[dir] ^= NF_CT_FTP_SEQ_PICKUP;
402 goto skip_nl_seq;
403 }
404
399 /* Now if this ends in \n, update ftp info. */ 405 /* Now if this ends in \n, update ftp info. */
400 pr_debug("nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n", 406 pr_debug("nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n",
401 ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)", 407 ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)",
@@ -406,6 +412,7 @@ static int help(struct sk_buff *skb,
406 goto out_update_nl; 412 goto out_update_nl;
407 } 413 }
408 414
415skip_nl_seq:
409 /* Initialize IP/IPv6 addr to expected address (it's not mentioned 416 /* Initialize IP/IPv6 addr to expected address (it's not mentioned
410 in EPSV responses) */ 417 in EPSV responses) */
411 cmd.l3num = nf_ct_l3num(ct); 418 cmd.l3num = nf_ct_l3num(ct);
@@ -512,6 +519,19 @@ out_update_nl:
512 return ret; 519 return ret;
513} 520}
514 521
522static int nf_ct_ftp_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
523{
524 struct nf_ct_ftp_master *ftp = nfct_help_data(ct);
525
526 /* This conntrack has been injected from user-space, always pick up
527 * sequence tracking. Otherwise, the first FTP command after the
528 * failover breaks.
529 */
530 ftp->flags[IP_CT_DIR_ORIGINAL] |= NF_CT_FTP_SEQ_PICKUP;
531 ftp->flags[IP_CT_DIR_REPLY] |= NF_CT_FTP_SEQ_PICKUP;
532 return 0;
533}
534
515static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly; 535static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
516 536
517static const struct nf_conntrack_expect_policy ftp_exp_policy = { 537static const struct nf_conntrack_expect_policy ftp_exp_policy = {
@@ -561,6 +581,7 @@ static int __init nf_conntrack_ftp_init(void)
561 ftp[i][j].expect_policy = &ftp_exp_policy; 581 ftp[i][j].expect_policy = &ftp_exp_policy;
562 ftp[i][j].me = THIS_MODULE; 582 ftp[i][j].me = THIS_MODULE;
563 ftp[i][j].help = help; 583 ftp[i][j].help = help;
584 ftp[i][j].from_nlattr = nf_ct_ftp_from_nlattr;
564 if (ports[i] == FTP_PORT) 585 if (ports[i] == FTP_PORT)
565 sprintf(ftp[i][j].name, "ftp"); 586 sprintf(ftp[i][j].name, "ftp");
566 else 587 else
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 2dcd080b8c4f..7bbfb3deea30 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1238,7 +1238,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
1238 if (help) { 1238 if (help) {
1239 if (help->helper == helper) { 1239 if (help->helper == helper) {
1240 /* update private helper data if allowed. */ 1240 /* update private helper data if allowed. */
1241 if (helper->from_nlattr && helpinfo) 1241 if (helper->from_nlattr)
1242 helper->from_nlattr(helpinfo, ct); 1242 helper->from_nlattr(helpinfo, ct);
1243 return 0; 1243 return 0;
1244 } else 1244 } else
@@ -1467,7 +1467,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
1467 goto err2; 1467 goto err2;
1468 } 1468 }
1469 /* set private helper data if allowed. */ 1469 /* set private helper data if allowed. */
1470 if (helper->from_nlattr && helpinfo) 1470 if (helper->from_nlattr)
1471 helper->from_nlattr(helpinfo, ct); 1471 helper->from_nlattr(helpinfo, ct);
1472 1472
1473 /* not in hash table yet so not strictly necessary */ 1473 /* not in hash table yet so not strictly necessary */
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 3678073360a3..945950a8b1f1 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -85,6 +85,9 @@ nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
85{ 85{
86 const struct nf_conn_help *help = nfct_help(ct); 86 const struct nf_conn_help *help = nfct_help(ct);
87 87
88 if (attr == NULL)
89 return -EINVAL;
90
88 if (help->helper->data_len == 0) 91 if (help->helper->data_len == 0)
89 return -EINVAL; 92 return -EINVAL;
90 93