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