--- zzzz-none-000/linux-5.4.213/net/netfilter/nf_nat_ftp.c 2022-09-15 10:04:56.000000000 +0000 +++ alder-5690pro-762/linux-5.4.213/net/netfilter/nf_nat_ftp.c 2024-08-14 09:02:14.000000000 +0000 @@ -25,11 +25,42 @@ MODULE_DESCRIPTION("ftp NAT helper"); MODULE_ALIAS_NF_NAT_HELPER(NAT_HELPER_NAME); +static ushort psid = 0; +module_param(psid, ushort, 0644); +MODULE_PARM_DESC(psid, "MAP_E devices's psid"); + +static uint psid_len = 0; +module_param(psid_len, uint, 0644); +MODULE_PARM_DESC(psid_len, "MAP_E devices's psid length"); + +static uint offset = 0; +module_param(offset, uint, 0644); +MODULE_PARM_DESC(offset, "MAP_E devices's psid offset"); + /* FIXME: Time out? --RR */ static struct nf_conntrack_nat_helper nat_helper_ftp = NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME); +/** + * nf_nat_port_valid_check - check the port is in the range of psid + * @skb the packets to be translated + * @port the port to be checked. + **/ +static int nf_nat_port_valid_check(struct sk_buff *skb, u16 port) +{ + if (psid == 0 || psid_len == 0 || offset == 0) + return 1; + + if ((psid_len + offset) > 16) + return 1; + + if ((((port >> (16 - psid_len - offset)) & ((1 << psid_len) - 1))) == psid) + return 1; + + return 0; +} + static int nf_nat_ftp_fmt_cmd(struct nf_conn *ct, enum nf_ct_ftp_type type, char *buffer, size_t buflen, union nf_inet_addr *addr, u16 port) @@ -69,7 +100,7 @@ struct nf_conntrack_expect *exp) { union nf_inet_addr newaddr; - u_int16_t port; + u16 port; int dir = CTINFO2DIR(ctinfo); struct nf_conn *ct = exp->master; char buffer[sizeof("|1||65535|") + INET6_ADDRSTRLEN]; @@ -86,10 +117,16 @@ * this one. */ exp->expectfn = nf_nat_follow_master; - /* Try to get same port: if not, try to change it. */ + /* In the case of MAP-E, the FTP ALG source port number must use its own + * PSID. Otherwise the returned packets from ftp server will use other + * than its own IPv6 address. + * so let the check hook to validate the port*/ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { int ret; + if (!nf_nat_port_valid_check(skb, port)) + continue; + exp->tuple.dst.u.tcp.port = htons(port); ret = nf_ct_expect_related(exp, 0); if (ret == 0)