Source code for snare.net.openvpn

# coding: utf-8
"""
OpenVPN functions.
"""
import fcntl
import os
import subprocess
import logging

logger = logging.getLogger(__name__)

[docs]class OpenVpnError(Exception): def __init__(self, instance, msg): self.instance = instance super().__init__(msg)
class OpenVpn: exe = 'openvpn' initmsg = b'Initialization Sequence Completed' def __init__(self, **kwargs): if 'daemonize' in kwargs: warnings.warn("This class will not be able to close a daemonized tunnel", warnings.Warning) self.options = kwargs self.initialized = False self._process = None def args(self): result = [] for name, value in self.options.items(): result.append('--{:s}'.format(name.replace('_', '-'))) # None is special to indicate the option have no value if value is not None: result.append(str(value)) return result def check(self): if self._process is not None: self._process.poll() code = self._process.returncode if code is not None and code != 0: raise OpenVpnError(self, "`openvpn {:s}` exited with error code: {:d}".format(" ".join(self.args()), code)) def running(self): return self._process is not None and self._process.poll() is None @staticmethod def maketun(): os.makedirs('/dev/net', exist_ok=True) subprocess.run(['mknod', '/dev/net/tun', 'c', '10', '200'], check=True) def connect(self): if not os.path.exists('/dev/net/tun'): self.maketun() if not self.running(): self.initialized = False self._process = subprocess.Popen( [self.exe] + self.args(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) self.check() def disconnect(self): if self.running(): self._process.terminate() try: os.waitpid(self._process.pid, 0) except ChildProcessError: # process is already dead pass def waitforinit(self): if not self.initialized: for line in self._process.stdout: logger.debug("openvpn: %s", line.decode('utf-8').strip()) if self.initmsg in line: self.initialized = True break else: self.check() raise OpenVpnError(self, "OpenVPN exited with code 0, but did not display init msg") def __enter__(self): self.connect() return self def __exit__(self, *args, **kwargs): self.disconnect()