luci-app-socat: add application

This commit is contained in:
Beginner-Go 2022-05-26 09:37:03 +00:00
parent 772b53145a
commit df8288f9d9
10 changed files with 419 additions and 0 deletions

View File

@ -0,0 +1,24 @@
# Copyright (C) 2020 Lienol <lawlienol@gmail.com>
#
# This is free software, licensed under the GNU General Public License v3.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-socat
PKG_VERSION:=20200824
PKG_RELEASE:=5
PKG_MAINTAINER:=Lienol <lawlienol@gmail.com>
LUCI_TITLE:=LuCI support for Socat
LUCI_DEPENDS:=+socat
LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/conffiles
/etc/config/socat
endef
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1,22 @@
-- Copyright 2020 Lienol <lawlienol@gmail.com>
module("luci.controller.socat", package.seeall)
function index()
if not nixio.fs.access("/etc/config/socat") then
return
end
entry({"admin", "network", "socat"}, alias("admin", "network", "socat", "index"), _("Socat"), 100).dependent = true
entry({"admin", "network", "socat", "index"}, cbi("socat/index")).leaf = true
entry({"admin", "network", "socat", "config"}, cbi("socat/config")).leaf = true
entry({"admin", "network", "socat", "status"}, call("act_status")).leaf = true
end
function act_status()
local e = {}
e.index = luci.http.formvalue("index")
e.status = luci.sys.call(string.format("ps -w | grep -v 'grep' | grep '/var/etc/socat/%s' >/dev/null", luci.http.formvalue("id"))) == 0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end

View File

