Files
OpenVPN-Monitoring-Simple/APP/config_manager.py

156 lines
5.8 KiB
Python
Raw Normal View History

import os
import re
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
class ConfigManager:
def __init__(self, template_dir, output_dir):
self.template_dir = template_dir
self.output_dir = output_dir
self.env = Environment(loader=FileSystemLoader(template_dir))
self.server_conf_path = Path(output_dir) / "server.conf"
def read_server_config(self):
"""Parse existing server config into a dictionary"""
if not self.server_conf_path.exists():
return {}
config = {}
try:
with open(self.server_conf_path, 'r') as f:
content = f.read()
# Regex mappings for simple key-value pairs
mappings = {
'port': r'^port\s+(\d+)',
'proto': r'^proto\s+(\w+)',
'dev': r'^dev\s+(\w+)',
'server_network': r'^server\s+([\d\.]+)',
'server_netmask': r'^server\s+[\d\.]+\s+([\d\.]+)',
'topology': r'^topology\s+(\w+)',
'cipher': r'^cipher\s+([\w\-]+)',
'data_ciphers': r'^data-ciphers\s+([\w\-:]+)',
'data_ciphers_fallback': r'^data-ciphers-fallback\s+([\w\-]+)',
'status_log': r'^status\s+(.+)',
'log_file': r'^log-append\s+(.+)',
'ipp_path': r'^ifconfig-pool-persist\s+(.+)',
'auth_algo': r'^auth\s+(\w+)',
'tun_mtu': r'^tun-mtu\s+(\d+)',
'mssfix': r'^mssfix\s+(\d+)'
}
for key, pattern in mappings.items():
match = re.search(pattern, content, re.MULTILINE)
if match:
config[key] = match.group(1)
# Boolean flags
config['client_to_client'] = bool(re.search(r'^client-to-client', content, re.MULTILINE))
# redirect-gateway is usually pushed
config['redirect_gateway'] = bool(re.search(r'push "redirect-gateway', content, re.MULTILINE))
config['crl_verify'] = bool(re.search(r'^crl-verify', content, re.MULTILINE))
# DNS
# push "dhcp-option DNS 8.8.8.8"
dns_matches = re.findall(r'push "dhcp-option DNS ([\d\.]+)"', content)
if dns_matches:
config['dns_servers'] = dns_matches
# Routes
# push "route 192.168.1.0 255.255.255.0"
route_matches = re.findall(r'push "route ([\d\.]+ [\d\.]+)"', content)
if route_matches:
config['routes'] = route_matches
return config
except Exception as e:
print(f"Error reading config: {e}")
return {}
def generate_server_config(self, params):
"""Generate server.conf from template"""
# Defaults
defaults = {
'port': 1194,
'proto': 'udp',
'server_network': '10.8.0.0',
'server_netmask': '255.255.255.0',
'topology': 'subnet',
'cipher': 'AES-256-GCM',
'auth_algo': 'SHA256',
'data_ciphers': 'AES-256-GCM:AES-128-GCM',
'data_ciphers_fallback': None,
'status_log': '/var/log/openvpn/openvpn-status.log',
'log_file': '/var/log/openvpn/openvpn.log',
'crl_verify': True,
'client_to_client': False,
'redirect_gateway': True,
'dns_servers': ['8.8.8.8', '8.8.4.4'],
'routes': [],
'tun_mtu': None,
'mssfix': None
}
# Merge params
ctx = {**defaults, **params}
try:
template = self.env.get_template('server.conf.j2')
output = template.render(ctx)
with open(self.server_conf_path, 'w') as f:
f.write(output)
return True, str(self.server_conf_path)
except Exception as e:
return False, str(e)
def generate_client_config(self, client_name, pki_path, server_config=None, extra_params=None):
"""Generate client .ovpn content
server_config: dict of server security/network settings
extra_params: dict of specific overrides (remote_host, port, proto)
"""
# Checks
pki = Path(pki_path)
ca_path = pki / "ca.crt"
cert_path = pki / "issued" / f"{client_name}.crt"
key_path = pki / "private" / f"{client_name}.key"
ta_path = pki / "ta.key"
if not (ca_path.exists() and cert_path.exists() and key_path.exists()):
return False, "Certificate files missing"
try:
# Read contents
ca = ca_path.read_text().strip()
cert = cert_path.read_text().strip()
# Cert file often contains text before -----BEGIN CERTIFICATE-----
if "-----BEGIN CERTIFICATE-----" in cert:
cert = cert[cert.find("-----BEGIN CERTIFICATE-----"):]
key = key_path.read_text().strip()
ta = ta_path.read_text().strip() if ta_path.exists() else None
ctx = {
'client_name': client_name,
'ca': ca,
'cert': cert,
'key': key,
'tls_auth': ta
}
# Merge server config if present
if server_config:
ctx.update(server_config)
# Merge extra params (host, port, proto) - takes precedence
if extra_params:
ctx.update(extra_params)
template = self.env.get_template('client.ovpn.j2')
output = template.render(ctx)
return True, output
except Exception as e:
return False, str(e)