summaryrefslogtreecommitdiffstats
path: root/retiolum
diff options
context:
space:
mode:
authortv <tv@also>2011-05-29 15:47:21 +0200
committertv <tv@also>2011-05-29 15:47:21 +0200
commite0ec5d2e8560ae433ee677622b24ba82dbe7630b (patch)
treea1fcb14eeafc3df41427896d9b413087d24d71f1 /retiolum
parentedaa1d7f7a0ed33c019fce185b8aff7563498b6e (diff)
lowered filesystem hierarchy--everything are modules
Diffstat (limited to 'retiolum')
-rw-r--r--retiolum/Makefile15
-rw-r--r--retiolum/README29
-rwxr-xr-xretiolum/bin/fillxx6
-rwxr-xr-xretiolum/bin/hosts11
-rwxr-xr-xretiolum/bin/ipv635
-rwxr-xr-xretiolum/bin/tinc18
-rwxr-xr-xretiolum/bin/update_tinc_hosts33
-rw-r--r--retiolum/doc/install_dotcloud85
-rw-r--r--retiolum/doc/install_no.de4
-rw-r--r--retiolum/scripts/README16
-rw-r--r--retiolum/scripts/adv_graphgen/README28
-rwxr-xr-xretiolum/scripts/adv_graphgen/parse.py101
-rwxr-xr-xretiolum/scripts/adv_graphgen/sanitize.sh13
-rw-r--r--retiolum/scripts/autostart/Makefile14
-rwxr-xr-xretiolum/scripts/autostart/tinc94
-rwxr-xr-xretiolum/scripts/tinc_multicast/retiolum34
-rwxr-xr-xretiolum/scripts/tinc_multicast/retiolum.py349
-rw-r--r--retiolum/scripts/tinc_setup/README18
-rw-r--r--retiolum/scripts/tinc_setup/autoupdate_cron.sh7
-rw-r--r--retiolum/scripts/tinc_setup/bootstrap.sh11
-rwxr-xr-xretiolum/scripts/tinc_setup/build_arch.sh14
-rwxr-xr-xretiolum/scripts/tinc_setup/build_debian.sh32
-rwxr-xr-xretiolum/scripts/tinc_setup/build_debian_clean.sh31
-rwxr-xr-xretiolum/scripts/tinc_setup/build_ec2.sh16
-rw-r--r--retiolum/scripts/tinc_setup/build_no.de.sh1
-rwxr-xr-xretiolum/scripts/tinc_setup/install.sh72
-rwxr-xr-xretiolum/scripts/tinc_setup/tinc-up20
-rw-r--r--retiolum/scripts/tinc_setup/write_channel.py26
28 files changed, 1133 insertions, 0 deletions
diff --git a/retiolum/Makefile b/retiolum/Makefile
new file mode 100644
index 00000000..0d99ee70
--- /dev/null
+++ b/retiolum/Makefile
@@ -0,0 +1,15 @@
+.phony: update it all so install
+
+all: select-target
+
+it: so
+so: it
+
+/etc/tinc/retiolum/hosts:
+ cd $(dir $@) && git clone https://github.com/krebscode/hosts
+
+update: /etc/tinc/retiolum/hosts
+ cd $< && git pull
+
+install:
+ scripts/tinc_setup/install.sh
diff --git a/retiolum/README b/retiolum/README
new file mode 100644
index 00000000..9b9725f2
--- /dev/null
+++ b/retiolum/README
@@ -0,0 +1,29 @@
+Retiolum Darknet Module for Krebs
+========================
+
+Enter the darknet with the help of tinc retiolum
+
+Getting Started
+-------------
+to get you started, check out scripts/tinc_setup/README
+
+1. the first step you will need to do is grab a binary copy of tinc via your
+packet manager, build it yourself or place all your hope into the build
+script of your distribution.
+2. after doing that you might want to run the scripts/tinc_setup/install.sh
+script to write all the configuration files and private/public keys.
+This installation is somewhat interactive so be sure not to fuck shit up.
+
+Other cool stuff
+---------------
+in bin/ there are some cool scripts which are partly needed and partly
+totally unnecessary to work with retiolum.
+
+As all the scripts are not too horribly long, be sure to use
+`cat bin/SCRIPTNAME` to get an understanding of what they do
+
+besides that in scripts/ there are 3 more scripts which perform pretty
+sophisticated tasks like finding instances via multicast or writing graphs
+of the current retiolum network. Try them if you dare :)
+
+
diff --git a/retiolum/bin/fillxx b/retiolum/bin/fillxx
new file mode 100755
index 00000000..5e558362
--- /dev/null
+++ b/retiolum/bin/fillxx
@@ -0,0 +1,6 @@
+#! /bin/sh
+while echo $1 | grep -q xx; do
+ xx=`od -An -tx1 -N 1 /dev/urandom | tr -d \ `
+ set -- `echo $1 | sed s/xx/$xx/`
+done
+echo $1
diff --git a/retiolum/bin/hosts b/retiolum/bin/hosts
new file mode 100755
index 00000000..6939f52c
--- /dev/null
+++ b/retiolum/bin/hosts
@@ -0,0 +1,11 @@
+#! /bin/sh
+set -euf
+
+netname=${1-retiolum}
+
+cd /etc/tinc/$netname/hosts
+
+for i in `ls`; do
+ sed -rn 's|^ *Subnet *= *([^ /]*)(/[0-9]*)? *$|\1\t'$i' '$i'.'$netname'|p' $i
+done | sort
+
diff --git a/retiolum/bin/ipv6 b/retiolum/bin/ipv6
new file mode 100755
index 00000000..65a1eaa1
--- /dev/null
+++ b/retiolum/bin/ipv6
@@ -0,0 +1,35 @@
+#! /bin/sh
+#
+# Manage IPv6 of the retiolum interface.
+#
+# usage: ipv6 {start,stop}
+#
+set -euf
+
+if test `id -u` != 0; then
+ echo "we're going sudo..." >&2
+ exec sudo "$0" "$@"
+ exit 23 # go to hell
+fi
+
+file=/etc/tinc/retiolum/hosts/`hostname`
+addr=`sed -rn 's|^Subnet *= *(42:[0-9A-Fa-f:]*/128)|\1|p' $file`
+route=42::/16
+
+start() {
+ stop
+ ip -6 addr add $addr dev retiolum
+ ip -6 route add $route dev retiolum
+}
+
+stop() {
+ ip -6 addr del $addr dev retiolum 2>/dev/null || :
+ ip -6 route del $route dev retiolum 2>/dev/null || :
+}
+
+## dispatch
+case "$1" in
+ (start) start;;
+ (stop) stop;;
+ (*) echo "You're made of stupid" 2>/dev/null; exit 23;;
+esac
diff --git a/retiolum/bin/tinc b/retiolum/bin/tinc
new file mode 100755
index 00000000..ffa1dbee
--- /dev/null
+++ b/retiolum/bin/tinc
@@ -0,0 +1,18 @@
+#! /bin/sh
+#
+set -euf
+
+init() {
+ f=/tmp/retiolum.GraphDumpFile
+ if ! test -f $f; then
+ touch $f &&
+ chown -v tincd: $f
+ fi
+
+ modprobe -v tun
+}
+
+if init; then
+ exec tincd --user=tincd --net=retiolum "$@"
+fi
+
diff --git a/retiolum/bin/update_tinc_hosts b/retiolum/bin/update_tinc_hosts
new file mode 100755
index 00000000..2d5cf957
--- /dev/null
+++ b/retiolum/bin/update_tinc_hosts
@@ -0,0 +1,33 @@
+#! /bin/sh
+set -euf
+
+if test "${nosudo-false}" != true -a `id -u` != 0; then
+ echo "we're going sudo..." >&2
+ exec sudo "$0" "$@"
+ exit 23 # go to hell
+fi
+
+DIRNAME=`dirname $0`
+export PATH="`readlink -f $DIRNAME`:$PATH"
+
+hosts="${hosts-/etc/hosts}"
+
+bs='# BEGIN OF RETIOLUM'
+es='# END OF RETIOLUM'
+
+case "${1-imstupid}" in
+ (start|restart)
+ if grep -q "^$bs$" $hosts && grep -q "^$es$" $hosts; then
+ $0 stop
+ echo "$bs" >> $hosts
+ hosts >> $hosts
+ echo "$es" >> $hosts
+ fi
+ ;;
+ (stop)
+ sed -ie "/^$bs$/,/^$es$/d" $hosts
+ ;;
+ (*)
+ echo 'Error 1: You are made of stupid!' >&2
+ exit 23
+esac
diff --git a/retiolum/doc/install_dotcloud b/retiolum/doc/install_dotcloud
new file mode 100644
index 00000000..ea976c55
--- /dev/null
+++ b/retiolum/doc/install_dotcloud
@@ -0,0 +1,85 @@
+The Dotcloud provided by duostack.com is a application development platform
+for simple deployment of your stuff.
+
+It also provides an ssh-interface via:
+<code>
+ dotcloud ssh project.module
+</code>
+
+to be able to use it without the hassle of going through the api, you will
+need to create an own dsa-key for ssh to use and deploy this public key on
+the machine
+<code>
+ ssh-keygen -t dsa -f dotcloud_project.dss
+ cat dotcloud_project.dss.pub (copy the contents to the dotclouds
+ ~/.ssh/authorized_keys2)
+</code>
+find your dotcloud host ip via
+<code>
+ dotcloud info project.module
+</code>
+
+You will gain a user shell with
+<code>
+ ssh dotcloud@module.project -p 5960
+</code>
+we will need to build some stuff in order to get a working copy of tinc.
+Everything needs to be done in userspace.
+<code>
+ mkdir build
+ cd build
+ curl http://www.openssl.org/source/openssl-1.0.0d.tar.gz | tar xz
+ cd openssl-1.0.0d
+ ./config --prefix=$HOME/usr -fPIC
+ make install
+ cp lib* $HOME/usr/lib
+ cd ..
+
+ curl http://www.oberhumer.com/opensource/lzo/download/lzo-2.04.tar.gz | tar xz
+ cd lzo-2.04
+ ./configure --prefix=$HOME/usr
+
+ curl http://zlib.net/zlib-1.2.5.tar.gz | tar xz
+ cd zlib-1.2.5/
+ ./configure --prefix=$HOME/usr
+ make install
+</code>
+before building we need to patch the tinc daemon to run without the need
+for a tun device.
+
+tutorial is here:
+https://hackerspace.be/TincVPN
+<code>
+
+ curl http://www.tinc-vpn.org/packages/tinc-1.0.14.tar.gz | tar xz
+ cd tinc-1.0.14
+ #replace the device.c with the patched (empty) one from the webpage
+ ./configure --prefix=$HOME/usr --sysconfdir=$HOME/etc \
+ --localstatedir=$HOME/var --with-openssl=`pwd`/../openssl-1.0.0d/ \
+ --with-openssl-lib=`pwd`/../openssl-1.0.0d/ \
+ --with-zlib-include=$HOME/usr/include --with-zlib-lib=$HOME/usr/lib
+ make
+ make install
+ mkdir ~/etc
+ mkdir -p ~/var/run
+ cd ~/painload/retiolum/scripts/tinc_setup
+ ./install cloudkrebs 10.7.7.221
+</code>
+
+be sure to fix the portnumber in the generated host file and add your own
+address in hosts/cloudkrebs:
+<code>
+ Address = my.public.address
+ Port = 1655
+
+ PUBKEY
+</code>
+
+also write the right in tinc.conf:
+<code>
+ Name = cloudkrebs
+
+ Mode = switch
+ #device = ...
+ # no device :)
+</code>
diff --git a/retiolum/doc/install_no.de b/retiolum/doc/install_no.de
new file mode 100644
index 00000000..a8b72a78
--- /dev/null
+++ b/retiolum/doc/install_no.de
@@ -0,0 +1,4 @@
+ok, i tried to just do the same step i did in the other cloud service, but
+it failed when trying to include tunnel headers.this is what to do:
+
+# add PATH_MAX to conf.c
diff --git a/retiolum/scripts/README b/retiolum/scripts/README
new file mode 100644
index 00000000..4dbb42af
--- /dev/null
+++ b/retiolum/scripts/README
@@ -0,0 +1,16 @@
+This Folder contains all the cool scripts created for tinc_retiolum
+
+currently the following functions are deployed:
+
+adv_graphgen/ - makefu
+ this folder contains a script suite which parses the interesting
+ parameters from the syslog file by sending SIGUSR2 to the tinc process
+
+tinc_multicast/ - Miefda,Lassulus
+ A tinc multicast script suite which provides automagic-discovery in a
+ local network by utilizing multicast
+
+tinc_setup/ - makefu (i am so sorry...)
+ A number of scripts which build and configure tinc on a local machine.
+ Core is the install.sh script which actually writes the configuration
+ and creates users as well as private/public keys
diff --git a/retiolum/scripts/adv_graphgen/README b/retiolum/scripts/adv_graphgen/README
new file mode 100644
index 00000000..082e0f2b
--- /dev/null
+++ b/retiolum/scripts/adv_graphgen/README
@@ -0,0 +1,28 @@
+The folder contains a number of scripts which provide a convenient way to
+generate advanced graphs from the SIGUSR2 output of tinc.
+
+it currently contains the following files:
+
+sanitize.sh:
+ wrapper arond parse.py which filters the syslog file for all tinc
+ related lines and removes the status informations:
+ this means that
+ <code>
+ May 19 20:40:44 servarch dnsmasq[5382]: reading /etc/resolv.conf
+ May 19 20:41:38 servarch tinc.retiolum[4780]: Error looking up pa-sharepoint.informatik.ba-stuttgart.de port 655: Name or service not known
+ </code>
+ becomes
+ <code>
+ Error looking up pa-sharepoint.informatik.ba-stuttgart.de port 655: Name or service not known
+ </code>
+ and so on.
+ It also provides a wrapper around graphviz which automagically
+ generates graphs from the produced graph file
+
+parse.py:
+ reads from stdin the sanitized syslog file and prints a valid dot file
+ from the given output.
+ The parser module may also produce any other output (e.g. for dns
+ entries and so on) you will need to actually read and modify the source
+ in order to be able to do this. ~May the source be with you~
+
diff --git a/retiolum/scripts/adv_graphgen/parse.py b/retiolum/scripts/adv_graphgen/parse.py
new file mode 100755
index 00000000..639c5316
--- /dev/null
+++ b/retiolum/scripts/adv_graphgen/parse.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python2
+# -*- coding: utf8 -*-
+
+import sys
+""" TODO: Refactoring needed to pull the edges out of the node structures again,
+it should be easier to handle both structures"""
+
+def write_digraph(nodes):
+ """
+ writes the complete digraph in dot format
+ """
+ print ('digraph retiolum {')
+ print (' node[shape=box,style=filled,fillcolor=grey]')
+ generate_stats(nodes)
+ nodes = delete_unused_nodes(nodes)
+ merge_edges(nodes)
+ for k,v in nodes.iteritems():
+ write_node(k,v)
+ print ('}')
+def generate_stats(nodes):
+ """ Generates some statistics of the network and nodes
+ """
+ for k,v in nodes.iteritems():
+ v['num_conns'] = len(v.get('to',[]))
+def delete_unused_nodes(nodes):
+ new_nodes = {}
+ for k,v in nodes.iteritems():
+ if v.get('to',[]):
+ new_nodes[k] = v
+ return new_nodes
+def merge_edges(nodes):
+ """ merge back and forth edges into one
+ DESTRUCTS the current structure by deleting "connections" in the nodes
+
+ """
+ for k,v in nodes.iteritems():
+ for con in v.get('to',[]):
+ for i,secon in enumerate(nodes[con['name']].get('to',[])):
+ if k == secon['name']:
+ del (nodes[con['name']]['to'][i])
+ con['bidirectional'] = True
+
+
+def write_node(k,v):
+ """ writes a single node and its edges
+ edges are weightet with the informations inside the nodes provided by
+ tinc
+ """
+ node = " "+k+"[label=\""
+ node += k+"\\l"
+ node += "external:"+v['external-ip']+":"+v['external-port']+"\\l"
+ if v.has_key('num_conns'):
+ node += "Num Connects:"+str(v['num_conns'])+"\\l"
+ for addr in v.get('internal-ip',['¯\\\\(°_o)/¯']):
+ node += "internal:"+addr+"\\l"
+ node +="\""
+ if v['external-ip'] == "MYSELF":
+ node += ",fillcolor=steelblue1"
+ node += "]"
+ print node
+
+ for con in v.get('to',[]):
+ edge = " "+k+ " -> " +con['name'] + "[weight="+str(float(con['weight']))
+ if con.get('bidirectional',False):
+ edge += ",dir=both"
+ edge += "]"
+ print edge
+
+def parse_input():
+ nodes={}
+ for line in sys.stdin:
+ line = line.replace('\n','')
+ if line == 'Nodes:':
+ nodes={}
+ for line in sys.stdin:
+ if line == 'End of nodes.\n':
+ break
+ l = line.replace('\n','').split() #TODO unhack me
+ nodes[l[0]]= { 'external-ip': l[2], 'external-port' : l[4] }
+ if line == 'Subnet list:':
+ for line in sys.stdin:
+ if line == 'End of subnet list.\n':
+ break
+ l = line.replace('\n','').split()
+ if not nodes[l[2]].get('internal-ip',False):
+ nodes[l[2]]['internal-ip'] = []
+ nodes[l[2]]['internal-ip'].append(l[0].split('#')[0])
+ if line == 'Edges:':
+ edges = {}
+ for line in sys.stdin:
+ if line == 'End of edges.\n':
+ break
+ l = line.replace('\n','').split()
+
+ if not nodes[l[0]].has_key('to') :
+ nodes[l[0]]['to'] = []
+ nodes[l[0]]['to'].append(
+ {'name':l[2],'addr':l[4],'port':l[6],'weight' : l[10] })
+ return nodes
+nodes = parse_input()
+write_digraph(nodes)
diff --git a/retiolum/scripts/adv_graphgen/sanitize.sh b/retiolum/scripts/adv_graphgen/sanitize.sh
new file mode 100755
index 00000000..0e12d207
--- /dev/null
+++ b/retiolum/scripts/adv_graphgen/sanitize.sh
@@ -0,0 +1,13 @@
+GRAPH_SETTER1=dot
+GRAPH_SETTER2=circo
+LOG_FILE=/var/log/everything.log
+OPENER=/bin/true
+
+sudo pkill -USR2 tincd
+sudo sed -n '/tinc.retiolum/{s/.*tinc.retiolum\[[0-9]*\]: //gp}' $LOG_FILE |\
+ ./parse.py > retiolum.dot
+
+$GRAPH_SETTER1 -Tpng -o $1retiolum_1.png retiolum.dot
+$GRAPH_SETTER2 -Tpng -o $1retiolum_2.png retiolum.dot
+$OPENER retiolum_1.png &>/dev/null
+#rm retiolum.dot
diff --git a/retiolum/scripts/autostart/Makefile b/retiolum/scripts/autostart/Makefile
new file mode 100644
index 00000000..aba6bd33
--- /dev/null
+++ b/retiolum/scripts/autostart/Makefile
@@ -0,0 +1,14 @@
+INIT_FOLDER=/etc/init.d
+.phony: all
+debian:
+ #TODO change the tinc file before writing
+ cp tinc /etc/init.d/tinc
+ chmod +x /etc/init.d
+ echo "retiolum" > /etc/tinc/nets.boot
+ update-rc.d tinc defaults
+arch:
+ @cp tinc /etc/rc.d
+ @chmod +x /etc/rc.d/tinc
+ @echo "add tinc to DAEMONS in /etc/rc.conf"
+
+
diff --git a/retiolum/scripts/autostart/tinc b/retiolum/scripts/autostart/tinc
new file mode 100755
index 00000000..12e77d6a
--- /dev/null
+++ b/retiolum/scripts/autostart/tinc
@@ -0,0 +1,94 @@
+#! /bin/sh
+#
+### BEGIN INIT INFO
+# Provides: tinc
+# Required-Start: $remote_fs $network
+# Required-Stop: $remote_fs $network
+# Should-Start: $syslog $named
+# Should-Stop: $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Start tinc daemons
+# Description: Create a file $NETSFILE (/etc/tinc/nets.boot),
+# and put all the names of the networks in there.
+# These names must be valid directory names under
+# $TCONF (/etc/tinc). Lines starting with a # will be
+# ignored in this file.
+### END INIT INFO
+#
+# Based on Lubomir Bulej's Redhat init script.
+
+DAEMON="/usr/sbin/tincd"
+NAME="tinc"
+DESC="tinc daemons"
+TCONF="/etc/tinc"
+NETSFILE="$TCONF/nets.boot"
+NETS=""
+
+modprobe tun
+
+test -f $DAEMON || exit 0
+
+[ -r /etc/default/tinc ] && . /etc/default/tinc
+
+# foreach_net "what-to-say" action [arguments...]
+foreach_net() {
+ if [ ! -f $NETSFILE ] ; then
+ echo "Please create $NETSFILE."
+ exit 0
+ fi
+ echo -n "$1"
+ shift
+ egrep '^[ ]*[a-zA-Z0-9_-]+' $NETSFILE | while read net args; do
+ echo -n " $net"
+ "$@" $net $args
+ done
+ echo "."
+}
+
+start() {
+ $DAEMON $EXTRA -n "$@"
+}
+stop() {
+ $DAEMON -n $1 -k
+}
+reload() {
+ $DAEMON -n $1 -kHUP
+}
+restart() {
+ stop "$@"
+ sleep 0.5
+ i=0;
+ while [ -f /var/run/tinc.$1.pid ] ; do
+ if [ $i = '10' ] ; then
+ break
+ else
+ echo -n "."
+ sleep 0.5
+ i=$(($i+1))
+ fi
+ done
+ start "$@"
+}
+
+case "$1" in
+ start)
+ foreach_net "Starting $DESC:" start
+ ;;
+ stop)
+ foreach_net "Stopping $DESC:" stop
+ ;;
+ reload|force-reload)
+ foreach_net "Reloading $DESC configuration:" reload
+ ;;
+ restart)
+ foreach_net "Restarting $DESC:" restart
+ ;;
+ *)
+ echo "Usage: /etc/init.d/$NAME {start|stop|reload|restart|force-reload}"
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/retiolum/scripts/tinc_multicast/retiolum b/retiolum/scripts/tinc_multicast/retiolum
new file mode 100755
index 00000000..1d6b775f
--- /dev/null
+++ b/retiolum/scripts/tinc_multicast/retiolum
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+. /etc/rc.conf
+. /etc/rc.d/functions
+
+TINCNAME='retiolum'
+case "$1" in
+ start)
+ stat_busy "Starting retiolum Daemon"
+ success=0
+ /home/death/git/retiolum/.scripts/tinc_multicast/retiolum.py -n retiolum -T &
+ sleep 2
+ if [ $success -eq 0 ]; then
+ add_daemon retiolum
+ stat_done
+ else
+ stat_fail
+ fi
+ ;;
+ stop)
+ stat_busy "Stopping retiolum Daemon"
+ kill `cat /var/lock/retiolum.retiolum`
+ rm_daemon retiolum
+ stat_done
+ ;;
+ restart)
+ $0 stop
+ sleep 4
+ $0 start
+ ;;
+ *)
+ echo "usage $0 {start¦stop¦restart}"
+esac
+exit 0
diff --git a/retiolum/scripts/tinc_multicast/retiolum.py b/retiolum/scripts/tinc_multicast/retiolum.py
new file mode 100755
index 00000000..8cf57471
--- /dev/null
+++ b/retiolum/scripts/tinc_multicast/retiolum.py
@@ -0,0 +1,349 @@
+#!/usr/bin/python2
+import sys, os, time, signal, socket, subprocess, thread, random, Queue, binascii, logging, hashlib, urllib2 #these should all be in the stdlib
+from optparse import OptionParser
+
+def pub_encrypt(hostname_t, text): #encrypt data with public key
+ logging.debug("encrypt: " + text)
+ if hostname_t.find("`") != -1: return(-1)
+ try:
+ enc_text = subprocess.os.popen("echo '" + text + "' | openssl rsautl -pubin -inkey /etc/tinc/" + netname + "/hosts/.pubkeys/" + hostname_t + " -encrypt | base64 -w0")
+ return(enc_text.read())
+ except:
+ return(-1)
+
+def priv_decrypt(enc_data): #decrypt data with private key
+ if enc_data.find("`") != -1: return(-1)
+ dec_text = subprocess.os.popen("echo '" + enc_data + "' | base64 -d | openssl rsautl -inkey /etc/tinc/" + netname + "/rsa_key.priv -decrypt")
+ return(dec_text.read())
+
+def address2hostfile(hostname, address): #adds address to hostsfile or restores it if address is empty
+ hostfile = "/etc/tinc/" + netname + "/hosts/" + hostname
+ addr_file = open(hostfile, "r")
+ addr_cache = addr_file.readlines()
+ addr_file.close()
+ if address != "":
+ addr_cache.insert(0, "Address = " + address + "\n")
+ addr_file = open(hostfile, "w")
+ addr_file.writelines(addr_cache)
+ addr_file.close
+ logging.info("sending SIGHUP to tinc deamon!")
+ tincd_ALRM = subprocess.call(["tincd -n " + netname + " --kill=HUP" ],shell=True)
+ else:
+ recover = subprocess.os.popen("tar xzf /etc/tinc/" + netname + "/hosts/hosts.tar.gz -C /etc/tinc/" + netname + "/hosts/ " + hostname)
+
+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
+
+def get_hostfiles(url_files, url_md5sum):
+ try:
+ get_hosts_tar = urllib2.urlopen(url_files)
+ get_hosts_md5 = urllib2.urlopen(url_md5sum)
+ hosts_tar = get_hosts_tar.read()
+ hosts_md5 = get_hosts_md5.read()
+
+ if str(hosts_md5) == str(hashlib.md5(hosts_tar).hexdigest() + " hosts.tar.gz\n"):
+ hosts = open("/etc/tinc/" + netname + "/hosts/hosts.tar.gz", "w")
+ hosts.write(hosts_tar)
+ hosts.close()
+ else:
+ logging.error("hosts.tar.gz md5sum check failed!")
+ except:
+ logging.error("hosts file download failed!")
+
+
+####Thread functions
+
+
+def sendthread(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(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")
+ logging.debug("recv: ;tst;" + dataval[3] + ";" + ip)
+ 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")
+ logging.debug("recv: ;" + dataval[1] + ";" + dataval[3] + ";" + ip + ";" + dataval[4])
+ 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")
+ logging.debug("recv: ;" + dataval[1] + ";" + dataval[3] + ";" + ip + ";" + dataval[4])
+ except:
+ logging.error("recv: socket init failed")
+ time.sleep(10)
+
+def timeoutthread(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":
+ with hostslock:
+ hostslist.append([curhost[1], curhost[2], time.time()])
+ address2hostfile(curhost[1], curhost[2])
+ logging.info("adding host to hostslist")
+ elif curhost[0] == "tst":
+ with hostslock:
+ line = findhostinlist(hostslist, curhost[1], curhost[2])
+ if line != -1:
+ hostslist[line][2] = time.time()
+ logging.debug("timeout: refreshing timestamp of " + hostslist[line][0])
+ else:
+ authfifo.put(["Stage1", curhost[1], curhost[2]])
+ logging.info("timeout: writing to auth")
+
+ else:
+ i = 0
+ with hostslock:
+ while i < len(hostslist):
+ if time.time() - hostslist[i][2] > 60:
+ address2hostfile(hostslist[i][0], "")
+ hostslist.remove(hostslist[i])
+ logging.info("timeout: deleting dead host")
+ else:
+ i += 1
+ time.sleep(2)
+
+def auththread(authfifo, sendfifo, timeoutfifo): #manages authentication with clients (bruteforce sensitve, should be fixed)
+ authlist = [] #hostname, ip, Challenge, timestamp
+
+
+ while True:
+ try:
+ 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(curauth[1], "#" + hostname + "#" + str(challengenum) + "#")
+ authlist.append([curauth[1], curauth[2], challengenum, time.time()])
+ else:
+ encrypted_message = pub_encrypt(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)
+ l