Advertisement
Guest User

ftpclient_ipv6.py

a guest
Mar 16th, 2017
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.89 KB | None | 0 0
  1. # Monkey patch `twisted.protocols.ftp.decodeHostPort` and
  2. # inherit from `twisted.protocols.ftp.FtpClient`
  3. from twisted.internet import defer
  4. from twisted.protocols.ftp import (
  5.     FTPFileListProtocol, decodeHostPort, FTPCommand, _unwrapFirstError, _PassiveConnectionFactory)
  6. from twisted.protocols.ftp import FTPClient as _FTPClient
  7.  
  8.  
  9. def _decodeHostPort(line):
  10.     if line.startswith("Entering Extended Passive Mode (|||"):
  11.         # https://github.com/basvodde/filezilla/blob/8f874dfe2fdfee4a95cf706bc860252a5793c32e/src/engine/ftpcontrolsocket.cpp#L3789
  12.         line = line[line.find("|||") + 3:]
  13.         host = None
  14.         port = int("".join([s for s in line if s.isdigit()]))
  15.         if port <= 0 or port > 65535:
  16.             raise ValueError("Bad port in EPSV response")
  17.     else:
  18.         abcdef = re.sub("[^0-9, ]", "", line)
  19.         parsed = [int(p.strip()) for p in abcdef.split(",")]
  20.         for x in parsed:
  21.             if x < 0 or x > 255:
  22.                 raise ValueError("Out of range", line, x)
  23.         a, b, c, d, e, f = parsed
  24.         host = "%s.%s.%s.%s" % (a, b, c, d)
  25.         port = (int(e) << 8) + int(f)
  26.         pass
  27.     return host, port
  28.  
  29. decodeHostPort = _decodeHostPort
  30.  
  31.  
  32. class FTPClient(_FTPClient):
  33.     def __init__(self, username, password, passive="EPSV"):
  34.         """
  35.        :param username: FTP user
  36.        :param password: FTP pass
  37.        :param passive: 'EPSV' (default) or 'PASV'
  38.        """
  39.         super(FTPClient, self).__init__(username=username,
  40.                                         password=password,
  41.                                         passive=passive)
  42.  
  43.     def _openDataConnection(self, commands, protocol):
  44.         cmds = [FTPCommand(command, public=1) for command in commands]
  45.         cmdsDeferred = defer.DeferredList([cmd.deferred for cmd in cmds],
  46.                                           fireOnOneErrback=True, consumeErrors=True)
  47.         cmdsDeferred.addErrback(_unwrapFirstError)
  48.  
  49.         if self.passive:
  50.             _mutable = [None]
  51.  
  52.             def doPassive(response):
  53.                 host, port = decodeHostPort(response[-1][4:])
  54.                 if not host:
  55.                     host = self.transport.addr[0]
  56.  
  57.                 f = _PassiveConnectionFactory(protocol)
  58.                 _mutable[0] = self.connectFactory(host, port, f)
  59.  
  60.             pasvCmd = FTPCommand(self.passive)
  61.             self.queueCommand(pasvCmd)
  62.             pasvCmd.deferred.addCallback(doPassive).addErrback(self.fail)
  63.  
  64.             results = [cmdsDeferred, pasvCmd.deferred, protocol.deferred]
  65.             d = defer.DeferredList(results, fireOnOneErrback=True, consumeErrors=True)
  66.             d.addErrback(_unwrapFirstError)
  67.  
  68.             def close(x, m=_mutable):
  69.                 m[0] and m[0].disconnect()
  70.                 return x
  71.  
  72.             d.addBoth(close)
  73.  
  74.         for cmd in cmds:
  75.             self.queueCommand(cmd)
  76.         return d
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement