You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

连接OpenShift集群FTP服务器时遇SSLException问题求助

问题描述

尝试连接OpenShift集群中运行的FTP服务器上传文件时,遭遇SSL关闭状态异常。代码基于Apache Mina FTPServer嵌入指南编写,求可行解决方案。

错误信息

javax.net.ssl.SSLException: Improper close state: Status = OK HandshakeStatus = NEED_WRAP
bytesConsumed = 0 bytesProduced = 7 sequenceNumber = 0
    at org.apache.mina.filter.ssl.SslHandler.closeOutbound(SslHandler.java:496)
    at org.apache.mina.filter.ssl.SslFilter.initiateClosure(SslFilter.java:773)
    at org.apache.mina.filter.ssl.SslFilter.filterClose(SslFilter.java:704)
    at org.apache.mina.core.filterchain.DefaultIoFilterChain.callPreviousFilterClose(DefaultIoFilterChain.java:776)
    at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1600(DefaultIoFilterChain.java:49)
    at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.filterClose(DefaultIoFilterChain.java:1155)
    at org.apache.mina.core.filterchain.IoFilterEvent.fire(IoFilterEvent.java:88)
    at org.apache.mina.filter.logging.MdcInjectionFilter.filter(MdcInjectionFilter.java:162)
    at org.apache.mina.filter.util.CommonEventFilter.filterClose(CommonEventFilter.java:60)
    at org.apache.mina.core.filterchain.DefaultIoFilterChain.callPreviousFilterClose(DefaultIoFilterChain.java:776)
    ...(省略重复栈帧)
    at java.base/java.lang.Thread.run(Thread.java:829)

Spring Boot 代码

@Configuration
public class FtpServerConfig {
    @Bean
    public FtpServerFactory ftpServerFactory() throws FtpException {
        FtpServerFactory serverFactory = new FtpServerFactory();
        ListenerFactory factory = new ListenerFactory();
        // 设置服务器地址
        factory.setServerAddress("localhost");
        // 设置端口
        factory.setPort(50001);

        // SSL 配置
        SslConfigurationFactory ssl = new SslConfigurationFactory();
        ssl.setKeystoreFile(new File("/tmp/tls/keystore.jks"));
        ssl.setKeystorePassword("passward");
        // 为监听器设置SSL配置
        factory.setSslConfiguration(ssl.createSslConfiguration());
        factory.setImplicitSsl(true);

        // 数据连接配置
        DataConnectionConfigurationFactory dataConnectionConfigFactory = new DataConnectionConfigurationFactory();
        // 禁用主动模式,使用被动连接
        dataConnectionConfigFactory.setActiveEnabled(false);
        // 设置被动端口范围
        dataConnectionConfigFactory.setPassivePorts("50000-60100");
        factory.setDataConnectionConfiguration(dataConnectionConfigFactory.createDataConnectionConfiguration());

        // 添加监听器
        serverFactory.addListener("default", factory.createListener());
        // 设置用户管理器
        serverFactory.setUserManager(getUserManager());
        return serverFactory;
    }

    private UserManager getUserManager() throws FtpException {
        PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
        UserManager userManager = userManagerFactory.createUserManager();

        BaseUser user = new BaseUser();
        user.setName("user");
        user.setPassword("123");

        FileUtil.createNewDirectory(ftpServerDir);
        user.setHomeDirectory("/tmp/my_ftp_server");
        user.setEnabled(true);
        List<Authority> authorities = new ArrayList<>();
        authorities.add(new WritePermission());
        authorities.add(new ConcurrentLoginPermission(0, 0));
        authorities.add(new TransferRatePermission(0, 0));
        user.setAuthorities(authorities);
        userManager.save(user);
        return userManager;
    }
}

@SpringBootApplication
public class FtpServerApplication implements CommandLineRunner {
    @Autowired
    private FtpServerFactory ftpServerFactory;

    public static void main(String[] args) {
        SpringApplication.run(FtpServerApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        FtpServer ftpServer = ftpServerFactory.createServer();
        ftpServer.start();
    }
}
解决方案

针对该SSL异常,结合OpenShift环境特性,可从以下方向排查修复:

1. 修正SSL握手匹配逻辑

异常源于SSL握手未完成时触发连接关闭,大概率是客户端与服务器的SSL模式不匹配:

  • 调整隐式SSL设置:如果客户端使用显式SSL(需发送AUTH TLS命令触发加密),将factory.setImplicitSsl(true)改为false,让连接先以明文建立,再通过命令切换到SSL。
  • 验证密钥库有效性:确保容器内/tmp/tls/keystore.jks路径正确、权限可读,密码与配置一致。可在容器内执行keytool -list -keystore /tmp/tls/keystore.jks验证密钥库状态。

2. 适配OpenShift网络配置

OpenShift Pod网络有严格的端口暴露和路由规则,需调整FTP服务器的网络相关配置:

  • 暴露被动端口范围:在Deployment的ports字段中添加50000-60100端口范围,或通过Service的nodePort/clusterIP配置确保端口可访问;若需外部访问,需配置Route并映射对应端口。
  • 修改服务器绑定地址:localhost仅允许容器内部访问,改为绑定0.0.0.0让服务器监听所有网卡;同时配置被动连接的外部地址,确保客户端能获取到可访问的IP/域名:
    factory.setServerAddress("0.0.0.0");
    dataConnectionConfigFactory.setPassiveExternalAddress("your-openshift-route-hostname");
    

3. 自定义连接关闭逻辑

重写Mina的IoHandler,避免在SSL握手未完成时强制关闭连接:

public class CustomFtpHandler extends IoHandlerAdapter {
    @Override
    public void inputClosed(IoSession session) throws Exception {
        SslHandler sslHandler = session.getAttribute(SslHandler.class);
        if (sslHandler != null && !sslHandler.isHandshakeComplete()) {
            session.closeOnFlush();
            return;
        }
        super.inputClosed(session);
    }
}

在FtpServerFactory中设置自定义Handler:

serverFactory.setFtpHandler(new CustomFtpHandler());

4. 检查依赖版本兼容性

老旧版本的Apache Mina FTPServer可能存在SSL处理bug,尝试升级到最新稳定版,确保与Spring Boot版本兼容。


内容的提问来源于stack exchange,提问作者Chetan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:12:00