Visualizzazione post con etichetta progetti. Mostra tutti i post
Visualizzazione post con etichetta progetti. Mostra tutti i post

20 gennaio, 2007

Esperimento: Una rete che si autoespande

In questo post voglio parlarvi di un esperimento che ho fatto in questi giorni con python. In pratica si tratta di una rete di nodi che si "auto trovano" nella rete mantenendo ognuno una lista con gli ip e i nomi degli altri nodi che viene aggiornata non appena un nodo viene a mancare. La cosa interessante è che non c'è un server centrale a gestire il tutto, ma ogni nodo è uguale all'altro ed ha la stessa importanza.

Come Funziona?
Ogni nodo (che in pratica è un programma python) è composto da 4 trhead ed un loop principale. Un thread (Broadcaster) si occupa di fare il broadcast sulla rete (N.B. quindi funziona solo sulla rete locale) della sua lista di contatti, che contiene l'ip e il nome degli altri nodi. Un secondo thread (Receiver) si occupa di ricevere il traffico broadcast inviato dagli altri nodi e di aggiornare la lista dei contatti. Un terzo thread (TcpListner) rimane in ascolto per connessioni tcp (questo serve agli altri nodi per capire se il nodo è ancora "vivo"). Infine un quarto thread (BlistCleaner) che si occupa di interrogare i nodi nella sua lista per scoprire se sono ancora attivi o meno e di aggiornare di conseguenza la sua lista di contatti.
La prima cosa che un nodo fa è quella di mandare in broadcast il suo ip e il suo nome (passati come parametri). Se ad esempio i nodi sono due, il secondo nodo cattura il broadcast del primo e lo inserisce nella sua lista di broadcast che contiene già se stesso e così via con gli altri nodi. Riporto di seguito il codice dei nodi:

PORT = 50000
TCPPORT = 80000
BCASTIP = '192.168.50.255'

import sys, time
import threading
import socket

class Broadcaster(threading.Thread):
def __init__(self, data):
threading.Thread.__init__(self)
self.data = data
self.exit = False

def run(self):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

while 1:
if self.exit: break
data = ""
print "Broadcasting: ", self.data.broad
for item in self.data.broad:
name, ip = item
data += name + ":" + ip + ","
if data != "":
# tolgo l'ultima virgola
data = data[:len(data) - 1]
try:
s.sendto(data, (BCASTIP, PORT))
except socket.error, e:
break
print "Broadcaster error: ", e
time.sleep(2)
s.close()
print "Exit Broadcaster"

class Receiver(threading.Thread):
def __init__(self, data):
threading.Thread.__init__(self)
self.exit = False
self.data = data

def run(self):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', PORT))
s.settimeout(0.1)
while 1:
if self.exit: break
try:
data, fromaddr = s.recvfrom(1024)
items = data.split(",")
self.data.rec = []
if len(items) > 0:
for item in items:
name, ip = item.split(":")
self.data.rec.append( (name, ip) )

print "Received: ", self.data.rec
except socket.timeout, e:
pass
except socket.error, e:
break
print "Receiver error: ", e


#print (data, fromaddr)
#print self.list

s.close()
print "Exit Receiver"

class TcpListner(threading.Thread):

def __init__(self, ip):
threading.Thread.__init__(self)
self.myip = ip
self.exit = False

def run(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind( (self.myip, TCPPORT) )
s.listen(1)
s.settimeout(0.1)

while 1:
if self.exit: break
try:
conn, addr = s.accept()
except socket.timeout, e:
pass
except socket.error, e:
s.close()
break
print "TcpListner error: ", e

s.close()
print "Exit TcpListner"

class BlistCleaner(threading.Thread):

def __init__(self, data, myname):
threading.Thread.__init__(self)
self.data = data
self.exit = False
self.myname = myname

def run(self):

while 1:
if len(self.data.broad) == 0: continue
for item in self.data.broad:
name, ip = item
if name != self.myname:
#print "check name: ", name, "ip: ", ip
try:
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
s.connect((ip, TCPPORT))
s.close()
except socket.error, e:
s.close()
print "Elimino ",name
self.data.broad.remove( (name, ip) )
self.data.rec.remove( (name, ip) )
print "Lista: ", self.data.broad
time.sleep(1)
if self.exit: break

print "Exit BlistCleaner"

class Data:
pass

data = Data()
data.rec = []
data.broad = []


broad = Broadcaster(data)
broad.setName("Broadcaster")
rec = Receiver(data)
rec.setName("Receiver")
# aggiungo il mio nome
name = sys.argv[1]
myip = sys.argv[2]

data.broad.append( (name, myip) )

tcpl = TcpListner(myip)
tcpl.setName("TcpListner")
cleaner = BlistCleaner(data, name)
cleaner.setName("BlistCleaner")

tcpl.start()
cleaner.start()

broad.start()
rec.start()

t = time.time()
while 1:
try:
if len(data.rec) > 0:
for n in data.rec:
if n not in data.broad:
data.broad.append(n)
time.sleep(0.1)
now = time.time()
if now - t > 3:
#print "rlist: ", rec.list
#print "blist: ", broad.list
t = now
except KeyboardInterrupt:
broad.exit = True
rec.exit = True
tcpl.exit = True
cleaner.exit = True
sys.exit(0)

Naturalmente sono da impostare l'indirizzo di broadcast e se salviamo il file come node.py dobbiamo eseguirlo come:

python [nomenodo] [mio_ip]
Per ora è solo un esperimento ma magari in futuro potrebbe risultarmi utile per qualcosa o magari può servire a voi come spunto per una nuova idea!

06 novembre, 2006

Un semplice port scanner

In questo post vedremo come costruire un semplice port scanner.

Cos'è un port scanner?

E' un programmino che
controlla se ci sono delle porte aperte su un certo indirizzo ip
e se si le riporta come tali.

A cosa potrebbe servirmi un port scanner?

Ad esempio potrebbe essere un metodo veloce per scoprire
quali porte sono aperte sul nostro pc ;)

In genere una porta è associata ad un servizio e solitamente i servizi
comuni hanno delle porte standard.
Ad esempio apache porta 80, ssh porta 22 etc.
Ma come si fa per vedere se una porta è aperta?
Semplicemente si può tentare di stabilire una connessione, se si
ha successo la porta è aperta.
Per stabilire una connessione in pratica apriamo un socket tcp
su una certa porta e proviamo a conneterci.
Un numero soltanto potrebbe dirci poco o niente, quindi cerchiamo
di associare un nome di servizio al numero. Per farlo su linux ci viene
incontro il file /etc/services il quale associa ad un numero di porta
un nome di servizio. Quindi non appena riusciamo a stabilire una
connessione, andiamo a ricercare su /etc/services per vedere a
quale servizio corrisponde. Se non troviamo niente vuol dire che non
si tratta di una porta standard.
A questo punto non resta che dare uno sguardo al codice che
troverete linkato in basso a destra.