second commit

This commit is contained in:
root 2021-01-24 23:29:37 +01:00
parent 267bd9d888
commit 43790ef31c
5 changed files with 258 additions and 7 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "easy-rsa"]
path = easy-rsa
url = https://github.com/OpenVPN/easy-rsa.git

1
easy-rsa Submodule

@ -0,0 +1 @@
Subproject commit a9cecc747c419197d9540ccd46259559e271788a

116
main.py
View File

@ -1,8 +1,17 @@
import sqlite3
import sys
from flask import Flask, request, jsonify
import os
from flask import Flask, request, jsonify, render_template, Response
app = Flask(__name__)
class Ex(Exception):
def __init__(self, code, message):
self._code = code
self._message = message
def getCode(self):
return self._code
def __str__(self):
return self._message
DATABASE='/data/database.sqlite3'
db = sqlite3.connect(DATABASE)
cu = db.cursor()
@ -10,11 +19,15 @@ db.execute('SELECT name FROM sqlite_master')
if len(cu.fetchall()) == 0:
print('creating database schema...')
db.execute('CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY, name TEXT UNIQUE)')
db.execute('CREATE TABLE IF NOT EXISTS gateway (id INTEGER PRIMARY KEY, name TEXT UNIQUE, user INTEGER REFERENCES user(id))')
db.execute('CREATE TABLE IF NOT EXISTS gateway (id INTEGER PRIMARY KEY, subid INTEGER NOT NULL, name TEXT UNIQUE, user INTEGER NOT NULL REFERENCES user(id))')
db.commit()
cu.close()
db.close()
os.environ['EASYRSA_PKI'] = '/data/pki'
os.environ['EASYRSA_BATCH'] = '1'
os.environ['PATH'] = os.environ['PATH'] + ':' + os.getcwd() + '/easy-rsa/easyrsa3'
@app.route('/')
def hello_world():
return 'It works!'
@ -45,24 +58,113 @@ def post_users():
return jsonify({'status': 'ok'})
except sqlite3.Error as e:
return jsonify({'status': 'error', 'message': str(e)}), 409
finally:
finally:
db.commit()
cu.close()
db.close()
@app.route('/gateways', methods=['GET'])
def get_gateway():
def get_gateways():
db = sqlite3.connect(DATABASE)
cu = db.cursor()
gateways = []
for row in cu.execute('SELECT id, name, user FROM gateway'):
gateways.append({'id': row[0], 'name': row[1], 'user': row[2], 'network': row[3]})
for row in cu.execute('SELECT g.id, g.subid, g.name, u.name FROM gateway AS g INNER JOIN user AS u ON u.id = g.user'):
gateways.append({'id': row[0], 'subid': row[1], 'name': row[2], 'user': row[3]})
cu.close()
db.close()
return jsonify(gateways)
@app.route('/gateways', methods=['POST'])
def post_gateways():
db = sqlite3.connect(DATABASE)
cu = db.cursor()
try:
name = request.json['name']
user = request.json['user']
# TODO sanitize name, it must be a FQDN
used_gateway_subids = []
for row in cu.execute('SELECT g.subid, u.id FROM gateway AS g INNER JOIN user AS u ON g.user = u.id WHERE u.name = ?', [str(user,)]):
used_gateway_subids.append(row[0])
userid = row[1]
# search for an empty id for gateway
for subid in range(0, 15):
if subid not in used_gateway_subids:
break
if subid in used_gateway_subids:
raise Ex(403, 'exit: maximum number of gateways reached for user')
cu.execute('INSERT INTO gateway (subid, name, user) VALUES (?, ?, (SELECT id FROM user WHERE name = ?))', [subid, str(name,), str(user,)])
os.environ['EASYRSA_REQ_CN'] = name
r = os.system('easyrsa gen-req {} nopass'.format(name))
if r != 0:
raise Ex(500, 'exit: {} cannot gen-req'.format(r))
r = os.system('easyrsa sign-req client {}'.format(name))
if r != 0:
raise Ex(500, 'exit: {} cannot sign-req'.format(r))
ipid = '{:x}{:x}'.format(userid, subid)
address = '2001:470:c844::' + ipid + '0/64'
network = '2001:470:c844:' + ipid + '0::/60'
staticclient = render_template('staticclient', address=address, network=network)
with open('/data/ovpn/clients/' + name, 'w') as f:
f.write(staticclient)
db.commit()
return jsonify({'status': 'ok'})
except KeyError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
except sqlite3.Error as e:
return jsonify({'status': 'error', 'message': str(e)}), 409
except Ex as e:
return jsonify({'status': 'error', 'message': str(e)}), e.getCode()
finally:
cu.close()
db.close()
@app.route('/gateway/<fqdn>', methods=['GET'])
def get_gateway(fqdn):
db = sqlite3.connect(DATABASE)
cu = db.cursor()
gateway = dict()
for row in cu.execute('SELECT g.id, g.subid, g.name, u.name FROM gateway AS g INNER JOIN user AS u ON u.id = g.user'):
gateway['id'] = row[0]
gateway['subid'] = row[1]
gateway['name'] = row[2]
gateway['user'] = row[3]
cu.close()
db.close()
return jsonify(gateway)
@app.route('/gateway/<fqdn>/config', methods=['GET'])
def get_gateway_config(fqdn):
# TODO sanity check FQDN
# WARNING: maybe you want to do more than a simple sanity check,
# or you have to trust the user of these API
# eg: he could retrieve the CA.key !!!
with open(os.environ['EASYRSA_PKI'] + '/issued/' + fqdn + '.crt') as f:
cert = f.read()
with open(os.environ['EASYRSA_PKI'] + '/private/' + fqdn + '.key') as f:
key = f.read()
with open(os.environ['EASYRSA_PKI'] + '/ca.crt') as f:
ca = f.read()
return Response(render_template('config.ovpn', ca=ca, cert=cert, key=key), mimetype='text/plain')
if __name__ == '__main__':
app.run(host="::", port=5000, debug=True)

