Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+31 -3
+5 -1
include/linux/netfilter/nf_conntrack_ftp.h
··· 18 18 19 19 #define FTP_PORT 21 20 20 21 + #define NF_CT_FTP_SEQ_PICKUP (1 << 0) 22 + 21 23 #define NUM_SEQ_TO_REMEMBER 2 22 24 /* This structure exists only once per master */ 23 25 struct nf_ct_ftp_master { 24 26 /* Valid seq positions for cmd matching after newline */ 25 27 u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; 26 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 30 34 struct nf_conntrack_expect;
+21
net/netfilter/nf_conntrack_ftp.c
··· 396 396 397 397 /* Look up to see if we're just after a \n. */ 398 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 405 /* Now if this ends in \n, update ftp info. */ 400 406 pr_debug("nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n", 401 407 ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)", ··· 412 406 goto out_update_nl; 413 407 } 414 408 409 + skip_nl_seq: 415 410 /* Initialize IP/IPv6 addr to expected address (it's not mentioned 416 411 in EPSV responses) */ 417 412 cmd.l3num = nf_ct_l3num(ct); ··· 519 512 return ret; 520 513 } 521 514 515 + static int nf_ct_ftp_from_nlattr(struct nlattr *attr, struct nf_conn *ct) 516 + { 517 + struct nf_ct_ftp_master *ftp = nfct_help_data(ct); 518 + 519 + /* This conntrack has been injected from user-space, always pick up 520 + * sequence tracking. Otherwise, the first FTP command after the 521 + * failover breaks. 522 + */ 523 + ftp->flags[IP_CT_DIR_ORIGINAL] |= NF_CT_FTP_SEQ_PICKUP; 524 + ftp->flags[IP_CT_DIR_REPLY] |= NF_CT_FTP_SEQ_PICKUP; 525 + return 0; 526 + } 527 + 522 528 static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly; 523 529 524 530 static const struct nf_conntrack_expect_policy ftp_exp_policy = { ··· 581 561 ftp[i][j].expect_policy = &ftp_exp_policy; 582 562 ftp[i][j].me = THIS_MODULE; 583 563 ftp[i][j].help = help; 564 + ftp[i][j].from_nlattr = nf_ct_ftp_from_nlattr; 584 565 if (ports[i] == FTP_PORT) 585 566 sprintf(ftp[i][j].name, "ftp"); 586 567 else
+2 -2
net/netfilter/nf_conntrack_netlink.c
··· 1238 1238 if (help) { 1239 1239 if (help->helper == helper) { 1240 1240 /* update private helper data if allowed. */ 1241 - if (helper->from_nlattr && helpinfo) 1241 + if (helper->from_nlattr) 1242 1242 helper->from_nlattr(helpinfo, ct); 1243 1243 return 0; 1244 1244 } else ··· 1467 1467 goto err2; 1468 1468 } 1469 1469 /* set private helper data if allowed. */ 1470 - if (helper->from_nlattr && helpinfo) 1470 + if (helper->from_nlattr) 1471 1471 helper->from_nlattr(helpinfo, ct); 1472 1472 1473 1473 /* not in hash table yet so not strictly necessary */