mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 00:15:13 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
Executable
+13
@@ -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
|
||||
@@ -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.
|
||||
@@ -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))
|
||||
@@ -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
|
||||
@@ -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 "$@"
|
||||
@@ -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 "$@"
|
||||
@@ -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 "$@"
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 "$@"
|
||||
@@ -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" "$@"
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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; }
|
||||
@@ -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 "$@"
|
||||
@@ -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 "$@"
|
||||
@@ -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 "$@"
|
||||
@@ -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 "$@"
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
"$1" 2>&1 | grep "$2"
|
||||
Reference in new issue
Block a user