mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2025-04-19 08:55:12 +00:00
Legacy firewall migrate routines and export fw rules.
This commit is contained in:
parent
de073a4795
commit
b6a7cdaac9
@ -142,8 +142,6 @@ class FirewallSettingsForm(forms.ModelForm):
|
||||
if not interface.startswith('wg') and interface != 'lo':
|
||||
interface_choices.append((interface, interface))
|
||||
|
||||
#if interface.startswith('wg'):
|
||||
# list_network_interfaces().remove(interface)
|
||||
default_forward_policy = forms.ChoiceField(label='Default Forward Policy', choices=[('accept', 'ACCEPT'), ('reject', 'REJECT'), ('drop', 'DROP')], initial='accept')
|
||||
allow_peer_to_peer = forms.BooleanField(label='Allow Peer to Peer', required=False)
|
||||
allow_instance_to_instance = forms.BooleanField(label='Allow Instance to Instance', required=False)
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-03-04 11:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('firewall', '0010_alter_firewallrule_firewall_chain'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='firewallsettings',
|
||||
name='last_firewall_reset',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
@ -73,6 +73,7 @@ class FirewallSettings(models.Model):
|
||||
allow_instance_to_instance = models.BooleanField(default=True)
|
||||
wan_interface = models.CharField(max_length=12, default='eth0')
|
||||
pending_changes = models.BooleanField(default=False)
|
||||
last_firewall_reset = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
@ -1,10 +1,10 @@
|
||||
from firewall.models import FirewallRule
|
||||
from wireguard.models import Peer, PeerAllowedIP
|
||||
from firewall.models import FirewallRule, FirewallSettings, RedirectRule
|
||||
from wireguard.models import Peer, PeerAllowedIP, WireGuardInstance
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def get_peer_addresses(peers, include_networks):
|
||||
addresses = []
|
||||
# Indica se algum peer está completamente sem PeerAllowedIP
|
||||
missing_ip = False
|
||||
for peer in peers.all():
|
||||
peer_ips = peer.peerallowedip_set.all().order_by('priority')
|
||||
if not include_networks:
|
||||
@ -13,17 +13,65 @@ def get_peer_addresses(peers, include_networks):
|
||||
if peer_ips.exists():
|
||||
addresses.extend([f"{peer_ip.allowed_ip}/{peer_ip.netmask}" for peer_ip in peer_ips])
|
||||
else:
|
||||
missing_ip = True
|
||||
addresses.append(f"Missing IP for selected peer: {peer}")
|
||||
|
||||
return addresses, missing_ip
|
||||
return addresses
|
||||
|
||||
def generate_iptable_rules():
|
||||
|
||||
def reset_firewall_to_default():
|
||||
for wireguard_instance in WireGuardInstance.objects.all():
|
||||
wireguard_instance.pending_changes = True
|
||||
wireguard_instance.legacy_firewall = False
|
||||
wireguard_instance.post_up = ''
|
||||
wireguard_instance.post_down = ''
|
||||
wireguard_instance.save()
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
firewall_settings.pending_changes = True
|
||||
firewall_settings.last_firewall_reset = timezone.now()
|
||||
firewall_settings.allow_peer_to_peer = True
|
||||
firewall_settings.allow_instance_to_instance = True
|
||||
firewall_settings.wan_interface = 'eth0'
|
||||
firewall_settings.default_forward_policy = 'drop'
|
||||
firewall_settings.save()
|
||||
|
||||
FirewallRule.objects.all().delete()
|
||||
RedirectRule.objects.all().delete()
|
||||
|
||||
FirewallRule.objects.create(
|
||||
firewall_chain='postrouting', sort_order=0, out_interface=firewall_settings.wan_interface, rule_action='masquerade',
|
||||
description='Masquerade traffic from VPN to WAN',
|
||||
)
|
||||
|
||||
FirewallRule.objects.create(
|
||||
firewall_chain='forward', sort_order=0, rule_action='accept', description='Allow established/related traffic',
|
||||
state_established=True, state_related=True
|
||||
)
|
||||
FirewallRule.objects.create(
|
||||
firewall_chain='forward', sort_order=1, rule_action='reject', description='Reject traffic to private networks exiting on WAN interface',
|
||||
in_interface='wg+', out_interface=firewall_settings.wan_interface, destination_ip='10.0.0.0', destination_netmask=8
|
||||
)
|
||||
FirewallRule.objects.create(
|
||||
firewall_chain='forward', sort_order=2, rule_action='reject', description='Reject traffic to private networks exiting on WAN interface',
|
||||
in_interface='wg+', out_interface=firewall_settings.wan_interface, destination_ip='172.16.0.0', destination_netmask=12
|
||||
)
|
||||
FirewallRule.objects.create(
|
||||
firewall_chain='forward', sort_order=3, rule_action='reject', description='Reject traffic to private networks exiting on WAN interface',
|
||||
in_interface='wg+', out_interface=firewall_settings.wan_interface, destination_ip='192.168.0.0', destination_netmask=16
|
||||
)
|
||||
FirewallRule.objects.create(
|
||||
firewall_chain='forward', sort_order=10, rule_action='accept', description='Allow traffic from VPN to WAN',
|
||||
in_interface='wg+', out_interface=firewall_settings.wan_interface
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
def export_user_firewall():
|
||||
iptables_rules = []
|
||||
rules = FirewallRule.objects.all().order_by('firewall_chain', 'sort_order')
|
||||
|
||||
for rule in rules:
|
||||
source_addresses, source_missing_ip = get_peer_addresses(rule.source_peer, rule.source_peer_include_networks)
|
||||
destination_addresses, destination_missing_ip = get_peer_addresses(rule.destination_peer, rule.destination_peer_include_networks)
|
||||
source_addresses = get_peer_addresses(rule.source_peer, rule.source_peer_include_networks)
|
||||
destination_addresses = get_peer_addresses(rule.destination_peer, rule.destination_peer_include_networks)
|
||||
|
||||
# Adiciona source_ip/destination_ip às listas, se definidos
|
||||
if rule.source_ip:
|
||||
@ -41,19 +89,24 @@ def generate_iptable_rules():
|
||||
|
||||
for protocol in protocols:
|
||||
for source in source_addresses:
|
||||
for destination in destination_addresses:
|
||||
if source and "Missing IP for selected peer:" in source:
|
||||
description = f" - {rule.description}" if rule.description else ""
|
||||
comment = f"\n# {rule.sort_order} - {rule.uuid}{description}"
|
||||
# Pula a geração de regra se um dos peers estiver faltando IP e for relevante para essa combinação
|
||||
if (source is None and source_missing_ip) or (destination is None and destination_missing_ip):
|
||||
iptables_rule = f"{comment} - Missing ip for selected peer\n"
|
||||
iptables_rules.append(iptables_rule)
|
||||
iptables_rules.append(f"# {rule.sort_order} - {rule.uuid}{description} - {source}\n")
|
||||
continue
|
||||
|
||||
for destination in destination_addresses:
|
||||
if destination and "Missing IP for selected peer:" in destination:
|
||||
description = f" - {rule.description}" if rule.description else ""
|
||||
iptables_rules.append(f"# {rule.sort_order} - {rule.uuid}{description} - {destination}\n")
|
||||
continue
|
||||
comment += '\n'
|
||||
|
||||
description = f" - {rule.description}" if rule.description else ""
|
||||
comment = f"# {rule.sort_order} - {rule.uuid}{description}\n"
|
||||
|
||||
if rule.firewall_chain == "forward":
|
||||
rule_base = "iptables -t filter -A FORWARD "
|
||||
rule_base = "iptables -t filter -A WGWADM_FORWARD "
|
||||
elif rule.firewall_chain == "postrouting":
|
||||
rule_base = "iptables -t nat -A POSTROUTING "
|
||||
rule_base = "iptables -t nat -A WGWADM_POSTROUTING "
|
||||
else:
|
||||
rule_base = f"#iptables -A {rule.firewall_chain.upper()} "
|
||||
rule_protocol = f"-p {protocol} " if protocol else ""
|
||||
@ -61,6 +114,8 @@ def generate_iptable_rules():
|
||||
rule_source = f"-s {source} " if source else ""
|
||||
rule_destination = f"-d {destination} " if destination else ""
|
||||
rule_action = f"-j {rule.rule_action.upper()}"
|
||||
rule_in_interface = f"-i {rule.in_interface} " if rule.in_interface else ""
|
||||
rule_out_interface = f"-o {rule.out_interface} " if rule.out_interface else ""
|
||||
|
||||
states = []
|
||||
if rule.state_new:
|
||||
@ -80,9 +135,83 @@ def generate_iptable_rules():
|
||||
not_source = "! " if rule.not_source and source else ""
|
||||
not_destination = "! " if rule.not_destination and destination else ""
|
||||
|
||||
|
||||
iptables_rule = f"{comment}{rule_base}{not_source}{rule_source}{not_destination}{rule_destination}{rule_state}{rule_protocol}{rule_destination_port}{rule_action}\n"
|
||||
iptables_rule = f"{comment}{rule_base}{rule_in_interface}{rule_out_interface}{not_source}{rule_source}{not_destination}{rule_destination}{rule_state}{rule_protocol}{rule_destination_port}{rule_action}\n"
|
||||
iptables_rules.append(iptables_rule)
|
||||
|
||||
return "".join(iptables_rules)
|
||||
|
||||
|
||||
def generate_firewall_header():
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
header = f'''#!/bin/bash
|
||||
# Description: Firewall rules for WireGuard_WebAdmin
|
||||
# Do not edit this file directly. Use the web interface to manage firewall rules.
|
||||
#
|
||||
# This script was generated by WireGuard_WebAdmin on {timezone.now().strftime('%Y-%m-%d %H:%M:%S %Z')}
|
||||
#
|
||||
|
||||
iptables -t nat -N WGWADM_POSTROUTING >> /dev/null 2>&1
|
||||
iptables -t nat -N WGWADM_PREROUTING >> /dev/null 2>&1
|
||||
iptables -t filter -N WGWADM_FORWARD >> /dev/null 2>&1
|
||||
|
||||
iptables -t nat -F WGWADM_POSTROUTING
|
||||
iptables -t nat -F WGWADM_PREROUTING
|
||||
iptables -t filter -F WGWADM_FORWARD
|
||||
|
||||
iptables -t nat -D POSTROUTING -j WGWADM_POSTROUTING >> /dev/null 2>&1
|
||||
iptables -t nat -D PREROUTING -j WGWADM_PREROUTING >> /dev/null 2>&1
|
||||
iptables -t filter -D FORWARD -j WGWADM_FORWARD >> /dev/null 2>&1
|
||||
|
||||
iptables -t nat -I POSTROUTING -j WGWADM_POSTROUTING
|
||||
iptables -t nat -I PREROUTING -j WGWADM_PREROUTING
|
||||
iptables -t filter -I FORWARD -j WGWADM_FORWARD
|
||||
'''
|
||||
|
||||
|
||||
return header
|
||||
|
||||
def generate_firewall_footer():
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
footer = '# The following rules come from Firewall settings\n'
|
||||
footer += '# Default FORWARD policy\n'
|
||||
footer += f'iptables -t filter -P FORWARD {firewall_settings.default_forward_policy.upper()}\n'
|
||||
|
||||
footer += '# Same instance Peer to Peer traffic\n'
|
||||
for wireguard_instance in WireGuardInstance.objects.all().order_by('instance_id'):
|
||||
footer += f'iptables -t filter -A WGWADM_FORWARD -i wg{wireguard_instance.instance_id} -o wg{wireguard_instance.instance_id} -j '
|
||||
footer += 'ACCEPT\n' if firewall_settings.allow_peer_to_peer else "REJECT\n"
|
||||
footer += '# Instance to Instance traffic\n'
|
||||
footer += 'iptables -t filter -A WGWADM_FORWARD -i wg+ -o wg+ -j '
|
||||
footer += 'ACCEPT\n' if firewall_settings.allow_instance_to_instance else "REJECT\n"
|
||||
return footer
|
||||
|
||||
|
||||
def generate_port_forward_firewall():
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
redirect_firewall = ''
|
||||
wan_interface = firewall_settings.wan_interface
|
||||
|
||||
for redirect_rule in RedirectRule.objects.all().order_by('port'):
|
||||
description = f" - {redirect_rule.description} " if redirect_rule.description else ""
|
||||
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()
|
||||
if peer_allowed_ip_address:
|
||||
rule_destination = peer_allowed_ip_address.allowed_ip
|
||||
if rule_destination:
|
||||
rule_text = f"# {redirect_rule.port}/{redirect_rule.protocol} - {redirect_rule.uuid} - Port Forward Rule set{description}\n"
|
||||
rule_text += f"iptables -t nat -A WGWADM_PREROUTING -p {redirect_rule.protocol} -d wireguard-webadmin -i {wan_interface} --dport {redirect_rule.port} -j DNAT --to-dest {rule_destination}:{redirect_rule.port}\n"
|
||||
|
||||
if redirect_rule.masquerade_source:
|
||||
rule_text += f"iptables -t nat -A WGWADM_POSTROUTING -p {redirect_rule.protocol} -d {rule_destination} -o wg+ --dport {redirect_rule.port} -j MASQUERADE\n"
|
||||
|
||||
if redirect_rule.add_forward_rule:
|
||||
rule_text += f"iptables -t filter -A WGWADM_FORWARD -p {redirect_rule.protocol} -d {rule_destination} -i {wan_interface} -o wg+ --dport {redirect_rule.port} -j ACCEPT\n"
|
||||
|
||||
redirect_firewall += rule_text
|
||||
|
||||
else:
|
||||
rule_text = f"# {redirect_rule.port}/{redirect_rule.protocol} - {redirect_rule.uuid} - Port Forward Rule set{description} - Missing IP for selected peer: {redirect_rule.peer}\n"
|
||||
redirect_firewall += rule_text
|
||||
|
||||
return redirect_firewall
|
@ -6,11 +6,16 @@ from firewall.forms import RedirectRuleForm, FirewallRuleForm, FirewallSettingsF
|
||||
from django.contrib import messages
|
||||
from wireguard.models import WireGuardInstance
|
||||
from user_manager.models import UserAcl
|
||||
from firewall.tools import generate_iptable_rules
|
||||
from firewall.tools import export_user_firewall, generate_firewall_header, generate_firewall_footer, generate_port_forward_firewall, reset_firewall_to_default
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
@login_required
|
||||
def view_redirect_rule_list(request):
|
||||
wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id')
|
||||
if wireguard_instances.filter(legacy_firewall=True).exists():
|
||||
return redirect('/firewall/migration_required/')
|
||||
if wireguard_instances.filter(pending_changes=True).exists():
|
||||
pending_changes_warning = True
|
||||
else:
|
||||
@ -24,6 +29,7 @@ def view_redirect_rule_list(request):
|
||||
return render(request, 'firewall/redirect_rule_list.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
def manage_redirect_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'})
|
||||
@ -59,8 +65,11 @@ def manage_redirect_rule(request):
|
||||
return render(request, 'firewall/manage_redirect_rule.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
def view_firewall_rule_list(request):
|
||||
wireguard_instances = WireGuardInstance.objects.all().order_by('instance_id')
|
||||
if wireguard_instances.filter(legacy_firewall=True).exists():
|
||||
return redirect('/firewall/migration_required/')
|
||||
firewall_settings, firewall_settings_created = FirewallSettings.objects.get_or_create(name='global')
|
||||
current_chain = request.GET.get('chain', 'forward')
|
||||
if current_chain not in ['forward', 'portforward', 'postrouting']:
|
||||
@ -81,6 +90,7 @@ def view_firewall_rule_list(request):
|
||||
return render(request, 'firewall/firewall_rule_list.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
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'})
|
||||
@ -96,6 +106,12 @@ def manage_firewall_rule(request):
|
||||
firewall_settings.pending_changes = True
|
||||
firewall_settings.save()
|
||||
instance.delete()
|
||||
# Marking wireguard_instance as having pending changes, not the best way to do this, but it works for now.
|
||||
# I will improve it later.
|
||||
wireguard_instance = WireGuardInstance.objects.all().first()
|
||||
if wireguard_instance:
|
||||
wireguard_instance.pending_changes = True
|
||||
wireguard_instance.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.')
|
||||
@ -111,6 +127,12 @@ def manage_firewall_rule(request):
|
||||
firewall_settings.save()
|
||||
form.save()
|
||||
messages.success(request, 'Firewall rule saved successfully')
|
||||
# Marking wireguard_instance as having pending changes, not the best way to do this, but it works for now.
|
||||
# I will improve it later.
|
||||
wireguard_instance = WireGuardInstance.objects.all().first()
|
||||
if wireguard_instance:
|
||||
wireguard_instance.pending_changes = True
|
||||
wireguard_instance.save()
|
||||
return redirect('/firewall/rule_list/?chain=' + current_chain)
|
||||
else:
|
||||
form = FirewallRuleForm(instance=instance, current_chain=current_chain)
|
||||
@ -132,6 +154,7 @@ def manage_firewall_rule(request):
|
||||
return render(request, 'firewall/manage_firewall_rule.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
def view_manage_firewall_settings(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'})
|
||||
@ -162,12 +185,39 @@ def view_manage_firewall_settings(request):
|
||||
return render(request, 'firewall/manage_firewall_settings.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
def view_generate_iptables_script(request):
|
||||
data = {'status': 'ok'}
|
||||
firewall_rule_list = FirewallRule.objects.all().order_by('firewall_chain', 'sort_order')
|
||||
for rule in firewall_rule_list:
|
||||
print(str(rule.sort_order) + ' - ' + str(rule.uuid))
|
||||
|
||||
rules_text = generate_iptable_rules()
|
||||
print(rules_text)
|
||||
#firewall_header = generate_firewall_header()
|
||||
#port_forward_firewall = generate_port_forward_firewall()
|
||||
#user_firewall = export_user_firewall()
|
||||
#firewall_footer = generate_firewall_footer()
|
||||
#print(port_forward_firewall)
|
||||
#print(firewall_header)
|
||||
#print(user_firewall)
|
||||
#print(firewall_footer)
|
||||
|
||||
return JsonResponse(data)
|
||||
|
||||
|
||||
@login_required
|
||||
def view_reset_firewall(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'})
|
||||
if request.GET.get('confirmation') == 'delete all rules and reset firewall':
|
||||
reset_firewall_to_default()
|
||||
messages.success(request, 'VPN Firewall|Firewall reset to default successfully!')
|
||||
else:
|
||||
messages.warning(request, 'VPN Firewall|Firewall was not reset to default. Confirmation did not match.')
|
||||
return redirect('/firewall/rule_list/')
|
||||
|
||||
|
||||
@login_required
|
||||
def view_firewall_migration_required(request):
|
||||
if not WireGuardInstance.objects.filter(legacy_firewall=True).exists():
|
||||
messages.warning(request, 'No Firewall Migration pending|No WireGuard instances with legacy firewall settings found.')
|
||||
return redirect('/firewall/rule_list/')
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=40).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||
|
||||
return render(request, 'firewall/firewall_migration_required.html')
|
47
templates/firewall/firewall_migration_required.html
Normal file
47
templates/firewall/firewall_migration_required.html
Normal file
@ -0,0 +1,47 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title>">Firewall migration required</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
I've upgraded our firewall's functionality. The new configuration tool enhances flexibility and power, granting complete control over your firewall via the web interface.<br><br>
|
||||
|
||||
Please note down your PostUp and PostDown rules before migrating; they will be erased in the process.<br><br>
|
||||
|
||||
Although the migration tool establishes a default rule set, you will have to manually input your specific rules.
|
||||
|
||||
</p>
|
||||
<div class="card-footer">
|
||||
|
||||
<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>Reset firewall to default</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_page_scripts %}
|
||||
|
||||
<script>
|
||||
function openCommandDialog(element) {
|
||||
var command = element.getAttribute('data-command');
|
||||
var confirmation = prompt("Reseting the firewall to default will remove all rules and settings. Are you sure you want to continue?\n\nType 'delete all rules and reset firewall' to confirm. ");
|
||||
if (confirmation) {
|
||||
var url = "/firewall/reset_to_default/?confirmation=" + encodeURIComponent(confirmation);
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
@ -58,6 +58,7 @@
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<a class="btn btn-outline-secondary" href="{{ back_url }}">Back</a>
|
||||
<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>Reset firewall to default</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -66,4 +67,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_page_scripts %}
|
||||
|
||||
<script>
|
||||
function openCommandDialog(element) {
|
||||
var command = element.getAttribute('data-command');
|
||||
var confirmation = prompt("Reseting the firewall to default will remove all rules and settings. Are you sure you want to continue?\n\nType 'delete all rules and reset firewall' to confirm. ");
|
||||
if (confirmation) {
|
||||
var url = "/firewall/reset_to_default/?confirmation=" + encodeURIComponent(confirmation);
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
@ -103,12 +103,12 @@
|
||||
<!-- Line 1: Post Up -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.post_up.id_for_label }}">{{ form.post_up.label }}</label>
|
||||
<textarea class="form-control" id="{{ form.post_up.id_for_label }}" name="{{ form.post_up.html_name }}" placeholder="Post Up" style="height: 150px;">{{ form.post_up.value|default_if_none:'' }}</textarea>
|
||||
<textarea class="form-control" id="{{ form.post_up.id_for_label }}" name="{{ form.post_up.html_name }}" placeholder="Post Up" style="height: 150px;" readonly>{{ form.post_up.value|default_if_none:'' }}</textarea>
|
||||
</div>
|
||||
<!-- Line 2: Post Down -->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.post_down.id_for_label }}">{{ form.post_down.label }}</label>
|
||||
<textarea class="form-control" id="{{ form.post_down.id_for_label }}" name="{{ form.post_down.html_name }}" placeholder="Post Down" style="height: 150px;">{{ form.post_down.value|default_if_none:'' }}</textarea>
|
||||
<textarea class="form-control" id="{{ form.post_down.id_for_label }}" name="{{ form.post_down.html_name }}" placeholder="Post Down" style="height: 150px;" readonly>{{ form.post_down.value|default_if_none:'' }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -124,6 +124,14 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block custom_page_scripts %}
|
||||
<script>
|
||||
function openCommandDialog(element) {
|
||||
var command = element.getAttribute('data-command');
|
||||
@ -133,40 +141,6 @@
|
||||
window.location.href = url;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block custom_page_scripts %}
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var alertShown = false;
|
||||
var fieldsToWatch = ['id_address', 'id_listen_port', 'id_instance_id', 'netmask'];
|
||||
function showAlert() {
|
||||
if (!alertShown) {
|
||||
$(document).Toasts('create', {
|
||||
class: 'bg-warning',
|
||||
title: 'Action Required!',
|
||||
body: 'When manually updating the "IP Address", "Netmask", "Listen Port", or "Instance ID", it is essential that you also manually review and update the "PostUp" and "PostDown" scripts to ensure that the new configuration matches your firewall.',
|
||||
|
||||
});
|
||||
alertShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fieldsToWatch.forEach(function(fieldId) {
|
||||
var field = document.getElementById(fieldId);
|
||||
if (field) {
|
||||
field.addEventListener('change', showAlert);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -30,6 +30,9 @@ class WireGuardInstanceForm(forms.ModelForm):
|
||||
hostname = cleaned_data.get('hostname')
|
||||
address = cleaned_data.get('address')
|
||||
netmask = cleaned_data.get('netmask')
|
||||
post_up = cleaned_data.get('post_up')
|
||||
post_down = cleaned_data.get('post_down')
|
||||
|
||||
peer_list_refresh_interval = cleaned_data.get('peer_list_refresh_interval')
|
||||
if peer_list_refresh_interval < 10:
|
||||
raise forms.ValidationError('Peer List Refresh Interval must be at least 10 seconds')
|
||||
@ -46,5 +49,13 @@ class WireGuardInstanceForm(forms.ModelForm):
|
||||
if current_network.overlaps(other_network):
|
||||
raise forms.ValidationError(f"The network range {current_network} overlaps with another instance's network range {other_network}.")
|
||||
|
||||
#if self.instance:
|
||||
# if post_up or post_down:
|
||||
# if self.instance.post_up != post_up or self.instance.post_down != post_down:
|
||||
# raise forms.ValidationError('Post Up and Post Down cannot be changed, please go to Firewall page to make changes to the firewall.')
|
||||
#else:
|
||||
# if post_up or post_down:
|
||||
# raise forms.ValidationError('Post Up and Post Down cannot be set, please go to Firewall page to make changes to the firewall.')
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-03-04 12:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wireguard', '0018_wireguardinstance_legacy_firewall'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='wireguardinstance',
|
||||
name='legacy_firewall',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
@ -59,7 +59,7 @@ class WireGuardInstance(models.Model):
|
||||
dns_primary = models.GenericIPAddressField(unique=False, protocol='IPv4', default='1.1.1.1')
|
||||
dns_secondary = models.GenericIPAddressField(unique=False, protocol='IPv4', default='1.0.0.1', blank=True, null=True)
|
||||
pending_changes = models.BooleanField(default=True)
|
||||
legacy_firewall = models.BooleanField(default=True)
|
||||
legacy_firewall = models.BooleanField(default=False)
|
||||
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
@ -31,25 +31,27 @@ def generate_instance_defaults():
|
||||
instance_id = new_instance_id
|
||||
interface_name = f"wg{instance_id}"
|
||||
|
||||
post_up_script = (
|
||||
f"iptables -t nat -A POSTROUTING -s {network} -o eth0 -j MASQUERADE\n"
|
||||
f"iptables -A INPUT -p udp -m udp --dport {port} -j ACCEPT\n"
|
||||
f"iptables -A FORWARD -i {interface_name} -o eth0 -d 10.0.0.0/8 -j REJECT\n"
|
||||
f"iptables -A FORWARD -i {interface_name} -o eth0 -d 172.16.0.0/12 -j REJECT\n"
|
||||
f"iptables -A FORWARD -i {interface_name} -o eth0 -d 192.168.0.0/16 -j REJECT\n"
|
||||
f"iptables -A FORWARD -i {interface_name} -j ACCEPT\n"
|
||||
f"iptables -A FORWARD -o {interface_name} -j ACCEPT"
|
||||
)
|
||||
#post_up_script = (
|
||||
# f"iptables -t nat -A POSTROUTING -s {network} -o eth0 -j MASQUERADE\n"
|
||||
# f"iptables -A INPUT -p udp -m udp --dport {port} -j ACCEPT\n"
|
||||
# f"iptables -A FORWARD -i {interface_name} -o eth0 -d 10.0.0.0/8 -j REJECT\n"
|
||||
# f"iptables -A FORWARD -i {interface_name} -o eth0 -d 172.16.0.0/12 -j REJECT\n"
|
||||
# f"iptables -A FORWARD -i {interface_name} -o eth0 -d 192.168.0.0/16 -j REJECT\n"
|
||||
# f"iptables -A FORWARD -i {interface_name} -j ACCEPT\n"
|
||||
# f"iptables -A FORWARD -o {interface_name} -j ACCEPT"
|
||||
#)
|
||||
|
||||
post_down_script = (
|
||||
f"iptables -t nat -D POSTROUTING -s {network} -o eth0 -j MASQUERADE\n"
|
||||
f"iptables -D INPUT -p udp -m udp --dport {port} -j ACCEPT\n"
|
||||
f"iptables -D FORWARD -i {interface_name} -o eth0 -d 10.0.0.0/8 -j REJECT\n"
|
||||
f"iptables -D FORWARD -i {interface_name} -o eth0 -d 172.16.0.0/12 -j REJECT\n"
|
||||
f"iptables -D FORWARD -i {interface_name} -o eth0 -d 192.168.0.0/16 -j REJECT\n"
|
||||
f"iptables -D FORWARD -i {interface_name} -j ACCEPT\n"
|
||||
f"iptables -D FORWARD -o {interface_name} -j ACCEPT"
|
||||
)
|
||||
#post_down_script = (
|
||||
# f"iptables -t nat -D POSTROUTING -s {network} -o eth0 -j MASQUERADE\n"
|
||||
# f"iptables -D INPUT -p udp -m udp --dport {port} -j ACCEPT\n"
|
||||
# f"iptables -D FORWARD -i {interface_name} -o eth0 -d 10.0.0.0/8 -j REJECT\n"
|
||||
# f"iptables -D FORWARD -i {interface_name} -o eth0 -d 172.16.0.0/12 -j REJECT\n"
|
||||
# f"iptables -D FORWARD -i {interface_name} -o eth0 -d 192.168.0.0/16 -j REJECT\n"
|
||||
# f"iptables -D FORWARD -i {interface_name} -j ACCEPT\n"
|
||||
# f"iptables -D FORWARD -o {interface_name} -j ACCEPT"
|
||||
#)
|
||||
post_up_script = ''
|
||||
post_down_script = ''
|
||||
|
||||
return {
|
||||
'name': '',
|
||||
|
@ -4,6 +4,7 @@ import qrcode
|
||||
import subprocess
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect, get_object_or_404, render
|
||||
from firewall.tools import generate_firewall_header, generate_firewall_footer, generate_port_forward_firewall, export_user_firewall
|
||||
from user_manager.models import UserAcl
|
||||
from wireguard.models import WireGuardInstance, Peer, PeerAllowedIP
|
||||
from firewall.models import RedirectRule
|
||||
@ -46,6 +47,19 @@ def generate_peer_config(peer_uuid):
|
||||
]
|
||||
return "\n".join(config_lines)
|
||||
|
||||
|
||||
def export_firewall_configuration():
|
||||
firewall_content = generate_firewall_header()
|
||||
firewall_content += generate_port_forward_firewall()
|
||||
firewall_content += export_user_firewall()
|
||||
firewall_content += generate_firewall_footer()
|
||||
firewall_path = "/etc/wireguard/wg-firewall.sh"
|
||||
with open(firewall_path, "w") as firewall_file:
|
||||
firewall_file.write(firewall_content)
|
||||
subprocess.run(['chmod', '+x', firewall_path], check=True)
|
||||
return
|
||||
|
||||
|
||||
@login_required
|
||||
def export_wireguard_configs(request):
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||
@ -53,35 +67,50 @@ def export_wireguard_configs(request):
|
||||
instances = WireGuardInstance.objects.all()
|
||||
base_dir = "/etc/wireguard"
|
||||
|
||||
export_firewall_configuration()
|
||||
|
||||
firewall_inserted = False
|
||||
for instance in instances:
|
||||
post_up_processed = clean_command_field(instance.post_up) if instance.post_up else ""
|
||||
post_down_processed = clean_command_field(instance.post_down) if instance.post_down else ""
|
||||
|
||||
if post_up_processed:
|
||||
post_up_processed += '; '
|
||||
if post_down_processed:
|
||||
post_down_processed += '; '
|
||||
if instance.legacy_firewall:
|
||||
post_up_processed = clean_command_field(instance.post_up) if instance.post_up else ""
|
||||
post_down_processed = clean_command_field(instance.post_down) if instance.post_down else ""
|
||||
|
||||
if post_up_processed:
|
||||
post_up_processed += '; '
|
||||
if post_down_processed:
|
||||
post_down_processed += '; '
|
||||
|
||||
for redirect_rule in RedirectRule.objects.filter(wireguard_instance=instance):
|
||||
rule_text_up = ""
|
||||
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()
|
||||
if peer_allowed_ip_address:
|
||||
rule_destination = peer_allowed_ip_address.allowed_ip
|
||||
if rule_destination:
|
||||
rule_text_up = f"iptables -t nat -A PREROUTING -p {redirect_rule.protocol} -d wireguard-webadmin --dport {redirect_rule.port} -j DNAT --to-dest {rule_destination}:{redirect_rule.port} ; "
|
||||
rule_text_down = f"iptables -t nat -D PREROUTING -p {redirect_rule.protocol} -d wireguard-webadmin --dport {redirect_rule.port} -j DNAT --to-dest {rule_destination}:{redirect_rule.port} ; "
|
||||
if redirect_rule.add_forward_rule:
|
||||
rule_text_up += f"iptables -A FORWARD -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j ACCEPT ; "
|
||||
rule_text_down += f"iptables -D FORWARD -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j ACCEPT ; "
|
||||
if redirect_rule.masquerade_source:
|
||||
rule_text_up += f"iptables -t nat -A POSTROUTING -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j MASQUERADE ; "
|
||||
rule_text_down += f"iptables -t nat -D POSTROUTING -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j MASQUERADE ; "
|
||||
post_up_processed += rule_text_up
|
||||
post_down_processed += rule_text_down
|
||||
|
||||
pass
|
||||
else:
|
||||
post_down_processed = ''
|
||||
|
||||
if not firewall_inserted:
|
||||
post_up_processed = '/etc/wireguard/wg-firewall.sh'
|
||||
firewall_inserted = True
|
||||
else:
|
||||
post_up_processed = ''
|
||||
|
||||
|
||||
for redirect_rule in RedirectRule.objects.filter(wireguard_instance=instance):
|
||||
rule_text_up = ""
|
||||
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()
|
||||
if peer_allowed_ip_address:
|
||||
rule_destination = peer_allowed_ip_address.allowed_ip
|
||||
if rule_destination:
|
||||
rule_text_up = f"iptables -t nat -A PREROUTING -p {redirect_rule.protocol} -d wireguard-webadmin --dport {redirect_rule.port} -j DNAT --to-dest {rule_destination}:{redirect_rule.port} ; "
|
||||
rule_text_down = f"iptables -t nat -D PREROUTING -p {redirect_rule.protocol} -d wireguard-webadmin --dport {redirect_rule.port} -j DNAT --to-dest {rule_destination}:{redirect_rule.port} ; "
|
||||
if redirect_rule.add_forward_rule:
|
||||
rule_text_up += f"iptables -A FORWARD -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j ACCEPT ; "
|
||||
rule_text_down += f"iptables -D FORWARD -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j ACCEPT ; "
|
||||
if redirect_rule.masquerade_source:
|
||||
rule_text_up += f"iptables -t nat -A POSTROUTING -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j MASQUERADE ; "
|
||||
rule_text_down += f"iptables -t nat -D POSTROUTING -d {rule_destination} -p {redirect_rule.protocol} --dport {redirect_rule.port} -j MASQUERADE ; "
|
||||
post_up_processed += rule_text_up
|
||||
post_down_processed += rule_text_down
|
||||
|
||||
config_lines = [
|
||||
"[Interface]",
|
||||
f"PrivateKey = {instance.private_key}",
|
||||
|
@ -23,7 +23,7 @@ from user_manager.views import view_user_list, view_manage_user
|
||||
from accounts.views import view_create_first_user, view_login, view_logout
|
||||
from wireguard_tools.views import export_wireguard_configs, download_config_or_qrcode, restart_wireguard_interfaces
|
||||
from api.views import wireguard_status, cron_check_updates, cron_update_peer_latest_handshake
|
||||
from firewall.views import view_redirect_rule_list, manage_redirect_rule, view_firewall_rule_list, manage_firewall_rule, view_manage_firewall_settings, view_generate_iptables_script
|
||||
from firewall.views import view_redirect_rule_list, manage_redirect_rule, view_firewall_rule_list, manage_firewall_rule, view_manage_firewall_settings, view_generate_iptables_script, view_reset_firewall, view_firewall_migration_required
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
@ -52,4 +52,6 @@ urlpatterns = [
|
||||
path('firewall/manage_firewall_rule/', manage_firewall_rule, name='manage_firewall_rule'),
|
||||
path('firewall/firewall_settings/', view_manage_firewall_settings, name='firewall_settings'),
|
||||
path('firewall/generate_firewall_script/', view_generate_iptables_script, name='generate_iptables_script'),
|
||||
path('firewall/reset_to_default/', view_reset_firewall, name='reset_firewall'),
|
||||
path('firewall/migration_required/', view_firewall_migration_required, name='firewall_migration_required')
|
||||
]
|
||||
|
Loading…
x
Reference in New Issue
Block a user