--- linux-2.6.3-old/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-04-14 21:32:58.000000000 +0200 +++ linux-2.6.3-patched/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-04-14 21:32:17.000000000 +0200 @@ -51,38 +51,38 @@ static int try_epsv_response(const char *, size_t, u_int32_t [], char); static struct ftp_search { - enum ip_conntrack_dir dir; const char *pattern; size_t plen; char skip; char term; enum ip_ct_ftp_type ftptype; int (*getnum)(const char *, size_t, u_int32_t[], char); -} search[] = { - { - IP_CT_DIR_ORIGINAL, +} search[IP_CT_DIR_MAX][2] = { + { + { "PORT", sizeof("PORT") - 1, ' ', '\r', IP_CT_FTP_PORT, try_rfc959, - }, - { - IP_CT_DIR_REPLY, - "227 ", sizeof("227 ") - 1, '(', ')', - IP_CT_FTP_PASV, - try_rfc959, - }, - { - IP_CT_DIR_ORIGINAL, + }, + { "EPRT", sizeof("EPRT") - 1, ' ', '\r', IP_CT_FTP_EPRT, try_eprt, - }, - { - IP_CT_DIR_REPLY, + } + } + , + { + { + "227 ", sizeof("227 ") - 1, '(', ')', + IP_CT_FTP_PASV, + try_rfc959, + }, + { "229 ", sizeof("229 ") - 1, '(', ')', IP_CT_FTP_EPSV, try_epsv_response, - }, + } + } }; static int try_number(const char *data, size_t dlen, u_int32_t array[], @@ -314,33 +314,34 @@ array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF; array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF; - for (i = 0; i < ARRAY_SIZE(search); i++) { - if (search[i].dir != dir) continue; + for (i = 0; i < ARRAY_SIZE(search[dir]); i++) { found = find_pattern(ftp_buffer, skb->len - dataoff, - search[i].pattern, - search[i].plen, - search[i].skip, - search[i].term, + search[dir][i].pattern, + search[dir][i].plen, + search[dir][i].skip, + search[dir][i].term, &matchoff, &matchlen, array, - search[i].getnum); + search[dir][i].getnum); if (found) break; } - if (found == -1) { + + if (found == 0) { /* General case: No match */ + ret = NF_ACCEPT; + goto out; + + } else if (found == -1) { /* We don't usually drop packets. After all, this is connection tracking, not packet filtering. However, it is necessary for accurate tracking in this case. */ if (net_ratelimit()) printk("conntrack_ftp: partial %s %u+%u\n", - search[i].pattern, + search[dir][i].pattern, ntohl(tcph.seq), datalen); ret = NF_DROP; goto out; - } else if (found == 0) { /* No match */ - ret = NF_ACCEPT; - goto out; } DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n", @@ -361,7 +362,7 @@ == ct->tuplehash[dir].tuple.src.ip) { exp->seq = ntohl(tcph.seq) + matchoff; exp_ftp_info->len = matchlen; - exp_ftp_info->ftptype = search[i].ftptype; + exp_ftp_info->ftptype = search[dir][i].ftptype; exp_ftp_info->port = array[4] << 8 | array[5]; } else { /* Enrico Scholz's passive FTP to partially RNAT'd ftp