12 #include <linux/module.h>
14 #include <linux/netfilter.h>
16 #include <linux/slab.h>
17 #include <linux/ipv6.h>
18 #include <linux/ctype.h>
27 #include <linux/netfilter/nf_conntrack_ftp.h>
36 static char *ftp_buffer;
42 static unsigned int ports_c;
52 unsigned int matchoff,
53 unsigned int matchlen,
57 static int try_rfc959(
const char *,
size_t,
struct nf_conntrack_man *,
char);
59 static int try_epsv_response(
const char *,
size_t,
struct nf_conntrack_man *,
62 static struct ftp_search {
73 .plen =
sizeof(
"PORT") - 1,
81 .plen =
sizeof(
"EPRT") - 1,
91 .plen =
sizeof(
"227 ") - 1,
99 .plen =
sizeof(
"229 ") - 1,
103 .getnum = try_epsv_response,
114 return (
int)(end -
src);
118 static int try_number(
const char *
data,
size_t dlen,
u_int32_t array[],
119 int array_size,
char sep,
char term)
123 memset(array, 0,
sizeof(array[0])*array_size);
126 for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) {
127 if (*data >=
'0' && *data <=
'9') {
128 array[
i] = array[
i]*10 + *data -
'0';
130 else if (*data == sep)
135 if (*data == term && i == array_size - 1)
138 pr_debug(
"Char %u (got %u nums) `%u' unexpected\n",
143 pr_debug(
"Failed to fill %u numbers separated by %c\n",
149 static int try_rfc959(
const char *data,
size_t dlen,
155 length = try_number(data, dlen, array, 6,
',', term);
159 cmd->
u3.
ip =
htonl((array[0] << 24) | (array[1] << 16) |
160 (array[2] << 8) | array[3]);
161 cmd->
u.
tcp.port =
htons((array[4] << 8) | array[5]);
166 static int get_port(
const char *data,
int start,
size_t dlen,
char delim,
172 for (i = start; i <
dlen; i++) {
174 if (data[i] == delim) {
177 *port =
htons(tmp_port);
178 pr_debug(
"get_port: return %d\n", tmp_port);
181 else if (data[i] >=
'0' && data[i] <=
'9')
182 tmp_port = tmp_port*10 + data[
i] -
'0';
184 pr_debug(
"get_port: invalid char.\n");
192 static int try_eprt(
const char *data,
size_t dlen,
struct nf_conntrack_man *cmd,
205 if (
isdigit(delim) || delim < 33 || delim > 126 || data[2] != delim) {
206 pr_debug(
"try_eprt: invalid delimitter.\n");
212 pr_debug(
"EPRT: invalid protocol number.\n");
216 pr_debug(
"EPRT: Got %c%c%c\n", delim, data[1], delim);
218 if (data[1] ==
'1') {
222 length = try_number(data + 3, dlen - 3, array, 4,
'.', delim);
224 cmd->
u3.
ip =
htonl((array[0] << 24) | (array[1] << 16)
225 | (array[2] << 8) | array[3]);
228 length = get_ipv6_addr(data + 3, dlen - 3,
234 pr_debug(
"EPRT: Got IP address!\n");
236 return get_port(data, 3 + length + 1, dlen, delim, &cmd->
u.
tcp.port);
240 static int try_epsv_response(
const char *data,
size_t dlen,
246 if (dlen <= 3)
return 0;
248 if (
isdigit(delim) || delim < 33 || delim > 126 ||
249 data[1] != delim || data[2] != delim)
252 return get_port(data, 3, dlen, delim, &cmd->
u.
tcp.port);
256 static int find_pattern(
const char *data,
size_t dlen,
258 char skip,
char term,
259 unsigned int *numoff,
260 unsigned int *numlen,
262 int (*getnum)(
const char *,
size_t,
267 pr_debug(
"find_pattern `%s': dlen = %Zu\n", pattern, dlen);
273 if (
strnicmp(data, pattern, dlen) == 0)
278 if (
strnicmp(data, pattern, plen) != 0) {
283 for (i = 0; i <
plen; i++) {
284 pr_debug(
"ftp:char %u `%c'(%u) vs `%c'(%u)\n",
286 pattern[i], pattern[i]);
295 for (i = plen; data[
i] !=
skip; i++)
296 if (i == dlen - 1)
return -1;
301 pr_debug(
"Skipped up to `%c'!\n", skip);
304 *numlen = getnum(data + i, dlen - i, cmd, term);
324 static void update_nl_seq(
struct nf_conn *
ct,
u32 nl_seq,
328 unsigned int i, oldest;
349 static int help(
struct sk_buff *skb,
350 unsigned int protoff,
367 int found = 0, ends_in_nl;
373 pr_debug(
"ftp: Conntrackinfo = %u\n", ctinfo);
377 th = skb_header_pointer(skb, protoff,
sizeof(_tcph), &_tcph);
381 dataoff = protoff + th->doff * 4;
383 if (dataoff >= skb->
len) {
384 pr_debug(
"ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
388 datalen = skb->
len - dataoff;
390 spin_lock_bh(&nf_ftp_lock);
391 fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
394 ends_in_nl = (fb_ptr[datalen - 1] ==
'\n');
398 if (!find_nl_seq(
ntohl(th->
seq), ct_ftp_info, dir)) {
406 pr_debug(
"nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n",
418 cmd.
l3num = nf_ct_l3num(ct);
423 found = find_pattern(fb_ptr, datalen,
428 &matchoff, &matchlen,
438 pr_debug(
"conntrack_ftp: partial %s %u+%u\n",
442 }
else if (found == 0) {
447 pr_debug(
"conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
448 matchlen, fb_ptr + matchoff,
449 matchlen,
ntohl(th->
seq) + matchoff);
460 daddr = &ct->
tuplehash[!dir].tuple.dst.u3;
463 if ((cmd.
l3num == nf_ct_l3num(ct)) &&
465 sizeof(cmd.
u3.
all))) {
471 pr_debug(
"conntrack_ftp: NOT RECORDING: %pI4 != %pI4\n",
475 pr_debug(
"conntrack_ftp: NOT RECORDING: %pI6 != %pI6\n",
492 &ct->
tuplehash[!dir].tuple.src.u3, daddr,
499 ret = nf_nat_ftp(skb, ctinfo,
search[dir][i].ftptype,
500 protoff, matchoff, matchlen, exp);
503 if (nf_ct_expect_related(exp) != 0)
516 update_nl_seq(ct, seq, ct_ftp_info, dir, skb);
518 spin_unlock_bh(&nf_ftp_lock);
543 static void nf_conntrack_ftp_fini(
void)
546 for (i = 0; i < ports_c; i++) {
547 for (j = 0; j < 2; j++) {
548 if (ftp[i][j].me ==
NULL)
551 pr_debug(
"nf_ct_ftp: unregistering helper for pf: %d "
553 ftp[i][j].tuple.src.l3num, ports[i]);
561 static int __init nf_conntrack_ftp_init(
void)
563 int i, j = -1, ret = 0;
574 for (i = 0; i < ports_c; i++) {
575 ftp[
i][0].tuple.src.l3num =
PF_INET;
577 for (j = 0; j < 2; j++) {
579 ftp[
i][
j].tuple.src.u.tcp.port =
htons(ports[i]);
581 ftp[
i][
j].expect_policy = &ftp_exp_policy;
583 ftp[
i][
j].help = help;
584 ftp[
i][
j].from_nlattr = nf_ct_ftp_from_nlattr;
590 pr_debug(
"nf_ct_ftp: registering helper for pf: %d "
592 ftp[i][j].tuple.src.l3num, ports[i]);
596 " helper for pf: %d port: %d\n",
597 ftp[i][j].tuple.src.l3num, ports[i]);
598 nf_conntrack_ftp_fini();