2020-03-27 09:27:18 +00:00
'use strict' ;
2020-04-09 12:39:09 +00:00
'require view' ;
'require dom' ;
'require poll' ;
2020-03-27 09:27:18 +00:00
'require rpc' ;
'require uci' ;
'require form' ;
'require validation' ;
var callHostHints , callDUIDHints , callDHCPLeases , CBILeaseStatus , CBILease6Status ;
callHostHints = rpc . declare ( {
object : 'luci-rpc' ,
method : 'getHostHints' ,
expect : { '' : { } }
} ) ;
callDUIDHints = rpc . declare ( {
object : 'luci-rpc' ,
method : 'getDUIDHints' ,
expect : { '' : { } }
} ) ;
callDHCPLeases = rpc . declare ( {
object : 'luci-rpc' ,
method : 'getDHCPLeases' ,
expect : { '' : { } }
} ) ;
CBILeaseStatus = form . DummyValue . extend ( {
renderWidget : function ( section _id , option _id , cfgvalue ) {
return E ( [
E ( 'h4' , _ ( 'Active DHCP Leases' ) ) ,
E ( 'div' , { 'id' : 'lease_status_table' , 'class' : 'table' } , [
E ( 'div' , { 'class' : 'tr table-titles' } , [
E ( 'div' , { 'class' : 'th' } , _ ( 'Hostname' ) ) ,
E ( 'div' , { 'class' : 'th' } , _ ( 'IPv4-Address' ) ) ,
E ( 'div' , { 'class' : 'th' } , _ ( 'MAC-Address' ) ) ,
E ( 'div' , { 'class' : 'th' } , _ ( 'Lease time remaining' ) )
] ) ,
E ( 'div' , { 'class' : 'tr placeholder' } , [
E ( 'div' , { 'class' : 'td' } , E ( 'em' , _ ( 'Collecting data...' ) ) )
] )
] )
] ) ;
}
} ) ;
CBILease6Status = form . DummyValue . extend ( {
renderWidget : function ( section _id , option _id , cfgvalue ) {
return E ( [
E ( 'h4' , _ ( 'Active DHCPv6 Leases' ) ) ,
E ( 'div' , { 'id' : 'lease6_status_table' , 'class' : 'table' } , [
E ( 'div' , { 'class' : 'tr table-titles' } , [
E ( 'div' , { 'class' : 'th' } , _ ( 'Host' ) ) ,
E ( 'div' , { 'class' : 'th' } , _ ( 'IPv6-Address' ) ) ,
E ( 'div' , { 'class' : 'th' } , _ ( 'DUID' ) ) ,
E ( 'div' , { 'class' : 'th' } , _ ( 'Lease time remaining' ) )
] ) ,
E ( 'div' , { 'class' : 'tr placeholder' } , [
E ( 'div' , { 'class' : 'td' } , E ( 'em' , _ ( 'Collecting data...' ) ) )
] )
] )
] ) ;
}
} ) ;
function validateHostname ( sid , s ) {
2020-05-20 08:46:25 +00:00
if ( s == null || s == '' )
return true ;
2020-03-27 09:27:18 +00:00
if ( s . length > 256 )
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid hostname' ) ) ;
var labels = s . replace ( /^\.+|\.$/g , '' ) . split ( /\./ ) ;
for ( var i = 0 ; i < labels . length ; i ++ )
if ( ! labels [ i ] . match ( /^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i ) )
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid hostname' ) ) ;
return true ;
}
function validateAddressList ( sid , s ) {
if ( s == null || s == '' )
return true ;
var m = s . match ( /^\/(.+)\/$/ ) ,
names = m ? m [ 1 ] . split ( /\// ) : [ s ] ;
for ( var i = 0 ; i < names . length ; i ++ ) {
var res = validateHostname ( sid , names [ i ] ) ;
if ( res !== true )
return res ;
}
return true ;
}
function validateServerSpec ( sid , s ) {
if ( s == null || s == '' )
return true ;
2020-05-20 08:46:25 +00:00
var m = s . match ( /^(?:\/(.+)\/)?(.*)$/ ) ;
2020-03-27 09:27:18 +00:00
if ( ! m )
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid hostname' ) ) ;
var res = validateAddressList ( sid , m [ 1 ] ) ;
if ( res !== true )
return res ;
if ( m [ 2 ] == '' || m [ 2 ] == '#' )
return true ;
// ipaddr%scopeid#srvport@source@interface#srcport
m = m [ 2 ] . match ( /^([0-9a-f:.]+)(?:%[^#@]+)?(?:#(\d+))?(?:@([0-9a-f:.]+)(?:@[^#]+)?(?:#(\d+))?)?$/ ) ;
if ( ! m )
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid IP address' ) ) ;
2020-05-20 08:46:25 +00:00
if ( validation . parseIPv4 ( m [ 1 ] ) ) {
if ( m [ 3 ] != null && ! validation . parseIPv4 ( m [ 3 ] ) )
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid IPv4 address' ) ) ;
}
else if ( validation . parseIPv6 ( m [ 1 ] ) ) {
if ( m [ 3 ] != null && ! validation . parseIPv6 ( m [ 3 ] ) )
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid IPv6 address' ) ) ;
}
else {
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid IP address' ) ) ;
}
if ( ( m [ 2 ] != null && + m [ 2 ] > 65535 ) || ( m [ 4 ] != null && + m [ 4 ] > 65535 ) )
2020-03-27 09:27:18 +00:00
return _ ( 'Expecting: %s' ) . format ( _ ( 'valid port value' ) ) ;
return true ;
}
2020-04-09 12:39:09 +00:00
return view . extend ( {
2020-03-27 09:27:18 +00:00
load : function ( ) {
return Promise . all ( [
callHostHints ( ) ,
callDUIDHints ( )
] ) ;
} ,
render : function ( hosts _duids ) {
var has _dhcpv6 = L . hasSystemFeature ( 'dnsmasq' , 'dhcpv6' ) || L . hasSystemFeature ( 'odhcpd' ) ,
hosts = hosts _duids [ 0 ] ,
duids = hosts _duids [ 1 ] ,
m , s , o , ss , so ;
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' ) ) ;
s . anonymous = true ;
s . addremove = false ;
s . tab ( 'general' , _ ( 'General Settings' ) ) ;
s . tab ( 'files' , _ ( 'Resolv and Hosts Files' ) ) ;
s . tab ( 'tftp' , _ ( 'TFTP Settings' ) ) ;
s . tab ( 'advanced' , _ ( 'Advanced Settings' ) ) ;
s . tab ( 'leases' , _ ( 'Static Leases' ) ) ;
s . taboption ( 'general' , form . Flag , 'domainneeded' ,
_ ( 'Domain required' ) ,
_ ( 'Don\'t forward <abbr title="Domain Name System">DNS</abbr>-Requests without <abbr title="Domain Name System">DNS</abbr>-Name' ) ) ;
s . taboption ( 'general' , form . Flag , 'authoritative' ,
_ ( 'Authoritative' ) ,
_ ( 'This is the only <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr> in the local network' ) ) ;
s . taboption ( 'files' , form . Flag , 'readethers' ,
_ ( 'Use <code>/etc/ethers</code>' ) ,
_ ( 'Read <code>/etc/ethers</code> to configure the <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr>-Server' ) ) ;
s . taboption ( 'files' , form . Value , 'leasefile' ,
_ ( 'Leasefile' ) ,
_ ( 'file where given <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr>-leases will be stored' ) ) ;
s . taboption ( 'files' , form . Flag , 'noresolv' ,
_ ( 'Ignore resolve file' ) ) . optional = true ;
o = s . taboption ( 'files' , form . Value , 'resolvfile' ,
_ ( 'Resolve file' ) ,
_ ( 'local <abbr title="Domain Name System">DNS</abbr> file' ) ) ;
o . depends ( 'noresolv' , '0' ) ;
o . placeholder = '/tmp/resolv.conf.d/resolv.conf.auto' ;
o . optional = true ;
s . taboption ( 'files' , form . Flag , 'nohosts' ,
_ ( 'Ignore <code>/etc/hosts</code>' ) ) . optional = true ;
s . taboption ( 'files' , form . DynamicList , 'addnhosts' ,
_ ( 'Additional Hosts files' ) ) . optional = true ;
o = s . taboption ( 'advanced' , form . Flag , 'quietdhcp' ,
_ ( 'Suppress logging' ) ,
_ ( 'Suppress logging of the routine operation of these protocols' ) ) ;
o . optional = true ;
o = s . taboption ( 'advanced' , form . Flag , 'sequential_ip' ,
_ ( 'Allocate IP sequentially' ) ,
_ ( 'Allocate IP addresses sequentially, starting from the lowest available address' ) ) ;
o . optional = true ;
o = s . taboption ( 'advanced' , form . Flag , 'boguspriv' ,
_ ( 'Filter private' ) ,
_ ( 'Do not forward reverse lookups for local networks' ) ) ;
o . default = o . enabled ;
s . taboption ( 'advanced' , form . Flag , 'filterwin2k' ,
_ ( 'Filter useless' ) ,
_ ( 'Do not forward requests that cannot be answered by public name servers' ) ) ;
s . taboption ( 'advanced' , form . Flag , 'localise_queries' ,
_ ( 'Localise queries' ) ,
_ ( 'Localise hostname depending on the requesting subnet if multiple IPs are available' ) ) ;
if ( L . hasSystemFeature ( 'dnsmasq' , 'dnssec' ) ) {
o = s . taboption ( 'advanced' , form . Flag , 'dnssec' ,
_ ( 'DNSSEC' ) ) ;
o . optional = true ;
o = s . taboption ( 'advanced' , form . Flag , 'dnsseccheckunsigned' ,
_ ( 'DNSSEC check unsigned' ) ,
_ ( 'Requires upstream supports DNSSEC; verify unsigned domain responses really come from unsigned domains' ) ) ;
o . default = o . enabled ;
o . optional = true ;
}
s . taboption ( 'general' , form . Value , 'local' ,
_ ( 'Local server' ) ,
_ ( 'Local domain specification. Names matching this domain are never forwarded and are resolved from DHCP or hosts files only' ) ) ;
s . taboption ( 'general' , form . Value , 'domain' ,
_ ( 'Local domain' ) ,
_ ( 'Local domain suffix appended to DHCP names and hosts file entries' ) ) ;
s . taboption ( 'advanced' , form . Flag , 'expandhosts' ,
_ ( 'Expand hosts' ) ,
_ ( 'Add local domain suffix to names served from hosts files' ) ) ;
s . taboption ( 'advanced' , form . Flag , 'nonegcache' ,
_ ( 'No negative cache' ) ,
_ ( 'Do not cache negative replies, e.g. for not existing domains' ) ) ;
s . taboption ( 'advanced' , form . Value , 'serversfile' ,
_ ( 'Additional servers file' ) ,
_ ( 'This file may contain lines like \'server=/domain/1.2.3.4\' or \'server=1.2.3.4\' for domain-specific or full upstream <abbr title="Domain Name System">DNS</abbr> servers.' ) ) ;
s . taboption ( 'advanced' , form . Flag , 'strictorder' ,
_ ( 'Strict order' ) ,
_ ( '<abbr title="Domain Name System">DNS</abbr> servers will be queried in the order of the resolvfile' ) ) . optional = true ;
s . taboption ( 'advanced' , form . Flag , 'allservers' ,
_ ( 'All Servers' ) ,
_ ( 'Query all available upstream <abbr title="Domain Name System">DNS</abbr> servers' ) ) . optional = true ;
o = s . taboption ( 'advanced' , form . DynamicList , 'bogusnxdomain' , _ ( 'Bogus NX Domain Override' ) ,
_ ( 'List of hosts that supply bogus NX domain results' ) ) ;
o . optional = true ;
o . placeholder = '67.215.65.132' ;
s . taboption ( 'general' , form . Flag , 'logqueries' ,
_ ( 'Log queries' ) ,
_ ( 'Write received DNS requests to syslog' ) ) . optional = true ;
o = s . taboption ( 'general' , form . DynamicList , 'server' , _ ( 'DNS forwardings' ) ,
_ ( 'List of <abbr title="Domain Name System">DNS</abbr> servers to forward requests to' ) ) ;
o . optional = true ;
o . placeholder = '/example.org/10.1.2.3' ;
// o.validate = validateServerSpec;
2020-09-18 13:23:21 +00:00
o = s . taboption ( 'general' , form . DynamicList , 'address' , _ ( 'Addresses' ) ,
_ ( 'List of domains to force to an IP address.' ) ) ;
o . optional = true ;
o . placeholder = '/router.local/192.168.0.1' ;
2020-03-27 09:27:18 +00:00
o = s . taboption ( 'general' , form . Flag , 'rebind_protection' ,
_ ( 'Rebind protection' ) ,
_ ( 'Discard upstream RFC1918 responses' ) ) ;
o . rmempty = false ;
o = s . taboption ( 'general' , form . Flag , 'rebind_localhost' ,
_ ( 'Allow localhost' ) ,
_ ( 'Allow upstream responses in the 127.0.0.0/8 range, e.g. for RBL services' ) ) ;
o . depends ( 'rebind_protection' , '1' ) ;
o = s . taboption ( 'general' , form . DynamicList , 'rebind_domain' ,
_ ( 'Domain whitelist' ) ,
_ ( 'List of domains to allow RFC1918 responses for' ) ) ;
o . optional = true ;
o . depends ( 'rebind_protection' , '1' ) ;
o . placeholder = 'ihost.netflix.com' ;
o . validate = validateAddressList ;
o = s . taboption ( 'advanced' , form . Value , 'port' ,
_ ( '<abbr title="Domain Name System">DNS</abbr> server port' ) ,
_ ( 'Listening port for inbound DNS queries' ) ) ;
o . optional = true ;
o . datatype = 'port' ;
o . placeholder = 53 ;
o = s . taboption ( 'advanced' , form . Value , 'queryport' ,
_ ( '<abbr title="Domain Name System">DNS</abbr> query port' ) ,
_ ( 'Fixed source port for outbound DNS queries' ) ) ;
o . optional = true ;
o . datatype = 'port' ;
o . placeholder = _ ( 'any' ) ;
o = s . taboption ( 'advanced' , form . Value , 'dhcpleasemax' ,
_ ( '<abbr title="maximal">Max.</abbr> <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr> leases' ) ,
_ ( 'Maximum allowed number of active DHCP leases' ) ) ;
o . optional = true ;
o . datatype = 'uinteger' ;
o . placeholder = _ ( 'unlimited' ) ;
o = s . taboption ( 'advanced' , form . Value , 'ednspacket_max' ,
_ ( '<abbr title="maximal">Max.</abbr> <abbr title="Extension Mechanisms for Domain Name System">EDNS0</abbr> packet size' ) ,
_ ( 'Maximum allowed size of EDNS.0 UDP packets' ) ) ;
o . optional = true ;
o . datatype = 'uinteger' ;
o . placeholder = 1280 ;
o = s . taboption ( 'advanced' , form . Value , 'dnsforwardmax' ,
_ ( '<abbr title="maximal">Max.</abbr> concurrent queries' ) ,
_ ( 'Maximum allowed number of concurrent DNS queries' ) ) ;
o . optional = true ;
o . datatype = 'uinteger' ;
o . placeholder = 150 ;
o = s . taboption ( 'advanced' , form . Value , 'cachesize' ,
_ ( 'Size of DNS query cache' ) ,
_ ( 'Number of cached DNS entries (max is 10000, 0 is no caching)' ) ) ;
o . optional = true ;
o . datatype = 'range(0,10000)' ;
o . placeholder = 150 ;
s . taboption ( 'tftp' , form . Flag , 'enable_tftp' ,
_ ( 'Enable TFTP server' ) ) . optional = true ;
o = s . taboption ( 'tftp' , form . Value , 'tftp_root' ,
_ ( 'TFTP server root' ) ,
_ ( 'Root directory for files served via TFTP' ) ) ;
o . optional = true ;
o . depends ( 'enable_tftp' , '1' ) ;
o . placeholder = '/' ;
o = s . taboption ( 'tftp' , form . Value , 'dhcp_boot' ,
_ ( 'Network boot image' ) ,
_ ( 'Filename of the boot image advertised to clients' ) ) ;
o . optional = true ;
o . depends ( 'enable_tftp' , '1' ) ;
o . placeholder = 'pxelinux.0' ;
o = s . taboption ( 'general' , form . Flag , 'localservice' ,
_ ( 'Local Service Only' ) ,
_ ( 'Limit DNS service to subnets interfaces on which we are serving DNS.' ) ) ;
o . optional = false ;
o . rmempty = false ;
o = s . taboption ( 'general' , form . Flag , 'nonwildcard' ,
_ ( 'Non-wildcard' ) ,
_ ( 'Bind dynamically to interfaces rather than wildcard address (recommended as linux default)' ) ) ;
o . default = o . enabled ;
o . optional = false ;
o . rmempty = true ;
o = s . taboption ( 'general' , form . DynamicList , 'interface' ,
_ ( 'Listen Interfaces' ) ,
_ ( 'Limit listening to these interfaces, and loopback.' ) ) ;
o . optional = true ;
o = s . taboption ( 'general' , form . DynamicList , 'notinterface' ,
_ ( 'Exclude interfaces' ) ,
_ ( 'Prevent listening on these interfaces.' ) ) ;
o . optional = true ;
o = s . taboption ( 'leases' , form . SectionValue , '__leases__' , form . GridSection , 'host' , null ,
_ ( 'Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.' ) + '<br />' +
_ ( 'Use the <em>Add</em> Button to add a new lease entry. The <em>MAC-Address</em> identifies the host, the <em>IPv4-Address</em> specifies the fixed address to use, and the <em>Hostname</em> is assigned as a symbolic name to the requesting host. The optional <em>Lease time</em> can be used to set non-standard host-specific lease time, e.g. 12h, 3d or infinite.' ) ) ;
ss = o . subsection ;
ss . addremove = true ;
ss . anonymous = true ;
so = ss . option ( form . Value , 'name' , _ ( 'Hostname' ) ) ;
so . validate = validateHostname ;
so . rmempty = true ;
so . write = function ( section , value ) {
uci . set ( 'dhcp' , section , 'name' , value ) ;
uci . set ( 'dhcp' , section , 'dns' , '1' ) ;
} ;
so . remove = function ( section ) {
uci . unset ( 'dhcp' , section , 'name' ) ;
uci . unset ( 'dhcp' , section , 'dns' ) ;
} ;
so = ss . option ( form . Value , 'mac' , _ ( '<abbr title="Media Access Control">MAC</abbr>-Address' ) ) ;
so . datatype = 'list(unique(macaddr))' ;
so . rmempty = true ;
so . cfgvalue = function ( section ) {
2020-10-19 13:10:06 +00:00
var macs = L . toArray ( uci . get ( 'dhcp' , section , 'mac' ) ) ,
2020-03-27 09:27:18 +00:00
result = [ ] ;
for ( var i = 0 , mac ; ( mac = macs [ i ] ) != null ; i ++ )
if ( /^([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2})$/ . test ( mac ) )
result . push ( '%02X:%02X:%02X:%02X:%02X:%02X' . format (
parseInt ( RegExp . $1 , 16 ) , parseInt ( RegExp . $2 , 16 ) ,
parseInt ( RegExp . $3 , 16 ) , parseInt ( RegExp . $4 , 16 ) ,
parseInt ( RegExp . $5 , 16 ) , parseInt ( RegExp . $6 , 16 ) ) ) ;
return result . length ? result . join ( ' ' ) : null ;
} ;
so . renderWidget = function ( section _id , option _index , cfgvalue ) {
var node = form . Value . prototype . renderWidget . apply ( this , [ section _id , option _index , cfgvalue ] ) ,
ipopt = this . section . children . filter ( function ( o ) { return o . option == 'ip' } ) [ 0 ] ;
node . addEventListener ( 'cbi-dropdown-change' , L . bind ( function ( ipopt , section _id , ev ) {
var mac = ev . detail . value . value ;
if ( mac == null || mac == '' || ! hosts [ mac ] || ! hosts [ mac ] . ipv4 )
return ;
var ip = ipopt . formvalue ( section _id ) ;
if ( ip != null && ip != '' )
return ;
var node = ipopt . map . findElement ( 'id' , ipopt . cbid ( section _id ) ) ;
if ( node )
2020-04-09 12:39:09 +00:00
dom . callClassMethod ( node , 'setValue' , hosts [ mac ] . ipv4 ) ;
2020-03-27 09:27:18 +00:00
} , this , ipopt , section _id ) ) ;
return node ;
} ;
Object . keys ( hosts ) . forEach ( function ( mac ) {
var hint = hosts [ mac ] . name || hosts [ mac ] . ipv4 ;
so . value ( mac , hint ? '%s (%s)' . format ( mac , hint ) : mac ) ;
} ) ;
so = ss . option ( form . Value , 'ip' , _ ( '<abbr title="Internet Protocol Version 4">IPv4</abbr>-Address' ) ) ;
so . datatype = 'or(ip4addr,"ignore")' ;
so . validate = function ( section , value ) {
var mac = this . map . lookupOption ( 'mac' , section ) ,
name = this . map . lookupOption ( 'name' , section ) ,
m = mac ? mac [ 0 ] . formvalue ( section ) : null ,
n = name ? name [ 0 ] . formvalue ( section ) : null ;
if ( ( m == null || m == '' ) && ( n == null || n == '' ) )
return _ ( 'One of hostname or mac address must be specified!' ) ;
return true ;
} ;
Object . keys ( hosts ) . forEach ( function ( mac ) {
if ( hosts [ mac ] . ipv4 ) {
var hint = hosts [ mac ] . name ;
so . value ( hosts [ mac ] . ipv4 , hint ? '%s (%s)' . format ( hosts [ mac ] . ipv4 , hint ) : hosts [ mac ] . ipv4 ) ;
}
} ) ;
so = ss . option ( form . Value , 'gw' , _ ( 'Gateway' ) ) ;
so . datatype = 'or(ip4addr,"ignore")' ;
so . rmempty = true ;
so = ss . option ( form . Value , 'leasetime' , _ ( 'Lease time' ) ) ;
so . rmempty = true ;
so = ss . option ( form . Value , 'duid' , _ ( '<abbr title="The DHCP Unique Identifier">DUID</abbr>' ) ) ;
so . datatype = 'and(rangelength(20,36),hexstring)' ;
Object . keys ( duids ) . forEach ( function ( duid ) {
so . value ( duid , '%s (%s)' . format ( duid , duids [ duid ] . hostname || duids [ duid ] . macaddr || duids [ duid ] . ip6addr || '?' ) ) ;
} ) ;
so = ss . option ( form . Value , 'hostid' , _ ( '<abbr title="Internet Protocol Version 6">IPv6</abbr>-Suffix (hex)' ) ) ;
o = s . taboption ( 'leases' , CBILeaseStatus , '__status__' ) ;
if ( has _dhcpv6 )
o = s . taboption ( 'leases' , CBILease6Status , '__status6__' ) ;
return m . render ( ) . then ( function ( mapEl ) {
2020-04-09 12:39:09 +00:00
poll . add ( function ( ) {
2020-03-27 09:27:18 +00:00
return callDHCPLeases ( ) . then ( function ( leaseinfo ) {
var leases = Array . isArray ( leaseinfo . dhcp _leases ) ? leaseinfo . dhcp _leases : [ ] ,
leases6 = Array . isArray ( leaseinfo . dhcp6 _leases ) ? leaseinfo . dhcp6 _leases : [ ] ;
cbi _update _table ( mapEl . querySelector ( '#lease_status_table' ) ,
leases . map ( function ( lease ) {
var exp ;
if ( lease . expires === false )
exp = E ( 'em' , _ ( 'unlimited' ) ) ;
else if ( lease . expires <= 0 )
exp = E ( 'em' , _ ( 'expired' ) ) ;
else
exp = '%t' . format ( lease . expires ) ;
return [
lease . hostname || '?' ,
lease . ipaddr ,
lease . macaddr ,
exp
] ;
} ) ,
E ( 'em' , _ ( 'There are no active leases' ) ) ) ;
if ( has _dhcpv6 ) {
cbi _update _table ( mapEl . querySelector ( '#lease6_status_table' ) ,
leases6 . map ( function ( lease ) {
var exp ;
if ( lease . expires === false )
exp = E ( 'em' , _ ( 'unlimited' ) ) ;
else if ( lease . expires <= 0 )
exp = E ( 'em' , _ ( 'expired' ) ) ;
else
exp = '%t' . format ( lease . expires ) ;
var hint = lease . macaddr ? hosts [ lease . macaddr ] : null ,
name = hint ? ( hint . name || hint . ipv4 || hint . ipv6 ) : null ,
host = null ;
if ( name && lease . hostname && lease . hostname != name && lease . ip6addr != name )
host = '%s (%s)' . format ( lease . hostname , name ) ;
else if ( lease . hostname )
host = lease . hostname ;
else if ( name )
host = name ;
return [
host || '-' ,
lease . ip6addrs ? lease . ip6addrs . join ( ' ' ) : lease . ip6addr ,
lease . duid ,
exp
] ;
} ) ,
E ( 'em' , _ ( 'There are no active leases' ) ) ) ;
}
} ) ;
} ) ;
return mapEl ;
} ) ;
}
} ) ;