]> git.ipfire.org Git - people/ms/ipfire-2.x.git/commitdiff
wireguard.cgi: Send the N2N peer configuration to the client
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 6 Dec 2024 18:50:33 +0000 (19:50 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 22 Apr 2025 14:48:53 +0000 (16:48 +0200)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
config/cfgroot/wireguard-functions.pl
html/cgi-bin/wireguard.cgi

index 33d9032c221878c874330aca8dbee3e7f97d2704..bfed3f4a546aeef2186d5a4bbaedb97a1bbb79a9 100644 (file)
@@ -338,6 +338,58 @@ sub free_pool_addresses($$) {
        return @free_addresses;
 }
 
+sub generate_net_configuration($$) {
+       my $key = shift;
+       my $private_key = shift;
+
+       # Load the peer
+       my %peer = &load_peer($key);
+
+       # Return if we could not find the peer
+       return undef unless (%peer);
+
+       # Return if this is not a network peer
+       return undef unless ($peer{'TYPE'} eq 'net');
+
+       my @allowed_ips = ();
+
+       # Convert all subnets into CIDR notation
+       foreach my $subnet ($peer{'LOCAL_SUBNETS'}) {
+               my $netaddress = &Network::get_netaddress($subnet);
+               my $prefix     = &Network::get_prefix($subnet);
+
+               # Skip invalid subnets
+               next if (!defined $netaddress || !defined $prefix);
+
+               push(@allowed_ips, "${netaddress}/${prefix}");
+       }
+
+       my $endpoint = $settings{'ENDPOINT'};
+
+       # If no endpoint is set, we fall back to the FQDN of the firewall
+       if ($endpoint eq "") {
+               $endpoint = $General::mainsettings{'HOSTNAME'} . "." . $General::mainsettings{'DOMAINNAME'};
+       }
+
+       # Derive our own public key
+       my $public_key = &derive_public_key($peer{'PRIVATE_KEY'});
+
+       my @conf = (
+               "[Interface]",
+               "PrivateKey = $private_key",
+               "Port = $peer{'ENDPOINT_PORT'}",
+               "",
+               "[Peer]",
+               "Endpoint = ${endpoint}:$peer{'PORT'}",
+               "PublicKey = $public_key",
+               "PresharedKey = $peer{'PSK'}",
+               "AllowedIPs = " . join(", ", @allowed_ips),
+               "PersistentKeepalive = $peer{'KEEPALIVE'}",
+       );
+
+       return join("\n", @conf);
+}
+
 sub generate_host_configuration($) {
        my $key = shift;
 
index 82751fe1eb35cc170c3c547039acf23327a64cf9..a98a6f68057998311362d8229b53e31eb60d906c 100644 (file)
@@ -171,13 +171,15 @@ if ($cgiparams{"ACTION"} eq $Lang::tr{'save'}) {
        # 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($cgiparams{"NAME"})) {
+       unless (&Wireguard::name_is_valid($name)) {
                push(@errormessages, $Lang::tr{'wg invalid name'});
        }
 
        # Check if the name is free
-       unless (&Wireguard::name_is_free($cgiparams{"NAME"}, $key)) {
+       unless (&Wireguard::name_is_free($name, $key)) {
                push(@errormessages, $Lang::tr{'wg name is already used'});
        }
 
@@ -248,7 +250,7 @@ if ($cgiparams{"ACTION"} eq $Lang::tr{'save'}) {
                # 1 = Type
                "net",
                # 2 = Name
-               $cgiparams{"NAME"},
+               $name,
                # 3 = Remote Public Key
                $remote_public_key,
                # 4 = Local Private Key
@@ -279,6 +281,45 @@ if ($cgiparams{"ACTION"} eq $Lang::tr{'save'}) {
                &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_net_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>
+                               <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 = ();