#!/usr/bin/env python from twisted.internet.protocol import DatagramProtocol import time from twisted.internet import reactor import sys, os, IN from socket import SOL_SOCKET, SO_BROADCAST import struct sys.path.append(os.path.dirname(sys.argv[0])+'/../domotika') from dmlib.dmcrypt import BTEABlock from dmlib import constants as C #import pprint from dmlib import ikaprotocol as proto from dmlib.utils.genutils import revlist class DomIka(DatagramProtocol): def startProtocol(self): #self.memkey=struct.pack('<LLLL', *DEFKEY) self.memkey=proto.DEFKEY self.btea=BTEABlock(self.memkey) self.bteadata=BTEABlock(self.memkey) self.ikahdr=proto.IkaPacketHeader() self.transport.socket.setsockopt(SOL_SOCKET, SO_BROADCAST, True) try: self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE, "br0") except: self.transport.socket.setsockopt(SOL_SOCKET, IN.SO_BINDTODEVICE, "eth0") def datagramReceived(self, data, (host, port)): print "%r -> %s:%d, received %r" % (time.time(), host, port, data) #print struct.unpack('B', data[0]) if(struct.unpack('B', data[0])[0]==C.IKAP_STARTBYTE): self.btea.setEncryptData(data[1:33]) self.ikahdr.formatHeader(self.btea.cleandata) print 'HEADER', self.ikahdr print 'CHECKSUM', hex(self.ikahdr.chksum) print 'CALCULATED CHECKSUM:', hex(self.ikahdr.calculateCheckSum()) totlen=self.ikahdr.srclen+self.ikahdr.dstlen+self.ikahdr.arglen datalendiff=len(data[33:])-totlen offset=0 self.bteadata.key=self.ikahdr.key self.bteadata.setEncryptData(data[33:]) if(self.ikahdr.srclen>0): print 'SRC:', self.bteadata.cleandata[offset:self.ikahdr.srclen] offset=self.ikahdr.srclen dstend=offset+self.ikahdr.dstlen if(self.ikahdr.dstlen>0): dst = self.bteadata.cleandata[offset:dstend] print 'DST:', dst offset=dstend argend=offset+self.ikahdr.arglen arg=False if(self.ikahdr.arglen>0): arg=self.bteadata.cleandata[offset:argend] if self.ikahdr.msgtype==C.IKAP_MSG_DEBUG: if dst.startswith("DEBUG.INPUT.CHANGED.TO") or dst.startswith("DEBUG.RELAY.CHANGED.TO"): arg=struct.unpack('B', arg[0])[0] elif self.ikahdr.ctx==C.IKAP_CTX_SYSTEM and self.ikahdr.msgtype==C.IKAP_MSG_NOTIFYCONF: if dst.startswith("NETWORK."): astr=struct.unpack('<26B', arg) arg="\n\tIP: "+".".join([str(x) for x in astr[0:4]]) arg+="\n\tNETMASK: "+".".join([str(x) for x in astr[4:8]]) arg+="\n\tGW: "+".".join([str(x) for x in astr[8:12]]) arg+="\n\tDNS1: "+".".join([str(x) for x in astr[12:16]]) arg+="\n\tDNS2: "+".".join([str(x) for x in astr[16:20]]) arg+="\n\tMAC: "+":".join([hex(x)[2:].zfill(2) for x in astr[20:26]]) elif dst.startswith("IOSTATUS.DEF"): astr=struct.unpack('<5B', arg) rel=list("".join(["".join(revlist(list(bin(x).replace("b", "").zfill(8)))) for x in astr[0:3]])) if int(astr[3]): rel=map(lambda x,y: "REL%d:%s" % (x,"ON" if int(y) else "OFF"), range(1,25) , rel[0:24]) else: rel=map(lambda x,y: "REL%d:%s" % (x,"ON" if int(y) else "OFF"), range(1,13) , rel[0:12]) arg=" SERIAL: " arg+="%s" % "YES" if int(astr[3]) else "NO" arg+=" AUTOSAVE: " arg+="%s" % "YES" if int(astr[4]) else "NO" for r in rel: arg+="\n\t"+r elif dst.startswith("IOSTATUS.NOW"): #print len(arg) astr=struct.unpack('<'+str(len(arg))+'B', arg) rel=list("".join(["".join(revlist(list(bin(x).replace("0b", "").zfill(8)))) for x in astr[0:3]])) if int(astr[6]): rel=map(lambda x,y: "REL%d:%s" % (x,"ON" if int(y) else "OFF"), range(1,25) , rel[0:24]) else: rel=map(lambda x,y: "REL%d:%s" % (x,"ON" if int(y) else "OFF"), range(1,13) , rel[0:12]) inp=list("".join(["".join(revlist(list(bin(x).replace("0b", "").zfill(8)))) for x in astr[3:6]])) if int(astr[6]): inp=map(lambda x,y: "INP%d:%s" % (x,"OFF" if int(y) else "ON"), range(1,25) , inp[0:24]) else: inp=map(lambda x,y: "INP%d:%s" % (x,"OFF" if int(y) else "ON"), range(1,13) , inp[0:12]) larg=len(arg) arg=" SERIAL: " arg+="%s" % "YES" if int(astr[6]) else "NO" if(larg>7): arg+=" AUTOSAVE: " arg+="%s" % "YES" if int(astr[7]) else "NO" for r in rel: arg+="\n\t"+r for ist in inp: arg+="\n\t"+ist elif self.ikahdr.ctx==C.IKAP_CTX_SYSTEM and self.ikahdr.msgtype==C.IKAP_MSG_REQUESTCONF: if dst.startswith("NETWORK."): astr=struct.unpack('<4B', arg) arg=" "+".".join([str(x) for x in astr[0:4]]) elif dst.startswith("RELAY.CHANGED"): astr=struct.unpack('<3B', arg[0:3]) tmp=[str(x) for x in astr[0:3]] arg="RELAY: "+tmp[0]+" ACTION: "+C.RELAY_ACT[int(tmp[1])]+" STATUS: " arg+="%s" % "ON" if int(tmp[2]) else "OFF" print 'ARGS:', arg offset=argend end=offset+4 checkdate=struct.unpack("<L", self.bteadata.cleandata[offset:end])[0] print 'CHECKDATE:', checkdate #packet=self.btea.cleandata[:-datalendiff] #print 'PACKET', self.btea.cleandata[:-datalendiff] print '-----------------------------' def stop(self): reactor.stop() if __name__ == '__main__': from twisted.internet import reactor reactor.listenUDP(12081, DomIka()) reactor.run()