diff options
Diffstat (limited to 'protocols')
13 files changed, 1075 insertions, 7 deletions
diff --git a/protocols/luci-proto-bonding/Makefile b/protocols/luci-proto-bonding/Makefile new file mode 100644 index 0000000000..81988cfa2f --- /dev/null +++ b/protocols/luci-proto-bonding/Makefile @@ -0,0 +1,17 @@ +# +# Copyright (C) 2020 TDT AG <development@tdt.de> +# +# This is free software, licensed under the Apache License Version 2.0. +# See https://www.apache.org/licenses/LICENSE-2.0 for more information. +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Support for Link Aggregation (Channel Bonding) +LUCI_DEPENDS:=+proto-bonding + +PKG_MAINTAINER:=Helge Mader <ma@dev.tdt.de> + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/protocols/luci-proto-bonding/htdocs/luci-static/resources/protocol/bonding.js b/protocols/luci-proto-bonding/htdocs/luci-static/resources/protocol/bonding.js new file mode 100644 index 0000000000..aadc2306d3 --- /dev/null +++ b/protocols/luci-proto-bonding/htdocs/luci-static/resources/protocol/bonding.js @@ -0,0 +1,425 @@ +'use strict'; +'require ui'; +'require uci'; +'require form'; +'require fs'; +'require network'; +'require tools.widgets as widgets'; + + +function getSelectableSlaves(section_id) { + var rv = []; + var NonUsableMac = /^(00:00:00:00:00:00|null)/; + var interfaces = uci.sections('network', 'interface'); + + return network.getDevices().then(function(devices) { + for (var i = 0; i < devices.length; i++) { + var in_use = false; + var NotUsable = NonUsableMac.test(devices[i].getMAC()); + + // Only "real" interfaces for slaves needed + if (NotUsable == false) { + for (var j = 0; j < interfaces.length; j++) { + if (uci.get('network', interfaces[j]['.name'], 'proto') == 'bonding') { + var slaves = L.toArray(uci.get('network', interfaces[j]['.name'], 'slaves')); + + for (var k = 0; k < slaves.length; k++) { + if (devices[i].ifname == slaves[k] && interfaces[j]['.name'] != section_id) { + in_use = true; + } + } + } + } + if (in_use == false) { + rv.push(devices[i].ifname); + } + } + } + + return rv.sort(); + }); +} + +function validateEmpty(section, value) { + if (value) { + return true; + } + else { + return _('Expecting: non-empty value'); + } +} + +function updatePrimaries(section, value) { + + var opt = this.map.lookupOption('slaves', section); + var selected_slaves = opt[0].formvalue(section); + + var uielem = this.map.lookupOption('primary', section)[0].getUIElement(section); + uielem.clearChoices(); + + for (var i = 0; i < selected_slaves.length; i++) { + uielem.addChoices(selected_slaves[i], selected_slaves[i]); + } + + return true; +} + +function validate_arp_policy(section, value) { + + var opt = this.map.lookupOption('link_monitoring', section); + var selected_link_monitoring = opt[0].formvalue(section); + + var opt = this.map.lookupOption('bonding_policy', section); + var selected_policy = opt[0].formvalue(section); + + if (selected_link_monitoring == 'arp') { + if (selected_policy == '802.3ad' || selected_policy == 'balance-tlb' || selected_policy == 'balance-alb') { + return _('ARP monitoring is not supported for the selected policy!'); + } + } + + return true; +} + +function validate_arp_ip_targets(section, value) { + + var opt = this.map.lookupOption('link_monitoring', section); + var selected_link_monitoring = opt[0].formvalue(section); + + var opt = this.map.lookupOption('arp_ip_target', section); + var selected_arp_ip_targets = opt[0].formvalue(section); + + var opt = this.map.lookupOption('bonding_policy', section); + var selected_policy = opt[0].formvalue(section); + + if (selected_link_monitoring == 'arp' && selected_arp_ip_targets.length == 0) { + return _('You must select at least one ARP IP target if ARP monitoring is selected!'); + } + + return true; +} + +function validate_primary_interface(section, value) { + + var opt = this.map.lookupOption('bonding_policy', section); + var selected_policy = opt[0].formvalue(section); + + var opt = this.map.lookupOption('slaves', section); + var selected_slaves = opt[0].formvalue(section); + + var opt = this.map.lookupOption('primary', section); + var selected_primary = opt[0].formvalue(section); + + if (selected_policy == 'active-backup' || selected_policy == 'balance-tlb' || selected_policy == 'balance-alb') { + if (selected_slaves.filter(function(slave) { return slave == selected_primary }).length == 0) + return _('You must select a primary interface which is included in selected slave interfaces!'); + } + + return true; +} + +return network.registerProtocol('bonding', { + getI18n: function() { + return _('Link Aggregation (Channel Bonding)'); + }, + + getIfname: function() { + return null; + }, + + getOpkgPackage: function() { + return 'bonding'; + }, + + isFloating: function() { + return true; + }, + + isCreateable: function(ifname) { + return getSelectableSlaves(ifname).then(L.bind(function(devices) { + return devices.length == 0 ? _('No more slaves available') : null; + }, this)); + + return _('No more slaves available'); + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + o = s.taboption('general', form.Value, 'ipaddr', + _('IPv4 address'), + _('The local IPv4 address')); + o.datatype = 'ip4addr'; + o.rmempty = false; + + o = s.taboption('general', form.Value, 'netmask', + _('IPv4 netmask'), + _('The local IPv4 netmask')); + o.datatype = 'ip4addr'; + o.validate = validateEmpty; + o.rmempty = false; + o.value("255.255.255.0"); + o.value("255.255.0.0"); + o.value("255.0.0.0"); + + o = s.taboption('advanced', form.MultiValue, 'slaves', + _('Slave Interfaces'), + _('Specifies which slave interfaces should be attached to this bonding interface')); + o.load = function(section_id) { + return getSelectableSlaves(section_id).then(L.bind(function(devices) { + for (var i = 0; i < devices.length; i++) { + this.value(devices[i], devices[i]); + } + + if (devices.length == 0) { + this.placeholder = _('No more slaves available, can not save interface'); + this.value('', ''); + return ''; + } + + return uci.get('network', section_id, 'slaves'); + }, this)); + }; + o.validate = updatePrimaries; + o.rmempty = false; + + o = s.taboption('advanced', form.ListValue, 'bonding_policy', + _('Bonding Policy'), + _('Specifies the mode to be used for this bonding interface')); + o.default = 'balance-rr'; + o.value('balance-rr', _('Round-Robin policy (balance-rr, 0)')); + o.value('active-backup', _('Active-Backup policy (active-backup, 1)')); + o.value('balance-xor', _('XOR policy (balance-xor, 2)')); + o.value('broadcast', _('Broadcast policy (broadcast, 3)')); + o.value('802.3ad', _('IEEE 802.3ad Dynamic link aggregation (802.3ad, 4)')); + o.value('balance-tlb', _('Adaptive transmit load balancing (balance-tlb, 5)')); + o.value('balance-alb', _('Adaptive load balancing (balance-alb, 6)')); + + o = s.taboption('advanced', widgets.DeviceSelect, 'primary', + _('Primary Slave'), + _('Specifies which slave is the primary device. It will always be the active slave while it is available')); + o.depends('bonding_policy', 'active-backup'); + o.depends('bonding_policy', 'balance-tlb'); + o.depends('bonding_policy', 'balance-alb'); + o.filter = function(section_id, value) { + // Never return anything as valid, as the valid possibilities + // will be set in the slaves validate function + return false; + }; + o.validate = validate_primary_interface; + + o = s.taboption('advanced', form.ListValue, 'primary_reselect', + _('Reselection policy for primary slave'), + _('Specifies the reselection policy for the primary slave when failure of the active slave or recovery of the primary slave occurs')); + o.default = 'always'; + o.value('always', _('Primary becomes active slave whenever it comes back up (always, 0)')); + o.value('better', _('Primary becomes active slave when it comes back up if speed and duplex better than current slave (better, 1)')); + o.value('failure', _('Only if current active slave fails and the primary slave is up (failure, 2)')); + o.depends('bonding_policy', 'active-backup'); + o.depends('bonding_policy', 'balance-tlb'); + o.depends('bonding_policy', 'balance-alb'); + + o = s.taboption('advanced', form.Value, 'min_links', + _('Minimum Number of Links'), + _('Specifies the minimum number of links that must be active before asserting carrier')); + o.datatype = 'uinteger'; + o.default = 0; + o.rmempty = false; + o.depends('bonding_policy', '802.3ad'); + + o = s.taboption('advanced', form.Value, 'ad_actor_sys_prio', + _('System Priority'), + _('Specifies the system priority')); + o.datatype = 'range(1,65535)'; + o.default = 65535; + o.rmempty = false; + o.depends('bonding_policy', '802.3ad'); + + o = s.taboption('advanced', form.Value, 'ad_actor_system', + _('MAC Address For The Actor'), + _("Specifies the mac-address for the actor in protocol packet exchanges (LACPDUs). If empty, masters' mac address defaults to system default")); + o.datatype = 'macaddr'; + o.default = ''; + o.depends('bonding_policy', '802.3ad'); + + o = s.taboption('advanced', form.ListValue, 'ad_select', + _('Aggregation Selection Logic'), + _('Specifies the aggregation selection logic to use')); + o.default = 'stable'; + o.value('stable', _('Aggregator: All slaves down or has no slaves (stable, 0)')); + o.value('bandwidth', _('Aggregator: Slave added/removed or state changes (bandwidth, 1)')); + o.value('count', _('Aggregator: Chosen by the largest number of ports + slave added/removed or state changes (count, 2)')); + o.depends('bonding_policy', '802.3ad'); + + o = s.taboption('advanced', form.ListValue, 'lacp_rate', + _('LACPDU Packets'), + _('Specifies the rate in which the link partner will be asked to transmit LACPDU packets')); + o.default = 'slow'; + o.value('slow', _('Every 30 seconds (slow, 0)')); + o.value('fast', _('Every second (fast, 1)')); + o.depends('bonding_policy', '802.3ad'); + + o = s.taboption('advanced', form.Value, 'packets_per_slave', + _('Packets To Transmit Before Moving To Next Slave'), + _("Specifies the number of packets to transmit through a slave before moving to the next one")); + o.datatype = 'range(0,65535)'; + o.default = '1'; + o.rmempty = false; + o.depends('bonding_policy', 'balance-rr'); + + o = s.taboption('advanced', form.Value, 'lp_interval', + _('Interval For Sending Learning Packets'), + _("Specifies the number of seconds between instances where the bonding driver sends learning packets to each slaves peer switch")); + o.datatype = 'range(1,2147483647)'; + o.default = '1'; + o.rmempty = false; + o.depends('bonding_policy', 'balance-tlb'); + o.depends('bonding_policy', 'balance-alb'); + + o = s.taboption('advanced', form.ListValue, 'tlb_dynamic_lb', + _('Enable Dynamic Shuffling Of Flows'), + _('Specifies whether to shuffle active flows across slaves based on the load')); + o.default = '1'; + o.value('1', _('Yes')); + o.value('0', _('No')); + o.depends('bonding_policy', 'balance-tlb'); + + o = s.taboption('advanced', form.ListValue, 'fail_over_mac', + _('Set same MAC Address to all slaves'), + _('Specifies whether active-backup mode should set all slaves to the same MAC address at enslavement')); + o.default = 'none'; + o.value('none', _('Yes (none, 0)')); + o.value('active', _('Set to currently active slave (active, 1)')); + o.value('follow', _('Set to first slave added to the bond (follow, 2)')); + o.depends('bonding_policy', 'active-backup'); + + o = s.taboption('advanced', form.Value, 'num_grat_arp__num_unsol_na', + _('Number of peer notifications after failover event'), + _("Specifies the number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements) to be issued after a failover event")); + o.datatype = 'range(0,255)'; + o.default = '1'; + o.rmempty = false; + o.depends('bonding_policy', 'active-backup'); + + o = s.taboption('advanced', form.ListValue, 'xmit_hash_policy', + _('Transmit Hash Policy'), + _('Selects the transmit hash policy to use for slave selection')); + o.default = 'layer2'; + o.value('layer2', _('Use XOR of hardware MAC addresses (layer2)')); + o.value('layer2+3', _('Use XOR of hardware MAC addresses and IP addresses (layer2+3)')); + o.value('layer3+4', _('Use upper layer protocol information (layer3+4)')); + o.value('encap2+3', _('Use XOR of hardware MAC addresses and IP addresses, rely on skb_flow_dissect (encap2+3)')); + o.value('encap3+4', _('Use upper layer protocol information, rely on skb_flow_dissect (encap3+4)')); + o.depends('bonding_policy', 'balance-rr'); + o.depends('bonding_policy', 'active-backup'); + o.depends('bonding_policy', 'balance-tlb'); + o.depends('bonding_policy', 'balance-alb'); + o.depends('bonding_policy', 'balance-xor'); + + o = s.taboption('advanced', form.Value, 'resend_igmp', + _('Number of IGMP membership reports'), + _("Specifies the number of IGMP membership reports to be issued after a failover event in 200ms intervals")); + o.datatype = 'range(0,255)'; + o.default = '1'; + o.rmempty = false; + o.depends('bonding_policy', 'balance-tlb'); + o.depends('bonding_policy', 'balance-alb'); + + o = s.taboption('advanced', form.ListValue, 'all_slaves_active', + _('Drop Duplicate Frames'), + _('Specifies that duplicate frames (received on inactive ports) should be dropped or delivered')); + o.default = '0'; + o.value('0', _('Yes')); + o.value('1', _('No')); + + o = s.taboption('advanced', form.ListValue, 'link_monitoring', + _('Link Monitoring'), + _('Method of link monitoring')); + o.default = 'off'; + o.value('off', _('Off')); + o.value('arp', _('ARP')); + o.value('mii', _('MII')); + o.validate = validate_arp_policy; + + o = s.taboption('advanced', form.Value, 'arp_interval', + _('ARP Interval'), + _("Specifies the ARP link monitoring frequency in milliseconds")); + o.datatype = 'uinteger'; + o.default = '0'; + o.rmempty = false; + o.depends('link_monitoring', 'arp'); + + o = s.taboption('advanced', form.DynamicList, 'arp_ip_target', + _('ARP IP Targets'), + _('Specifies the IP addresses to use for ARP monitoring')); + o.datatype = 'ipaddr'; + o.cast = 'string'; + o.depends('link_monitoring', 'arp'); + o.validate = validate_arp_ip_targets; + + o = s.taboption('advanced', form.ListValue, 'arp_all_targets', + _('ARP mode to consider a slave as being up'), + _('Specifies the quantity of ARP IP targets that must be reachable')); + o.default = 'any'; + o.value('any', _('Consider the slave up when any ARP IP target is reachable (any, 0)')); + o.value('all', _('Consider the slave up when all ARP IP targets are reachable (all, 1)')); + o.depends({link_monitoring: 'arp', bonding_policy: 'active-backup'}); + + o = s.taboption('advanced', form.ListValue, 'arp_validate', + _('ARP Validation'), + _('Specifies whether ARP probes and replies should be validated or non-ARP traffic should be filtered for link monitoring')); + o.default = 'filter'; + o.value('none', _('No validation or filtering')); + o.value('active', _('Validation only for active slave')); + o.value('backup', _('Validation only for backup slaves')); + o.value('all', _('Validation for all slaves')); + o.value('filter', _('Filtering for all slaves, no validation')); + o.value('filter_active', _('Filtering for all slaves, validation only for active slave')); + o.value('filter_backup', _('Filtering for all slaves, validation only for backup slaves')); + o.depends('link_monitoring', 'arp'); + + o = s.taboption('advanced', form.Value, 'miimon', + _('MII Interval'), + _("Specifies the MII link monitoring frequency in milliseconds")); + o.datatype = 'uinteger'; + o.default = '0'; + o.rmempty = false; + o.depends('link_monitoring', 'mii'); + + o = s.taboption('advanced', form.Value, 'downdelay', + _('Down Delay'), + _("Specifies the time in milliseconds to wait before disabling a slave after a link failure detection")); + o.datatype = 'uinteger'; + o.default = '0'; + o.rmempty = false; + o.depends('link_monitoring', 'mii'); + + o = s.taboption('advanced', form.Value, 'updelay', + _('Up Delay'), + _("Specifies the time in milliseconds to wait before enabling a slave after a link recovery detection")); + o.datatype = 'uinteger'; + o.default = '0'; + o.rmempty = false; + o.depends('link_monitoring', 'mii'); + + o = s.taboption('advanced', form.ListValue, 'use_carrier', + _('Method to determine link status'), + _('Specifies whether or not miimon should use MII or ETHTOOL ioctls vs. netif_carrier_ok()')); + o.default = '1'; + o.value('0', _('MII / ETHTOOL ioctls')); + o.value('1', _('netif_carrier_ok()')); + o.depends('link_monitoring', 'mii'); + } +}); diff --git a/protocols/luci-proto-gre/Makefile b/protocols/luci-proto-gre/Makefile new file mode 100644 index 0000000000..0b0fa541cb --- /dev/null +++ b/protocols/luci-proto-gre/Makefile @@ -0,0 +1,21 @@ +# +# Based on luci-proto-ipip. +# Credited author of luci-proto-ipip is Roger Pueyo Centelles <roger.pueyo@guifi.net> +# Copyright 2016 Roger Pueyo Centelles <roger.pueyo@guifi.net> +# +# Modified by Jan Betik <jan.betik@svine.su> +# Copyright 2020 Jan Betik <jan.betik@svine.su> +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Support for GRE tunnels (RFC2784) +LUCI_DEPENDS:=+gre + +PKG_MAINTAINER:=Jan Betik <jan.betik@svine.su> + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/gre.js b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/gre.js new file mode 100644 index 0000000000..e431bccd76 --- /dev/null +++ b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/gre.js @@ -0,0 +1,96 @@ +'use strict'; +'require form'; +'require network'; +'require tools.widgets as widgets'; + +network.registerPatternVirtual(/^gre4-.+$/); + +return network.registerProtocol('gre', { + getI18n: function() { + return _('GRE tunnel over IPv4'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'gre4-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'gre'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + // -- general --------------------------------------------------------------------- + + o = s.taboption('general', form.Value, 'peeraddr', _("Remote IPv4 address or FQDN"), _("The IPv4 address or the fully-qualified domain name of the remote tunnel end.")); + o.optional = false; + o.datatype = 'or(hostname,ip4addr("nomask"))'; + + o = s.taboption('general', form.Value, 'ipaddr', _("Local IPv4 address"), _("The local IPv4 address over which the tunnel is created (optional).")); + o.optional = true; + o.datatype = 'ip4addr("nomask")'; + + // -- advanced --------------------------------------------------------------------- + + o = s.taboption('advanced', widgets.NetworkSelect, 'tunlink', _("Bind interface"), _("Bind the tunnel to this interface (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('advanced', form.Value, 'mtu', _("Override MTU"), _("Specify an MTU (Maximum Transmission Unit) other than the default (1280 bytes) (optional).")); + o.optional = true; + o.placeholder = 1280; + o.datatype = 'range(68, 9200)'; + + o = s.taboption('advanced', form.Value, 'ttl', _("Override TTL"), _("Specify a TTL (Time to Live) for the encapsulating packet other than the default (64) (optional).")); + o.optional = true; + o.placeholder = 64; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'tos', _('Override TOS'), _("Specify a TOS (Type of Service). Can be either <code>inherit</code> (the outer header inherits the value of the inner header) or an hexadecimal value starting with <code>0x</code> (optional).")); + o.optional = true; + o.validate = function(section_id, value) { + if (value.length > 0 && !value.match(/^0x[a-fA-F0-9]{1,2}$/) && !value.match(/^inherit$/i)) + return _('Invalid value'); + + return true; + }; + + o = s.taboption('advanced', form.Flag, 'df', _("Don't Fragment"), _("Enable the DF (Don't Fragment) flag of the encapsulating packets.")); + o.default = o.enabled; + + o = s.taboption('advanced', form.Flag, 'nohostroute', _("No host route"), _("Do not create host route to peer (optional).")); + o.optional = true; + + o = s.taboption('advanced', form.Value, 'ikey', _("Incoming key"), _("Key for incoming packets (optional).")); + o.optional = true; + o.datatype = 'integer'; + + o = s.taboption('advanced', form.Value, 'okey', _("Outgoing key"), _("Key for outgoing packets (optinal).")); + o.optional = true; + o.datatype = 'integer'; + + s.taboption('advanced', form.Flag, 'icsum', _("Incoming checksum"), _("Require incoming checksum (optional).")); + s.taboption('advanced', form.Flag, 'ocsum', _("Outgoing checksum"), _("Compute outgoing checksum (optional).")); + s.taboption('advanced', form.Flag, 'iseqno', _("Incoming serialization"), _("Require incoming packets serialization (optional).")); + s.taboption('advanced', form.Flag, 'oseqno', _("Outgoing serialization"), _("Perform outgoing packets serialization (optional).")); + + } +}); diff --git a/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/gretap.js b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/gretap.js new file mode 100644 index 0000000000..426b5d98df --- /dev/null +++ b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/gretap.js @@ -0,0 +1,101 @@ +'use strict'; +'require form'; +'require network'; +'require tools.widgets as widgets'; + +network.registerPatternVirtual(/^gre4t-.+$/); + +return network.registerProtocol('gretap', { + getI18n: function() { + return _('GRETAP tunnel over IPv4'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'gre4t-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'gre'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + // -- general --------------------------------------------------------------------- + + o = s.taboption('general', form.Value, 'peeraddr', _("Remote IPv4 address or FQDN"), _("The IPv4 address or the fully-qualified domain name of the remote tunnel end.")); + o.optional = false; + o.datatype = 'or(hostname,ip4addr("nomask"))'; + + o = s.taboption('general', form.Value, 'ipaddr', _("Local IPv4 address"), _("The local IPv4 address over which the tunnel is created (optional).")); + o.optional = true; + o.datatype = 'ip4addr("nomask")'; + + o = s.taboption('general', widgets.NetworkSelect, 'network', _("Network interface"), _("Logical network to which the tunnel will be added (bridged) (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + // -- advanced --------------------------------------------------------------------- + + o = s.taboption('advanced', widgets.NetworkSelect, 'tunlink', _("Bind interface"), _("Bind the tunnel to this interface (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('advanced', form.Value, 'mtu', _("Override MTU"), _("Specify an MTU (Maximum Transmission Unit) other than the default (1280 bytes) (optional).")); + o.optional = true; + o.placeholder = 1280; + o.datatype = 'range(68, 9200)'; + + o = s.taboption('advanced', form.Value, 'ttl', _("Override TTL"), _("Specify a TTL (Time to Live) for the encapsulating packet other than the default (64) (optional).")); + o.optional = true; + o.placeholder = 64; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'tos', _('Override TOS'), _("Specify a TOS (Type of Service). Can be either <code>inherit</code> (the outer header inherits the value of the inner header) or an hexadecimal value starting with <code>0x</code> (optional).")); + o.optional = true; + o.validate = function(section_id, value) { + if (value.length > 0 && !value.match(/^0x[a-fA-F0-9]{1,2}$/) && !value.match(/^inherit$/i)) + return _('Invalid value'); + + return true; + }; + + o = s.taboption('advanced', form.Flag, 'df', _("Don't Fragment"), _("Enable the DF (Don't Fragment) flag of the encapsulating packets.")); + o.default = o.enabled; + + o = s.taboption('advanced', form.Flag, 'nohostroute', _("No host route"), _("Do not create host route to peer (optional).")); + o.optional = true; + + o = s.taboption('advanced', form.Value, 'ikey', _("Incoming key"), _("Key for incoming packets (optional).")); + o.optional = true; + o.datatype = 'integer'; + + o = s.taboption('advanced', form.Value, 'okey', _("Outgoing key"), _("Key for outgoing packets (optinal).")); + o.optional = true; + o.datatype = 'integer'; + + s.taboption('advanced', form.Flag, 'icsum', _("Incoming checksum"), _("Require incoming checksum (optional).")); + s.taboption('advanced', form.Flag, 'ocsum', _("Outgoing checksum"), _("Compute outgoing checksum (optional).")); + s.taboption('advanced', form.Flag, 'iseqno', _("Incoming serialization"), _("Require incoming packets serialization (optional).")); + s.taboption('advanced', form.Flag, 'oseqno', _("Outgoing serialization"), _("Perform outgoing packets serialization (optional).")); + + } +}); diff --git a/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/grev6.js b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/grev6.js new file mode 100644 index 0000000000..bd9a43e27b --- /dev/null +++ b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/grev6.js @@ -0,0 +1,98 @@ +'use strict'; +'require form'; +'require network'; +'require tools.widgets as widgets'; + +network.registerPatternVirtual(/^gre6-.+$/); + +return network.registerProtocol('grev6', { + getI18n: function() { + return _('GRE tunnel over IPv6'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'gre6-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'gre'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + // -- general --------------------------------------------------------------------- + + o = s.taboption('general', form.Value, 'peer6addr', _("Remote IPv6 address or FQDN"), _("The IPv6 address or the fully-qualified domain name of the remote tunnel end.")); + o.optional = false; + o.datatype = 'or(hostname,ip6addr("nomask"))'; + + o = s.taboption('general', form.Value, 'ip6addr', _("Local IPv6 address"), _("The local IPv6 address over which the tunnel is created (optional).")); + o.optional = true; + o.datatype = 'ip6addr("nomask")'; + + o = s.taboption('general', widgets.NetworkSelect, 'weakif', _("Source interface"), _("Logical network from which to select the local endpoint if local IPv6 address is empty and no WAN IPv6 is available (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + // -- advanced --------------------------------------------------------------------- + + o = s.taboption('advanced', widgets.NetworkSelect, 'tunlink', _("Bind interface"), _("Bind the tunnel to this interface (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('advanced', form.Value, 'mtu', _("Override MTU"), _("Specify an MTU (Maximum Transmission Unit) other than the default (1280 bytes) (optional).")); + o.optional = true; + o.placeholder = 1280; + o.datatype = 'range(68, 9200)'; + + o = s.taboption('advanced', form.Value, 'ttl', _("Override TTL"), _("Specify a TTL (Time to Live) for the encapsulating packet other than the default (64) (optional).")); + o.optional = true; + o.placeholder = 64; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'tos', _('Traffic Class'), _("Specify a Traffic Class. Can be either <code>inherit</code> (the outer header inherits the value of the inner header) or an hexadecimal value starting with <code>0x</code> (optional).")); + o.optional = true; + o.validate = function(section_id, value) { + if (value.length > 0 && !value.match(/^0x[a-fA-F0-9]{1,2}$/) && !value.match(/^inherit$/i)) + return _('Invalid value'); + + return true; + }; + + o = s.taboption('advanced', form.Flag, 'nohostroute', _("No host route"), _("Do not create host route to peer (optional).")); + o.optional = true; + + o = s.taboption('advanced', form.Value, 'ikey', _("Incoming key"), _("Key for incoming packets (optional).")); + o.optional = true; + o.datatype = 'integer'; + + o = s.taboption('advanced', form.Value, 'okey', _("Outgoing key"), _("Key for outgoing packets (optinal).")); + o.optional = true; + o.datatype = 'integer'; + + s.taboption('advanced', form.Flag, 'icsum', _("Incoming checksum"), _("Require incoming checksum (optional).")); + s.taboption('advanced', form.Flag, 'ocsum', _("Outgoing checksum"), _("Compute outgoing checksum (optional).")); + s.taboption('advanced', form.Flag, 'iseqno', _("Incoming serialization"), _("Require incoming packets serialization (optional).")); + s.taboption('advanced', form.Flag, 'oseqno', _("Outgoing serialization"), _("Perform outgoing packets serialization (optional).")); + + } +}); diff --git a/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/grev6tap.js b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/grev6tap.js new file mode 100644 index 0000000000..3b1a503719 --- /dev/null +++ b/protocols/luci-proto-gre/htdocs/luci-static/resources/protocol/grev6tap.js @@ -0,0 +1,103 @@ +'use strict'; +'require form'; +'require network'; +'require tools.widgets as widgets'; + +network.registerPatternVirtual(/^gre6t-.+$/); + +return network.registerProtocol('grev6tap', { + getI18n: function() { + return _('GRETAP tunnel over IPv6'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'gre6t-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'gre'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + // -- general --------------------------------------------------------------------- + + o = s.taboption('general', form.Value, 'peer6addr', _("Remote IPv6 address or FQDN"), _("The IPv6 address or the fully-qualified domain name of the remote tunnel end.")); + o.optional = false; + o.datatype = 'or(hostname,ip6addr("nomask"))'; + + o = s.taboption('general', form.Value, 'ip6addr', _("Local IPv6 address"), _("The local IPv6 address over which the tunnel is created (optional).")); + o.optional = true; + o.datatype = 'ip6addr("nomask")'; + + o = s.taboption('general', widgets.NetworkSelect, 'weakif', _("Source interface"), _("Logical network from which to select the local endpoint if local IPv6 address is empty and no WAN IPv6 is available (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('general', widgets.NetworkSelect, 'network', _("Network interface"), _("Logical network to which the tunnel will be added (bridged) (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + // -- advanced --------------------------------------------------------------------- + + o = s.taboption('advanced', widgets.NetworkSelect, 'tunlink', _("Bind interface"), _("Bind the tunnel to this interface (optional).")); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('advanced', form.Value, 'mtu', _("Override MTU"), _("Specify an MTU (Maximum Transmission Unit) other than the default (1280 bytes) (optional).")); + o.optional = true; + o.placeholder = 1280; + o.datatype = 'range(68, 9200)'; + + o = s.taboption('advanced', form.Value, 'ttl', _("Override TTL"), _("Specify a TTL (Time to Live) for the encapsulating packet other than the default (64) (optional).")); + o.optional = true; + o.placeholder = 64; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'tos', _('Traffic Class'), _("Specify a Traffic Class. Can be either <code>inherit</code> (the outer header inherits the value of the inner header) or an hexadecimal value starting with <code>0x</code> (optional).")); + o.optional = true; + o.validate = function(section_id, value) { + if (value.length > 0 && !value.match(/^0x[a-fA-F0-9]{1,2}$/) && !value.match(/^inherit$/i)) + return _('Invalid value'); + + return true; + }; + + o = s.taboption('advanced', form.Flag, 'nohostroute', _("No host route"), _("Do not create host route to peer (optional).")); + o.optional = true; + + o = s.taboption('advanced', form.Value, 'ikey', _("Incoming key"), _("Key for incoming packets (optional).")); + o.optional = true; + o.datatype = 'integer'; + + o = s.taboption('advanced', form.Value, 'okey', _("Outgoing key"), _("Key for outgoing packets (optinal).")); + o.optional = true; + o.datatype = 'integer'; + + s.taboption('advanced', form.Flag, 'icsum', _("Incoming checksum"), _("Require incoming checksum (optional).")); + s.taboption('advanced', form.Flag, 'ocsum', _("Outgoing checksum"), _("Compute outgoing checksum (optional).")); + s.taboption('advanced', form.Flag, 'iseqno', _("Incoming serialization"), _("Require incoming packets serialization (optional).")); + s.taboption('advanced', form.Flag, 'oseqno', _("Outgoing serialization"), _("Perform outgoing packets serialization (optional).")); + + } +}); diff --git a/protocols/luci-proto-openconnect/htdocs/luci-static/resources/protocol/openconnect.js b/protocols/luci-proto-openconnect/htdocs/luci-static/resources/protocol/openconnect.js index 86fd27f294..1f07f97513 100644 --- a/protocols/luci-proto-openconnect/htdocs/luci-static/resources/protocol/openconnect.js +++ b/protocols/luci-proto-openconnect/htdocs/luci-static/resources/protocol/openconnect.js @@ -102,6 +102,7 @@ return network.registerProtocol('openconnect', { s.taboption('general', form.Value, 'serverhash', _("VPN Server's certificate SHA1 hash")); s.taboption('general', form.Value, 'authgroup', _('Auth Group')); + s.taboption('general', form.Value, 'usergroup', _('User Group')); s.taboption("general", form.Value, "username", _("Username")); o = s.taboption('general', form.Value, 'password', _('Password')); diff --git a/protocols/luci-proto-openconnect/root/usr/libexec/rpcd/luci.openconnect b/protocols/luci-proto-openconnect/root/usr/libexec/rpcd/luci.openconnect index 9378cc518b..38650a615f 100755 --- a/protocols/luci-proto-openconnect/root/usr/libexec/rpcd/luci.openconnect +++ b/protocols/luci-proto-openconnect/root/usr/libexec/rpcd/luci.openconnect @@ -59,19 +59,19 @@ elseif arg[1] == "call" then if arg[2] == "getCertificates" then print(json.stringify({ - user_certificate = readfile(string.format("/etc/openconnect/user-cert-%s.pem", args.interface)), - user_privatekey = readfile(string.format("/etc/openconnect/user-key-%s.pem", args.interface)), - ca_certificate = readfile(string.format("/etc/openconnect/ca-%s.pem", args.interface)) + user_certificate = readfile(string.format("/etc/openconnect/user-cert-vpn-%s.pem", args.interface)), + user_privatekey = readfile(string.format("/etc/openconnect/user-key-vpn-%s.pem", args.interface)), + ca_certificate = readfile(string.format("/etc/openconnect/ca-vpn-%s.pem", args.interface)) })) elseif arg[2] == "setCertificates" then if args.user_certificate then - writefile(string.format("/etc/openconnect/user-cert-%s.pem", args.interface), args.user_certificate) + writefile(string.format("/etc/openconnect/user-cert-vpn-%s.pem", args.interface), args.user_certificate) end if args.user_privatekey then - writefile(string.format("/etc/openconnect/user-key-%s.pem", args.interface), args.user_privatekey) + writefile(string.format("/etc/openconnect/user-key-vpn-%s.pem", args.interface), args.user_privatekey) end if args.ca_certificate then - writefile(string.format("/etc/openconnect/ca-%s.pem", args.interface), args.ca_certificate) + writefile(string.format("/etc/openconnect/ca-vpn-%s.pem", args.interface), args.ca_certificate) end print(json.stringify({ result = true })) end diff --git a/protocols/luci-proto-vxlan/Makefile b/protocols/luci-proto-vxlan/Makefile new file mode 100644 index 0000000000..d6b2e6faaa --- /dev/null +++ b/protocols/luci-proto-vxlan/Makefile @@ -0,0 +1,16 @@ +# +# Copyright 2020 Wojciech Jowsa <wojciech.jowsa@gmail.com> +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Support for Virtual eXtensible Local Area Network (VXLAN, RFC7348) +LUCI_DEPENDS:=+vxlan + +PKG_MAINTAINER:=Wojciech Jowsa <wojciech.jowsa@gmail.com> + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/protocols/luci-proto-vxlan/htdocs/luci-static/resources/protocol/vxlan.js b/protocols/luci-proto-vxlan/htdocs/luci-static/resources/protocol/vxlan.js new file mode 100644 index 0000000000..9927f0bc65 --- /dev/null +++ b/protocols/luci-proto-vxlan/htdocs/luci-static/resources/protocol/vxlan.js @@ -0,0 +1,89 @@ +'use strict'; +'require form'; +'require network'; +'require tools.widgets as widgets'; + +network.registerPatternVirtual(/^vxlan-.+$/); + +return network.registerProtocol('vxlan', { + getI18n: function() { + return _('VXLAN (RFC7348)'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'vxlan-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'vxlan'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + o = s.taboption('general', form.Value, 'peeraddr', _('Remote IPv4 address'), _('The IPv4 address or the fully-qualified domain name of the remote end.')); + o.optional = false; + o.datatype = 'or(hostname,ip4addr("nomask"))'; + + o = s.taboption('general', form.Value, 'ipaddr', _('Local IPv4 address'), _('The local IPv4 address over which the tunnel is created (optional).')); + o.optional = true; + o.datatype = 'ip4addr("nomask")'; + + o = s.taboption('general', form.Value, 'port', _('Destination port')); + o.optional = true; + o.placeholder = 4789; + o.datatype = 'port'; + + o = s.taboption('general', form.Value, 'vid', _('VXLAN network identifier'), _('ID used to uniquely identify the VXLAN')); + o.optional = true; + o.datatype = 'range(1, 16777216)'; + + o = s.taboption('general', widgets.NetworkSelect, 'tunlink', _('Bind interface'), _('Bind the tunnel to this interface (optional).')); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU'), _('Specify an MTU (Maximum Transmission Unit) other than the default (1280 bytes).')); + o.optional = true; + o.placeholder = 1280; + o.datatype = 'range(68, 9200)'; + + o = s.taboption('advanced', form.Value, 'ttl', _('Override TTL'), _('Specify a TTL (Time to Live) for the encapsulating packet other than the default (64).')); + o.optional = true; + o.placeholder = 64; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'tos', _('Override TOS'), _('Specify a TOS (Type of Service).')); + o.optional = true; + o.datatype = 'range(0, 255)'; + + o = s.taboption('advanced', form.Value, 'macaddr', _('Override MAC address')); + o.optional = true; + o.datatype = 'macaddr'; + + o = s.taboption('advanced', form.Flag, 'rxcsum', _('Enable rx checksum')); + o.optional = true; + o.default = o.enabled; + + o = s.taboption('advanced', form.Flag, 'txcsum', _('Enable tx checksum')); + o.optional = true; + o.default = o.enabled; + + } +}); diff --git a/protocols/luci-proto-vxlan/htdocs/luci-static/resources/protocol/vxlan6.js b/protocols/luci-proto-vxlan/htdocs/luci-static/resources/protocol/vxlan6.js new file mode 100644 index 0000000000..f568e7e244 --- /dev/null +++ b/protocols/luci-proto-vxlan/htdocs/luci-static/resources/protocol/vxlan6.js @@ -0,0 +1,84 @@ +'use strict'; +'require form'; +'require network'; +'require tools.widgets as widgets'; + +network.registerPatternVirtual(/^vxlan-.+$/); + +return network.registerProtocol('vxlan6', { + getI18n: function() { + return _('VXLANv6 (RFC7348)'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'vxlan-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'vxlan'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var o; + + o = s.taboption('general', form.Value, 'peer6addr', _('Remote IPv6 address'), _('The IPv6 address or the fully-qualified domain name of the remote end.')); + o.optional = false; + o.datatype = 'or(hostname,cidr6)'; + + o = s.taboption('general', form.Value, 'ip6addr', _('Local IPv6 address'), _('The local IPv6 address over which the tunnel is created (optional).')); + o.optional = true; + o.datatype = 'cidr6'; + + o = s.taboption('general', form.Value, 'vid', _('VXLAN network identifier'), _('ID used to uniquely identify the VXLAN')); + o.optional = true; + o.datatype = 'range(1, 16777216)'; + + o = s.taboption('general', widgets.NetworkSelect, 'tunlink', _('Bind interface'), _('Bind the tunnel to this interface (optional).')); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + + o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU'), _('Specify an MTU (Maximum Transmission Unit) other than the default (1280 bytes).')); + o.optional = true; + o.placeholder = 1280; + o.datatype = 'range(68, 9200)'; + + o = s.taboption('advanced', form.Value, 'ttl', _('Override TTL'), _('Specify a TTL (Time to Live) for the encapsulating packet other than the default (64).')); + o.optional = true; + o.placeholder = 64; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'tos', _('Override TOS'), _('Specify a TOS (Type of Service).')); + o.optional = true; + o.datatype = 'range(0, 255)'; + + o = s.taboption('advanced', form.Value, 'macaddr', _('Override MAC address')); + o.optional = true; + o.datatype = 'macaddr'; + + o = s.taboption('advanced', form.Flag, 'rxcsum', _('Enable rx checksum')); + o.optional = true; + o.default = o.enabled; + + o = s.taboption('advanced', form.Flag, 'txcsum', _('Enable tx checksum')); + o.optional = true; + o.default = o.enabled; + + } +}); diff --git a/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js b/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js index c8e1f8403e..e88c07c339 100644 --- a/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js +++ b/protocols/luci-proto-wireguard/htdocs/luci-static/resources/protocol/wireguard.js @@ -1,4 +1,5 @@ 'use strict'; +'require uci'; 'require form'; 'require network'; @@ -9,6 +10,9 @@ function validateBase64(section_id, value) { if (value.length != 44 || !value.match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/)) return _('Invalid Base64 key string'); + if (value[43] != "=" ) + return _('Invalid Base64 key string'); + return true; } @@ -123,7 +127,14 @@ return network.registerProtocol('wireguard', { o = ss.option(form.DynamicList, 'allowed_ips', _('Allowed IPs'), _("Required. IP addresses and prefixes that this peer is allowed to use inside the tunnel. Usually the peer's tunnel IP addresses and the networks the peer routes through the tunnel.")); o.datatype = 'ipaddr'; - o.rmempty = false; + o.validate = function(section, value) { + var opt = this.map.lookupOption('allowed_ips', section); + var ips = opt[0].formvalue(section); + if (ips.length == 0) { + return _('Value must not be empty'); + } + return true; + }; o = ss.option(form.Flag, 'route_allowed_ips', _('Route Allowed IPs'), _('Optional. Create routes for Allowed IPs for this peer.')); @@ -138,5 +149,11 @@ return network.registerProtocol('wireguard', { o = ss.option(form.Value, 'persistent_keepalive', _('Persistent Keep Alive'), _('Optional. Seconds between keep alive messages. Default is 0 (disabled). Recommended value if this device is behind a NAT is 25.')); o.datatype = 'range(0,65535)'; o.placeholder = '0'; + }, + + deleteConfiguration: function() { + uci.sections('network', 'wireguard_%s'.format(this.sid), function(s) { + uci.remove('network', s['.name']); + }); } }); |