112 lines
3.9 KiB
Python
112 lines
3.9 KiB
Python
import os
|
|
import stat
|
|
import subprocess
|
|
|
|
from .posix import PosixProcessProvider
|
|
from .provider import FirewallProvider, RouteProvider, TunnelPrepProvider
|
|
from .util import get_executable
|
|
|
|
|
|
class ProcfsProvider(PosixProcessProvider):
|
|
def pid2exe(self, pid):
|
|
try:
|
|
return os.readlink('/proc/%d/exe' % pid)
|
|
except (OSError, IOError):
|
|
return None
|
|
|
|
def ppid_of(self, pid=None):
|
|
if pid is None:
|
|
return os.getppid()
|
|
try:
|
|
return int(next(open('/proc/%d/stat' % pid)).split()[3])
|
|
except (OSError, ValueError, IOError):
|
|
return None
|
|
|
|
|
|
class Iproute2Provider(RouteProvider):
|
|
def __init__(self):
|
|
self.iproute = get_executable('/sbin/ip')
|
|
|
|
def _iproute(self, *args, **kwargs):
|
|
cl = [self.iproute]
|
|
cl.extend(str(v) for v in args if v is not None)
|
|
for k, v in kwargs.items():
|
|
if v is not None:
|
|
cl.extend((k, str(v)))
|
|
|
|
if args[:2] == ('route', 'get'):
|
|
output_start, keys = 1, ('via', 'dev', 'src', 'mtu')
|
|
elif args[:2] == ('link', 'show'):
|
|
output_start, keys = 3, ('state', 'mtu')
|
|
else:
|
|
output_start = None
|
|
|
|
if output_start is not None:
|
|
words = subprocess.check_output(cl, universal_newlines=True).split()
|
|
if args[:2] == ('route', 'get') and words[0] in ('broadcast', 'multicast', 'local', 'unreachable'):
|
|
output_start += 1
|
|
return {words[i]: words[i + 1] for i in range(output_start, len(words), 2) if words[i] in keys}
|
|
else:
|
|
subprocess.check_call(cl)
|
|
|
|
def add_route(self, destination, *, via=None, dev=None, src=None, mtu=None):
|
|
self._iproute('route', 'add', destination, via=via, dev=dev, src=src, mtu=mtu)
|
|
|
|
def replace_route(self, destination, *, via=None, dev=None, src=None, mtu=None):
|
|
self._iproute('route', 'replace', destination, via=via, dev=dev, src=src, mtu=mtu)
|
|
|
|
def remove_route(self, destination):
|
|
self._iproute('route', 'del', destination)
|
|
|
|
def get_route(self, destination):
|
|
r = self._iproute('route', 'get', destination)
|
|
# Ignore localhost or incomplete routes
|
|
if r.get('dev') == 'lo':
|
|
del r['dev']
|
|
if 'dev' in r or 'via' in r:
|
|
return r
|
|
|
|
def flush_cache(self):
|
|
self._iproute('route', 'flush', 'cache')
|
|
self._iproute('-6', 'route', 'flush', 'cache')
|
|
|
|
def get_link_info(self, device):
|
|
return self._iproute('link', 'show', device)
|
|
|
|
def set_link_info(self, device, state, mtu=None):
|
|
self._iproute('link', 'set', state, dev=device, mtu=mtu)
|
|
|
|
def add_address(self, device, address):
|
|
flag = '-6' if address.version == 6 else '-4'
|
|
self._iproute(flag, 'address', 'add', address, dev=device)
|
|
|
|
|
|
class IptablesProvider(FirewallProvider):
|
|
def __init__(self):
|
|
self.iptables = get_executable('/sbin/iptables')
|
|
|
|
def _iptables(self, *args):
|
|
cl = [self.iptables]
|
|
cl.extend(args)
|
|
subprocess.check_call(cl)
|
|
|
|
def configure_firewall(self, device):
|
|
self._iptables('-A', 'INPUT', '-i', device, '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT')
|
|
self._iptables('-A', 'INPUT', '-i', device, '-j', 'DROP')
|
|
|
|
def deconfigure_firewall(self, device):
|
|
self._iptables('-D', 'INPUT', '-i', device, '-j', 'DROP')
|
|
self._iptables('-D', 'INPUT', '-i', device, '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT')
|
|
|
|
|
|
class CheckTunDevProvider(TunnelPrepProvider):
|
|
def create_tunnel(self):
|
|
node = '/dev/net/tun'
|
|
if not os.path.exists(node):
|
|
os.makedirs(os.path.dirname(node), exist_ok=True)
|
|
os.mknod(node, mode=0o640 | stat.S_IFCHR, device=os.makedev(10, 200))
|
|
|
|
def prepare_tunnel(self):
|
|
if not os.access('/dev/net/tun', os.R_OK | os.W_OK):
|
|
raise OSError("can't read and write /dev/net/tun")
|