diff --git a/hook.py b/hook.py index e210d84..0c449e4 100755 --- a/hook.py +++ b/hook.py @@ -2,73 +2,137 @@ import os from sqlalchemy import create_engine, MetaData, Table, Column, \ - String, Time, Interval, func + String, DateTime, Interval, func from sqlalchemy.sql import select, and_ from sqlalchemy.dialects.mysql import SMALLINT, INTEGER import json import logging from datetime import datetime, timedelta +import argparse +import sys if __name__ == '__main__': logger = logging.getLogger('main') - logging.basicConfig(level=logging.DEBUG) + parser = argparse.ArgumentParser(description='OpenVPN Server Hook') + parser.add_argument('--debug', action='store_true') + parser.add_argument('args', nargs=argparse.REMAINDER) + args = parser.parse_args() + if args.debug: + logging.basicConfig(level=logging.DEBUG) + logging.debug('Additional arguments: ' + ' '.join(args.args)) + sqlEcho = True + else: + logging.basicConfig(level=logging.INFO) + sqlEcho = False with open(os.getcwd() + '/config.json') as f: config = json.load(f) - engine = create_engine(config['dburl'], echo=True) + engine = create_engine(config['dburl'], echo=sqlEcho) metadata = MetaData() vpnsessions = Table('sessions', metadata, Column('session_id', INTEGER(unsigned=True), primary_key=True, autoincrement=True), - Column('daemon_start_time', Time), + Column('daemon_start_time', DateTime), Column('username', String(32)), Column('ip', String(64)), Column('port', SMALLINT(unsigned=True)), - Column('connect_time', Time), + Column('connect_time', DateTime), + Column('vpn_ip', String(15)), # NULL if still connected: - Column('session_length', Interval, nullable=True), + Column('disconnect_time', DateTime, + nullable=True), Column('bytes_to_client', INTEGER(unsigned=True)), Column('bytes_from_client', INTEGER(unsigned=True)), Column('client_os', String(128)), Column('client_ssl', String(32)), - Column('client_ver', String(32)) + Column('client_ver', String(32)), + Column('client_gui_ver', String(32)), + Column('client_device_name', String(128)) ) metadata.create_all(engine) - daemonStartTime = datetime.fromtimestamp( - int(os.getenv('daemon_start_time'))) - scriptType = os.envron.get('script_type') + scriptType = os.getenv('script_type') if scriptType == 'up': pass elif scriptType == 'down': pass elif scriptType == 'client-connect': + if os.getenv('IV_SSL') is None: # client didn't push peer info + logger.info("Client didn't push peer info, rejecting.") + sys.exit(1) + daemonStartTime = datetime.fromtimestamp( + int(os.getenv('daemon_start_time'))) username = os.getenv('username') ip = os.getenv('trusted_ip') + vpnIP = os.getenv('ifconfig_pool_remote_ip') + clientOS = ' '.join(filter(None, [os.getenv('IV_PLAT'), + os.getenv('IV_PLAT_VER')])) + clientSSL = os.getenv('IV_SSL') + clientVer = os.getenv('IV_VER') + clientGUIVer = os.getenv('IV_UI_VER') + clientDeviceName = os.getenv('UV_DeviceName') port = int(os.getenv('trusted_port')) - connectTime = datetime.fromtimestamp( - int(os.getenv('time_unix'))) + connectTime = datetime.fromtimestamp(int(os.getenv('time_unix'))) stmt = select([ func.count(vpnsessions.c.session_id)]).\ where( and_( vpnsessions.c.username == username, vpnsessions.c.daemon_start_time == daemonStartTime, - vpnsessions.c.session_length is None + vpnsessions.c.disconnect_time == None ) ) conn = engine.connect() - print(conn.execute(stmt).fetchone()) - ins = vpnsessions.insert() + connectedSessions = conn.execute(stmt).fetchone()[0] + if connectedSessions >= config['max_sessions_per_user']: + # with open(args[0], 'rw') as f: + # f.write('disable') + logger.info("Maximum sessions for user " + username + + " reached, authentication rejected.") + sys.exit(1) + ins = vpnsessions.insert().values( + daemon_start_time=daemonStartTime, + username=username, + ip=ip, + port=port, + connect_time=connectTime, + vpn_ip=vpnIP, + client_os=clientOS, + client_ssl=clientSSL, + client_ver=clientVer, + client_gui_ver=clientGUIVer, + client_device_name=clientDeviceName + ) + logger.debug("Creating session info: daemon start time {}, VPN IP {}.". + format(daemonStartTime, vpnIP)) + conn.execute(ins) pass elif scriptType == 'client-disconnect': - sessionLength = timedelta( - seconds=int(os.getenv('time_duration'))) + daemonStartTime = datetime.fromtimestamp( + int(os.getenv('daemon_start_time'))) + connectTime = datetime.fromtimestamp(int(os.getenv('time_unix'))) + sessionLength = timedelta(seconds=int(os.getenv('time_duration'))) bytesToClient = int(os.getenv('bytes_sent')) bytesFromClient = int(os.getenv('bytes_received')) + vpnIP = os.getenv('ifconfig_pool_remote_ip') + stmt = vpnsessions.update().\ + where( + and_( + vpnsessions.c.daemon_start_time == daemonStartTime, + vpnsessions.c.disconnect_time== None, + vpnsessions.c.vpn_ip == vpnIP + ) + ).\ + values(disconnect_time=connectTime + sessionLength, + bytes_to_client=bytesToClient, + bytes_from_client=bytesFromClient) + logger.debug("Terminating session: daemon start time {}, VPN IP {}.". + format(daemonStartTime, vpnIP)) + conn = engine.connect() + conn.execute(stmt) pass elif scriptType == 'learn-address': pass