Commit cd6631b4 authored by Ulysse Beaugnon's avatar Ulysse Beaugnon

Merge branch 'master' of https://git.erp5.org/repos/vifibnet

parents f8574d91 4d956fea
#!/usr/bin/env python
import argparse, random, smtplib, sqlite3
import argparse, math, random, smtplib, sqlite3, string, time
from email.mime.text import MIMEText
from SimpleXMLRPCServer import SimpleXMLRPCServer
from functools import wraps
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
from OpenSSL import crypto
import netaddr
import traceback
class RequestHandler(SimpleXMLRPCRequestHandler):
def _dispatch(self, method, params):
return self.server._dispatch(method, (self,) + params)
class main(object):
def __init__(self):
self.cert_duration = 365 * 86400
# Command line parsing
parser = argparse.ArgumentParser(
description='Peer discovery http server for vifibnet')
......@@ -18,46 +26,62 @@ class main(object):
help='Path to ca.crt file')
_('--key', required=True,
help='Path to certificate key')
_('--network', required=True,
help='Vifib subnet')
config = parser.parser_arg()
_('--mailhost', required=True,
help='SMTP server mail host')
self.config = parser.parse_args()
# Database initializing
self.db = sqlite3.connect(config.db, isolation_level=None)
self.db = sqlite3.connect(self.config.db, isolation_level=None)
self.db.execute("""CREATE TABLE IF NOT EXISTS peers (
prefix text primary key not null,
ip text not null,
port integer not null,
proto text not null)""")
self.db.execute("""CREATE TABLE IF NOT EXISTS tokens (
token text primary key not null,
email text not null,
prefix_len integer not null default 16,
prefix_len integer not null,
date integer not null)""")
self.db.execute("""CREATE TABLE IF NOT EXISTS certificates (
prefix text primary key not null,
email text not null,
cert text not null)""")
try:
self.db.execute("""CREATE TABLE vifib (
prefix text primary key not null,
email text,
cert text)""")
except sqlite3.OperationalError, e:
if e.args[0] == 'table vifib already exists':
pass
else:
raise RuntimeError
else:
self.db.execute("INSERT INTO vifib VALUES ('',null,null)")
# Loading certificates
with open(config.ca) as f:
with open(self.config.ca) as f:
self.ca = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
with open(config.key) as f:
with open(self.config.key) as f:
self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, f.read())
# Get vifib network prefix
self.network = bin(self.ca.get_serial_number())[3:]
# Starting server
server = SimpleXMLRPCServer(("localhost", 8000))
server = SimpleXMLRPCServer(("localhost", 8000), requestHandler=RequestHandler, allow_none=True)
server.register_instance(self)
server.serve_forever()
def requestToken(self, email):
def requestToken(self, handler, email):
while True:
# Generating token
token = ''.join(random.sample(string.ascii_lowercase, 8))
# Updating database
try:
self.db.execute("INSERT INTO tokens (?,?,null,?)", (token, email, int(time.time())))
self.db.execute("INSERT INTO tokens VALUES (?,?,?,?)", (token, email, 16, int(time.time())))
break
except sqlite3.IntegrityError, e:
pass
# Creating and sending email
s = smtplib.SMTP('localhost')
s = smtplib.SMTP(self.config.mailhost)
me = 'postmaster@vifibnet.com'
msg = MIMEText('Hello world !\nYour token : %s' % (token,))
msg['Subject'] = '[Vifibnet] Token Request'
......@@ -66,45 +90,67 @@ class main(object):
s.sendmail(me, email, msg.as_string())
s.quit()
def requestCertificate(self, token, cert_req):
n = len(cert_req_list)
def _getPrefix(self, prefix_len):
assert 0 < prefix_len <= 128 - len(self.network)
for prefix, in self.db.execute("""SELECT prefix FROM vifib WHERE length(prefix) <= ? AND cert is null
ORDER BY length(prefix) DESC""", (prefix_len,)):
while len(prefix) < prefix_len:
self.db.execute("UPDATE vifib SET prefix = ? WHERE prefix = ?", (prefix + '1', prefix))
prefix += '0'
self.db.execute("INSERT INTO vifib VALUES (?,null,null)", (prefix,))
return prefix
raise RuntimeError # TODO: raise better exception
def requestCertificate(self, handler, token, cert_req):
try:
req = crypto.load_certificate_request(crypto.FILETYPE_PEM, cert_req)
try:
# TODO : check syntax
token, email, prefix_len, _ = self.db.execute("SELECT * FROM tokens WHERE token = ?", (token,)).fetchone()
with self.db:
try:
token, email, prefix_len, _ = self.db.execute("SELECT * FROM tokens WHERE token = ?", (token,)).next()
except StopIteration:
# TODO: return nice error message
raise
self.db.execute("DELETE FROM tokens WHERE token = ?", (token,))
# Create a new prefix
# TODO : FIX !
# i impair => ok
# récursif sinon
for i, prefix in enumerate(self.db.execute("""SELECT DISTINCT substr(prefix,1,?) FROM certificates
WHERE length(prefix) >= ? ORDER BY prefix""", (prefix_len, prefix_len))):
if i != int(prefix, 2):
pass
break
else:
prefix = i
# Get a new prefix
prefix = self._getPrefix(prefix_len)
# create certificate
# Create certificate
cert = crypto.X509()
#cert.set_serial_number(serial)
#cert.gmtime_adj_notBefore(notBefore)
#cert.gmtime_adj_notAfter(notAfter)
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(self.cert_duration)
cert.set_issuer(self.ca.get_subject())
cert.set_subject(req.get_subject())
subject = req.get_subject()
subject.serialNumber = "%u/%u" % (int(prefix, 2), prefix_len)
cert.set_subject(subject)
cert.set_pubkey(req.get_pubkey())
cert.sign(self.key, 'sha1')
cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
# Insert certificate into db
self.db.execute("INSERT INTO certificates (?,?)", (, email, cert) )
self.db.execute("UPDATE vifib SET email = ?, cert = ? WHERE prefix = ?", (email, cert, prefix) )
return cert
except:
traceback.print_exc()
raise
def getCa(self, handler):
return crypto.dump_certificate(crypto.FILETYPE_PEM, self.ca)
def declare(self, handler, address):
# guess prefix from handler.client_address
ip1, ip2 = struct.unpack('>QQ', socket.inet_pton(socket.AF_INET6, handler.client_address)))
prefix = bin(ip1)[2:] + bin(ip2)]2:]
ip, port, proto = address
self.db.execute("INSERT INTO peers VALUES (?,?,?,?)", (prefix, ip, port, proto))
def getPeerList(self, handler, n, address):
assert 0 < n < 1000
self.declare(handler, address)
return self.db.execute("SELECT ip, port, proto FROM peers ORDER BY random() LIMIT ?", (n,)).fetchall()
# Returning certificate
return cert
except: Exception:
# TODO : what to do ?
pass
if __name__ == "__main__":
main()
#!/usr/bin/env python
from OpenSSL import crypto
import argparse, os, subprocess, xmlrpclib
def main():
parser = argparse.ArgumentParser(
description='Setup script for vifib')
_ = parser.add_argument
_('--server', required=True,
help='Address of the server delivering certifiactes')
_('--port', required=True, type=int,
help='Port to which connect on the server')
_('-d', '--dir', default='/etc/vifib',
help='Directory where the key and certificate will be stored')
_('-r', '--req', nargs='+',
help='''Certificate request additional arguments. For example :
--req name1 value1 name2 value2, to add attributes name1 and name2''')
config = parser.parse_args()
if config.req and len(config.req) % 2 == 1:
print "Sorry, request argument was incorrect, there must be an even number of request arguments"
os.exit(1)
# Get token
email = raw_input('Please enter your email address : ')
s = xmlrpclib.ServerProxy('http://%s:%u' % (config.server, config.port))
_ = s.requestToken(email)
token = raw_input('Please enter your token : ')
# Generate key and cert request
pkey = crypto.PKey()
pkey.generate_key(crypto.TYPE_RSA, 2048)
key = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
req = crypto.X509Req()
subj = req.get_subject()
if config.req:
while len(config.req) > 1:
key = config.req.pop(0)
value = config.req.pop(0)
setattr(subj, key, value)
req.set_pubkey(pkey)
req.sign(pkey, 'sha1')
req = crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)
# Get certificates
ca = s.getCa()
cert = s.requestCertificate(token,req)
# Generating dh file
subprocess.call(['openssl', 'dhparam', '-out', os.path.join(config.dir, 'dh2048.pem'), '2048'])
# Store cert and key
with open(os.path.join(config.dir, 'cert.key'), 'w') as f:
f.write(key)
with open(os.path.join(config.dir, 'cert.crt'), 'w') as f:
f.write(cert)
with open(os.path.join(config.dir, 'ca.pem'), 'w') as f:
f.write(ca)
print "Certificate setup complete."
if __name__ == "__main__":
main()
#!/usr/bin/env python
import argparse, errno, os, select, sqlite3, subprocess, sys, time
import argparse, errno, os, select, sqlite3, subprocess, sys, time, xmlrpclib
import traceback
import upnpigd
import openvpn
......@@ -11,22 +11,34 @@ connection_dict = {} # to remember current connections we made
free_interface_set = set(('client1', 'client2', 'client3', 'client4', 'client5',
'client6', 'client7', 'client8', 'client9', 'client10'))
# TODO : How do we get our vifib ip ?
# TODO : flag in some way the peers that are connected to us so we don't connect to them
# Or maybe we just don't care,
# Or maybe we just don't care,
class PeersDB:
def __init__(self, dbPath):
self.proxy = xmlrpclib.ServerProxy('http://%s:%u' % (config.server, config.server_port))
log.log('Connectiong to peers database', 4)
self.db = sqlite3.connect(dbPath, isolation_level=None)
log.log('Initializing peers database', 4)
self.db.execute("""CREATE TABLE IF NOT EXISTS peers
( id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT NOT NULL,
port INTEGER NOT NULL,
proto TEXT NOT NULL,
used INTEGER NOT NULL)""")
self.db.execute("CREATE INDEX IF NOT EXISTS _peers_used ON peers(used)")
self.db.execute("UPDATE peers SET used = 0")
try:
self.db.execute("""CREATE TABLE peers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT NOT NULL,
port INTEGER NOT NULL,
proto TEXT NOT NULL,
used INTEGER NOT NULL default 0)""")
self.db.execute("CREATE INDEX _peers_used ON peers(used)")
self.db.execute("UPDATE peers SET used = 0")
except sqlite3.OperationalError, e:
if e.args[0] != 'table peers already exists':
raise RuntimeError
else:
self.populateDB(100)
def populateDB(self, n):
(ip, port) = upnpigd.GetExternalInfo(1194)
proto = 'udp'
self.db.executemany("INSERT INTO peers (ip, port, proto) VALUES ?", self.proxy.getPeerList(n, port, proto))
def getUnusedPeers(self, nPeers):
return self.db.execute("SELECT id, ip, port, proto FROM peers WHERE used = 0 "
......@@ -40,6 +52,12 @@ class PeersDB:
log.log('Updating peers database : unusing peer ' + str(id), 5)
self.db.execute("UPDATE peers SET used = 0 WHERE id = ?", (id,))
def ipFromPrefix(prefix, prefix_len):
tmp = hew(int(prefix, 2))[2::]
ip = VIFIB_NET
for i in xrange(0, len(ip), 4):
ip += tmp[i:i+4] + ':'
ip += ':'
def startBabel(**kw):
args = ['babeld',
......@@ -65,6 +83,10 @@ def getConfig():
parser = argparse.ArgumentParser(
description='Resilient virtual private network application')
_ = parser.add_argument
_('--server', required=True,
help='Address for peer discovery server')
_('--server-port', required=True,
help='Peer discovery server port')
_('--log-directory', default='/var/log',
help='Path to vifibnet logs directory')
_('--client-count', default=2, type=int,
......@@ -84,6 +106,8 @@ def getConfig():
help='Path to babeld state-file')
_('--verbose', '-v', default=0, type=int,
help='Defines the verbose level')
_('--cert', required=True,
help='Path to the certificate file')
# Temporary args - to be removed
_('--ip', required=True,
help='IPv6 of the server')
......@@ -91,8 +115,18 @@ def getConfig():
_('openvpn_args', nargs=argparse.REMAINDER,
help="Common OpenVPN options (e.g. certificates)")
openvpn.config = config = parser.parse_args()
with open(config.cert, 'r') as f:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f)
subject = cert.get_subject()
prefix_txt, prefix_len_txt = subject.serialNumber.split('/')
prefix = int(prefix_txt)
prefix_len = int(prefix_len_txt)
ip = ipFromPrefix(prefix)
print ip
if config.openvpn_args[0] == "--":
del config.openvpn_args[0]
config.openvpn_args.append('--cert')
config.openvpn_args.append(config.cert)
def startNewConnection(n):
try:
......@@ -100,7 +134,8 @@ def startNewConnection(n):
log.log('Establishing a connection with id %s (%s:%s)' % (id,ip,port), 2)
iface = free_interface_set.pop()
connection_dict[id] = ( openvpn.client( ip, '--dev', iface, '--proto', proto, '--rport', str(port),
stdout=os.open('%s/vifibnet.client.%s.log' % (config.log_directory, id), os.O_WRONLY|os.O_CREAT|os.O_TRUNC) ),
stdout=os.open(os.path.join(config.log_directory, 'vifibnet.client.%s.log' % (id,)),
os.O_WRONLY|os.O_CREAT|os.O_TRUNC) ),
iface)
peers_db.usePeer(id)
except KeyError:
......@@ -158,6 +193,7 @@ def main():
# Get arguments
getConfig()
log.verbose = config.verbose
# TODO: get proto to use ?
(externalIp, externalPort) = upnpigd.GetExternalInfo(1194)
# Setup database
......@@ -177,7 +213,7 @@ def main():
# Establish connections
log.log('Starting openvpn server', 3)
serverProcess = openvpn.server(config.ip, write_pipe, '--dev', 'vifibnet',
stdout=os.open('%s/vifibnet.server.log' % (config.log_directory,), os.O_WRONLY | os.O_CREAT | os.O_TRUNC))
stdout=os.open(os.path.join(config.log_directory, 'vifibnet.server.log'), os.O_WRONLY | os.O_CREAT | os.O_TRUNC))
startNewConnection(config.client_count)
# Timed refresh initializing
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment