diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml
index 8afe915f..c92a871a 100644
--- a/.github/workflows/unit-tests.yaml
+++ b/.github/workflows/unit-tests.yaml
@@ -7,6 +7,7 @@ on:
branches:
- '**'
pull_request:
+ types: [opened, reopened]
paths-ignore:
- '**.md'
@@ -60,21 +61,10 @@ jobs:
run: ./configure --prefix=$HOME/test-install
- name: Make
run: make
- - name: Test
+ - name: Test & dist & install
run: |
cp etc/wgwrangler.dist.yaml etc/wgwrangler.yaml
make test
- - name: Check Dist
- run: |
- make dist
- tar xf *-$(cat VERSION).tar.gz
- cd *-$(cat VERSION)
- ./configure --prefix=$HOME/test-install
- make
- make install
- cd $HOME/test-install
- cp etc/wgwrangler.dist.yaml etc/wgwrangler.yaml
- ./bin/wgwrangler
- name: Cache Prep
run: |
rm thirdparty/Makefile* thirdparty/cpan*snapshot
diff --git a/Makefile.am b/Makefile.am
index 4c5ccf93..85ab8726 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,4 +38,4 @@ share/messages.pot: $(PM) $(CALLBACKERY_PM)
for lang in $(LANGUAGES); do ( test -f $$lang || cp share/messages.pot $$lang ); $(MSGMERGE) -s --force-po -U $$lang share/messages.pot; done
test:
- $(MJ_CLASS)_CONFIG=t/etc/wgwrangler.yaml prove -w
+ $(MJ_CLASS)_CONFIG_HOME=t/etc prove -w
diff --git a/README.md b/README.md
index 078ea83e..655e5fdf 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,8 @@ sudo apt install libqrencode-dev
make
```
+**Minimum Node.js: `v14` -> If no compatible node version is found, the frontend is not built!**
+
Configure will check if all requirements are met and give
hints on how to fix the situation if something is missing.
@@ -79,6 +81,12 @@ Currently supported ubuntu versions:
- 20.04 LTS
- 22.04 LTS
+Configuration
+-------------
+
+Do get started, rename `/etc/opt/wg-wrangler/wgwrangler.dist.yaml` to `/etc/opt/wg-wrangler/wgwrangler.yaml` and adjust
+according your needs.
+
Development
-----------
@@ -98,7 +106,7 @@ file and run ./bootstrap.
**Honored Environment Variables**
- `WGwrangler_NO_WG` If defined, we do not call any wg* command from code (e.g. to generate pub/private-keys)
-- `WGwrangler_CONFIG` Use this variable to set the path to the main `wgwrangler.yaml` file, defaults to `etc/wgrangler.yaml`
+- `WGwrangler_CONFIG_HOME` Use this variable to set the path to the main configuration files (email template + main config)
Packaging
---------
diff --git a/bin/wgwrangler-source-mode.sh b/bin/wgwrangler-source-mode.sh
index 7b513dcd..8efc2991 100755
--- a/bin/wgwrangler-source-mode.sh
+++ b/bin/wgwrangler-source-mode.sh
@@ -2,5 +2,5 @@
export MOJO_MODE=development
export MOJO_LOG_LEVEL=debug
export WGwrangler_NO_WG=1
-export WGwrangler_CONFIG=t/etc/wgwrangler.yaml
+export WGwrangler_CONFIG_HOME=t/etc
exec $(dirname $0)/wgwrangler prefork --listen 'http://*:7192'
diff --git a/debian/wg-wrangler.service b/debian/wg-wrangler.service
index aa3d3a2a..9b1bc1d7 100644
--- a/debian/wg-wrangler.service
+++ b/debian/wg-wrangler.service
@@ -6,7 +6,7 @@ Type=simple
Environment=LISTEN_ON=http://127.0.0.1:7171
Environment=MOJO_MODE=production
Environment=MOJO_LOG_LEVEL=info
-Environment=WGwrangler_CONFIG=/etc/opt/wg-wrangler/wgwrangler.yaml
+Environment=WGwrangler_CONFIG_HOME=/etc/opt/wg-wrangler
# Environment variables defined in this file (if it exists) override previously defined ones
EnvironmentFile=-/etc/opt/wg-wrangler/env.conf
diff --git a/etc/env.dist.conf b/etc/env.dist.conf
index b07c0acc..bb12fe6c 100644
--- a/etc/env.dist.conf
+++ b/etc/env.dist.conf
@@ -1,4 +1,4 @@
LISTEN_ON=http://127.0.0.1:7171
MOJO_MODE=production
MOJO_LOG_LEVEL=info
-WGwrangler_CONFIG=/etc/opt/wg-wrangler/wgwrangler.yaml
+WGwrangler_CONFIG_HOME=/etc/opt/wg-wrangler
diff --git a/templates/send_config_by_email.email.ep b/etc/send_config_by_email.dist.ep
similarity index 51%
rename from templates/send_config_by_email.email.ep
rename to etc/send_config_by_email.dist.ep
index db300976..0d766f66 100644
--- a/templates/send_config_by_email.email.ep
+++ b/etc/send_config_by_email.dist.ep
@@ -1,5 +1,5 @@
Subject: Wireguard VPN Configuration
-Reply-To: rt@oetiker.ch
+Reply-To: <%= $sender_email %>
----
Dear <%= $name %>
This is your vpn configuration for your device "<%= $device_name %>" to access <%= $endpoint %>.
@@ -8,18 +8,19 @@ Add the config file attached to this message
enjoy!
----
-
+
Dear <%= $name %>
-This is your vpn configuration for your device "<%= $device_name %>" to access <%= $endpoint %>.
+This is your vpn configuration for your device "<%= $device_name %>" to access <%= $endpoint %>.
-- Install a Wireguard client.
-- Add the config file attached to this message
+ - Install a Wireguard client.
+ - Add the config file attached to this message
Your Wireguard Configuration as a QR Code, readable by mobile Wireguard clients
-
+
enjoy!
diff --git a/etc/wgwrangler.dist.yaml b/etc/wgwrangler.dist.yaml
index 6794c04e..6b8aabd7 100644
--- a/etc/wgwrangler.dist.yaml
+++ b/etc/wgwrangler.dist.yaml
@@ -1,20 +1,37 @@
-
BACKEND:
cfg_db: /var/opt/wg-wrangler/wgwrangler.db
sesame_user: adfadsfasdf4ee3r
# perl -MDigest::SHA -e 'print Digest::SHA::hmac_sha1_hex("access"),"\n"'
sesame_pass: 393afhkjhffjj
- vpn_name: your_vpn_name
+ # A name for your VPN service, available as tag in the email template
+ vpn_name: 'Awesome Wireguard VPN'
+ # Enable versioning for wireguard configurations
enable_git: false
- no_apply: true
+ # Instead of applying the configuration automatically after every edit, show a button to apply the configuration manually
+ no_apply: false
not_applied_suffix: .not_applied
- wireguard_home: /dummy_home/
+ # Where does your wireguard configuration reside? (trailing slash expected)
+ wireguard_home: /etc/wireguard/
wg_apply_command: sudo -n wg-quick strip %interface% > /tmp/wg_tmp && sudo -n wg syncconf %interface% /tmp/wg_tmp && rm /tmp/wg_tmp
wg_show_command: sudo -n wg show all dump
+ # Ranges defined here are not possible to acquire
+ # Note: Make sure your subnet calculations are correct, e.g 192.168.1.1/24 is not a valid network _per se_, the
+ # correct notation is 192.168.1.0/24 (!)
+ reserved_ranges:
+ wg0:
+ - 10.0.0.0/29
+ default_dns:
+ wg1: 192.168.2.1
+ default_allowed_ips:
+ wg0:
+ - 192.168.0.0/24
+ wg1:
+ - 192.168.0.0/24
+ sender_email: support@oetiker.ch
FRONTEND:
-# logo = ../resource/wgwrangler/logo.png
-# logo_small = ../resource/wgwrangler/logo-small.png
+ # logo = ../resource/wgwrangler/logo.png
+ # logo_small = ../resource/wgwrangler/logo-small.png
title: WGwrangler
initial_plugin: WireguardShow
company_name: OETIKER+PARTNER AG
@@ -31,9 +48,6 @@ PLUGIN:
- WireguardShow:
module: WireguardShow
tab-name: Wireguard
- default-dns: 192.168.0.1
- default-allowed-ips: 192.168.0.0/24
- sender-email: support@oetiker.ch
- WireguardVersions:
module: WireguardVersions
diff --git a/lib/WGwrangler/Model/IPmanager.pm b/lib/Net/IPManager.pm
similarity index 55%
rename from lib/WGwrangler/Model/IPmanager.pm
rename to lib/Net/IPManager.pm
index 549cb622..0b8565f8 100644
--- a/lib/WGwrangler/Model/IPmanager.pm
+++ b/lib/Net/IPManager.pm
@@ -1,3 +1,10 @@
+package Net::IPManager;
+use strict;
+use warnings FATAL => 'all';
+use Net::IP;
+use experimental 'signatures';
+use Net::IPManager::Constants;
+
=head1 NAME
WGwrangler::Model::IPmanager - Manages IPs and Interface-ranges
@@ -10,51 +17,48 @@ Keeps track of acquired and released ips
=cut
-package WGwrangler::Model::IPmanager;
-use Mojo::Base -base, -signatures;
-use CallBackery::Translate qw(trm);
-use Net::IP;
-has 'interface_ranges' => sub ($self) {
- {};
-};
-has 'ip_meta_info' => sub ($self) {
- {};
-};
+sub new($class) {
+ my $self = {
+ 'interface_ranges' => {},
+ 'acquired_ips' => {},
+ 'ip_meta_info' => {}
+ };
+ bless $self, $class;
+ return $self;
+}
+
-has 'acquired_ips' => sub ($self) {
- {};
-};
=head3 populate_range($interface, $ip_ranges_str)
Sets the possible ranges for an interface. Throws an exception if C<$ip_ranges_str> contain invalid values.
C<$ip_ranges_str> is expected to be a comma-separated list of ip-ranges in CIDR notation
=cut
-sub populate_range ($self, $interface, $ip_ranges_str) {
+sub populate_range($self, $interface, $ip_ranges_str) {
my @ranges;
my @ips = map {_trm($_)} split /\,/, $ip_ranges_str;
for my $ip_range (@ips) {
my $may_ip = Net::IP->new($ip_range) or die "Could not read ip-range for `$interface`: " . Net::IP::Error();
# prepare acquired ip storage
- $self->acquired_ips->{$interface}{$may_ip->ip()} = {};
+ $self->{acquired_ips}->{$interface}{$may_ip->ip()} = {};
push @ranges, $may_ip;
}
- $self->interface_ranges->{$interface} = \@ranges;
- $self->ip_meta_info->{$interface}{n_ips} = 0;
+ $self->{interface_ranges}->{$interface} = \@ranges;
+ $self->{ip_meta_info}->{$interface}{n_ips} = 0;
return 1;
}
-=head3 acquire_multiple($interface, $ips_string)
+=head3 acquire_multiple($interface, $ips_string, $force=0)
Takes a string of comma-separated ip(-ranges) in CIDR notation. Returns 1 if all ips have been acquired successfully
=cut
-sub acquire_multiple ($self, $interface, $ips_string) {
+sub acquire_multiple($self, $interface, $ips_string, $force = 0) {
my @ips = map {_trm($_)} split /\,/, $ips_string;
for my $ip (@ips) {
- unless ($self->acquire_single($interface, $ip)) {
+ unless ($self->acquire_single($interface, $ip, $force)) {
# die "Could not acquire IP `$ip` for interface `$interface`";
}
}
@@ -66,62 +70,70 @@ sub acquire_multiple ($self, $interface, $ips_string) {
Takes an ip string (one single ip) in CIDR notation and tries to acquire it respecting the already acquired ones for
this interface.
-Returns 1 on success.
+Returns undef on success.
Raises exception if C<$ip_string> is invalid.
=cut
-
-sub acquire_single ($self, $interface, $ip_string) {
+sub acquire_single($self, $interface, $ip_string, $force = 0) {
my $may_ip = Net::IP->new($ip_string) or die "Could not read ip for `$ip_string`: " . Net::IP::Error();
- for my $interface_range (@{$self->interface_ranges->{$interface}}) {
+ for my $interface_range (@{$self->{interface_ranges}->{$interface}}) {
+ # Check if $may_ip is the first or last ip of an interface range (and only check if want to acquire a single ip)
+ if ($may_ip->size() == 1 && ($interface_range->ip() eq $may_ip->ip() || $interface_range->last_ip() eq $may_ip->last_ip())) {
+ return E_CANNOT_ACQUIRE_FIRST_OR_LAST;
+ }
if ($self->_is_in($may_ip, $interface_range)) {
# cheap check
- if (exists $self->acquired_ips->{$interface}{$interface_range->ip()}{$may_ip->ip()}) {
- return undef;
- }
- # expensive check
- for my $acquired_key (keys %{$self->acquired_ips->{$interface}{$interface_range->ip()}}) {
- if ($self->_is_in($may_ip, $self->acquired_ips->{$interface}{$interface_range->ip()}{$acquired_key})) {
- return undef;
+ if ($force == 0) {
+ if (exists $self->{acquired_ips}->{$interface}{$interface_range->ip()}{$may_ip->ip()}) {
+ return E_ALREADY_ACQUIRED;
+ }
+ # expensive check
+ for my $acquired_ip (keys %{$self->{acquired_ips}->{$interface}{$interface_range->ip()}}) {
+ if ($self->_is_in($may_ip, $self->{acquired_ips}->{$interface}{$interface_range->ip()}{$acquired_ip})) {
+ return E_ALREADY_ACQUIRED;
+ }
}
}
- $self->acquired_ips->{$interface}{$interface_range->ip()}{$may_ip->ip()} = $may_ip;
- $self->ip_meta_info->{$interface}{n_ips}++;
- return 1;
+ $self->{acquired_ips}->{$interface}{$interface_range->ip()}{$may_ip->ip()} = $may_ip;
+ $self->{ip_meta_info}->{$interface}{n_ips}++;
+ return undef;
+ }
+ else {
+ return E_SUBNET_NOT_MATCHING;
}
}
- return undef;
+ return E_UNKNOWN_INTERFACE;
}
+
=head3 release_ip($interface, $ip_string)
-Releases a specific ip from an interface.
+Releases a specific ip from an interface. For performance reasons, we do not check if the address has been acquired before
-Returns 1 on success.
+Returns undef on success.
Raises exception if C<$ip_string> is invalid.
=cut
-sub release_ip ($self, $interface, $ip_string) {
+sub release_ip($self, $interface, $ip_string) {
my $may_ip = Net::IP->new($ip_string) or die "Could not read ip for `$ip_string`: " . Net::IP::Error();
- for my $interface_range (@{$self->interface_ranges->{$interface}}) {
+ for my $interface_range (@{$self->{interface_ranges}->{$interface}}) {
if ($self->_is_in($may_ip, $interface_range)) {
- delete $self->acquired_ips->{$interface}{$interface_range->ip()}{$may_ip->ip()};
- $self->ip_meta_info->{$interface}{n_ips}--;
- return 1;
+ delete $self->{acquired_ips}->{$interface}{$interface_range->ip()}{$may_ip->ip()};
+ $self->{ip_meta_info}->{$interface}{n_ips}--;
+ return undef;
}
}
- return undef;
+ return E_UNKNOWN_INTERFACE;
}
-sub _is_in ($self, $ip, $range) {
+sub _is_in($self, $ip, $range) {
if ($range->version() == $ip->version()) {
- my $ip_result = $ip->overlaps($range);
# Just for debugging
# my $s = $ip->ip();
# my $t = $range->ip();
- # my $c = $ip_result && ($ip_result == $IP_IDENTICAL || $ip_result == $IP_A_IN_B_OVERLAP || $range->intip() == $ip->intip());
- return $ip_result && ($ip_result == $IP_IDENTICAL || $ip_result == $IP_A_IN_B_OVERLAP || $range->intip() == $ip->intip());
+ my $ip_result = $ip->overlaps($range);
+ return $ip_result != 0;
}
return undef;
}
@@ -131,7 +143,7 @@ sub _is_in ($self, $ip, $range) {
Checks whether C<$ips_string> looks like a valid ip in CIDR notation
=cut
-sub looks_like_ip ($self, $ips_string) {
+sub looks_like_ip($self, $ips_string) {
my @ips = map {_trm($_)} split /\,/, $ips_string;
for my $ip (@ips) {
my $may_ip = Net::IP->new($ip) or undef;
@@ -139,28 +151,43 @@ sub looks_like_ip ($self, $ips_string) {
return 1;
}
+=head3 get_next_ip($interface_range [, $offset = 1])
+
+Takes a subnet (larger than /32 or /128) and returns the IP with $offset away from the network address.
+
+=cut
+sub get_next_ip($interface_range, $offset = 1) {
+ my $prefix = $interface_range->version() == 4 ? '/32' : '/128';
+ my $next_ip = $interface_range->ip_add_num($offset);
+ # This is unfortunately necessary since ip_add_num() keeps the subnet size
+ return defined $next_ip ? Net::IP->new($next_ip->ip() . $prefix) : undef;
+}
+
=head3 suggest_ip($interface)
Returns a comma separated string of the next free ip(s) for C<$interface>. If no ips are left, an empty string is returned
=cut
-sub suggest_ip ($self, $interface) {
+sub suggest_ip($self, $interface) {
my @suggested_ips;
- for my $interface_range (@{$self->interface_ranges->{$interface}}) {
+ for my $interface_range (@{$self->{interface_ranges}->{$interface}}) {
# get a list of all acquired ip/ranges for this interface and sort them lowest to highest
my $ip_range_string = $interface_range->ip();
- my @acquired_ip_list = map {$self->acquired_ips->{$interface}{$ip_range_string}{$_}} keys(%{$self->acquired_ips->{$interface}{$ip_range_string}});
+ my @acquired_ip_list = map {$self->{acquired_ips}->{$interface}{$ip_range_string}{$_}} keys(%{$self->{acquired_ips}->{$interface}{$ip_range_string}});
my @acquired_ips_sorted = sort {$a->intip() <=> $b->intip()} @acquired_ip_list;
- # prepare suggestion
- my $ip_suggestion = $interface_range->ip_add_num(1);
+ # prepare suggestion (first possible address of interface)
+ my $ip_suggestion = get_next_ip($interface_range);
+ my $offset = 1;
for my $acquired_ip (@acquired_ips_sorted) {
if ($self->_is_in($ip_suggestion, $acquired_ip)) {
- # Jump subnet size
- $ip_suggestion = $ip_suggestion->ip_add_num($acquired_ip->size());
- if (!$ip_suggestion) {
+ # Calculate subnet jump size
+ my $subnet_size = $acquired_ip->size();
+ $offset += $subnet_size > 1 ? $subnet_size - 1 : $subnet_size;
+ $ip_suggestion = get_next_ip($interface_range, $offset);
+ if (!defined $ip_suggestion) {
# return "No IPs left for`". $ip_range->ip() ."`";
last;
}
@@ -188,9 +215,9 @@ By providing C<$current_peer_ips>, reassigning the same ip as before is allowed.
Returns empty string on success and an error string on failure
=cut
-sub is_valid_for_interface ($self, $interface, $ips_string, $current_peer_ips = undef) {
+sub is_valid_for_interface($self, $interface, $ips_string, $current_peer_ips = undef) {
# First check if the requested interface is indeed valid
- if (exists $self->interface_ranges->{$interface}) {
+ if (exists $self->{interface_ranges}->{$interface}) {
my @ips_string_to_test = map {_trm($_)} split /\,/, $ips_string;
my @current_peer_ips = map {_trm($_)} split /\,/, $current_peer_ips if defined $current_peer_ips;
my $found_matching_version = 0;
@@ -211,20 +238,20 @@ sub is_valid_for_interface ($self, $interface, $ips_string, $current_peer_ips =
}
}
if (not defined $ip_is_within_on_disk_version) {
- for my $interface_range (@{$self->interface_ranges->{$interface}}) {
+ for my $interface_range (@{$self->{interface_ranges}->{$interface}}) {
# my $s = $interface_range->ip();
# my $t = $self->_is_in($ip_object_to_test, $interface_range);
if ($self->_is_in($ip_object_to_test, $interface_range)) {
$found_matching_version++;
# Cheap check
- if (exists $self->acquired_ips->{$interface}{$interface_range->ip()}{$ip_object_to_test->ip()}) {
- return "IP/range `" . $ip_object_to_test->ip() . "` " . trm('is already acquired');
+ if (exists $self->{acquired_ips}->{$interface}{$interface_range->ip()}{$ip_object_to_test->ip()}) {
+ return "IP/range `" . $ip_object_to_test->ip() . "` " . 'is already acquired';
}
# expensive check
- for my $acquired_key (keys %{$self->acquired_ips->{$interface}{$interface_range->ip()}}) {
- # my $t = $self->_is_in($self->acquired_ips->{$interface}{$interface_range->ip()}{$acquired_key}, $ip_object_to_test);
- if ($self->_is_in($self->acquired_ips->{$interface}{$interface_range->ip()}{$acquired_key}, $ip_object_to_test)) {
- return "IP/range `" . $ip_object_to_test->ip() . "`" . trm('overlaps with an already acquired network');
+ for my $acquired_key (keys %{$self->{acquired_ips}->{$interface}{$interface_range->ip()}}) {
+ # my $t = $self->_is_in($self->{acquired_ips}->{$interface}{$interface_range->ip()}{$acquired_key}, $ip_object_to_test);
+ if ($self->_is_in($self->{acquired_ips}->{$interface}{$interface_range->ip()}{$acquired_key}, $ip_object_to_test)) {
+ return "IP/range `" . $ip_object_to_test->ip() . "`" . 'overlaps with an already acquired network';
}
}
last;
@@ -233,7 +260,7 @@ sub is_valid_for_interface ($self, $interface, $ips_string, $current_peer_ips =
}
}
- return $found_matching_version == @ips_string_to_test ? "" : trm('It seems that some parts of') . "`" . $ips_string . "`" . trm('do not belong to') . "`$interface`";
+ return $found_matching_version == @ips_string_to_test ? "" : 'It seems that some parts of' . "`" . $ips_string . "`" . 'do not belong to' . "`$interface`";
}
else {
return "Invalid interface `$interface` - Did you call populate_range() before?";
@@ -246,7 +273,7 @@ sub is_valid_for_interface ($self, $interface, $ips_string, $current_peer_ips =
Utility method to parse the individual ip-string from a comma separated list
=cut
-sub extract_ips ($ip_string) {
+sub extract_ips($ip_string) {
my @ips = split /\,/, $ip_string;
chomp(@ips);
my @results;
@@ -259,8 +286,10 @@ sub extract_ips ($ip_string) {
return \@results
}
-sub _trm ($str) {
+sub _trm($str) {
$str =~ s/^\s+|\s+$//g;
return $str;
}
+1;
+
1;
\ No newline at end of file
diff --git a/lib/Net/IPManager/Constants.pm b/lib/Net/IPManager/Constants.pm
new file mode 100644
index 00000000..fb18b08f
--- /dev/null
+++ b/lib/Net/IPManager/Constants.pm
@@ -0,0 +1,22 @@
+package Net::IPManager::Constants;
+use strict;
+use warnings FATAL => 'all';
+
+use constant {
+ E_ALREADY_ACQUIRED => 'IP already acquired',
+ E_NO_INTERFACES_CONFIGURED => 'No interfaces configured',
+ E_UNKNOWN_INTERFACE => 'Unknown interface',
+ E_SUBNET_NOT_MATCHING => 'Subnet not matching',
+ E_CANNOT_ACQUIRE_FIRST_OR_LAST => 'Cannot acquire first or last address of subnet',
+};
+
+use base 'Exporter';
+our @EXPORT = qw(
+ E_ALREADY_ACQUIRED
+ E_NO_INTERFACES_CONFIGURED
+ E_UNKNOWN_INTERFACE
+ E_SUBNET_NOT_MATCHING
+ E_CANNOT_ACQUIRE_FIRST_OR_LAST
+);
+
+1;
\ No newline at end of file
diff --git a/lib/WGwrangler.pm b/lib/WGwrangler.pm
index d360f495..1ea2a718 100644
--- a/lib/WGwrangler.pm
+++ b/lib/WGwrangler.pm
@@ -38,19 +38,23 @@ has config => sub {
my $self = shift;
my $config = CallBackery::Model::ConfigJsonSchema->new(
app => $self,
- file => $ENV{WGwrangler_CONFIG} || $self->home->rel_file('etc/wgwrangler.yaml')
+ file => $ENV{WGwrangler_CONFIG_HOME}.'/wgwrangler.yaml' || $self->home->rel_file('etc/wgwrangler.yaml')
);
my $be = $config->schema->{properties}{BACKEND};
$be->{properties} = {
%{$be->{properties}},
- vpn_name => { type => 'string' },
- enable_git => { type => 'boolean' },
- not_applied_suffix => { type => 'string' },
- wireguard_home => { type => 'string' },
- no_apply => { type => 'boolean' },
- wg_apply_command => { type => 'string' },
- wg_show_command => { type => 'string' }
+ vpn_name => { type => 'string' },
+ enable_git => { type => 'boolean' },
+ not_applied_suffix => { type => 'string' },
+ wireguard_home => { type => 'string' },
+ no_apply => { type => 'boolean' },
+ wg_apply_command => { type => 'string' },
+ wg_show_command => { type => 'string' },
+ reserved_ranges => { 'type' => 'object', 'description' => 'Reserved ranges per interface' },
+ default_dns => { 'type' => 'object', 'description' => 'Default dns names per interface' },
+ default_allowed_ips => { 'type' => 'object', 'description' => 'Default allowed ips names per interface' },
+ sender_email => { 'type' => 'string', 'description' => 'Use this address as sender and reply-to email' }
};
push @{$config->schema->{properties}{BACKEND}{required}}, 'wireguard_home';
diff --git a/lib/WGwrangler/GuiPlugin/CommitMessageForm.pm b/lib/WGwrangler/GuiPlugin/CommitMessageForm.pm
index 7a717ea0..78f53401 100644
--- a/lib/WGwrangler/GuiPlugin/CommitMessageForm.pm
+++ b/lib/WGwrangler/GuiPlugin/CommitMessageForm.pm
@@ -84,7 +84,7 @@ has actionCfg => sub ($self) {
];
};
-sub getAllFieldValues ($self, $args) {
+sub getAllFieldValues ($self, $args, $form_data, $qx_locale) {
return [];
}
diff --git a/lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm b/lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm
index 92741e74..0b8d78af 100644
--- a/lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm
+++ b/lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm
@@ -159,6 +159,7 @@ has formCfg => sub ($self) {
label => trm('Allowed IPs'),
widget => 'text',
triggerFormReset => true,
+ reloadOnFormReset => true,
validator => sub ($value, $parameter, $formData) {
return $self->app->wireguardModel->validator('single-ip', $value);
},
@@ -229,6 +230,7 @@ has formCfg => sub ($self) {
label => trm('DNS'),
widget => 'text',
triggerFormReset => true,
+ reloadOnFormReset => true,
validator => sub ($value, $parameter, $formData) {
return $self->app->wireguardModel->validator('single-ip', $value);
},
@@ -319,7 +321,7 @@ has actionCfg => sub ($self) {
'name' => $name,
'endpoint' => $fqdn,
'email' => $email,
- 'sender_email' => $self->config->{'sender-email'},
+ 'sender_email' => $self->config->{'sender_email'},
'device_name' => $device,
'attachment' => {
attributes => {
@@ -432,14 +434,24 @@ sub getAllFieldValues ($self, $args, $formData, $qx_locale) {
}
$data->{'private-key'} = $private_key;
$data->{'public-key'} = $public_key;
+ my $dns = exists($self->config->{'default_dns'}{"$may_interface"}) ? $self->config->{'default_dns'}{"$may_interface"}: '';
+ my $allowed_ips = exists($self->config->{'default_allowed_ips'}{"$may_interface"}) ? join(',',@{$self->config->{'default_allowed_ips'}{"$may_interface"}}): '';
+
+ $data->{DNS} = $dns;
+ $data->{'allowed-ips'} = $allowed_ips;
+ unless ($formData->{currentFormData}{'DNS'}) {
+ $formData->{currentFormData}{'DNS'} = $dns;
+ }
+ unless ($formData->{currentFormData}{'allowed-ips'}) {
+ $formData->{currentFormData}{'allowed-ips'} = $allowed_ips;
+ }
+
$data->{'config_preview'} = generate_preview_config($formData->{currentFormData}, $private_key, $interface_public_key);
}
else {
$data->{'config_preview'} = 'Select an interface first';
}
$data->{'created'} = strftime("%Y-%m-%d %H:%M:%S %z", localtime);
- $data->{'allowed-ips'} = $self->config->{'default-allowed-ips'};
- $data->{'DNS'} = $self->config->{'default-dns'};
return $data;
}
diff --git a/lib/WGwrangler/GuiPlugin/WireguardShow.pm b/lib/WGwrangler/GuiPlugin/WireguardShow.pm
index da98c159..93981a98 100644
--- a/lib/WGwrangler/GuiPlugin/WireguardShow.pm
+++ b/lib/WGwrangler/GuiPlugin/WireguardShow.pm
@@ -15,7 +15,7 @@ All the methods of L plus:
=cut
-has formCfg => sub ($self) {
+has formCfg => sub($self) {
return [
{
@@ -35,7 +35,7 @@ has formCfg => sub ($self) {
]
};
-has tableCfg => sub ($self) {
+has tableCfg => sub($self) {
return [
{
label => trm('Disabled'),
@@ -136,7 +136,7 @@ has tableCfg => sub ($self) {
]
};
-has actionCfg => sub ($self) {
+has actionCfg => sub($self) {
my $bg_config = $self->app->config->cfgHash->{BACKEND};
return [] if $self->user and not $self->user->may('write');
@@ -155,12 +155,13 @@ has actionCfg => sub ($self) {
backend => {
plugin => 'WireguardAddPeerForm',
config => {
- 'default-allowed-ips' => $self->config->{'default-allowed-ips'},
- 'default-dns' => $self->config->{'default-dns'},
- 'sender-email' => $self->config->{'sender-email'},
+ 'default_allowed_ips' => $bg_config->{'default_allowed_ips'},
+ 'default_dns' => $bg_config->{'default_dns'},
+ 'sender_email' => $bg_config->{'sender_email'},
'vpn_name' => $bg_config->{vpn_name},
'no_apply' => $bg_config->{no_apply},
- 'enable_git' => $bg_config->{enable_git}
+ 'enable_git' => $bg_config->{enable_git},
+ 'sender_email' => $bg_config->{sender_email}
}
}
},
@@ -194,7 +195,7 @@ has actionCfg => sub ($self) {
buttonSet => {
enabled => false,
},
- actionHandler => sub ($self, $args) {
+ actionHandler => sub($self, $args) {
my $id = $args->{selection}{'public-key'};
die mkerror(4992, "You have to select a peer first") if not $id;
@@ -307,26 +308,6 @@ has actionCfg => sub ($self) {
];
};
-has grammar => sub ($self) {
- $self->mergeGrammar(
- $self->SUPER::grammar,
- {
- _doc => "Wireguard plugin config",
- _vars => [ qw(default-dns default-allowed-ips sender-email) ],
- 'default-dns' => {
- _doc => 'Default DNS server to be filled in the DNS field',
- },
- 'default-allowed-ips' => {
- _doc => 'Default allowed-ips for new peers'
- },
- 'sender-email' => {
- _doc => 'Value to set in the From: email header',
- _type => 'string'
- }
- },
- );
-};
-
sub getTableRowCount ($self, $args, $qx_locale) {
my $filter = $args->{formData}{wg_interface};
return $self->app->wireguardModel->get_peer_count($filter);
diff --git a/lib/WGwrangler/Model/Email.pm b/lib/WGwrangler/Model/Email.pm
index 0d72a7da..66d8187d 100644
--- a/lib/WGwrangler/Model/Email.pm
+++ b/lib/WGwrangler/Model/Email.pm
@@ -32,7 +32,7 @@ has mailTransport => sub ($self) {
sub getText ($self, $template, $args) {
my $render = $self->template->render_file(
- $self->home->child('templates', $template . '.email.ep'),
+ $ENV{WGwrangler_CONFIG_HOME}.'/'.$template,
$args);
if (ref $render eq 'Mojo::Exception') {
die("Faild to process $template: " . $render->message);
diff --git a/lib/WGwrangler/Model/MailHandler.pm b/lib/WGwrangler/Model/MailHandler.pm
index dc312d48..f12bae53 100644
--- a/lib/WGwrangler/Model/MailHandler.pm
+++ b/lib/WGwrangler/Model/MailHandler.pm
@@ -42,7 +42,7 @@ sub prepare_and_send ($self, $mail_cfg) {
my $send_cfg = {
from => $mail_cfg->{sender_email},
to => $mail_cfg->{email},
- template => 'send_config_by_email',
+ template => 'send_config_by_email.ep',
args => $mail_cfg,
attachments => [ $mail_cfg->{attachment} ]
};
diff --git a/lib/WGwrangler/Model/WireguardDataAdapter.pm b/lib/WGwrangler/Model/WireguardDataAdapter.pm
index a73d8158..6304cc38 100644
--- a/lib/WGwrangler/Model/WireguardDataAdapter.pm
+++ b/lib/WGwrangler/Model/WireguardDataAdapter.pm
@@ -21,14 +21,14 @@ use Wireguard::WGmeta::Wrapper::Show;
use Wireguard::WGmeta::Wrapper::ConfigT;
use Wireguard::WGmeta::Wrapper::Bridge;
use Wireguard::WGmeta::Validator;
-use WGwrangler::Model::IPmanager;
+use Net::IPManager;
use CallBackery::Translate qw(trm);
has app => sub {
die 'app property must be set';
};
-has log => sub ($self) {
+has log => sub($self) {
$self->app->log;
};
@@ -36,7 +36,7 @@ has 'wireguard_home' => sub {
die 'This is a required attribute';
};
-has 'backend_config' => sub ($self) {
+has 'backend_config' => sub($self) {
$self->app->config->cfgHash->{BACKEND}
};
@@ -77,10 +77,10 @@ has 'wg_show' => sub ($self) {
Wireguard::WGmeta::Wrapper::Show->new($self->_get_wg_show_data());
};
-has 'ip_manager' => sub ($self) {
- my $ip_manager = WGwrangler::Model::IPmanager->new();
+has 'ip_manager' => sub($self) {
+ my $ip_manager = Net::IPManager->new();
for my $interface (keys %{$self->wg_meta->{parsed_config}}) {
- _populate_ip_manager($interface, $self->wg_meta, $ip_manager);
+ _populate_ip_manager($interface, $self->wg_meta, $ip_manager, $self->app->bgc);
}
return $ip_manager;
};
@@ -92,14 +92,19 @@ sub _get_wg_show_data ($self) {
sub _reload_callback ($interface, $ref_list_args) {
my ($self) = @{$ref_list_args};
- _populate_ip_manager($interface, $self->wg_meta, $self->ip_manager);
+ _populate_ip_manager($interface, $self->wg_meta, $self->ip_manager, $self->app->bgc);
}
-sub _populate_ip_manager ($interface, $wg_metaT, $ip_manager) {
+sub _populate_ip_manager ($interface, $wg_metaT, $ip_manager, $bgc) {
if (exists $wg_metaT->{parsed_config}{$interface}{$interface}{address}) {
my $interface_networks = $wg_metaT->{parsed_config}{$interface}{$interface}{address};
$ip_manager->populate_range($interface, $interface_networks);
}
+ # Acquire reserved ranges first
+ if (exists($bgc->{'reserved_ranges'}{$interface})) {
+ my $reserved_ranges = join(',', @{$bgc->{'reserved_ranges'}{$interface}});
+ $ip_manager->acquire_multiple($interface, $reserved_ranges);
+ }
for my $identifier ($wg_metaT->get_section_list($interface)) {
unless ($identifier eq $interface) {
my $ips_string = $wg_metaT->{parsed_config}{$interface}{$identifier}{'allowed-ips'};
diff --git a/share/de.po b/share/de.po
index 918c9af5..683c6d55 100644
--- a/share/de.po
+++ b/share/de.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: wgwrangler 0.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-07-18 13:58+0200\n"
+"POT-Creation-Date: 2023-03-17 15:08+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,8 +17,8 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:23
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
msgid "*"
msgstr ""
@@ -26,8 +26,8 @@ msgstr ""
msgid "A device name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:423
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:500
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:426
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:503
msgid "Access Denied"
msgstr ""
@@ -35,13 +35,13 @@ msgstr ""
msgid "Actual Address"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:145
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
msgid "Add Peer"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:92
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
msgid "Add User"
msgstr ""
@@ -122,8 +122,8 @@ msgstr ""
msgid "DNS"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:443
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:517
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:446
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:520
msgid "Data Decoding Problem %1"
msgstr ""
@@ -143,8 +143,8 @@ msgstr ""
msgid "Description"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:77
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
msgid "Device"
msgstr ""
@@ -230,13 +230,13 @@ msgstr ""
msgid "Failed to send mail to %1"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:60
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
msgid "Family Name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:53
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
msgid "Given Name"
msgstr ""
@@ -248,12 +248,12 @@ msgstr ""
msgid "Has to be larger than 0 and a number"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:48
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
msgid "Interface"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "It seems that some parts of"
msgstr ""
@@ -261,8 +261,8 @@ msgstr ""
msgid "List of ip addresses, separated by comma and in CDIR notation"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:63
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
msgid "Name"
msgstr ""
@@ -294,8 +294,8 @@ msgstr ""
msgid "Not enough arguments for validator `alias`"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:74
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
msgid "Note"
msgstr ""
@@ -328,8 +328,8 @@ msgstr ""
msgid "Persistent-keepalive"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:428
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:507
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:431
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:510
msgid "Plugin Name missing"
msgstr ""
@@ -337,8 +337,8 @@ msgstr ""
msgid "Public Key"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:256
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
msgid "Reload Data"
msgstr ""
@@ -386,7 +386,7 @@ msgstr ""
msgid "Transfer-TX"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:434
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:437
msgid "Upload Missing"
msgstr ""
@@ -402,13 +402,13 @@ msgstr ""
msgid "User email - config is sent to this email if desired"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:38
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
msgid "UserId"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:46
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
msgid "Username"
msgstr ""
@@ -441,18 +441,18 @@ msgstr ""
msgid "cardCfg must be defined in child plugin class"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "do not belong to"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:221
+#: lib/WGwrangler/Model/IPmanager.pm:223
msgid "is already acquired"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:227
+#: lib/WGwrangler/Model/IPmanager.pm:229
msgid "overlaps with an already acquired network"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:139
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:92
msgid "sorry, don't know the field you are talking about"
msgstr ""
diff --git a/share/en.po b/share/en.po
index 918c9af5..683c6d55 100644
--- a/share/en.po
+++ b/share/en.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: wgwrangler 0.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-07-18 13:58+0200\n"
+"POT-Creation-Date: 2023-03-17 15:08+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,8 +17,8 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:23
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
msgid "*"
msgstr ""
@@ -26,8 +26,8 @@ msgstr ""
msgid "A device name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:423
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:500
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:426
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:503
msgid "Access Denied"
msgstr ""
@@ -35,13 +35,13 @@ msgstr ""
msgid "Actual Address"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:145
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
msgid "Add Peer"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:92
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
msgid "Add User"
msgstr ""
@@ -122,8 +122,8 @@ msgstr ""
msgid "DNS"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:443
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:517
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:446
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:520
msgid "Data Decoding Problem %1"
msgstr ""
@@ -143,8 +143,8 @@ msgstr ""
msgid "Description"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:77
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
msgid "Device"
msgstr ""
@@ -230,13 +230,13 @@ msgstr ""
msgid "Failed to send mail to %1"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:60
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
msgid "Family Name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:53
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
msgid "Given Name"
msgstr ""
@@ -248,12 +248,12 @@ msgstr ""
msgid "Has to be larger than 0 and a number"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:48
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
msgid "Interface"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "It seems that some parts of"
msgstr ""
@@ -261,8 +261,8 @@ msgstr ""
msgid "List of ip addresses, separated by comma and in CDIR notation"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:63
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
msgid "Name"
msgstr ""
@@ -294,8 +294,8 @@ msgstr ""
msgid "Not enough arguments for validator `alias`"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:74
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
msgid "Note"
msgstr ""
@@ -328,8 +328,8 @@ msgstr ""
msgid "Persistent-keepalive"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:428
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:507
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:431
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:510
msgid "Plugin Name missing"
msgstr ""
@@ -337,8 +337,8 @@ msgstr ""
msgid "Public Key"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:256
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
msgid "Reload Data"
msgstr ""
@@ -386,7 +386,7 @@ msgstr ""
msgid "Transfer-TX"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:434
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:437
msgid "Upload Missing"
msgstr ""
@@ -402,13 +402,13 @@ msgstr ""
msgid "User email - config is sent to this email if desired"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:38
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
msgid "UserId"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:46
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
msgid "Username"
msgstr ""
@@ -441,18 +441,18 @@ msgstr ""
msgid "cardCfg must be defined in child plugin class"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "do not belong to"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:221
+#: lib/WGwrangler/Model/IPmanager.pm:223
msgid "is already acquired"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:227
+#: lib/WGwrangler/Model/IPmanager.pm:229
msgid "overlaps with an already acquired network"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:139
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:92
msgid "sorry, don't know the field you are talking about"
msgstr ""
diff --git a/share/fr.po b/share/fr.po
index 918c9af5..683c6d55 100644
--- a/share/fr.po
+++ b/share/fr.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: wgwrangler 0.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-07-18 13:58+0200\n"
+"POT-Creation-Date: 2023-03-17 15:08+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,8 +17,8 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:23
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
msgid "*"
msgstr ""
@@ -26,8 +26,8 @@ msgstr ""
msgid "A device name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:423
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:500
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:426
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:503
msgid "Access Denied"
msgstr ""
@@ -35,13 +35,13 @@ msgstr ""
msgid "Actual Address"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:145
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
msgid "Add Peer"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:92
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
msgid "Add User"
msgstr ""
@@ -122,8 +122,8 @@ msgstr ""
msgid "DNS"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:443
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:517
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:446
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:520
msgid "Data Decoding Problem %1"
msgstr ""
@@ -143,8 +143,8 @@ msgstr ""
msgid "Description"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:77
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
msgid "Device"
msgstr ""
@@ -230,13 +230,13 @@ msgstr ""
msgid "Failed to send mail to %1"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:60
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
msgid "Family Name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:53
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
msgid "Given Name"
msgstr ""
@@ -248,12 +248,12 @@ msgstr ""
msgid "Has to be larger than 0 and a number"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:48
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
msgid "Interface"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "It seems that some parts of"
msgstr ""
@@ -261,8 +261,8 @@ msgstr ""
msgid "List of ip addresses, separated by comma and in CDIR notation"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:63
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
msgid "Name"
msgstr ""
@@ -294,8 +294,8 @@ msgstr ""
msgid "Not enough arguments for validator `alias`"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:74
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
msgid "Note"
msgstr ""
@@ -328,8 +328,8 @@ msgstr ""
msgid "Persistent-keepalive"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:428
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:507
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:431
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:510
msgid "Plugin Name missing"
msgstr ""
@@ -337,8 +337,8 @@ msgstr ""
msgid "Public Key"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:256
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
msgid "Reload Data"
msgstr ""
@@ -386,7 +386,7 @@ msgstr ""
msgid "Transfer-TX"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:434
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:437
msgid "Upload Missing"
msgstr ""
@@ -402,13 +402,13 @@ msgstr ""
msgid "User email - config is sent to this email if desired"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:38
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
msgid "UserId"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:46
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
msgid "Username"
msgstr ""
@@ -441,18 +441,18 @@ msgstr ""
msgid "cardCfg must be defined in child plugin class"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "do not belong to"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:221
+#: lib/WGwrangler/Model/IPmanager.pm:223
msgid "is already acquired"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:227
+#: lib/WGwrangler/Model/IPmanager.pm:229
msgid "overlaps with an already acquired network"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:139
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:92
msgid "sorry, don't know the field you are talking about"
msgstr ""
diff --git a/share/it.po b/share/it.po
index 918c9af5..683c6d55 100644
--- a/share/it.po
+++ b/share/it.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: wgwrangler 0.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-07-18 13:58+0200\n"
+"POT-Creation-Date: 2023-03-17 15:08+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,8 +17,8 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:23
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:48
msgid "*"
msgstr ""
@@ -26,8 +26,8 @@ msgstr ""
msgid "A device name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:423
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:500
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:426
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:503
msgid "Access Denied"
msgstr ""
@@ -35,13 +35,13 @@ msgstr ""
msgid "Actual Address"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:145
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:367
msgid "Add Peer"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:92
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:205
msgid "Add User"
msgstr ""
@@ -122,8 +122,8 @@ msgstr ""
msgid "DNS"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:443
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:517
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:446
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:520
msgid "Data Decoding Problem %1"
msgstr ""
@@ -143,8 +143,8 @@ msgstr ""
msgid "Description"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:77
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:145
msgid "Device"
msgstr ""
@@ -230,13 +230,13 @@ msgstr ""
msgid "Failed to send mail to %1"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:60
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:94
msgid "Family Name"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:53
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:85
msgid "Given Name"
msgstr ""
@@ -248,12 +248,12 @@ msgstr ""
msgid "Has to be larger than 0 and a number"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:48
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:44
msgid "Interface"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "It seems that some parts of"
msgstr ""
@@ -261,8 +261,8 @@ msgstr ""
msgid "List of ip addresses, separated by comma and in CDIR notation"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:63
+#: lib/WGwrangler/GuiPlugin/WireguardAddPeerForm.pm:117
msgid "Name"
msgstr ""
@@ -294,8 +294,8 @@ msgstr ""
msgid "Not enough arguments for validator `alias`"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:74
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:104
msgid "Note"
msgstr ""
@@ -328,8 +328,8 @@ msgstr ""
msgid "Persistent-keepalive"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:428
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:507
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:431
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:510
msgid "Plugin Name missing"
msgstr ""
@@ -337,8 +337,8 @@ msgstr ""
msgid "Public Key"
msgstr ""
-#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
#: lib/WGwrangler/GuiPlugin/WireguardShow.pm:256
+#: lib/WGwrangler/GuiPlugin/WireguardVersions.pm:126
msgid "Reload Data"
msgstr ""
@@ -386,7 +386,7 @@ msgstr ""
msgid "Transfer-TX"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:434
+#: thirdparty/lib/perl5/CallBackery/Controller/RpcService.pm:437
msgid "Upload Missing"
msgstr ""
@@ -402,13 +402,13 @@ msgstr ""
msgid "User email - config is sent to this email if desired"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:38
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:50
msgid "UserId"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
#: thirdparty/lib/perl5/CallBackery/GuiPlugin/Users.pm:46
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/UserForm.pm:59
msgid "Username"
msgstr ""
@@ -441,18 +441,18 @@ msgstr ""
msgid "cardCfg must be defined in child plugin class"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:236
+#: lib/WGwrangler/Model/IPmanager.pm:238
msgid "do not belong to"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:221
+#: lib/WGwrangler/Model/IPmanager.pm:223
msgid "is already acquired"
msgstr ""
-#: lib/WGwrangler/Model/IPmanager.pm:227
+#: lib/WGwrangler/Model/IPmanager.pm:229
msgid "overlaps with an already acquired network"
msgstr ""
-#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:139
+#: thirdparty/lib/perl5/CallBackery/GuiPlugin/AbstractForm.pm:92
msgid "sorry, don't know the field you are talking about"
msgstr ""
diff --git a/t/IPManager_v4.t b/t/IPManager_v4.t
new file mode 100644
index 00000000..cdefa4e3
--- /dev/null
+++ b/t/IPManager_v4.t
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More;
+
+use experimental 'signatures';
+use FindBin;
+use lib $FindBin::Bin.'/../thirdparty/lib/perl5';
+use lib $FindBin::Bin.'/../lib';
+use Net::IPManager;
+use Net::IPManager::Constants;
+
+my $IPManager = Net::IPManager->new();
+use constant TEST_INTERFACE => 'test-interface';
+
+$IPManager->populate_range(TEST_INTERFACE, '192.168.0.0/24');
+
+# acquire single ip and check if the suggestions are updated accordingly
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '192.168.0.1/32', "Single ip suggestion 1";
+$IPManager->acquire_single(TEST_INTERFACE, '192.168.0.1/32');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '192.168.0.2/32', "Single ip suggestion 2";
+
+# Release ip again and check if suggestions are updated accordingly
+$IPManager->release_ip(TEST_INTERFACE, '192.168.0.1/32');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '192.168.0.1/32', "Single ip successfully released";
+
+# acquire other (higher) ip and check if suggestions are still returning the lowest possible address
+$IPManager->acquire_single(TEST_INTERFACE, '192.168.0.10/32');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '192.168.0.1/32', "Acquire arbitrary and suggest";
+
+# Checks
+# Try to required already occupied address
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.10/32') eq E_ALREADY_ACQUIRED, 'Already acquired';
+
+# Try to acquire/release on unknown interface
+ok $IPManager->acquire_single('DOES NOT EXIST', '192.168.0.10/32') eq E_UNKNOWN_INTERFACE, 'Unknown interface (acquire)';
+ok $IPManager->release_ip('DOES NOT EXIST', '192.168.0.10/32') eq E_UNKNOWN_INTERFACE, 'Unknown interface (acquire)';
+
+# Wrong subnet
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.2.10/32') eq E_SUBNET_NOT_MATCHING, 'Non matching subnet (acquire)';
+
+# Entire networks (192.168.0.0 - 192.168.0.7)
+$IPManager->acquire_single(TEST_INTERFACE, '192.168.0.0/29');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '192.168.0.8/32', 'IP suggestions after network acquire';
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.6/32') eq E_ALREADY_ACQUIRED, 'Try acquiring ip inside acquired subnet';
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.8/29') eq E_ALREADY_ACQUIRED, 'Try acquiring with overlapping subnet';
+
+# Multi acquire
+$IPManager->acquire_multiple(TEST_INTERFACE, '192.168.0.8/32,192.168.0.9/32');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '192.168.0.11/32', 'IP suggestion after multi-acquire';
+
+# try release ip inside acquired subnet
+$IPManager->release_ip(TEST_INTERFACE, '192.168.0.4/32');
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.4/32') eq E_ALREADY_ACQUIRED, 'Try release ip inside subnet';
+
+# try acquire with overlapping subnet
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.8/29') eq E_ALREADY_ACQUIRED, 'Try acquire with overlapping address';
+
+# try acquire first and last address of interface subnet
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.0/32') eq E_CANNOT_ACQUIRE_FIRST_OR_LAST, 'Try acquire first';
+ok $IPManager->acquire_single(TEST_INTERFACE, '192.168.0.255/32') eq E_CANNOT_ACQUIRE_FIRST_OR_LAST, 'Try acquire last';
+
+done_testing();
+
diff --git a/t/IPManager_v6.t b/t/IPManager_v6.t
new file mode 100644
index 00000000..720babef
--- /dev/null
+++ b/t/IPManager_v6.t
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More;
+
+use experimental 'signatures';
+use FindBin;
+use lib $FindBin::Bin.'/../thirdparty/lib/perl5';
+use lib $FindBin::Bin.'/../lib';
+use Net::IPManager;
+use Net::IPManager::Constants;
+
+my $IPManager = Net::IPManager->new();
+use constant TEST_INTERFACE => 'test-interface';
+
+$IPManager->populate_range(TEST_INTERFACE, '2001:db8::/64');
+
+# acquire single ip and check if the suggestions are updated accordingly
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '2001:0db8:0000:0000:0000:0000:0000:0001/128', "Single ip suggestion 1";
+$IPManager->acquire_single(TEST_INTERFACE, '2001:db8::1/128');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '2001:0db8:0000:0000:0000:0000:0000:0002/128', "Single ip suggestion 2";
+
+# Release ip again and check if suggestions are updated accordingly
+$IPManager->release_ip(TEST_INTERFACE, '2001:db8::1/128');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '2001:0db8:0000:0000:0000:0000:0000:0001/128', "Single ip successfully released";
+
+# acquire other (higher) ip and check if suggestions are still returning the lowest possible address
+$IPManager->acquire_single(TEST_INTERFACE, '2001:db8::83/128');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '2001:0db8:0000:0000:0000:0000:0000:0001/128', "Acquire arbitrary and suggest";
+
+# Checks
+# Try to required already occupied address
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:db8::83/128') eq E_ALREADY_ACQUIRED, 'Already acquired';
+
+# Try to acquire/release on unknown interface
+ok $IPManager->acquire_single('DOES NOT EXIST', '2001:db8::a/128') eq E_UNKNOWN_INTERFACE, 'Unknown interface (acquire)';
+ok $IPManager->release_ip('DOES NOT EXIST', '2001:0db8:0000:0000:0000:0000:0000:000a/128') eq E_UNKNOWN_INTERFACE, 'Unknown interface (acquire)';
+
+# Wrong subnet
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:db9::a/128') eq E_SUBNET_NOT_MATCHING, 'Non matching subnet (acquire)';
+
+# Entire networks (2001:db8:: - 2001:db8::7f)
+$IPManager->acquire_single(TEST_INTERFACE, '2001:db8::2/128');
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:db8::/121') eq E_ALREADY_ACQUIRED, 'Try acquiring overlapping subnet';
+# release ::2 and try again
+$IPManager->release_ip(TEST_INTERFACE, '2001:db8::2/128');
+$IPManager->acquire_single(TEST_INTERFACE, '2001:db8::/121');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '2001:0db8:0000:0000:0000:0000:0000:0080/128', 'IP suggestions after network acquire';
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:db8::6f') eq E_ALREADY_ACQUIRED, 'Try acquiring ip inside acquired subnet';
+
+# Multi acquire
+$IPManager->acquire_single(TEST_INTERFACE, '2001:0db8:0000:0000:0000:0000:0000:0080/128');
+ok $IPManager->suggest_ip(TEST_INTERFACE) eq '2001:0db8:0000:0000:0000:0000:0000:0081/128', 'IP suggestion after multi-acquire';
+
+# try release ip inside acquired subnet
+$IPManager->release_ip(TEST_INTERFACE, '2001:db8::12/128');
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:db8::12/128') eq E_ALREADY_ACQUIRED, 'Try release ip inside subnet';
+
+# try acquire first and last address of interface subnet
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:db8::/128') eq E_CANNOT_ACQUIRE_FIRST_OR_LAST, 'Try acquire first';
+ok $IPManager->acquire_single(TEST_INTERFACE, '2001:0db8:0000:0000:ffff:ffff:ffff:ffff/128') eq E_CANNOT_ACQUIRE_FIRST_OR_LAST, 'Try acquire last';
+
+done_testing();
+
diff --git a/t/dummy_home/show_dummy b/t/dummy_home/show_dummy
index 54c061a5..cefd9d4f 100644
--- a/t/dummy_home/show_dummy
+++ b/t/dummy_home/show_dummy
@@ -1,4 +1,4 @@
wg0 eOSNqjwOrtIQMOaVxOXXdGjvgQ6gIzS09ltKJMjAPl8= MN6ipoevVEFdsQ+vciTdsgeD30e9w0qT2jPZOFotmHQ= 51861 off
-wg0 2mO59ijYCvfJUi6pnNO0H697xiZHTzs4mLA5da5m13w= (none) 89.333.25.1:5589 10.0.2.1/32 0 1234 5985 off
-wg0 KpXASgjXPh5xtIxFclQUZzq4PuqbDfHT1CaU8shTsVE= (none) 8.8.8.8:42 10.0.2.1/32 0 4242 4242 off
-wg0 Mu46ORALOMuD/T/uyuBiJNecOps4q80TB6BH6F2W9SA= (none) 45.68.254.22:6633 10.0.2.1/32 0 5 10 off
+wg0 2mO59ijYCvfJUi6pnNO0H697xiZHTzs4mLA5da5m13w= (none) 89.333.25.1:5589 10.0.10.50/32 0 1234 5985 off
+wg0 KpXASgjXPh5xtIxFclQUZzq4PuqbDfHT1CaU8shTsVE= (none) 8.8.8.8:42 10.0.10.51/32 0 4242 4242 off
+wg0 Mu46ORALOMuD/T/uyuBiJNecOps4q80TB6BH6F2W9SA= (none) 45.68.254.22:6633 10.0.10.52/32 0 5 10 off
diff --git a/t/dummy_home/wg0.conf b/t/dummy_home/wg0.conf
index b855c0dc..9b7b335e 100644
--- a/t/dummy_home/wg0.conf
+++ b/t/dummy_home/wg0.conf
@@ -1,4 +1,4 @@
-#+Checksum = 3186310980
+#+Checksum = 1626909375
[Interface]
Address = 10.0.10.0/24, fdc9:281f:04d7:9ee9::0/64
@@ -9,7 +9,7 @@ PrivateKey = MN6ipoevVEFdsQ+vciTdsgeD30e9w0qT2jPZOFotmHQ=
[Peer]
#+name = CCCCC
PublicKey = 2mO59ijYCvfJUi6pnNO0H697xiZHTzs4mLA5da5m13w=
-AllowedIPs = 10.0.10.1/32
+AllowedIPs = 10.0.10.50/32
#+Alias = tes
#+device = wefwefef
#+description = wefwefwef
@@ -17,29 +17,45 @@ AllowedIPs = 10.0.10.1/32
[Peer]
#+name = DDDDD
PublicKey = KpXASgjXPh5xtIxFclQUZzq4PuqbDfHT1CaU8shTsVE=
-AllowedIPs = 10.0.10.2/32
+AllowedIPs = 10.0.10.51/32
#+email = wefwefwef@ttt.com
#+description = zöziöwaqdwqdqwdwadqwdqwd
#-[Peer]
#-#+name = Tester
#-PublicKey = Mu46ORALOMuD/T/uyuBiJNecOps4q80TB6BH6F2W9SA=
-#-AllowedIPs = 10.0.10.6/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0006/128
+#-AllowedIPs = 10.0.10.52/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0006/128
#-#+Email = hans@bla.com
#-#+Description = iu.i.uä0äu90
[Peer]
#+name = OOOOOOOO
PublicKey = mUkItQOH7RkFNod+fT3glxilssdj79MSoXtBS4Ip/3M=
-AllowedIPs = 10.0.10.7/32
+AllowedIPs = 10.0.10.53/32
#+description = Hallo das ist ein Testwefwef
#+email = hallo@test.com
-#-[Peer]
-#-PublicKey = dummy_pub_key
-#-AllowedIPs = 10.0.10.1/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0001/128
-#-#+name = Hansli_tab2
-#-#+email = hansli@gmx.ch
-#-#+device = hansli_tab_device
-#-#+created = 2021-07-18 13:15:05 +0200
-#-#+description = DSEC with spaces
+[Peer]
+PublicKey = dummy_pub_key
+AllowedIPs = 10.0.10.54/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0001/128
+#+name = Hansli_tab2
+#+email = hansli@gmx.ch
+#+device = hansli_tab_device
+#+created = 2021-07-18 13:15:05 +0200
+#+description = DSEC with spaces
+
+[Peer]
+PublicKey = dummy_pub_key8818
+AllowedIPs = 10.0.10.8/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0001/128
+#+name = Tobias
+#+email = bossert@oetiker.ch
+#+device = Bla
+#+created = 2023-03-17 19:00:09 +0100
+
+[Peer]
+PublicKey = dummy_pub_key761
+AllowedIPs = fdc9:281f:04d7:9ee9:0000:0000:0000:0000/128
+#+name = T
+#+email = bossert@oetiker.ch
+#+device = wef
+#+created = 2023-03-17 19:01:16 +0100
diff --git a/t/dummy_home/wg1.conf b/t/dummy_home/wg1.conf
index 18b4f5a7..e8376c42 100644
--- a/t/dummy_home/wg1.conf
+++ b/t/dummy_home/wg1.conf
@@ -9,14 +9,14 @@ PrivateKey = MN6ipoevVEFdsQ+vciTdsgeD30e9w0qT2jPZOFotmHQ=
[Peer]
#+name = CCCCC
PublicKey = 2mO59ijYCvfJUi6pnNO0H697xiZHTzs4mLA5da5m13w=
-AllowedIPs = 10.0.0.1/32
+AllowedIPs = 10.0.0.30/32
#+Alias = tes
#+description = Added in file
#-[Peer]
#-#+name = DDDDD
#-PublicKey = KpXASgjXPh5xtIxFclQUZzq4PuqbDfHT1CaU8shTsVE=
-#-AllowedIPs = 10.0.0.2/32
+#-AllowedIPs = 10.0.0.35/32
#-#+email = wefwefwef@ttt.com
#-#+description = Das ist ein Test
#-#+device = Hello_device
@@ -24,14 +24,14 @@ AllowedIPs = 10.0.0.1/32
[Peer]
#+name = Tester
PublicKey = Mu46ORALOMuD/T/uyuBiJNecOps4q80TB6BH6F2W9SA=
-AllowedIPs = 10.0.0.6/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0006/128
+AllowedIPs = 10.0.0.31/32,fdc9:281f:04d7:9ee9:0000:0000:0000:0006/128
#+email = hans@bla.com
#+description = iu.i.uä0äu90
[Peer]
#+name = OOOOOOOO
PublicKey = mUkItQOH7RkFNod+fT3glxilssdj79MSoXtBS4Ip/3M=
-AllowedIPs = 10.0.0.7/32
+AllowedIPs = 10.0.0.31/32
#+description = Hallo das ist ein Testwefwef
#+email = hallo@test.com
diff --git a/t/etc/send_config_by_email.ep b/t/etc/send_config_by_email.ep
new file mode 100644
index 00000000..0d766f66
--- /dev/null
+++ b/t/etc/send_config_by_email.ep
@@ -0,0 +1,27 @@
+Subject: Wireguard VPN Configuration
+Reply-To: <%= $sender_email %>
+----
+Dear <%= $name %>
+This is your vpn configuration for your device "<%= $device_name %>" to access <%= $endpoint %>.
+Install a Wireguard client https://www.wireguard.com/install
+Add the config file attached to this message
+
+enjoy!
+----
+
+
+
+Dear <%= $name %>
+This is your vpn configuration for your device "<%= $device_name %>" to access <%= $endpoint %>.
+
+ - Install a Wireguard client.
+ - Add the config file attached to this message
+
+Your Wireguard Configuration as a QR Code, readable by mobile Wireguard clients
+
+
+
+enjoy!
+
+
\ No newline at end of file
diff --git a/t/etc/wgwrangler.yaml b/t/etc/wgwrangler.yaml
index 931aa213..1b5a34db 100644
--- a/t/etc/wgwrangler.yaml
+++ b/t/etc/wgwrangler.yaml
@@ -6,11 +6,24 @@ BACKEND:
sesame_pass: wedfwfewqf
vpn_name: your_vpn_name
enable_git: false
- no_apply: true
+ no_apply: false
not_applied_suffix: .not_applied
wireguard_home: t/dummy_home/
wg_apply_command: echo "applied for %interface%"
wg_show_command: cat t/dummy_home/show_dummy
+ reserved_ranges:
+ wg0:
+ - 10.0.10.0/29
+ default_dns:
+ wg0: 192.168.0.1
+ wg1: 9.9.9.9
+ default_allowed_ips:
+ wg0:
+ - 0.0.0.0/0
+ - 192.168.1.0/32
+ wg1:
+ - 192.168.0.0/24
+ sender_email: support@oetiker.ch
FRONTEND:
# logo = ../resource/wgwrangler/logo.png
@@ -31,9 +44,6 @@ PLUGIN:
- WireguardShow:
module: WireguardShow
tab-name: Wireguard
- default-dns: 10.0.0.1
- default-allowed-ips: 10.0.0.0/24
- sender-email: support@oetiker.ch
- WireguardVersions:
module: WireguardVersions