zhouaidong 6 лет назад
Сommit
7a350fbf23

+ 45 - 0
pom.xml

@@ -0,0 +1,45 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>com.cmss</groupId>
+  <artifactId>ftpProxy</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>ftpProxy</name>
+  <url>http://maven.apache.org</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+			<groupId>commons-net</groupId>
+			<artifactId>commons-net</artifactId>
+			<version>3.3</version>
+		</dependency>
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>fastjson</artifactId>
+			<version>1.1.24</version>
+		</dependency>
+		<dependency>
+	    <groupId>com.jcraft</groupId>
+	    <artifactId>jsch</artifactId>
+	    <version>0.1.54</version>
+		</dependency>
+		<dependency>
+	    <groupId>log4j</groupId>
+	    <artifactId>log4j</artifactId>
+	    <version>1.2.17</version>
+		</dependency>
+  </dependencies>
+</project>

+ 195 - 0
src/main/java/com/cmss/pretendProxy/Configuration.java

@@ -0,0 +1,195 @@
+package com.cmss.pretendProxy;
+
+/*
+ Copyright (C) 1998-2014 Christian Schmidt
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+class Configuration {
+
+    Properties properties;
+
+    int bindPort;
+
+    int bindBacklog;
+
+    InetAddress bindAddress;
+
+    String masqueradeHostname;
+
+    boolean isUrlSyntaxEnabled;
+
+    int[] serverBindPorts;
+
+    int[] clientBindPorts;
+
+    boolean serverOneBindPort, clientOneBindPort;
+
+    boolean debug;
+
+    List allowFrom, denyFrom, allowTo, denyTo;
+
+    // Messages.
+    String msgConnect;
+
+    String msgConnectionRefused;
+
+    String msgOriginAccessDenied;
+
+    String msgDestinationAccessDenied;
+
+    String msgIncorrectSyntax;
+
+    String msgInternalError;
+
+    String msgMasqHostDNSError;
+
+    public Configuration(final Properties properties) throws UnknownHostException {
+
+        this.properties = properties;
+
+        bindPort = getInt("bind_port", 8089);
+        bindBacklog = getInt("bind_backlog", -1);
+        final String ba = getString("bind_address");
+        bindAddress = ba == null ? null : InetAddress.getByName(ba.trim());
+
+        serverBindPorts = getPortRanges("server_bind_ports");
+        clientBindPorts = getPortRanges("client_bind_ports");
+        serverOneBindPort = serverBindPorts != null && serverBindPorts.length == 2
+                && serverBindPorts[0] == serverBindPorts[1];
+        clientOneBindPort = clientBindPorts != null && clientBindPorts.length == 2
+                && clientBindPorts[0] == clientBindPorts[1];
+
+        masqueradeHostname = getString("masquerade_host");
+        if (masqueradeHostname != null) {
+            // This is just to throw an UnknownHostException
+            // if the config is incorrectly set up.
+            InetAddress.getByName(masqueradeHostname.trim());
+        }
+
+        allowFrom = getSubnets("allow_from");
+        denyFrom = getSubnets("deny_from");
+        allowTo = getSubnets("allow_to");
+        denyTo = getSubnets("deny_to");
+
+        isUrlSyntaxEnabled = getBool("enable_url_syntax", true);
+        debug = getBool("output_debug_info", false);
+
+        msgConnect = "220 " + getString("msg_connect", "Java FTP Proxy Server (usage: USERID=user@site) ready.");
+
+        msgConnectionRefused = "421 " + getString("msg_connection_refused", "Connection refused, closing connection.");
+
+        msgOriginAccessDenied = "531 " + getString("msg_origin_access_denied", "Access denied - closing connection.");
+
+        msgDestinationAccessDenied = "531 "
+                + getString("msg_destination_access_denied", "Access denied - closing connection.");
+
+        msgIncorrectSyntax = "531 " + getString("msg_incorrect_syntax", "Incorrect usage - closing connection.");
+
+        msgInternalError = "421 " + getString("msg_internal_error", "Internal error, closing connection.");
+
+        msgMasqHostDNSError = "421 "
+                + getString("msg_masqerade_hostname_dns_error", "Unable to resolve address for " + masqueradeHostname
+                        + " - closing connection.");
+    }
+
+    public boolean getBool(final String name, final boolean defaultValue) {
+
+        final String value = getString(name);
+        return value == null ? defaultValue : value.trim().equals("1");
+    }
+
+    public int getInt(final String name, final int defaultValue) {
+
+        final String value = properties.getProperty(name);
+        properties.remove(name);
+        return value == null ? defaultValue : Integer.parseInt(value.trim());
+    }
+
+    public String getString(final String name) {
+
+        return getString(name, null);
+    }
+
+    public String getString(final String name, final String defaultValue) {
+
+        final String value = properties.getProperty(name, defaultValue);
+        properties.remove(name);
+        return value;
+    }
+
+    public List getSubnets(final String name) {
+
+        final String s = getString(name);
+        if (s == null) {
+            return null;
+        }
+
+        final List list = new LinkedList();
+        final StringTokenizer st = new StringTokenizer(s.trim(), ",");
+        while (st.hasMoreTokens()) {
+            list.add(new Subnet(st.nextToken().trim()));
+        }
+
+        return list;
+    }
+
+    /**
+     * Returns an array of length 2n, where n is the number of port ranges specified. Index 2i will contain the first port number in the i'th range,
+     * and index 2i+1 will contain the last. E.g. the string "111,222-333,444-555,666" will result in the following array: {111, 111, 222, 333, 444,
+     * 555, 666, 666}
+     */
+    public int[] getPortRanges(final String name) {
+
+        final String s = getString(name);
+        if (s == null) {
+            return null;
+        }
+
+        final StringTokenizer st = new StringTokenizer(s.trim(), ",");
+        final int[] ports = new int[st.countTokens() * 2];
+
+        if (ports.length == 0) {
+            return null;
+        }
+
+        int lastPort = 0;
+        for (int p = 0; st.hasMoreTokens(); p += 2) {
+            final String range = st.nextToken().trim();
+            final int i = range.indexOf('-');
+
+            if (i == -1) {
+                ports[p] = ports[p + 1] = Integer.parseInt(range);
+            } else {
+                ports[p] = Integer.parseInt(range.substring(0, i));
+                ports[p + 1] = Integer.parseInt(range.substring(i + 1));
+            }
+            if (ports[p] < lastPort || ports[p] > ports[p + 1]) {
+                throw new RuntimeException("Ports should be listed in increasing order.");
+            }
+            lastPort = ports[p + 1];
+        }
+
+        return ports;
+    }
+}

+ 836 - 0
src/main/java/com/cmss/pretendProxy/FtpProxyServer.java

