Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IPv6 compatibility to the DNS handling #30

Merged
merged 2 commits into from
Jan 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions vpn_slice/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def do_post_connect(env, args):
for host in args.hosts:
ips = providers.dns.lookup_host(
host, dns_servers=env.dns, search_domains=args.domain,
bind_address=env.myaddr)
bind_addresses=env.myaddrs)
if ips is None:
print("WARNING: Lookup for %s on VPN DNS servers failed." % host, file=stderr)
else:
Expand Down Expand Up @@ -255,7 +255,7 @@ def do_post_connect(env, args):
shuffle(dns)
if args.verbose > 1:
print("Issuing DNS lookup of %s to prevent idle timeout..." % dummy, file=stderr)
providers.dns.lookup_host(dummy, dns_servers=dns, bind_address=env.myaddr)
providers.dns.lookup_host(dummy, dns_servers=dns, bind_addresses=env.myaddrs)

########################################

Expand All @@ -273,11 +273,11 @@ def do_post_connect(env, args):
('netmask','INTERNAL_IP4_NETMASK',IPv4Address), # a.b.c.d
('netmasklen','INTERNAL_IP4_NETMASKLEN',int),
('network','INTERNAL_IP4_NETADDR',IPv4Address), # a.b.c.d
('dns','INTERNAL_IP4_DNS',lambda x: [IPv4Address(x) for x in x.split()],[]),
('dns','INTERNAL_IP4_DNS',lambda x: [ip_address(x) for x in x.split()],[]),
('nbns','INTERNAL_IP4_NBNS',lambda x: [IPv4Address(x) for x in x.split()],[]),
('myaddr6','INTERNAL_IP6_ADDRESS',IPv6Interface), # x:y::z or x:y::z/p
('netmask6','INTERNAL_IP6_NETMASK',IPv6Interface), # x:y:z:: or x:y::z/p
('dns6','INTERNAL_IP6_DNS',lambda x: [IPv6Address(x) for x in x.split()],[]),
('dns6','INTERNAL_IP6_DNS',lambda x: [ip_address(x) for x in x.split()],[]),
('nsplitinc','CISCO_SPLIT_INC',int,0),
('nsplitexc','CISCO_SPLIT_EXC',int,0),
('nsplitinc6','CISCO_IPV6_SPLIT_INC',int,0),
Expand Down Expand Up @@ -311,6 +311,12 @@ def parse_env(environ=os.environ):
else:
env.network6 = None

env['myaddrs'] = []
if env.myaddr:
env.myaddrs.append(env.myaddr)
if env.myaddr6:
env.myaddrs.append(env.myaddr6)

# Handle splits
env.splitinc = []
env.splitexc = []
Expand Down
37 changes: 31 additions & 6 deletions vpn_slice/posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,47 @@ class DigProvider(DNSProvider):
def __init__(self):
self.dig = get_executable('/usr/bin/dig')

def lookup_host(self, hostname, dns_servers, *, bind_address=None, search_domains=()):
def lookup_host(self, hostname, dns_servers, bind_addresses, *, search_domains=()):
cl = [self.dig, '+short', '+noedns']
if bind_address:
cl.extend(('-b', str(bind_address)))
cl.extend('@{!s}'.format(s) for s in dns_servers)
some_cls = []

# We only do lookups for protocols of which we have bind addresses
if bind_addresses == None or len(bind_addresses) == 0:
return None

ipv4_lookup = False
ipv6_lookup = False

for bind in bind_addresses:
if bind.version == 4:
ipv4_lookup = True
if bind.version == 6:
ipv6_lookup = True

bind_cl = cl + ['-b', str(bind)]
bind_cl.extend('@{!s}'.format(dns) for dns in dns_servers if dns.version == bind.version)
some_cls.append(bind_cl)

field_requests = []
if ipv4_lookup:
field_requests.extend([hostname, 'A'])
if ipv6_lookup:
field_requests.extend([hostname, 'AAAA'])

# 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:
all_cls = (cl + ['+domain={!s}'.format(sd), hostname] for sd in search_domains)
for cl in some_cls:
all_cls.extend(cl + ['+domain={!s}'.format(sd)] + field_requests for sd in search_domains)
else:
all_cls = (cl + [hostname],)
for cl in some_cls:
all_cls.extend(cl + field_requests)
result = set()
for cl in all_cls:
print(cl)
p = subprocess.Popen(cl, stdout=subprocess.PIPE)
output, _ = p.communicate()
if p.returncode != 0:
Expand Down
2 changes: 1 addition & 1 deletion vpn_slice/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def deconfigure_firewall(self, device):

class DNSProvider(metaclass=ABCMeta):
@abstractmethod
def lookup_host(self, hostname, dns_servers, *, bind_address=None, search_domains=()):
def lookup_host(self, hostname, dns_servers, *, bind_addresses=None, search_domains=()):
"""Look up the address of a host."""


Expand Down