#!/usr/bin/perl
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2024 Michael Tremer #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see . #
# #
###############################################################################
use strict;
# enable only the following on debugging purpose
use warnings;
use CGI::Carp 'fatalsToBrowser';
use Imager::QRCode;
use MIME::Base64;
require "/var/ipfire/general-functions.pl";
require "${General::swroot}/header.pl";
require "${General::swroot}/location-functions.pl";
require "${General::swroot}/wireguard-functions.pl";
my %cgiparams = ();
my @errormessages = ();
# Generate keys
&Wireguard::generate_keys();
# Fetch CGI parameters
&Header::getcgihash(\%cgiparams, {'wantfile' => 1, 'filevar' => 'FH'});
# Save on main page
if ($cgiparams{"ACTION"} eq $Lang::tr{'save'}) {
my @client_dns = ();
# Store whether enabled or not
if ($cgiparams{'ENABLED'} =~ m/^(on|off)?$/) {
$Wireguard::settings{'ENABLED'} = $cgiparams{'ENABLED'};
}
# Check endpoint
if (&General::validfqdn($cgiparams{'ENDPOINT'}) || &Network::check_ip_address($cgiparams{'ENDPOINT'}) || ($cgiparams{'ENDPOINT'} eq '')) {
$Wireguard::settings{'ENDPOINT'} = $cgiparams{'ENDPOINT'};
} else {
push(@errormessages, $Lang::tr{'invalid endpoint'});
}
# Check port
if (&General::validport($cgiparams{'PORT'})) {
$Wireguard::settings{'PORT'} = $cgiparams{'PORT'};
} else {
push(@errormessages, $Lang::tr{'invalid port'});
}
# Check client pool
if (&Wireguard::pool_is_in_use($Wireguard::settings{'CLIENT_POOL'})) {
# Ignore any changes if the pool is in use
} elsif (&Network::check_subnet($cgiparams{'CLIENT_POOL'})) {
$Wireguard::settings{'CLIENT_POOL'} = &Network::normalize_network($cgiparams{'CLIENT_POOL'});
} elsif ($cgiparams{'CLIENT_POOL'} ne '') {
push(@errormessages, $Lang::tr{'wg invalid client pool'});
}
# Check client DNS
if (defined $cgiparams{'CLIENT_DNS'}) {
@client_dns = split(/,/, $cgiparams{'CLIENT_DNS'});
foreach my $dns (@client_dns) {
unless (&Network::check_ip_address($dns)) {
push(@errormessages, "$Lang::tr{'wg invalid client dns'}: ${dns}");
}
}
# Store CLIENT_DNS
$Wireguard::settings{'CLIENT_DNS'} = join("|", @client_dns);
}
# Don't continue on error
goto MAIN if (scalar @errormessages);
# Store the configuration file
&General::writehash("/var/ipfire/wireguard/settings", \%Wireguard::settings);
# Start if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
} else {
&General::system("/usr/local/bin/wireguardctrl", "stop");
}
# Delete an existing peer
} elsif ($cgiparams{"ACTION"} eq $Lang::tr{'remove'}) {
my $key = $cgiparams{'KEY'};
# Fail if the peer does not exist
unless (exists $Wireguard::peers{$key}) {
push(@errormessages, $Lang::tr{'wg peer does not exist'});
goto MAIN;
}
# Delete the peer
delete($Wireguard::peers{$key});
# Store the configuration
&General::writehasharray("/var/ipfire/wireguard/peers", \%Wireguard::peers);
# Reload if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
}
# Edit an existing peer
} elsif ($cgiparams{"ACTION"} eq $Lang::tr{'edit'}) {
my $key = $cgiparams{'KEY'};
# Fail if the peer does not exist
unless (exists $Wireguard::peers{$key}) {
push(@errormessages, $Lang::tr{'wg peer does not exist'});
goto MAIN;
}
# Fetch type
my $type = $Wireguard::peers{$key}[1];
my $remote_subnets = &Wireguard::decode_subnets($Wireguard::peers{$key}[8]);
my $local_subnets = &Wireguard::decode_subnets($Wireguard::peers{$key}[10]);
# Flush CGI parameters & load configuration
%cgiparams = (
"KEY" => $key,
"ENABLED" => $Wireguard::peers{$key}[0],
"TYPE" => $Wireguard::peers{$key}[1],
"NAME" => $Wireguard::peers{$key}[2],
"PUBLIC_KEY" => $Wireguard::peers{$key}[3],
"PRIVATE_KEY" => $Wireguard::peers{$key}[4],
"PORT" => $Wireguard::peers{$key}[5],
"ENDPOINT_ADDRESS" => $Wireguard::peers{$key}[6],
"ENDPOINT_PORT" => $Wireguard::peers{$key}[7],
"REMOTE_SUBNETS" => join(", ", @$remote_subnets),
"REMARKS" => &MIME::Base64::decode_base64($Wireguard::peers{$key}[9]),
"LOCAL_SUBNETS" => join(", ", @$local_subnets),
"PSK" => $Wireguard::peers{$key}[11],
"KEEPALIVE" => $Wireguard::peers{$key}[12],
"LOCAL_ADDRESS" => $Wireguard::peers{$key}[13],
);
# Jump to the editor
if ($type eq "host") {
goto EDITHOST;
} elsif ($type eq "net") {
goto EDITNET;
} else {
die "Unsupported type: $type";
}
} elsif ($cgiparams{"ACTION"} eq "IMPORT") {
my @local_subnets = ();
my $peer;
# Parse the configuration file
($peer, @errormessages) = &Wireguard::parse_configuration($cgiparams{'NAME'}, $cgiparams{'FH'});
# Check local subnets
if (defined $cgiparams{'LOCAL_SUBNETS'}) {
@local_subnets = split(/,/, $cgiparams{'LOCAL_SUBNETS'});
foreach my $subnet (@local_subnets) {
$subnet =~ s/^\s+//g;
$subnet =~ s/\s+$//g;
unless (&Network::check_subnet($subnet)) {
push(@errormessages, $Lang::tr{'wg invalid local subnet'} . ": ${subnet}");
}
}
} else {
push(@errormessages, $Lang::tr{'wg no local subnets'});
}
# Show any error messages
goto IMPORT if (@errormessages);
# Allocate a new key
my $key = &General::findhasharraykey(\%Wireguard::peers);
# Save the connection
$Wireguard::peers{$key} = [
# 0 = Enabled
"on",
# 1 = Type
"net",
# 2 = Name
$peer->{"NAME"},
# 3 = Remote Public Key
$peer->{"PUBLIC_KEY"},
# 4 = Local Private Key
$peer->{"PRIVATE_KEY"},
# 5 = Port
$peer->{"PORT"},
# 6 = Endpoint Address
$peer->{"ENDPOINT_ADDRESS"},
# 7 = Endpoint Port
$peer->{"ENDPOINT_PORT"},
# 8 = Remote Subnets
&Wireguard::encode_subnets(@{ $peer->{"REMOTE_SUBNETS"} }),
# 9 = Remark
&Wireguard::encode_remarks($cgiparams{"REMARKS"}),
# 10 = Local Subnets
&Wireguard::encode_subnets(@local_subnets),
# 11 = PSK
$peer->{"PSK"},
# 12 = Keepalive
$peer->{"KEEPALIVE"} || $Wireguard::DEFAULT_KEEPALIVE,
# 13 = Local Address
$peer->{"LOCAL_ADDRESS"},
];
# Store the configuration
&General::writehasharray("/var/ipfire/wireguard/peers", \%Wireguard::peers);
# Reload if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
}
} elsif ($cgiparams{"ACTION"} eq "CREATE-PEER-NET") {
my @local_subnets = ();
my @remote_subnets = ();
# Allocate a new key
my $key = &General::findhasharraykey(\%Wireguard::peers);
my $name = $cgiparams{"NAME"};
# Check if the name is valid
unless (&Wireguard::name_is_valid($name)) {
push(@errormessages, $Lang::tr{'wg invalid name'});
}
# Check if the name is free
unless (&Wireguard::name_is_free($name, $key)) {
push(@errormessages, $Lang::tr{'wg name is already used'});
}
# Check the endpoint address
if ($cgiparams{'ENDPOINT_ADDRESS'} eq '') {
# The endpoint address may be empty
} elsif (&General::validfqdn($cgiparams{'ENDPOINT_ADDRESS'})) {
# The endpoint is a valid FQDN
} elsif (&Network::check_ip_address($cgiparams{'ENDPOINT_ADDRESS'})) {
# The endpoint is a valid IP address
} else {
push(@errormessages, $Lang::tr{'wg invalid endpoint address'});
}
# Check local subnets
if (defined $cgiparams{'LOCAL_SUBNETS'}) {
@local_subnets = split(/,/, $cgiparams{'LOCAL_SUBNETS'});
foreach my $subnet (@local_subnets) {
$subnet =~ s/^\s+//g;
$subnet =~ s/\s+$//g;
unless (&Network::check_subnet($subnet)) {
push(@errormessages, $Lang::tr{'wg invalid local subnet'} . ": ${subnet}");
}
}
} else {
push(@errormessages, $Lang::tr{'wg no local subnets'});
}
# Check remote subnets
if (defined $cgiparams{'REMOTE_SUBNETS'}) {
@remote_subnets = split(/,/, $cgiparams{'REMOTE_SUBNETS'});
foreach my $subnet (@remote_subnets) {
$subnet =~ s/^\s+//g;
$subnet =~ s/\s+$//g;
unless (&Network::check_subnet($subnet)) {
push(@errormessages, $Lang::tr{'wg invalid remote subnet'} . ": ${subnet}");
}
}
} else {
push(@errormessages, $Lang::tr{'wg no remote subnets'});
}
# If there are any errors, we go back to the editor
goto CREATENET if (scalar @errormessages);
# Generate a new key pair
my $local_private_key = &Wireguard::generate_private_key();
my $remote_private_key = &Wireguard::generate_private_key();
# Derive the public key
my $remote_public_key = &Wireguard::derive_public_key($remote_private_key);
# Generate a new PSK
my $psk = &Wireguard::generate_private_key();
# Generate two new ports
my $local_port = &Wireguard::get_free_port();
my $remote_port = &Wireguard::get_free_port();
# Save the connection
$Wireguard::peers{$key} = [
# 0 = Enabled
"on",
# 1 = Type
"net",
# 2 = Name
$name,
# 3 = Remote Public Key
$remote_public_key,
# 4 = Local Private Key
$local_private_key,
# 5 = Port
$local_port,
# 6 = Endpoint Address
$cgiparams{"ENDPOINT_ADDRESS"},
# 7 = Endpoint Port
$remote_port,
# 8 = Remote Subnets
&Wireguard::encode_subnets(@remote_subnets),
# 9 = Remark
&Wireguard::encode_remarks($cgiparams{"REMARKS"}),
# 10 = Local Subnets
&Wireguard::encode_subnets(@local_subnets),
# 11 = PSK
$psk,
# 12 = Keepalive
$Wireguard::DEFAULT_KEEPALIVE,
# 13 = Local Address
"",
];
# Store the configuration
&General::writehasharray("/var/ipfire/wireguard/peers", \%Wireguard::peers);
# Reload if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
}
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Generate the client configuration
my $config = &Wireguard::generate_peer_configuration($key, $remote_private_key);
# Encode the configuration as Base64
$config = &MIME::Base64::encode_base64($config);
# Open a new box
&Header::openbox('100%', '', "$Lang::tr{'wg peer configuration'}: $name");
# Make the filename for files
my $filename = &Header::normalize("${name}.conf");
print <
$Lang::tr{'wg warning configuration only shown once'}
END
&Header::closebox();
&Header::closepage();
exit(0);
} elsif ($cgiparams{"ACTION"} eq "SAVE-PEER-NET") {
my @local_subnets = ();
my @remote_subnets = ();
# Fetch or allocate a new key
my $key = $cgiparams{'KEY'};
# Load the existing peer
my $peer = &Wireguard::load_peer($key);
# Fail if we don't have the key
unless (defined $peer) {
die "Peer $key does not exist\n";
}
# Check if the name is valid
unless (&Wireguard::name_is_valid($cgiparams{"NAME"})) {
push(@errormessages, $Lang::tr{'wg invalid name'});
}
# Check if the name is free
unless (&Wireguard::name_is_free($cgiparams{"NAME"}, $key)) {
push(@errormessages, $Lang::tr{'wg name is already used'});
}
# Check the public key
unless (&Wireguard::key_is_valid($cgiparams{'PUBLIC_KEY'})) {
push(@errormessages, $Lang::tr{'wg invalid public key'});
}
# Check PSK
if ($cgiparams{'PSK'} eq '') {
# The PSK may be empty
} elsif (!&Wireguard::key_is_valid($cgiparams{'PSK'})) {
push(@errormessages, $Lang::tr{'wg invalid psk'});
}
# Select a new random port if none given
if ($cgiparams{'PORT'} eq "") {
$cgiparams{'PORT'} = &Wireguard::get_free_port();
# If a port was given we check that it is valid
} elsif (!&General::validport($cgiparams{'PORT'})) {
push(@errormessages, $LANG::tr{'invalid port'});
}
# Check the endpoint address
if ($cgiparams{'ENDPOINT_ADDRESS'} eq '') {
# The endpoint address may be empty
} elsif (&General::validfqdn($cgiparams{'ENDPOINT_ADDRESS'})) {
# The endpoint is a valid FQDN
} elsif (&Network::check_ip_address($cgiparams{'ENDPOINT_ADDRESS'})) {
# The endpoint is a valid IP address
} else {
push(@errormessages, $Lang::tr{'wg invalid endpoint address'});
}
# Check the endpoint port
unless (&General::validport($cgiparams{'ENDPOINT_PORT'})) {
push(@errormessages, $Lang::tr{'wg invalid endpoint port'});
}
# Check keepalive
unless (&Wireguard::keepalive_is_valid($cgiparams{'KEEPALIVE'})) {
push(@errormessages, $Lang::tr{'wg invalid keepalive interval'});
}
# Check local subnets
if (defined $cgiparams{'LOCAL_SUBNETS'}) {
@local_subnets = split(/,/, $cgiparams{'LOCAL_SUBNETS'});
foreach my $subnet (@local_subnets) {
$subnet =~ s/^\s+//g;
$subnet =~ s/\s+$//g;
unless (&Network::check_subnet($subnet)) {
push(@errormessages, $Lang::tr{'wg invalid local subnet'} . ": ${subnet}");
}
}
} else {
push(@errormessages, $Lang::tr{'wg no local subnets'});
}
# Check remote subnets
if (defined $cgiparams{'REMOTE_SUBNETS'}) {
@remote_subnets = split(/,/, $cgiparams{'REMOTE_SUBNETS'});
foreach my $subnet (@remote_subnets) {
$subnet =~ s/^\s+//g;
$subnet =~ s/\s+$//g;
unless (&Network::check_subnet($subnet)) {
push(@errormessages, $Lang::tr{'wg invalid remote subnet'} . ": ${subnet}");
}
}
} else {
push(@errormessages, $Lang::tr{'wg no remote subnets'});
}
# If there are any errors, we go back to the editor
goto EDITNET if (scalar @errormessages);
# Save the connection
$Wireguard::peers{$key} = [
# 0 = Enabled
"on",
# 1 = Type
"net",
# 2 = Name
$cgiparams{"NAME"},
# 3 = Public Key
$cgiparams{"PUBLIC_KEY"},
# 4 = Private Key
$peer->{"PRIVATE_KEY"},
# 5 = Port
$cgiparams{"PORT"},
# 6 = Endpoint Address
$cgiparams{"ENDPOINT_ADDRESS"},
# 7 = Endpoint Port
$cgiparams{"ENDPOINT_PORT"},
# 8 = Remote Subnets
&Wireguard::encode_subnets(@remote_subnets),
# 9 = Remark
&Wireguard::encode_remarks($cgiparams{"REMARKS"}),
# 10 = Local Subnets
&Wireguard::encode_subnets(@local_subnets),
# 11 = PSK
$cgiparams{"PSK"} || "",
# 12 = Keepalive
$cgiparams{"KEEPALIVE"} || 0,
# 13 = Local Address
"",
];
# Store the configuration
&General::writehasharray("/var/ipfire/wireguard/peers", \%Wireguard::peers);
# Reload if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
}
} elsif ($cgiparams{"ACTION"} eq "SAVE-PEER-HOST") {
my $private_key;
my @free_addresses = ();
my @local_subnets = ();
# Fetch or allocate a new key
my $key = $cgiparams{'KEY'} || &General::findhasharraykey(\%Wireguard::peers);
# Is this a new connection?
my $is_new = !exists $Wireguard::peers{$key};
# Check if the name is valid
unless (&Wireguard::name_is_valid($cgiparams{"NAME"})) {
push(@errormessages, $Lang::tr{'wg invalid name'});
}
# Check if the name is free
unless (&Wireguard::name_is_free($cgiparams{"NAME"}, $key)) {
push(@errormessages, $Lang::tr{'wg name is already used'});
}
# Check local subnets
if (defined $cgiparams{'LOCAL_SUBNETS'}) {
@local_subnets = split(/,/, $cgiparams{'LOCAL_SUBNETS'});
foreach my $subnet (@local_subnets) {
$subnet =~ s/^\s+//g;
$subnet =~ s/\s+$//g;
unless (&Network::check_subnet($subnet)) {
push(@errormessages, $Lang::tr{'wg invalid local subnet'} . ": ${subnet}");
}
}
} else {
push(@errormessages, $Lang::tr{'wg no local subnets'});
}
# Check if we have address space left in the pool
if ($is_new) {
# Fetch the next free address
@free_addresses = &Wireguard::free_pool_addresses($Wireguard::settings{'CLIENT_POOL'}, 1);
# Fail if we ran out of addresses
if (scalar @free_addresses == 0) {
push(@errormessages, $Lang::tr{'wg no more free addresses in pool'});
}
}
# If there are any errors, we go back to the editor
goto EDITHOST if (scalar @errormessages);
# Generate things for a new peer
if ($is_new) {
# Generate a new private key
$private_key = &Wireguard::generate_private_key();
# Derive the public key
$cgiparams{"PUBLIC_KEY"} = &Wireguard::derive_public_key($private_key);
# Generate a new PSK
$cgiparams{"PSK"} = &Wireguard::generate_private_key();
# Fetch a free address from the pool
foreach (@free_addresses) {
$cgiparams{'CLIENT_ADDRESS'} = $_;
last;
}
# Fetch some configuration parts
} else {
$cgiparams{"PUBLIC_KEY"} = $Wireguard::peers{$key}[3];
$cgiparams{'CLIENT_ADDRESS'} = $Wireguard::peers{$key}[8];
$cgiparams{"PSK"} = $Wireguard::peers{$key}[11];
}
# Save the connection
$Wireguard::peers{$key} = [
# 0 = Enabled
"on",
# 1 = Type
"host",
# 2 = Name
$cgiparams{"NAME"},
# 3 = Public Key
$cgiparams{"PUBLIC_KEY"},
# 4 = Private Key
"",
# 5 = Port
"",
# 6 = Endpoint Address
"",
# 7 = Endpoint Port
"",
# 8 = Remote Subnets
$cgiparams{'CLIENT_ADDRESS'},
# 9 = Remark
&Wireguard::encode_remarks($cgiparams{"REMARKS"}),
# 10 = Local Subnets
&Wireguard::encode_subnets(@local_subnets),
# 11 = PSK
$cgiparams{"PSK"},
# 12 = Keepalive
0,
# 13 = Local Address
"",
];
# Store the configuration
&General::writehasharray("/var/ipfire/wireguard/peers", \%Wireguard::peers);
# Reload if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
}
# Show the client configuration when creating a new peer
if ($is_new) {
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Load the peer
my $peer = &Wireguard::load_peer($key);
# Generate the client configuration
my $config = &Wireguard::generate_peer_configuration($key, $private_key);
# Create a QR code generator
my $qrgen = Imager::QRCode->new(
size => 6,
margin => 0,
version => 0,
level => 'M',
mode => '8-bit',
casesensitive => 1,
lightcolor => Imager::Color->new(255, 255, 255),
darkcolor => Imager::Color->new(0, 0, 0),
);
# The generated QR code
my $qrcode;
# Encode the configuration
my $img = $qrgen->plot("$config");
# Encode the image as PNG
$img->write(data => \$qrcode, type => "png") or die $img->errstr;
# Encode the image as bas64
$qrcode = &MIME::Base64::encode_base64($qrcode);
# Encode the configuration as Base64
$config = &MIME::Base64::encode_base64($config);
# Open a new box
&Header::openbox('100%', '', "$Lang::tr{'wg peer configuration'}: $peer->{'NAME'}");
# Make the filename for files
my $filename = &Header::normalize($peer->{'NAME'}) . ".conf";
print <
$Lang::tr{'wg warning configuration only shown once'}
END
&Header::closebox();
&Header::closepage();
exit(0);
}
} elsif ($cgiparams{"ACTION"} eq $Lang::tr{'add'}) {
if ($cgiparams{"TYPE"} eq "net") {
goto CREATENET;
} elsif ($cgiparams{"TYPE"} eq "host") {
goto CREATEHOST;
} elsif ($cgiparams{"TYPE"} eq "import") {
goto IMPORT;
# Ask the user what type they want
} else {
goto ADD;
}
# Toggle Enable/Disable
} elsif ($cgiparams{'ACTION'} eq 'TOGGLE-ENABLE-DISABLE') {
my $key = $cgiparams{'KEY'} || 0;
if (exists $Wireguard::peers{$key}) {
if ($Wireguard::peers{$key}[0] eq "on") {
$Wireguard::peers{$key}[0] = "off";
} else {
$Wireguard::peers{$key}[0] = "on";
}
}
# Store the configuration
&General::writehasharray("/var/ipfire/wireguard/peers", \%Wireguard::peers);
# Reload if enabled
if (&Wireguard::is_enabled()) {
&General::system("/usr/local/bin/wireguardctrl", "start");
}
}
# The main page starts here
MAIN:
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Show any error messages
&Header::errorbox(@errormessages);
# Open a box for Global Settings
&Header::openbox('100%', '', $Lang::tr{'global settings'});
my %checked = (
"ENABLED" => (&Wireguard::is_enabled()) ? "checked" : "",
);
my %readonly = (
"CLIENT_POOL" => (&Wireguard::pool_is_in_use($Wireguard::settings{'CLIENT_POOL'}) ? "readonly" : ""),
);
my $client_dns = $Wireguard::settings{'CLIENT_DNS'} =~ s/\|/, /gr;
print <
$Lang::tr{'enabled'}
$Lang::tr{'wg endpoint'}
$Lang::tr{'port'}
$Lang::tr{'wg host to net client settings'}
$Lang::tr{'wg client pool'}
$Lang::tr{'wg dns'}
END
&Header::closebox();
# Show a list with all peers
&Header::opensection();
if (%Wireguard::peers) {
print <
$Lang::tr{'name'}
$Lang::tr{'remark'}
$Lang::tr{'status'}
$Lang::tr{'action'}
END
# Dump all RW peers
my %DUMP = &Wireguard::dump("wg0");
# Iterate through all peers...
foreach my $key (sort { $Wireguard::peers{$a}[2] cmp $Wireguard::peers{$b}[2] } keys %Wireguard::peers) {
my $enabled = $Wireguard::peers{$key}[0];
my $type = $Wireguard::peers{$key}[1];
my $name = $Wireguard::peers{$key}[2];
my $pubkey = $Wireguard::peers{$key}[3];
#my $privkey = $Wireguard::peers{$key}[4]
#my $port = $Wireguard::peers{$key}[5];
my $endpoint = $Wireguard::peers{$key}[6];
#my $endpport = $Wireguard::peers{$key}[7];
my $routes = $Wireguard::peers{$key}[8];
my $remarks = &Wireguard::decode_remarks($Wireguard::peers{$key}[9]);
my $connected = $Lang::tr{'capsclosed'};
my $country = "ZZ";
my $location = "";
my $gif = ($enabled eq "on") ? "on.gif" : "off.gif";
my @status = ("status");
# Fetch the dump
my %dump = ($type eq "net") ? &Wireguard::dump("wg$key") : %DUMP;
# Fetch the status of the peer (if possible)
my $status = $dump{$pubkey} || ();
# Fetch the actual endpoint
my ($actual_endpoint, $actual_port) = split(/:/, $status->{"endpoint"}, 2);
# WireGuard performs a handshake very two minutes, so we should be considered online then
my $is_connected = (time - $status->{"latest-handshake"}) <= 120;
# We are connected!
if ($is_connected) {
push(@status, "is-connected");
$connected = $Lang::tr{'capsopen'};
# If we have an endpoint lets lookup the country
if ($actual_endpoint) {
$country = &Location::Functions::lookup_country_code($actual_endpoint);
# If we found a country, let's show it
if ($country) {
my $icon = &Location::Functions::get_flag_icon($country);
$location = <
EOF
}
}
# We are not connected...
} else {
push(@status, "is-disconnected");
}
# Escape remarks
if ($remarks) {
$remarks = &Header::escape($remarks);
}
print <
$name
$remarks
END
if ($location) {
print <
$connected
$location
END
} else {
print <
$connected
END
}
print <
END
}
print"";
}
# Show controls
print <
END
&Header::closesection();
&Header::closepage();
exit(0);
ADD:
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Show any error messages
&Header::errorbox(@errormessages);
# Open a new box
&Header::openbox('100%', '', $Lang::tr{'connection type'});
my %disabled = (
"host" => "",
);
# If there is no CLIENT_POOL configured, we disable the option
if ($Wireguard::settings{'CLIENT_POOL'} eq "") {
$disabled{"host"} = "disabled";
# If the client pool is out of addresses, we do the same
} else {
my @free_addresses = &Wireguard::free_pool_addresses($Wireguard::settings{'CLIENT_POOL'}, 1);
if (scalar @free_addresses == 0) {
$disabled{"host"} = "disabled";
}
}
# Check the first available option
my %checked = (
"host" => ($disabled{"host"} eq "disabled") ? "" : "checked",
"net" => ($disabled{"host"} eq "disabled") ? "checked" : "",
);
print <
END
&Header::closebox();
&Header::closepage();
exit(0);
IMPORT:
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Show any error messages
&Header::errorbox(@errormessages);
# Open a new box
&Header::openbox('100%', '', $Lang::tr{'wg import peer'});
print <
$Lang::tr{'name'}
$Lang::tr{'remarks'}
$Lang::tr{'configuration file'}
$Lang::tr{'routing'}
$Lang::tr{'local subnets'}
END
&Header::closebox();
&Header::closepage();
exit(0);
CREATENET:
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Show any error messages
&Header::errorbox(@errormessages);
# Open a new box
&Header::openbox('100%', '', $Lang::tr{'wg create net-to-net peer'});
# Set defaults
&General::set_defaults(\%cgiparams, {
"LOCAL_SUBNETS" =>
$Network::ethernet{"GREEN_NETADDRESS"}
. "/" . $Network::ethernet{"GREEN_NETMASK"},
});
print <
$Lang::tr{'name'}
$Lang::tr{'remarks'}
$Lang::tr{'wg endpoint'}
$Lang::tr{'endpoint address'}
$Lang::tr{'routing'}
$Lang::tr{'local subnets'}
$Lang::tr{'remote subnets'}
END
&Header::closebox();
&Header::closepage();
exit(0);
EDITNET:
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Show any error messages
&Header::errorbox(@errormessages);
# Fetch the key
my $key = $cgiparams{'KEY'};
# Open a new box
&Header::openbox('100%', '', $Lang::tr{'wg edit net-to-net peer'});
# Derive our own public key
my $public_key = &Wireguard::derive_public_key($cgiparams{'PRIVATE_KEY'});
print <
$Lang::tr{'name'}
$Lang::tr{'remarks'}
$Lang::tr{'public key'}
$Lang::tr{'wg endpoint'}
$Lang::tr{'endpoint address'}
$Lang::tr{'endpoint port'}
$Lang::tr{'local port'}
$Lang::tr{'public key'}
$Lang::tr{'wg pre-shared key (optional)'}
$Lang::tr{'wg keepalive interval'}
$Lang::tr{'routing'}
$Lang::tr{'local subnets'}
$Lang::tr{'remote subnets'}
END
&Header::closebox();
&Header::closepage();
exit(0);
CREATEHOST:
EDITHOST:
# Send HTTP Headers
&Header::showhttpheaders();
# Open the page
&Header::openpage($Lang::tr{'wireguard'}, 1, '');
# Show any error messages
&Header::errorbox(@errormessages);
# Fetch the key
my $key = $cgiparams{'KEY'};
# Open a new box
&Header::openbox('100%', '',
(defined $key) ? $Lang::tr{'wg edit host-to-net peer'} : $Lang::tr{'wg create host-to-net peer'});
# Set defaults
unless (defined $key) {
&General::set_defaults(\%cgiparams, {
"LOCAL_SUBNETS" => "0.0.0.0/0",
});
}
print <
$Lang::tr{'name'}
$Lang::tr{'remarks'}
$Lang::tr{'routing'}
$Lang::tr{'allowed subnets'}
END
&Header::closebox();
&Header::closepage();
exit(0);