142
templates/config.ovpn Normal file
View File

@ -0,0 +1,142 @@
#############################################
# OpenVPN 2.0 client config file #
#############################################
# #
# golem.linux.it #
# #
# in caso di problemi visitare la pagina #
# https://golem.linux.it/wiki/VPN_del_GOLEM #
# https://golem.linux.it/wiki/IPv6_@_GOLEM #
# #
# se non si riesce a risolvere, contattare #
# l'amministratore di rete #
#############################################
# Specify that we are a client and that we
# will be pulling certain config file directives
# from the server.
client
# Use the same setting as you are using on
# the server.
# On most systems, the VPN will not function
# unless you partially or fully disable
# the firewall for the TUN/TAP interface.
dev tun
# Windows needs the TAP-Win32 adapter name
# from the Network Connections panel
# if you have more than one. On XP SP2,
# you may need to disable the firewall
# for the TAP adapter.
;dev-node MyTap
# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
proto udp6
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote vpntest.andromeda.golem.linux.it 6666
# Choose a random host from the remote
# list for load-balancing. Otherwise
# try hosts in the order specified.
;remote-random
# Keep trying indefinitely to resolve the
# host name of the OpenVPN server. Very useful
# on machines which are not permanently connected
# to the internet such as laptops.
resolv-retry infinite
# Most clients don't need to bind to
# a specific local port number.
nobind
# Downgrade privileges after initialization (non-Windows only)
user nobody
group nobody
# Try to preserve some state across restarts.
persist-key
persist-tun
# If you are connecting through an
# HTTP proxy to reach the actual OpenVPN
# server, put the proxy server/IP and
# port number here. See the man page
# if your proxy server requires
# authentication.
;http-proxy-retry # retry on connection failures
;http-proxy [proxy server] [proxy port #]
# Wireless networks often produce a lot
# of duplicate packets. Set this flag
# to silence duplicate packet warnings.
;mute-replay-warnings
# SSL/TLS parms.
# See the server config file for more
# description. It's best to use
# a separate .crt/.key file pair
# for each client. A single ca
# file can be used for all clients.
#ca /home/golem/ca.crt
#cert /home/golemiss3.golem.it.crt
#key /home/golem/iss3.golem.it.key
# Verify server certificate by checking that the
# certicate has the correct key usage set.
# This is an important precaution to protect against
# a potential attack discussed here:
# http://openvpn.net/howto.html#mitm
#
# To use this feature, you will need to generate
# your server certificates with the keyUsage set to
# digitalSignature, keyEncipherment
# and the extendedKeyUsage to
# serverAuth
# EasyRSA can do this for you.
remote-cert-tls server
# If a tls-auth key is used on the server
# then every client must also have the key.
; tls-auth ta.key 1
# Select a cryptographic cipher.
# If the cipher option is used on the server
# then you must also specify it here.
# Note that 2.4 client/server will automatically
# negotiate AES-256-GCM in TLS mode.
# See also the ncp-cipher option in the manpage
cipher AES-256-CBC
# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
; comp-lzo
# Set log file verbosity.
verb 3
# Silence repeating messages
;mute 20
# Periodically ping the server,
# and if it doesn't answer after a timeout
# try to reconnect again
keepalive 30 120
<ca>
{{ ca }}
</ca>
<cert>
{{ cert }}
</cert>
<key>
{{ key }}
</key>

3
templates/staticclient Normal file
View File

@ -0,0 +1,3 @@
ifconfig-ipv6-push {{ address }}
iroute-ipv6 {{ network }}