return E([
E('h2', _('Firewall - Custom Rules')),
E('p', {}, _('Custom rules allow you to execute arbitrary iptables commands which are not otherwise covered by the firewall framework. The commands are executed after each firewall restart, right after the default ruleset has been loaded.')),
- E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 10 }, [ fwuser != null ? fwuser : '' ]))
+ E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 25 }, [ fwuser != null ? fwuser : '' ]))
]);
},
]);
ifaces.forEach(function(iface) {
- tab.appendChild(E('p', {}, E('img', { 'data-iface': iface, 'style': 'display:none' })));
+ tab.appendChild(E('span', {}, E('img', { 'data-iface': iface, 'style': 'visibility:hidden; margin:5px 10px' })));
fs.exec_direct('/usr/bin/vnstati', [ '-'+style, '-i', iface, '-o', '-' ], 'blob').then(function(res) {
var img = tab.querySelector('img[data-iface="%s"]'.format(iface));
img.src = URL.createObjectURL(res);
- img.style.display = '';
+ img.style.visibility = 'visible';
tab.firstElementChild.style.display = 'none';
});
});
s = m.section(form.TypedSection, "yggdrasil", _("Encryption keys"));
s.anonymous = true;
- s.option(form.Value, "EncryptionPublicKey", _("Encryption public key"));
- s.option(form.Value, "EncryptionPrivateKey", _("Encryption private key"),
- _("Keep this private. When compromised, generate a new keypair and IPv6."));
- s.option(form.Value, "SigningPublicKey", _("Signing public key"));
- s.option(form.Value, "SigningPrivateKey", _("Signing private key"),
+ s.option(form.Value, "PublicKey", _("Encryption public key"));
+ s.option(form.Value, "PrivateKey", _("Encryption private key"),
_("Keep this private. When compromised, generate a new keypair and IPv6."));
return m.render();
+++ /dev/null
-'use strict';
-'require view';
-'require form';
-
-return view.extend({
- render: function() {
- var m, s, o;
-
- m = new form.Map('yggdrasil', 'Yggdrasil');
-
- s = m.section(form.TypedSection, "yggdrasil", _("Session firewall settings"));
- s.anonymous = true;
-
- s.option(form.Flag, "SessionFirewall_Enable", _("Enable session firewall"),
- _("If disabled, network traffic from any node will be allowed. If enabled, the below rules apply"));
- s.option(form.Flag, "SessionFirewall_AllowFromDirect", _("Allow from direct"),
- _("Allow network traffic from directly connected peers"));
- s.option(form.Flag, "SessionFirewall_AllowFromRemote", _("Allow from remote"),
- _("Allow network traffic from remote nodes on the network that you are not directly peered with"));
- s.option(form.Flag, "SessionFirewall_AlwaysAllowOutbound",
- _("Always allow outbound"), _("Allow outbound network traffic regardless of AllowFromDirect or AllowFromRemote"));
-
- s = m.section(form.TableSection, "whitelisted_encryption_public_key",
- _("Whitelisted public keys"),
- _("Network traffic is always accepted from those peers, regardless of AllowFromDirect or AllowFromRemote"));
- s.option(form.Value, "key", _("Public key"));
- s.anonymous = true;
- s.addremove = true;
-
- s = m.section(form.TableSection, "blacklisted_encryption_public_key",
- _("Blacklisted public keys"),
- _("Network traffic is always rejected from those peers, regardless of AllowFromDirect or AllowFromRemote"));
- s.option(form.Value, "key", _("Public key"));
- s.anonymous = true;
- s.addremove = true;
-
- return m.render();
- }
-});
s.anonymous = true;
s.option(form.Value, "IfName", _("Yggdrasil's network interface name"));
- s.option(form.Value, "LinkLocalTCPPort", _("Link-local TCP port"),
- _("The port number to be used for the link-local TCP listeners for the "+
- "configured MulticastInterfaces. This option does not affect listeners" +
- "specified in the Listen option. Unless you plan to firewall link-local" +
- "traffic, it is best to leave this as the default value of 0. This " +
- "option cannot currently be changed by reloading config during runtime."));
s.option(form.Flag, "NodeInfoPrivacy", _("Enable NodeInfo privacy"),
_("By default, nodeinfo contains some defaults including the platform," +
}
s.option(form.Value, "IfMTU", _("MTU size for the interface"));
- s.option(form.Value, "SwitchOptions_MaxTotalQueueSize",
- _("Maximum size of all switch queues combined"));
-
- o = m.section(form.TableSection, "multicast_interface", _("Multicast interfaces"),
- _("Regular expressions for which interfaces multicast peer discovery " +
- "should be enabled on. If none specified, multicast peer discovery is " +
- "disabled. The default value is .* which uses all interfaces."));
- o.option(form.Value, "name", _("Interface name"),
- _("Set .* to multicast on all interfaces"));
- o.anonymous = true;
- o.addremove = true;
o = m.section(form.TableSection, "listen_address", _("Listen addresses"),
_("Listen addresses for incoming connections. You will need to add " +
"Multicast peer discovery will work regardless of any listeners set " +
"here. Each listener should be specified in URI format as above, e.g. " +
"tcp://0.0.0.0:0 or tcp://[::]:0 to listen on all interfaces."));
- _("Address to listen for incoming connections"),
o.option(form.Value, "uri",
_("e.g. tcp://0.0.0.0:0 or tcp://[::]:0"));
o.anonymous = true;
o.addremove = true;
+ o = m.section(form.TableSection, "multicast_interface", _("Multicast interface"),
+ _("Configuration for which interfaces multicast peer discovery should be enabled on. " +
+ "Regex is a regular expression which is matched against an interface name, and interfaces use the first configuration that they match gainst. " +
+ "Beacon configures whether or not the node should send link-local multicast beacons to advertise their presence, while listening for incoming connections on Port. " +
+ "Listen controls whether or not the node listens for multicast beacons and opens outgoing connections."));
+ o.option(form.Value, "regex", _("Regular expression"));
+ o.option(form.Flag, "beacon", _("Send beacons"));
+ o.option(form.Flag, "listen", _("Listen for beacons"));
+ o.option(form.Value, "port", _("Link-local port"));
+ o.anonymous = true;
+ o.addremove = true;
+
return m.render();
}
});
"IPv6 address": "self-address",
"IPv6 subnet": "self-subnet",
"Coords": "self-coords",
- "Public key": "self-boxpubkey",
+ "Public key": "self-key",
"Build name": "self-buildname",
"Build version": "self-version"
};
peerings.setAttribute("class", "table"); peerings.id = "yggdrasil-peerings";
var tr = document.createElement("tr");
tr.setAttribute("class", "tr table-titles");
- ["Endpoint", "Address", "Proto", "Uptime", "Received", "Transmitted"].forEach(function(t) {
+ ["Endpoint", "Address", "Coords", "Key", "Port"].forEach(function(t) {
var th = document.createElement("th"); th.setAttribute("class", "th nowrap left");
th.innerText = t;
tr.appendChild(th);
while (table.rows.length > 1) { table.deleteRow(1); }
Object.keys(peers).forEach(function(address) {
var row = table.insertRow(-1);
- row.insertCell(-1).textContent = peers[address].endpoint;
+ row.style.fontSize = "xx-small";
+ row.insertCell(-1).textContent = peers[address].remote;
row.insertCell(-1).textContent = address;
- row.insertCell(-1).textContent = peers[address].proto;
- row.insertCell(-1).textContent = '%t'.format(peers[address].uptime);
- row.insertCell(-1).textContent = '%1024.2mB'.format(peers[address].bytes_recvd);
- row.insertCell(-1).textContent = '%1024.2mB'.format(peers[address].bytes_sent);
+ row.insertCell(-1).textContent = "[" + peers[address].coords.toString() + "]";
+ row.insertCell(-1).textContent = peers[address].key;
+ row.insertCell(-1).textContent = peers[address].port;
});
}
+ setTimeout(update_active_peers, 5000);
});
}
var r = obj[address];
view.querySelector('#self-address').innerText = address;
view.querySelector('#self-subnet').innerText = r.subnet;
- view.querySelector('#self-coords').innerText = r.coords;
- view.querySelector('#self-boxpubkey').innerText = r.box_pub_key;
+ view.querySelector('#self-coords').innerText = "[" + r.coords + "]";
+ view.querySelector('#self-key').innerText = r.key;
view.querySelector('#self-buildname').innerText = r.build_name;
view.querySelector('#self-version').innerText = r.build_version;
- var table = view.querySelector('#yggdrasil-peerings');
- Object.keys(peers).forEach(function(address) {
- var row = table.insertRow(-1);
- row.insertCell(-1).textContent = peers[address].endpoint;
- row.insertCell(-1).textContent = address;
- row.insertCell(-1).textContent = peers[address].proto;
- row.insertCell(-1).textContent = '%t'.format(peers[address].uptime);
- row.insertCell(-1).textContent = '%1024.2mB'.format(peers[address].bytes_recvd);
- row.insertCell(-1).textContent = '%1024.2mB'.format(peers[address].bytes_sent);
-
- });
- setInterval(update_active_peers, 5000);
+ update_active_peers();
} else {
view.innerHTML = "<h2>Yggdrasil is not running</h2>";
}
+++ /dev/null
-'use strict';
-'require view';
-'require form';
-
-return view.extend({
- render: function() {
- var m, s, o;
-
- m = new form.Map('yggdrasil', 'Yggdrasil');
-
- s = m.section(form.TypedSection, "yggdrasil", _("Tunnel Routing"));
- s.anonymous = true;
- s.option(form.Flag, "TunnelRouting_Enable", "Enable tunnel routing",
- _("Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively " +
- "allows you to use Yggdrasil to route to, or to bridge other networks, " +
- "similar to a VPN tunnel. Tunnelling works between any two nodes and " +
- "does not require them to be directly peered."));
-
- o = m.section(form.TableSection, "ipv4_remote_subnet", _("IPv4 remote subnet"),
- _("IPv4 subnets belonging to remote nodes, mapped to the node's public"));
- o.option(form.Value, "key", _("Key"), _("Public encryption key"));
- o.option(form.Value, "subnet", _("Subnet"), _("IPv4 subnet"));
- o.anonymous = true;
- o.addremove = true;
-
- o = m.section(form.TableSection, "ipv4_local_subnet", _("IPv4 local subnet"),
- _("IPv4 subnets belonging to this node's end of the tunnels. Only traffic " +
- "from these ranges will be tunnelled."));
- o.option(form.Value, "subnet", _("Subnet"), _("IPv4 subnet"));
- o.anonymous = true;
- o.addremove = true;
-
- o = m.section(form.TableSection, "ipv6_remote_subnet", _("IPv6 remote subnet"),
- _("IPv6 subnets belonging to remote nodes, mapped to the node's public"));
- o.option(form.Value, "key", _("Key"), _("Public encryption key"));
- o.option(form.Value, "subnet", _("Subnet"), _("IPv6 subnet"));
- o.anonymous = true;
- o.addremove = true;
-
- o = m.section(form.TableSection, "ipv6_local_subnet", _("IPv6 local subnet"),
- _("IPv6 subnets belonging to this node's end of the tunnels. Only traffic " +
- "from these ranges (or the Yggdrasil node's IPv6 address/subnet) " +
- "will be tunnelled."));
- o.option(form.Value, "subnet", _("Subnet"), _("IPv6 subnet"));
- o.anonymous = true;
- o.addremove = true;
-
- return m.render();
- }
-});
"type": "view",
"path": "yggdrasil/keys"
}
- },
-
- "admin/network/yggdrasil/session_firewall": {
- "title": "Session firewall",
- "order": 5,
- "action": {
- "type": "view",
- "path": "yggdrasil/session_firewall"
- }
- },
-
- "admin/network/yggdrasil/tunnel_routing": {
- "title": "Tunnel routing",
- "order": 6,
- "action": {
- "type": "view",
- "path": "yggdrasil/tunnel_routing"
- }
}
}
return true;
}
+function cbi_validate_named_section_add(input)
+{
+ var button = input.parentNode.parentNode.querySelector('.cbi-button-add');
+ if (input.value !== '') {
+ button.disabled = false;
+ }
+ else {
+ button.disabled = true;
+ }
+}
+
function cbi_validate_reset(form)
{
window.setTimeout(
* Provides a password for HTTP basic authentication.
*
* @property {number} [timeout]
- * Specifies the request timeout in seconds.
+ * Specifies the request timeout in milliseconds.
*
* @property {boolean} [credentials=false]
* Whether to include credentials such as cookies in the request.
<div class="cbi-section-error"><%:Invalid%></div>
<%- end %>
<div>
- <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname" data-optional="true" />
+ <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname" data-optional="true" onkeyup="cbi_validate_named_section_add(this)"/>
</div>
- <input class="btn cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" />
+ <input class="btn cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" disabled="" />
<% end %>
</div>
<%- end %>
<div class="cbi-section-error"><%:Invalid%></div>
<%- end %>
<div>
- <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>." name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>." data-type="uciname" data-optional="true" />
+ <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>." name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>." data-type="uciname" data-optional="true" onkeyup="cbi_validate_named_section_add(this)"/>
</div>
- <input class="btn cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" />
+ <input class="btn cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" disabled=""/>
<%- end %>
</div>
<%- end %>
},
"depends": {
"acl": [ "luci-mod-network-dhcp" ],
+ "fs": {
+ "/usr/sbin/dnsmasq": "executable"
+ },
"uci": { "dhcp": true }
}
},
var fields = [
_('Total Available'), (mem.available) ? mem.available : (mem.total && mem.free && mem.buffered) ? mem.free + mem.buffered : null, mem.total,
_('Used'), (mem.total && mem.free) ? (mem.total - mem.free) : null, mem.total,
- _('Buffered'), (mem.total && mem.buffered) ? mem.buffered : null, mem.total
];
+ if (mem.buffered)
+ fields.push(_('Buffered'), mem.buffered, mem.total);
+
if (mem.cached)
fields.push(_('Cached'), mem.cached, mem.total);
return E([
E('h2', _('Scheduled Tasks')),
E('p', { 'class': 'cbi-section-descr' }, _('This is the system crontab in which scheduled tasks can be defined.')),
- E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 10, 'disabled': isReadonlyView }, [ crontab != null ? crontab : '' ]))
+ E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 25, 'disabled': isReadonlyView }, [ crontab != null ? crontab : '' ]))
]);
},
}
#mainmenu {
- flex: 1 1 200px;
+ flex: 1 1 100px;
+ max-width: 250px;
background: var(--main-dark-color);
color: var(--main-bright-color);
padding: 1em;