vpn: assign an IPv6 subnet instead of a single address
We are limited by the size of IPv4 pool (/18), so why not give everyone an IPv4-internetful of IPv6 addresses.
This commit is contained in:
parent
85714f83b9
commit
a8abf580f9
|
@ -108,7 +108,7 @@ def save_config():
|
||||||
wireguard = db.read('wireguard')
|
wireguard = db.read('wireguard')
|
||||||
for ip, key in wireguard.items():
|
for ip, key in wireguard.items():
|
||||||
ip4 = [f'{ip}/32']
|
ip4 = [f'{ip}/32']
|
||||||
ip6 = [f'{key["ip6"]}/128'] if key.get('ip6') else None
|
ip6 = [f'{key["ip6"]}'] if key.get('ip6') else None
|
||||||
for network in user_networks.get(key.get('user', ''), ()):
|
for network in user_networks.get(key.get('user', ''), ()):
|
||||||
if group := network_group(network):
|
if group := network_group(network):
|
||||||
ipset_add(ipsets, group, ip4, ip6)
|
ipset_add(ipsets, group, ip4, ip6)
|
||||||
|
|
17
web/vpn.py
17
web/vpn.py
|
@ -29,6 +29,19 @@ def list():
|
||||||
@blueprint.route('/new', methods=('POST',))
|
@blueprint.route('/new', methods=('POST',))
|
||||||
@flask_login.login_required
|
@flask_login.login_required
|
||||||
def new():
|
def new():
|
||||||
|
# Each key is associated with a new IPv4 address from the pool settings['wg_net'].
|
||||||
|
# Each key gets an IPv6 subnet depending on the amount of surplus addresses available.
|
||||||
|
# For wg_net 10.10.0.0/18 and wg_net6 1234:5678:90ab:cdef::/64,
|
||||||
|
# the key for 10.10.0.10/32 would get 1234:5678:90ab:cdef:a::/80.
|
||||||
|
def ipv4to6(net4, ip4, net6):
|
||||||
|
# Calculate the address and prefix length for the assigned IPv6 network.
|
||||||
|
len4 = (net4.max_prefixlen - net4.prefixlen)
|
||||||
|
len6 = (net6.max_prefixlen - net6.prefixlen)
|
||||||
|
# Make sure the network address ends at a colon. Wastes some addresses but IPv6.
|
||||||
|
assigned = (len6 - len4) - (len6 - len4) % 16
|
||||||
|
ip6 = (net6.network_address + (index<<assigned)).compressed
|
||||||
|
return ip6 + '/' + str(net6.max_prefixlen - assigned)
|
||||||
|
|
||||||
pubkey = flask.request.json.get('pubkey', '')
|
pubkey = flask.request.json.get('pubkey', '')
|
||||||
if not re.match(wgkey_regex, pubkey):
|
if not re.match(wgkey_regex, pubkey):
|
||||||
return flask.Response('invalid key', status=400, mimetype='text/plain')
|
return flask.Response('invalid key', status=400, mimetype='text/plain')
|
||||||
|
@ -38,14 +51,14 @@ def new():
|
||||||
text=True, capture_output=True, shell=True).stdout.strip()
|
text=True, capture_output=True, shell=True).stdout.strip()
|
||||||
|
|
||||||
host = ipaddress.ip_interface(settings.get('wg_net', '10.0.0.1/24'))
|
host = ipaddress.ip_interface(settings.get('wg_net', '10.0.0.1/24'))
|
||||||
|
ip6 = None
|
||||||
with db.locked():
|
with db.locked():
|
||||||
# Find a free address for the new key.
|
# Find a free address for the new key.
|
||||||
keys = db.read('wireguard')
|
keys = db.read('wireguard')
|
||||||
ip6 = None
|
|
||||||
for index, ip in enumerate(host.network.hosts(), start=1):
|
for index, ip in enumerate(host.network.hosts(), start=1):
|
||||||
if ip != host.ip and str(ip) not in keys:
|
if ip != host.ip and str(ip) not in keys:
|
||||||
if wg_net6 := settings.get('wg_net6'):
|
if wg_net6 := settings.get('wg_net6'):
|
||||||
ip6 = (ipaddress.ip_interface(wg_net6) + index).ip
|
ip6 = ipv4to6(host.network, ip, ipaddress.ip_interface(wg_net6).network)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return flask.Response('no more available IP addresses', status=500, mimetype='text/plain')
|
return flask.Response('no more available IP addresses', status=500, mimetype='text/plain')
|
||||||
|
|
Loading…
Reference in a new issue