Search code examples
javaftpsapache-commons-net

Apache FTPSClient hangs on data transfer


We use org.apache.commons.net FTPClient and wish to add FTPS support with FTPSClient.

Unfortunately transfer hangs whenever server sends 150 code.

This is an attempt to reading directory list:

220 Welcome
AUTH TLS
234 Proceed with negotiation.
USER *****
331 Please specify the password.
PASS *****
230 Login successful.
TYPE I
200 Switching to Binary mode.
PBSZ 0
200 PBSZ set to 0.
PROT P
200 PROT now Private.
SYST
215 UNIX Type: L8
PASV
227 Entering Passive Mode (******).
LIST
150 Here comes the directory listing.

Unsupported or unrecognized SSL message

and this is attempt for file upload:

220 Welcome
AUTH TLS
234 Proceed with negotiation.
USER *****
331 Please specify the password.
PASS *****
230 Login successful.
TYPE I
200 Switching to Binary mode.
PBSZ 0
200 PBSZ set to 0.
PROT P
200 PROT now Private.
PASV
227 Entering Passive Mode (******).
150 Ok to send data.

Read timed out
java.net.SocketTimeoutException: Read timed out

test file is being created but with some bogus payload and connection hangs until it times out.

Interesting thing is that with javax.net.debug=all option, I can see the last written chunk:

javax.net.ssl|DEBUG|10|Test worker|2021-01-13 02:02:59.467 CET|SSLSocketOutputRecord.java:255|Raw write (
  0000: 16 03 03 01 93 01 00 01   8F 03 03 70 08 E3 CA EF  ...........p....
  0010: BD A1 F6 D4 9C 86 24 F0   89 00 D1 7A 34 89 5E FB  ......$....z4.^.
  0020: 8D 3D 40 AE BC A8 22 32   85 09 CB 20 80 AB 30 AD  .=@..."2... ..0.
  0030: A3 C4 8F C8 24 62 D5 85   9C FC 17 60 56 1D 91 54  ....$b.....`V..T
  0040: 59 E2 01 A6 F1 B2 EE E6   F8 08 1A EC 00 5A 13 01  Y............Z..
  0050: 13 02 C0 2C C0 2B C0 30   00 9D C0 2E C0 32 00 9F  ...,.+.0.....2..
  0060: 00 A3 C0 2F 00 9C C0 2D   C0 31 00 9E 00 A2 C0 24  .../...-.1.....$
  0070: C0 28 00 3D C0 26 C0 2A   00 6B 00 6A C0 0A C0 14  .(.=.&.*.k.j....
  0080: 00 35 C0 05 C0 0F 00 39   00 38 C0 23 C0 27 00 3C  .5.....9.8.#.'.<
  0090: C0 25 C0 29 00 67 00 40   C0 09 C0 13 00 2F C0 04  .%.).g.@...../..
  00A0: C0 0E 00 33 00 32 00 FF   01 00 00 EC 00 05 00 05  ...3.2..........
  00B0: 01 00 00 00 00 00 0A 00   12 00 10 00 17 00 18 00  ................
  00C0: 19 01 00 01 01 01 02 01   03 01 04 00 0B 00 02 01  ................
  00D0: 00 00 0D 00 28 00 26 04   03 05 03 06 03 08 04 08  ....(.&.........
  00E0: 05 08 06 08 09 08 0A 08   0B 04 01 05 01 06 01 04  ................
  00F0: 02 03 03 03 01 03 02 02   03 02 01 02 02 00 32 00  ..............2.
  0100: 28 00 26 04 03 05 03 06   03 08 04 08 05 08 06 08  (.&.............
  0110: 09 08 0A 08 0B 04 01 05   01 06 01 04 02 03 03 03  ................
  0120: 01 03 02 02 03 02 01 02   02 00 11 00 09 00 07 02  ................
  0130: 00 04 00 00 00 00 00 17   00 00 00 2B 00 09 08 03  ...........+....
  0140: 04 03 03 03 02 03 01 00   2D 00 02 01 01 00 33 00  ........-.....3.
  0150: 47 00 45 00 17 00 41 04   B4 84 79 54 04 7E 9C FD  G.E...A...yT....
  0160: 59 ED 51 E8 8D 82 FE 02   0A DA E4 91 10 AA D7 FB  Y.Q.............
  0170: 5E DE A9 0B 9A F7 F6 58   9D A3 D3 B6 1A 99 61 B8  ^......X......a.
  0180: 8F 6F 25 98 4A 12 5A 93   9D D6 64 2A A8 F2 DF D5  .o%.J.Z...d*....
  0190: 3E 33 69 49 7B B4 E6 6D                            >3iI...m
)
javax.net.ssl|WARNING|10|Test worker|2021-01-13 02:03:59.530 CET|SSLSocketImpl.java:1555|handling exception (
"throwable" : {
  java.net.SocketTimeoutException: Read timed out

This last chunk is what is being saved on server as a file content and no finish response.

Currently I don't know what server is is or it's configuration, unfortunately it's a blackbox to us.

Here is our test code (client setup part simplified without exception handling to reduce post):

        val ftp = FTPSClient()

        ftp.addProtocolCommandListener(PrintCommandListener(PrintWriter(System.out)));
        ftp.connect(uri.host, uri.port)
        ftp.login(uri.username, uri.password)
        ftp.setFileType(FTP.BINARY_FILE_TYPE)
        ftp.enterLocalPassiveMode()
        ftp.execPBSZ(0)
        ftp.execPROT("P")

        //ftp.listFiles().forEach { println(it) }

        if (!ftp.storeFile("test", "test".byteInputStream())) {
            println("FTP server responded: ${ftp.replyCode} ${ftp.replyString}")
        }

What can be the problem? Is it our code's fault (or Apache library) or it's some server misbehavior?


Solution

  • Even though I have no idea what is the source of the bug, I downgraded Apache Commons Net version from 3.7 to 3.6 and it works. Will try to dig deeper and maybe find more details, but the solution is to just downgrade library version.

    -edit-

    I also tested with 3.7.2 and now it works, so we simply used a buggy version of the lib :).