This commit is contained in:
who
2007-11-09 13:31:05 +01:00
parent c3e692e2a6
commit 8f6c07eca2
2 changed files with 106 additions and 87 deletions

View File

@ -3,7 +3,7 @@
SHAREDSECRET="test123" SHAREDSECRET="test123"
DYNID="testhost" DYNID="testhost"
DATE=`date +%s` DATE=`date +%s`
CHECKSUM=`echo "$DYNID $SHAREDSECRET $DATE" | md5sum | awk '{print $1}'` CHECKSUM=`echo -n "$DYNID $SHAREDSECRET $DATE" | md5sum | awk '{print $1}'`
OUT="$DYNID $DATE $CHECKSUM" OUT="$DYNID $DATE $CHECKSUM"
echo $OUT | nc -q 0 -u 88.198.170.2 9090 echo -n $OUT | nc -q 0 -u 127.0.0.1 9090

193
server/yadyn Normal file → Executable file
View File

@ -1,111 +1,130 @@
#!/usr/bin/python #!/usr/bin/python
import select
import socket import socket
import Queue
import threading
import md5
import time import time
import random
class Entry(object):
def __init__(self, dynid, sharedSecret, name):
self.dynid = dynid
self.sharedSecret = sharedSecret
self.name = name
self.lastEventTime = 0
self.address = ''
class IllegalEventException(Exception):
def __init__(self, msg):
self.msg = msg
ALPHANUM = (0,1,2,3,4,5,6,7,8,9, class Event(object):
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') def __init__(self, address, data, receiveTime):
class DoneException(Exception): pass
class TimeoutException(Exception): pass
class Client(object):
def __init__(self, sock, address):
self.sock = sock
self.address = address self.address = address
self.timestamp = int(time.time()) self.data = data
self.timeout = 5 self.receiveTime = receiveTime
self.state = 0
def prepare(self):
self.port = self.address[1]
self.address = self.address[0]
(self.dynid, self.msgTime, self.checksum) = self.data.split(' ')
self.msgTime = int(self.msgTime)
self.prepared = True
def process(self): def process(self):
self.timestamp = int(time.time()) if not self.prepared:
data = self.sock.recv(8192) self.prepare()
if data == None or data == '':
raise DoneException if not ENTRIES.has_key(self.dynid):
if data[-1] in ('\r','\n'): raise IllegalEventException("unknown dynid in event %s" % str(self))
data = data[:-1] entry = ENTRIES[self.dynid]
if data[-1] in ('\r','\n'):
data = data[:-1] if self.msgTime + MSG_TIME_CORRIDOR < self.receiveTime:
print "<%s> %d" % (data, len(data)) raise IllegalEventException("event too old %s" % str(self))
if self.msgTime - MSG_TIME_CORRIDOR > self.receiveTime:
raise IllegalEventException("event too young %s" % str(self))
if self.state == 0: if entry.lastEventTime >= self.msgTime:
#print "State 0" raise IllegalEventException("timing sequence failure in event, possibly replay %s" % str(self))
if data == "hello":
self.challenge = ''.join(random.sample(ALPHANUM, 5)) di = "%s %s %d" % (self.dynid, entry.sharedSecret, self.msgTime)
print self.challenge d = md5.new(di).hexdigest()
self.sock.send(self.challenge) print "%s, received: %s, calculated: %s" % (di, self.checksum, d)
self.state = 1 if d != self.checksum:
return raise IllegalEventException("wrong checksum for event %s" % str(self))
entry.lastEventTime = self.msgTime
if entry.address == self.address:
print "Same address, nothing to do."
else: else:
raise DoneException entry.address = self.address
elif self.state == 1: print "Set in DNS: %s -> %s" % (entry.name, entry.address)
print "State 1"
if data == self.challenge:
self.sock.send("OK")
raise DoneException
print "After state machine"
def __str__(self):
if not self.prepared:
self.prepare()
return "%s from %s:%d" % (self.data, self.address, self.port)
class Handler(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.q = queue
self.setDaemon(True)
def run(self):
while True:
event = self.q.get()
try:
event.prepare()
print "Processing event %s" % str(event)
event.process()
except IllegalEventException, e:
print "Some failure: %s" % e.msg
class Expirer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.setDaemon(True)
def run(self):
while True:
print "Expiring ..."
currentTime = int(time.time())
for entry in ENTRIES.values():
if entry.lastEventTime != 0 and entry.lastEventTime + EVENT_LIFE_TIME < currentTime:
print "Entry %s expired" % entry.dynid
entry.lastEventTime = 0
entry.address = NULL_ADDRESS
print "Set in DNS: %s -> %s" % (entry.name, entry.address)
time.sleep(10)
def checkTimeout(self): ENTRIES = {
if self.timestamp + self.timeout < int(time.time()): 'testhost': Entry('testhost,', 'test123', 'test.test.de'),
raise TimeoutException() }
MSG_TIME_CORRIDOR = 5
EVENT_LIFE_TIME = 10
NULL_ADDRESS = '0.0.0.0'
def close(self): q = Queue.Queue()
self.sock.close()
handler = Handler(q)
handler.start()
expirer = Expirer()
expirer.start()
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("", 9090))
sSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sSock.bind(("", 9090))
sSock.listen(5)
print "sSock: ", sSock.fileno()
p = select.poll()
p.register(sSock.fileno(), select.POLLIN)
clients = {}
while True: while True:
events = p.poll(1000) data, address = s.recvfrom(256)
for (fd, event) in events:
# print "fd: %d, event: %d" % (fd, event)
if fd == sSock.fileno() and (event & select.POLLIN):
# print "received connect"
cSock, cAddress = sSock.accept()
clients[cSock.fileno()] = Client(cSock, cAddress)
# print "cSock: %d, address: %s" % (cSock.fileno(), str(cAddress))
p.register(cSock.fileno(), select.POLLIN)
else:
# print "received data for ", fd
if event & select.POLLIN:
client = clients[fd]
try: try:
client.process() q.put_nowait(Event(address, data, int(time.time())))
except Exception, e: except Queue.Full:
print "Closing %d, %s" % (fd, str(e)) print "Event %s from %s dropped" % (data, str(address))
client.close()
del clients[fd]
p.unregister(fd)
# print "clients: " + str(clients)
for fd in clients.keys():
try:
clients[fd].checkTimeout()
except TimeoutException:
# print "Timeout %d" % fd
clients[fd].close()
del clients[fd]
p.unregister(fd)