--- /dev/null
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=natmap
+PKG_VERSION:=20221203
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/heiher/natmap/releases/download/$(PKG_VERSION)
+PKG_HASH:=c7aa0bb1f3e057bf1fa987ad6166ba7c2e80510a89593e04f4fe0f36f1873338
+
+PKG_MAINTAINER:=Richard Yu <yurichard3839@gmail.com>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=License
+
+PKG_USE_MIPS16:=0
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/natmap
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=TCP/UDP port mapping tool for full cone NAT
+ URL:=https://github.com/heiher/natmap
+endef
+
+MAKE_FLAGS += REV_ID="$(PKG_VERSION)"
+
+define Package/natmap/install
+ $(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_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
+endef
+
+$(eval $(call BuildPackage,natmap))
--- /dev/null
+#!/bin/sh
+
+. /usr/share/libubox/jshn.sh
+
+(
+ json_init
+ json_add_string ip "$1"
+ json_add_int port "$2"
+ json_add_int inner_port "$4"
+ json_add_string protocol "$5"
+ json_dump > /var/run/natmap/$PPID.json
+)
+
+[ -n "${NOTIFY_SCRIPT}" ] && {
+ export -n NOTIFY_SCRIPT
+ exec "${NOTIFY_SCRIPT}" "$@"
+}
--- /dev/null
+#!/bin/sh /etc/rc.common
+
+START=99
+USE_PROCD=1
+
+NAME=natmap
+PROG=/usr/bin/$NAME
+
+STATUS_PATH=/var/run/natmap
+
+load_interfaces() {
+ config_get interface "$1" interface
+ config_get enable "$1" enable 1
+
+ [ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
+}
+
+validate_section_natmap() {
+ uci_load_validate "${NAME}" natmap "$1" "$2" \
+ 'enable:bool:1' \
+ 'ipv4:bool:0' \
+ 'ipv6:bool:0' \
+ 'udp_mode:bool:0' \
+ 'interface:string' \
+ 'interval:uinteger' \
+ 'stun_server:host' \
+ 'http_server:host' \
+ 'port:port' \
+ 'forward_target:host' \
+ 'notify_script:file'
+}
+
+natmap_instance() {
+ [ "$2" = 0 ] || {
+ echo "validation failed"
+ return 1
+ }
+
+ [ "${enable}" = 0 ] && return 1
+
+ procd_open_instance "$1"
+ procd_set_param command "$PROG" \
+ ${interval:+-k $interval} \
+ ${stun_server:+-s "$stun_server"} \
+ ${http_server:+-h "$http_server"}
+
+ [ "${ipv4}" = 1 ] && procd_append_param command -4
+ [ "${ipv6}" = 1 ] && procd_append_param command -6
+ [ "${udp_mode}" = 1 ] && procd_append_param command -u
+
+ [ -n "$interface" ] && {
+ local ifname
+
+ network_get_device ifname "$interface" || ifname="$interface"
+ procd_append_param command -i "$ifname"
+ procd_append_param netdev "$ifname"
+ }
+
+ if [ -n "$forward_target" ]; then
+ procd_append_param command -t "$forward_target" -p $port
+ else
+ procd_append_param command -b $port
+ fi
+
+ [ -n "${notify_script}" ] && procd_set_param env "NOTIFY_SCRIPT=${notify_script}"
+ procd_append_param command -e /usr/lib/natmap/update.sh
+
+ procd_set_param respawn
+ procd_set_param stdout 1
+ procd_set_param stderr 1
+
+ procd_close_instance
+}
+
+clear_status_files() {
+ find "${STATUS_PATH}" -type f -print0 | xargs -0 rm -f --
+}
+
+service_triggers() {
+ local interfaces
+
+ procd_add_reload_trigger "${NAME}"
+
+ config_load "${NAME}"
+ config_foreach load_interfaces natmap
+
+ [ -n "${interfaces}" ] && {
+ for n in $interfaces ; do
+ procd_add_reload_interface_trigger $n
+ done
+ }
+
+ procd_add_validation validate_section_natmap
+}
+
+start_service() {
+ . /lib/functions/network.sh
+
+ mkdir -p "${STATUS_PATH}"
+ clear_status_files
+
+ config_load "${NAME}"
+ config_foreach validate_section_natmap natmap natmap_instance
+}
+
+reload_service() {
+ stop
+ start
+}
+
+service_stopped() {
+ clear_status_files
+}