🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 97c049ed0a
commit 0acff03804
14253 files changed
+3893239

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
VERSION="$1"
CURDIR="$2"
BIN_PATH="$3"
if [ -d "$CURDIR/.git" ]; then
config="$CURDIR/.git/config"
else
config="$(sed "s|^gitdir:\s*|$CURDIR/|;s|$|/config|" "$CURDIR/.git")"
fi
[ -n "$(sed -En '/^\[remote /{h;:top;n;/^\[/b;s,(https?://gitcode\.(com|net)),\1,;T top;H;x;s|\n\s*|: |;p;}' "$config")" ] && {
echo -e "#!/bin/sh\necho $VERSION" > "$BIN_PATH"
}
exit 0
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Anya Lin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+144
View File
@@ -0,0 +1,144 @@
# SPDX-License-Identifier: MIT
#
# Copyright (C) 2023-2026 Anya Lin <hukk1996@gmail.com>
include $(TOPDIR)/rules.mk
PKG_UPSTREAM_NAME:=natmap
PKG_NAME:=natmapt
PKG_UPSTREAM_VERSION:=20260214
PKG_UPSTREAM_GITHASH:=
PKG_VERSION:=$(PKG_UPSTREAM_VERSION)$(if $(PKG_UPSTREAM_GITHASH),~$(call version_abbrev,$(PKG_UPSTREAM_GITHASH)))
PKG_RELEASE:=1
SCRIPTS_VERSION:=0.2026.01.24
PKG_SOURCE_SUBDIR:=$(PKG_UPSTREAM_NAME)-$(PKG_UPSTREAM_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
ifeq ($(PKG_UPSTREAM_GITHASH),)
PKG_SOURCE_URL:=https://github.com/heiher/natmap/releases/download/$(PKG_UPSTREAM_VERSION)
PKG_HASH:=skip
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.xz
else
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/heiher/natmap.git
PKG_SOURCE_VERSION:=f8d7996710677c9885c148dda80a42d626f0a17b
PKG_MIRROR_HASH:=skip
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR)-$(PKG_SOURCE_VERSION).tar.gz
endif
PKG_MAINTAINER:=Anya Lin <hukk1996@gmail.com>, Richard Yu <yurichard3839@gmail.com>, Ray Wang <r@hev.cc>
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=License
PKG_USE_MIPS16:=0
PKG_BUILD_FLAGS:=no-mips16
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
define Package/natmapt
SECTION:=net
CATEGORY:=Network
TITLE:=TCP/UDP port mapping tool for full cone NAT
URL:=https://github.com/heiher/natmap
DEPENDS:=+curl +jsonfilter +bash
endef
MAKE_FLAGS += REV_ID="$(PKG_VERSION)"
define Package/natmapt/conffiles
/etc/config/natmap
endef
define Package/natmapt/prerm
#!/bin/sh
rm -f "$$IPKG_INSTROOT/usr/bin/natmap-curl"
exit 0
endef
define Package/natmapt/install
$(CURDIR)/.prepare.sh $(VERSION) $(CURDIR) $(PKG_BUILD_DIR)/bin/natmap
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/natmap $(1)/usr/bin/
$(INSTALL_DIR) $(1)/usr/lib/natmap/
$(INSTALL_BIN) ./files/natmap-update.sh $(1)/usr/lib/natmap/update.sh
$(INSTALL_BIN) ./files/common.sh $(1)/usr/lib/natmap/common.sh
$(INSTALL_DIR) $(1)/etc/config/
$(INSTALL_CONF) ./files/natmap.config $(1)/etc/config/natmap
$(INSTALL_DIR) $(1)/etc/init.d/
$(INSTALL_BIN) ./files/natmap.init $(1)/etc/init.d/natmap
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/natmap.defaults $(1)/etc/uci-defaults/97_natmap
$(INSTALL_DIR) $(1)/etc/natmap/client
$(INSTALL_BIN) ./files/client/qBittorrent $(1)/etc/natmap/client/
$(LN) qBittorrent $(1)/etc/natmap/client/qBittorrent-announce_port
$(INSTALL_DIR) $(1)/etc/natmap/notify
$(INSTALL_BIN) ./files/notify/ntfy $(1)/etc/natmap/notify/
$(INSTALL_DIR) $(1)/etc/natmap/ddns
$(INSTALL_BIN) ./files/ddns/Cloudflare $(1)/etc/natmap/ddns/
endef
define Package/natmapt-scripts/Default
SECTION:=net
CATEGORY:=Network
TITLE:=NATMap $(1) scripts ($(2))
DEPENDS:=+natmapt
PROVIDES:=@natmapt-$(1)-scripts @natmapt-$(1)-script-$(2)
VERSION:=$(SCRIPTS_VERSION)
PKGARCH:=all
endef
define Package/natmapt-scripts/install/Default
$(INSTALL_DIR) $(1)/etc/natmap/$(2)
$(INSTALL_BIN) ./files/$(2)/$(3) $(1)/etc/natmap/$(2)/
endef
define Package/natmapt-client-script-transmission
$(call Package/natmapt-scripts/Default,client,Transmission)
DEPENDS+:=
endef
define Package/natmapt-client-script-transmission/install
$(call Package/natmapt-scripts/install/Default,$(1),client,Transmission)
endef
define Package/natmapt-client-script-deluge
$(call Package/natmapt-scripts/Default,client,Deluge)
DEPENDS+:=
endef
define Package/natmapt-client-script-deluge/install
$(call Package/natmapt-scripts/install/Default,$(1),client,Deluge)
endef
define Package/natmapt-notify-script-pushbullet
$(call Package/natmapt-scripts/Default,notify,Pushbullet)
DEPENDS+:=
endef
define Package/natmapt-notify-script-pushbullet/install
$(call Package/natmapt-scripts/install/Default,$(1),notify,Pushbullet)
endef
define Package/natmapt-notify-script-pushover
$(call Package/natmapt-scripts/Default,notify,Pushover)
DEPENDS+:=
endef
define Package/natmapt-notify-script-pushover/install
$(call Package/natmapt-scripts/install/Default,$(1),notify,Pushover)
endef
define Package/natmapt-notify-script-telegram
$(call Package/natmapt-scripts/Default,notify,Telegram)
DEPENDS+:=
endef
define Package/natmapt-notify-script-telegram/install
$(call Package/natmapt-scripts/install/Default,$(1),notify,Telegram)
endef
$(eval $(call BuildPackage,natmapt))
$(eval $(call BuildPackage,natmapt-client-script-transmission))
$(eval $(call BuildPackage,natmapt-client-script-deluge))
$(eval $(call BuildPackage,natmapt-notify-script-pushbullet))
$(eval $(call BuildPackage,natmapt-notify-script-pushover))
$(eval $(call BuildPackage,natmapt-notify-script-telegram))
+54
View File
@@ -0,0 +1,54 @@
# openwrt-natmap
TCP/UDP port mapping for full cone NAT
> [NATMap][] project is used to establish a TCP/UDP port mapping from ISP NAT public address to local private address. If all layers of NAT are full cones (NAT-1), any host can access internal services through the mapped public address.
## Features included outside of NATMap
- [x] Automatically configure the Firewall
- [x] Transparent Port forward (Forward port = 0)
- [x] Refresh the listen port of the BT Client (Forward port = 0)
- [x] Port update notify script
- [x] A Record update script
- [x] AAAA Record update script
- [x] SRV Record update script
- [x] HTTPS Record update script
- [ ] SVCB Record update script
## Releases
You can find the prebuilt-ipks [here](https://fantastic-packages.github.io/releases/)\
And LuCI can be found here [luci-app-natmapt][]
## Build
```shell
# Take the x86_64 platform as an example
tar xjf openwrt-sdk-21.02.3-x86-64_gcc-8.4.0_musl.Linux-x86_64.tar.xz
# Go to the SDK root dir
cd OpenWrt-sdk-*-x86_64_*
# First run to generate a .config file
make menuconfig
./scripts/feeds update -a
./scripts/feeds install -a
# Get Makefile
git clone --depth 1 --branch master --single-branch --no-checkout https://github.com/muink/openwrt-natmapt.git package/natmapt
pushd package/natmapt
umask 022
git checkout
popd
# Select the package Network -> natmapt
make menuconfig
# Start compiling
make package/natmapt/compile V=99
```
## Collaborators
[Ray Wang](https://github.com/heiher)\
[Richard Yu](https://github.com/ysc3839)\
[Anya Lin](https://github.com/muink)
[NATMap]: https://github.com/heiher/natmap
[luci-app-natmapt]: https://github.com/muink/luci-app-natmapt
## License
This project is licensed under the MIT License
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
# Copyright (C) 2023 muink https://github.com/muink
#
# Client listen port refresh script
#
# depends jsonfilter
. /usr/lib/natmap/common.sh
# http_request <cookie> <data>
http_request() {
$CURL $retry --compressed -L -X POST \
-b "$1" -H "Content-Type: application/json" \
-d "$2" \
--url ${scheme}://${host}:${web_port}/json
}
start() {
local retry='--connect-timeout 1 --retry 0'
local cookie="$($CURL $retry --compressed -L -i \
-H "Content-Type: application/json" \
-d '{"method": "auth.login", "params": ["'"${password}"'"], "id": 1}' \
--url ${scheme}://${host}:${web_port}/json \
| grep -i set-cookie | sed -En 's|^.*(_session_id=\S+);.*|\1|p')"
local connected="$(http_request "$cookie" '{"method": "web.connected", "params": [], "id": 1}' | jsonfilter -qe '@.result')"
if [ "$connected" = "true" ]; then
http_request "$cookie" '{"method": "core.set_config", "params": [{"random_port": false}], "id": 1}'
http_request "$cookie" '{"method": "core.set_config", "params": [{"listen_ports": ["'"${port}"'","'"${port}"'"]}], "id": 1}'
fi
http_request "$cookie" '{"method": "auth.delete_session", "params": [], "id": 1}'
}
# All external parameters required
ALL_PARAMS="host port scheme web_port username password"
eval "$(JSON_EXPORT "$1")"; shift
start "$@"
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh
# Copyright (C) 2023 muink https://github.com/muink
#
# Client listen port refresh script
#
# depends
. /usr/lib/natmap/common.sh
start() {
local retry='--connect-timeout 1 --retry 0'
scheme='http' # only supports http
local sid="$($CURL $retry -L \
-u ${username}:${password} \
--url ${scheme}://${host}:${web_port}/transmission/rpc \
| sed 's|.*<code>||g;s|</code>.*||g')"
$CURL $retry -L -X POST \
-H "$sid" -u ${username}:${password} \
-d '{"method":"session-set","arguments":{"peer-port":"'"${port}"'"}}' \
--url ${scheme}://${host}:${web_port}/transmission/rpc
}
# All external parameters required
ALL_PARAMS="host port scheme web_port username password"
eval "$(JSON_EXPORT "$1")"; shift
start "$@"
+40
View File
@@ -0,0 +1,40 @@
#!/bin/sh
# Copyright (C) 2023-2025 muink https://github.com/muink
#
# Client listen port refresh script
#
# depends
. /usr/lib/natmap/common.sh
start() {
local retry='--connect-timeout 1 --retry 0'
local self_signed='-k'
local payload
case "$(basename "$0")" in
qBittorrent)
payload='json={"listen_port":'"${port}"'}';;
qBittorrent-announce_port)
payload='json={"announce_port":'"${port}"'}';;
*)
payload='json={"listen_port":'"${port}"'}';;
esac
local cookie="$($CURL $retry $self_signed -L -i \
-H "Referer: ${scheme}://${host}:${web_port}" \
-d "username=${username}&password=${password}" \
--url ${scheme}://${host}:${web_port}/api/v2/auth/login \
| grep -i set-cookie | sed -En 's|^.*(SID=\S+);.*|\1|p')"
$CURL $retry $self_signed -L -X POST \
-b "$cookie" \
-d "$payload" \
--url ${scheme}://${host}:${web_port}/api/v2/app/setPreferences
$CURL $retry $self_signed -L -I \
--cookie "$cookie" \
--url ${scheme}://${host}:${web_port}/api/v2/auth/logout
}
# All external parameters required
ALL_PARAMS="host port scheme web_port username password"
eval "$(JSON_EXPORT "$1")"; shift
start "$@"
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# Copyright (C) 2023 muink https://github.com/muink
#
# depends curl jsonfilter
CURL="$(command -v natmap-curl)"
# JSON_EXPORT <json>
JSON_EXPORT() {
for k in $ALL_PARAMS; do
jsonfilter -qs "$1" -e "$k=@['$k']"
done
}
# INIT_GLOBAL_VAR <var1> [var2] [var3] ...
INIT_GLOBAL_VAR() {
for _key in "$@"; do
eval "$_key=''"
done
}
+93
View File
@@ -0,0 +1,93 @@
#!/bin/bash
# Copyright (C) 2023 muink https://github.com/muink
#
# DDNS script
#
# depends jsonfilter
. /usr/lib/natmap/common.sh
. /usr/share/libubox/jshn.sh
# http_request <data> [record_id]
http_request() {
local data="$1"
local id="$2"
local method
[ -z "${id}" ] && method=POST || method=PUT # or PATCH
$CURL $retry -L -o /dev/null -X ${method} \
--url "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${id}" \
-H "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json' \
-d "$data"
}
start() {
local retry='--connect-timeout 3 --retry 5'
#$CURL $retry -L -X GET \
# --url "https://api.cloudflare.com/client/v4/user/tokens/verify" \
# -H "Authorization: Bearer ${TOKEN}" \
# -H "Content-Type:application/json" | jq
#$CURL $retry -L -X GET \
# --url "https://api.cloudflare.com/client/v4/zones" \
# -H "Authorization: Bearer ${TOKEN}" \
# -H "Content-Type:application/json" | jq
local records="$($CURL $retry -L -X GET \
--url "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
-H "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json')"
[ -z "$records" -o -n "$(grep -E "\"success\":\s*false" <<< "$records")" ] && return 1
local the_record
if [ -n "$host" ]; then
the_record="$(jsonfilter -s "$records" -qe '@.result[*]'|grep "\"type\": \"${hostype}\""|grep "\"name\": \"${host}\"")"
json_init
json_add_string type "${hostype}"
json_add_string name "${host}"
json_add_string content "${ip}"
json_add_int ttl 1
json_add_boolean proxied 0
http_request "$(json_dump)" "$(jsonfilter -s "$the_record" -qe '@.id')"
fi
if [ -n "${srv}" ]; then
the_record="$(jsonfilter -s "$records" -qe '@.result[*]'|grep "\"type\": \"SRV\""|grep "\"name\": \"_${srv_serv}._${srv_proto}.${srv}\""|grep "\"priority\": ${srv_priority}"|grep "\"weight\": ${srv_weight}")"
json_init
json_add_string type "SRV"
json_add_string name "_${srv_serv}._${srv_proto}.${srv}"
json_add_object data
json_add_int priority "${srv_priority}"
json_add_int weight "${srv_weight}"
json_add_int port "${port}"
json_add_string target "${srv_target}"
json_close_object
json_add_int ttl 1
json_add_boolean proxied 0
http_request "$(json_dump)" "$(jsonfilter -s "$the_record" -qe '@.id')"
fi
if [ -n "${https}" ]; then
the_record="$(jsonfilter -s "$records" -qe '@.result[*]'|grep "\"type\": \"HTTPS\""|grep "\"name\": \"${https}\""|grep "\"priority\": ${https_priority}")"
json_init
json_add_string type "HTTPS"
json_add_string name "${https}"
json_add_object data
json_add_int priority "${https_priority}"
json_add_string target "${https_target}"
json_add_string value "${https_svcparams}"
json_close_object
json_add_int ttl 1
json_add_boolean proxied 0
http_request "$(json_dump)" "$(jsonfilter -s "$the_record" -qe '@.id')"
fi
}
# All external parameters required
ALL_PARAMS="hostype host srv srv_serv srv_proto srv_target srv_priority srv_weight ip port https https_target https_svcparams https_priority tokens"
eval "$(JSON_EXPORT "$1")"; shift
# All external tokens required
INIT_GLOBAL_VAR TOKEN ZONE_ID
eval "$tokens"
start "$@"
+83
View File
@@ -0,0 +1,83 @@
#!/bin/bash
export ip="$1"
export port="$2"
export ip4p="$3"
export inner_port="$4"
export protocol="$5"
export inner_ip="$6"
shift 6
. /usr/share/libubox/jshn.sh
INITD='/etc/init.d/natmap'
STATUS_PATH='/var/run/natmap'
# fallloop <retry interval> <retry limit> <func> [args...]
fallloop() {
local retry="$1"; shift
local limit="$1"; shift
local func="$1"; shift
local error=1 count=0 && until [ $error = 0 -o $count -ge $limit ]; do
$func "$@" && error=0 || error=$?
let count++ && sleep $retry
done
}
# keep dest_port(forward port) consistent with public port
if [ -n "$RWFW" -a "$($INITD info|jsonfilter -qe "@['$(basename $INITD)'].instances['$SECTIONID'].data.firewall[0].dest_port")" != "$port" ]; then
export PUBPORT="$port" #PROCD_DEBUG=1
$INITD start "$SECTIONID"
fi
(
json_init
json_add_string sid "$SECTIONID"
json_add_string comment "$COMMENT"
json_add_string ip "$ip"
json_add_int port "$port"
json_add_string ip4p "$ip4p"
json_add_int inner_port "$inner_port"
json_add_string protocol "$protocol"
json_add_string inner_ip "$inner_ip"
json_dump > "$STATUS_PATH/$PPID.json"
)
if [ -n "$REFRESH" ]; then
json_init
json_load "$REFRESH_PARAM"
json_add_int port "$port"
$REFRESH "$(json_dump)"
fi
if [ -n "$NOTIFY" ]; then
_text="$(jsonfilter -qs "$NOTIFY_PARAM" -e '@["text"]')"
[ -z "$_text" ] && _text="NATMap: ${COMMENT:+$COMMENT: }[${protocol^^}] $inner_ip:$inner_port -> $ip:$port" \
|| _text="$(echo "$_text" | sed " \
s|<comment>|$COMMENT|g; \
s|<protocol>|$protocol|g; \
s|<inner_ip>|$inner_ip|g; \
s|<inner_port>|$inner_port|g; \
s|<ip>|$ip|g; \
s|<port>|$port|g")"
json_init
json_load "$NOTIFY_PARAM"
json_add_string comment "$COMMENT"
json_add_string text "$_text"
fallloop 5m 4 $NOTIFY "$(json_dump)" &
fi
if [ -n "$DDNS" ]; then
_hostype="$(jsonfilter -qs "$DDNS_PARAM" -e '@["hostype"]')"
_svcparams="$(jsonfilter -qs "$DDNS_PARAM" -e '@["https_svcparams"]')"
_svcparams="$(echo "$_svcparams" | sed -E "s,\s*(port=\d*|$), port=${port},")" # port
[ "$_hostype" = A ] && _svcparams="$(echo "$_svcparams" | sed -E "s|\b(ipv4hint=)\S*|\1${ip}|")" # ipv4hint
[ "$_hostype" = AAAA ] && _svcparams="$(echo "$_svcparams" | sed -E "s|\b(ipv6hint=)\S*|\1${ip}|")" # ipv6hint
json_init
json_load "$DDNS_PARAM"
json_add_string https_svcparams "$_svcparams"
json_add_string ip "$ip"
json_add_int port "$port"
fallloop 5m 4 $DDNS "$(json_dump)" &
fi
[ -n "${CUSTOM_SCRIPT}" ] && {
export -n CUSTOM_SCRIPT
exec "${CUSTOM_SCRIPT}" "$ip" "$port" "$ip4p" "$inner_port" "$protocol" "$inner_ip" "$SECTIONID" "$COMMENT" "$@"
}
+100
View File
@@ -0,0 +1,100 @@
config global
option enable '0'
option def_tcp_stun 'stunserver.stunprotocol.org'
option def_udp_stun 'stunserver.stunprotocol.org'
option def_http_server 'example.com'
option def_tcp_interval '30'
option def_udp_interval '15'
option def_udp_stun_cycle '3'
config natmap
option enable '0'
option interval ''
option stun_server ''
option http_server 'www.baidu.com'
option udp_mode '0'
option family ''
option bind_ifname ''
option port '8080'
option forward '0'
option forward_mode 'via'
option natloopback '1'
option forward_target ''
option forward_port ''
option custom_script ''
option log_stdout '1'
option log_stderr '1'
config natmap
option enable '1'
option comment 'MC Server'
option family 'ipv4'
option udp_mode '0'
option port '25565'
option forward '1'
option forward_mode 'dnat'
option natloopback '1'
option forward_target '192.168.1.123'
option forward_port '25565'
option ddns_enable '1'
option ddns_script '/etc/natmap/ddns/Cloudflare'
list ddns_tokens 'TOKEN=<api_token>'
list ddns_tokens 'ZONE_ID=<zone_id>'
option ddns_a 'mc.example.com'
option ddns_srv 'mc.example.com'
option ddns_srv_serv 'minecraft'
option ddns_srv_proto 'tcp'
config natmap
option enable '1'
option comment 'qBittorrent'
option udp_mode '0'
option family 'ipv4'
option port '114514'
option forward '1'
option forward_mode 'dnat'
option natloopback '0'
option forward_target '192.168.1.123'
option forward_port '0'
option refresh '1'
option clt_script '/etc/natmap/client/qBittorrent'
option clt_scheme 'http'
option clt_web_port '8080'
option clt_username 'admin'
option clt_password 'wrt6V5xAB6_t6Cr6Vm7554'
option notify_enable '1'
option notify_script '/etc/natmap/notify/ntfy'
list notify_tokens 'TOPIC=<topic>'
list notify_tokens 'TITLE=<title>'
config natmap
option enable '1'
option comment 'librespeed-go'
option udp_mode '0'
option family 'ipv4'
option bind_ifname 'eth1'
option port '8989'
option forward '1'
option forward_mode 'dnat'
option forward_target '127.0.0.1'
option forward_port '8989'
option ddns_enable '1'
option ddns_script '/etc/natmap/ddns/Cloudflare'
list ddns_tokens 'TOKEN=<api_token>'
list ddns_tokens 'ZONE_ID=<zone_id>'
option ddns_enable '1'
option ddns_a 'web.example.com'
option ddns_https 'web.example.com'
option ddns_https_target '.'
option ddns_https_svcparams 'alpn="h2,http/1.1"'
config natmap
option enable '0'
option comment 'DNSmasq need trun off '"'"'Local_service_only'"'"''
option udp_mode '1'
option family 'ipv4'
option port '5321'
option forward '1'
option forward_mode 'dnat'
option forward_target '0.0.0.0'
option forward_port '53'
+32
View File
@@ -0,0 +1,32 @@
#!/bin/sh
# Copyright (C) 2023 muink https://github.com/muink
CONF='/etc/config/natmap'
NAME='natmap'
NATMAPSECTION='natmap'
. /lib/functions/network.sh
# uci options migration
if [ -z "$(grep '^config global$' "$CONF")" ]; then
sed -i '1i\\config global' "$CONF"
## notify_script --> custom_script
sed -i 's|\boption notify_script|option custom_script|g' "$CONF"
## interface --> bind_ifname
for k in $(uci -q show $NAME|sed -En "s|^$NAME\.@$NATMAPSECTION\[(\d+)\]\.interface='(.*)'$|'\1:\2'|gp"); do
i=${k%%:*}; i=${i#\'}
iface="${k#*:}"; iface="${iface%\'}"
network_get_device ifname "$iface"
[ -z "$ifname" ] && network_get_physdev ifname "$iface"
[ -z "$ifname" ] && continue
uci set $NAME.@$NATMAPSECTION[$i].bind_ifname="$ifname"
uci delete $NAME.@$NATMAPSECTION[$i].interface
uci commit $NAME
done
else
## def_interval --> def_tcp_interval/def_udp_interval
sed -Ei 's|def_interval (.*)|def_tcp_interval \1\n\toption def_udp_interval \1|' "$CONF"
fi
# gen natmap-curl
ln -sf "$(command -v curl)" /usr/bin/natmap-curl
exit 0
+486
View File
@@ -0,0 +1,486 @@
#!/bin/bash /etc/rc.common
. "${IPKG_INSTROOT}/lib/functions/network.sh"
START=97
STOP=90
USE_PROCD=1
# natmap
[ -x "$(command -v nft)" ] && FW='fw4' || FW='fw3'
NAME=natmap
GLOBALSECTION=global
NATMAPSECTION=natmap
PROG=/usr/bin/$NAME
STATUS_PATH=/var/run/natmap
config_load "$NAME"
# define global var: DEF_WAN DEF_WAN6 NIC_* NIC6_*
define_nic() {
local dev sub addr
# get all active NICs
for dev in $(ls /sys/class/net/); do
#ipv4
sub=$(ip -o -4 addr|sed -En "s|.*${dev}\s+inet\s+([0-9\./]+).*|\1|gp")
eval "NIC_${dev//[[:punct:]]/_}=\"\$sub\""
#ipv6
sub=$(ip -o -6 addr|sed -En "s|.*${dev}\s+inet6\s+([A-Za-z0-9\./:]+).*|\1|gp")
# ref: https://github.com/openwrt/openwrt/blob/main/package/base-files/files/lib/functions/network.sh#L53 #network_get_subnet6()
for _ in $sub; do
for addr in $sub; do
case "$addr" in fe[8ab]?:*|f[cd]??:*)
continue
esac
sub=$addr; break
done
# Attempt to return first non-fe80::/10 range
for addr in $sub; do
case "$addr" in fe[8ab]?:*)
continue
esac
sub=$addr; break
done
# Return first item
for addr in $sub; do
sub=$addr; break
done
done
eval "NIC6_${dev//[[:punct:]]/_}=\"\$sub\""
done
# get default gateway 0.0.0.0/::
network_find_wan DEF_WAN true
network_find_wan6 DEF_WAN6 true
return 0
}
define_nic
load_interfaces() {
local bind_ifname enable
config_get bind_ifname "$1" bind_ifname
config_get_bool enable "$1" enable 0
[ "$enable" = 1 ] && interfaces=" $(uci -q show network|grep "device='$bind_ifname'"|cut -f2 -d'.') $interfaces"
}
# define global var: GLOBAL_*
define_global() {
[ "$2" == "0" ] || { >&2 echo "$(basename $0): section $1 validation failed"; return 1; }
local error=0
local v ucivv="enable def_tcp_stun def_udp_stun def_http_server def_fwmark_value def_tcp_interval def_udp_interval def_udp_stun_cycle"
for v in $ucivv; do
[ -z "$(config_get $1 $v)" ] && grep -qEv "^(def_fwmark_value)$" <<< "$v" && {
err_msg__empty $1 $v
let error++
}
eval "GLOBAL_$v=\$$v"
done
[ "$error" -gt 0 ] && return 1 || return 0
}
validate_section_global() {
uci_load_validate "$NAME" "$GLOBALSECTION" "$1" "$2" \
'enable:bool:0' \
'def_tcp_stun:string' \
'def_udp_stun:string' \
'def_http_server:string' \
'def_fwmark_value:string' \
'def_tcp_interval:and(uinteger, min(1)):30' \
'def_udp_interval:and(uinteger, min(1)):15' \
'def_udp_stun_cycle:uinteger:5' \
'test_port:and(port, min(1))'
}
validate_section_natmap() {
uci_load_validate "$NAME" "$NATMAPSECTION" "$1" "$2" \
'enable:bool:0' \
'interval:and(uinteger, min(1))' \
'stun_cycle:uinteger' \
'stun_server:string' \
'http_server:string' \
'fwmark_value:string' \
'comment:string' \
'udp_mode:bool:0' \
'family:or("ipv4", "ipv6"):ipv4' \
'bind_ifname:network' \
'port:or(port, portrange)' \
'port_pointer:bool:0' \
'forward:bool:0' \
'forward_mode:or("dnat", "via"):via' \
'natloopback:bool:1' \
'forward_congestion:string' \
'forward_timeout:and(uinteger, min(1))' \
'forward_target:or(hostname,ipaddr(1))' \
'forward_port:port' \
'refresh:bool:0' \
'clt_script:file' \
'clt_scheme:or("http", "https"):http' \
'clt_web_port:and(port, min(1))' \
'clt_username:string' \
'clt_password:string' \
'notify_enable:bool:0' \
'notify_script:file' \
'notify_tokens:list(string)' \
'notify_custom_domain:hostname' \
'notify_text:string' \
'ddns_enable:bool:0' \
'ddns_script:file' \
'ddns_tokens:list(string)' \
'ddns_a:hostname' \
'ddns_aaaa:hostname' \
'ddns_srv:hostname' \
'ddns_srv_serv:string' \
'ddns_srv_proto:string:tcp' \
'ddns_srv_target:hostname' \
'ddns_srv_priority:range(0, 65535):0' \
'ddns_srv_weight:range(0, 65535):65535' \
'ddns_https:hostname' \
'ddns_https_target:or(".", hostname):.' \
'ddns_https_svcparams:string:alpn="h2,http/1.1"' \
'ddns_https_priority:range(1, 65535):1' \
'custom_script:file' \
'log_stdout:bool:1' \
'log_stderr:bool:1'
}
# ip_match <hostname>
hostname_match() {
[ "$#" -ge 1 ] || return 1
local _hostname="$1"
echo "$_hostname" | grep -E "^[[:alnum:]][-[:alnum:]]{0,62}(\.[[:alnum:]][-[:alnum:]]{0,62})*\.?$"
}
# ip_match <family> <ipaddr>
ip_match() {
[ "$#" -ge 2 ] || return 1
local _family="$1"
local _ip="$2"
case "$_family" in
ipv4)
echo "$_ip" | grep -E "^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$"
;;
ipv6)
echo "$_ip" | grep -E "^(([[:xdigit:]]{1,4}:){7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,7}:|([[:xdigit:]]{1,4}:){1,6}:[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,5}(:[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}:){1,4}(:[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}:){1,3}(:[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}:){1,2}(:[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}:(:[[:xdigit:]]{1,4}){1,6}|:((:[[:xdigit:]]{1,4}){1,7}|:)|\
fe80:(:[[:xdigit:]]{0,4}){0,4}%\w+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)|([[:xdigit:]]{1,4}:){1,4}:((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?))$"
;;
esac
}
# fwmark_match <fwmark>
fwmark_match() {
echo "$1" | grep -E '^(0|0x[[:xdigit:]]+|[1-9][0-9]*|0[0-7]+)$'
}
natmap_instance() {
procd_open_instance "$1"
procd_set_param command "$PROG" \
${interval:+-k "$interval"} \
${stun_cycle:+-c "$stun_cycle"} \
${stun_server:+-s "$stun_server"} \
${http_server:+-h "$http_server"} \
${fwmark_value:+-f "$fwmark_value"} \
${port:+-b "$([ "$port_pointer" = 1 ] && echo ${port/-/\~} || echo $port)"} \
[ "${family}" = ipv4 ] && procd_append_param command -4
[ "${family}" = ipv6 ] && procd_append_param command -6
[ "${udp_mode}" = 1 ] && procd_append_param command -u
procd_set_param netdev "br-lan"
[ -n "${bind_ifname}" ] && {
procd_append_param command -i "$bind_ifname"
procd_append_param netdev "$bind_ifname"
} || {
local ifname
network_get_device ifname "$DEF_WAN" && procd_append_param netdev "$ifname"
network_get_device ifname "$DEF_WAN6" && procd_append_param netdev "$ifname"
}
if [ "$forward" = 1 -a "$forward_mode" = "via" -a -n "${forward_target}" ]; then
procd_append_param command ${forward_congestion:+-C "$forward_congestion"} ${forward_timeout:+-T "$forward_timeout"} -t "$forward_target" -p "$forward_port"
fi
procd_set_param env "SECTIONID=$1"
procd_append_param env "COMMENT=$comment"
if [ "$forward" = 1 ]; then
# Rewrite the dest_port(forward port) using a public port
[ "$forward_port" = 0 -a "$forward_mode" = "dnat" ] && procd_append_param env "RWFW=1"
if [ "$refresh" = 1 ]; then
procd_append_param env "REFRESH=$clt_script"
json_init
json_add_string scheme "$clt_scheme"
json_add_int web_port "$clt_web_port"
json_add_string username "$clt_username"
json_add_string password "$clt_password"
json_add_string host "$forward_target"
procd_append_param env "REFRESH_PARAM=$(json_dump)"
fi
fi
if [ "$notify_enable" = 1 ]; then
procd_append_param env "NOTIFY=$notify_script"
json_init
json_add_string custom_domain "$notify_custom_domain"
json_add_string text "$notify_text"
json_add_string tokens "$notify_tokens"
procd_append_param env "NOTIFY_PARAM=$(json_dump)"
fi
if [ "$ddns_enable" = 1 ]; then
procd_append_param env "DDNS=$ddns_script"
json_init
json_add_string tokens "$ddns_tokens"
[ "$family" = ipv4 ] && json_add_string hostype "A" && json_add_string host "$ddns_a"
[ "$family" = ipv6 ] && json_add_string hostype "AAAA" && json_add_string host "$ddns_aaaa"
[ -n "$ddns_srv" ] && {
json_add_string srv "$ddns_srv"
json_add_string srv_serv "$ddns_srv_serv"
json_add_string srv_proto "$ddns_srv_proto"
json_add_string srv_target "$ddns_srv_target"
json_add_int srv_priority "$ddns_srv_priority"
json_add_int srv_weight "$ddns_srv_weight"
}
[ -n "$ddns_https" ] && {
json_add_string https "$ddns_https"
json_add_string https_target "$ddns_https_target"
json_add_string https_svcparams "$ddns_https_svcparams"
json_add_int https_priority "$ddns_https_priority"
}
procd_append_param env "DDNS_PARAM=$(json_dump)"
fi
[ -n "${custom_script}" ] && procd_append_param env "CUSTOM_SCRIPT=${custom_script}"
procd_append_param command -e /usr/lib/natmap/update.sh
procd_set_param respawn
procd_set_param stdout "$log_stdout"
procd_set_param stderr "$log_stderr"
procd_open_data
# configure firewall
json_add_array firewall
if [ "$forward" = 1 -a "$forward_mode" = "dnat" ]; then
json_add_object ''
json_add_string type redirect
json_add_string target DNAT
json_add_string name "$1"
json_add_string family "$family"
json_add_string proto "$proto"
json_add_string src "$($FW -q device $bind_ifname)"
#json_add_string src_dip "$bind_ip" # fix for #11 (The external address of the firewall will not be updated), fw4 cannot add `iifname` rule in `<action>_<fw zone>` chain
json_add_string src_dport "$port"
#json_add_string dest '' # zlan or zwan
json_add_string dest_ip "$forward_target"
[ -n "$PUBPORT" ] \
&& json_add_string dest_port "$PUBPORT" && unset PUBPORT \
|| json_add_string dest_port "$forward_port"
json_add_boolean reflection $natloopback
json_close_object
fi
if [ "$forward" = 1 -a "$forward_mode" = "via" -o "$forward" = 0 ]; then
json_add_object ''
json_add_string type rule
json_add_string target ACCEPT
json_add_string name "$1"
json_add_string family "$family"
json_add_string proto "$proto"
json_add_string direction in
json_add_string src "$($FW -q device $bind_ifname)"
#json_add_string dest '' # '' = input
#json_add_string dest_ip "$bind_ip" # fix for #11 (The external address of the firewall will not be updated), fw4 cannot add `iifname` rule in `<action>_<fw zone>` chain
json_add_string dest_port "$port"
json_close_object
fi
json_close_array
procd_close_data
procd_close_instance
}
clear_status_files() {
local f sid="$1"
mkdir -p "${STATUS_PATH}" 2>/dev/null
pushd "${STATUS_PATH}" >/dev/null
if [ -n "$sid" ]; then
for f in *.json; do
[ "$(jsonfilter -q -i $f -e '@.sid')" = "$sid" ] || continue
rm -f $f; break
done
else
find . -type f -print0 | xargs -0 rm -f --
fi
popd >/dev/null
}
# err_msg__empty <section> <option>
err_msg__empty() {
>&2 echo "$(basename $0): section $1 option $2 cannot be empty"
}
launcher() {
[ "$2" = 0 ] || { >&2 echo "$(basename $0): section $1 validation failed"; return 1; }
[ "$enable" = 0 ] && return 0
# global options
if [ "$udp_mode" = 1 ]; then
local interval=${interval:-$GLOBAL_def_udp_interval} \
stun_cycle=${stun_cycle:-$GLOBAL_def_udp_stun_cycle} \
stun_server=${stun_server:-$GLOBAL_def_udp_stun} \
http_server='' \
;
else
local interval=${interval:-$GLOBAL_def_tcp_interval} \
stun_cycle='' \
stun_server=${stun_server:-$GLOBAL_def_tcp_stun} \
http_server=${http_server:-$GLOBAL_def_http_server} \
;
fi
local fwmark_value=${fwmark_value:-$GLOBAL_def_fwmark_value}
# natmap options
local error=0
local proto ifname bind_ip lan_addr
[ "$udp_mode" = 1 ] && proto=udp || proto=tcp
case "$family" in
ipv4) network_get_device ifname "$DEF_WAN";;
ipv6) network_get_device ifname "$DEF_WAN6";;
esac
local bind_ifname=${bind_ifname:-$ifname}
[ -z "$bind_ifname" ] && >&2 echo "$(basename $0): section $1 option bind_ifname parsing failed, there may be no $family network connection" && let error++
case "$family" in
ipv4)
eval "bind_ip=\"\${NIC_${bind_ifname//[[:punct:]]/_}%/*}\""
lan_addr="${NIC_br_lan%/*}"
;;
ipv6)
eval "bind_ip=\"\${NIC6_${bind_ifname//[[:punct:]]/_}%/*}\""
lan_addr="${NIC6_br_lan%/*}"
;;
esac
[ -z "$bind_ip" ] && >&2 echo "$(basename $0): section $1 option bind_ip parsing failed, there may be no $family network connection" && let error++
[ -z "$port" ] && err_msg__empty $1 port && let error++
grep -qE '^([1-9]\d*)(-([1-9]\d*))?$' <<< "$port" || { >&2 echo "$(basename $0): section $1 option port '$port' is invalid"; let error++; }
[ -z "$fwmark_value" -o -n "$(fwmark_match "$fwmark_value")" ] || { >&2 echo "$(basename $0): section $1 option fwmark_value '$fwmark_value' is invalid"; let error++; }
## forward
if [ "$forward" = 1 ]; then
[ "$forward_mode" = "dnat" -a "$family" = "ipv6" ] && >&2 echo "$(basename $0): section $1 option forward_mode 'dnat' not support under IPv6" && let error++
[ "$forward_mode" != "dnat" ] && natloopback=0
if [ -n "$forward_target" ]; then
if [ -n "$(hostname_match "$forward_target")" -a -z "$(ip_match ipv4 "$forward_target")" ]; then
# hostname
[ "$forward_mode" = "dnat" ] && >&2 echo "$(basename $0): section $1 option forward_target '$forward_target', hostname not support under DNAT mode" && let error++
else
# ipaddr(1)
[ -n "$(grep -E "^127(\.\d+){3}" <<< $forward_target)" -o "$forward_target" = "::1" ] && forward_target="$lan_addr"
[ -n "$(grep -E "^0(\.\d+){3}" <<< $forward_target)" -o "$forward_target" = "::" ] && forward_target="$bind_ip"
if [ -n "$forward_target" ]; then
[ -z "$(ip_match "$family" "$forward_target")" ] && >&2 echo "$(basename $0): section $1 option forward_target '$forward_target' not a $family address" && let error++
else
>&2 echo "$(basename $0): section $1 option forward_target parsing failed, there may be no $family network connection"; let error++
fi
fi
else
err_msg__empty $1 forward_target; let error++
fi
[ -z "$forward_port" ] && err_msg__empty $1 forward_port && let error++
elif [ "$forward" = 0 ]; then
natloopback=0
unset forward_target forward_port
fi
## refresh
if [ "$refresh" = 1 ]; then
[ -x "$clt_script" ] || { >&2 echo "$(basename $0): section $1 option clt_script '$clt_script' is empty or non-executable"; let error++; }
[ -z "$clt_web_port" ] && err_msg__empty $1 clt_web_port && let error++
fi
## notify
if [ "$notify_enable" = 1 ]; then
[ -x "$notify_script" ] || { >&2 echo "$(basename $0): section $1 option notify_script '$notify_script' is empty or non-executable"; let error++; }
fi
## ddns
if [ "$ddns_enable" = 1 ]; then
[ -x "$ddns_script" ] || { >&2 echo "$(basename $0): section $1 option ddns_script '$ddns_script' is empty or non-executable"; let error++; }
if [ -n "$ddns_srv" ]; then
[ -z "$ddns_srv_serv" ] && err_msg__empty $1 ddns_srv_serv && let error++
local ddns_srv_target=${ddns_srv_target:-$ddns_srv}
fi
fi
# review
[ -n "$NATMAP_DEBUG" ] && {
local v ucivv="enable interval stun_cycle stun_server http_server fwmark_value comment udp_mode proto family bind_ifname ifname bind_ip lan_addr port port_pointer forward forward_mode natloopback forward_congestion forward_timeout forward_target forward_port refresh clt_script clt_scheme clt_web_port clt_username clt_password notify_enable notify_script notify_tokens notify_custom_domain notify_text ddns_enable ddns_script ddns_tokens ddns_a ddns_aaaa ddns_srv ddns_srv_serv ddns_srv_proto ddns_srv_target ddns_srv_priority ddns_srv_weight ddns_https ddns_https_target ddns_https_svcparams ddns_https_priority custom_script"
for v in $ucivv; do eval "echo $1 $v=\'\$$v\'"; done # ash not support ${!v}
}
[ "$error" -gt 0 ] && return 1
natmap_instance "$1"
}
service_triggers() {
procd_add_reload_trigger "$NAME" 'network'
local interfaces
config_foreach load_interfaces $NATMAPSECTION
[ -n "$interfaces" ] && {
for n in $interfaces; do
procd_add_reload_interface_trigger $n
done
} || {
for n in $DEF_WAN $DEF_WAN6; do
procd_add_reload_interface_trigger $n
done
}
interfaces=$(uci show network|grep "device='br-lan'"|cut -f2 -d'.')
[ -n "$interfaces" ] && {
for n in $interfaces; do
procd_add_reload_interface_trigger $n
done
}
procd_add_validation validate_section_natmap
}
start_service() {
local sid="$1"
config_foreach validate_section_global "$GLOBALSECTION" define_global || return $?
[ "${GLOBAL_enable:=0}" == "0" ] && return 1
if [ -n "$sid" ]; then
clear_status_files "$sid"
validate_section_natmap "$sid" launcher
else
clear_status_files
config_foreach validate_section_natmap "$NATMAPSECTION" launcher
fi
}
stop_service() {
local sid="$1"
clear_status_files "$sid"
}
service_stopped() {
sleep 1s # Wait for procd_kill complete
ps | grep natmap | awk '{print $1}' | xargs kill -9
}
reload_service() {
stop "$@"
start "$@"
}
service_started() { procd_set_config_changed firewall; }
service_stopped() { procd_set_config_changed firewall; }
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
# Copyright (C) 2023 muink https://github.com/muink
#
# Port update notify script
#
# depends
. /usr/lib/natmap/common.sh
start() {
local retry='--connect-timeout 3 --retry 5'
$CURL $retry -L -o /dev/null -X POST \
-H "Access-Token: ${TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"type":"note","body":"'"${text}"'","title":"'"${TITLE}"'"}' \
--url "https://${custom_domain:-api.pushbullet.com}/v2/pushes"
}
# All external parameters required
ALL_PARAMS="custom_domain text tokens"
eval "$(JSON_EXPORT "$1")"; shift
# All external tokens required
INIT_GLOBAL_VAR TOKEN TITLE
eval "$tokens"
start "$@"
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
# Copyright (C) 2023 muink https://github.com/muink
#
# Port update notify script
#
# depends
. /usr/lib/natmap/common.sh
start() {
local retry='--connect-timeout 3 --retry 5'
$CURL $retry -L -o /dev/null -X POST \
-H 'Content-Type: application/json' \
-d '{"token":"'"${TOKEN}"'","user":"'"${TO_ID}"'","device":"'"${DEVICE}"'","message":"'"${text}"'","title":"'"${TITLE}"'","html":"'"${HTML}"'"}' \
--url https://${custom_domain:-api.pushover.net}/1/messages.json
}
# All external parameters required
ALL_PARAMS="custom_domain text tokens"
eval "$(JSON_EXPORT "$1")"; shift
# All external tokens required
INIT_GLOBAL_VAR TOKEN TO_ID DEVICE TITLE HTML
eval "$tokens"
start "$@"
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
# Copyright (C) 2023-2025 muink https://github.com/muink
#
# Port update notify script
#
# depends
. /usr/lib/natmap/common.sh
start() {
local retry='--connect-timeout 3 --retry 5'
# 如果 CUESTOM_PROXY 不为空,则添加 -x 参数
local proxy_param=${CUESTOM_PROXY:+-x $CUESTOM_PROXY}
$CURL $retry -L -o /dev/null -X POST $proxy_param \
-H 'Content-Type: application/json' \
-d '{"chat_id":"'"${CHAT_ID}"'","text":"'"${text}"'","parse_mode":"HTML","disable_notification":"false"}' \
--url "https://${custom_domain:-api.telegram.org}/bot${TOKEN}/sendMessage"
}
# All external parameters required
ALL_PARAMS="custom_domain text tokens"
eval "$(JSON_EXPORT "$1")"; shift
# All external tokens required
INIT_GLOBAL_VAR TOKEN CHAT_ID CUESTOM_PROXY
eval "$tokens"
start "$@"
+55
View File
@@ -0,0 +1,55 @@
#!/bin/bash
# Copyright (C) 2023 muink https://github.com/muink
#
# Port update notify script
#
# depends
. /usr/lib/natmap/common.sh
. /usr/share/libubox/jshn.sh
# http_request <data>
http_request() {
local data="$1"
$CURL $retry -L -o /dev/null -X POST \
-H 'Content-Type: application/json' \
-d "$data" \
--url https://${custom_domain:-ntfy.sh}/
}
start() {
local retry='--connect-timeout 3 --retry 5'
json_init
json_add_string topic "${TOPIC}"
json_add_string message "${text}"
json_add_string title "${TITLE}"
# Add priority and tag option
json_add_int priority "${PRIORITY:-3}"
json_add_array tags
for _t in ${TAGS//,/ }; do
json_add_string "" "$_t"
done
json_close_array
[ -n "${WACTION}" ] && {
json_add_array actions
json_add_object
json_add_string action "view"
json_add_string label "Open page"
json_add_string url "http${HTTPS:+s}://${ip}:${port}"
json_add_boolean clear 0
json_close_object
json_close_array
}
http_request "$(json_dump)"
}
# All external parameters required
ALL_PARAMS="custom_domain text tokens"
eval "$(JSON_EXPORT "$1")"; shift
# All external tokens required
INIT_GLOBAL_VAR TOPIC TITLE WACTION HTTPS PRIORITY TAGS
eval "$tokens"
start "$@"
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
"$1" 2>&1 | grep "$2"