#!/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 download configuration file'}

$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{'qr code'}

$Lang::tr{'wg scan the qr code'}

$Lang::tr{'wg download configuration file'}

$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 = < $country 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);