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"
DYNID="testhost"
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"
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
import select
import socket
import Queue
import threading
import md5
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,
'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')
class DoneException(Exception): pass
class TimeoutException(Exception): pass
class Client(object):
def __init__(self, sock, address):
self.sock = sock
class Event(object):
def __init__(self, address, data, receiveTime):
self.address = address
self.timestamp = int(time.time())
self.timeout = 5
self.state = 0
self.data = data
self.receiveTime = receiveTime
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):
self.timestamp = int(time.time())
data = self.sock.recv(8192)
if data == None or data == '':
raise DoneException
if data[-1] in ('\r','\n'):
data = data[:-1]
if data[-1] in ('\r','\n'):
data = data[:-1]
print "<%s> %d" % (data, len(data))
if not self.prepared:
self.prepare()
if not ENTRIES.has_key(self.dynid):
raise IllegalEventException("unknown dynid in event %s" % str(self))
entry = ENTRIES[self.dynid]
if self.msgTime + MSG_TIME_CORRIDOR < self.receiveTime:
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:
#print "State 0"
if data == "hello":
self.challenge = ''.join(random.sample(ALPHANUM, 5))
print self.challenge
self.sock.send(self.challenge)
self.state = 1
return
if entry.lastEventTime >= self.msgTime:
raise IllegalEventException("timing sequence failure in event, possibly replay %s" % str(self))
di = "%s %s %d" % (self.dynid, entry.sharedSecret, self.msgTime)
d = md5.new(di).hexdigest()
print "%s, received: %s, calculated: %s" % (di, self.checksum, d)
if d != self.checksum:
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:
raise DoneException
elif self.state == 1:
print "State 1"
if data == self.challenge:
self.sock.send("OK")
raise DoneException
print "After state machine"
entry.address = self.address
print "Set in DNS: %s -> %s" % (entry.name, entry.address)
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):
if self.timestamp + self.timeout < int(time.time()):
raise TimeoutException()
ENTRIES = {
'testhost': Entry('testhost,', 'test123', 'test.test.de'),
}
MSG_TIME_CORRIDOR = 5
EVENT_LIFE_TIME = 10
NULL_ADDRESS = '0.0.0.0'
def close(self):
self.sock.close()
q = Queue.Queue()
handler = Handler(q)
handler.start()
expirer = Expirer()
expirer.start()
sSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
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 = {}
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", 9090))
while True:
events = p.poll(1000)
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]
data, address = s.recvfrom(256)
try:
client.process()
except Exception, e:
print "Closing %d, %s" % (fd, str(e))
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)
q.put_nowait(Event(address, data, int(time.time())))
except Queue.Full:
print "Event %s from %s dropped" % (data, str(address))