@@ -0,0 +1,836 @@
+package com.cmss.pretendProxy;
+
+/*
+ Java FTP Proxy Server 1.3.0
+ Copyright (C) 1998-2014 Christian Schmidt
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ Find the latest version at http://aggemam.dk/ftpproxy
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.BindException;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+
+public class FtpProxyServer extends ProxyServer {
+
+    public FtpProxyServer() {
+
+        super.logPrefix = "[FTP代理]";
+    }
+
+    /**
+     * 初始化
+     */
+    protected void init() throws Exception {
+
+        _socketFactory_ = SocketFactory.getDefault();
+        _serverSocketFactory_ = ServerSocketFactory.getDefault();
+    }
+
+    @Override
+    public void run() {
+
+        infoLog("代理服务初始化");
+        try {
+            init();
+        } catch (final Exception e) {
+            errorLog("初始化代理服务失败", e);
+            return;
+        }
+
+        infoLog("代理服务启动");
+
+        final int bindPort = config.bindPort;
+        ServerSocket ssControlClient = null;
+        try {
+            debugLog("代理服务启动开始" + cuttingLine);
+            if (config.bindAddress == null) {
+                ssControlClient = new ServerSocket(bindPort);
+            } else {
+                ssControlClient = new ServerSocket(bindPort, config.bindBacklog, config.bindAddress);
+            }
+            infoLog("代理服务器:" + ssControlClient.toString());
+            debugLog("代理服务已启动" + cuttingLine);
+            while (true) {
+                final Socket skControlClient = ssControlClient.accept();
+                infoLog("新连接:" + skControlClient.toString());
+                _startProxyClient_(skControlClient);
+            }
+        } catch (final Exception e) {
+            errorLog("启动代理服务出错", e);
+        } finally {
+            close(ssControlClient, "FTP代理服务");
+            //代理出现异常  强制重启
+            infoLog("代理服务已关闭" + cuttingLine);
+            try {
+                //异常后睡眠10秒重启
+                Thread.sleep(10000);
+            } catch (final InterruptedException e) {
+                errorLog("", e);
+            }
+            infoLog("代理服务开始重启" + cuttingLine);
+            final FtpProxyServer proxyServer = new FtpProxyServer();
+            proxyServer.setConfig(config);
+            proxyServer.start();
+            infoLog("代理服务已重启" + cuttingLine);
+        }
+
+    }
+
+    protected void _startProxyClient_(final Socket skControlClient) {
+
+        new FtpProxy(skControlClient).start();
+
+    }
+
+    class FtpProxy extends Thread {
+
+        Socket skControlClient, skControlServer;
+
+        BufferedReader brClient, brServer;
+
+        PrintStream psClient, psServer;
+
+        ServerSocket ssDataClient, ssDataServer;
+
+        Socket skDataClient, skDataServer;
+
+        DataConnect dcData;
+
+        // 接口的IP分别面向客户端和服务器端.
+        String sLocalClientIP;
+
+        String sLocalServerIP;
+
+        //连接服务端模式  默认主动模式
+        boolean serverPassive = false;
+
+        //用户登录状态
+        boolean userLoggedIn = false;
+
+        boolean connectionClosed = false;
+
+        public FtpProxy(final Socket skControlClient) {
+
+            this.skControlClient = skControlClient;
+        }
+
+        public boolean isInSubnetList(final List list, final InetAddress ia) {
+
+            if (list == null) {
+                return false;
+            }
+
+            for (final Iterator iterator = list.iterator(); iterator.hasNext();) {
+                final Subnet subnet = (Subnet) iterator.next();
+
+                if (subnet.isInSubnet(ia)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int parsePort(String s) throws IOException {
+
+            int port;
+            try {
+                int i = s.lastIndexOf('(');
+                int j = s.lastIndexOf(')');
+                if ((i != -1) && (j != -1) && (i < j)) {
+                    s = s.substring(i + 1, j);
+                }
+
+                i = s.lastIndexOf(',');
+                j = s.lastIndexOf(',', i - 1);
+
+                port = Integer.parseInt(s.substring(i + 1));
+                port += 256 * Integer.parseInt(s.substring(j + 1, i));
+            } catch (final Exception e) {
+                throw new IOException();
+            }
+            return port;
+        }
+
+        public synchronized ServerSocket getServerSocket(final int[] portRanges, final InetAddress ia)
+                throws IOException {
+
+            ServerSocket ss = null;
+            if (portRanges != null) {
+                // Current index of portRanges array.
+                int i;
+                int port;
+
+                final Integer lastPort = (Integer) lastPorts.get(portRanges);
+                if (lastPort != null) {
+                    port = lastPort.intValue();
+                    for (i = 0; i < portRanges.length && port > portRanges[i + 1]; i += 2) {
+                        ;
+                    }
+                    port++;
+                } else {
+                    port = portRanges[0];
+                    i = 0;
+                }
+
+                for (int lastTry = -2; port != lastTry; port++) {
+                    if (port > portRanges[i + 1]) {
+                        i = (i + 2) % portRanges.length;
+                        port = portRanges[i];
+                    }
+                    if (lastTry == -1) {
+                        lastTry = port;
+                    }
+                    try {
+                        ss = new ServerSocket(port, 1, ia);
+                        lastPorts.put(portRanges, new Integer(port));
+                        break;
+                    } catch (final BindException e) {
+                        // Port already in use.
+                    }
+                }
+            } else {
+                ss = new ServerSocket(0, 1, ia);
+            }
+            return ss;
+        }
+
+        protected String formatLogPrefix(final String param) {
+
+            String sourceAddress = null;
+            String targetAddress = null;
+            if (client2proxy.equals(param)) {
+                sourceAddress = skControlClient.getInetAddress().getHostAddress() + ":" + skControlClient.getPort();
+                targetAddress = skControlClient.getLocalAddress().getHostAddress() + ":"
+                        + skControlClient.getLocalPort();
+            } else if (proxy2client.equals(param)) {
+                sourceAddress = skControlClient.getLocalAddress().getHostAddress() + ":"
+                        + skControlClient.getLocalPort();
+                targetAddress = skControlClient.getInetAddress().getHostAddress() + ":" + skControlClient.getPort();
+            } else if (server2proxy.equals(param)) {
+                sourceAddress = skControlServer.getInetAddress().getHostAddress() + ":" + skControlServer.getPort();
+                targetAddress = skControlServer.getLocalAddress().getHostAddress() + ":"
+                        + skControlServer.getLocalPort();
+            } else if (proxy2server.equals(param)) {
+                sourceAddress = skControlServer.getLocalAddress().getHostAddress() + ":"
+                        + skControlServer.getLocalPort();
+                targetAddress = skControlServer.getInetAddress().getHostAddress() + ":" + skControlServer.getPort();
+            } else if (server2client.equals(param)) {
+                sourceAddress = skControlServer.getInetAddress().getHostAddress() + ":" + skControlServer.getPort();
+                targetAddress = skControlClient.getInetAddress().getHostAddress() + ":" + skControlClient.getPort();
+            } else if (client2server.equals(param)) {
+                sourceAddress = skControlClient.getInetAddress().getHostAddress() + ":" + skControlClient.getPort();
+                targetAddress = skControlServer.getInetAddress().getHostAddress() + ":" + skControlServer.getPort();
+            }
+            return "[" + sourceAddress + "--->" + targetAddress + "]" + "[" + param + "]";
+
+        }
+
+        @Override
+        public void run() {
+
+            try {
+
+                brClient = new BufferedReader(new InputStreamReader(skControlClient.getInputStream()));
+                psClient = new PrintStream(skControlClient.getOutputStream(), true);
+
+                if ((config.allowFrom != null && !isInSubnetList(config.allowFrom, skControlClient.getInetAddress()))
+                        || isInSubnetList(config.denyFrom, skControlClient.getInetAddress())) {
+                    infoLog("该ip被限制连接:" + skControlClient.getInetAddress());
+                    final String toClient = config.msgOriginAccessDenied;
+                    psClient.print(toClient + CRLF);
+                    debugLog(formatLogPrefix(proxy2client) + toClient);
+                    skControlClient.close();
+                    return;
+                }
+
+                debugLog("解析masquerade_host");
+                try {
+                    if (config.masqueradeHostname == null) {
+                        sLocalClientIP = skControlClient.getLocalAddress().getHostAddress().replace('.', ',');
+                    } else {
+                        sLocalClientIP = InetAddress.getByName(config.masqueradeHostname.trim()).getHostAddress()
+                                .replace('.', ',');
+                    }
+                } catch (final UnknownHostException e) {
+                    errorLog("解析masquerade_host失败", e);
+                    final String toClient = config.msgMasqHostDNSError;
+                    psClient.print(toClient + CRLF);
+                    debugLog(proxy2client + toClient);
+                    skControlClient.close();
+                    return;
+                }
+
+                final String toClient = config.msgConnect;
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+
+                for (;;) {
+                    final String s = brClient.readLine();
+                    if (s == null) {
+                        break;
+                    }
+                    readCommandFromClient(s);
+                    // Exit if connection closed (response == 221,421,530).
+                    if (connectionClosed) {
+                        break;
+                    }
+                }
+
+            } catch (final Exception e) {
+                errorLog("", e);
+                final String toClient = config.msgInternalError;
+                psClient.print(toClient + CRLF);
+                debugLog(proxy2client + toClient);
+            } finally {
+                if (!config.clientOneBindPort) {
+                    close(ssDataClient, "ssDataClient");
+                }
+                if (!config.serverOneBindPort) {
+                    close(ssDataServer, "ssDataServer");
+                }
+                close(skDataClient, "skDataClient");
+                close(skDataServer, "skDataServer");
+                close(psClient, "psClient");
+                close(psServer, "psServer");
+                close(dcData, "dcData");
+                close(skControlClient, "skControlClient");
+            }
+        }
+
+        /**
+         * 从客户端读取命令
+         *
+         * @param fromClient
+         * @throws IOException
+         */
+        private void readCommandFromClient(final String fromClient) throws IOException {
+
+            final String cmd = fromClient.toUpperCase();
+
+            if (!userLoggedIn && (cmd.startsWith("PASV") || cmd.startsWith("PORT"))) {
+                debugLog(formatLogPrefix(client2proxy) + fromClient);
+                // 不登录不支持模式选择.
+                psClient.print("530 Not logged in." + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + fromClient);
+                return;
+            }
+
+            if (cmd.startsWith("USER")) {
+                //代理连接FTP服务器
+                connectServer(fromClient);
+            } else if (cmd.startsWith("PASS")) {
+                //输入密码
+                imputPassword(fromClient);
+            } else if (cmd.startsWith("PASV") || cmd.startsWith("EPSV")) {
+                //客户端被动
+                setupDataConnectionUsePassive(fromClient);
+            } else if (cmd.startsWith("PORT")) {
+                //主动模式
+                setupDataConnectionUseActive(fromClient);
+            } else if (cmd.startsWith("NOOP")) {
+                //空操作  响应有可能超时
+                diposeNoop(fromClient);
+            } else {
+                psServer.print(fromClient + CRLF);
+                debugLog(formatLogPrefix(client2server) + fromClient);
+                readResponseFromServer(true);
+            }
+
+        }
+
+        /**
+         * 连接FTP服务器
+         */
+        private void connectServer(final String cmd) throws IOException {
+
+            debugLog(formatLogPrefix(client2proxy) + cmd);
+
+            String username = null;
+            String hostname = null;
+            int serverport = 21;
+
+            final String userString = cmd.substring(5);
+            // String userString = "ftp1@10.139.10.176:21";
+
+            final int a = userString.lastIndexOf('@');
+            int c = userString.lastIndexOf(':');
+            if (c < a) {
+                c = -1;
+            }
+
+            //网络URL 未实现
+            //网络url使用 格式 "ftp1*10.139.10.176*21"
+
+            if (c == -1) {
+                username = userString.substring(0, a);
+                hostname = userString.substring(a + 1);
+            } else {
+                username = userString.substring(0, a);
+                hostname = userString.substring(a + 1, c);
+                serverport = Integer.parseInt(userString.substring(c + 1));
+            }
+            debugLog("username:" + username);
+            debugLog("hostname:" + hostname);
+            debugLog("serverport:" + serverport);
+
+            if (hostname == null) {
+                final String toClient = config.msgIncorrectSyntax;
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+                skControlClient.close();
+                return;
+            }
+
+            final InetAddress serverAddress = InetAddress.getByName(hostname);
+
+            if ((config.allowTo != null && !isInSubnetList(config.allowTo, serverAddress))
+                    || isInSubnetList(config.denyTo, serverAddress)) {
+                infoLog("该ip被限制连接:" + serverAddress);
+                final String toClient = config.msgDestinationAccessDenied;
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+                skControlClient.close();
+                return;
+            }
+
+            debugLog("连接----> " + hostname + ":" + serverport);
+
+            try {
+
+                skControlServer = new Socket(serverAddress, serverport);
+                brServer = new BufferedReader(new InputStreamReader(skControlServer.getInputStream()));
+                psServer = new PrintStream(skControlServer.getOutputStream(), true);
+                final String fromServer = brServer.readLine();
+                debugLog(formatLogPrefix(server2proxy) + fromServer);
+                if (fromServer.startsWith("421")) {
+                    final String toClient = fromServer;
+                    psClient.print(toClient + CRLF);
+                    debugLog(formatLogPrefix(proxy2client) + toClient);
+                    return;
+                }
+                skControlServer = _connectServer_(skControlServer, hostname, serverport);
+            } catch (final ConnectException e) {
+                errorLog("连接" + hostname + ":" + serverport + "失败", e);
+                final String toClient = config.msgConnectionRefused;
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+                return;
+            }
+
+            brServer = new BufferedReader(new InputStreamReader(skControlServer.getInputStream()));
+            psServer = new PrintStream(skControlServer.getOutputStream(), true);
+
+            //服务端数据连接ip
+            sLocalServerIP = skControlServer.getLocalAddress().getHostAddress().replace('.', ',');
+
+            //登录
+            final String toServer = "USER " + username;
+            psServer.print(toServer + CRLF);
+            debugLog(formatLogPrefix(proxy2server) + toServer);
+            readResponseFromServer(true);
+        }
+
+        /**
+         * 为扩展ssl用
+         *
+         * @param serverport
+         * @param hostname
+         *
+         * @param skControlServer2
+         */
+        protected Socket _connectServer_(final Socket socket, final String hostname, final int serverport)
+                throws IOException {
+
+            return socket;
+        }
+
+        /**
+         * 输入密码
+         */
+        private void imputPassword(final String cmd) throws IOException {
+
+            psServer.print(cmd + CRLF);
+            debugLog(formatLogPrefix(client2server) + "PASS *******");
+            final String fromServer = brServer.readLine();
+            psClient.print(fromServer + CRLF);
+            debugLog(formatLogPrefix(server2client) + fromServer);
+
+            //登录判断
+            final int response = Integer.parseInt(fromServer.substring(0, 3));
+            if (response == 230) {
+                userLoggedIn = true;
+            }
+
+            _initServer_();
+        }
+
+        /**
+         * 初始化一些参数
+         */
+        protected void _initServer_() throws IOException {
+
+        }
+
+        /**
+         * 数据连接 主动模式
+         */
+        private void setupDataConnectionUseActive(final String cmd) throws IOException {
+
+            //暂时未实现
+
+            debugLog(formatLogPrefix(client2proxy) + cmd);
+
+            if (ssDataClient != null && !config.clientOneBindPort) {
+                try {
+                    ssDataClient.close();
+                } catch (final IOException ioe) {
+                }
+                ssDataClient = null;
+            }
+            if (skDataClient != null) {
+                try {
+                    skDataClient.close();
+                } catch (final IOException ioe) {
+                }
+            }
+            if (ssDataServer != null && !config.serverOneBindPort) {
+                try {
+                    ssDataServer.close();
+                } catch (final IOException ioe) {
+                }
+            }
+            if (skDataServer != null) {
+                try {
+                    skDataServer.close();
+                } catch (final IOException ioe) {
+                }
+            }
+
+            if (dcData != null) {
+                dcData.close();
+            }
+
+            debugLog(formatLogPrefix(client2proxy) + cmd);
+
+            try {
+                //客户端主动
+                final int clientPort = parsePort(cmd);
+                skDataClient = new Socket(skControlClient.getInetAddress(), clientPort);
+
+                String toClient = "200 PORT command successful.";
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+
+                //服务端主动
+
+                if (ssDataServer == null || !config.serverOneBindPort) {
+                    //开启数据监听端口
+                    ssDataServer = getServerSocket(config.serverBindPorts, skControlServer.getLocalAddress());
+                }
+
+                if (ssDataServer != null) {
+                    final int serverPort = ssDataServer.getLocalPort();
+                    final String toServer = "PORT " + sLocalServerIP + ',' + serverPort / 256 + ','
+                            + (serverPort % 256);
+                    //通知服务端来连
+                    psServer.print(toServer + CRLF);
+                    debugLog(formatLogPrefix(proxy2server) + toServer);
+                    debugLog("端口号:" + serverPort);
+
+                    readResponseFromServer(false);
+
+                } else {
+                    //无可用端口
+                    toClient = "425 Cannot allocate local port.";
+                    psClient.print(toClient + CRLF);
+                    debugLog(formatLogPrefix(proxy2client) + toClient);
+                }
+
+            } catch (final IOException e) {
+                final String toClient = "425 PORT command failed - try using PASV instead.";
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+                return;
+            }
+
+        }
+
+        /**
+         * 被动模式
+         */
+        private void setupDataConnectionUsePassive(final String cmd) throws IOException {
+
+            debugLog(formatLogPrefix(client2proxy) + cmd);
+
+            //创建新连接时先关闭旧连接
+            if (ssDataClient != null && !config.clientOneBindPort) {
+                try {
+                    ssDataClient.close();
+                } catch (final IOException ioe) {
+                }
+            }
+            if (skDataClient != null) {
+                try {
+                    skDataClient.close();
+                } catch (final IOException ioe) {
+                }
+            }
+            if (ssDataServer != null && !config.serverOneBindPort) {
+                try {
+                    ssDataServer.close();
+                } catch (final IOException ioe) {
+                }
+            }
+            if (skDataServer != null) {
+                try {
+                    skDataServer.close();
+                } catch (final IOException ioe) {
+                }
+            }
+            if (dcData != null) {
+                dcData.close();
+            }
+
+            if (ssDataClient == null || !config.clientOneBindPort) {
+                ssDataClient = getServerSocket(config.clientBindPorts, skControlClient.getLocalAddress());
+            }
+
+            if (ssDataClient != null) {
+                final int clientPort = ssDataClient.getLocalPort();
+                //客户端被动
+                String toClient;
+                if (cmd.startsWith("EPSV")) {
+                    //IPv6
+                    toClient = "229 Entering Extended Passive Mode (|||" + clientPort + "|)";
+                } else {
+                    toClient = "227 Entering Passive Mode (" + sLocalClientIP + "," + clientPort / 256 + ","
+                            + (clientPort % 256) + ")";
+                }
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+                debugLog("端口号:" + clientPort);
+
+                skDataClient = ssDataClient.accept();
+                if (!config.clientOneBindPort) {
+                    close(ssDataClient, "ssDataClient");
+                }
+
+                //服务端被动 IPV6 未处理
+                final String toServer = cmd;
+                psServer.print(toServer + CRLF);
+                debugLog(formatLogPrefix(proxy2server) + toServer);
+
+                //获取服务端返回的端口
+                final String fromServer = readResponseFromServer(false);
+                final int serverPort = parsePort(fromServer);
+                debugLog("Server: " + skControlServer.getInetAddress() + ":" + serverPort);
+
+                //与服务端建立连接
+                skDataServer = _socketFactory_.createSocket();
+                skDataServer.connect(new InetSocketAddress(skControlServer.getInetAddress(), serverPort));
+
+            } else {
+                final String toClient = "425 Cannot allocate local port..";
+                psClient.print(toClient + CRLF);
+                debugLog(formatLogPrefix(proxy2client) + toClient);
+            }
+
+        }
+
+        /**
+         * NOOP命令单独处理 可能无响应
+         *
+         * @param fromClient
+         * @throws SocketException
+         */
+        private void diposeNoop(final String fromClient) throws SocketException {
+
+            psServer.print(fromClient + CRLF);
+            debugLog(formatLogPrefix(client2server) + fromClient);
+
+            final int soTimeOut = skControlClient.getSoTimeout();
+            skControlClient.setSoTimeout(3000);
+
+            try {
+                readResponseFromServer(true);
+            } catch (final IOException e) {
+
+            } finally {
+                skControlClient.setSoTimeout(soTimeOut);
+            }
+
+        }
+
+        /**
+         * 从服务端读取响应
+         *
+         * @param true 直接推送给客户端 false 代理拦截
+         * @return
+         * @throws IOException
+         */
+        private String readResponseFromServer(final boolean forwardToClient) throws IOException {
+
+            String fromServer = brServer.readLine();
+            String firstLine = fromServer;
+            final int response = Integer.parseInt(fromServer.substring(0, 3));
+            if (fromServer.charAt(3) == '-') {
+                final String multiLine = fromServer.substring(0, 3) + ' ';
+                while (!fromServer.startsWith(multiLine)) {
+                    if (forwardToClient) {
+                        psClient.print(fromServer + CRLF);
+                    }
+                    debugLog(formatLogPrefix((forwardToClient ? server2client : server2proxy)) + fromServer);
+                    fromServer = brServer.readLine();
+                }
+            }
+
+            if (forwardToClient || response == 110) {
+                psClient.print(fromServer + CRLF);
+            }
+            debugLog(formatLogPrefix((forwardToClient ? server2client : server2proxy)) + fromServer);
+
+            // Check for successful login.
+            if (response == 230) {
+                userLoggedIn = true;
+            } else if (response == 221 || response == 421 || response == 530) {
+                if (userLoggedIn) {
+                    connectionClosed = true;
+                }
+                userLoggedIn = false;
+            }
+
+            if (response == 150) {
+                _openConection_();
+            }
+
+            if (response >= 100 && response <= 199) {
+                firstLine = readResponseFromServer(true);
+            }
+
+            if (brServer.ready()) {
+                firstLine = readResponseFromServer(true);
+            }
+
+            return firstLine;
+        }
+
+        /**
+         * 开启数据连接
+         *
+         * @throws IOException
+         */
+        protected void _openConection_() throws IOException {
+
+            (dcData = new DataConnect(skDataClient, skDataServer)).start();
+
+        }
+
+        public class DataConnect extends Thread implements Closeable {
+
+            private final byte buffer[] = new byte[DATABUFFERSIZE];
+
+            private final Socket[] sockets;
+
+            private boolean isInitialized;
+
+            private final Object mutex = new Object();
+
+            // Each argument may be either a Socket or a ServerSocket.
+            public DataConnect(final Socket s1, final Socket s2) {
+
+                this.sockets = new Socket[] { s1, s2 };
+            }
+
+            @Override
+            public void run() {
+
+                BufferedInputStream bis = null;
+                BufferedOutputStream bos = null;
+
+                try {
+                    // n = 0 - Thread Copy socket 0 to socket 1
+                    // n = 1 - Thread Copy socket 1 to socket 0
+                    final int n = isInitialized ? 1 : 0;
+                    if (!isInitialized) {
+                        isInitialized = true;
+                        // In some cases thread socket[0] -> socket[1] thread can
+                        // finish before socket[1] -> socket[0] has a chance to
+                        // start,
+                        // so synchronize on a semaphore
+                        synchronized (mutex) {
+                            new Thread(this).start();
+                            try {
+                                mutex.wait();
+                            } catch (final InterruptedException e) {
+                                // Never occurs.
+                            }
+                        }
+
+                    }
+
+                    bis = new BufferedInputStream(sockets[n].getInputStream());
+                    bos = new BufferedOutputStream(sockets[1 - n].getOutputStream());
+
+                    synchronized (mutex) {
+                        mutex.notify();
+                    }
+
+                    for (;;) {
+                        for (int i; (i = bis.read(buffer, 0, DATABUFFERSIZE)) != -1;) {
+                            bos.write(buffer, 0, i);
+                        }
+                        break;
+                    }
+                    bos.flush();
+                } catch (final SocketException e) {
+                    // Socket closed.
+                } catch (final IOException e) {
+                    errorLog("数据连接异常", e);
+                }
+                close();
+            }
+
+            @Override
+            public void close() {
+
+                FtpProxyServer.this.close(sockets[0], "数据连接1");
+                FtpProxyServer.this.close(sockets[1], "数据连接2");
+
+            }
+        }
+
+    }
+
+}

+ 142 - 0
src/main/java/com/cmss/pretendProxy/FtpsProxyServer.java

@@ -0,0 +1,142 @@
+package com.cmss.pretendProxy;
+
+/*
+ Java FTP Proxy Server 1.3.0
+ Copyright (C) 1998-2014 Christian Schmidt
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ Find the latest version at http://aggemam.dk/ftpproxy
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import org.apache.commons.net.ftp.FTPSServerSocketFactory;
+import org.apache.commons.net.ftp.FTPSSocketFactory;
+import org.apache.commons.net.util.TrustManagerUtils;
+
+public class FtpsProxyServer extends FtpProxyServer {
+
+    private SSLContext context;
+
+    public FtpsProxyServer() {
+
+        super.logPrefix = "[FTPS代理]";
+    }
+
+    /**
+     * 初始化context
+     */
+    @Override
+    protected void init() throws Exception {
+
+        final String keyName = "zhou_ks";
+        final char[] keyPwd = "123456".toCharArray();
+        final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+
+        // 装载当前目录下的key store. 可用jdk中的keytool工具生成keystore
+        InputStream in = null;
+        keyStore.load(in = FtpsProxyServer.class.getClassLoader().getResourceAsStream(keyName), keyPwd);
+        in.close();
+
+        // 初始化key manager factory
+        final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(keyStore, keyPwd);
+
+        // 初始化ssl context
+        final TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
+        //            context = SSLContextUtils.createSSLContext("TLS", kmf.getKeyManagers(), trustManager);
+        final SSLContext context = SSLContext.getInstance("TLS");
+        context.init(kmf.getKeyManagers(), new TrustManager[] { trustManager }, new SecureRandom());
+
+        this.context = context;
+        this._socketFactory_ = new FTPSSocketFactory(context);
+        this._serverSocketFactory_ = new FTPSServerSocketFactory(context);
+    }
+
+    @Override
+    protected void _startProxyClient_(final Socket skControlClient) {
+
+        new FtpsProxy(skControlClient).start();
+
+    }
+
+    class FtpsProxy extends FtpProxy {
+
+        public FtpsProxy(final Socket skControlClient) {
+
+            super(skControlClient);
+        }
+
+        @Override
+        protected Socket _connectServer_(final Socket socket, final String hostname, final int serverport)
+                throws IOException {
+
+            final String toServer = "AUTH TLS";
+            psServer.print(toServer + CRLF);
+            debugLog(formatLogPrefix(proxy2server) + toServer);
+            final String fromServer = brServer.readLine();
+            //234 Proceed with negotiation
+            debugLog(formatLogPrefix(server2proxy) + fromServer);
+            final SSLSocketFactory ssf = context.getSocketFactory();
+            final SSLSocket sslSocket = (SSLSocket) ssf.createSocket(skControlServer, hostname, serverport, false);
+            sslSocket.setEnableSessionCreation(true);
+            sslSocket.setUseClientMode(true);
+            sslSocket.setNeedClientAuth(false);
+            sslSocket.setWantClientAuth(false);
+            sslSocket.startHandshake();
+            return sslSocket;
+        }
+
+        @Override
+        protected void _initServer_() throws IOException {
+
+            //登录后相关ftps特有设置设置  与客户端无关
+            //客户端连接优化后可去掉
+            final String toServer = "PROT P";
+            psServer.print(toServer + CRLF);
+            debugLog(formatLogPrefix(proxy2server) + toServer);
+            final String fromServer = brServer.readLine();
+            debugLog(formatLogPrefix(server2proxy) + fromServer);
+        }
+
+        @Override
+        protected void _openConection_() throws IOException {
+
+            //被动模式
+            final SSLSocket sslSocket = (SSLSocket) skDataServer;
+            sslSocket.setEnableSessionCreation(true);
+            sslSocket.setUseClientMode(true);
+            sslSocket.setNeedClientAuth(false);
+            sslSocket.setWantClientAuth(false);
+            sslSocket.startHandshake();
+            infoLog("握手成功");
+            (dcData = new DataConnect(skDataClient, skDataServer)).start();
+
+        }
+
+    }
+
+}

+ 117 - 0
src/main/java/com/cmss/pretendProxy/PretendProxy.java

@@ -0,0 +1,117 @@
+/*------------------------------------------------------------------------------
+ *******************************************************************************
+ * COPYRIGHT China Mobile (SuZhou) Software Technology Co.,Ltd. 2017
+ *******************************************************************************
+ *----------------------------------------------------------------------------*/
+package com.cmss.pretendProxy;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+/**
+ * 代理的启动类,主要工作,读取配置文件,启动代理服务器
+ */
+public class PretendProxy {
+
+    private static final Logger LOGGER = Logger.getLogger(PretendProxy.class);
+
+    private final static String ftpConfigFile = "ftpProxy.conf";
+
+    private final static String ftpsConfigFile = "ftpsProxy.conf";
+
+    private final static String cuttingLine = "==============================";
+
+    public PretendProxy() {
+
+    }
+
+    /**
+     * 代理启动
+     */
+    public void startProxy() throws Exception {
+
+        infoLog("代理启动");
+        infoLog("ftp代理服务启动");
+        startProxy(ftpConfigFile, new FtpProxyServer());
+        infoLog("ftps代理服务启动");
+        startProxy(ftpsConfigFile, new FtpsProxyServer());
+
+    }
+
+    private int startProxy(String configFile, final ProxyServer proxyServer) throws Exception {
+
+        infoLog("读取配置文件");
+        debugLog("读取配置文件开始" + cuttingLine);
+        final Properties properties = new Properties();
+        configFile = PretendProxy.class.getClassLoader().getResource("").getPath().replaceAll("%20", " ") + configFile;
+        infoLog("配置文件路径:" + configFile);
+        try {
+            properties.load(new FileInputStream(configFile));
+        } catch (final IOException e) {
+            errorLog("读取配置文件出错", e);
+            throw e;
+        }
+        debugLog("读取配置文件结束" + cuttingLine);
+
+        infoLog("解析配置文件");
+        debugLog("解析配置文件开始" + cuttingLine);
+        Configuration config;
+        try {
+            config = new Configuration(properties);
+        } catch (final Exception e) {
+            errorLog("解析配置文件出错", e);
+            throw e;
+        }
+        // 在配置类解析时,配置类会删除配置变量——任何剩余的变量都是未知的,因此是无效的。
+        if (properties.size() > 0) {
+            errorLog("无效的配置变量" + properties.propertyNames().nextElement(), null);
+            return -1;
+        }
+        debugLog("解析配置文件结束" + cuttingLine);
+
+        //启动代理
+        infoLog("启动代理");
+        debugLog("启动代理开始" + cuttingLine);
+        proxyServer.setConfig(config);
+        proxyServer.start();
+        debugLog("启动代理结束" + cuttingLine);
+        return 0;
+    }
+
+    /**
+     * 调试日志
+     */
+    private void debugLog(final String msg) {
+
+        LOGGER.debug(msg);
+
+    }
+
+    /**
+     * 普通日志
+     */
+    private void infoLog(final String msg) {
+
+        LOGGER.info(msg);
+
+    }
+
+    /**
+     * 错误日志
+     */
+    private void errorLog(final String msg, final Exception e) {
+
+        LOGGER.error(msg, e);
+
+    }
+
+    public static void main(final String[] args) throws Exception {
+
+        new PretendProxy().startProxy();
+
+    }
+
+}

+ 97 - 0
src/main/java/com/cmss/pretendProxy/ProxyServer.java

@@ -0,0 +1,97 @@
+package com.cmss.pretendProxy;
+
+import java.io.Closeable;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+
+import org.apache.log4j.Logger;
+
+public abstract class ProxyServer extends Thread {
+
+    private static final Logger LOGGER = Logger.getLogger(ProxyServer.class);
+
+    final static String cuttingLine = "==============================";
+
+    final static String server2proxy = "服务端--->代理";
+
+    final static String proxy2server = "代理--->服务端";
+
+    final static String proxy2client = "代理--->客户端";
+
+    final static String client2proxy = "客户端--->代理";
+
+    final static String server2client = "服务端--->客户端";
+
+    final static String client2server = "客户端--->服务端";
+
+    final static String CRLF = "\r\n";
+
+    final static int DATABUFFERSIZE = 512;
+
+    //端口列表
+    final Map lastPorts = new HashMap();
+
+    String logPrefix = "";
+
+    String logPostfix = "";
+
+    Configuration config;
+
+    /** The socket's SocketFactory. */
+    SocketFactory _socketFactory_;
+
+    /** The socket's ServerSocket Factory. */
+    ServerSocketFactory _serverSocketFactory_;
+
+    public void setConfig(final Configuration config) {
+
+        this.config = config;
+    }
+
+    /**
+     * 调试日志
+     */
+    public void debugLog(final String msg) {
+
+        LOGGER.debug(logPrefix + msg + logPostfix);
+
+    }
+
+    /**
+     * 普通日志
+     */
+    public void infoLog(final String msg) {
+
+        LOGGER.info(logPrefix + msg + logPostfix);
+
+    }
+
+    /**
+     * 错误日志
+     */
+    public void errorLog(final String msg, final Exception e) {
+
+        LOGGER.error(logPrefix + msg + logPostfix, e);
+
+    }
+
+    /**
+     * 关闭连接
+     *
+     * @param o
+     * @param msg
+     */
+    public void close(final Object o, final String msg) {
+
+        if (o != null && o instanceof Closeable) {
+            try {
+                ((Closeable) o).close();
+            } catch (final Exception e) {
+                errorLog("关闭" + msg + "异常", e);
+            }
+        }
+    }
+}

+ 167 - 0
src/main/java/com/cmss/pretendProxy/Subnet.java

@@ -0,0 +1,167 @@
+package com.cmss.pretendProxy;
+
+/*
+ * Copyright (C) 1998-2014 Christian Schmidt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+import java.net.InetAddress;
+import java.util.StringTokenizer;
+
+/**
+ * <p>
+ * This class represents an Internet Protocol (IP) subnet.
+ * </p>
+ *
+ * @see java.net.InetAddress
+ */
+
+public class Subnet {
+	private byte[] addr;
+	private byte[] mask;
+
+	/**
+	 * Creates a <code>Subnet</code> object from the specified address and
+	 * subnet mask.
+	 *
+	 * @param inetAddr
+	 *            the address
+	 * @param mask
+	 *            the subnet mask represented as a byte array in network byte
+	 *            order
+	 */
+	public Subnet(InetAddress inetAddr, byte[] mask) {
+		this.addr = inetAddr.getAddress();
+		this.mask = mask;
+
+		for (int i = 0; i < 4; i++) {
+			addr[i] = (byte) (addr[i] & mask[i]);
+		}
+	}
+
+	/**
+	 * Creates a <code>Subnet</code> object from the specified address and
+	 * subnet mask.
+	 *
+	 * @param inetAddr
+	 *            the address
+	 * @param d
+	 *            the subnet mask represented as the number of significant bits
+	 *            (0 through 32)
+	 */
+	public Subnet(InetAddress inetAddr, short d) {
+		if (d > 32) {
+			throw new IllegalArgumentException("Invalid format: " + d);
+		}
+
+		this.addr = inetAddr.getAddress();
+
+		int m = (0xFFFFFFFF << d) & 0xFFFFFFFF;
+
+		this.mask = new byte[4];
+		for (int i = 0; i < 4; i++) {
+			mask[i] = (byte) ((m >> 8 * (3 - i)) & 0xFF);
+			addr[i] = (byte) (addr[i] & mask[i]);
+		}
+	}
+
+	/**
+	 * Creates a <code>Subnet</code> object from the string representation of a
+	 * subnet mask. The subnet mask may be represented as a single IP-address (
+	 * <code>123.45.67.89</code>) or as an entire subnet written as a network
+	 * number and a mask. The mask may either be represented as
+	 * <code>byte</code> array in network byte order (
+	 * <code>123.45.67.89/255.255.254.0</code>) or as a number indicating the
+	 * number of significant bits (<code>123.45.67.89/23</code>).
+	 *
+	 */
+	public Subnet(String subnet) throws IllegalArgumentException {
+		try {
+			int j = subnet.indexOf('/');
+
+			if (j == -1) {
+				// The format is "123.45.67.89".
+
+				this.addr = parseString(subnet);
+				this.mask = new byte[4];
+				mask[0] = mask[1] = mask[2] = mask[3] = (byte) 0xFF;
+			} else {
+				this.addr = parseString(subnet.substring(0, j));
+
+				// The part after the slash.
+				String s = subnet.substring(j + 1);
+				if (s.indexOf('.') == -1) {
+					// The format is "123.45.67.89/23".
+
+					short d = Short.parseShort(s);
+
+					int m = (0xFFFFFFFF << (32 - d)) & 0xFFFFFFFF;
+
+					this.mask = new byte[4];
+					for (int i = 0; i < 4; i++) {
+						mask[i] = (byte) ((m >> 8 * (3 - i)) & 0xFF);
+						addr[i] = (byte) (addr[i] & mask[i]);
+					}
+				} else {
+					// The format is "123.45.67.89/255.255.254.0".
+
+					this.mask = parseString(s);
+					for (int i = 0; i < 4; i++) {
+						addr[i] = (byte) (addr[i] & mask[i]);
+					}
+				}
+			}
+		} catch (RuntimeException e) {
+			throw new IllegalArgumentException("Invalid format: " + subnet);
+		}
+	}
+
+	/**
+	 * Determines whether an <code>InetAddress</code> is included in a given
+	 * subnet.
+	 */
+	public boolean isInSubnet(InetAddress inetAddr) {
+		byte[] address = inetAddr.getAddress();
+
+		for (int i = 0; i < 4; i++) {
+			if (addr[i] != (byte) (address[i] & mask[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Constructs a string representation this subnet. The string is formatted
+	 * like this: <code>123.45.67.89/255.255.254.0</code>.
+	 */
+	public String toString() {
+		return (addr[0] & 0xFF) + "." + (addr[1] & 0xFF) + "."
+				+ (addr[2] & 0xFF) + "." + (addr[3] & 0xFF) + "/"
+				+ (mask[0] & 0xFF) + "." + (mask[1] & 0xFF) + "."
+				+ (mask[2] & 0xFF) + "." + (mask[3] & 0xFF);
+	}
+
+	private static byte[] parseString(String s) {
+		StringTokenizer st = new StringTokenizer(s, ".");
+
+		byte[] addr = new byte[4];
+		for (int i = 0; i < 4; i++) {
+			addr[i] = (byte) Integer.parseInt(st.nextToken());
+		}
+		return addr;
+	}
+}

+ 72 - 0
src/main/resources/ftpProxy.conf

@@ -0,0 +1,72 @@
+### ftpProxy
+### 配置文件
+
+#代理侦听传入连接的端口
+#默认8090
+bind_port=8090
+
+#代理连接数
+bind_backlog=100
+
+#代理服务创建时绑定ip(不填默认全部)
+bind_address=127.0.0.1
+
+#如果希望通过代理返回的ip地址响应PASV命令,在这里插入ip地址或主机名。
+#这可以用来提供外部访问NAT防火墙后的ftp服务器或通过SSH隧道。
+masquerade_host=127.0.0.1
+
+#代理与服务端的数据模式与客户端与代理之间相同,即客户端与代理采用被动模式,代理与服务端也采用被动模式
+#当在客户端和代理之间使用被动模式且代理和服务器之间使用主动模式时,代理选择一个端口号来监听数据连接。
+#如果不能自由选择这个端口号,例如由于客户机和代理或代理和服务器之间的防火墙限制,
+#您可以在这里指定侦听来自服务器和客户端的数据连接时可能使用的端口列表。
+#注意,这些端口范围仅在代理为数据连接(不是在客户端和代理之间的主动模式,或在代理和服务器之间的被动模式下运行)时使用。
+#该格式是一个逗号分隔的端口数或端口范围的列表,其格式为xxxx - yyyy。
+#注意,有些服务器将拒绝连接到特权端口,即端口号< 1024。
+#如果指定一个端口,则使用稍微不同的绑定技术。
+#因此,如果您只指定了几个端口,那么如果您只指定一个端口,您可能会获得更好的结果。
+#但是,您不能有更多的同时连接,而不能有可用的端口。
+#单端口时,数据连接不重开端口,使用旧serverSocket (连接过多不建议使用)
+server_bind_ports=16000-16999
+client_bind_ports=17000-17999
+
+### 访问控制
+
+#使用deny_from和allow_from可以限制哪些客户机可以连接到代理。
+#使用deny_to和allow_to可以限制哪些主机允许连接。
+#如果没有设置deny_from或allow_from,每个人都可以连接。
+#如果只设置了deny_from,那么每个人都可以连接,除了deny_from中提到的那些。
+#如果只设置allow_from,则允许从allow_from中提到的客户端连接。
+#如果设置了deny_from和allow_from,只允许在allow_from中提到的客户机,但不允许在deny_from中连接。
+#同样的逻辑也适用于deny_to和allow_to。
+#该格式与use_passive和use_active相同。
+#deny_to=192.168.0.0/16,172.16.0.0/12,10.0.0.1/8,127.0.0.1
+#deny_from=
+#allow_to=
+#allow_from=
+
+
+### 信息
+
+#如果您想要将另一个消息通过connect发送给客户端,您应该在这里写入。如果only_auto设置为1,则将使用“auto FTP server”的消息。
+#默认为“Java FTP Proxy Server (usage: USERID=user@site) ready.”。
+#msg_connect=Connect fail...
+
+#如果访问被拒绝到deny_from和allow_from的设置,则消息发送给客户端。
+#默认为“Access denied - closing connection.”。
+#msg_origin_access_denied=
+
+#如果由于deny_to和allow_to的设置拒绝访问,则消息发送给客户端。
+#默认为“Access denied - closing connection.”。
+#msg_destination_access_denied=
+
+#如果客户端不提供表单user@site语法的用户名,并且没有指定auto_host,则发送消息。
+#默认为“Incorrect usage - closing  connection.”。
+#msg_incorrect_syntax=
+
+#在未处理的异常事件中发送给客户机的消息。
+#默认是“Internal error, closing  connection.”。
+#msg_internal_error=
+
+#如果masquerade_host无法解析,则消息发送给客户端。
+#默认为“Unable to resolve address for  |masqueradeHostname| - closing connection.”。
+#msg_masqerade_hostname_dns_error=

+ 72 - 0
src/main/resources/ftpsProxy.conf

@@ -0,0 +1,72 @@
+### ftpsProxy
+### 配置文件
+
+#代理侦听传入连接的端口
+#默认8090
+bind_port=8091
+
+#代理连接数
+bind_backlog=100
+
+#代理服务创建时绑定ip(不填默认全部)
+bind_address=127.0.0.1
+
+#如果希望通过代理返回的ip地址响应PASV命令,在这里插入ip地址或主机名。
+#这可以用来提供外部访问NAT防火墙后的ftp服务器或通过SSH隧道。
+masquerade_host=127.0.0.1
+
+#代理与服务端的数据模式与客户端与代理之间相同,即客户端与代理采用被动模式,代理与服务端也采用被动模式
+#当在客户端和代理之间使用被动模式且代理和服务器之间使用主动模式时,代理选择一个端口号来监听数据连接。
+#如果不能自由选择这个端口号,例如由于客户机和代理或代理和服务器之间的防火墙限制,
+#您可以在这里指定侦听来自服务器和客户端的数据连接时可能使用的端口列表。
+#注意,这些端口范围仅在代理为数据连接(不是在客户端和代理之间的主动模式,或在代理和服务器之间的被动模式下运行)时使用。
+#该格式是一个逗号分隔的端口数或端口范围的列表,其格式为xxxx - yyyy。
+#注意,有些服务器将拒绝连接到特权端口,即端口号< 1024。
+#如果指定一个端口,则使用稍微不同的绑定技术。
+#因此,如果您只指定了几个端口,那么如果您只指定一个端口,您可能会获得更好的结果。
+#但是,您不能有更多的同时连接,而不能有可用的端口。
+#单端口时,数据连接不重开端口,使用旧serverSocket (连接过多不建议使用)
+server_bind_ports=18000-18999
+client_bind_ports=19000-19999
+
+### 访问控制
+
+#使用deny_from和allow_from可以限制哪些客户机可以连接到代理。
+#使用deny_to和allow_to可以限制哪些主机允许连接。
+#如果没有设置deny_from或allow_from,每个人都可以连接。
+#如果只设置了deny_from,那么每个人都可以连接,除了deny_from中提到的那些。
+#如果只设置allow_from,则允许从allow_from中提到的客户端连接。
+#如果设置了deny_from和allow_from,只允许在allow_from中提到的客户机,但不允许在deny_from中连接。
+#同样的逻辑也适用于deny_to和allow_to。
+#该格式与use_passive和use_active相同。
+#deny_to=192.168.0.0/16,172.16.0.0/12,10.0.0.1/8,127.0.0.1
+#deny_from=
+#allow_to=
+#allow_from=
+
+
+### 信息
+
+#如果您想要将另一个消息通过connect发送给客户端,您应该在这里写入。如果only_auto设置为1,则将使用“auto FTP server”的消息。
+#默认为“Java FTP Proxy Server (usage: USERID=user@site) ready.”。
+#msg_connect=Connect fail...
+
+#如果访问被拒绝到deny_from和allow_from的设置,则消息发送给客户端。
+#默认为“Access denied - closing connection.”。
+#msg_origin_access_denied=
+
+#如果由于deny_to和allow_to的设置拒绝访问,则消息发送给客户端。
+#默认为“Access denied - closing connection.”。
+#msg_destination_access_denied=
+
+#如果客户端不提供表单user@site语法的用户名,并且没有指定auto_host,则发送消息。
+#默认为“Incorrect usage - closing  connection.”。
+#msg_incorrect_syntax=
+
+#在未处理的异常事件中发送给客户机的消息。
+#默认是“Internal error, closing  connection.”。
+#msg_internal_error=
+
+#如果masquerade_host无法解析,则消息发送给客户端。
+#默认为“Unable to resolve address for  |masqueradeHostname| - closing connection.”。
+#msg_masqerade_hostname_dns_error=

+ 24 - 0
src/main/resources/log4j.properties

@@ -0,0 +1,24 @@
+### set log levels ###
+log4j.rootLogger = debug ,  stdout
+
+### 输出到控制台 ###
+log4j.appender.stdout = org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target = System.out
+log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
+
+### 输出到日志文件 ###
+log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
+log4j.appender.D.File = logs/log.log
+log4j.appender.D.Append = true
+log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
+log4j.appender.D.layout = org.apache.log4j.PatternLayout
+log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
+
+### 保存异常信息到单独文件 ###
+log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
+log4j.appender.D.File = logs/error.log ## 异常日志文件名
+log4j.appender.D.Append = true
+log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
+log4j.appender.D.layout = org.apache.log4j.PatternLayout
+log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

BIN
src/main/resources/zhou_ks


+ 249 - 0
src/test/java/com/cmss/pretendProxy/FtpProxyTest.java

@@ -0,0 +1,249 @@
+package com.cmss.pretendProxy;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.UnknownHostException;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+
+public class FtpProxyTest {
+
+    public static void main(final String[] args) throws UnknownHostException, IOException {
+
+        //        testConnect();
+
+        //        testList();
+
+        testUpload();
+
+        //        testDownload();
+
+    }
+
+    /**
+     * 测试连接代理服务器 和 登录
+     */
+    public static void testConnect() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8090);
+
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("ftp_6@10.139.8.171:21", "ftp_6");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试list目录
+     */
+    public static void testList() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8090);
+
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("ftp_6@10.139.8.171:21", "ftp_6");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+            ftpClient.changeWorkingDirectory("/");// 转移到FTP服务器目录
+
+            ftpClient.enterLocalPassiveMode();
+
+            final FTPFile[] fs = ftpClient.listFiles();
+            System.out.println("size:" + fs.length);
+            for (int i = 0; i < fs.length; i++) {
+                System.out.println(fs[i].getName());
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试upload
+     */
+    public static void testUpload() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            //            ftpClient.connect("127.0.0.1", 8090);
+            ftpClient.connect("10.139.8.126", 21);
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            //            ftpClient.login("ftp_6@10.139.8.171:21", "ftp_6");
+            ftpClient.login("ftp_7", "ftp_7");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+
+            ftpClient.enterLocalPassiveMode();
+
+            final FTPFile[] fs = ftpClient.listFiles();
+            System.out.println("上传前size:" + fs.length);
+            for (int i = 0; i < fs.length; i++) {
+                System.out.println(fs[i].getName());
+            }
+
+            InputStream in = null;
+            // Upload.
+            try {
+                final File file = new File("E:/testProxy.txt");
+
+                // Use passive mode to pass firewalls.
+                ftpClient.enterLocalPassiveMode();
+
+                final String ftpFileName = "testProxy1.txt";
+
+                in = new BufferedInputStream(new FileInputStream(file));
+                if (!ftpClient.storeFile(ftpFileName, in)) {
+                    throw new IOException("Can't upload file '" + ftpFileName
+                            + "' to FTP server. Check FTP permissions and path.");
+                }
+
+            } finally {
+                try {
+                    if (in != null) {
+                        in.close();
+                    }
+                } catch (final IOException ex) {
+                }
+            }
+
+            final FTPFile[] fs1 = ftpClient.listFiles();
+            System.out.println("上传后size:" + fs1.length);
+            for (int i = 0; i < fs1.length; i++) {
+                System.out.println(fs1[i].getName());
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试download
+     */
+    public static void testDownload() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8090);
+
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("ftp_6@10.139.8.171:21", "ftp_6");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+
+            // Download.
+            OutputStream out = null;
+            try {
+                // Use passive mode to pass firewalls.
+                ftpClient.enterLocalPassiveMode();
+
+                final File localFile = new File("E:/testProxyDownload.txt");
+                final String ftpFileName = "us.txt";
+
+                // Download file.
+                out = new BufferedOutputStream(new FileOutputStream(localFile));
+                if (!ftpClient.retrieveFile(ftpFileName, out)) {
+                    throw new IOException("Error loading file " + ftpFileName
+                            + " from FTP server. Check FTP permissions and path.");
+                }
+
+                out.flush();
+            } finally {
+                if (out != null) {
+                    try {
+                        out.close();
+                    } catch (final IOException ex) {
+                    }
+                }
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+}

+ 782 - 0
src/test/java/com/cmss/pretendProxy/FtpsClientTest.java

@@ -0,0 +1,782 @@
+/*------------------------------------------------------------------------------
+ *******************************************************************************
+ * COPYRIGHT China Mobile (SuZhou) Software Technology Co.,Ltd. 2018
+ *******************************************************************************
+ *----------------------------------------------------------------------------*/
+package com.cmss.pretendProxy;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.apache.commons.net.ftp.FTPSClient;
+import org.apache.commons.net.ftp.FTPSServerSocketFactory;
+import org.apache.commons.net.ftp.FTPSSocketFactory;
+import org.apache.commons.net.util.SSLContextUtils;
+import org.apache.commons.net.util.TrustManagerUtils;
+
+public class FtpsClientTest {
+
+    public static void main(final String[] args) throws Exception {
+
+        //        testConnect();
+
+        //        testList();
+
+        _testList();
+
+        // testUpload();
+
+        //        testDownload();
+    }
+
+    public static void testConnect() throws Exception {
+
+        //ftpsClent
+        //        final FTPSClient fc = new FTPSClient(false);
+        //        fc.connect("10.139.5.112", 21);
+        //        fc.login("eshub", "eshub");
+        //        if (!FTPReply.isPositiveCompletion(fc.getReplyCode())) {
+        //            fc.disconnect();
+        //            return;
+        //        }
+        //        System.out.println("登录成功");
+        //        fc.logout();
+
+        //socket
+
+        Socket s = new Socket("10.139.5.112", 21);
+        System.out.println(s);
+        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
+        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
+
+        String readLine = br.readLine();
+        System.out.println(readLine);
+        bw.write("AUTH SSL\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //234 Proceed with negotiation
+        System.out.println(readLine);
+
+        final TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
+        final SSLContext context = SSLContextUtils.createSSLContext("TLS", null, trustManager);
+        final SSLSocketFactory ssf = context.getSocketFactory();
+        final SSLSocket socket = (SSLSocket) ssf.createSocket(s, s.getInetAddress().getHostAddress(), s.getPort(),
+                false);
+        socket.setEnableSessionCreation(true);
+        socket.setUseClientMode(true);
+        socket.startHandshake();
+
+        s = socket;
+        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
+        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
+
+        bw.write("USER eshub\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //331 Please specify the password.
+        System.out.println(readLine);
+        bw.write("PASS eshub\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //230 Login successful.
+        System.out.println(readLine);
+        bw.write("QUIT\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //221 Goodbye.
+        System.out.println(readLine);
+
+    }
+
+    /**
+     * 测试list目录
+     */
+    public static void testList() throws Exception {
+
+        //ftpsClent
+        //        final FTPSClient fc = new FTPSClient(false);
+        //        fc.connect("10.139.5.112", 21);
+        //        fc.login("eshub", "eshub");
+        //        if (!FTPReply.isPositiveCompletion(fc.getReplyCode())) {
+        //            fc.disconnect();
+        //            return;
+        //        }
+        //        System.out.println("登录成功");
+        //
+        //        fc.setFileType(2);
+        //        fc.execPROT("P");
+        //        fc.enterLocalPassiveMode();
+        //
+        //        final FTPFile[] fs = fc.listFiles();
+        //        System.out.println("size:" + fs.length);
+        //        for (int i = 0; i < fs.length; i++) {
+        //            System.out.println(fs[i].getName());
+        //        }
+        //        fc.logout();
+
+        //socket
+
+        Socket cmdSocket = new Socket("10.139.5.112", 21);
+        System.out.println(cmdSocket);
+        BufferedReader br = new BufferedReader(new InputStreamReader(cmdSocket.getInputStream()));
+        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(cmdSocket.getOutputStream()));
+
+        String readLine = br.readLine();
+        System.out.println(readLine);
+        bw.write("AUTH SSL\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //234 Proceed with negotiation
+        System.out.println(readLine);
+
+        final TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
+        final SSLContext context = SSLContextUtils.createSSLContext("TLS", null, trustManager);
+        final SSLSocketFactory ssf = context.getSocketFactory();
+        final SSLSocket socket = (SSLSocket) ssf.createSocket(cmdSocket, cmdSocket.getInetAddress().getHostAddress(),
+                cmdSocket.getPort(), false);
+        socket.setEnableSessionCreation(true);
+        socket.setUseClientMode(true);
+        socket.startHandshake();
+
+        cmdSocket = socket;
+
+        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
+        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
+
+        //登录
+        bw.write("USER eshub\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //331 Please specify the password.
+        System.out.println(readLine);
+        bw.write("PASS eshub\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //230 Login successful.
+        System.out.println(readLine);
+
+        //设置模式
+        bw.write("TYPE I\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //
+        System.out.println(readLine);
+        bw.write("PROT P\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //
+        System.out.println(readLine);
+
+        //开通数据连接
+        bw.write("PASV \r\n");
+        bw.flush();
+        readLine = br.readLine();
+        System.out.println(readLine);
+
+        final int port = parsePort(readLine);
+
+        final SSLSocket dataSocket = (SSLSocket) new FTPSSocketFactory(context).createSocket();
+        dataSocket.connect(new InetSocketAddress(cmdSocket.getInetAddress(), port));
+
+        //发送命令
+        bw.write("LIST\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //
+        System.out.println(readLine);
+
+        dataSocket.setUseClientMode(true);
+        dataSocket.setEnableSessionCreation(true);
+        dataSocket.startHandshake();
+        System.out.println("已建立数据连接");
+        final BufferedReader brClient = new BufferedReader(new InputStreamReader(dataSocket.getInputStream()));
+        final PrintStream psClient = new PrintStream(dataSocket.getOutputStream(), true);
+        while ((readLine = brClient.readLine()) != null) {
+
+            System.out.println(readLine);
+        }
+        readLine = br.readLine();
+        System.out.println(readLine);
+        bw.write("QUIT\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //221 Goodbye.
+        System.out.println(readLine);
+    }
+
+    /**
+     * 测试list目录
+     */
+    public static void _testList() throws Exception {
+
+        //ftpsClent
+        final FTPSClient fc = new FTPSClient(false);
+        fc.connect("10.139.5.112", 21);
+        fc.login("eshub", "eshub");
+        if (!FTPReply.isPositiveCompletion(fc.getReplyCode())) {
+            fc.disconnect();
+            return;
+        }
+        System.out.println("登录成功");
+
+        fc.setFileType(2);
+        fc.execPROT("P");
+        fc.enterLocalPassiveMode();
+
+        final FTPFile[] fs = fc.listFiles();
+        System.out.println("size:" + fs.length);
+        for (int i = 0; i < fs.length; i++) {
+            System.out.println(fs[i].getName());
+        }
+        fc.logout();
+
+        //socket
+
+        Socket cmdSocket = new Socket("10.139.5.112", 21);
+        System.out.println(cmdSocket);
+        BufferedReader br = new BufferedReader(new InputStreamReader(cmdSocket.getInputStream()));
+        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(cmdSocket.getOutputStream()));
+
+        String readLine = br.readLine();
+        System.out.println(readLine);
+        bw.write("AUTH SSL\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //234 Proceed with negotiation
+        System.out.println(readLine);
+
+        final TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
+        final SSLContext context = SSLContextUtils.createSSLContext("TLS", null, trustManager);
+        final SSLSocketFactory ssf = context.getSocketFactory();
+        final SSLSocket socket = (SSLSocket) ssf.createSocket(cmdSocket, cmdSocket.getInetAddress().getHostAddress(),
+                cmdSocket.getPort(), false);
+        socket.setEnableSessionCreation(true);
+        socket.setUseClientMode(true);
+        socket.startHandshake();
+
+        cmdSocket = socket;
+
+        br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
+        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
+
+        //登录
+        bw.write("USER eshub\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //331 Please specify the password.
+        System.out.println(readLine);
+        bw.write("PASS eshub\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //230 Login successful.
+        System.out.println(readLine);
+
+        //设置模式
+        bw.write("TYPE I\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //200 Switching to Binary mode.
+        System.out.println(readLine);
+        bw.write("PROT P\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //200 PROT now Private.
+        System.out.println(readLine);
+
+        //开通数据连接
+
+        final ServerSocket server = new FTPSServerSocketFactory(context).createServerSocket(0, 1,
+                cmdSocket.getLocalAddress());
+        System.out.println(server);
+        final String toServer = "PORT " + cmdSocket.getLocalAddress().getHostAddress().replace('.', ',') + ','
+                + server.getLocalPort() / 256 + ',' + (server.getLocalPort() % 256);
+        System.out.println(toServer);
+        bw.write(toServer + "\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //
+        System.out.println(readLine);
+
+        //发送命令
+        bw.write("LIST\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //
+        System.out.println(readLine);
+
+        final SSLSocket dataSocket = (SSLSocket) server.accept();
+        dataSocket.setUseClientMode(true);
+        dataSocket.setEnableSessionCreation(true);
+        dataSocket.startHandshake();
+        System.out.println("已建立数据连接");
+        final BufferedReader brClient = new BufferedReader(new InputStreamReader(dataSocket.getInputStream()));
+        final PrintStream psClient = new PrintStream(dataSocket.getOutputStream(), true);
+        while ((readLine = brClient.readLine()) != null) {
+
+            System.out.println(readLine);
+        }
+        readLine = br.readLine();
+        System.out.println(readLine);
+        bw.write("QUIT\r\n");
+        bw.flush();
+        readLine = br.readLine();
+        //221 Goodbye.
+        System.out.println(readLine);
+    }
+
+    /**
+     * 测试upload
+     */
+    public static void testUpload() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("172.20.44.229", 8089);
+
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("ftp1@10.139.10.176:21", "ftp123456");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+            // ftpClient.changeWorkingDirectory("/");// 转移到FTP服务器目录
+
+            ftpClient.enterLocalPassiveMode();
+
+            final FTPFile[] fs = ftpClient.listFiles();
+            System.out.println("上传前size:" + fs.length);
+            for (int i = 0; i < fs.length; i++) {
+                System.out.println(fs[i].getName());
+            }
+
+            InputStream in = null;
+            // Upload.
+            try {
+                final File file = new File("D:/testProxy.txt");
+
+                // Use passive mode to pass firewalls.
+                ftpClient.enterLocalPassiveMode();
+
+                final String ftpFileName = "testProxy1.txt";
+
+                in = new BufferedInputStream(new FileInputStream(file));
+                if (!ftpClient.storeFile(ftpFileName, in)) {
+                    throw new IOException("Can't upload file '" + ftpFileName
+                            + "' to FTP server. Check FTP permissions and path.");
+                }
+
+            } finally {
+                try {
+                    if (in != null) {
+                        in.close();
+                    }
+                } catch (final IOException ex) {
+                }
+            }
+
+            final FTPFile[] fs1 = ftpClient.listFiles();
+            System.out.println("上传后size:" + fs1.length);
+            for (int i = 0; i < fs1.length; i++) {
+                System.out.println(fs1[i].getName());
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试download
+     */
+    public static void testDownload() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("10.139.10.123", 8089);
+
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("ftp1@10.139.10.176:21", "ftp123456");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+
+            // Download.
+            OutputStream out = null;
+            try {
+                // Use passive mode to pass firewalls.
+                ftpClient.enterLocalPassiveMode();
+
+                final File localFile = new File("D:/BigFile.zip");
+                final String ftpFileName = "BigFile.zip";
+
+                // Download file.
+                out = new BufferedOutputStream(new FileOutputStream(localFile));
+                if (!ftpClient.retrieveFile(ftpFileName, out)) {
+                    throw new IOException("Error loading file " + ftpFileName
+                            + " from FTP server. Check FTP permissions and path.");
+                }
+
+                out.flush();
+            } finally {
+                if (out != null) {
+                    try {
+                        out.close();
+                    } catch (final IOException ex) {
+                    }
+                }
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    //    @Override
+    //    public void connect(final String hostname, final String portStr, final String username, final String password) {
+    //
+    //        if (isConnected()) {
+    //            LOGGER.error("FTPS已连接!");
+    //            return;
+    //        }
+    //
+    //        int port = 21;
+    //
+    //        if (!("".equals(portStr)) && null != portStr) {
+    //            port = Integer.parseInt(portStr);
+    //        }
+    //
+    //        this.hostname = hostname;
+    //        this.port = port;
+    //        this.username = username;
+    //        this.password = password;
+    //
+    //        try {
+    //
+    //            client.setConnectTimeout(CONNECT_TIMEOUT);
+    //            LOGGER.debug("FTPS连接中。。。");
+    //            client.connect(hostname, port);
+    //            LOGGER.debug("FTPS连接成功。。。");
+    //
+    //            LOGGER.debug("FTPS登录中。。。");
+    //            client.login(username, password);
+    //            if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
+    //                client.disconnect();
+    //                LOGGER.error("FTPS登录失败。。。");
+    //            }
+    //            LOGGER.debug("FTPS登录成功。。。");
+    //
+    //            // PBSZ = 0
+    //            //            client.execPBSZ(0);
+    //
+    //            // 设置以二进制方式传输
+    //            client.setFileType(FTPSClient.BINARY_FILE_TYPE);
+    //            client.setControlEncoding(ENCODING);
+    //            // Protection level set to P
+    //            client.execPROT("P"); // 521 PROT P required
+    //            // 被动模式
+    //            if (PASSIVE_MODE) {
+    //                client.enterLocalPassiveMode();
+    //            }
+    //            client.setSoTimeout(CLIENT_TIMEOUT);
+    //            //            client.setBufferSize(1024 * 1024);
+    //        } catch (final Exception e) {
+    //            LOGGER.error("打开FTPS服务器失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //    }
+    //
+    //    @Override
+    //    public void disconnect() {
+    //
+    //        try {
+    //            if (client != null && client.isConnected()) {
+    //                client.logout();
+    //                client.disconnect();
+    //            }
+    //        } catch (final Exception e) {
+    //            LOGGER.error("关闭FTPS服务器错误,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public void deleteFile(final String filePath) {
+    //
+    //        checkConnected();
+    //
+    //        try {
+    //            client.deleteFile(new String(filePath.getBytes("utf-8"), "iso-8859-1"));
+    //        } catch (final IOException e) {
+    //            LOGGER.error("删除文件【" + filePath + "】失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public void changeDir(final String remotePath) {
+    //
+    //        checkConnected();
+    //
+    //        try {
+    //            client.changeWorkingDirectory(new String(remotePath.getBytes("utf-8"), "iso-8859-1"));
+    //        } catch (final IOException e) {
+    //            LOGGER.error("切换目录【" + remotePath + "】失败,异常信息: ", e);
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public boolean isConnected() {
+    //
+    //        return client != null && client.isConnected();
+    //    }
+    //
+    //    @Override
+    //    public void uploadOutputStream(final InputStream inputStream, final String remotePath) {
+    //
+    //        checkConnected();
+    //
+    //        try {
+    //
+    //            new Thread(new Polling(client)).start();
+    //
+    //            final boolean storeFile = client.storeFile(new String(remotePath.getBytes("utf-8"), "iso-8859-1"),
+    //                    inputStream);
+    //            if (!storeFile) {
+    //                LOGGER.error("目录未找到:" + remotePath);
+    //                throw new BusinessException(FtpExceptionEnum.FTP_DIR_NOT_EXIST.getExceptionType());
+    //            }
+    //        } catch (final IOException e) {
+    //            LOGGER.error("上传文件【" + remotePath + "】失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public InputStream getInputStream(final String remotePath) {
+    //
+    //        checkConnected();
+    //
+    //        try {
+    //
+    //            new Thread(new Polling(client)).start();
+    //
+    //            final InputStream inputStream = client.retrieveFileStream(new String(remotePath.getBytes("utf-8"),
+    //                    "iso-8859-1"));
+    //            if (inputStream == null) {
+    //                LOGGER.error("文件未找到:" + remotePath);
+    //                throw new BusinessException(FtpExceptionEnum.FTP_FILE_NOT_EXIST.getExceptionType());
+    //            }
+    //            return inputStream;
+    //        } catch (final IOException e) {
+    //            LOGGER.error("获取下载流【" + remotePath + "】失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public List<String> lsFile(final String remotePath) {
+    //
+    //        checkConnected();
+    //
+    //        try {
+    //            final FTPFile[] listFiles = client.listFiles(new String(remotePath.getBytes("utf-8"), "iso-8859-1"));
+    //            final List<String> lsFile = new ArrayList<String>();
+    //            for (final FTPFile file : listFiles) {
+    //                if (file.isFile()) {
+    //                    lsFile.add(file.getName());
+    //                }
+    //            }
+    //            return lsFile;
+    //        } catch (final IOException e) {
+    //            LOGGER.error("获取文件列表【" + remotePath + "】失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //    }
+    //
+    //    @Override
+    //    public long getFileSize(final String remotePath) {
+    //
+    //        checkConnected();
+    //        try {
+    //            if (remotePath.lastIndexOf("/") != -1) {
+    //                final String path = remotePath.substring(0, remotePath.lastIndexOf("/"));
+    //                final String fileName = remotePath.substring(remotePath.lastIndexOf("/") + 1);
+    //                final FTPFile[] listFiles = client.listFiles(new String(path.getBytes("utf-8"), "iso-8859-1"));
+    //                for (final FTPFile file : listFiles) {
+    //                    if (fileName.equals(file.getName())) {
+    //                        return file.getSize();
+    //                    }
+    //                }
+    //            } else {
+    //                final FTPFile[] listFiles = client.listFiles();
+    //                for (final FTPFile file : listFiles) {
+    //                    if (remotePath.equals(file.getName())) {
+    //                        return file.getSize();
+    //                    }
+    //                }
+    //            }
+    //            throw new BusinessException(FtpExceptionEnum.FTP_FILE_NOT_EXIST.getExceptionType());
+    //        } catch (final IOException e) {
+    //            LOGGER.error("获取文件大小【" + remotePath + "】失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public void moveFile(final String remotePath, final String movePath) {
+    //
+    //        checkConnected();
+    //        try {
+    //            final boolean result = client.rename(new String(remotePath.getBytes("utf-8"), "iso-8859-1"), new String(
+    //                    movePath.getBytes("utf-8"), "iso-8859-1"));
+    //            if (!result) {
+    //                LOGGER.error("移动文件失败:" + remotePath + ">>>" + movePath);
+    //                throw new BusinessException(FtpExceptionEnum.FTP_MOVE_FILE_NOT_EXIST.getExceptionType());
+    //            }
+    //        } catch (final IOException e) {
+    //            LOGGER.error("移动文件" + remotePath + ">>>" + movePath + "失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+    //
+    //    /**
+    //     * 校验连接
+    //     */
+    //    private void checkConnected() {
+    //
+    //        if (!isConnected()) {
+    //            LOGGER.debug("尚未连接FTPS。。。 ");
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //    }
+    //
+    //    class Polling implements Runnable {
+    //
+    //        private FTPSClient client = null;
+    //
+    //        Polling() {
+    //
+    //        }
+    //
+    //        Polling(final FTPSClient client) {
+    //
+    //            this.client = client;
+    //        }
+    //
+    //        @Override
+    //        public void run() {
+    //
+    //            while (isConnected()) {
+    //                LOGGER.info("FTPS正在轮询");
+    //                try {
+    //                    client.noop();
+    //                } catch (final Exception e) {
+    //                    LOGGER.error("FTPS轮询失败", e);
+    //                }
+    //                try {
+    //                    Thread.sleep(1000 * 60);
+    //                } catch (final Exception e) {
+    //                    LOGGER.error("", e);
+    //                }
+    //            }
+    //
+    //        }
+    //
+    //    }
+    //
+    //    @Override
+    //    public String getRootDir() {
+    //
+    //        checkConnected();
+    //        try {
+    //            final String workingDirectory = client.printWorkingDirectory();
+    //            return workingDirectory;
+    //        } catch (final IOException e) {
+    //            LOGGER.error("获取根目录失败,异常信息: ", e);
+    //            throw new BusinessException(FtpExceptionEnum.FTP_NET_EXCP.getExceptionType());
+    //        }
+    //
+    //    }
+
+    public static int parsePort(String s) throws IOException {
+
+        int port;
+        try {
+            int i = s.lastIndexOf('(');
+            int j = s.lastIndexOf(')');
+            if ((i != -1) && (j != -1) && (i < j)) {
+                s = s.substring(i + 1, j);
+            }
+
+            i = s.lastIndexOf(',');
+            j = s.lastIndexOf(',', i - 1);
+
+            port = Integer.parseInt(s.substring(i + 1));
+            port += 256 * Integer.parseInt(s.substring(j + 1, i));
+        } catch (final Exception e) {
+            throw new IOException();
+        }
+        return port;
+    }
+
+}

+ 265 - 0
src/test/java/com/cmss/pretendProxy/FtpsProxyTest.java

@@ -0,0 +1,265 @@
+/*------------------------------------------------------------------------------
+ *******************************************************************************
+ * COPYRIGHT China Mobile (SuZhou) Software Technology Co.,Ltd. 2017
+ *
+ * The copyright to the computer program(s) herein is the property of
+ * CMSS Co.,Ltd. The programs may be used and/or copied only with written
+ * permission from CMSS Co.,Ltd. or in accordance with the terms and conditions
+ * stipulated in the agreement/contract under which the program(s) have been
+ * supplied.
+ *******************************************************************************
+ *----------------------------------------------------------------------------*/
+package com.cmss.pretendProxy;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+
+public class FtpsProxyTest {
+
+    public static void main(final String[] args) throws Exception {
+
+        //        testConnect();
+
+        //        testList();
+
+        //        testUpload();
+
+        testDownload();
+    }
+
+    /**
+     * 测试连接代理服务器 和 登录
+     */
+    public static void testConnect() {
+
+        //        final FTPSClient ftpClient = new FTPSClient(false);
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8091);
+
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("eshub@10.139.5.112:21", "eshub");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试list目录
+     */
+    public static void testList() {
+
+        final FTPClient ftpClient = new FTPClient();
+        //        final FTPSClient ftpClient = new FTPSClient();
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8091);
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("eshub@10.139.5.112:21", "eshub");
+
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+            //            ftpClient.changeWorkingDirectory("/");// 转移到FTP服务器目录
+
+            ftpClient.enterLocalPassiveMode();
+            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
+            ftpClient.setControlEncoding("UTF-8");
+
+            final FTPFile[] fs = ftpClient.listFiles();
+            System.out.println("size:" + fs.length);
+            for (int i = 0; i < fs.length; i++) {
+                System.out.println(fs[i].getName());
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试upload
+     */
+    public static void testUpload() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8091);
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("eshub@10.139.5.112:21", "eshub");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+            // ftpClient.changeWorkingDirectory("/");// 转移到FTP服务器目录
+
+            ftpClient.enterLocalPassiveMode();
+            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
+            ftpClient.setControlEncoding("UTF-8");
+
+            final FTPFile[] fs = ftpClient.listFiles();
+            System.out.println("上传前size:" + fs.length);
+            for (int i = 0; i < fs.length; i++) {
+                System.out.println(fs[i].getName());
+            }
+
+            InputStream in = null;
+            // Upload.
+            try {
+                final File file = new File("E:/testProxy.txt");
+
+                // Use passive mode to pass firewalls.
+                ftpClient.enterLocalPassiveMode();
+
+                final String ftpFileName = "testProxy1.txt";
+
+                in = new BufferedInputStream(new FileInputStream(file));
+                if (!ftpClient.storeFile(ftpFileName, in)) {
+                    throw new IOException("Can't upload file '" + ftpFileName
+                            + "' to FTP server. Check FTP permissions and path.");
+                }
+
+            } finally {
+                try {
+                    if (in != null) {
+                        in.close();
+                    }
+                } catch (final IOException ex) {
+                }
+            }
+
+            final FTPFile[] fs1 = ftpClient.listFiles();
+            System.out.println("上传后size:" + fs1.length);
+            for (int i = 0; i < fs1.length; i++) {
+                System.out.println(fs1[i].getName());
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+    /**
+     * 测试download
+     */
+    public static void testDownload() {
+
+        final FTPClient ftpClient = new FTPClient();
+
+        try {
+            int reply;
+            // 代理服务器IP和端口
+            ftpClient.connect("127.0.0.1", 8091);
+            // 登录名:FTP服务器用户名@FTP服务器IP:端口,密码:FTP服务器用户名对应的密码
+            ftpClient.login("eshub@10.139.5.112:21", "eshub");
+            reply = ftpClient.getReplyCode();
+
+            System.out.println("reply:" + reply);
+
+            if (!FTPReply.isPositiveCompletion(reply)) {
+                ftpClient.disconnect();
+                return;
+            }
+
+            // Download.
+            OutputStream out = null;
+            try {
+                // Use passive mode to pass firewalls.
+                ftpClient.enterLocalPassiveMode();
+                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
+                ftpClient.setControlEncoding("UTF-8");
+
+                final File localFile = new File("E:/textDownload.txt");
+                final String ftpFileName = "testProxy1.txt";
+
+                // Download file.
+                out = new BufferedOutputStream(new FileOutputStream(localFile));
+                if (!ftpClient.retrieveFile(ftpFileName, out)) {
+                    throw new IOException("Error loading file " + ftpFileName
+                            + " from FTP server. Check FTP permissions and path.");
+                }
+
+                out.flush();
+            } finally {
+                if (out != null) {
+                    try {
+                        out.close();
+                    } catch (final IOException ex) {
+                    }
+                }
+            }
+
+            ftpClient.logout();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.disconnect();
+                } catch (final IOException ioe) {
+                }
+            }
+        }
+    }
+
+}