Legacy firewall migrate routines and export fw rules.

This commit is contained in:
Eduardo Silva 2024-03-04 12:58:33 -03:00
parent de073a4795
commit b6a7cdaac9
14 changed files with 406 additions and 112 deletions

View File

@ -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)

View File

@ -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),
),
]

View File

@ -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)

View File

@ -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

View File

@ -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')

View 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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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

View File

@ -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),
),
]

View File

@ -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)

View File

@ -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': '',

View File

@ -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}",

View File

@ -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')
]