aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2013-05-22 08:59:10 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-05-27 07:32:43 -0400
commit4e7dba99c9e606e304f104ce4071d8b5ba93957e (patch)
treebc8a093ce2879288f1c902ec215b895a2da353dc /net/netfilter
parent9d5242b19269432ea388d766312ed49f184f83fd (diff)
netfilter: Implement RFC 1123 for FTP conntrack
The FTP conntrack code currently only accepts the following format for the 227 response for PASV: 227 Entering Passive Mode (148,100,81,40,31,161). It doesn't accept the following format from an obscure server: 227 Data transfer will passively listen to 67,218,99,134,50,144 From RFC 1123: The format of the 227 reply to a PASV command is not well standardized. In particular, an FTP client cannot assume that the parentheses shown on page 40 of RFC-959 will be present (and in fact, Figure 3 on page 43 omits them). Therefore, a User-FTP program that interprets the PASV reply must scan the reply for the first digit of the host and port numbers. This patch adds support for the RFC 1123 clarification by: - Allowing a search filter to specify NUL as the terminator so that try_number will return successfully if the array of numbers has been filled when an unexpected character is encountered. - Using space as the separator for the 227 reply and then scanning for the first digit of the number sequence. The number sequence is parsed out using the existing try_rfc959 but with a NUL terminator. References: https://bugzilla.novell.com/show_bug.cgi?id=466279 References: http://bugzilla.netfilter.org/show_bug.cgi?id=574 Reported-by: Mark Post <mpost@novell.com> Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Pablo Neira Ayuso <pablo@netfilter.org> Cc: Patrick McHardy <kaber@trash.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: netfilter-devel@vger.kernel.org Cc: netfilter@vger.kernel.org Cc: coreteam@netfilter.org Cc: netdev@vger.kernel.org Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_ftp.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 6b217074237b..b8a0924064ef 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -55,10 +55,14 @@ unsigned int (*nf_nat_ftp_hook)(struct sk_buff *skb,
55 struct nf_conntrack_expect *exp); 55 struct nf_conntrack_expect *exp);
56EXPORT_SYMBOL_GPL(nf_nat_ftp_hook); 56EXPORT_SYMBOL_GPL(nf_nat_ftp_hook);
57 57
58static int try_rfc959(const char *, size_t, struct nf_conntrack_man *, char); 58static int try_rfc959(const char *, size_t, struct nf_conntrack_man *,
59static int try_eprt(const char *, size_t, struct nf_conntrack_man *, char); 59 char, unsigned int *);
60static int try_rfc1123(const char *, size_t, struct nf_conntrack_man *,
61 char, unsigned int *);
62static int try_eprt(const char *, size_t, struct nf_conntrack_man *,
63 char, unsigned int *);
60static int try_epsv_response(const char *, size_t, struct nf_conntrack_man *, 64static int try_epsv_response(const char *, size_t, struct nf_conntrack_man *,
61 char); 65 char, unsigned int *);
62 66
63static struct ftp_search { 67static struct ftp_search {
64 const char *pattern; 68 const char *pattern;
@@ -66,7 +70,7 @@ static struct ftp_search {
66 char skip; 70 char skip;
67 char term; 71 char term;
68 enum nf_ct_ftp_type ftptype; 72 enum nf_ct_ftp_type ftptype;
69 int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char); 73 int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char, unsigned int *);
70} search[IP_CT_DIR_MAX][2] = { 74} search[IP_CT_DIR_MAX][2] = {
71 [IP_CT_DIR_ORIGINAL] = { 75 [IP_CT_DIR_ORIGINAL] = {
72 { 76 {
@@ -90,10 +94,8 @@ static struct ftp_search {
90 { 94 {
91 .pattern = "227 ", 95 .pattern = "227 ",
92 .plen = sizeof("227 ") - 1, 96 .plen = sizeof("227 ") - 1,
93 .skip = '(',
94 .term = ')',
95 .ftptype = NF_CT_FTP_PASV, 97 .ftptype = NF_CT_FTP_PASV,
96 .getnum = try_rfc959, 98 .getnum = try_rfc1123,
97 }, 99 },
98 { 100 {
99 .pattern = "229 ", 101 .pattern = "229 ",
@@ -132,8 +134,9 @@ static int try_number(const char *data, size_t dlen, u_int32_t array[],
132 i++; 134 i++;
133 else { 135 else {
134 /* Unexpected character; true if it's the 136 /* Unexpected character; true if it's the
135 terminator and we're finished. */ 137 terminator (or we don't care about one)
136 if (*data == term && i == array_size - 1) 138 and we're finished. */
139 if ((*data == term || !term) && i == array_size - 1)
137 return len; 140 return len;
138 141
139 pr_debug("Char %u (got %u nums) `%u' unexpected\n", 142 pr_debug("Char %u (got %u nums) `%u' unexpected\n",
@@ -148,7 +151,8 @@ static int try_number(const char *data, size_t dlen, u_int32_t array[],
148 151
149/* Returns 0, or length of numbers: 192,168,1,1,5,6 */ 152/* Returns 0, or length of numbers: 192,168,1,1,5,6 */
150static int try_rfc959(const char *data, size_t dlen, 153static int try_rfc959(const char *data, size_t dlen,
151 struct nf_conntrack_man *cmd, char term) 154 struct nf_conntrack_man *cmd, char term,
155 unsigned int *offset)
152{ 156{
153 int length; 157 int length;
154 u_int32_t array[6]; 158 u_int32_t array[6];
@@ -163,6 +167,33 @@ static int try_rfc959(const char *data, size_t dlen,
163 return length; 167 return length;
164} 168}
165 169
170/*
171 * From RFC 1123:
172 * The format of the 227 reply to a PASV command is not
173 * well standardized. In particular, an FTP client cannot
174 * assume that the parentheses shown on page 40 of RFC-959
175 * will be present (and in fact, Figure 3 on page 43 omits
176 * them). Therefore, a User-FTP program that interprets
177 * the PASV reply must scan the reply for the first digit
178 * of the host and port numbers.
179 */
180static int try_rfc1123(const char *data, size_t dlen,
181 struct nf_conntrack_man *cmd, char term,
182 unsigned int *offset)
183{
184 int i;
185 for (i = 0; i < dlen; i++)
186 if (isdigit(data[i]))
187 break;
188
189 if (i == dlen)
190 return 0;
191
192 *offset += i;
193
194 return try_rfc959(data + i, dlen - i, cmd, 0, offset);
195}
196
166/* Grab port: number up to delimiter */ 197/* Grab port: number up to delimiter */
167static int get_port(const char *data, int start, size_t dlen, char delim, 198static int get_port(const char *data, int start, size_t dlen, char delim,
168 __be16 *port) 199 __be16 *port)
@@ -191,7 +222,7 @@ static int get_port(const char *data, int start, size_t dlen, char delim,
191 222
192/* Returns 0, or length of numbers: |1|132.235.1.2|6275| or |2|3ffe::1|6275| */ 223/* Returns 0, or length of numbers: |1|132.235.1.2|6275| or |2|3ffe::1|6275| */
193static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd, 224static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd,
194 char term) 225 char term, unsigned int *offset)
195{ 226{
196 char delim; 227 char delim;
197 int length; 228 int length;
@@ -239,7 +270,8 @@ static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd,
239 270
240/* Returns 0, or length of numbers: |||6446| */ 271/* Returns 0, or length of numbers: |||6446| */
241static int try_epsv_response(const char *data, size_t dlen, 272static int try_epsv_response(const char *data, size_t dlen,
242 struct nf_conntrack_man *cmd, char term) 273 struct nf_conntrack_man *cmd, char term,
274 unsigned int *offset)
243{ 275{
244 char delim; 276 char delim;
245 277
@@ -261,9 +293,10 @@ static int find_pattern(const char *data, size_t dlen,
261 unsigned int *numlen, 293 unsigned int *numlen,
262 struct nf_conntrack_man *cmd, 294 struct nf_conntrack_man *cmd,
263 int (*getnum)(const char *, size_t, 295 int (*getnum)(const char *, size_t,
264 struct nf_conntrack_man *, char)) 296 struct nf_conntrack_man *, char,
297 unsigned int *))
265{ 298{
266 size_t i; 299 size_t i = plen;
267 300
268 pr_debug("find_pattern `%s': dlen = %Zu\n", pattern, dlen); 301 pr_debug("find_pattern `%s': dlen = %Zu\n", pattern, dlen);
269 if (dlen == 0) 302 if (dlen == 0)
@@ -293,16 +326,18 @@ static int find_pattern(const char *data, size_t dlen,
293 pr_debug("Pattern matches!\n"); 326 pr_debug("Pattern matches!\n");
294 /* Now we've found the constant string, try to skip 327 /* Now we've found the constant string, try to skip
295 to the 'skip' character */ 328 to the 'skip' character */
296 for (i = plen; data[i] != skip; i++) 329 if (skip) {
297 if (i == dlen - 1) return -1; 330 for (i = plen; data[i] != skip; i++)
331 if (i == dlen - 1) return -1;
298 332
299 /* Skip over the last character */ 333 /* Skip over the last character */
300 i++; 334 i++;
335 }
301 336
302 pr_debug("Skipped up to `%c'!\n", skip); 337 pr_debug("Skipped up to `%c'!\n", skip);
303 338
304 *numoff = i; 339 *numoff = i;
305 *numlen = getnum(data + i, dlen - i, cmd, term); 340 *numlen = getnum(data + i, dlen - i, cmd, term, numoff);
306 if (!*numlen) 341 if (!*numlen)
307 return -1; 342 return -1;
308 343