mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-09 18:45:54 +02:00
Choose one IP from client pool and add it to road warrior interface wg0 so road warrior VPN client could reach firewall through the VPN Signed-off-by: Vincent Li <vincent.mc.li@gmail.com>
1549 lines
37 KiB
Perl
1549 lines
37 KiB
Perl
#!/usr/bin/perl
|
|
###############################################################################
|
|
# #
|
|
# IPFire.org - A linux based firewall #
|
|
# Copyright (C) 2024 Michael Tremer <michael.tremer@ipfire.org> #
|
|
# #
|
|
# 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 <http://www.gnu.org/licenses/>. #
|
|
# #
|
|
###############################################################################
|
|
|
|
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);
|
|
}
|
|
|
|
# Check wg0 ADDRESS - make it optional
|
|
if (defined $cgiparams{'ADDRESS'}) {
|
|
if ($cgiparams{'ADDRESS'} ne '') {
|
|
my $address = $cgiparams{'ADDRESS'};
|
|
unless (&Network::check_ip_address($address)) {
|
|
push(@errormessages, "$Lang::tr{'wg invalid wg0 address'}: ${address}");
|
|
}
|
|
# Store ADDRESS only if it's valid and not empty
|
|
$Wireguard::settings{'ADDRESS'} = $address;
|
|
} else {
|
|
# Explicitly set to empty string when field is empty
|
|
$Wireguard::settings{'ADDRESS'} = '';
|
|
}
|
|
}
|
|
|
|
# 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 <<END;
|
|
<div class="text-center">
|
|
<p>
|
|
<a href="data:text/plain;base64,${config}" download="${filename}">
|
|
$Lang::tr{'wg download configuration file'}
|
|
</a>
|
|
</p>
|
|
|
|
<p class="text-error">
|
|
$Lang::tr{'wg warning configuration only shown once'}
|
|
</p>
|
|
|
|
<p>
|
|
<form method="GET" action="">
|
|
<button type="submit">$Lang::tr{'done'}</button>
|
|
</form>
|
|
</p>
|
|
</div>
|
|
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 <<END;
|
|
<div class="text-center">
|
|
<p>
|
|
<img src="data:image/png;base64,${qrcode}" alt="$Lang::tr{'qr code'}">
|
|
</p>
|
|
|
|
<p>
|
|
$Lang::tr{'wg scan the qr code'}
|
|
</p>
|
|
|
|
<p>
|
|
<a href="data:text/plain;base64,${config}" download="${filename}">
|
|
$Lang::tr{'wg download configuration file'}
|
|
</a>
|
|
</p>
|
|
|
|
<p class="text-error">
|
|
$Lang::tr{'wg warning configuration only shown once'}
|
|
</p>
|
|
|
|
<p>
|
|
<form method="GET" action="">
|
|
<button type="submit">$Lang::tr{'done'}</button>
|
|
</form>
|
|
</p>
|
|
</div>
|
|
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 <<END;
|
|
<form method="POST" action="">
|
|
<table class="form">
|
|
<tr>
|
|
<td>$Lang::tr{'enabled'}</td>
|
|
<td>
|
|
<input type="checkbox" name="ENABLED" $checked{'ENABLED'} />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>$Lang::tr{'wg endpoint'} <img src='/blob.gif' alt='*' /></td>
|
|
<td>
|
|
<input type="text" name="ENDPOINT" value="$Wireguard::settings{'ENDPOINT'}" placeholder="$General::mainsettings{'HOSTNAME'}.$General::mainsettings{'DOMAINNAME'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>$Lang::tr{'wg address'}</td>
|
|
<td>
|
|
<input type="text" name="ADDRESS" value="$Wireguard::settings{'ADDRESS'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>$Lang::tr{'port'} <img src='/blob.gif' alt='*' /></td>
|
|
<td>
|
|
<input type="number" name="PORT" value="$Wireguard::settings{'PORT'}"
|
|
min="1024" max="65535" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'wg host to net client settings'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>$Lang::tr{'wg client pool'} <img src='/blob.gif' alt='*' /></td>
|
|
<td>
|
|
<input type="text" name="CLIENT_POOL"
|
|
value="$Wireguard::settings{'CLIENT_POOL'}" $readonly{'CLIENT_POOL'} />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>$Lang::tr{'wg dns'} <img src='/blob.gif' alt='*' /></td>
|
|
<td>
|
|
<input type="text" name="CLIENT_DNS"
|
|
value="$client_dns" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="action">
|
|
<td colspan="2">
|
|
<input type='submit' name='ACTION' value='$Lang::tr{'save'}' />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
END
|
|
&Header::closebox();
|
|
|
|
# Show a list with all peers
|
|
&Header::opensection();
|
|
|
|
if (%Wireguard::peers) {
|
|
print <<END;
|
|
<table class='tbl'>
|
|
<tr>
|
|
<th width='15%'>
|
|
$Lang::tr{'name'}
|
|
</th>
|
|
|
|
<th>
|
|
$Lang::tr{'remark'}
|
|
</th>
|
|
|
|
<th width='20%' colspan='2'>
|
|
$Lang::tr{'status'}
|
|
</th>
|
|
|
|
<th width='10%' colspan='3'>
|
|
$Lang::tr{'action'}
|
|
</th>
|
|
</tr>
|
|
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;
|
|
<a href="country.cgi#$country">
|
|
<img src="$icon" border='0' align='absmiddle'
|
|
alt='$country' title='$actual_endpoint:$actual_port - $country' />
|
|
</a>
|
|
EOF
|
|
}
|
|
}
|
|
|
|
# We are not connected...
|
|
} else {
|
|
push(@status, "is-disconnected");
|
|
}
|
|
|
|
# Escape remarks
|
|
if ($remarks) {
|
|
$remarks = &Header::escape($remarks);
|
|
}
|
|
|
|
print <<END;
|
|
<tr>
|
|
<th scope="row" title="${pubkey}">
|
|
$name
|
|
</th>
|
|
|
|
<td>
|
|
$remarks
|
|
</td>
|
|
END
|
|
|
|
if ($location) {
|
|
print <<END;
|
|
<td class="@status">
|
|
$connected
|
|
</td>
|
|
|
|
<td class="@status">
|
|
$location
|
|
</td>
|
|
END
|
|
} else {
|
|
print <<END;
|
|
<td class="@status" colspan="2">
|
|
$connected
|
|
</td>
|
|
END
|
|
}
|
|
|
|
print <<END;
|
|
<td class="text-center">
|
|
<form method='post'>
|
|
<input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif'
|
|
alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
|
|
<input type='hidden' name='ACTION' value='TOGGLE-ENABLE-DISABLE' />
|
|
<input type='hidden' name='KEY' value='$key' />
|
|
</form>
|
|
</td>
|
|
|
|
<td class="text-center">
|
|
<form method='post'>
|
|
<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
|
|
<input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif'
|
|
alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
|
|
<input type='hidden' name='KEY' value='$key' />
|
|
</form>
|
|
</td>
|
|
|
|
<td class="text-center">
|
|
<form method='post'>
|
|
<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
|
|
<input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif'
|
|
alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
|
|
<input type='hidden' name='KEY' value='$key' />
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
END
|
|
}
|
|
|
|
print"</table>";
|
|
}
|
|
|
|
# Show controls
|
|
print <<END;
|
|
<table class="form">
|
|
<tr class="action">
|
|
<td>
|
|
<form method='post'>
|
|
<input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
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;
|
|
<form method="POST" ENCTYPE="multipart/form-data">
|
|
<p>
|
|
<label>
|
|
<input type='radio' name='TYPE' value='host' $disabled{'host'} $checked{'host'} />
|
|
$Lang::tr{'host to net vpn'}
|
|
</label>
|
|
</p>
|
|
|
|
<p>
|
|
<label>
|
|
<input type='radio' name='TYPE' value='net' $checked{'net'} />
|
|
$Lang::tr{'net to net vpn'}
|
|
</label>
|
|
</p>
|
|
|
|
<p>
|
|
<label>
|
|
<input type='radio' name='TYPE' value='import' />
|
|
$Lang::tr{'import connection'}
|
|
</label>
|
|
</p>
|
|
|
|
<table class="form">
|
|
<tr class="action">
|
|
<td>
|
|
<input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
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 <<END;
|
|
<form method="POST" ENCTYPE="multipart/form-data">
|
|
<input type="hidden" name="ACTION" value="IMPORT">
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'name'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="NAME"
|
|
value="$cgiparams{'NAME'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'remarks'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="REMARKS"
|
|
value="$cgiparams{'REMARKS'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'configuration file'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type='file' name='FH' required />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'routing'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'local subnets'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="LOCAL_SUBNETS"
|
|
value="$cgiparams{'LOCAL_SUBNETS'}" required />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<table class="form">
|
|
<tr class="action">
|
|
<td colspan="2">
|
|
<input type='submit' value='$Lang::tr{'import'}' />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
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 <<END;
|
|
<form method="POST" ENCTYPE="multipart/form-data">
|
|
<input type="hidden" name="ACTION" value="CREATE-PEER-NET">
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'name'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="NAME"
|
|
value="$cgiparams{'NAME'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'remarks'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="REMARKS"
|
|
value="$cgiparams{'REMARKS'}" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'wg endpoint'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'endpoint address'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="ENDPOINT_ADDRESS"
|
|
value="$cgiparams{'ENDPOINT_ADDRESS'}" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'routing'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'local subnets'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="LOCAL_SUBNETS"
|
|
value="$cgiparams{'LOCAL_SUBNETS'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'remote subnets'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="REMOTE_SUBNETS"
|
|
value="$cgiparams{'REMOTE_SUBNETS'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="action">
|
|
<td colspan="2">
|
|
<input type='submit' value='$Lang::tr{'create'}' />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
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 <<END;
|
|
<form method="POST" ENCTYPE="multipart/form-data">
|
|
<input type="hidden" name="ACTION" value="SAVE-PEER-NET">
|
|
<input type="hidden" name="KEY" value="$cgiparams{'KEY'}">
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'name'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="NAME"
|
|
value="$cgiparams{'NAME'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'remarks'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="REMARKS"
|
|
value="$cgiparams{'REMARKS'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'public key'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" value="$public_key" readonly />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'wg endpoint'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'endpoint address'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="ENDPOINT_ADDRESS"
|
|
value="$cgiparams{'ENDPOINT_ADDRESS'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'endpoint port'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="number" name="ENDPOINT_PORT"
|
|
value="$cgiparams{'ENDPOINT_PORT'}" required
|
|
min="1" max="65535" placeholder="${Wireguard::DEFAULT_PORT}"/>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'local port'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="number" name="PORT"
|
|
value="$cgiparams{'PORT'}" min="1" max="65535"
|
|
placeholder="$Lang::tr{'wg leave empty to automatically select'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>$Lang::tr{'public key'}</td>
|
|
<td>
|
|
<input type="text" name="PUBLIC_KEY"
|
|
value="$cgiparams{'PUBLIC_KEY'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>$Lang::tr{'wg pre-shared key (optional)'}</td>
|
|
<td>
|
|
<input type="text" name="PSK"
|
|
value="$cgiparams{'PSK'}" />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'wg keepalive interval'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="number" name="KEEPALIVE"
|
|
value="$cgiparams{'KEEPALIVE'}" required
|
|
min="0" max="65535" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'routing'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'local subnets'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="LOCAL_SUBNETS"
|
|
value="$cgiparams{'LOCAL_SUBNETS'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'remote subnets'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="REMOTE_SUBNETS"
|
|
value="$cgiparams{'REMOTE_SUBNETS'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="action">
|
|
<td colspan="2">
|
|
<input type='submit' value='$Lang::tr{'save'}' />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
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 <<END;
|
|
<form method="POST" ENCTYPE="multipart/form-data">
|
|
<input type="hidden" name="ACTION" value="SAVE-PEER-HOST">
|
|
<input type="hidden" name="KEY" value="$cgiparams{'KEY'}">
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'name'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="NAME"
|
|
value="$cgiparams{'NAME'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'remarks'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="REMARKS"
|
|
value="$cgiparams{'REMARKS'}" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h6>$Lang::tr{'routing'}</h6>
|
|
|
|
<table class="form">
|
|
<tr>
|
|
<td>
|
|
$Lang::tr{'allowed subnets'}
|
|
</td>
|
|
|
|
<td>
|
|
<input type="text" name="LOCAL_SUBNETS"
|
|
value="$cgiparams{'LOCAL_SUBNETS'}" required />
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="action">
|
|
<td colspan="2">
|
|
<input type='submit' value='$Lang::tr{'save'}' />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
END
|
|
|
|
&Header::closebox();
|
|
&Header::closepage();
|
|
|
|
exit(0);
|