luci-mod-network: improve static DHCP lease validation
- Ensure that MAC addresses are unique within the same pool
- Ensure that IP addresses are globally unique
- Ensure that IP addresses are within any DHCP pool range
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
(cherry picked from commit 7e56289538
)
This commit is contained in:
parent
e3ef035260
commit
e8b8a9be64
1 changed files with 115 additions and 6 deletions
|
@ -5,6 +5,7 @@
|
|||
'require rpc';
|
||||
'require uci';
|
||||
'require form';
|
||||
'require network';
|
||||
'require validation';
|
||||
|
||||
var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status;
|
||||
|
@ -65,6 +66,58 @@ CBILease6Status = form.DummyValue.extend({
|
|||
}
|
||||
});
|
||||
|
||||
function calculateNetwork(addr, mask) {
|
||||
addr = validation.parseIPv4(addr);
|
||||
|
||||
if (!isNaN(mask))
|
||||
mask = validation.parseIPv4(network.prefixToMask(+mask));
|
||||
else
|
||||
mask = validation.parseIPv4(mask);
|
||||
|
||||
if (addr == null || mask == null)
|
||||
return null;
|
||||
|
||||
return [
|
||||
[
|
||||
addr[0] & (mask[0] >>> 0 & 255),
|
||||
addr[1] & (mask[1] >>> 0 & 255),
|
||||
addr[2] & (mask[2] >>> 0 & 255),
|
||||
addr[3] & (mask[3] >>> 0 & 255)
|
||||
].join('.'),
|
||||
mask.join('.')
|
||||
];
|
||||
}
|
||||
|
||||
function getDHCPPools() {
|
||||
return uci.load('dhcp').then(function() {
|
||||
let sections = uci.sections('dhcp', 'dhcp'),
|
||||
tasks = [], pools = [];
|
||||
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
if (sections[i].ignore == '1' || !sections[i].interface)
|
||||
continue;
|
||||
|
||||
tasks.push(network.getNetwork(sections[i].interface).then(L.bind(function(section_id, net) {
|
||||
var cidr = (net.getIPAddrs()[0] || '').split('/');
|
||||
|
||||
if (cidr.length == 2) {
|
||||
var net_mask = calculateNetwork(cidr[0], cidr[1]);
|
||||
|
||||
pools.push({
|
||||
section_id: section_id,
|
||||
network: net_mask[0],
|
||||
netmask: net_mask[1]
|
||||
});
|
||||
}
|
||||
}, null, sections[i]['.name'])));
|
||||
}
|
||||
|
||||
return Promise.all(tasks).then(function() {
|
||||
return pools;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validateHostname(sid, s) {
|
||||
if (s == null || s == '')
|
||||
return true;
|
||||
|
@ -138,20 +191,58 @@ function validateServerSpec(sid, s) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function validateMACAddr(pools, sid, s) {
|
||||
if (s == null || s == '')
|
||||
return true;
|
||||
|
||||
var leases = uci.sections('dhcp', 'host'),
|
||||
this_macs = L.toArray(s).map(function(m) { return m.toUpperCase() });
|
||||
|
||||
for (var i = 0; i < pools.length; i++) {
|
||||
var this_net_mask = calculateNetwork(uci.get('dhcp', sid, 'ip'), pools[i].netmask);
|
||||
|
||||
if (!this_net_mask)
|
||||
continue;
|
||||
|
||||
for (var j = 0; j < leases.length; j++) {
|
||||
if (leases[j]['.name'] == sid || !leases[j].ip)
|
||||
continue;
|
||||
|
||||
var lease_net_mask = calculateNetwork(leases[j].ip, pools[i].netmask);
|
||||
|
||||
if (!lease_net_mask || this_net_mask[0] != lease_net_mask[0])
|
||||
continue;
|
||||
|
||||
var lease_macs = L.toArray(leases[j].mac).map(function(m) { return m.toUpperCase() });
|
||||
|
||||
for (var k = 0; k < lease_macs.length; k++)
|
||||
for (var l = 0; l < this_macs.length; l++)
|
||||
if (lease_macs[k] == this_macs[l])
|
||||
return _('The MAC address %h is already used by another static lease in the same DHCP pool').format(this_macs[l]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
callHostHints(),
|
||||
callDUIDHints()
|
||||
callDUIDHints(),
|
||||
getDHCPPools()
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(hosts_duids) {
|
||||
render: function(hosts_duids_pools) {
|
||||
var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'),
|
||||
hosts = hosts_duids[0],
|
||||
duids = hosts_duids[1],
|
||||
hosts = hosts_duids_pools[0],
|
||||
duids = hosts_duids_pools[1],
|
||||
pools = hosts_duids_pools[2],
|
||||
m, s, o, ss, so;
|
||||
|
||||
console.debug(pools);
|
||||
|
||||
m = new form.Map('dhcp', _('DHCP and DNS'), _('Dnsmasq is a combined <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr>-Server and <abbr title="Domain Name System">DNS</abbr>-Forwarder for <abbr title="Network Address Translation">NAT</abbr> firewalls'));
|
||||
|
||||
s = m.section(form.TypedSection, 'dnsmasq', _('Server Settings'));
|
||||
|
@ -429,7 +520,7 @@ return view.extend({
|
|||
};
|
||||
|
||||
so = ss.option(form.Value, 'mac', _('<abbr title="Media Access Control">MAC</abbr>-Address'));
|
||||
so.datatype = 'list(unique(macaddr))';
|
||||
so.datatype = 'list(macaddr)';
|
||||
so.rmempty = true;
|
||||
so.cfgvalue = function(section) {
|
||||
var macs = L.toArray(uci.get('dhcp', section, 'mac')),
|
||||
|
@ -468,6 +559,7 @@ return view.extend({
|
|||
|
||||
return node;
|
||||
};
|
||||
so.validate = validateMACAddr.bind(so, pools);
|
||||
Object.keys(hosts).forEach(function(mac) {
|
||||
var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0];
|
||||
so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac);
|
||||
|
@ -484,7 +576,24 @@ return view.extend({
|
|||
if ((m == null || m == '') && (n == null || n == ''))
|
||||
return _('One of hostname or mac address must be specified!');
|
||||
|
||||
return true;
|
||||
if (value == null || value == '' || value == 'ignore')
|
||||
return true;
|
||||
|
||||
var leases = uci.sections('dhcp', 'host');
|
||||
|
||||
for (var i = 0; i < leases.length; i++)
|
||||
if (leases[i]['.name'] != section && leases[i].ip == value)
|
||||
return _('The IP address %h is already used by another static lease').format(value);
|
||||
|
||||
|
||||
for (var i = 0; i < pools.length; i++) {
|
||||
var net_mask = calculateNetwork(value, pools[i].netmask);
|
||||
|
||||
if (net_mask && net_mask[0] == pools[i].network)
|
||||
return true;
|
||||
}
|
||||
|
||||
return _('The IP address is outside of any DHCP pool address range');
|
||||
};
|
||||
|
||||
var ipaddrs = {};
|
||||
|
|
Loading…
Reference in a new issue