Commit b496108c authored by Xavier Thompson's avatar Xavier Thompson

WIP remember to add tap to interface

parent d89dafbd
......@@ -373,7 +373,7 @@ class Partition(object):
if ipv6_range:
self.ipv6_range = ipaddress.IPv6Network(ipv6_range, strict=False)
elif conf.ipv6_range:
self.ipv6_range = interface.getPartitionIPv6Range(index)
self.ipv6_range = interface.getIPv6Range(index)
# Tap
tap = options['network_interface']
if tap or conf.create_tap:
......@@ -468,7 +468,7 @@ class Tap(object):
interface = computer.interface
options = definition[name]
self.name = name
# Tap IPv4: tap-to-host gateway and host-to-tap address
# IPv4 (gateway=host and address=application)
ipv4_gateway = options['ipv4_gateway']
ipv4_address = options['ipv4_address']
if bool(ipv4_gateway) != bool(ipv4_address):
......@@ -482,23 +482,21 @@ class Tap(object):
elif interface.tap_ipv4_network:
self.ipv4_gateway = interface.getTapIPv4Gateway(index)
self.ipv4_address = interface.getTapIPv4Range(index)
# Tap IPv6: host-to-tap gateway and tap-to-host address
# IPv6 (gateway=application and address=host)
ipv6_gateway = options['ipv6_gateway']
ipv6_address = options['ipv6_address']
if not ipv6_gateway and ipv6_address:
if bool(ipv6_gateway) != bool(ipv6_address):
conf.wrong(
"Options %r for tap %s must not be provided without option %r",
"Options %r and %r for tap %s must either both be provided or neither",
'ipv6_address', 'ipv6_gateway', name
)
if ipv6_gateway:
self.ipv6_gateway = ipv6_gateway = ipaddress.IPv6Interface(ipv6_gateway)
if ipv6_address:
self.ipv6_gateway = ipaddress.IPv6Interface(ipv6_gateway)
self.ipv6_address = ipaddress.IPv6Interface(ipv6_address)
else:
self.ipv6_address = addressFromNetwork(ipv6_gateway.network, -1)
elif conf.tap_ipv6:
self.ipv6_gateway = ipv6_gateway = interface.getTapIPv6Range(index)
self.ipv6_address = addressFromNetwork(ipv6_gateway.network, -1)
ipv6_network = interface.getIPv6Range(index, 'tap')
self.ipv6_gateway = addressFromNetwork(ipv6_network, 1)
self.ipv6_address = addressFromNetwork(ipv6_network, -1)
def format(self, interface, user):
conf = interface.conf
......@@ -506,6 +504,9 @@ class Tap(object):
self.ensureTap(user, conf)
# Create/ensure IPv4 routes
self.ensureIPv4Routes(conf)
# Add host IPV6 address to interface
if self.ipv6_address:
interface.addIPv6(self.ipv6_address)
# Create/ensure IPv6 routes
self.ensureIPv6Routes(conf)
......@@ -570,6 +571,100 @@ class Tap(object):
call(['ip', '-6', 'route', 'add', network, 'dev', tap, 'via', cidr])
class Tun(object):
name : str
ipv4_address : ipaddress.IPv4Interface = None
ipv6_address : ipaddress.IPv6Interface = None
def __init__(self, name, index, computer, definition):
conf = computer.conf
interface = computer.interface
options = definition[name]
self.name = name
# IPv4
ipv4_address = options['ipv4_address']
if ipv4_address:
self.ipv4_address = ipaddress.IPv4Interface(ipv4_address)
else:
self.ipv4_address = interface.getTunIPv4Range(index)
# IPv6
ipv6_address = options['ipv6_address']
if ipv6_address:
self.ipv6_address = ipaddress.IPv6Interface(ipv6_address)
elif conf.tap_ipv6:
ipv6_network = interface.getIPv6Range(index, 'tun')
self.ipv6_address = addressFromNetwork(ipv6_network, -1)
def format(self, interface, user):
conf = interface.conf
# Create/ensure tun interface
self.ensureTun(user, conf)
# Create/ensure IPv4 routes
self.ensureIPv4Routes(conf)
# Create/ensure IPv6 routes
self.ensureIPv6Routes(conf)
def ensureTun(self, user, conf):
tun = self.name
user = user.name
check_file = '/sys/devices/virtual/net/%s/owner' % tun
if os.path.exists(check_file):
with open(check_file) as f:
owner_id = f.read().strip()
try:
owner_id = int(owner_id)
except ValueError:
owner_id = pwd.getpwnam(owner_id).pw_uid
user_id = pwd.getpwnam(user).pw_uid
if owner_id != user_id:
conf.abort(
"Wrong owner of tun %s, expected %s (%s) got %s",
tun, user_id, user, owner_id
)
else:
call(['ip', 'tuntap', 'add', 'dev', tun, 'mode', 'tun', 'user', user])
call(['ip', 'link', 'set', tun, 'up'])
def ensureIPv4Routes(self, conf):
tun = self.name
ipv4 = self.ipv4_address
if ipv4:
cidr = str(ipv4)
code, out = call(['ip', 'route', 'show', cidr], throw=False)
if code != 0 or cidr not in out or tun not in out:
call(['ip', 'route', 'add', cidr, 'dev', tun])
if ipv4.network.prefixlen < 32:
network = str(ipv4.network)
code, out = call(['ip', 'route', 'show', network], throw=False)
if code != 0 or 'dev ' + tun not in out:
call(['ip', 'route', 'add', network, 'dev', tun, 'via', cidr])
elif 'via ' + cidr not in out:
conf.abort(
"Route to network %s (%s) exists but is not via %s",
network, tap, cidr
)
def ensureIPv6Routes(self, conf):
tap = self.name
ipv6 = self.ipv6_gateway
if ipv6:
cidr = str(ipv6)
code, out = call(['ip', '-6', 'route', 'show', cidr], throw=False)
if code != 0 or cidr not in out or tap not in out:
call(['ip', '-6', 'route', 'add', cidr, 'dev', tap])
network = str(ipv6.network)
code, out = call(['ip', '-6', 'route', 'show', network], throw=False)
if code != 0 or 'dev ' + tap not in out:
call(['ip', '-6', 'route', 'add', network, 'dev', tap, 'via', cidr])
elif 'via ' + cidr not in out:
conf.warn(
"Route to network %s (%s) exists but is not via %s, fixing it",
network, tap, cidr
)
call(['ip', '-6', 'route', 'del', network, 'dev', tap])
call(['ip', '-6', 'route', 'add', network, 'dev', tap, 'via', cidr])
class Interface(object):
ipv4_interface : str
ipv6_interface : str
......@@ -674,20 +769,14 @@ class Interface(object):
def getPartitionIPv6Addr(self, index):
return addressFromNetwork(self.ipv6_network, index + 2)
def getPartitionIPv6Range(self, index):
def getIPv6Range(self, index, mode='partition'):
k = ('partition', 'tap', 'tun').index(mode) + 1
network = self.ipv6_network
prefixlen = network.prefixlen + 16
bits = 128 - network.prefixlen
addr = network[(1 << (bits - 2)) + (index << (128 - prefixlen))]
addr = network[(k << (bits - 2)) + (index << (128 - prefixlen))]
return ipaddress.IPv6Network((addr, prefixlen))
def getTapIPv6Range(self, index):
network = self.ipv6_network
prefixlen = network.prefixlen + 16
bits = 128 - network.prefixlen
addr = network[(2 << (bits - 2)) + (index << (128 - prefixlen)) + 1]
return ipaddress.IPv6Interface((addr, prefixlen))
def enableIPv6NonLocalBind(self):
call(['sysctl', 'net.ipv6.ip_nonlocal_bind=1'])
network = str(self.ipv6_network)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment