änderungen für mac
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import fcntl
|
||||
import os
|
||||
import subprocess
|
||||
from ipaddress import ip_address
|
||||
from signal import SIGTERM
|
||||
|
||||
from .provider import DNSProvider, HostsProvider, ProcessProvider
|
||||
from .util import get_executable
|
||||
|
||||
|
||||
class DigProvider(DNSProvider):
|
||||
def __init__(self):
|
||||
self.dig = get_executable('/usr/bin/dig')
|
||||
self.base_cl = [self.dig, '+short', '+noedns']
|
||||
|
||||
def lookup_host(self, hostname, keep_going=True):
|
||||
dns_servers = self.dns_servers
|
||||
bind_addresses = self.bind_addresses
|
||||
search_domains = self.search_domains
|
||||
|
||||
if not bind_addresses:
|
||||
some_cls = [self.base_cl + ['@{!s}'.format(dns) for dns in dns_servers]]
|
||||
field_requests = [hostname, 'A', hostname, 'AAAA']
|
||||
else:
|
||||
some_cls = []
|
||||
field_requests = []
|
||||
for bind in bind_addresses:
|
||||
# We only do lookups for protocols of which we have bind addresses.
|
||||
# (For example, if we have only an IPv4 bind address, we don't lookup AAAA/IPv6
|
||||
# DNS records because we won't be able to route traffic to them.)
|
||||
field_requests.extend([hostname, ('AAAA' if bind.version == 6 else 'A')])
|
||||
|
||||
# We can only do a lookup via DNS-over-IPv[X] if we have an IPv[X] address to bind to.
|
||||
matching_dns = ['@{!s}'.format(dns) for dns in dns_servers if dns.version == bind.version]
|
||||
if matching_dns:
|
||||
some_cls.append(self.base_cl + ['-b', str(bind)] + matching_dns)
|
||||
|
||||
# N.B.: dig does not correctly handle the specification of multiple
|
||||
# +domain arguments, discarding all but the last one. Therefore
|
||||
# we need to run it multiple times and combine the results
|
||||
# if multiple search_domains are specified.
|
||||
all_cls = []
|
||||
if search_domains:
|
||||
for cl in some_cls:
|
||||
all_cls.extend(cl + ['+domain={!s}'.format(sd)] + field_requests for sd in search_domains)
|
||||
else:
|
||||
for cl in some_cls:
|
||||
all_cls.extend([cl + field_requests])
|
||||
|
||||
# actually fetch results
|
||||
result = set()
|
||||
for cl in all_cls:
|
||||
p = subprocess.Popen(cl, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
||||
output, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise subprocess.CalledProcessError(p.returncode, cl, output=output, stderr=stderr)
|
||||
for line in output.splitlines():
|
||||
try:
|
||||
result.add(ip_address(line.strip()))
|
||||
except ValueError:
|
||||
# dig sometimes returns extra domain names instead of IP addresses
|
||||
pass
|
||||
if result and not keep_going:
|
||||
return result
|
||||
|
||||
return result or None
|
||||
|
||||
|
||||
class HostsFileProvider(HostsProvider):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
if not os.access(path, os.R_OK | os.W_OK):
|
||||
raise OSError('Cannot read/write {}'.format(path))
|
||||
|
||||
def write_hosts(self, host_map, name):
|
||||
tag = 'vpn-slice-{} AUTOCREATED'.format(name)
|
||||
with open(self.path, 'r+') as hostf:
|
||||
fcntl.flock(hostf, fcntl.LOCK_EX) # POSIX only, obviously
|
||||
lines = hostf.readlines()
|
||||
keeplines = [l for l in lines if not l.endswith('# %s\n' % tag)]
|
||||
hostf.seek(0, 0)
|
||||
hostf.writelines(keeplines)
|
||||
for ip, names in host_map:
|
||||
print('%s %s\t\t# %s' % (ip, ' '.join(names), tag), file=hostf)
|
||||
hostf.truncate()
|
||||
return len(host_map) or len(lines) - len(keeplines)
|
||||
|
||||
|
||||
class PosixHostsFileProvider(HostsFileProvider):
|
||||
def __init__(self):
|
||||
super().__init__('/etc/hosts')
|
||||
|
||||
|
||||
class PosixProcessProvider(ProcessProvider):
|
||||
def kill(self, pid, signal=SIGTERM):
|
||||
os.kill(pid, signal)
|
||||
|
||||
def pid(self):
|
||||
return os.getpid()
|
||||
|
||||
def is_alive(self, pid):
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
return True
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
Reference in New Issue
Block a user