Usando proxies con Python

Presento un pequeño código para usar proxies SOCKS 4 y 5 en python, en principio la idea era mostrarlo junto un servidor proxy en C, pero viendo que con esto se podía tumbar, tardará un poco más...

El código es este (para descargar completo más abajo): from socket import socket, AF_INET, SOCK_STREAM, inet_aton, getaddrinfo,\

              SOL_TCP

from string import letters

from random import choice

import sys

Lee siempre una cantidad de un socket

def sock_read(sock, n):

b = "" # Inicia el buffer

i = 0 # Tamaño del buffer

while (i < n): # Mientas no lee todo

   c = sock.recv(n - i) # Lee lo que falta



   if (len(c) < 1): # Si no se leyó nada

                    # es que el socket está cerrado

       raise Exception("Closed socket")



   b += c      # Añadir lo nuevo al buffer

   i += len(c) # y actualizar su tamaño

return b # Devolver el buffer

Convertir sockaddr a una dirección de red

def str2host(addr, ipv = 4):

for i in letters: # Si hay letras

   if i in addr[0]: # es un nombre de dominio

       d = getaddrinfo(addr[0], addr[1], 0, 0, SOL_TCP)

       # La primera dirección, el

       # primer dato de la última tupla



       for j in d:

           if (len(j[-1]) == 2) and (ipv == 4): # A ipv4 tuple

               return inet_aton(j[-1][0])

           elif (len(j[-1]) == 4) and (ipv == 6): # A ipv6 tuple

               return inet_aton(j[-1][0])

       raise Exception("Host not found")

# Sino se traduce directamente

return inet_aton(addr[0])

Pasa un número de 2 bytes a str

Suponiendo little endian

def uint16str(n):

data = [] # Prepara el buffer

data.append( chr(n & 255) ) # Lee el byte menos significativo

n >>= 8 # Mueve todo un byte a la derecha

data.append( chr(n & 255) ) # Lee el nuevo lsb

data.reverse() # Le da la vuelta (little endian)

return ''.join(data) # Y lo convierte en una cadeba

Envía el código de excepción de un servidor SOCKS4

def SOCKS4_ex(ans):

# Relación código/respuesta

s4_ex = { 91 : "Request rejected or failed",

         92 : "Request rejected becasue SOCKS server cannot connect to

identd on the client",

         93 : "Request rejected because the client program and identd

report different user-ids"}

raise Exception(s4_ex[ord(ans)]) # Produce la excepción

Envía el código de excepción de un servidor SOCKS5

def SOCKS5_ex(ans):

# Relación código/respuesta

s5_ex = { 1 : "General SOCKS server failure",

         2 : "Connection not allowed by ruleset",

         3 : "Network unreachable",

         4 : "Host unreachable",

         5 : "Connection refused",

         6 : "TTL expired",

         7 : "Command not supported",

         8 : "Address type not supported" }

raise Exception(s5_ex[ord(ans)]) # Produce la excepción

Especifica la dirección a un proxy SOCKS

def SOCKS_hop(sock, addr, proto = 4, ipv = 4):

if (proto == 4): # Protocolo SOCKS4

   # Mensaje de conexión

   sock.send(chr(4) + chr(1) + uint16str(addr[1]) + str2host(addr) +\

        chr(0))



   # Mensaje de confirmación/error

   code = sock_read(sock, 8)[1]



   # Si algo falló

   if (code != chr(90)):

       # Mandar una excepción

       SOCKS4_ex(code)

elif (proto == 5): # Protocolo SOCKS5

   atype = None

   if (ipv == 4): # Hosts ipv4

       atype = chr(1)

   elif (ipv == 6): # Hosts ipv6

       atype = chr(4)

   else:

       raise Exception("Unknown IP version")



   sock.send(chr(5) + chr(1) + chr(0))



   # Mensaje de confirmación/error

   code = sock_read(sock, 2)



   if (code != (chr(5) + chr(0))):

       raise Exception("Requiere autenticación")



   # Mensaje de conexión

   l = sock.send(chr(5) + chr(1) + chr(0) + atype + str(str2host(addr)) +\

        uint16str(addr[1]))



   # Mensaje de confirmación/error

   code = sock_read(sock, l)[1]



   # Si algo falló

   if (code != chr(00)):

       # Mandar una excepción

       SOCKS5_ex(code)

else: # Protocolo desconocido

   raise Exception("Unknown SOCKS version")

Simplemente hay que levantar una conexión hacia un proxy y luego llamar a SOCKS_hopcon los siguientes argumentos:

* El socket que se uso para la conexión

* Una tupla dirección/puerto como al conectar un socket

* Versión de SOCKS: 4 o 5(Opcional, por defecto 4)

* Versión del protocolo IP (Opcional, por defecto 4)
*

Si se produce un error en el proceso (no está conectado a un servidor SOCKS o le servidor no se pudo conectar al nuevo host, por ejemplo) manda una excepción.

Para este ejemplo, si se pasa algún parámetro, se leerá como una lista de proxies (ip:puerto   en cada línea) y va saltando entre proxies al azar. Sino se le pasa ningún parámetro se conecta a localhost en el puerto 1080 y intenta usarlo como servidor SOCKS5 para ver cuantas veces se puede conectar a si mismo [Cuidado]: unos cuantos hilos haciendo esto provocaron algo parecido a un DOS en un pequeño servidor SSH funcionando como proxy =P if name == "main":

if (len(sys.argv) > 1):

   plist = []

   f = open(sys.argv[1], "rt")

   while True:

       txt = f.readline()

       if (len(txt) < 1):

           break

       addr = txt.split(":")

       plist.append((addr[0], int(addr[1])))



   f.close()





   last = choice(plist)  # Selecciona un proxy al azar

   next = last

   i = 0



   sys.stdout.write("[" + str(i) + "] " + str(next))

   sys.stdout.flush()

   sock = socket(AF_INET, SOCK_STREAM)

   sock.connect(next)

   sys.stdout.write("\n")

   while True:

       i += 1

       while (next == last):

           next = choice(plist)

       last = next

       sys.stdout.write("[" + str(i) + "] " + str(next))

       sys.stdout.flush()

       SOCKS_hop(sock, next)

       sys.stdout.write("\n")

else:

   sock = socket(AF_INET, SOCK_STREAM)



   #sock.connect(('127.0.0.1', 4444))

   sock.connect(('localhost', 1080))

   i = 0

   while True:

       #SOCKS_hop(sock, ('localhost', 4444))

       SOCKS_hop(sock, ('127.0.0.1', 1080), 5)

       i += 1

       print i

El código completo [pysocks.py] [Referencias] SOCKS_4 SOCKS_4A RFC1928_-_SOCKS5

untagged

De Firefox y URL's extrañas [Offtopic] » « SniperlCat 0.3.1, pasado a perl estricto y correjidos bugs varios