diff --git a/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js b/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js new file mode 100644 index 000000000..7ba8d1e43 --- /dev/null +++ b/luci-app-omr-bypass/htdocs/luci-static/resources/view/services/omr-bypass.js @@ -0,0 +1,164 @@ +'use strict'; +'require rpc'; +'require form'; +'require fs'; +'require uci'; +'require tools.widgets as widgets'; + +var callHostHints; + +return L.view.extend({ + callHostHints: rpc.declare({ + object: 'luci-rpc', + method: 'getHostHints', + expect: { '': {} } + }), + + load: function() { + return this.callHostHints(); + }, + + render: function(hosts) { + var m, s, o; + + m = new form.Map('omr-bypass', _('Bypass')); + + s = m.section(form.GridSection, 'domains', _('Domains')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'domain', _('Domain')); + o.rmempty = false; + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + s = m.section(form.GridSection, 'ips', _('IPs and Networks')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'ip', _('IP')); + o.rmempty = false; + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + s = m.section(form.GridSection, 'ips', _('Ports destination')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'dport', _('port')); + o.rmempty = false; + + o = s.option(form.MultiValue, 'proto', _('protocol')); + o.default = 'tcp'; + o.modalonly = true; + o.custom = true; + o.rmempty = false; + o.value('tcp'); + o.value('udp'); + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + s = m.section(form.GridSection, 'mac', _('MAC-Address')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'mac', _('source MAC-Address')); + o.datatype = 'list(unique(macaddr))'; + o.rmempty = false; + Object.keys(hosts).forEach(function(mac) { + var hint = hosts[mac].name || hosts[mac].ipv4; + o.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac); + }); + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + s = m.section(form.GridSection, 'lan_ip', _('Source lan IP address or network')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'ip', _('IP Address')); + o.datatype = 'or(ip4addr,ip6addr)'; + o.rmempty = false; + Object.keys(hosts).forEach(function(mac) { + if (hosts[mac].ipv4) { + var hint = hosts[mac].name; + o.value(hosts[mac].ipv4, hint ? '%s (%s)'.format(hosts[mac].ipv4, hint) : hosts[mac].ipv4); + } + }); + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + s = m.section(form.GridSection, 'asns', _('ASN')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'asn', _('ASN')); + o.rmempty = false; + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + s = m.section(form.GridSection, 'dpis', _('Protocols and services')); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'proto', _('Protocol/Service')); + o.rmempty = false; + o.load = function(section_id) { + return Promise.all([ + fs.lines('/proc/net/xt_ndpi/proto'), + fs.lines('/proc/net/xt_ndpi/host_proto') + ]).then(L.bind(function(linesi) { + var proto = linesi[0], + host = linesi[1], + name = []; + for (var i = 0; i < proto.length; i++) { + var m = proto[i].split(/\s+/); + if (m && m[0] != "#id") + name.push(m[2]); + } + for (var i = 0; i < host.length; i++) { + var m = host[i].split(/:/); + if (m && m[0] != "#Proto") + name.push(m[0]); + } + name = Array.from(new Set(name)).sort(); + for (var i = 0; i < name.length; i++) { + this.value(name[i]); + } + return this.super('load', [section_id]); + },this)); + }; + + o = s.option(widgets.DeviceSelect, 'interface', _('Interface')); + o.rmempty = false; + + o = s.option(form.Value, 'note', _('Note')); + o.rmempty = true; + + return m.render(); + } +}); diff --git a/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua b/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua deleted file mode 100644 index 46ba4fabf..000000000 --- a/luci-app-omr-bypass/luasrc/controller/omr-bypass.lua +++ /dev/null @@ -1,9 +0,0 @@ -local ucic = luci.model.uci.cursor() -local dt = require "luci.cbi.datatypes" -module("luci.controller.omr-bypass", package.seeall) - -function index() - entry({"admin", "services", "omr-bypass"}, alias("admin", "services", "omr-bypass", "index"), _("OMR-Bypass")) - --entry({"admin", "services", "omr-bypass", "index"}, template("omr-bypass/bypass")) - entry({"admin", "services", "omr-bypass", "index"}, cbi("omr-bypass")) -end diff --git a/luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua b/luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua deleted file mode 100644 index b819c39b1..000000000 --- a/luci-app-omr-bypass/luasrc/model/cbi/omr-bypass.lua +++ /dev/null @@ -1,169 +0,0 @@ --- Copyright 2018-2019 Ycarus (Yannick Chabanois) --- Licensed to the public under the Apache License 2.0. - -local ipc = require "luci.ip" -local sys = require "luci.sys" -local net = require "luci.model.network".init() -local ifaces = net:get_interfaces() or { net:get_interface() } - -m = Map("omr-bypass", translate("Bypass"), translate("Here you can bypass ShadowSocks and VPN. If you set Interface to Default this use any working interface.")) - -s = m:section(TypedSection, "domains", translate("Domains")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -hn = s:option(Value, "name", translate("Domain")) -hn.datatype = "hostname" -hn.optional = false -hn.rmempty = true - -ifd = s:option(ListValue, "interface", translate("Interface")) -ifd.rmempty = true - -dn = s:option(Value,"note",translate("Note")) - -s = m:section(TypedSection, "ips", translate("IPs and Networks")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -ip = s:option(Value, "ip", translate("IP")) -ip.datatype = "ipaddr" -ip.rmempty = true -ip.optional = false - -ifi = s:option(ListValue, "interface", translate("Interface")) -ifi.rmempty = true - -inn = s:option(Value,"note",translate("Note")) - - -s = m:section(TypedSection, "dest_port", translate("Ports destination")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -dp = s:option(Value, "dport", translate("port")) -dp.rmempty = true -dp.optional = false - -proto = s:option(ListValue, "proto", translate("Protocol")) -proto:value("all",translate("ALL")) -proto:value("tcp","TCP") -proto:value("udp","UDP") -proto:value("icmp","ICMP") -proto.rmempty = true -proto.optional = false - -ifdp = s:option(ListValue, "interface", translate("Interface")) -ifdp.rmempty = true - -dpn = s:option(Value,"note",translate("Note")) - -s = m:section(TypedSection, "macs", translate("MAC-Address")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -mac = s:option(Value, "mac", translate("Source MAC-Address")) -mac.datatype = "list(macaddr)" -mac.rmempty = true -mac.optional = false - -sys.net.host_hints(function(m, v4, v6, name) - if m then - mac:value(m, "%s (%s)" %{m, name or v4 or v6}) - end -end) - -ifm = s:option(ListValue, "interface", translate("Interface")) -ifm.rmempty = true - -macn = s:option(Value,"note",translate("Note")) - -s = m:section(TypedSection, "lan_ip", translate("Source lan IP address or network")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -ip = s:option(Value, "ip", translate("IP Address")) -ip.datatype = "ipaddr" -ip.rmempty = true -ip.optional = false - -ifl = s:option(ListValue, "interface", translate("Interface")) -ifl.rmempty = true - -lanipn = s:option(Value,"note",translate("Note")) - -s = m:section(TypedSection, "asns", translate("ASN")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -asn = s:option(Value, "asn", translate("ASN")) -asn.rmempty = true -asn.optional = false - -ifa = s:option(ListValue, "interface", translate("Interface")) -ifa.rmempty = true - -asnn = s:option(Value,"note",translate("Note")) - -s = m:section(TypedSection, "dpis", translate("Protocols and services")) -s.addremove = true -s.anonymous = true -s.template = "cbi/tblsection" - -dpi = s:option(ListValue, "proto", translate("Protocol/Service")) -dpi.rmempty = true -dpi.optional = false -local xt_ndpi_available = nixio.fs.access("/proc/net/xt_ndpi/proto") -if xt_ndpi_available then - local protos = {} - for l in io.lines("/proc/net/xt_ndpi/proto") do - local a,b,c,d = l:match('(%w+) (%w+)') - if b ~= "2" and not string.match(b,"custom") then - table.insert(protos,b) - end - end - table.sort(protos, function(a, b) return a:upper() < b:upper() end) - for _,b in ipairs(protos) do - dpi:value(b,"%s" % tostring(b)) - end -end - -ifp = s:option(ListValue, "interface", translate("Interface")) -ifp.rmempty = true - -psn = s:option(Value,"note",translate("Note")) - - -ifd.default = "all" -ifi.default = "all" -ifp.default = "all" -ifm.default = "all" -ifl.default = "all" -ifa.default = "all" -ifdp.default = "all" -ifd:value("all",translate("Default")) -ifi:value("all",translate("Default")) -ifp:value("all",translate("Default")) -ifm:value("all",translate("Default")) -ifl:value("all",translate("Default")) -ifa:value("all",translate("Default")) -ifdp:value("all",translate("Default")) -for _, iface in ipairs(ifaces) do - if iface:is_up() then - ifd:value(iface:name(),"%s" % iface:name()) - ifi:value(iface:name(),"%s" % iface:name()) - ifp:value(iface:name(),"%s" % iface:name()) - ifm:value(iface:name(),"%s" % iface:name()) - ifl:value(iface:name(),"%s" % iface:name()) - ifa:value(iface:name(),"%s" % iface:name()) - ifdp:value(iface:name(),"%s" % iface:name()) - end -end - -return m diff --git a/luci-app-omr-bypass/root/usr/share/luci/menu.d/luci-app-omr-bypass.json b/luci-app-omr-bypass/root/usr/share/luci/menu.d/luci-app-omr-bypass.json new file mode 100644 index 000000000..3a00a15d0 --- /dev/null +++ b/luci-app-omr-bypass/root/usr/share/luci/menu.d/luci-app-omr-bypass.json @@ -0,0 +1,10 @@ +{ + "admin/services/omr-bypass": { + "title": "Bypass", + "order": 60, + "action": { + "type": "view", + "path": "services/omr-bypass" + } + } +} diff --git a/luci-app-omr-bypass/root/usr/share/rpcd/acl.d/luci-app-omr-bypass.json b/luci-app-omr-bypass/root/usr/share/rpcd/acl.d/luci-app-omr-bypass.json new file mode 100644 index 000000000..8d3d97244 --- /dev/null +++ b/luci-app-omr-bypass/root/usr/share/rpcd/acl.d/luci-app-omr-bypass.json @@ -0,0 +1,11 @@ +{ + "luci-app-omr-bypass": { + "description": "Grant access to ndpi resources", + "read": { + "file": { + "/proc/net/xt_ndpi/proto": [ "read" ], + "/proc/net/xt_ndpi/host_proto": [ "read" ], + } + } + } +} \ No newline at end of file