diff --git a/firewall/admin.py b/firewall/admin.py index e8acf03..006c919 100644 --- a/firewall/admin.py +++ b/firewall/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from firewall.models import RedirectRule +from firewall.models import RedirectRule, FirewallRule, FirewallSettings class RedirectRuleAdmin(admin.ModelAdmin): @@ -8,3 +8,16 @@ class RedirectRuleAdmin(admin.ModelAdmin): admin.site.register(RedirectRule, RedirectRuleAdmin) + +class FirewallRuleAdmin(admin.ModelAdmin): + list_display = ('firewall_chain', 'description', 'in_interface', 'out_interface', 'source_ip', 'source_netmask', 'source_peer_include_networks', 'not_source', 'destination_ip', 'destination_netmask', 'destination_peer_include_networks', 'not_destination', 'protocol', 'destination_port', 'state_new', 'state_related', 'state_established', 'state_invalid', 'state_untracked', 'not_state', 'rule_action', 'sort_order') + search_fields = ('firewall_chain', 'description', 'in_interface', 'out_interface', 'source_ip', 'source_netmask', 'source_peer_include_networks', 'not_source', 'destination_ip', 'destination_netmask', 'destination_peer_include_networks', 'not_destination', 'protocol', 'destination_port', 'state_new', 'state_related', 'state_established', 'state_invalid', 'state_untracked', 'not_state', 'rule_action', 'sort_order') + +admin.site.register(FirewallRule, FirewallRuleAdmin) + + +class FirewallSettingsAdmin(admin.ModelAdmin): + list_display = ('wan_interface', 'default_forward_policy', 'default_output_policy', 'allow_peer_to_peer', 'allow_instance_to_instance') + +admin.site.register(FirewallSettings, FirewallSettingsAdmin) + diff --git a/firewall/forms.py b/firewall/forms.py index 720b5db..7f3a5d6 100644 --- a/firewall/forms.py +++ b/firewall/forms.py @@ -1,5 +1,5 @@ -from firewall.models import RedirectRule -from wireguard.models import Peer, WireGuardInstance +from firewall.models import RedirectRule, FirewallRule, FirewallSettings +from wireguard.models import Peer, WireGuardInstance, NETMASK_CHOICES from django import forms @@ -34,7 +34,7 @@ class RedirectRuleForm(forms.ModelForm): raise forms.ValidationError("Port 8000 (tcp) is reserved for wireguard-webadmin.") if protocol == 'udp': - if WireGuardInstance.objects.filter(udp_port=port).exists(): + if WireGuardInstance.objects.filter(listen_port=port).exists(): raise forms.ValidationError("Port " + str(port) + " (udp) is already in use by a WireGuard instance.") if peer and ip_address: @@ -49,4 +49,48 @@ class RedirectRuleForm(forms.ModelForm): if ip_address: cleaned_data['peer'] = None - return cleaned_data \ No newline at end of file + return cleaned_data + + +class FirewallRuleForm(forms.ModelForm): + firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global') + interface_list = [('', '------'),] + interface_list.append((firewall_settings.wan_interface, firewall_settings.wan_interface + ' (WAN)')) + + for wireguard_instance in WireGuardInstance.objects.all().order_by('instance_id'): + wireguard_instance_interface = 'wg'+ str(wireguard_instance.instance_id) + interface_list.append((wireguard_instance_interface, wireguard_instance_interface)) + + interface_list.append(('wg+', 'wg+ (Any WireGuard Interface)')) + + description = forms.CharField(label='Description', required=False) + firewall_chain = forms.ChoiceField(label='Firewall Chain', choices=[('forward', 'FORWARD'), ('postrouting', 'POSTROUTING (nat)')], initial='forward') + in_interface = forms.ChoiceField(label='In Interface', choices=interface_list, required=False) + out_interface = forms.ChoiceField(label='Out Interface', choices=interface_list, required=False) + source_ip = forms.GenericIPAddressField(label='Source IP', required=False) + source_netmask = forms.IntegerField(label='Source Netmask', initial=32, min_value=0, max_value=32) + source_peer = forms.ModelMultipleChoiceField(label='Source Peer', queryset=Peer.objects.all(), required=False) + source_peer_include_networks = forms.BooleanField(label='Source Peer Include Networks', required=False) + not_source = forms.BooleanField(label='Not Source', required=False) + destination_ip = forms.GenericIPAddressField(label='Destination IP', required=False) + destination_netmask = forms.IntegerField(label='Destination Netmask', initial=32, min_value=0, max_value=32) + destination_peer = forms.ModelMultipleChoiceField(label='Destination Peer', queryset=Peer.objects.all(), required=False) + destination_peer_include_networks = forms.BooleanField(label='Destination Peer Include Networks', required=False) + not_destination = forms.BooleanField(label='Not Destination', required=False) + protocol = forms.ChoiceField(label='Protocol', choices=[('', 'all'), ('tcp', 'TCP'), ('udp', 'UDP'), ('both', 'TCP+UDP'), ('icmp', 'ICMP')], required=False) + destination_port = forms.CharField(label='Destination Port', required=False) + state_new = forms.BooleanField(label='State NEW', required=False) + state_related = forms.BooleanField(label='State RELATED', required=False) + state_established = forms.BooleanField(label='State ESTABLISHED', required=False) + state_invalid = forms.BooleanField(label='State INVALID', required=False) + state_untracked = forms.BooleanField(label='State UNTRACKED', required=False) + not_state = forms.BooleanField(label='Not State', required=False) + rule_action = forms.ChoiceField(label='Rule Action', initial='accept', choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP'), ('masquerade', 'MASQUERADE')]) + sort_order = forms.IntegerField(label='Sort Order', initial=0, min_value=0) + + class Meta: + model = FirewallRule + fields = ['description', 'firewall_chain', 'in_interface', 'out_interface', 'source_ip', 'source_netmask', 'source_peer', 'source_peer_include_networks', 'not_source', 'destination_ip', 'destination_netmask', 'destination_peer', 'destination_peer_include_networks', 'not_destination', 'protocol', 'destination_port', 'state_new', 'state_related', 'state_established', 'state_invalid', 'state_untracked', 'not_state', 'rule_action', 'sort_order'] + + + diff --git a/firewall/migrations/0003_firewallsettings_forwardrule.py b/firewall/migrations/0003_firewallsettings_forwardrule.py new file mode 100644 index 0000000..fdf2786 --- /dev/null +++ b/firewall/migrations/0003_firewallsettings_forwardrule.py @@ -0,0 +1,61 @@ +# Generated by Django 5.0.2 on 2024-02-28 15:37 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0002_redirectrule_masquerade_source_and_more'), + ('wireguard', '0018_wireguardinstance_legacy_firewall'), + ] + + operations = [ + migrations.CreateModel( + name='FirewallSettings', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('global', models.CharField(max_length=6, unique=True)), + ('default_forward_policy', models.CharField(choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP')], default='accept', max_length=6)), + ('default_output_policy', models.CharField(choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP')], default='accept', max_length=6)), + ('allow_peer_to_peer', models.BooleanField(default=True)), + ('allow_instance_to_instance', models.BooleanField(default=True)), + ('wan_interface', models.CharField(default='eth0', max_length=12)), + ], + ), + migrations.CreateModel( + name='ForwardRule', + fields=[ + ('description', models.CharField(blank=True, max_length=100, null=True)), + ('firewall_chain', models.CharField(choices=[('FORWARD', 'FORWARD'), ('OUTPUT', 'OUTPUT'), ('POSTROUTING', 'POSTROUTING (nat)')], default='FORWARD', max_length=12)), + ('in_interface', models.CharField(blank=True, default='', max_length=12, null=True)), + ('out_interface', models.CharField(blank=True, default='', max_length=12, null=True)), + ('source_ip', models.GenericIPAddressField(blank=True, null=True, protocol='IPv4')), + ('source_netmask', models.PositiveIntegerField(choices=[(8, '/8 (255.0.0.0)'), (9, '/9 (255.128.0.0)'), (10, '/10 (255.192.0.0)'), (11, '/11 (255.224.0.0)'), (12, '/12 (255.240.0.0)'), (13, '/13 (255.248.0.0)'), (14, '/14 (255.252.0.0)'), (15, '/15 (255.254.0.0)'), (16, '/16 (255.255.0.0)'), (17, '/17 (255.255.128.0)'), (18, '/18 (255.255.192.0)'), (19, '/19 (255.255.224.0)'), (20, '/20 (255.255.240.0)'), (21, '/21 (255.255.248.0)'), (22, '/22 (255.255.252.0)'), (23, '/23 (255.255.254.0)'), (24, '/24 (255.255.255.0)'), (25, '/25 (255.255.255.128)'), (26, '/26 (255.255.255.192)'), (27, '/27 (255.255.255.224)'), (28, '/28 (255.255.255.240)'), (29, '/29 (255.255.255.248)'), (30, '/30 (255.255.255.252)'), (32, '/32 (255.255.255.255)')], default=32)), + ('source_peer_include_networks', models.BooleanField(default=False)), + ('not_source', models.BooleanField(default=False)), + ('destination_ip', models.GenericIPAddressField(blank=True, null=True, protocol='IPv4')), + ('destination_netmask', models.PositiveIntegerField(choices=[(8, '/8 (255.0.0.0)'), (9, '/9 (255.128.0.0)'), (10, '/10 (255.192.0.0)'), (11, '/11 (255.224.0.0)'), (12, '/12 (255.240.0.0)'), (13, '/13 (255.248.0.0)'), (14, '/14 (255.252.0.0)'), (15, '/15 (255.254.0.0)'), (16, '/16 (255.255.0.0)'), (17, '/17 (255.255.128.0)'), (18, '/18 (255.255.192.0)'), (19, '/19 (255.255.224.0)'), (20, '/20 (255.255.240.0)'), (21, '/21 (255.255.248.0)'), (22, '/22 (255.255.252.0)'), (23, '/23 (255.255.254.0)'), (24, '/24 (255.255.255.0)'), (25, '/25 (255.255.255.128)'), (26, '/26 (255.255.255.192)'), (27, '/27 (255.255.255.224)'), (28, '/28 (255.255.255.240)'), (29, '/29 (255.255.255.248)'), (30, '/30 (255.255.255.252)'), (32, '/32 (255.255.255.255)')], default=32)), + ('destination_peer_include_networks', models.BooleanField(default=False)), + ('not_destination', models.BooleanField(default=False)), + ('protocol', models.CharField(blank=True, choices=[('', 'all'), ('tcp', 'TCP'), ('udp', 'UDP'), ('both', 'TCP+UDP'), ('icmp', 'ICMP')], default='', max_length=4, null=True)), + ('destination_port', models.CharField(blank=True, max_length=11, null=True)), + ('state_new', models.BooleanField(default=False)), + ('state_related', models.BooleanField(default=False)), + ('state_established', models.BooleanField(default=False)), + ('state_invalid', models.BooleanField(default=False)), + ('state_untracked', models.BooleanField(default=False)), + ('not_state', models.BooleanField(default=False)), + ('rule_action', models.CharField(choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP'), ('masquerade', 'MASQUERADE')], default='accept', max_length=10)), + ('sort_order', models.PositiveIntegerField(default=0)), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('destination_peer', models.ManyToManyField(blank=True, related_name='forward_rules_as_destination', to='wireguard.peer')), + ('source_peer', models.ManyToManyField(blank=True, related_name='forward_rules_as_source', to='wireguard.peer')), + ('wireguard_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wireguard.wireguardinstance')), + ], + ), + ] diff --git a/firewall/migrations/0004_rename_forwardrule_firewallrule.py b/firewall/migrations/0004_rename_forwardrule_firewallrule.py new file mode 100644 index 0000000..c83a3a7 --- /dev/null +++ b/firewall/migrations/0004_rename_forwardrule_firewallrule.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-29 13:02 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0003_firewallsettings_forwardrule'), + ('wireguard', '0018_wireguardinstance_legacy_firewall'), + ] + + operations = [ + migrations.RenameModel( + old_name='ForwardRule', + new_name='FirewallRule', + ), + ] diff --git a/firewall/migrations/0005_firewallsettings_created_firewallsettings_updated.py b/firewall/migrations/0005_firewallsettings_created_firewallsettings_updated.py new file mode 100644 index 0000000..79e6613 --- /dev/null +++ b/firewall/migrations/0005_firewallsettings_created_firewallsettings_updated.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.2 on 2024-02-29 13:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0004_rename_forwardrule_firewallrule'), + ] + + operations = [ + migrations.AddField( + model_name='firewallsettings', + name='created', + field=models.DateTimeField(auto_now=True), + ), + migrations.AddField( + model_name='firewallsettings', + name='updated', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/firewall/migrations/0006_alter_firewallsettings_created.py b/firewall/migrations/0006_alter_firewallsettings_created.py new file mode 100644 index 0000000..172b69a --- /dev/null +++ b/firewall/migrations/0006_alter_firewallsettings_created.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-29 13:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0005_firewallsettings_created_firewallsettings_updated'), + ] + + operations = [ + migrations.AlterField( + model_name='firewallsettings', + name='created', + field=models.DateTimeField(auto_now_add=True), + ), + ] diff --git a/firewall/migrations/0007_firewallsettings_pending_changes.py b/firewall/migrations/0007_firewallsettings_pending_changes.py new file mode 100644 index 0000000..240bd45 --- /dev/null +++ b/firewall/migrations/0007_firewallsettings_pending_changes.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-29 14:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0006_alter_firewallsettings_created'), + ] + + operations = [ + migrations.AddField( + model_name='firewallsettings', + name='pending_changes', + field=models.BooleanField(default=False), + ), + ] diff --git a/firewall/migrations/0008_remove_firewallsettings_global_firewallsettings_name.py b/firewall/migrations/0008_remove_firewallsettings_global_firewallsettings_name.py new file mode 100644 index 0000000..e3bced2 --- /dev/null +++ b/firewall/migrations/0008_remove_firewallsettings_global_firewallsettings_name.py @@ -0,0 +1,22 @@ +# Generated by Django 5.0.2 on 2024-02-29 17:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0007_firewallsettings_pending_changes'), + ] + + operations = [ + migrations.RemoveField( + model_name='firewallsettings', + name='global', + ), + migrations.AddField( + model_name='firewallsettings', + name='name', + field=models.CharField(default='global', max_length=6, unique=True), + ), + ] diff --git a/firewall/migrations/0009_remove_firewallrule_wireguard_instance.py b/firewall/migrations/0009_remove_firewallrule_wireguard_instance.py new file mode 100644 index 0000000..0e196b2 --- /dev/null +++ b/firewall/migrations/0009_remove_firewallrule_wireguard_instance.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.2 on 2024-03-01 00:12 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0008_remove_firewallsettings_global_firewallsettings_name'), + ] + + operations = [ + migrations.RemoveField( + model_name='firewallrule', + name='wireguard_instance', + ), + ] diff --git a/firewall/migrations/0010_alter_firewallrule_firewall_chain.py b/firewall/migrations/0010_alter_firewallrule_firewall_chain.py new file mode 100644 index 0000000..7ec28ca --- /dev/null +++ b/firewall/migrations/0010_alter_firewallrule_firewall_chain.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-03-01 01:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('firewall', '0009_remove_firewallrule_wireguard_instance'), + ] + + operations = [ + migrations.AlterField( + model_name='firewallrule', + name='firewall_chain', + field=models.CharField(choices=[('forward', 'FORWARD'), ('postrouting', 'POSTROUTING (nat)')], default='forward', max_length=12), + ), + ] diff --git a/firewall/models.py b/firewall/models.py index d6b0532..3137379 100644 --- a/firewall/models.py +++ b/firewall/models.py @@ -1,5 +1,6 @@ from django.db import models from wireguard.models import Peer, WireGuardInstance +from wireguard.models import NETMASK_CHOICES import uuid @@ -24,3 +25,55 @@ class RedirectRule(models.Model): unique_together = ['port', 'protocol'] +class FirewallRule(models.Model): + description = models.CharField(max_length=100, blank=True, null=True) + firewall_chain = models.CharField(max_length=12, default='forward', choices=[('forward', 'FORWARD'), ('postrouting', 'POSTROUTING (nat)')]) + + in_interface = models.CharField(max_length=12, default='', blank=True, null=True) + out_interface = models.CharField(max_length=12, default='', blank=True, null=True) + + source_ip = models.GenericIPAddressField(blank=True, null=True, protocol='IPv4') + source_netmask = models.PositiveIntegerField(default=32, choices=NETMASK_CHOICES) + source_peer = models.ManyToManyField(Peer, related_name="forward_rules_as_source", blank=True) + source_peer_include_networks = models.BooleanField(default=False) + not_source = models.BooleanField(default=False) + + destination_ip = models.GenericIPAddressField(blank=True, null=True, protocol='IPv4') + destination_netmask = models.PositiveIntegerField(default=32, choices=NETMASK_CHOICES) + destination_peer = models.ManyToManyField(Peer, related_name="forward_rules_as_destination", blank=True) + destination_peer_include_networks = models.BooleanField(default=False) + not_destination = models.BooleanField(default=False) + + protocol = models.CharField(max_length=4, default='', blank=True, null=True, choices=[('', 'all'), ('tcp', 'TCP'), ('udp', 'UDP'), ('both', 'TCP+UDP'), ('icmp', 'ICMP'),]) + destination_port = models.CharField(max_length=11, blank=True, null=True) + + state_new = models.BooleanField(default=False) + state_related = models.BooleanField(default=False) + state_established = models.BooleanField(default=False) + state_invalid = models.BooleanField(default=False) + state_untracked = models.BooleanField(default=False) + not_state = models.BooleanField(default=False) + + rule_action = models.CharField(max_length=10, default='accept', choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP'), ('masquerade', 'MASQUERADE')]) + + sort_order = models.PositiveIntegerField(default=0) + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4) + + def __str__(self): + return str(self.uuid) + + +class FirewallSettings(models.Model): + name = models.CharField(max_length=6, default='global', unique=True) + default_forward_policy = models.CharField(max_length=6, default='accept', choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP')]) + default_output_policy = models.CharField(max_length=6, default='accept', choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP')]) + allow_peer_to_peer = models.BooleanField(default=True) + allow_instance_to_instance = models.BooleanField(default=True) + wan_interface = models.CharField(max_length=12, default='eth0') + pending_changes = models.BooleanField(default=False) + + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + diff --git a/firewall/views.py b/firewall/views.py index 35715ef..62775cf 100644 --- a/firewall/views.py +++ b/firewall/views.py @@ -1,6 +1,6 @@ from django.shortcuts import render, get_object_or_404, redirect -from firewall.models import RedirectRule -from firewall.forms import RedirectRuleForm +from firewall.models import RedirectRule, FirewallRule, FirewallSettings +from firewall.forms import RedirectRuleForm, FirewallRuleForm from django.contrib import messages from wireguard.models import WireGuardInstance from user_manager.models import UserAcl @@ -15,7 +15,8 @@ def view_redirect_rule_list(request): context = { 'page_title': 'Port Forward List', 'pending_changes_warning': pending_changes_warning, - 'redirect_rule_list': RedirectRule.objects.all().order_by('wireguard_instance', 'protocol', 'port') + 'redirect_rule_list': RedirectRule.objects.all().order_by('port'), + 'current_chain': 'portforward', } return render(request, 'firewall/redirect_rule_list.html', context=context) @@ -52,4 +53,57 @@ def manage_redirect_rule(request): context['form'] = form context['instance'] = instance - return render(request, 'firewall/manage_redirect_rule.html', context=context) \ No newline at end of file + return render(request, 'firewall/manage_redirect_rule.html', context=context) + + +def view_firewall_rule_list(request): + wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id') + current_chain = request.GET.get('chain', 'forward') + if current_chain not in ['forward', 'portforward', 'postrouting']: + current_chain = 'forward' + if wireguard_instances.filter(pending_changes=True).exists(): + pending_changes_warning = True + else: + pending_changes_warning = False + context = { + 'page_title': 'Firewall Rule List', + 'pending_changes_warning': pending_changes_warning, + 'firewall_rule_list': FirewallRule.objects.filter(firewall_chain=current_chain).order_by('sort_order'), + 'current_chain': current_chain, + } + return render(request, 'firewall/firewall_rule_list.html', context=context) + + +def manage_firewall_rule(request): + if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=40).exists(): + return render(request, 'access_denied.html', {'page_title': 'Access Denied'}) + context = {'page_title': 'Manage Firewall Rule'} + instance = None + uuid = request.GET.get('uuid', None) + if uuid: + instance = get_object_or_404(FirewallRule, uuid=uuid) + if request.GET.get('action') == 'delete': + if request.GET.get('confirmation') == 'delete': + firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global') + firewall_settings.pending_changes = True + firewall_settings.save() + messages.success(request, 'Firewall rule deleted successfully') + else: + messages.warning(request, 'Error deleting Firewall rule|Confirmation did not match. Firewall rule was not deleted.') + return redirect('/firewall/rule_list/') + + if request.method == 'POST': + form = FirewallRuleForm(request.POST, instance=instance) + if form.is_valid(): + firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global') + firewall_settings.pending_changes = True + firewall_settings.save() + form.save() + messages.success(request, 'Firewall rule saved successfully') + return redirect('/firewall/rule_list/') + else: + form = FirewallRuleForm(instance=instance) + context['form'] = form + context['instance'] = instance + + return render(request, 'firewall/manage_firewall_rule.html', context=context) diff --git a/templates/base.html b/templates/base.html index d49e3da..c5e6036 100644 --- a/templates/base.html +++ b/templates/base.html @@ -25,6 +25,7 @@ + {% block page_custom_head %}{% endblock%} {% load custom_tags %} {% tag_webadmin_version as webadmin_version %} diff --git a/templates/firewall/firewall_nav_tabs.html b/templates/firewall/firewall_nav_tabs.html new file mode 100644 index 0000000..9457ef3 --- /dev/null +++ b/templates/firewall/firewall_nav_tabs.html @@ -0,0 +1,12 @@ +
\ No newline at end of file diff --git a/templates/firewall/firewall_rule_list.html b/templates/firewall/firewall_rule_list.html new file mode 100644 index 0000000..031e2d7 --- /dev/null +++ b/templates/firewall/firewall_rule_list.html @@ -0,0 +1,175 @@ +{% extends 'base.html' %} + +{% block page_custom_head %} + +{% endblock%} + +{% block content %} + +Instance | -Protocol | -Port | -Destination | -Allow Forward | -Masquerade Source | -Actions | -||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
{{ redirect_rule.wireguard_instance }} | -{{ redirect_rule.protocol }} | -{{ redirect_rule.port }} | -- {% if redirect_rule.peer %} - - {% if redirect_rule.peer.name %} - {{ redirect_rule.peer.name }} - {% else %} - {{ redirect_rule.peer.public_key|slice:":16" }}{% if redirect_rule.peer.public_key|length > 16 %}...{% endif %} - {% endif %} - - {% else %} - {{ redirect_rule.ip_address }} - {% endif %} - | -
-
- {% if redirect_rule.add_forward_rule %}
-
- {% else %}
-
-
- {% endif %}
+
+
- {% endif %}
-
+ {% include "firewall/firewall_nav_tabs.html" %}
+
+
+
+
+
+
|
- - - | -