Fábio C. Barrionuevo da Luz
Publicado em:

Wed 11 June 2014

←Home

pyftpdlib - Criando um servidor FTP simples com python

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:

acessando o servidor FTP localmente pelo navegador

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()
Topo
comments powered by Disqus