]> git.ipfire.org Git - ipfire-2.x.git/blame - src/scripts/openvpn-metrics
openvpn: Store connection times in ASCII timestamps
[ipfire-2.x.git] / src / scripts / openvpn-metrics
CommitLineData
708f2b73
MT
1#!/usr/bin/python3
2############################################################################
3# #
4# This file is part of the IPFire Firewall. #
5# #
6# IPFire is free software; you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation; either version 2 of the License, or #
9# (at your option) any later version. #
10# #
11# IPFire is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with IPFire; if not, write to the Free Software #
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
19# #
20# Copyright (C) 2007-2020 IPFire Team <info@ipfire.org>. #
21# #
22############################################################################
23
24import argparse
25import logging
26import logging.handlers
27import os
28import sqlite3
29import sys
30
31_ = lambda x: x
32
33DEFAULT_DATABASE_PATH = "/var/ipfire/ovpn/clients.db"
34
35def setup_logging(level=logging.INFO):
36 l = logging.getLogger("openvpn-metrics")
37 l.setLevel(level)
38
39 # Log to console
40 h = logging.StreamHandler()
41 h.setLevel(logging.DEBUG)
42 l.addHandler(h)
43
44 # Log to syslog
45 h = logging.handlers.SysLogHandler(address="/dev/log",
46 facility=logging.handlers.SysLogHandler.LOG_DAEMON)
47 h.setLevel(logging.INFO)
48 l.addHandler(h)
49
50 # Format syslog messages
51 formatter = logging.Formatter("openvpn-metrics[%(process)d]: %(message)s")
52 h.setFormatter(formatter)
53
54 return l
55
56# Initialise logging
57log = setup_logging()
58
59class OpenVPNMetrics(object):
60 def __init__(self):
61 self.db = self._open_database()
62
63 def parse_cli(self):
64 parser = argparse.ArgumentParser(
65 description=_("Tool that collects metrics of OpenVPN Clients"),
66 )
67 subparsers = parser.add_subparsers()
68
69 # client-connect
70 client_connect = subparsers.add_parser("client-connect",
71 help=_("Called when a client connects"),
72 )
73 client_connect.add_argument("file", nargs="?",
74 help=_("Configuration file")
75 )
76 client_connect.set_defaults(func=self.client_connect)
77
78 # client-disconnect
79 client_disconnect = subparsers.add_parser("client-disconnect",
80 help=_("Called when a client disconnects"),
81 )
82 client_disconnect.add_argument("file", nargs="?",
83 help=_("Configuration file")
84 )
85 client_disconnect.set_defaults(func=self.client_disconnect)
86
87 # Parse CLI
88 args = parser.parse_args()
89
90 # Print usage if no action was given
91 if not "func" in args:
92 parser.print_usage()
93 sys.exit(2)
94
95 return args
96
97 def __call__(self):
98 # Parse command line arguments
99 args = self.parse_cli()
100
101 # Call function
102 try:
103 ret = args.func(args)
104 except Exception as e:
105 log.critical(e)
106
107 # Return with exit code
108 sys.exit(ret or 0)
109
110 def _open_database(self, path=DEFAULT_DATABASE_PATH):
111 db = sqlite3.connect(path)
112
113 # Create schema if it doesn't exist already
114 db.executescript("""
115 CREATE TABLE IF NOT EXISTS sessions(
116 common_name TEXT NOT NULL,
616de0b4
MT
117 connected_at TEXT NOT NULL,
118 disconnected_at TEXT,
708f2b73
MT
119 bytes_received INTEGER,
120 bytes_sent INTEGER
121 );
122
123 -- Create index for speeding up searches
124 CREATE INDEX IF NOT EXISTS sessions_common_name ON sessions(common_name);
125 """)
126
127 return db
128
129 def _get_environ(self, key):
130 if not key in os.environ:
131 sys.stderr.write("%s missing from environment\n" % key)
132 raise SystemExit(1)
133
134 return os.environ.get(key)
135
136 def client_connect(self, args):
137 common_name = self._get_environ("common_name")
138
139 # Time
140 time_ascii = self._get_environ("time_ascii")
141 time_unix = self._get_environ("time_unix")
142
143 log.info("Opening session for %s at %s" % (common_name, time_ascii))
144
145 c = self.db.cursor()
146 c.execute("INSERT INTO sessions(common_name, connected_at) \
616de0b4 147 VALUES(?, DATETIME(?, 'unixepoch'))", (common_name, time_unix))
708f2b73
MT
148 self.db.commit()
149
150 def client_disconnect(self, args):
151 common_name = self._get_environ("common_name")
152 duration = self._get_environ("time_duration")
153
154 # Collect some usage statistics
155 bytes_received = self._get_environ("bytes_received")
156 bytes_sent = self._get_environ("bytes_sent")
157
158 log.info("Closing session for %s after %ss and receiving/sending %s/%s bytes" \
159 % (common_name, duration, bytes_received, bytes_sent))
160
161 c = self.db.cursor()
616de0b4
MT
162 c.execute("UPDATE sessions SET disconnected_at = DATETIME(connected_at, '+' || ? || ' seconds'), \
163 bytes_received = ?, bytes_sent = ? \
164 WHERE common_name = ? AND disconnected_at IS NULL",
708f2b73
MT
165 (duration, bytes_received, bytes_sent, common_name))
166 self.db.commit()
167
168def main():
169 m = OpenVPNMetrics()
170 m()
171
172main()