From 32931dfd1660fa0e8ffd90c47922751f45048540 Mon Sep 17 00:00:00 2001
From: Eduardo Silva
+
+
+
+ {{ ip_address}}
+
+
+
+
+
+ {% if ip_address.priority == 0 %}
+ Main ip address
+ {% else %}
+ Priority: {{ ip_address.priority }}
+ {% endif %}
+
+ default route
+
+ {% if ip_address.priority == 0 %}
+ Main ip address
+ {% else %}
+ Priority: {{ ip_address.priority }}
+ {% endif %}
+
- Priority: {{ ip_address.priority }}
-
Upcoming Enhancements
-
diff --git a/templates/wireguard/wireguard_manage_peer.html b/templates/wireguard/wireguard_manage_peer.html
index aa364ac..7ace359 100644
--- a/templates/wireguard/wireguard_manage_peer.html
+++ b/templates/wireguard/wireguard_manage_peer.html
@@ -47,30 +47,91 @@
Endpoints:
Allowed IPs:
- {% for address in peer.peerallowedip_set.all %}{% if address.priority == 0 %}
- {% if address.missing_from_wireguard %}
- {{ address }}
- {% else %}
- {{ address }}
- {% endif %}
- {% endif %}{% endfor %}
-
- {% for address in peer.peerallowedip_set.all %}{% if address.priority >= 1 %}
- {% if address.missing_from_wireguard %}
- {{ address }}
- {% else %}
- {{ address }}
- {% endif %}
- {% endif %}{% endfor %}
+ {% for address in peer.peerallowedip_set.all %}
+ {% if address.priority == 0 and address.config_file == 'server' %}{{ address }}{% endif %}
+ {% endfor %}
+ {% for address in peer.peerallowedip_set.all %}
+ {% if address.priority >= 1 and address.config_file == 'server' %}{{ address }}{% endif %}
+ {% endfor %}
{% for address in peer.peerallowedip_set.all %}{% if address.priority == 0 %} - {% if address.missing_from_wireguard %} - {{ address }} - {% else %} - {{ address }} - {% endif %} - {% endif %}{% endfor %} - - {% for address in peer.peerallowedip_set.all %}{% if address.priority >= 1 %} - {% if address.missing_from_wireguard %} - {{ address }} - {% else %} - {{ address }} - {% endif %} - {% endif %}{% endfor %} -
- {% endcomment %} - diff --git a/wireguard/migrations/0020_peerallowedip_config_file.py b/wireguard/migrations/0020_peerallowedip_config_file.py new file mode 100644 index 0000000..1c35f7e --- /dev/null +++ b/wireguard/migrations/0020_peerallowedip_config_file.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-03-08 18:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wireguard', '0019_alter_wireguardinstance_legacy_firewall'), + ] + + operations = [ + migrations.AddField( + model_name='peerallowedip', + name='config_file', + field=models.CharField(choices=[('server', 'Server Config'), ('client', 'Client config')], default='server', max_length=6), + ), + ] diff --git a/wireguard/migrations/0021_remove_peerallowedip_missing_from_wireguard.py b/wireguard/migrations/0021_remove_peerallowedip_missing_from_wireguard.py new file mode 100644 index 0000000..03bcff0 --- /dev/null +++ b/wireguard/migrations/0021_remove_peerallowedip_missing_from_wireguard.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.2 on 2024-03-08 18:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wireguard', '0020_peerallowedip_config_file'), + ] + + operations = [ + migrations.RemoveField( + model_name='peerallowedip', + name='missing_from_wireguard', + ), + ] diff --git a/wireguard/models.py b/wireguard/models.py index fb4a579..447c686 100644 --- a/wireguard/models.py +++ b/wireguard/models.py @@ -111,7 +111,7 @@ class PeerAllowedIP(models.Model): priority = models.PositiveBigIntegerField(default=1) allowed_ip = models.GenericIPAddressField(protocol='IPv4') netmask = models.IntegerField(default=32, choices=NETMASK_CHOICES) - missing_from_wireguard = models.BooleanField(default=False) + config_file = models.CharField(max_length=6, choices=(('server', 'Server Config'), ('client', 'Client config')), default='server') created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) diff --git a/wireguard_peer/forms.py b/wireguard_peer/forms.py index 1213ac2..808ce50 100644 --- a/wireguard_peer/forms.py +++ b/wireguard_peer/forms.py @@ -18,8 +18,10 @@ class PeerForm(forms.ModelForm): class PeerAllowedIPForm(forms.ModelForm): def __init__(self, *args, **kwargs): current_peer = kwargs.pop('current_peer', None) + config_file = kwargs.pop('config_file', None) super().__init__(*args, **kwargs) self.current_peer = current_peer + self.config_file = config_file allowed_ip = forms.GenericIPAddressField(label='Allowed IP or Network', required=True) netmask = forms.ChoiceField(choices=NETMASK_CHOICES, label='Netmask', initial=24, required=True) @@ -33,29 +35,34 @@ class PeerAllowedIPForm(forms.ModelForm): if allowed_ip is None: raise forms.ValidationError("Please provide a valid IP address.") - wireguard_network = ipaddress.ip_network(f"{self.current_peer.wireguard_instance.address}/{self.current_peer.wireguard_instance.netmask}", strict=False) + if self.config_file == 'server': + wireguard_network = ipaddress.ip_network(f"{self.current_peer.wireguard_instance.address}/{self.current_peer.wireguard_instance.netmask}", strict=False) + if priority == 0: + zero_priority_ips_query = PeerAllowedIP.objects.filter(peer=self.current_peer, config_file='server', priority=0) + if self.instance: + zero_priority_ips_query = zero_priority_ips_query.exclude(uuid=self.instance.uuid) + if zero_priority_ips_query.exists(): + raise forms.ValidationError("A peer can have only one IP with priority zero.") - if priority == 0: - zero_priority_ips_query = PeerAllowedIP.objects.filter(peer=self.current_peer, priority=0) - if self.instance: - zero_priority_ips_query = zero_priority_ips_query.exclude(uuid=self.instance.uuid) - if zero_priority_ips_query.exists(): - raise forms.ValidationError("A peer can have only one IP with priority zero.") - - duplicated_ip = PeerAllowedIP.objects.filter(allowed_ip=allowed_ip) - if self.instance: - duplicated_ip = duplicated_ip.exclude(uuid=self.instance.uuid) - if duplicated_ip.exists(): - raise forms.ValidationError("This IP is already in use by another peer.") - if ipaddress.ip_address(allowed_ip) not in wireguard_network: - raise forms.ValidationError("The IP address does not belong to the Peer's WireGuard instance network range. Please check the IP address or change the priority.") - if str(netmask) != str(32): - raise forms.ValidationError("The netmask for priority 0 IP must be 32.") - if self.current_peer.wireguard_instance.address == allowed_ip: - raise forms.ValidationError("The IP address is the same as the Peer's WireGuard instance address.") + duplicated_ip = PeerAllowedIP.objects.filter(config_file='server', allowed_ip=allowed_ip) + if self.instance: + duplicated_ip = duplicated_ip.exclude(uuid=self.instance.uuid) + if duplicated_ip.exists(): + raise forms.ValidationError("This IP is already in use by another peer.") + if ipaddress.ip_address(allowed_ip) not in wireguard_network: + raise forms.ValidationError("The IP address does not belong to the Peer's WireGuard instance network range. Please check the IP address or change the priority.") + if str(netmask) != str(32): + raise forms.ValidationError("The netmask for priority 0 IP must be 32.") + if self.current_peer.wireguard_instance.address == allowed_ip: + raise forms.ValidationError("The IP address is the same as the Peer's WireGuard instance address.") + else: + if ipaddress.ip_address(allowed_ip) in wireguard_network: + raise forms.ValidationError("The IP address belongs to the Peer's WireGuard instance network range. Please check the IP address or change use priority 0 instead.") + elif self.config_file == 'client': + if priority < 1: + raise forms.ValidationError("Priority must be greater than or equal to 1") else: - if ipaddress.ip_address(allowed_ip) in wireguard_network: - raise forms.ValidationError("The IP address belongs to the Peer's WireGuard instance network range. Please check the IP address or change use priority 0 instead.") + raise forms.ValidationError('Invalid config file') class Meta: model = PeerAllowedIP diff --git a/wireguard_peer/views.py b/wireguard_peer/views.py index 1205cc2..a6b0d82 100644 --- a/wireguard_peer/views.py +++ b/wireguard_peer/views.py @@ -22,7 +22,7 @@ def generate_peer_default(wireguard_instance): # the code below can be an issue for larger networks, for now it's fine, but it should be optimized in the future used_ips = set(WireGuardInstance.objects.all().values_list('address', flat=True)) | \ - set(PeerAllowedIP.objects.filter(priority=0).values_list('allowed_ip', flat=True)) + set(PeerAllowedIP.objects.filter(config_file='server', priority=0).values_list('allowed_ip', flat=True)) free_ip_address = None for ip in network.hosts(): @@ -88,6 +88,7 @@ def view_wireguard_peer_manage(request): wireguard_instance=current_instance, ) PeerAllowedIP.objects.create( + config_file='server', peer=new_peer, allowed_ip=new_peer_data['allowed_ip'], priority=0, @@ -115,7 +116,8 @@ def view_wireguard_peer_manage(request): messages.warning(request, 'Error deleting peer|Invalid confirmation message. Type "delete" to confirm.') return redirect('/peer/manage/?peer=' + str(current_peer.uuid)) page_title = 'Update Peer ' - peer_ip_list = current_peer.peerallowedip_set.all().order_by('priority') + peer_ip_list = current_peer.peerallowedip_set.filter(config_file='server').order_by('priority') + peer_client_ip_list = current_peer.peerallowedip_set.filter(config_file='client').order_by('priority') if current_peer.name: page_title += current_peer.name else: @@ -133,31 +135,28 @@ def view_wireguard_peer_manage(request): else: return redirect('/peer/list/') context = { - 'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer, 'form': form, 'peer_ip_list': peer_ip_list + 'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer, 'form': form, + 'peer_ip_list': peer_ip_list, 'peer_client_ip_list': peer_client_ip_list } return render(request, 'wireguard/wireguard_manage_peer.html', context) - def view_manage_ip_address(request): if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists(): return render(request, 'access_denied.html', {'page_title': 'Access Denied'}) + + config_file = request.GET.get('config', 'server') + if request.GET.get('peer'): current_peer = get_object_or_404(Peer, uuid=request.GET.get('peer')) - page_title = 'Add new IP address for Peer ' + #page_title = 'Add new IP address for Peer ' + str(current_peer) current_ip = None - if current_peer.name: - page_title += current_peer.name - else: - page_title += current_peer.public_key elif request.GET.get('ip'): current_ip = get_object_or_404(PeerAllowedIP, uuid=request.GET.get('ip')) current_peer = current_ip.peer - page_title = 'Update IP address for Peer ' - if current_peer.name: - page_title += current_peer.name - else: - page_title += current_peer.public_key[:10] + ("..." if len(current_peer.public_key) > 16 else "") + config_file = current_ip.config_file + #page_title = 'Update IP address for Peer ' + str(current_peer) + if request.GET.get('action') == 'delete': if request.GET.get('confirmation') == 'delete': current_ip.delete() @@ -168,13 +167,20 @@ def view_manage_ip_address(request): else: messages.warning(request, 'Error deleting IP address|Invalid confirmation message. Type "delete" to confirm.') return redirect('/peer/ip/?ip=' + str(current_ip.uuid)) - + if config_file not in ['client', 'server']: + config_file = 'server' + if config_file == 'client': + page_title = 'Manage client route' + else: + page_title = 'Manage IP address or Network' + if request.method == 'POST': - form = PeerAllowedIPForm(request.POST or None, instance=current_ip, current_peer=current_peer) + form = PeerAllowedIPForm(request.POST or None, instance=current_ip, current_peer=current_peer, config_file=config_file) if form.is_valid(): this_form = form.save(commit=False) if not current_ip: this_form.peer = current_peer + this_form.config_file = config_file this_form.save() current_peer.wireguard_instance.pending_changes = True current_peer.wireguard_instance.save() diff --git a/wireguard_tools/views.py b/wireguard_tools/views.py index c69ffa2..ae85a3c 100644 --- a/wireguard_tools/views.py +++ b/wireguard_tools/views.py @@ -23,15 +23,18 @@ def generate_peer_config(peer_uuid): peer = get_object_or_404(Peer, uuid=peer_uuid) wg_instance = peer.wireguard_instance - priority_zero_ip = PeerAllowedIP.objects.filter(peer=peer, priority=0).first() + priority_zero_ip = PeerAllowedIP.objects.filter(config_file='server', peer=peer, priority=0).first() if not priority_zero_ip: return "No IP with priority zero found for this peer." client_address = f"{priority_zero_ip.allowed_ip}/{priority_zero_ip.netmask}" - #allowed_ips = PeerAllowedIP.objects.filter(peer=peer).exclude(uuid=priority_zero_ip.uuid).order_by('priority') - #allowed_ips_line = ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips]) + allowed_ips = PeerAllowedIP.objects.filter(peer=peer, config_file='client').order_by('priority') + if allowed_ips: + allowed_ips_line = ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips]) + else: + allowed_ips_line = "0.0.0.0/0, ::/0" config_lines = [ "[Interface]", @@ -41,7 +44,7 @@ def generate_peer_config(peer_uuid): "\n[Peer]", f"PublicKey = {wg_instance.public_key}", f"Endpoint = {wg_instance.hostname}:{wg_instance.listen_port}", - f"AllowedIPs = 0.0.0.0/0, ::/0", + f"AllowedIPs = {allowed_ips_line}", f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "", f"PersistentKeepalive = {peer.persistent_keepalive}", ] @@ -85,7 +88,7 @@ def export_wireguard_configs(request): rule_text_down = "" rule_destination = redirect_rule.ip_address if redirect_rule.peer: - peer_allowed_ip_address = PeerAllowedIP.objects.filter(peer=redirect_rule.peer, netmask=32, priority=0).first() + peer_allowed_ip_address = PeerAllowedIP.objects.filter(config_file='server', peer=redirect_rule.peer, netmask=32, priority=0).first() if peer_allowed_ip_address: rule_destination = peer_allowed_ip_address.allowed_ip if rule_destination: @@ -128,7 +131,7 @@ def export_wireguard_configs(request): f"PresharedKey = {peer.pre_shared_key}" if peer.pre_shared_key else "", f"PersistentKeepalive = {peer.persistent_keepalive}", ] - allowed_ips = PeerAllowedIP.objects.filter(peer=peer).order_by('priority') + allowed_ips = PeerAllowedIP.objects.filter(config_file='server', peer=peer).order_by('priority') allowed_ips_line = "AllowedIPs = " + ", ".join([f"{ip.allowed_ip}/{ip.netmask}" for ip in allowed_ips]) peer_lines.append(allowed_ips_line) config_lines.extend(peer_lines) diff --git a/wireguard_webadmin/settings.py b/wireguard_webadmin/settings.py index 354941c..3cfc67b 100644 --- a/wireguard_webadmin/settings.py +++ b/wireguard_webadmin/settings.py @@ -129,6 +129,6 @@ STATICFILES_DIRS = [ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -WIREGUARD_WEBADMIN_VERSION = 9507 +WIREGUARD_WEBADMIN_VERSION = 9601 from wireguard_webadmin.production_settings import * \ No newline at end of file