miketeo / pysmb

pysmb is an experimental SMB/CIFS library written in Python. It implements the client-side SMB/CIFS protocol (SMB1 and SMB2) which allows your Python application to access and transfer files to/from SMB/CIFS shared folders like your Windows file sharing and Samba folders.
Other
341 stars 94 forks source link

Possible issue in class DirectTCPSessionMessage #157

Open pasiorovuo opened 4 years ago

pasiorovuo commented 4 years ago

We have been experiencing an odd issue where pysmb fails after around 15 minutes, with the exception below (date + time added by execution script):

Wed May 20 10:10:45 UTC 2020
Traceback (most recent call last):
  File "transfer.py", line 116, in <module>
    main()
  File "transfer.py", line 110, in main
    timeout=CIFS_TIMEOUT
  File "/usr/local/lib/python3.7/site-packages/smb/SMBConnection.py", line 365, in storeFile
    return self.storeFileFromOffset(service_name, path, file_obj, 0, True, timeout)
  File "/usr/local/lib/python3.7/site-packages/smb/SMBConnection.py", line 396, in storeFileFromOffset
    self._pollForNetBIOSPacket(timeout)
  File "/usr/local/lib/python3.7/site-packages/smb/SMBConnection.py", line 634, in _pollForNetBIOSPacket
    self.feedData(data)
  File "/usr/local/lib/python3.7/site-packages/nmb/base.py", line 49, in feedData
    length = self.data_nmb.decode(self.data_buf, offset)
  File "/usr/local/lib/python3.7/site-packages/nmb/nmb_structs.py", line 60, in decode
    raise NMBError("Invalid protocol header for Direct TCP session message")
nmb.nmb_structs.NMBError: Invalid protocol header for Direct TCP session message
Wed May 20 10:15:45 UTC 2020

We initiated the connection with following command:

    connection = smb.SMBConnection.SMBConnection(
        username=parsed.username or '',
        password=parsed.password or '',
        my_name='',
        remote_name='',
        use_ntlm_v2=True,
        is_direct_tcp=True
    )

is_direct_tcp being the thing to note here.

I took a look at the source code of version 1.2.1 and traced back to where the exception originated, and this stands out in method decode on line 57 of nmb_structs.py:

length = struct.unpack(self.HEADER_STRUCT_FORMAT, data[offset:offset+self.HEADER_STRUCT_SIZE])[0]

On line 33 in same file (decode() of NMBSessionMessage) we have:

self.type, self.flags, length = struct.unpack(self.HEADER_STRUCT_FORMAT, data[offset:offset+self.HEADER_STRUCT_SIZE])

Difference being that the length is the 3rd element of the tuple returned by decode() of NMBSessionMessage and 1st in DirectTCPSessionMessage's decode(). Could this be the issue here?

miketeo commented 4 years ago

@pasiorovuo : May I know if there is prolonged time lapse where the SMBConnection instance was left idling in your application? You have mentioned that pysmb fails after around 15 minutes,

SMBConnection was not designed to be left idle by the application. When SMBConnection is left idle, it is unable to keep the SMB connection "alive", so the server might just assume the connection is dead and close the connection.

pasiorovuo commented 4 years ago

We thought about that too. However, in our case we move (read, copy, delete from SMB location) small files, ranging from few kb to 100 kb from an on-premise location to AWS S3. The process was moving around 10 to 15 files per second without idle periods.

pasiorovuo commented 4 years ago

The issue can be worked around with using is_direct_tcp=False during creation of the connection.