@ -0,0 +1,82 @@
local d = require "luci.dispatcher"
m = Map("socat", translate("Socat Config"))
m.redirect = d.build_url("admin", "network", "socat")
s = m:section(NamedSection, arg[1], "config", "")
s.addremove = false
s.dynamic = false
o = s:option(Flag, "enable", translate("Enable"))
o.default = "1"
o.rmempty = false
o = s:option(Value, "remarks", translate("Remarks"))
o.default = translate("Remarks")
o.rmempty = false
o = s:option(ListValue, "protocol", translate("Protocol"))
o:value("port_forwards", translate("Port Forwards"))
o = s:option(ListValue, "family", translate("Restrict to address family"))
o:value("", translate("IPv4 and IPv6"))
o:value("4", translate("IPv4 only"))
o:value("6", translate("IPv6 only"))
o:depends("protocol", "port_forwards")
o = s:option(ListValue, "proto", translate("Protocol"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:depends("protocol", "port_forwards")
o = s:option(Value, "listen_port", translate("Listen port"))
o.datatype = "portrange"
o.rmempty = false
o:depends("protocol", "port_forwards")
o = s:option(Flag, "reuseaddr", "reuseaddr", translate("Bind to a port local"))
o.default = "1"
o.rmempty = false
o = s:option(ListValue, "dest_proto", translate("Destination Protocol"))
o:value("tcp4", "IPv4-TCP")
o:value("udp4", "IPv4-UDP")
o:value("tcp6", "IPv6-TCP")
o:value("udp6", "IPv6-UDP")
o:depends("protocol", "port_forwards")
dest_ipv4 = s:option(Value, "dest_ipv4", translate("Destination address"))
luci.sys.net.ipv4_hints(function(ip, name)
dest_ipv4:value(ip, "%s (%s)" %{ ip, name })
end)
function dest_ipv4.cfgvalue(self, section)
return m:get(section, "dest_ip")
end
function dest_ipv4.write(self, section, value)
m:set(section, "dest_ip", value)
end
dest_ipv4:depends("dest_proto", "tcp4")
dest_ipv4:depends("dest_proto", "udp4")
dest_ipv6 = s:option(Value, "dest_ipv6", translate("Destination address"))
luci.sys.net.ipv6_hints(function(ip, name)
dest_ipv6:value(ip, "%s (%s)" %{ ip, name })
end)
function dest_ipv6.cfgvalue(self, section)
return m:get(section, "dest_ip")
end
function dest_ipv6.write(self, section, value)
m:set(section, "dest_ip", value)
end
dest_ipv6:depends("dest_proto", "tcp6")
dest_ipv6:depends("dest_proto", "udp6")
o = s:option(Value, "dest_port", translate("Destination port"))
o.datatype = "portrange"
o.rmempty = false
o = s:option(Flag, "firewall_accept", translate("Open firewall port"))
o.default = "1"
o.rmempty = false
return m

View File

@ -0,0 +1,78 @@
local d = require "luci.dispatcher"
local e = luci.model.uci.cursor()
m = Map("socat")
m.title = translate("Socat")
m.description = translate("Socat is a versatile networking tool named after 'Socket CAT', which can be regarded as an N-fold enhanced version of NetCat")
s = m:section(NamedSection, "global", "global")
s.anonymous = true
s.addremove = false
o = s:option(Flag, "enable", translate("Enable"))
o.rmempty = false
s = m:section(TypedSection, "config", translate("Port Forwards"))
s.anonymous = true
s.addremove = true
s.template = "cbi/tblsection"
s.extedit = d.build_url("admin", "network", "socat", "config", "%s")
function s.filter(e, t)
if m:get(t, "protocol") == "port_forwards" then
return true
end
end
function s.create(e, t)
local uuid = string.gsub(luci.sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)"), "-", "")
t = uuid
TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t))
end
function s.remove(e, t)
e.map.proceed = true
e.map:del(t)
luci.http.redirect(d.build_url("admin", "network", "socat"))
end
o = s:option(Flag, "enable", translate("Enable"))
o.width = "5%"
o.rmempty = false
o = s:option(DummyValue, "status", translate("Status"))
o.template = "socat/status"
o.value = translate("Collecting data...")
o = s:option(DummyValue, "remarks", translate("Remarks"))
o = s:option(DummyValue, "family", translate("Listen Protocol"))
o.cfgvalue = function(t, n)
local listen = Value.cfgvalue(t, n) or ""
local protocol = (m:get(n, "proto") or ""):upper()
if listen == "" then
return protocol
else
return "IPv" .. listen .. "-" .. protocol
end
end
o = s:option(DummyValue, "listen_port", translate("Listen port"))
o = s:option(DummyValue, "dest_proto", translate("Destination Protocol"))
o.cfgvalue = function(t, n)
local listen = Value.cfgvalue(t, n)
local protocol = listen:sub(0, #listen - 1):upper()
local ip_type = "IPv" .. listen:sub(#listen)
return ip_type .. "-" .. protocol
end
o = s:option(DummyValue, "dest_ip", translate("Destination address"))
o = s:option(DummyValue, "dest_port", translate("Destination port"))
o = s:option(Flag, "firewall_accept", translate("Open firewall port"))
o.default = "1"
o.rmempty = false
m:append(Template("socat/list_status"))
return m

View File

@ -0,0 +1,19 @@
<script type="text/javascript">
//<![CDATA[
var _status = document.getElementsByClassName('_status');
for(var i = 0; i < _status.length; i++) {
var id = _status[i].parentElement.parentElement.parentElement.id;
id = id.substr(id.lastIndexOf("-") + 1);
XHR.poll(1,'<%=url([[admin]], [[network]], [[socat]], [[status]])%>', {
index: i,
id: id
},
function(x, result) {
_status[result.index].setAttribute("style","font-weight:bold;");
_status[result.index].setAttribute("color",result.status ? "green":"red");
_status[result.index].innerHTML = (result.status ? '✓' : 'X');
}
);
}
//]]>
</script>

View File

@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<font class="_status" hint="<%=self:cfgvalue(section)%>">--</font>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,50 @@
msgid "Socat"
msgstr "Socat"
msgid "Socat is a versatile networking tool named after 'Socket CAT', which can be regarded as an N-fold enhanced version of NetCat"
msgstr "Socat 是 Linux 下的一个多功能的网络工具名字来由是「Socket CAT」。其功能与有瑞士军刀之称的 Netcat 类似,可以看做是 Netcat 的加强版。"
msgid "Socat Config"
msgstr "Socat 配置"
msgid "Status"
msgstr "状态"
msgid "Enabled"
msgstr "启用"
msgid "Remarks"
msgstr "备注"
msgid "Protocol"
msgstr "协议"
msgid "IPv6 Only"
msgstr "仅IPv6"
msgid "When checked, only IPv6 ports are listen for, otherwise IPv4 will also be listened for."
msgstr "当勾选时仅监听IPv6否则将会同时监听IPv4。"
msgid "Port Forwards"
msgstr "端口转发"
msgid "Listen Protocol"
msgstr "监听协议"
msgid "Listen port"
msgstr "监听端口"
msgid "Bind to a port local"
msgstr "绑定到本地端口"
msgid "Destination Protocol"
msgstr "目标协议"
msgid "Destination address"
msgstr "目标地址"
msgid "Destination port"
msgstr "目标端口"
msgid "Open firewall port"
msgstr "打开防火墙端口"

View File

@ -0,0 +1,3 @@
config global 'global'
option enable '0'

View File

@ -0,0 +1,119 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2020 Lienol <lawlienol@gmail.com>
START=99
CONFIG=socat
CONFIG_PATH=/var/etc/$CONFIG
add_rule() {
iptables -N SOCAT
iptables -I INPUT -j SOCAT
ip6tables -N SOCAT
ip6tables -I INPUT -j SOCAT
}
del_rule() {
iptables -D INPUT -j SOCAT 2>/dev/null
iptables -F SOCAT 2>/dev/null
iptables -X SOCAT 2>/dev/null
ip6tables -D INPUT -j SOCAT 2>/dev/null
ip6tables -F SOCAT 2>/dev/null
ip6tables -X SOCAT 2>/dev/null
}
gen_include() {
echo '#!/bin/sh' > /var/etc/$CONFIG.include
extract_rules() {
local _ipt="iptables"
[ "$1" == "6" ] && _ipt="ip6tables"
echo "*$2"
${_ipt}-save -t $2 | grep "SOCAT" | \
sed -e "s/^-A \(INPUT\)/-I \1 1/"
echo 'COMMIT'
}
cat <<-EOF >> /var/etc/$CONFIG.include
iptables-save -c | grep -v "SOCAT" | iptables-restore -c
iptables-restore -n <<-EOT
$(extract_rules 4 filter)
EOT
ip6tables-save -c | grep -v "SOCAT" | ip6tables-restore -c
ip6tables-restore -n <<-EOT
$(extract_rules 6 filter)
EOT
EOF
return 0
}
run_service() {
config_get enable $1 enable
[ "$enable" = "0" ] && return 0
config_get remarks $1 remarks
config_get protocol $1 protocol
config_get family $1 family
config_get proto $1 proto
config_get listen_port $1 listen_port
config_get reuseaddr $1 reuseaddr
config_get dest_proto $1 dest_proto
config_get dest_ip $1 dest_ip
config_get dest_port $1 dest_port
config_get firewall_accept $1 firewall_accept
ln -s /usr/bin/socat ${CONFIG_PATH}/$1
if [ "$reuseaddr" == "1" ]; then
reuseaddr=",reuseaddr"
else
reuseaddr=""
fi
if [ "$family" == "6" ]; then
ipv6only_params=",ipv6-v6only"
else
ipv6only_params=""
fi
# 端口转发
if [ "$protocol" == "port_forwards" ]; then
listen=${proto}${family}
[ "$family" == "" ] && listen=${proto}6
${CONFIG_PATH}/$1 ${listen}-listen:${listen_port}${ipv6only_params}${reuseaddr},fork ${dest_proto}:${dest_ip}:${dest_port} >/dev/null 2>&1 &
fi
[ "$firewall_accept" == "1" ] && {
if [ -z "$family" ] || [ "$family" == "6" ]; then
ip6tables -A SOCAT -p $proto --dport $listen_port -m comment --comment "$remarks" -j ACCEPT
fi
if [ -z "$family" ] || [ "$family" == "4" ]; then
iptables -A SOCAT -p $proto --dport $listen_port -m comment --comment "$remarks" -j ACCEPT
fi
}
}
stop_service() {
ps -w | grep "$CONFIG_PATH/" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
del_rule
rm -rf $CONFIG_PATH /var/etc/$CONFIG.include
}
start() {
enable=$(uci -q get $CONFIG.@global[0].enable)
if [ "$enable" = "0" ];then
stop_service
else
mkdir -p $CONFIG_PATH
add_rule
config_load $CONFIG
config_foreach run_service "config"
gen_include
fi
}
stop() {
stop_service
}
restart() {
stop
start
}

View File

@ -0,0 +1,19 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete firewall.socat
set firewall.socat=include
set firewall.socat.type=script
set firewall.socat.path=/var/etc/socat.include
set firewall.socat.reload=1
EOF
uci -q batch <<-EOF >/dev/null
delete ucitrack.@socat[-1]
add ucitrack socat
set ucitrack.@socat[-1].init=luci_socat
commit ucitrack
EOF
rm -rf /tmp/luci-*cache
exit 0