Criando um servidor FTP simples com python
O que é FTP?
FTP é um acrônimo de File Transfer Protocol. É um protocolo inventado por Abhay Bhushan em abril de 1971 para resolver os problemas de transferências de dados na ARPANET, rede precursora (pode-se dizer mãe) da Internet, sendo que ele é anterior ao TCP e IP.
Baseado no trabalho de Abhay Bhushan foi criada a RFC114, que padronizou a primeira versão do protocolo.
Posteriormente o protocolo FTP foi modificado para trabalhar sobre o TCP.
O protocolo FTP está em constante evolução, sendo que a versão mais recente para IPv4 é o RFC959, com melhorias de segurança adicionada pelo RFC2228 e pela adição na RFC2428 de extensões para suporte a IPv6.
FTP tambem é o nome que comumente referencia software o "servidor ftp" e o software "cliente ftp".
Como funciona ?
O protocolo FTP possui dois modos de funcionamento. O modo Ativo e o modo Passivo.
Em ambos os casos, o cliente cria uma conexão de controle TCP em uma porta não privilegiada aleatória N para a porta de comando do servidor FTP, ou seja, a porta 21 do servidor FTP. Essa conexão é chamada de conexão de controle.
No modo Ativo, o cliente começa a escutar conexões de dados recebidas na porta N+1 a partir do servidor (o cliente envia o comando FTP PORT N+1 para informar o servidor no qual a porta está ouvindo).
Em situações em que o cliente está atrás de um firewall e é incapaz de aceitar conexões TCP, o modo Passivo pode ser usado.
Neste modo, o cliente usa a conexão de controle para enviar o comando PASV para o servidor, que em seguida responde ao cliente enviando o endereço IP e número da porta do servidor, o qual o cliente usa para abrir uma conexão de dados de uma porta arbitraria para o ip e porta enviado pelo servidor.
Comandos FTP
O RFC959 bem como as posteriores modificações, adicionam alguns comandos que devem ser implementados pelos servidores e clientes FTP.
A lista com alguns desse comandos pode ser vista no link: http://en.wikipedia.org/wiki/List_of_FTP_commands
Servidor FTP
Existem vários softwares que implementam um servidor FTP.
Os mais conhecidos e utilizados são: vsftpd (Very Secure FTP Daemon) e ProFTPd para Linux, e o FileZilla Server para Windows.
Uma lista mais completa pode ser encontrada no Wikipedia, neste link: http://en.wikipedia.org/wiki/List_of_FTP_server_software
Cliente FTP
Existem varios clientes para o protocolo FTP.
O Windows Explorer, gerenciador de arquivos padrão em ambiente Windows, possui suporte completo ao protocolo FTP.
O navegador web Mozilla Firefox, bem como os navegadores Google Chrome, Internet Explorer, possuem capacidade de acessar servidores ftp, mas somente em modo de leitura.
O complemento FireFTP para o navegador web Mozilla Firefox, adiciona ao Firefox suporte completo ao protocolo FTP.
pyftpdlib - O que é?
pyftpdlib é uma biblioteca Python que implementa um Servidor FTP, fornecendo uma interface de alto nivel para facilmente escrever servidores FTP muito eficientes, escaláveis e assíncronos.
É a implementação do RFC959 servidor de FTP mais completo disponível para a linguagem de programação Python e é usado em projetos como o Google Chromium e Bazaar e incluída por padrão nos repositórios de pacotes do Debian, Ubuntu, Fedora e FreeBSD.
Recursos
- Extremamente leve, rápido e escalável (veja os benchmarks e o porquê).
- Usa sendfile (2) (ver pysendfile) chamada de sistema para uploads.
- Usa epoll() / kqueue() / select() para lidar com a concorrência de forma assíncrona, e opcionalmente, tambem suporta modelo de multiplas threads/processos.
- É portavel: inteiramente escrito em Python puro; trabalha com Python 2.4 à 3.4 (usando uma única base de código).
- Suporta SFTP (RFC4217), IPv6 (RFC2428), os nomes de arquivo Unicode (RFC2640), comando MLSD/MLST (RFC3659).
- Suporta usuários virtuais e sistemas de arquivos virtuais.
- Sistema extremamente flexível de "autorizadores", capaz de gerenciar usuários "virtuais" e usuários "reais" em tanto UNIX e Windows.
- Cobertura de teste perto de 100%.
Instalando no Ubuntu 14.04 64bits
Para instalar é relativamente simples. Você possui duas opções de como instalar.
Opção 1 - Instalar diretametente à partir do repositório do Ubuntu. :
Abra um terminal e execute:
sudo apt-get install python-pyftpdlib
Obs: O repositório do ubuntu possui uma versão muito desatualizada (1.2) do pyftpdlib, que atualmente está na versão 1.4. Recomendo usar a opção 2.
Opção 2 - Instalar utilizando o pip:
Supondo que você já possua o pip instalado.
Abra um terminal e execute:
sudo pip install pyftpdlib
Se não possuir o pip instalado.
sudo apt-get install python-setuptools
sudo easy_install pip
sudo pip install pyftpdlib
Modo standalone
Com o modo standalone, você pode criar rápidamente um servidor FTP anonimo somente leitura, disponibilizar os arquivos do diretorio atual simplesmente executando:
python -m pyftpdlib
Após executar o comando acima, você obterá uma saida similar a esta:
fabio@luzfcb:~$ python -m pyftpdlib
[I 14-06-11 13:17:38] >>> starting FTP server on 0.0.0.0:2121, pid=21884 <<<
[I 14-06-11 13:17:38] poller: <class 'pyftpdlib.ioloop.Epoll'>
[I 14-06-11 13:17:38] masquerade (NAT) address: None
[I 14-06-11 13:17:38] passive ports: None
[I 14-06-11 13:17:38] use sendfile(2): False
Para visualizar localmente, abra o navegador e acesse o endereço ftp://127.0.0.1:2121 ou ftp://endereço_ip_ou_hostname_atual_do_seu_servidor:2121
Você vai obter algo como:
No terminal, você poderá visualizar o log:
fabio@luzfcb:~$ python -m pyftpdlib
[I 14-06-11 13:17:38] >>> starting FTP server on 0.0.0.0:2121, pid=21884 <<<
[I 14-06-11 13:17:38] poller: <class 'pyftpdlib.ioloop.Epoll'>
[I 14-06-11 13:17:38] masquerade (NAT) address: None
[I 14-06-11 13:17:38] passive ports: None
[I 14-06-11 13:17:38] use sendfile(2): False
[I 14-06-11 13:22:28] 127.0.0.1:41154-[] FTP session opened (connect)
[I 14-06-11 13:22:28] 127.0.0.1:41154-[anonymous] USER 'anonymous' logged in.
[I 14-06-11 13:22:28] 127.0.0.1:41154-[anonymous] CWD /home/luzfcb/pythonclub.github.io 250
[I 14-06-11 13:22:28] 127.0.0.1:41154-[anonymous] FTP session closed (disconnect
Você tambem pode usar algumas opções para modificar como o pyftpdlib é iniciado.
Para ver estas opção, execute:
fabio@luzfcb:~$ python -m pyftpdlib -h
Start a stand alone anonymous FTP server.
Options:
-h, --help
show this help message and exit
-i ADDRESS, --interface=ADDRESS
specify the interface to run on (default all interfaces)
-p PORT, --port=PORT
specify port number to run on (default 2121)
-w, --write
grants write access for the anonymous user (default read-only)
-d FOLDER, --directory=FOLDER
specify the directory to share (default current directory)
-n ADDRESS, --nat-address=ADDRESS
the NAT address to use for passive connections
-r FROM-TO, --range=FROM-TO
the range of TCP ports to use for passive connections (e.g. -r 8000-9000)
-v, --version
print pyftpdlib version and exit
-V, --verbose
activate a more verbose logging
Por exemplo, poderiamos mudar a porta padrão
python -m pyftpdlib -p 8080
Se você quiser iniciar o servidor FTP de modo que quem for acessar não necessite informar a porta, ou seja ele poderá acessar o servidor em um endereço similar a ftp://127.0.0.1 ou ftp://endereço_ip_ou_hostname_atual_do_seu_servidor, é necessario executá-lo como super-usuário, informando a porta 21, que é a padrão do protocolo, conforme exemplificado abaixo.
sudo python -m pyftpdlib -p 21
Modo customizado por você
Em um exemplo um pouco mais complicado, pode-se programar um servidor FTP com autenticação, com multiplos processos, que usa os usuarios e senha já definidos no Linux/Unix.
import logging
import sys
from pyftpdlib.handlers import FTPHandler
# servidor normal
#from pyftpdlib.servers import FTPServer
# servidor multiprocesso
from pyftpdlib.servers import MultiprocessFTPServer
from pyftpdlib.authorizers import UnixAuthorizer
from pyftpdlib.filesystems import UnixFilesystem
def main():
# configuracao de log
logger = logging.getLogger()
ch = logging.StreamHandler(sys.stdout)
logger.setLevel(logging.DEBUG)
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
# fim configuracao de log
# usando os usuarios UNIX
authorizer = UnixAuthorizer(rejected_users=["root"], require_valid_shell=True)
handler = FTPHandler
handler.authorizer = authorizer
handler.abstracted_fs = UnixFilesystem
handler.log_prefix = "%(username)s@%(remote_ip)s"
#logger.basicConfig(filename='/var/log/pyftpd.log', level=logging.INFO)
# utilizando o servidor multiprocesso
server = MultiprocessFTPServer(('', 21), handler)
server.serve_forever()
if __name__ == "__main__":
main()
"pyftpdlib - Criando um servidor FTP simples com python" de "Fábio C. Barrionuevo da Luz" está licenciado com uma Licença Creative Commons - Atribuição-NãoComercial-SemDerivações 4.0 Internacional.