El código es este (para descargar completo más abajo):
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Escrito por kenkeiras
# Bajo la WTFPL <http://sam.zoy.org/wtfpl/>
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_hop con 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)
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]:
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Escrito por kenkeiras
# Bajo la WTFPL <http://sam.zoy.org/wtfpl/>
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")
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
[Referencias]
SOCKS 4
SOCKS 4A
RFC1928 - SOCKS5
buen código
ResponderEliminar@anónimo: gracias =)
ResponderEliminar