diff options
Diffstat (limited to 'retiolum/hosts')
-rwxr-xr-x | retiolum/hosts/.scripts/datamgmt.py | 101 | ||||
-rwxr-xr-x | retiolum/hosts/.scripts/retiolum.py | 312 |
2 files changed, 413 insertions, 0 deletions
diff --git a/retiolum/hosts/.scripts/datamgmt.py b/retiolum/hosts/.scripts/datamgmt.py new file mode 100755 index 00000000..0d8f056d --- /dev/null +++ b/retiolum/hosts/.scripts/datamgmt.py @@ -0,0 +1,101 @@ +#!/usr/bin/python2 +import sqlite3 +import os, sys + +def create_db(netname): + conn = sqlite3.connect("/etc/tinc/"+ netname + "/hosts.sqlite") + db = conn.cursor() + db.execute('''create table hosts(hostname text, subnet text, address text, port text, r_pub text, t_pub text)''') + conn.commit() + db.close() + +def PubInDb(netname, hostname): + pubfile = open("/etc/tinc/" + netname + "/hosts/.pubkeys/" + hostname, "r") + publines = pubfile.readlines() + pubfile.close() + pubkey = "" + for i in range(len(publines)): + pubkey += publines[i] + print(pubkey) + conn = sqlite3.connect("/etc/tinc/" + netname + "/hosts.sqlite") + c = conn.cursor() + tupel = [pubkey, hostname] + c.execute('UPDATE hosts SET r_pub=? WHERE hostname=?', tupel) + conn.commit() + c.close() + +def HostInDb(netname, hostname): + hostFile = open("/etc/tinc/"+ netname + "/hosts/" + hostname, "r") + hostlines = hostFile.readlines() + hostFile.close() + conn = sqlite3.connect("/etc/tinc/"+ netname + "/hosts.sqlite") + db = conn.cursor() + + lines = 0 + Subnet = "" + Tinc_pub_key = "" + Address = "#Address = none\n" + Port = "Port = 655\n" + while lines < len(hostlines): + if hostlines[lines][0:4] == "Addr": + Address = hostlines[lines] + print Address + if hostlines[lines][0:4] == "Subn": + Subnet = hostlines[lines] + print Subnet + if hostlines[lines][0:4] == "Port": + Port = hostlines[lines] + print Port + if hostlines[lines][0:10] == "-----BEGIN": + Tinc_pub_key_array = hostlines[lines:lines+8] + line = 0 + Tinc_pub_key = "" + while line < len(Tinc_pub_key_array): + Tinc_pub_key += Tinc_pub_key_array[line] + line += 1 + print Tinc_pub_key + lines += 1 + if not(Subnet == "" or Tinc_pub_key == ""): + tupel = (hostname, Subnet, Address, Port, Tinc_pub_key ) + conn = sqlite3.connect("/etc/tinc/"+ netname + "/hosts.sqlite") + db = conn.cursor() + db.execute('insert into hosts values(?,?,?,?,"none",?)', tupel) + conn.commit() + db.close() + +def ShowDb(netname): + conn = sqlite3.connect("/etc/tinc/" + netname + "/hosts.sqlite") + db = conn.cursor() + db.execute("select * from hosts") + for hosts in db: + for i in range(len(hosts)): + print hosts[i] + db.close + +def DirInDb(netname): + #the normal tinc files are read into the sqlite + files = os.listdir("/etc/tinc/" + netname + "/hosts/") + file_n = 0 + while file_n < len(files): + if files[file_n][0] == ".": + files.remove(files[file_n]) + file_n -= 1 + file_n += 1 + for filename in files: + HostInDb(netname, filename) + #the pubkeys are included into the sqlite + pubfiles = os.listdir("/etc/tinc/" + netname + "/hosts/.pubkeys/") + for pubname in pubfiles: + PubInDb(netname, pubname) + + +#Program start here +netname = sys.argv[1] + +try: + os.remove("/etc/tinc/" + netname + "/hosts.sqlite") +except: + print("no hosts.sqlite found") + +create_db(netname) +DirInDb(netname) diff --git a/retiolum/hosts/.scripts/retiolum.py b/retiolum/hosts/.scripts/retiolum.py new file mode 100755 index 00000000..99da7aae --- /dev/null +++ b/retiolum/hosts/.scripts/retiolum.py @@ -0,0 +1,312 @@ +#!/usr/bin/python2 +import sys, os, time, socket, subprocess, thread, random, Queue, binascii, logging #these should all be in the stdlib +import sqlite3 +from Crypto.PublicKey import RSA +from optparse import OptionParser + +def pub_encrypt(netname, hostname_t, text): #encrypt data with public key + conn = sqlite3.connect("/etc/tinc/" + netname + "/hosts.sqlite") + c = conn.cursor() + hostname_tupel = [hostname_t] + pubkey = "" + try: + c.execute("select r_pub from hosts where hostname=?", hostname_tupel) + except: + logging.error("RSA_Encryption: Database error") + return -1 + for i in c: + pubkey += i[0] + c.close + rsa_pub = RSA.importKey(pubkey) + enc_text = rsa_pub.encrypt(text, 0) #seems like RSA_encrypt needs no random + return(binascii.b2a_base64(enc_text[0])) + +def priv_decrypt(netname, enc_data): #decrypt data with private key + raw_privkey = open("/etc/tinc/" + netname + "/rsa_key.priv", "r") + r_privkey = raw_privkey.readlines() + privkey = "" + for i in xrange(len(r_privkey)): + privkey += r_privkey[i] + raw_privkey.close() + + + rsa_priv = RSA.importKey(privkey) + dec_text = rsa_priv.decrypt(binascii.a2b_base64(enc_data)) + return(dec_text) + +def database2hostfiles(netname): #make hostsfiles from database + conn = sqlite3.connect("/etc/tinc/" + netname + "/hosts.sqlite") + c = conn.cursor() + c.execute("select * from hosts") + for i in c: + host = open("/etc/tinc/" + netname + "/hosts/" + i[0], "w") + host.write(i[2]) + host.write(i[3]) + host.write(i[1]) + host.write(i[5]) + host.close() + c.close() + +def address2hostfile(netname, hostname, address): #adds address to hostsfile or restores it if address is empty + tupel = [hostname,] + conn = sqlite3.connect("/etc/tinc/" + netname + "/hosts.sqlite") + c = conn.cursor() + c.execute("select * from hosts where hostname=?", tupel) + for i in c: + host = open("/etc/tinc/" + netname + "/hosts/" + i[0], "w") + if address != "": + host.write("Address = " + address + "\n") + host.write(i[2]) + host.write(i[3]) + host.write(i[1]) + host.write(i[5]) + host.close() + c.close() + logging.info("sending ALRM to tinc deamon!") + tincd_ALRM = subprocess.call(["tincd -n " + netname + " --kill=HUP" ],shell=True) + +def findhostinlist(hostslist, hostname, ip): #finds host + ip in list + for line in xrange(len(hostslist)): + if hostname == hostslist[line][0] and ip == hostslist[line][1]: + return line + return -1 #nothing found + +def getHostname(netname): + tconf = open("/etc/tinc/" + netname + "/tinc.conf", "r") + feld = tconf.readlines() + tconf.close() + for x in feld: + if x.startswith("Name"): + return str(x.partition("=")[2].lstrip().rstrip("\n")) + + print("hostname not found!") + return -1 #nothing found + + +####Thread functions + + +def sendthread(netname, hostname, sendfifo, ghostmode): #send to multicast, sends keep alive packets + while True: + try: + #{socket init start + ANY = "0.0.0.0" + SENDPORT = 23542 + MCAST_ADDR = "224.168.2.9" + MCAST_PORT = 1600 + + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) #initalize socket with udp + sock.bind((ANY,SENDPORT)) #now bound to Interface and Port + sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) #activate multicast + #}socket init end + + if ghostmode == 0: + + i = 9 + + while True: + i += 1 + if not sendfifo.empty(): + sock.sendto(sendfifo.get(), (MCAST_ADDR,MCAST_PORT) ) + logging.info("send: sending sendfifo") + else: + time.sleep(1) + if i == 10: + sock.sendto("#Stage1#" + netname + "#" + hostname + "#", (MCAST_ADDR,MCAST_PORT) ) + logging.debug("send: sending keep alive") + i = 0 + else: + while True: + if not sendfifo.empty(): + sock.sendto(sendfifo.get(), (MCAST_ADDR,MCAST_PORT) ) + logging.info("send: sending sendfifo") + else: + time.sleep(1) + + except: + logging.error("send: socket init failed") + time.sleep(10) + + + +def recvthread(netname, hostname, timeoutfifo, authfifo): #recieves input from multicast, send them to timeout or auth + while True: + try: + ANY = "0.0.0.0" + MCAST_ADDR = "224.168.2.9" + MCAST_PORT = 1600 + + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) #create a UDP socket + sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #allow multiple sockets to use the same PORT number + sock.bind((ANY,MCAST_PORT)) #Bind to the port that we know will receive multicast data + sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255) #tell the kernel that we are a multicast socket + + + status = sock.setsockopt(socket.IPPROTO_IP, + socket.IP_ADD_MEMBERSHIP, #Tell the kernel that we want to add ourselves to a multicast group + socket.inet_aton(MCAST_ADDR) + socket.inet_aton(ANY)); #The address for the multicast group is the third param + + while True: + while True: + + try: + data, addr = sock.recvfrom(1024) + ip, port = addr + break + except socket.error, e: + pass + + logging.debug("recv: got data") + dataval = data.split("#") + if dataval[0] == "": + if dataval[2] == netname: + if dataval[1] == "Stage1": + if dataval[3] != hostname: + timeoutfifo.put(["tst", dataval[3], ip]) + logging.info("recv: got Stage1: writing data to timeout") + if dataval[1] == "Stage2": + if dataval[3] == hostname: + authfifo.put([dataval[1], dataval[3], ip, dataval[4]]) + logging.info("recv: got Stage2: writing data to auth") + if dataval[1] == "Stage3": + if dataval[3] != hostname: + authfifo.put([dataval[1], dataval[3], ip, dataval[4]]) + logging.info("recv: got Stage3: writing data to auth") + except: + logging.error("recv: socket init failed") + time.sleep(10) + +def timeoutthread(netname, timeoutfifo, authfifo): #checks if the hostname is already in the list, deletes timeouted nodes + hostslist = [] #hostname, ip, timestamp + + while True: + if not timeoutfifo.empty(): + curhost = timeoutfifo.get() + if curhost[0] == "add": + hostslist.append([curhost[1], curhost[2], time.time()]) + address2hostfile(netname, curhost[1], curhost[2]) + logging.info("adding host to hostslist") + elif curhost[0] == "tst": + line = findhostinlist(hostslist, curhost[1], curhost[2]) + if line != -1: + hostslist[line][2] = time.time() + logging.debug("timeout: refreshing timestamp") + else: + authfifo.put(["Stage1", curhost[1], curhost[2]]) + logging.info("timeout: writing to auth") + + else: + i = 0 + while i < len(hostslist): + if time.time() - hostslist[i][2] > 60: + address2hostfile(netname, hostslist[i][0], "") + del hostslist[i] + logging.info("timeout: deleting dead host") + else: + i += 1 + time.sleep(2) + +def auththread(netname, hostname, authfifo, sendfifo, timeoutfifo): #manages authentication with clients (bruteforce sensitve, should be fixed) + authlist = [] #hostname, ip, Challenge, timestamp + + + while True: + if not authfifo.empty(): + logging.debug("auth: authfifo is not empty") + curauth = authfifo.get() + if curauth[0] == "Stage1": + line = findhostinlist(authlist, curauth[1], curauth[2]) + if line == -1: + challengenum = random.randint(0,65536) + encrypted_message = pub_encrypt(netname, curauth[1], "#" + hostname + "#" + str(challengenum) + "#") + authlist.append([curauth[1], curauth[2], challengenum, time.time()]) + else: + encrypted_message = pub_encrypt(netname, authlist[line][0], "#" + hostname + "#" + str(authlist[line][2]) + "#") + if encrypted_message == -1: + logging.info("auth: RSA Encryption Error") + else: + sendtext = "#Stage2#" + netname + "#" + curauth[1] + "#" + encrypted_message + "#" + sendfifo.put(sendtext) + logging.info("auth: got Stage1 sending now Stage2") + + if curauth[0] == "Stage2": + dec_message = priv_decrypt(netname, curauth[3]) + splitmes = dec_message.split("#") + if splitmes[0] == "": + encrypted_message = pub_encrypt(netname, splitmes[1], "#" + splitmes[2] + "#") + if encrypted_message == -1: + logging.error("auth: RSA Encryption Error") + else: + sendtext = "#Stage3#" + netname + "#" + curauth[1] + "#" + encrypted_message + "#" + sendfifo.put(sendtext) + logging.info("auth: got Stage2 sending now Stage3") + + if curauth[0] == "Stage3": + line = findhostinlist(authlist, curauth[1], curauth[2]) + if line != -1: + dec_message = priv_decrypt(netname, curauth[3]) + splitmes = dec_message.split("#") + logging.info("auth: checking challenge") + if splitmes[0] == "" and splitmes[1] == str(authlist[line][2]): + timeoutfifo.put(["add", curauth[1], curauth[2]]) + del authlist[line] + logging.info("auth: Stage3 checked, sending now to timeout") + else: + logging.error("auth: challenge failed") + + else: + i = 0 + while i < len(authlist): + if time.time() - authlist[i][3] > 120: + del authlist[i] + logging.info("auth: deleting timeoutet auth") + else: + i += 1 + time.sleep(1) + +#Program starts here! +#netname = "retiolum" +#hostname = "miefda901" + +parser = OptionParser() +parser.add_option("-n", "--netname", dest="netname", help="the netname of the tinc network") +parser.add_option("-H", "--hostname", dest="hostname", default="default" , help="your nodename, if not given, it will try too read it from tinc.conf") +parser.add_option("-d", "--debug", dest="debug", default="0", help="debug level: 0,1,2,3 if empty debug level=0") +parser.add_option("-g", "--ghost", action="store_true", dest="ghost", default=False, help="deactivates active sending, keeps you anonymous in the public network") +(option, args) = parser.parse_args() + +if option.netname == None: + parser.error("Netname is required, use -h for help!") +if option.hostname == "default": + option.hostname = getHostname(option.netname) + +hostname = option.hostname +netname = option.netname + + +#Logging stuff +LEVELS = {'3' : logging.DEBUG, + '2' : logging.INFO, + '1' : logging.ERROR, + '0' : logging.CRITICAL} + +level_name = option.debug +level = LEVELS.get(level_name, logging.NOTSET) +logging.basicConfig(level=level) + +wget = subprocess.call(["wget vpn.miefda.org/hosts.sqlite -O /etc/tinc/" + netname + "/hosts.sqlite"], shell=True) +database2hostfiles(netname) +start_tincd = subprocess.call(["tincd -n " + netname ],shell=True) + +sendfifo = Queue.Queue() #sendtext +authfifo = Queue.Queue() #Stage{1, 2, 3} hostname ip enc_data +timeoutfifo = Queue.Queue() #State{tst, add} hostname ip + +thread_recv = thread.start_new_thread(recvthread, (netname, hostname, timeoutfifo, authfifo)) +thread_send = thread.start_new_thread(sendthread, (netname, hostname, sendfifo, option.ghost)) +thread_timeout = thread.start_new_thread(timeoutthread, (netname, timeoutfifo, authfifo)) +thread_auth = thread.start_new_thread(auththread, (netname, hostname, authfifo, sendfifo, timeoutfifo)) + +##dirty while function, SHOULD BE IMPROVED +while True: + time.sleep(10) |