mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-19 11:04:42 +00:00
VPN: WireGuard / Peer config builder - add a new option to generate client configs and store their public parts on this firewall. closes https://github.com/opnsense/core/issues/7308
Endpoints are stored in the instance option as these are only relevant for the client (e.g. servers fqdn:port). Default allowed ip's for clients are all, we might consider storing these in the instance at some point as well, but lets avoid toggles nobody asked for yet.
This commit is contained in:
parent
1d593fe984
commit
13b685a0a7
@ -130,4 +130,14 @@ class ClientController extends ApiMutableModelControllerBase
|
||||
{
|
||||
return $this->toggleBase('clients.client', $uuid);
|
||||
}
|
||||
|
||||
public function getClientBuilderAction()
|
||||
{
|
||||
return $this->getBase('configbuilder', 'clients.client', null);
|
||||
}
|
||||
|
||||
public function addClientBuilderAction()
|
||||
{
|
||||
return $this->addBase('configbuilder', 'clients.client');
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 Deciso B.V.
|
||||
* Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -29,11 +30,20 @@ namespace OPNsense\Wireguard;
|
||||
|
||||
class GeneralController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
protected function templateJSIncludes()
|
||||
{
|
||||
$result = parent::templateJSIncludes();
|
||||
$result[] = '/ui/js/jquery.qrcode.js';
|
||||
$result[] = '/ui/js/qrcode.js';
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->generalForm = $this->getForm("general");
|
||||
$this->view->formDialogEditWireguardClient = $this->getForm("dialogEditWireguardClient");
|
||||
$this->view->formDialogEditWireguardServer = $this->getForm("dialogEditWireguardServer");
|
||||
$this->view->formDialogConfigBuilder = $this->getForm("dialogConfigBuilder");
|
||||
$this->view->pick('OPNsense/Wireguard/general');
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>configbuilder.servers</id>
|
||||
<label>Instance</label>
|
||||
<type>dropdown</type>
|
||||
<help>Choose an instance to create a new peer for.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.endpoint</id>
|
||||
<label>Endpoint</label>
|
||||
<type>text</type>
|
||||
<help>Specify how to reach the instance, usually the public address of this firewall. (e.g. my.endpoint.local:51820)</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.name</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
<help>Set the name for this peer.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.pubkey</id>
|
||||
<label>Public key</label>
|
||||
<type>text</type>
|
||||
<help>Public key of this peer. You can generate the key using the private key piped to "wg pubkey".</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.privkey</id>
|
||||
<label>Public key</label>
|
||||
<type>text</type>
|
||||
<help>Private key of this peer, not stored on this host, only used for the configuration below.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.psk</id>
|
||||
<label>Pre-shared key</label>
|
||||
<type>text</type>
|
||||
<help>Optional shared secret (PSK) for this peer.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.tunneladdress</id>
|
||||
<label>Allowed IPs</label>
|
||||
<type>text</type>
|
||||
<help>List of networks allowed to pass trough the tunnel adapter. Use CIDR notation like 10.0.0.0/24.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.keepalive</id>
|
||||
<label>Keepalive interval</label>
|
||||
<type>text</type>
|
||||
<help>Set persistent keepalive interval in seconds.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>configbuilder.output</id>
|
||||
<label>Config</label>
|
||||
<type>textbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<label>Store and generate next</label>
|
||||
<id>configbuilder.store_btn</id>
|
||||
<type>info</type>
|
||||
<help>Store the public parts of this peer and generate a keypair for the next.</help>
|
||||
</field>
|
||||
</form>
|
||||
@ -3,8 +3,9 @@
|
||||
<WireGuard cssClass="fa fa-lock fa-fw">
|
||||
<Instances order="10" url="/ui/wireguard/general#instances"/>
|
||||
<Peers order="20" url="/ui/wireguard/general#peers"/>
|
||||
<Status order="30" url="/ui/wireguard/diagnostics/"/>
|
||||
<LogFile order="40" VisibleName="Log File" url="/ui/diagnostics/log/core/wireguard"/>
|
||||
<Configbuilder order="30" url="/ui/wireguard/general#configbuilder"/>
|
||||
<Status order="40" url="/ui/wireguard/diagnostics/"/>
|
||||
<LogFile order="50" VisibleName="Log File" url="/ui/diagnostics/log/core/wireguard"/>
|
||||
</WireGuard>
|
||||
</VPN>
|
||||
</menu>
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
</check001>
|
||||
</Constraints>
|
||||
</disableroutes>
|
||||
<endpoint type="TextField"/>
|
||||
<gateway type="NetworkField"/>
|
||||
<carp_depend_on type="VirtualIPField">
|
||||
<type>carp</type>
|
||||
@ -66,7 +67,7 @@
|
||||
</template>
|
||||
</Model>
|
||||
<Multiple>Y</Multiple>
|
||||
<ValidationMessage>Choose an Peer.</ValidationMessage>
|
||||
<ValidationMessage>Choose a peer.</ValidationMessage>
|
||||
</peers>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
@ -33,8 +33,7 @@
|
||||
$('.selectpicker').selectpicker('refresh');
|
||||
});
|
||||
|
||||
let grid_peers = $("#grid-peers").UIBootgrid(
|
||||
{
|
||||
let grid_peers = $("#grid-peers").UIBootgrid({
|
||||
search: '/api/wireguard/client/searchClient',
|
||||
get: '/api/wireguard/client/getClient/',
|
||||
set: '/api/wireguard/client/setClient/',
|
||||
@ -48,11 +47,8 @@
|
||||
}
|
||||
return request;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
});
|
||||
grid_peers.on("loaded.rs.jquery.bootgrid", function (e){
|
||||
// reload servers before grid load
|
||||
if ($("#server_filter > option").length == 0) {
|
||||
@ -68,16 +64,14 @@
|
||||
}
|
||||
});
|
||||
|
||||
$("#grid-instances").UIBootgrid(
|
||||
{
|
||||
search: '/api/wireguard/server/searchServer',
|
||||
get: '/api/wireguard/server/getServer/',
|
||||
set: '/api/wireguard/server/setServer/',
|
||||
add: '/api/wireguard/server/addServer/',
|
||||
del: '/api/wireguard/server/delServer/',
|
||||
toggle: '/api/wireguard/server/toggleServer/'
|
||||
}
|
||||
);
|
||||
$("#grid-instances").UIBootgrid({
|
||||
search: '/api/wireguard/server/searchServer',
|
||||
get: '/api/wireguard/server/getServer/',
|
||||
set: '/api/wireguard/server/setServer/',
|
||||
add: '/api/wireguard/server/addServer/',
|
||||
del: '/api/wireguard/server/delServer/',
|
||||
toggle: '/api/wireguard/server/toggleServer/'
|
||||
});
|
||||
|
||||
|
||||
$("#reconfigureAct").SimpleActionButton({
|
||||
@ -110,11 +104,124 @@
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
/**
|
||||
* Quick instance filter on top
|
||||
*/
|
||||
$("#filter_container").detach().prependTo('#grid-peers-header > .row > .actionBar > .actions');
|
||||
$("#server_filter").change(function(){
|
||||
$('#grid-peers').bootgrid('reload');
|
||||
});
|
||||
|
||||
/**
|
||||
* Config maker tab hooks
|
||||
*/
|
||||
$("#control_label_configbuilder\\.psk").append($("#pskgen_cb_div").detach().show());
|
||||
$("#pskgen_cb").click(function(){
|
||||
ajaxGet("/api/wireguard/client/psk", {}, function(data, status){
|
||||
if (data.status && data.status === 'ok') {
|
||||
$("#configbuilder\\.psk").val(data.psk).change();
|
||||
}
|
||||
});
|
||||
})
|
||||
let tmp = $("#configbuilder\\.output").closest('tr');
|
||||
tmp.find('td:eq(2)').empty().append($("<div id='qrcode'/>"));
|
||||
$("#configbuilder\\.output").css('max-width', '100%');
|
||||
$("#configbuilder\\.output").css('height', '256px');
|
||||
$("#configbuilder\\.output").change(function(){
|
||||
$('#qrcode').empty().qrcode($(this).val());
|
||||
});
|
||||
|
||||
$("#configbuilder\\.servers").change(function(){
|
||||
ajaxGet('/api/wireguard/server/getServer/' + $(this).val(), {}, function(data, status) {
|
||||
if (data.server) {
|
||||
let endpoint = $("#configbuilder\\.endpoint");
|
||||
endpoint
|
||||
.val(data.server.endpoint)
|
||||
.data('org-value', data.server.endpoint)
|
||||
.data('pubkey', data.server.pubkey)
|
||||
.change();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#configbuilder\\.store_btn").replaceWith($("#btn_configbuilder_save"));
|
||||
|
||||
$("#btn_configbuilder_save").click(function(){
|
||||
let instance_id = $("#configbuilder\\.servers").val();
|
||||
let endpoint = $("#configbuilder\\.endpoint");
|
||||
let peer = {
|
||||
configbuilder: {
|
||||
enabled: '1',
|
||||
name: $("#configbuilder\\.name").val(),
|
||||
pubkey: $("#configbuilder\\.pubkey").val(),
|
||||
psk: $("#configbuilder\\.psk").val(),
|
||||
tunneladdress: $("#configbuilder\\.tunneladdress").val(),
|
||||
keepalive: $("#configbuilder\\.keepalive").val(),
|
||||
servers: instance_id,
|
||||
}
|
||||
};
|
||||
ajaxCall('/api/wireguard/client/addClientBuilder', peer, function(data, status) {
|
||||
if (data.validations) {
|
||||
handleFormValidation("frm_config_builder", data.validations);
|
||||
} else {
|
||||
if (endpoint.val() != endpoint.data('org-value')) {
|
||||
let param = {'server': {'endpoint': endpoint.val()}};
|
||||
ajaxCall('/api/wireguard/server/setServer/' + instance_id, param, function(data, status){
|
||||
configbuilder_new();
|
||||
});
|
||||
} else {
|
||||
configbuilder_new();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('input[id ^= "configbuilder\\."]').change(configbuilder_update_config);
|
||||
$('select[id ^= "configbuilder\\."]').change(configbuilder_update_config);
|
||||
|
||||
function configbuilder_new()
|
||||
{
|
||||
mapDataToFormUI({'frm_config_builder':"/api/wireguard/client/get_client_builder"}).done(function(data){
|
||||
formatTokenizersUI();
|
||||
$('.selectpicker').selectpicker('refresh');
|
||||
ajaxGet("/api/wireguard/server/key_pair", {}, function(data, status){
|
||||
if (data.status && data.status === 'ok') {
|
||||
$("#configbuilder\\.pubkey").val(data.pubkey);
|
||||
$("#configbuilder\\.privkey").val(data.privkey).change();
|
||||
}
|
||||
});
|
||||
$("#configbuilder\\.tunneladdress").val("0.0.0.0/0,::/0");
|
||||
clearFormValidation("frm_config_builder");
|
||||
});
|
||||
}
|
||||
|
||||
function configbuilder_update_config()
|
||||
{
|
||||
let rows = [];
|
||||
rows.push('[Interface]');
|
||||
rows.push('PrivateKey = ' + $("#configbuilder\\.privkey").val());
|
||||
rows.push('');
|
||||
rows.push('[Peer]');
|
||||
rows.push('PublicKey = ' + $("#configbuilder\\.endpoint").data('pubkey'));
|
||||
if ($("#configbuilder\\.psk").val()) {
|
||||
rows.push('PresharedKey = ' + $("#configbuilder\\.psk").val());
|
||||
}
|
||||
rows.push('Endpoint = ' + $("#configbuilder\\.endpoint").val());
|
||||
rows.push('AllowedIPs = ' + $("#configbuilder\\.tunneladdress").val());
|
||||
if ($("#configbuilder\\.keepalive").val()) {
|
||||
rows.push('PersistentKeepalive = ' + $("#configbuilder\\.keepalive").val());
|
||||
}
|
||||
$("#configbuilder\\.output").val(rows.join("\n")).change();
|
||||
}
|
||||
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
if (e.target.id == 'tab_configbuilder'){
|
||||
configbuilder_new();
|
||||
} else if (e.target.id == 'tab_peers') {
|
||||
$('#grid-peers').bootgrid('reload');
|
||||
}
|
||||
});
|
||||
|
||||
// update history on tab state and implement navigation
|
||||
if(window.location.hash != "") {
|
||||
$('a[href="' + window.location.hash + '"]').click()
|
||||
@ -130,12 +237,13 @@
|
||||
|
||||
<!-- Navigation bar -->
|
||||
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
|
||||
<li class="active"><a data-toggle="tab" href="#instances">{{ lang._('Instances') }}</a></li>
|
||||
<li><a data-toggle="tab" href="#peers">{{ lang._('Peers') }}</a></li>
|
||||
<li class="active"><a data-toggle="tab" id="tab_instances" href="#instances">{{ lang._('Instances') }}</a></li>
|
||||
<li><a data-toggle="tab" id="tab_peers" href="#peers">{{ lang._('Peers') }}</a></li>
|
||||
<li><a data-toggle="tab" id="tab_configbuilder" href="#configbuilder">{{ lang._('Peer config builder') }}</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content content-box tab-content">
|
||||
<div id="peers" class="tab-pane fade in active">
|
||||
<div id="peers" class="tab-pane fade in">
|
||||
<span id="pskgen_div" style="display:none" class="pull-right">
|
||||
<button id="pskgen" type="button" class="btn btn-secondary" title="{{ lang._('Generate new psk.') }}" data-toggle="tooltip">
|
||||
<i class="fa fa-fw fa-gear"></i>
|
||||
@ -175,7 +283,7 @@
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="instances" class="tab-pane fade in">
|
||||
<div id="instances" class="tab-pane fade in active">
|
||||
<span id="keygen_div" style="display:none" class="pull-right">
|
||||
<button id="keygen" type="button" class="btn btn-secondary" title="{{ lang._('Generate new keypair.') }}" data-toggle="tooltip">
|
||||
<i class="fa fa-fw fa-gear"></i>
|
||||
@ -207,6 +315,20 @@
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div id="configbuilder" class="tab-pane fade in">
|
||||
<span id="pskgen_cb_div" style="display:none" class="pull-right">
|
||||
<button id="pskgen_cb" type="button" class="btn btn-secondary" title="{{ lang._('Generate new psk.') }}" data-toggle="tooltip">
|
||||
<i class="fa fa-fw fa-gear"></i>
|
||||
</button>
|
||||
</span>
|
||||
<span id="configbuilder_div" style="display:none">
|
||||
<button id="btn_configbuilder_save" type="button" class="btn btn-primary">
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
{{ partial("layout_partials/base_form",['fields':formDialogConfigBuilder,'id':'frm_config_builder'])}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="page-content-main">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user