Skip to content

Commit

Permalink
#179 - Improved logic around handling changing of network address of …
Browse files Browse the repository at this point in the history
…the VPN. Also server ip address is also added to AllowedIPs if strict Allowed IPs is enabled.
  • Loading branch information
vijaygill committed Dec 13, 2024
1 parent 40872d4 commit 5fb3761
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 44 deletions.
54 changes: 28 additions & 26 deletions src/api_project/api_app/db_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def at_end_migrate(
ip_address = get_next_free_ip_address(
network_address=IP_ADDRESS_SERVER_DEFAULT,
existing_ip_addresses=[],
for_server=True,
)
server_configuration = (
server_configuration_existing[0]
Expand All @@ -78,8 +79,7 @@ def at_end_migrate(
private_key=private_key,
)
)
if not server_configuration.ip_address:
server_configuration.ip_address = ip_address
server_configuration.ip_address = ip_address
if not server_configuration.public_key:
server_configuration.public_key = public_key
if not server_configuration.ip_address:
Expand All @@ -88,28 +88,30 @@ def at_end_migrate(

server_configuration = ServerConfiguration.objects.all()[0]
Peer = apps.get_model("api_app", "Peer")
for peer_name, description in SAMPLE_PEERS:
peer_existing = Peer.objects.filter(name=peer_name)
if peer_existing:
continue
peers = Peer.objects.all()
existing_ip_addresses = []
if peers:
existing_ip_addresses = (
[p.ip_address for p in peers if p.ip_address] if peers else []
peers_existing = Peer.objects.all()
if not peers_existing:
for peer_name, description in SAMPLE_PEERS:
peer_existing = Peer.objects.filter(name=peer_name)
if peer_existing:
continue
peers = Peer.objects.all()
existing_ip_addresses = []
if peers:
existing_ip_addresses = (
[p.ip_address for p in peers if p.ip_address] if peers else []
)
existing_ip_addresses += [server_configuration.ip_address]
existing_ip_addresses = [ip for ip in existing_ip_addresses if ip]
ip_address = get_next_free_ip_address(
network_address=server_configuration.network_address,
existing_ip_addresses=existing_ip_addresses,
)
existing_ip_addresses += [server_configuration.ip_address]
existing_ip_addresses = [ip for ip in existing_ip_addresses if ip]
ip_address = get_next_free_ip_address(
network_address=server_configuration.network_address,
existing_ip_addresses=existing_ip_addresses,
)
public_key, private_key = generate_keys()
peer = Peer(
name=peer_name,
description=description,
public_key=public_key,
private_key=private_key,
ip_address=ip_address,
)
peer.save()
public_key, private_key = generate_keys()
peer = Peer(
name=peer_name,
description=description,
public_key=public_key,
private_key=private_key,
ip_address=ip_address,
)
peer.save()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.4 on 2024-12-13 17:03

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api_app', '0007_serverconfiguration_strict_allowed_ips_in_peer_config'),
]

operations = [
migrations.AlterField(
model_name='serverconfiguration',
name='last_changed_datetime',
field=models.DateTimeField(),
),
]
53 changes: 49 additions & 4 deletions src/api_project/api_app/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import datetime
import ipaddress

from django.core.exceptions import ValidationError
from django.db import models

from .util import (
logger,
generate_keys,
get_next_free_ip_address,
get_target_ip_address_parts,
Expand Down Expand Up @@ -191,9 +193,23 @@ class ServerConfiguration(models.Model):
peer_default_port = models.IntegerField()
allow_check_updates = models.BooleanField(null=True, default=False)
strict_allowed_ips_in_peer_config = models.BooleanField(null=True, default=False)
last_changed_datetime = models.DateTimeField(
auto_now=True,
)
last_changed_datetime = models.DateTimeField()

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
saved_state_fields = [
"host_name_external",
"port_external",
"port_internal",
"upstream_dns_ip_address",
"network_address",
"ip_address",
"strict_allowed_ips_in_peer_config",
]
saved_state = {}
for saved_state_field in saved_state_fields:
saved_state[saved_state_field] = getattr(self, saved_state_field)
self.__saved_state = saved_state

def __str__(self):
return f"{self.host_name_external} - {self.port_external}"
Expand All @@ -203,13 +219,42 @@ def save(self, force_insert=False, force_update=False, **kwargs):
public_key, private_key = generate_keys()
self.public_key = public_key
self.private_key = private_key
if self.network_address and (not self.ip_address):

saved_state = self.__saved_state
fields_changed = []
fields_changed_all = "*all*"
if saved_state:
for saved_state_field in saved_state.keys():
if saved_state[saved_state_field] != getattr(self, saved_state_field):
fields_changed += [saved_state_field]
else:
fields_changed = [fields_changed_all]

logger.debug(f"ServerConfiguration: fields_changed: {fields_changed}")

if (
("network_address" in fields_changed)
or (fields_changed_all in fields_changed)
and self.network_address
):
peers = Peer.objects.all()
existing_ip_addresses = (
[p.ip_address for p in peers if p.ip_address] if peers else []
)
self.ip_address = get_next_free_ip_address(
network_address=self.network_address,
existing_ip_addresses=existing_ip_addresses,
for_server=True,
)

if (not self.last_changed_datetime) or fields_changed:
self.last_changed_datetime = datetime.datetime.now(datetime.timezone.utc)

super().save(force_insert, force_update)
if ("network_address" in fields_changed) or (
fields_changed_all in fields_changed
):
peers = Peer.objects.all()
for peer in peers:
peer.ip_address = None # this will force updating of IP address again
peer.save()
13 changes: 8 additions & 5 deletions src/api_project/api_app/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,21 @@ def get_target_ip_address_parts(value):
return res


def get_next_free_ip_address(network_address, existing_ip_addresses):
def get_next_free_ip_address(network_address, existing_ip_addresses, for_server=False):
sc_intf = ipaddress.ip_interface(network_address)
ip_address_pool = [x for x in sc_intf.network.hosts()]
ip_address_pool.sort()
ip_address_pool = [str(x) for x in ip_address_pool]
if existing_ip_addresses:
ip_addresses_to_exclude = [
ipaddress.ip_interface(p).ip
for p in existing_ip_addresses
str(ipaddress.ip_interface(p).ip) for p in existing_ip_addresses
]
ip_address_pool = [
x for x in ip_address_pool if x not in ip_addresses_to_exclude
]
res = ip_address_pool[0]
logger.debug(f"existing_ip_addresses: {existing_ip_addresses}")
res = ip_address_pool[0] if for_server else ip_address_pool[1]
logger.debug(f"ip_address_pool : {ip_address_pool}")
logger.debug(f"existing_ip_addresses : {existing_ip_addresses}")
logger.debug(f"for_server : {for_server}")
logger.debug(f"get_next_free_ip_address: {res}")
return res
13 changes: 6 additions & 7 deletions src/api_project/api_app/wireguardhelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
)
from .util import (
ensure_folder_exists_for_file,
get_next_free_ip_address,
get_target_ip_address_parts,
is_network_address,
)
Expand Down Expand Up @@ -113,13 +112,13 @@ def get_wireguard_configurations_for_peer(
# if serverConfiguration.upstream_dns_ip_address:
# allowed_ips += [serverConfiguration.upstream_dns_ip_address]

# # add VPN's own network also.
# if serverConfiguration.network_address:
# allowed_ips += [serverConfiguration.network_address]
# add VPN server's ip address also.
if serverConfiguration.network_address:
allowed_ips += [serverConfiguration.ip_address]

# if 0.0.0.0/0 is in the list, no need to have anything else.
if IP_ADDRESS_INTERNET in allowed_ips:
allowed_ips = [IP_ADDRESS_INTERNET]
# if 0.0.0.0/0 is in the list, no need to have anything else.
if IP_ADDRESS_INTERNET in allowed_ips:
allowed_ips = [IP_ADDRESS_INTERNET]

allowed_ips = list(set(allowed_ips))

Expand Down
2 changes: 1 addition & 1 deletion src/clientapp/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<p-toast></p-toast>
<div class="container">
<div class="item item-header">
<mat-card appearance="outlined">
Expand Down Expand Up @@ -29,7 +30,6 @@ <h6>Run &amp; manage your WireGuard &trade; VPN in one UI.</h6>
</ng-template>
</p-messages>
</div>
<p-messages />
</div>
</div>
<div class="item item-main" style="display: flex;flex-direction: row;">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<tr>
<td><label for="ipAddress">Network Address</label></td>
<td><input pInputText id="networkAddress" [(ngModel)]="editItem.network_address"
pTooltip="Network address of the VPN." tooltipPosition="top" pAutoFocus
pTooltip="Network address of the VPN. Changing this will require reassignment of IP addresses of all peers and sending out new configuration to each peer." tooltipPosition="top" pAutoFocus
[autofocus]="true" />
<app-validation-errors-display field="network_address"
[validationResult]="validationResult">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class ManageServerConfigurationComponent {
}
},
complete: () => {
this.refreshData()
},
});
}
Expand Down

0 comments on commit 5fb3761

Please sign in to comment.