luci-proto-wireguard: handle multiple peers in imported configuration

When importing a fully configuration, import all peer entries from it
instead of non-deterministically merging all peer keys into one.

When importing a remote configuration as peer, only use the setting from
the peer section matching our local interface pubkey.

Also relabel the `Import peer configuration` button to
`Import configuration as peer` in order to be more explicit.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
(cherry picked from commit 94bfa33452)
This commit is contained in:
Jo-Philipp Wich 2022-08-01 13:00:31 +02:00
parent d09fbe0bbf
commit 18e6040bb8

View file

@ -253,20 +253,26 @@ return network.registerProtocol('wireguard', {
ss.parseConfig = function(data) {
var lines = String(data).split(/(\r?\n)+/),
section = null,
config = {};
config = { peers: [] },
s;
for (var i = 0; i < lines.length; i++) {
var line = lines[i].replace(/#.*$/, '').trim();
if (line.match(/^\[(\w+)\]$/)) {
section = RegExp.$1.toLowerCase();
if (section == 'peer')
config.peers.push(s = {});
else
s = config;
}
else if (section && line.match(/^(\w+)\s*=\s*(.+)$/)) {
var key = RegExp.$1,
val = RegExp.$2.trim();
if (val.length)
config[section + '_' + key.toLowerCase()] = val;
s[section + '_' + key.toLowerCase()] = val;
}
}
@ -292,37 +298,41 @@ return network.registerProtocol('wireguard', {
if (!stubValidator.apply('port', config.interface_listenport || '0'))
return _('ListenPort setting is invalid');
if (config.peer_publickey != null && validateBase64(null, config.peer_publickey) !== true)
return _('PublicKey setting is invalid');
for (var i = 0; i < config.peers.length; i++) {
var pconf = config.peers[i];
if (config.peer_presharedkey != null && validateBase64(null, config.peer_presharedkey) !== true)
return _('PresharedKey setting is invalid');
if (pconf.peer_publickey != null && validateBase64(null, pconf.peer_publickey) !== true)
return _('PublicKey setting is invalid');
if (config.peer_allowedips) {
config.peer_allowedips = config.peer_allowedips.split(/[, ]+/);
if (pconf.peer_presharedkey != null && validateBase64(null, pconf.peer_presharedkey) !== true)
return _('PresharedKey setting is invalid');
for (var i = 0; i < config.peer_allowedips.length; i++)
if (!stubValidator.apply('ipaddr', config.peer_allowedips[i]))
return _('AllowedIPs setting is invalid');
if (pconf.peer_allowedips) {
pconf.peer_allowedips = pconf.peer_allowedips.split(/[, ]+/);
for (var j = 0; j < pconf.peer_allowedips.length; j++)
if (!stubValidator.apply('ipaddr', pconf.peer_allowedips[j]))
return _('AllowedIPs setting is invalid');
}
else {
pconf.peer_allowedips = [ '0.0.0.0/0', '::/0' ];
}
if (pconf.peer_endpoint) {
var host_port = pconf.peer_endpoint.match(/^\[([a-fA-F0-9:]+)\]:(\d+)$/) || pconf.peer_endpoint.match(/^(.+):(\d+)$/);
if (!host_port || !stubValidator.apply('host', host_port[1]) || !stubValidator.apply('port', host_port[2]))
return _('Endpoint setting is invalid');
pconf.peer_endpoint = [ host_port[1], host_port[2] ];
}
if (pconf.peer_persistentkeepalive == 'off' || pconf.peer_persistentkeepalive == '0')
delete pconf.peer_persistentkeepalive;
if (!stubValidator.apply('port', pconf.peer_persistentkeepalive || '0'))
return _('PersistentKeepAlive setting is invalid');
}
else {
config.peer_allowedips = [ '0.0.0.0/0', '::/0' ];
}
if (config.peer_endpoint) {
var host_port = config.peer_endpoint.match(/^\[([a-fA-F0-9:]+)\]:(\d+)$/) || config.peer_endpoint.match(/^(.+):(\d+)$/);
if (!host_port || !stubValidator.apply('host', host_port[1]) || !stubValidator.apply('port', host_port[2]))
return _('Endpoint setting is invalid');
config.peer_endpoint = [ host_port[1], host_port[2] ];
}
if (config.peer_persistentkeepalive == 'off' || config.peer_persistentkeepalive == '0')
delete config.peer_persistentkeepalive;
if (!stubValidator.apply('port', config.peer_persistentkeepalive || '0'))
return _('PersistentKeepAlive setting is invalid');
return config;
};
@ -356,22 +366,25 @@ return network.registerProtocol('wireguard', {
s.getOption('dns').getUIElement(s.section).setValue(config.interface_dns);
}
var sid = uci.add('network', 'wireguard_' + s.section);
for (var i = 0; i < config.peers.length; i++) {
var pconf = config.peers[i];
var sid = uci.add('network', 'wireguard_' + s.section);
uci.sections('network', 'wireguard_' + s.section, function(peer) {
if (peer.public_key == config.peer_publickey)
uci.remove('network', peer['.name']);
});
uci.sections('network', 'wireguard_' + s.section, function(peer) {
if (peer.public_key == pconf.peer_publickey)
uci.remove('network', peer['.name']);
});
uci.set('network', sid, 'description', comment || _('Imported peer configuration'));
uci.set('network', sid, 'public_key', config.peer_publickey);
uci.set('network', sid, 'preshared_key', config.peer_presharedkey);
uci.set('network', sid, 'allowed_ips', config.peer_allowedips);
uci.set('network', sid, 'persistent_keepalive', config.peer_persistentkeepalive);
uci.set('network', sid, 'description', comment || _('Imported peer configuration'));
uci.set('network', sid, 'public_key', pconf.peer_publickey);
uci.set('network', sid, 'preshared_key', pconf.peer_presharedkey);
uci.set('network', sid, 'allowed_ips', pconf.peer_allowedips);
uci.set('network', sid, 'persistent_keepalive', pconf.peer_persistentkeepalive);
if (config.peer_endpoint) {
uci.set('network', sid, 'endpoint_host', config.peer_endpoint[0]);
uci.set('network', sid, 'endpoint_port', config.peer_endpoint[1]);
if (pconf.peer_endpoint) {
uci.set('network', sid, 'endpoint_host', pconf.peer_endpoint[0]);
uci.set('network', sid, 'endpoint_port', pconf.peer_endpoint[1]);
}
}
return s.map.save(null, true);
@ -382,6 +395,7 @@ return network.registerProtocol('wireguard', {
else {
return getPublicAndPrivateKeyFromPrivate(config.interface_privatekey).then(function(keypair) {
var sid = uci.add('network', 'wireguard_' + s.section);
var pub = s.formvalue(s.section, 'public_key');
uci.sections('network', 'wireguard_' + s.section, function(peer) {
if (peer.public_key == keypair.pub)
@ -391,9 +405,17 @@ return network.registerProtocol('wireguard', {
uci.set('network', sid, 'description', comment || _('Imported peer configuration'));
uci.set('network', sid, 'public_key', keypair.pub);
uci.set('network', sid, 'private_key', keypair.priv);
uci.set('network', sid, 'preshared_key', config.peer_presharedkey);
uci.set('network', sid, 'allowed_ips', config.peer_allowedips);
uci.set('network', sid, 'persistent_keepalive', config.peer_persistentkeepalive);
for (var i = 0; i < config.peers.length; i++) {
var pconf = config.peers[i];
if (pconf.peer_publickey == pub) {
uci.set('network', sid, 'preshared_key', pconf.peer_presharedkey);
uci.set('network', sid, 'allowed_ips', pconf.peer_allowedips);
uci.set('network', sid, 'persistent_keepalive', pconf.peer_persistentkeepalive);
break;
}
}
return s.map.save(null, true);
}).then(function() {
@ -481,7 +503,7 @@ return network.registerProtocol('wireguard', {
nodes.appendChild(E('button', {
'class': 'btn',
'click': ui.createHandlerFn(this, 'handleConfigImport', 'peer')
}, [ _('Import peer configuration…') ]));
}, [ _('Import configuration as peer…') ]));
return nodes;
};