From f095b225ddfa034aaec12831a8ad6617aa2e2788 Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Tue, 7 Apr 2020 21:59:03 +0800 Subject: [PATCH 01/27] bcm27xx: rpi4: enable wifi in first boot (#4220) --- .../bcm27xx/base-files/lib/preinit/79_move_config | 2 +- .../base-files/lib/preinit/82_set_rpi_info | 15 +++++++++++++++ target/linux/bcm27xx/bcm2710/config-4.19 | 1 + target/linux/bcm27xx/bcm2711/config-4.19 | 3 ++- 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 target/linux/bcm27xx/base-files/lib/preinit/82_set_rpi_info diff --git a/target/linux/bcm27xx/base-files/lib/preinit/79_move_config b/target/linux/bcm27xx/base-files/lib/preinit/79_move_config index b8738b645e..a2a2efecb0 100644 --- a/target/linux/bcm27xx/base-files/lib/preinit/79_move_config +++ b/target/linux/bcm27xx/base-files/lib/preinit/79_move_config @@ -13,7 +13,7 @@ move_config() { insmod vfat mkdir -p /boot mount -t vfat -o rw,noatime $BOOTPART /boot - [ -f "/boot/$BACKUP_FILE" ] && mv -f "/boot/$BACKUP_FILE" / + [ -f /boot/sysupgrade.tgz ] && mv -f /boot/sysupgrade.tgz / fi } diff --git a/target/linux/bcm27xx/base-files/lib/preinit/82_set_rpi_info b/target/linux/bcm27xx/base-files/lib/preinit/82_set_rpi_info new file mode 100644 index 0000000000..ad83d90b4c --- /dev/null +++ b/target/linux/bcm27xx/base-files/lib/preinit/82_set_rpi_info @@ -0,0 +1,15 @@ +#!/bin/sh + +set_rpi_info() { + case "$(board_name)" in + raspberrypi,4-model-b) + sed -i 's/VHT80/VHT40/g' /lib/wifi/mac80211.sh + sed -i 's|pcdata(boardinfo.system or "?")|pcdata(boardinfo.system or "ARMv8 Processor")|g' /usr/lib/lua/luci/view/admin_status/index.htm + ;; + *) + sed -i 's|pcdata(boardinfo.system or "?")|pcdata(boardinfo.system or "ARMv8 Processor")|g' /usr/lib/lua/luci/view/admin_status/index.htm + ;; + esac +} + +boot_hook_add preinit_main set_rpi_info diff --git a/target/linux/bcm27xx/bcm2710/config-4.19 b/target/linux/bcm27xx/bcm2710/config-4.19 index 99c9859652..80cd167283 100644 --- a/target/linux/bcm27xx/bcm2710/config-4.19 +++ b/target/linux/bcm27xx/bcm2710/config-4.19 @@ -542,6 +542,7 @@ CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 CONFIG_THERMAL_GOV_STEP_WISE=y CONFIG_THERMAL_OF=y +CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THREAD_INFO_IN_TASK=y CONFIG_TICK_CPU_ACCOUNTING=y CONFIG_TIMER_OF=y diff --git a/target/linux/bcm27xx/bcm2711/config-4.19 b/target/linux/bcm27xx/bcm2711/config-4.19 index 77f3f45543..6aa897a2e1 100644 --- a/target/linux/bcm27xx/bcm2711/config-4.19 +++ b/target/linux/bcm27xx/bcm2711/config-4.19 @@ -510,6 +510,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_GPIO=y CONFIG_RESET_CONTROLLER=y CONFIG_RFS_ACCEL=y +# CONFIG_RPI_AXIPERF is not set # CONFIG_RPIVID_MEM is not set CONFIG_RPS=y CONFIG_RWSEM_SPIN_ON_OWNER=y @@ -551,6 +552,7 @@ CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 CONFIG_THERMAL_GOV_STEP_WISE=y CONFIG_THERMAL_OF=y +CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THREAD_INFO_IN_TASK=y CONFIG_TICK_CPU_ACCOUNTING=y CONFIG_TIMER_OF=y @@ -583,4 +585,3 @@ CONFIG_XPS=y CONFIG_XZ_DEC_ARM=y CONFIG_XZ_DEC_BCJ=y CONFIG_ZONE_DMA32=y -# CONFIG_RPI_AXIPERF is not set From a1b538a9f5d8c96aa9ad66086455f9963e3e8e7d Mon Sep 17 00:00:00 2001 From: lean Date: Tue, 7 Apr 2020 22:44:32 +0800 Subject: [PATCH 02/27] ipq40xx: switch to ath10k-ct --- package/lean/luci-app-cifs-mount/Makefile | 2 +- package/lean/luci-app-cifs-mount/root/etc/init.d/cifs | 2 +- target/linux/ipq40xx/Makefile | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package/lean/luci-app-cifs-mount/Makefile b/package/lean/luci-app-cifs-mount/Makefile index 448ec65027..bb63c91dc5 100644 --- a/package/lean/luci-app-cifs-mount/Makefile +++ b/package/lean/luci-app-cifs-mount/Makefile @@ -11,7 +11,7 @@ LUCI_DEPENDS:=+kmod-fs-cifs +kmod-nls-utf8 LUCI_PKGARCH:=all PKG_NAME:=luci-app-cifs-mount PKG_VERSION:=1 -PKG_RELEASE:=6 +PKG_RELEASE:=7 include $(TOPDIR)/feeds/luci/luci.mk diff --git a/package/lean/luci-app-cifs-mount/root/etc/init.d/cifs b/package/lean/luci-app-cifs-mount/root/etc/init.d/cifs index 59ffc71d46..0089a767eb 100755 --- a/package/lean/luci-app-cifs-mount/root/etc/init.d/cifs +++ b/package/lean/luci-app-cifs-mount/root/etc/init.d/cifs @@ -1,6 +1,6 @@ #!/bin/sh /etc/rc.common -START=45 +START=97 ENABLED=0 WORKGROUPD=0 diff --git a/target/linux/ipq40xx/Makefile b/target/linux/ipq40xx/Makefile index 8157764fdb..c75f3d518b 100644 --- a/target/linux/ipq40xx/Makefile +++ b/target/linux/ipq40xx/Makefile @@ -9,7 +9,7 @@ CPU_SUBTYPE:=neon-vfpv4 MAINTAINER:=John Crispin # TODO: drop kmod-usb-dwc3-of-simple when migrating to 4.19 -KERNEL_PATCHVER:=4.14 +KERNEL_PATCHVER:=4.19 KERNELNAME:=zImage Image dtbs @@ -17,8 +17,8 @@ include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += \ kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom \ kmod-leds-gpio kmod-gpio-button-hotplug swconfig \ - kmod-ath10k wpad-openssl \ - kmod-usb3 kmod-usb-dwc3 ath10k-firmware-qca4019 \ + kmod-ath10k-ct wpad-openssl \ + kmod-usb3 kmod-usb-dwc3 ath10k-firmware-qca4019-ct \ automount autosamba luci-app-ipsec-vpnd v2ray shadowsocks-libev-ss-redir shadowsocksr-libev-server luci-app-music-remote-center \ luci-app-unblockmusic luci-app-cpufreq luci-app-zerotier luci-app-xlnetacc ca-certificates kmod-fs-cifs kmod-nls-utf8 \ htop fdisk e2fsprogs From cef6bffa6f5cea7a469a92e254aa151e3c23c16f Mon Sep 17 00:00:00 2001 From: ricksuzade-maker <58425544+ricksuzade-maker@users.noreply.github.com> Date: Tue, 7 Apr 2020 23:41:56 +0800 Subject: [PATCH 03/27] Bump wireguard to 1.0.20200401 (#4217) The newest official stable release. --- package/network/services/wireguard/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/services/wireguard/Makefile b/package/network/services/wireguard/Makefile index bf4d6440ba..2d8a766023 100644 --- a/package/network/services/wireguard/Makefile +++ b/package/network/services/wireguard/Makefile @@ -11,12 +11,12 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=wireguard -PKG_VERSION:=0.0.20200318 -PKG_RELEASE:=2 +PKG_VERSION:=1.0.20200401 +PKG_RELEASE:=1 PKG_SOURCE:=wireguard-linux-compat-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://git.zx2c4.com/wireguard-linux-compat/snapshot/ -PKG_HASH:=fa74a8627f731754fbf4ea7d6ae8f571a2cfe8cd4b744a5f165065619cb836a1 +PKG_HASH:=7dfb4a8315e1d6ae406ff32d01c496175df558dd65968a19e5222d02c7cfb77a PKG_LICENSE:=GPL-2.0 PKG_LICENSE_FILES:=COPYING From 25b01424c06c55e5233bce0dc465f58e3c5cd8c7 Mon Sep 17 00:00:00 2001 From: lean Date: Wed, 8 Apr 2020 12:14:04 +0800 Subject: [PATCH 04/27] workflows: add dependenc host build --- .github/workflows/openwrt-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openwrt-ci.yml b/.github/workflows/openwrt-ci.yml index e2c4d4582e..814f682156 100644 --- a/.github/workflows/openwrt-ci.yml +++ b/.github/workflows/openwrt-ci.yml @@ -34,7 +34,7 @@ jobs: sudo rm -rf /usr/share/dotnet /etc/mysql /etc/php /etc/apt/sources.list.d sudo -E apt-get -y purge azure-cli ghc* zulu* hhvm llvm* firefox google* dotnet* powershell openjdk* mysql* php* sudo -E apt-get update - sudo -E apt-get -y install build-essential asciidoc binutils bzip2 gawk gettext git libncurses5-dev libz-dev patch python3 unzip zlib1g-dev lib32gcc1 libc6-dev-i386 subversion flex uglifyjs gcc-multilib g++-multilib p7zip p7zip-full msmtp libssl-dev texinfo libglib2.0-dev xmlto qemu-utils upx libelf-dev autoconf automake libtool autopoint device-tree-compiler + sudo -E apt-get -y install build-essential asciidoc binutils bzip2 gawk gettext git libncurses5-dev libz-dev patch python3 unzip zlib1g-dev lib32gcc1 libc6-dev-i386 subversion flex uglifyjs gcc-multilib g++-multilib p7zip p7zip-full msmtp libssl-dev texinfo libglib2.0-dev xmlto qemu-utils upx libelf-dev autoconf automake libtool autopoint device-tree-compiler antlr3 gperf sudo -E apt-get -y autoremove --purge sudo -E apt-get clean From 6d92b607674a2a0d75171fa94f709e6137011937 Mon Sep 17 00:00:00 2001 From: lean Date: Wed, 8 Apr 2020 12:38:04 +0800 Subject: [PATCH 05/27] luci-app-music-remote-center: add place holder --- .../lean/luci-app-music-remote-center/Makefile | 2 +- .../root/opt/music/Treat - idiots.mp3 | Bin 0 -> 194100 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 package/lean/luci-app-music-remote-center/root/opt/music/Treat - idiots.mp3 diff --git a/package/lean/luci-app-music-remote-center/Makefile b/package/lean/luci-app-music-remote-center/Makefile index e99a3161de..9b65a68bb6 100644 --- a/package/lean/luci-app-music-remote-center/Makefile +++ b/package/lean/luci-app-music-remote-center/Makefile @@ -10,7 +10,7 @@ LUCI_TITLE:=Luci for Music Remote Center LUCI_DEPENDS:=+alsa-utils +forked-daapd LUCI_PKGARCH:=all PKG_VERSION:=1 -PKG_RELEASE:=3 +PKG_RELEASE:=5 include $(TOPDIR)/feeds/luci/luci.mk diff --git a/package/lean/luci-app-music-remote-center/root/opt/music/Treat - idiots.mp3 b/package/lean/luci-app-music-remote-center/root/opt/music/Treat - idiots.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..616b70611a1bc2fd102ad4dcc523bb2bf99efc94 GIT binary patch literal 194100 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 &oefvH$vg?Fb-4NC@Mm<~ozj@{#(;z33JGA)&@2 zO3kM9OOiGLIGKZbY(nw!v3SF@uULzhSv>Zsy~D8_z+kzKe18>U6ujkVY!U!1D`Eta za-DmmFRjdrmDJG{LB!}Q;dY}9ipG*64O8>FcWb)(A=LSZVA3t+Su#(^-Wyie*z`r_ zFxQfHB=udn1sg@#!qJ?p@^_WsPYSPDwta(kQ=^pUqmM?mHoY~#Sokf?iweU*gAc*`LrzCK!~42kE>C7Egsx?4SO&hkd~-COSF^N zqSbeBs=)0*Sdwe+;)I-+uvo0+Dz7!X?+8I!LWt#x1^4-^y6$w*$n}K&s>HsP?FNHy z7tb-Qngn9YRj@dKF-t-R){9=3b>TT8Es(n=`om}2gXPYKWZkDexHxIFm`A(j*8c~) zBY+g-wZs2{8Rtj1qzJf)2)TS8l)l%wIdf!wp>gPQQVCTF3t7y#4W(A`I_{cpI1Wl` zpjhAS289Yi2hD!XU~i_h(2WlAP_*-3q2C@hTFd@c@QGI+Ao6xDWLp*vTqWMbdL!LO z@QH+4{&>$=F7Om*E*Z=%Oufa-7i&(vBxYl3qFqIZ5=E%gCrA=(I&sNvd4_9-ps2CE z`7>L}iE^xk$<)xDgf7f7`(UWD5uljU8uO8Hl`KAwqP9CUp>V81-HXa{Jy}#~GH-gJG@UwPU@pGYH2@yd1_1(Ck*a< z`6wFeLf5r7r&7V0XNN2H#)c+X$P&g>PD4DfdEWaIODDs=Iei-$2YGC}haa1sE-6Jv zhTpw{y}Kpj78tYXBZu!`jA%|@)Gd=o>TfPRm`Wz@dQ_c+=KIF(Ldh~u+O3sz#dYs~ z4!F_S6${=jl4-(@=WCv{Wd^9-3MxLM>%iqo0mL+DtMn>oqlb@rH*tOC3x%>>FYlUX zXJ#GzPO{0ld<=K> zbA3##E*|>c-yf;~{+ptZw~$!~sxXGxxl2RQ-M1d&aSR%|t-d(%dXxqT%`~PEMo>Pw z?61NN(PiqGsX6dGt}2bz{5f zEzuQ5Yn{1SsAPq|S^GCqrQxc*M8~y<1qPBk0D`PL> z4K3ji+-4lOV5a9_etU&OV~K-!-8(NJl)mez@sfRKS6uu~sQ2ujV9W2yyRW}E#glXG z+*dk=-%i&^tS3i+qeI&#u1`+s&n-6St)4KH3S0}TX8rSCj9!cQ`l_0ufK9J*Mw7L2 zgtlmvkpU#H%t(O;FYaN~Ur|iQ6ma`UC^sKY9{~wP>qFA~YMhT(O{=oyBdMa*gyfwn z)Wlqq`D9!O9fXk_CE93k!BC%ILqlNr^K9^IfRX{cxT3nyljDs?@YA5tAjZW|n2Edc zz_X$D?DTEy%>F+detZYPSGDlmH$k=BjfZ@mF@V|ulacrMf8XcQSg0BOvNOl2uqbRa zvCb>4{F26^t+BFA8|V8H8RD5HKs9biG!dsX#AABj}q^h z2UCLjZ)uBEcIlYTi&CV!N4WOp1XUL?0l%o_GbZK8|N4=qJTZNm

n;1;=E$5Xz!A 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

52hKDEtfWfgA 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%0D#}agnY;4Z0SOM{E-bj^AzB$y#sz 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 literal 0 HcmV?d00001 From b6b408c8fad74c341eacfec43b08d981b146e6ea Mon Sep 17 00:00:00 2001 From: lean Date: Wed, 8 Apr 2020 13:30:03 +0800 Subject: [PATCH 06/27] Version bump to R20.4.8 --- package/lean/default-settings/Makefile | 2 +- package/lean/default-settings/files/zzz-default-settings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/lean/default-settings/Makefile b/package/lean/default-settings/Makefile index b592c92d03..b942eb922f 100644 --- a/package/lean/default-settings/Makefile +++ b/package/lean/default-settings/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=default-settings PKG_VERSION:=1.1 -PKG_RELEASE:=56 +PKG_RELEASE:=57 PKG_LICENSE:=GPLv3 PKG_LICENSE_FILES:=LICENSE diff --git a/package/lean/default-settings/files/zzz-default-settings b/package/lean/default-settings/files/zzz-default-settings index 11216e970e..edd794655f 100755 --- a/package/lean/default-settings/files/zzz-default-settings +++ b/package/lean/default-settings/files/zzz-default-settings @@ -43,7 +43,7 @@ sed -i '/option disabled/d' /etc/config/wireless sed -i '/set wireless.radio${devidx}.disabled/d' /lib/wifi/mac80211.sh sed -i '/DISTRIB_REVISION/d' /etc/openwrt_release -echo "DISTRIB_REVISION='R20.3.19'" >> /etc/openwrt_release +echo "DISTRIB_REVISION='R20.4.8'" >> /etc/openwrt_release sed -i '/DISTRIB_DESCRIPTION/d' /etc/openwrt_release echo "DISTRIB_DESCRIPTION='OpenWrt '" >> /etc/openwrt_release From dc875de0ea77cbdcaf32eb25407b89d2efbecf20 Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Wed, 8 Apr 2020 19:07:29 +0800 Subject: [PATCH 07/27] kernel: netdev: add missing config for mlx5 driver (#4228) * kernel: Fix miss config and module for mlx driver Missing config symbols could lead to build failures on kernel 4.14/4.19. Signed-off-by: Tan Zien [rephrase commit message - reorder symbols] Signed-off-by: David Bauer * kernel: netdev: add missing config for mlx5 driver The mlk5 kmod lacks all necessary build symbols for kernel 4.14 (again). Add missing symbols to avoid build failure on these targets. Signed-off-by: Tan Zien [rewrite commit message - reorder symbols] Signed-off-by: David Bauer Co-authored-by: Tan Zien --- package/kernel/linux/modules/netdevices.mk | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/package/kernel/linux/modules/netdevices.mk b/package/kernel/linux/modules/netdevices.mk index eba26dbb2d..c89e9707c7 100644 --- a/package/kernel/linux/modules/netdevices.mk +++ b/package/kernel/linux/modules/netdevices.mk @@ -1079,12 +1079,15 @@ define KernelPackage/mlx4-core SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=Mellanox ConnectX(R) mlx4 core Network Driver DEPENDS:=@PCI_SUPPORT +kmod-ptp - FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx4/mlx4_core.ko + FILES:= \ + $(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx4/mlx4_core.ko \ + $(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx4/mlx4_en.ko KCONFIG:= CONFIG_MLX4_EN \ + CONFIG_MLX4_EN_DCB=n \ CONFIG_MLX4_CORE=y \ CONFIG_MLX4_CORE_GEN2=y \ CONFIG_MLX4_DEBUG=n - AUTOLOAD:=$(call AutoProbe,mlx4_core) + AUTOLOAD:=$(call AutoProbe,mlx4_core mlx4_en) endef define KernelPackage/mlx4-core/description @@ -1100,7 +1103,20 @@ define KernelPackage/mlx5-core FILES:=$(LINUX_DIR)/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko KCONFIG:= CONFIG_MLX5_CORE \ CONFIG_MLX5_CORE_EN=y \ - CONFIG_MLX5_EN_RXNFC=y + CONFIG_MLX5_CORE_EN_DCB=n \ + CONFIG_MLX5_CORE_IPOIB=n \ + CONFIG_MLX5_EN_ARFS=n \ + CONFIG_MLX5_EN_IPSEC=n \ + CONFIG_MLX5_EN_RXNFC=y \ + CONFIG_MLX5_EN_TLS=n \ + CONFIG_MLX5_ESWITCH=n \ + CONFIG_MLX5_FPGA=n \ + CONFIG_MLX5_FPGA_IPSEC=n \ + CONFIG_MLX5_FPGA_TLS=n \ + CONFIG_MLX5_MPFS=y \ + CONFIG_MLX5_SW_STEERING=n \ + CONFIG_MLX5_TC_CT=n \ + CONFIG_MLX5_TLS=n AUTOLOAD:=$(call AutoProbe,mlx5_core) endef From 7bf824b1fcb5b4501b492fb5ef712b92f1711908 Mon Sep 17 00:00:00 2001 From: lean Date: Thu, 9 Apr 2020 00:25:33 +0800 Subject: [PATCH 08/27] qBittorrent: bump to v4.2.3 --- package/lean/qBittorrent/Makefile | 6 +- .../001-remove-ico-not-for-webui.patch | 126 --- .../patches/002-add-autoban-function.patch | 807 ------------------ 3 files changed, 3 insertions(+), 936 deletions(-) delete mode 100644 package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch delete mode 100644 package/lean/qBittorrent/patches/002-add-autoban-function.patch diff --git a/package/lean/qBittorrent/Makefile b/package/lean/qBittorrent/Makefile index a8825a2877..8eba767194 100644 --- a/package/lean/qBittorrent/Makefile +++ b/package/lean/qBittorrent/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qbittorrent -PKG_VERSION:=4.1.9 -PKG_RELEASE=6 +PKG_VERSION:=4.2.3 +PKG_RELEASE=1 PKG_SOURCE:=$(PKG_NAME)-release-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/qbittorrent/qBittorrent/tar.gz/release-$(PKG_VERSION)? -PKG_HASH:=620127f73f88ed3f2b2e4195cbc641f7c27f967d3b045e45f7916c0995fd61fe +PKG_HASH:=be490e73253c65c439a64afb348e562aaf92eee5c729e51e16a0bac2048166fd PKG_BUILD_DIR:=$(BUILD_DIR)/qBittorrent-release-$(PKG_VERSION) diff --git a/package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch b/package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch deleted file mode 100644 index ee27bbaca4..0000000000 --- a/package/lean/qBittorrent/patches/001-remove-ico-not-for-webui.patch +++ /dev/null @@ -1,126 +0,0 @@ ---- a/src/icons/icons.qrc -+++ b/src/icons/icons.qrc -@@ -250,38 +250,16 @@ - flags/zm.svg - flags/zw.svg - L.gif -- loading.png - qbt-theme/application-exit.svg -- qbt-theme/application-rss+xml.svg -- qbt-theme/application-x-mswinurl.svg - qbt-theme/checked.svg - qbt-theme/configure.svg -- qbt-theme/dialog-cancel.svg -- qbt-theme/dialog-information.svg -- qbt-theme/dialog-warning.svg - qbt-theme/document-edit-verify.svg - qbt-theme/document-edit.svg -- qbt-theme/document-encrypt.svg -- qbt-theme/document-import.svg -- qbt-theme/document-new.svg -- qbt-theme/document-properties.svg -- qbt-theme/document-save.svg -- qbt-theme/download.svg -- qbt-theme/edit-clear-history.svg - qbt-theme/edit-clear.svg - qbt-theme/edit-copy.svg -- qbt-theme/edit-cut.svg - qbt-theme/edit-delete.svg -- qbt-theme/edit-find-user.svg - qbt-theme/edit-find.svg -- qbt-theme/edit-paste.svg - qbt-theme/edit-rename.svg -- qbt-theme/folder-documents.svg -- qbt-theme/folder-download.svg -- qbt-theme/folder-new.svg -- qbt-theme/folder-remote.svg -- qbt-theme/gear.svg -- qbt-theme/gear32.svg - qbt-theme/go-bottom.svg - qbt-theme/go-down.svg - qbt-theme/go-top.svg -@@ -295,43 +273,15 @@ - qbt-theme/kt-set-max-upload-speed.png - qbt-theme/list-add.svg - qbt-theme/list-remove.svg -- qbt-theme/mail-folder-inbox.svg -- qbt-theme/mail-mark-read.svg - qbt-theme/media-playback-pause.svg - qbt-theme/media-playback-start.svg - qbt-theme/media-seek-forward.svg -- qbt-theme/network-server.svg -- qbt-theme/network-wired.svg -- qbt-theme/object-locked.svg -- qbt-theme/office-chart-line.svg -- qbt-theme/preferences-desktop.svg -- qbt-theme/preferences-other.svg -- qbt-theme/preferences-system-network.svg -- qbt-theme/preferences-web-browser-cookies.svg -- qbt-theme/rss-config.png - qbt-theme/security-high.svg - qbt-theme/security-low.svg -- qbt-theme/services.svg -- qbt-theme/speedometer.svg - qbt-theme/system-log-out.svg -- qbt-theme/tab-close.svg -- qbt-theme/task-attention.svg -- qbt-theme/task-complete.png -- qbt-theme/task-ongoing.png -- qbt-theme/task-reject.png -- qbt-theme/text-plain.svg -- qbt-theme/tools-report-bug.svg -- qbt-theme/unavailable.svg -- qbt-theme/user-group-delete.svg -- qbt-theme/user-group-new.svg -- qbt-theme/view-calendar-journal.svg - qbt-theme/view-categories.svg -- qbt-theme/view-filter.svg -- qbt-theme/view-preview.svg -- qbt-theme/view-refresh.svg - qbt-theme/view-statistics.svg - qbt-theme/wallet-open.svg -- qbt-theme/webui.svg - skin/arrow-right.gif - skin/bg-dropdown.gif - skin/bg-handle-horizontal.gif -@@ -342,7 +292,6 @@ - skin/completed.svg - skin/connected.svg - skin/disconnected.svg -- skin/dock-tabs.gif - skin/download.svg - skin/downloading.svg - skin/error.svg -@@ -353,14 +302,11 @@ - skin/handle-icon-horizontal.gif - skin/handle-icon.gif - skin/knob.gif -- skin/logo-blank.gif - skin/logo.gif - skin/logo2.gif - skin/mascot.png - skin/paused.svg - skin/qbittorrent-tray.svg -- skin/qbittorrent-tray-dark.svg -- skin/qbittorrent-tray-light.svg - skin/qbittorrent32.png - skin/queued.svg - skin/ratio.svg -@@ -370,17 +316,12 @@ - skin/spacer.gif - skin/spinner-placeholder.gif - skin/spinner.gif -- skin/splash.png - skin/stalledDL.svg - skin/stalledUP.svg - skin/tabs.gif - skin/toolbox-divider.gif -- skin/toolbox-divider2.gif - skin/uploading.svg - slow.png - slow_off.png -- sphere.png -- sphere2.png -- url.png - - diff --git a/package/lean/qBittorrent/patches/002-add-autoban-function.patch b/package/lean/qBittorrent/patches/002-add-autoban-function.patch deleted file mode 100644 index 8de0f1e47b..0000000000 --- a/package/lean/qBittorrent/patches/002-add-autoban-function.patch +++ /dev/null @@ -1,807 +0,0 @@ ---- a/src/base/bittorrent/peerinfo.cpp -+++ b/src/base/bittorrent/peerinfo.cpp -@@ -186,11 +186,26 @@ PeerAddress PeerInfo::address() const - m_nativeInfo.ip.port()); - } - -+int PeerInfo::port() const -+{ -+ return m_nativeInfo.ip.port(); -+} -+ - QString PeerInfo::client() const - { - return QString::fromStdString(m_nativeInfo.client); - } - -+QString PeerInfo::pid() const -+{ -+ return QString::fromStdString(m_nativeInfo.pid.to_string()); -+} -+ -+QString PeerInfo::pidtoclient() const -+{ -+ return QString::fromStdString(libt::identify_client(m_nativeInfo.pid)); -+} -+ - qreal PeerInfo::progress() const - { - return m_nativeInfo.progress; ---- a/src/base/bittorrent/peerinfo.h -+++ b/src/base/bittorrent/peerinfo.h -@@ -34,6 +34,7 @@ - #include - - #include -+#include - - namespace BitTorrent - { -@@ -85,7 +86,10 @@ namespace BitTorrent - bool isPlaintextEncrypted() const; - - PeerAddress address() const; -+ int port() const; - QString client() const; -+ QString pid() const; -+ QString pidtoclient() const; - qreal progress() const; - int payloadUpSpeed() const; - int payloadDownSpeed() const; ---- a/src/base/bittorrent/session.cpp -+++ b/src/base/bittorrent/session.cpp -@@ -69,6 +69,7 @@ - #endif - - #include "base/algorithm.h" -+#include "base/bittorrent/peerinfo.h" - #include "base/exceptions.h" - #include "base/global.h" - #include "base/logger.h" -@@ -335,6 +336,8 @@ Session::Session(QObject *parent) - , m_isAltGlobalSpeedLimitEnabled(BITTORRENT_SESSION_KEY("UseAlternativeGlobalSpeedLimit"), false) - , m_isBandwidthSchedulerEnabled(BITTORRENT_SESSION_KEY("BandwidthSchedulerEnabled"), false) - , m_saveResumeDataInterval(BITTORRENT_SESSION_KEY("SaveResumeDataInterval"), 60) -+ , m_autoBanUnknownPeer(BITTORRENT_SESSION_KEY("AutoBanUnknownPeer"), true) -+ , m_showTrackerAuthWindow(BITTORRENT_SESSION_KEY("ShowTrackerAuthWindow"), true) - , m_port(BITTORRENT_SESSION_KEY("Port"), 8999) - , m_useRandomPort(BITTORRENT_SESSION_KEY("UseRandomPort"), false) - , m_networkInterface(BITTORRENT_SESSION_KEY("Interface")) -@@ -502,6 +505,7 @@ Session::Session(QObject *parent) - libt::ip_filter filter; - processBannedIPs(filter); - m_nativeSession->set_ip_filter(filter); -+ loadOfflineFilter(); - } - - m_categories = map_cast(m_storedCategories); -@@ -518,6 +522,17 @@ Session::Session(QObject *parent) - connect(m_refreshTimer, &QTimer::timeout, this, &Session::refresh); - m_refreshTimer->start(); - -+ // Unban Timer -+ m_unbanTimer = new QTimer(this); -+ m_unbanTimer->setInterval(500); -+ connect(m_unbanTimer, &QTimer::timeout, this, &Session::processUnbanRequest); -+ -+ // Ban Timer -+ m_banTimer = new QTimer(this); -+ m_banTimer->setInterval(500); -+ connect(m_banTimer, &QTimer::timeout, this, &Session::autoBanBadClient); -+ m_banTimer->start(); -+ - m_statistics = new Statistics(this); - - updateSeedingLimitTimer(); -@@ -1077,6 +1092,7 @@ void Session::configure() - enableIPFilter(); - else - disableIPFilter(); -+ loadOfflineFilter(); - m_IPFilteringChanged = false; - } - -@@ -1905,6 +1921,95 @@ void Session::banIP(const QString &ip) - } - } - -+bool Session::checkAccessFlags(const QString &ip) -+{ -+ libt::ip_filter filter = m_nativeSession->get_ip_filter(); -+ boost::system::error_code ec; -+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec); -+ Q_ASSERT(!ec); -+ if (ec) return false; -+ return filter.access(addr); -+} -+ -+void Session::tempblockIP(const QString &ip) -+{ -+ libt::ip_filter filter = m_nativeSession->get_ip_filter(); -+ boost::system::error_code ec; -+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec); -+ Q_ASSERT(!ec); -+ if (ec) return; -+ filter.add_rule(addr, addr, libt::ip_filter::blocked); -+ m_nativeSession->set_ip_filter(filter); -+ insertQueue(ip); -+} -+ -+void Session::removeBlockedIP(const QString &ip) -+{ -+ libt::ip_filter filter = m_nativeSession->get_ip_filter(); -+ boost::system::error_code ec; -+ libt::address addr = libt::address::from_string(ip.toLatin1().constData(), ec); -+ Q_ASSERT(!ec); -+ if (ec) return; -+ filter.add_rule(addr, addr, 0); -+ m_nativeSession->set_ip_filter(filter); -+} -+ -+void Session::eraseIPFilter() -+{ -+ q_bannedIPs.clear(); -+ q_unbanTime.clear(); -+ if (isIPFilteringEnabled()) { -+ enableIPFilter(); -+ } else { -+ disableIPFilter(); -+ loadOfflineFilter(); -+ } -+} -+ -+void Session::autoBanBadClient() -+{ -+ const BitTorrent::SessionStatus tStatus = BitTorrent::Session::instance()->status(); -+ if (tStatus.peersCount > 0) { -+ bool m_AutoBan = BitTorrent::Session::instance()->isAutoBanUnknownPeerEnabled(); -+ foreach (BitTorrent::TorrentHandle *const torrent, BitTorrent::Session::instance()->torrents()) { -+ QList peers = torrent->peers(); -+ foreach (const BitTorrent::PeerInfo &peer, peers) { -+ BitTorrent::PeerAddress addr = peer.address(); -+ if (addr.ip.isNull()) continue; -+ QString ip = addr.ip.toString(); -+ int port = peer.port(); -+ QString client = peer.client(); -+ QString ptoc = peer.pidtoclient(); -+ QString pid = peer.pid().left(8); -+ QString country = peer.country(); -+ -+ QRegExp IDFilter("-(XL|SD|XF|QD|BN|DL)(\\d+)-"); -+ QRegExp UAFilter("\\d+.\\d+.\\d+.\\d+"); -+ if (IDFilter.exactMatch(pid) || UAFilter.exactMatch(client)) { -+ qDebug("Auto Banning bad Peer %s...", ip.toLocal8Bit().data()); -+ Logger::instance()->addMessage(tr("Auto banning bad Peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(pid).arg(ptoc).arg(country)); -+ tempblockIP(ip); -+ continue; -+ } -+ -+ if(m_AutoBan) { -+ if (client.contains("Unknown") && country == "CN") { -+ qDebug("Auto Banning Unknown Peer %s...", ip.toLocal8Bit().data()); -+ Logger::instance()->addMessage(tr("Auto banning Unknown Peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(pid).arg(ptoc).arg(country)); -+ tempblockIP(ip); -+ continue; -+ } -+ if (port >= 65000 && country == "CN" && client.contains("Transmission")) { -+ qDebug("Auto Banning Offline Downloader %s...", ip.toLocal8Bit().data()); -+ Logger::instance()->addMessage(tr("Auto banning Offline Downloader '%1:%2'...'%3'...'%4'...'%5'").arg(ip).arg(port).arg(pid).arg(ptoc).arg(country)); -+ tempblockIP(ip); -+ } -+ } -+ } -+ } -+ } -+} -+ - // Delete a torrent from the session, given its hash - // deleteLocalFiles = true means that the torrent will be removed from the hard-drive too - bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles) -@@ -2787,6 +2892,30 @@ void Session::setSaveResumeDataInterval( - } - } - -+bool Session::isAutoBanUnknownPeerEnabled() const -+{ -+ return m_autoBanUnknownPeer; -+} -+ -+void Session::setAutoBanUnknownPeer(bool value) -+{ -+ if (value != isAutoBanUnknownPeerEnabled()) { -+ m_autoBanUnknownPeer = value; -+ } -+} -+ -+bool Session::isShowTrackerAuthWindow() const -+{ -+ return m_showTrackerAuthWindow; -+} -+ -+void Session::setShowTrackerAuthWindow(bool value) -+{ -+ if (value != isShowTrackerAuthWindow()) { -+ m_showTrackerAuthWindow = value; -+ } -+} -+ - int Session::port() const - { - static int randomPort = Utils::Random::rand(1024, 65535); -@@ -3877,6 +4006,220 @@ void Session::disableIPFilter() - m_nativeSession->set_ip_filter(filter); - } - -+// Insert banned IP to Queue -+void Session::insertQueue(QString ip) -+{ -+ q_bannedIPs.enqueue(ip); -+ q_unbanTime.enqueue(QDateTime::currentMSecsSinceEpoch() + 60 * 60 * 1000); -+ -+ if (!m_unbanTimer->isActive()) { -+ m_unbanTimer->start(); -+ } -+} -+ -+// Process Unban Queue -+void Session::processUnbanRequest() -+{ -+ if (q_bannedIPs.isEmpty() && q_unbanTime.isEmpty()) { -+ m_unbanTimer->stop(); -+ } -+ else if (m_isActive) { -+ return; -+ } -+ else { -+ m_isActive = true; -+ int64_t currentTime = QDateTime::currentMSecsSinceEpoch(); -+ int64_t nextTime = q_unbanTime.dequeue(); -+ int delayTime = int(nextTime - currentTime); -+ QString nextIP = q_bannedIPs.dequeue(); -+ if (delayTime < 0) { -+ QTimer::singleShot(0, [=] { BitTorrent::Session::instance()->removeBlockedIP(nextIP); m_isActive = false; }); -+ } -+ else { -+ QTimer::singleShot(delayTime, [=] { BitTorrent::Session::instance()->removeBlockedIP(nextIP); m_isActive = false; }); -+ } -+ } -+} -+ -+// Handle ipfilter.dat -+int trim(char* const data, int start, int end) -+{ -+ if (start >= end) return start; -+ int newStart = start; -+ -+ for (int i = start; i <= end; ++i) { -+ if (isspace(data[i]) != 0) { -+ data[i] = '\0'; -+ } -+ else { -+ newStart = i; -+ break; -+ } -+ } -+ -+ for (int i = end; i >= start; --i) { -+ if (isspace(data[i]) != 0) -+ data[i] = '\0'; -+ else -+ break; -+ } -+ -+ return newStart; -+} -+ -+int findAndNullDelimiter(char *const data, char delimiter, int start, int end) -+{ -+ for (int i = start; i <= end; ++i) { -+ if (data[i] == delimiter) { -+ data[i] = '\0'; -+ return i; -+ } -+ } -+ -+ return -1; -+} -+ -+int Session::parseOfflineFilterFile(QString ipDat, libt::ip_filter &filter) -+{ -+ int ruleCount = 0; -+ QFile file(ipDat); -+ if (!file.exists()) return ruleCount; -+ -+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { -+ LogMsg(tr("I/O Error: Could not open IP filter file in read mode."), Log::CRITICAL); -+ return ruleCount; -+ } -+ -+ std::vector buffer(2 * 1024 * 1024, 0); // seems a bit faster than QVector -+ qint64 bytesRead = 0; -+ int offset = 0; -+ int start = 0; -+ int endOfLine = -1; -+ int nbLine = 0; -+ -+ while (true) { -+ bytesRead = file.read(buffer.data() + offset, 2 * 1024 * 1024 - offset - 1); -+ if (bytesRead < 0) -+ break; -+ int dataSize = bytesRead + offset; -+ if (bytesRead == 0 && dataSize == 0) -+ break; -+ -+ for (start = 0; start < dataSize; ++start) { -+ endOfLine = -1; -+ // The file might have ended without the last line having a newline -+ if (!(bytesRead == 0 && dataSize > 0)) { -+ for (int i = start; i < dataSize; ++i) { -+ if (buffer[i] == '\n') { -+ endOfLine = i; -+ // We need to NULL the newline in case the line has only an IP range. -+ // In that case the parser won't work for the end IP, because it ends -+ // with the newline and not with a number. -+ buffer[i] = '\0'; -+ break; -+ } -+ } -+ } -+ else { -+ endOfLine = dataSize; -+ buffer[dataSize] = '\0'; -+ } -+ -+ if (endOfLine == -1) { -+ // read the next chunk from file -+ // but first move(copy) the leftover data to the front of the buffer -+ offset = dataSize - start; -+ memmove(buffer.data(), buffer.data() + start, offset); -+ break; -+ } -+ else { -+ ++nbLine; -+ } -+ -+ if ((buffer[start] == '#') -+ || ((buffer[start] == '/') && ((start + 1 < dataSize) && (buffer[start + 1] == '/')))) { -+ start = endOfLine; -+ continue; -+ } -+ -+ // Each line should follow this format: -+ // 001.009.096.105 - 001.009.096.105 , 000 , Some organization -+ // The 3rd entry is access level and if above 127 the IP range isn't blocked. -+ int firstComma = findAndNullDelimiter(buffer.data(), ',', start, endOfLine); -+ if (firstComma != -1) -+ findAndNullDelimiter(buffer.data(), ',', firstComma + 1, endOfLine); -+ -+ // Check if there is an access value (apparently not mandatory) -+ if (firstComma != -1) { -+ // There is possibly one -+ const long int nbAccess = strtol(buffer.data() + firstComma + 1, nullptr, 10); -+ // Ignoring this rule because access value is too high -+ if (nbAccess > 127L) { -+ start = endOfLine; -+ continue; -+ } -+ } -+ -+ // IP Range should be split by a dash -+ int endOfIPRange = ((firstComma == -1) ? (endOfLine - 1) : (firstComma - 1)); -+ int delimIP = findAndNullDelimiter(buffer.data(), '-', start, endOfIPRange); -+ if (delimIP == -1) { -+ start = endOfLine; -+ continue; -+ } -+ -+ boost::system::error_code ec; -+ int newStart = trim(buffer.data(), start, delimIP - 1); -+ libt::address startAddr = libt::address::from_string(buffer.data() + newStart, ec); -+ Q_ASSERT(!ec); -+ if (ec) { -+ start = endOfLine; -+ continue; -+ } -+ -+ newStart = trim(buffer.data(), delimIP + 1, endOfIPRange); -+ libt::address endAddr = libt::address::from_string(buffer.data() + newStart, ec); -+ Q_ASSERT(!ec); -+ if (ec) { -+ start = endOfLine; -+ continue; -+ } -+ -+ if ((startAddr.is_v4() != endAddr.is_v4()) -+ || (startAddr.is_v6() != endAddr.is_v6())) { -+ start = endOfLine; -+ continue; -+ } -+ -+ start = endOfLine; -+ -+ filter.add_rule(startAddr, endAddr, libt::ip_filter::blocked); -+ ++ruleCount; -+ } -+ -+ if (start >= dataSize) -+ offset = 0; -+ } -+ -+ return ruleCount; -+} -+ -+void Session::loadOfflineFilter() { -+ int Count = 0; -+ libt::ip_filter offlineFilter = m_nativeSession->get_ip_filter(); -+ -+#if defined(Q_OS_WIN) -+ Count = parseOfflineFilterFile("./ipfilter.dat", offlineFilter); -+#endif -+ -+#if (defined(Q_OS_UNIX) && !defined(Q_OS_MAC)) -+ Count = parseOfflineFilterFile(QDir::home().absoluteFilePath(".config")+"/qBittorrent/ipfilter.dat", offlineFilter); -+#endif -+ -+ m_nativeSession->set_ip_filter(offlineFilter); -+ Logger::instance()->addMessage(tr("Successfully parsed the offline downloader IP filter: %1 rules were applied.", "%1 is a number").arg(Count)); -+} -+ - void Session::recursiveTorrentDownload(const InfoHash &hash) - { - TorrentHandle *const torrent = m_torrents.value(hash); -@@ -4063,6 +4406,7 @@ void Session::handleIPFilterParsed(int r - } - Logger::instance()->addMessage(tr("Successfully parsed the provided IP filter: %1 rules were applied.", "%1 is a number").arg(ruleCount)); - emit IPFilterParsed(false, ruleCount); -+ loadOfflineFilter(); - } - - void Session::handleIPFilterError() ---- a/src/base/bittorrent/session.h -+++ b/src/base/bittorrent/session.h -@@ -40,8 +40,10 @@ - #include - #include - #include -+#include - #include - #include -+#include - #include - #include - -@@ -341,6 +343,10 @@ namespace BitTorrent - - uint saveResumeDataInterval() const; - void setSaveResumeDataInterval(uint value); -+ bool isAutoBanUnknownPeerEnabled() const; -+ void setAutoBanUnknownPeer(bool value); -+ bool isShowTrackerAuthWindow() const; -+ void setShowTrackerAuthWindow(bool value); - int port() const; - void setPort(int port); - bool useRandomPort() const; -@@ -467,6 +473,19 @@ namespace BitTorrent - void setMaxRatioAction(MaxRatioAction act); - - void banIP(const QString &ip); -+ bool checkAccessFlags(const QString &ip); -+ void tempblockIP(const QString &ip); -+ void removeBlockedIP(const QString &ip); -+ void eraseIPFilter(); -+ void autoBanBadClient(); -+ -+ // Unban Timer -+ bool m_isActive = false; -+ QQueue q_bannedIPs; -+ QQueue q_unbanTime; -+ QTimer *m_unbanTimer; -+ QTimer *m_banTimer; -+ void insertQueue(QString ip); - - bool isKnownTorrent(const InfoHash &hash) const; - bool addTorrent(QString source, const AddTorrentParams ¶ms = AddTorrentParams()); -@@ -546,6 +565,9 @@ namespace BitTorrent - void tagAdded(const QString &tag); - void tagRemoved(const QString &tag); - -+ public slots: -+ void processUnbanRequest(); -+ - private slots: - void configureDeferred(); - void readAlerts(); -@@ -601,6 +623,8 @@ namespace BitTorrent - void populateAdditionalTrackers(); - void enableIPFilter(); - void disableIPFilter(); -+ int parseOfflineFilterFile(QString ipDat, libtorrent::ip_filter &filter); -+ void loadOfflineFilter(); - - bool addTorrent_impl(CreateTorrentParams params, const MagnetUri &magnetUri, - TorrentInfo torrentInfo = TorrentInfo(), -@@ -713,6 +737,8 @@ namespace BitTorrent - CachedSettingValue m_isAltGlobalSpeedLimitEnabled; - CachedSettingValue m_isBandwidthSchedulerEnabled; - CachedSettingValue m_saveResumeDataInterval; -+ CachedSettingValue m_autoBanUnknownPeer; -+ CachedSettingValue m_showTrackerAuthWindow; - CachedSettingValue m_port; - CachedSettingValue m_useRandomPort; - CachedSettingValue m_networkInterface; ---- a/src/base/bittorrent/torrenthandle.cpp -+++ b/src/base/bittorrent/torrenthandle.cpp -@@ -1561,7 +1561,8 @@ void TorrentHandle::handleTrackerErrorAl - m_trackerInfos[trackerUrl].lastMessage = message; - - if (p->status_code == 401) -- m_session->handleTorrentTrackerAuthenticationRequired(this, trackerUrl); -+ if (Preferences::instance()->getShowTrackerAuthWindow()) -+ m_session->handleTorrentTrackerAuthenticationRequired(this, trackerUrl); - - m_session->handleTorrentTrackerError(this, trackerUrl); - } ---- a/src/base/preferences.cpp -+++ b/src/base/preferences.cpp -@@ -1090,6 +1090,26 @@ void Preferences::setTrayIconStyle(TrayI - } - #endif - -+bool Preferences::getAutoBanUnknownPeer() const -+{ -+ return value("Preferences/Advanced/AutoBanUnknownPeer", false).toBool(); -+} -+ -+void Preferences::setAutoBanUnknownPeer(const bool checked) -+{ -+ setValue("Preferences/Advanced/AutoBanUnknownPeer", checked); -+} -+ -+bool Preferences::getShowTrackerAuthWindow() const -+{ -+ return value("Preferences/Advanced/ShowTrackerAuthWindow", true).toBool(); -+} -+ -+void Preferences::setShowTrackerAuthWindow(const bool checked) -+{ -+ setValue("Preferences/Advanced/ShowTrackerAuthWindow", checked); -+} -+ - // Stuff that don't appear in the Options GUI but are saved - // in the same file. - ---- a/src/base/preferences.h -+++ b/src/base/preferences.h -@@ -300,6 +300,10 @@ public: - TrayIcon::Style trayIconStyle() const; - void setTrayIconStyle(TrayIcon::Style style); - #endif // Q_OS_MAC -+ bool getAutoBanUnknownPeer() const; -+ void setAutoBanUnknownPeer(const bool checked); -+ bool getShowTrackerAuthWindow() const; -+ void setShowTrackerAuthWindow(const bool checked); - - // Stuff that don't appear in the Options GUI but are saved - // in the same file. ---- a/src/base/settingsstorage.cpp -+++ b/src/base/settingsstorage.cpp -@@ -91,6 +91,8 @@ namespace - {"BitTorrent/Session/InterfaceName", "Preferences/Connection/InterfaceName"}, - {"BitTorrent/Session/InterfaceAddress", "Preferences/Connection/InterfaceAddress"}, - {"BitTorrent/Session/SaveResumeDataInterval", "Preferences/Downloads/SaveResumeDataInterval"}, -+ {"BitTorrent/Session/AutoBanUnknownPeer", "Preferences/Advanced/AutoBanUnknownPeer"}, -+ {"BitTorrent/Session/ShowTrackerAuthWindow", "Preferences/Advanced/ShowTrackerAuthWindow"}, - {"BitTorrent/Session/Encryption", "Preferences/Bittorrent/Encryption"}, - {"BitTorrent/Session/ForceProxy", "Preferences/Connection/ProxyForce"}, - {"BitTorrent/Session/ProxyPeerConnections", "Preferences/Connection/ProxyPeerConnections"}, ---- a/src/gui/advancedsettings.cpp -+++ b/src/gui/advancedsettings.cpp -@@ -60,6 +60,8 @@ enum AdvSettingsRows - NETWORK_LISTEN_IPV6, - // behavior - SAVE_RESUME_DATA_INTERVAL, -+ CONFIRM_AUTO_BAN, -+ SHOW_TRACKER_AUTH_WINDOW, - CONFIRM_RECHECK_TORRENT, - RECHECK_COMPLETED, - #if defined(Q_OS_WIN) || defined(Q_OS_MAC) -@@ -215,6 +217,10 @@ void AdvancedSettings::saveAdvancedSetti - // Announce IP - QHostAddress addr(lineEditAnnounceIP.text().trimmed()); - session->setAnnounceIP(addr.isNull() ? "" : addr.toString()); -+ // Auto ban Unknown Peer -+ session->setAutoBanUnknownPeer(cb_auto_ban_unknown_peer.isChecked()); -+ // Show Tracker Authenticaion Window -+ session->setShowTrackerAuthWindow(cb_show_tracker_auth_window.isChecked()); - - // Program notification - MainWindow *const mainWindow = static_cast(QCoreApplication::instance())->mainWindow(); -@@ -465,6 +471,12 @@ void AdvancedSettings::loadAdvancedSetti - // Announce IP - lineEditAnnounceIP.setText(session->announceIP()); - addRow(ANNOUNCE_IP, tr("IP Address to report to trackers (requires restart)"), &lineEditAnnounceIP); -+ // Auto Ban Unknown Peer from China -+ cb_auto_ban_unknown_peer.setChecked(session->isAutoBanUnknownPeerEnabled()); -+ addRow(CONFIRM_AUTO_BAN, tr("Auto Ban Unknown Peer from China"), &cb_auto_ban_unknown_peer); -+ // Show Tracker Authenticaion Window -+ cb_show_tracker_auth_window.setChecked(session->isShowTrackerAuthWindow()); -+ addRow(SHOW_TRACKER_AUTH_WINDOW, tr("Show Tracker Authenticaion Window"), &cb_show_tracker_auth_window); - - // Program notifications - const MainWindow *const mainWindow = static_cast(QCoreApplication::instance())->mainWindow(); ---- a/src/gui/advancedsettings.h -+++ b/src/gui/advancedsettings.h -@@ -65,7 +65,8 @@ private: - QCheckBox checkBoxOsCache, checkBoxRecheckCompleted, checkBoxResolveCountries, checkBoxResolveHosts, checkBoxSuperSeeding, - checkBoxProgramNotifications, checkBoxTorrentAddedNotifications, checkBoxTrackerFavicon, checkBoxTrackerStatus, - checkBoxConfirmTorrentRecheck, checkBoxConfirmRemoveAllTags, checkBoxListenIPv6, checkBoxAnnounceAllTrackers, checkBoxAnnounceAllTiers, -- checkBoxGuidedReadCache, checkBoxMultiConnectionsPerIp, checkBoxSuggestMode, checkBoxCoalesceRW, checkBoxSpeedWidgetEnabled; -+ checkBoxGuidedReadCache, checkBoxMultiConnectionsPerIp, checkBoxSuggestMode, checkBoxCoalesceRW, checkBoxSpeedWidgetEnabled, -+ cb_auto_ban_unknown_peer, cb_show_tracker_auth_window; - QComboBox comboBoxInterface, comboBoxInterfaceAddress, comboBoxUtpMixedMode, comboBoxChokingAlgorithm, comboBoxSeedChokingAlgorithm; - QLineEdit lineEditAnnounceIP; - ---- a/src/gui/mainwindow.cpp -+++ b/src/gui/mainwindow.cpp -@@ -73,6 +73,7 @@ - #include "addnewtorrentdialog.h" - #include "application.h" - #include "autoexpandabledialog.h" -+#include "base/bittorrent/peerinfo.h" - #include "cookiesdialog.h" - #include "downloadfromurldialog.h" - #include "executionlogwidget.h" ---- a/src/gui/properties/peerlistdelegate.h -+++ b/src/gui/properties/peerlistdelegate.h -@@ -49,6 +49,7 @@ public: - CONNECTION, - FLAGS, - CLIENT, -+ PEERID, - PROGRESS, - DOWN_SPEED, - UP_SPEED, ---- a/src/gui/properties/peerlistwidget.cpp -+++ b/src/gui/properties/peerlistwidget.cpp -@@ -75,6 +75,7 @@ PeerListWidget::PeerListWidget(Propertie - m_listModel->setHeaderData(PeerListDelegate::FLAGS, Qt::Horizontal, tr("Flags")); - m_listModel->setHeaderData(PeerListDelegate::CONNECTION, Qt::Horizontal, tr("Connection")); - m_listModel->setHeaderData(PeerListDelegate::CLIENT, Qt::Horizontal, tr("Client", "i.e.: Client application")); -+ m_listModel->setHeaderData(PeerListDelegate::PEERID, Qt::Horizontal, tr("Peer ID", "i.e.: Client Peer ID")); - m_listModel->setHeaderData(PeerListDelegate::PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded")); - m_listModel->setHeaderData(PeerListDelegate::DOWN_SPEED, Qt::Horizontal, tr("Down Speed", "i.e: Download speed")); - m_listModel->setHeaderData(PeerListDelegate::UP_SPEED, Qt::Horizontal, tr("Up Speed", "i.e: Upload speed")); -@@ -288,8 +289,13 @@ void PeerListWidget::banSelectedPeers() - for (const QModelIndex &index : selectedIndexes) { - int row = m_proxyModel->mapToSource(index).row(); - QString ip = m_listModel->data(m_listModel->index(row, PeerListDelegate::IP_HIDDEN)).toString(); -+ QString client = m_listModel->data(m_listModel->index(row, PeerListDelegate::CLIENT)).toString(); -+ QString peerid = m_listModel->data(m_listModel->index(row, PeerListDelegate::PEERID)).toString(); -+ QHostAddress host; -+ host.setAddress(ip); -+ const QString countryName = Net::GeoIPManager::CountryName(Net::GeoIPManager::instance()->lookup(host)); - qDebug("Banning peer %s...", ip.toLocal8Bit().data()); -- Logger::instance()->addMessage(tr("Manually banning peer '%1'...").arg(ip)); -+ Logger::instance()->addMessage(tr("Manually banning peer '%1'...'%2'...'%3'...'%4'").arg(ip).arg(peerid).arg(client).arg(countryName)); - BitTorrent::Session::instance()->banIP(ip); - } - // Refresh list -@@ -398,6 +404,7 @@ QStandardItem *PeerListWidget::addPeer(c - m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped()); -+ m_listModel->setData(m_listModel->index(row, PeerListDelegate::PEERID), peer.pid().left(8).toHtmlEscaped()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed()); -@@ -429,6 +436,7 @@ void PeerListWidget::updatePeer(const QS - m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flags()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::FLAGS), peer.flagsDescription(), Qt::ToolTipRole); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::CLIENT), peer.client().toHtmlEscaped()); -+ m_listModel->setData(m_listModel->index(row, PeerListDelegate::PEERID), peer.pid().left(8).toHtmlEscaped()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::PROGRESS), peer.progress()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::DOWN_SPEED), peer.payloadDownSpeed()); - m_listModel->setData(m_listModel->index(row, PeerListDelegate::UP_SPEED), peer.payloadUpSpeed()); ---- a/src/webui/api/appcontroller.cpp -+++ b/src/webui/api/appcontroller.cpp -@@ -153,6 +153,7 @@ void AppController::preferencesAction() - data["ip_filter_path"] = Utils::Fs::toNativePath(session->IPFilterFile()); - data["ip_filter_trackers"] = session->isTrackerFilteringEnabled(); - data["banned_IPs"] = session->bannedIPs().join("\n"); -+ data["auto_ban_unknown_peer"] = session->isAutoBanUnknownPeerEnabled(); - - // Speed - // Global Rate Limits -@@ -401,6 +402,8 @@ void AppController::setPreferencesAction - session->setTrackerFilteringEnabled(m["ip_filter_trackers"].toBool()); - if (m.contains("banned_IPs")) - session->setBannedIPs(m["banned_IPs"].toString().split('\n')); -+ if (m.contains("auto_ban_unknown_peer")) -+ session->setAutoBanUnknownPeer(m["auto_ban_unknown_peer"].toBool()); - - // Speed - // Global Rate Limits ---- a/src/webui/api/transfercontroller.cpp -+++ b/src/webui/api/transfercontroller.cpp -@@ -30,6 +30,7 @@ - - #include - -+#include "base/logger.h" - #include "base/bittorrent/session.h" - - const char KEY_TRANSFER_DLSPEED[] = "dl_info_speed"; -@@ -111,3 +112,37 @@ void TransferController::speedLimitsMode - { - setResult(QString::number(BitTorrent::Session::instance()->isAltGlobalSpeedLimitEnabled())); - } -+ -+void TransferController::tempblockPeerAction() -+{ -+ checkParams({"ip"}); -+ QString ip = params()["ip"]; -+ boost::system::error_code ec; -+ boost::asio::ip::address addr = boost::asio::ip::address::from_string(ip.toStdString(), ec); -+ bool isBanned = BitTorrent::Session::instance()->checkAccessFlags(QString::fromStdString(addr.to_string())); -+ -+ if (ip.isEmpty()) { -+ setResult(QLatin1String("IP field should not be empty.")); -+ return; -+ } -+ -+ if (ec) { -+ setResult(QLatin1String("The given IP address is not valid.")); -+ return; -+ } -+ -+ if (isBanned) { -+ setResult(QLatin1String("The given IP address already exists.")); -+ return; -+ } -+ -+ BitTorrent::Session::instance()->tempblockIP(ip); -+ Logger::instance()->addMessage(tr("Peer '%1' banned via Web API.").arg(ip)); -+ setResult(QLatin1String("Done.")); -+} -+ -+void TransferController::resetIPFilterAction() -+{ -+ BitTorrent::Session::instance()->eraseIPFilter(); -+ setResult(QLatin1String("Erased.")); -+} ---- a/src/webui/api/transfercontroller.h -+++ b/src/webui/api/transfercontroller.h -@@ -46,4 +46,6 @@ private slots: - void downloadLimitAction(); - void setUploadLimitAction(); - void setDownloadLimitAction(); -+ void tempblockPeerAction(); -+ void resetIPFilterAction(); - }; ---- a/src/webui/www/private/preferences_content.html -+++ b/src/webui/www/private/preferences_content.html -@@ -377,6 +377,8 @@ - - - -+ -+ - - - -@@ -1252,6 +1254,7 @@ - $('ipfilter_text').setProperty('value', pref.ip_filter_path); - $('ipfilter_trackers_checkbox').setProperty('checked', pref.ip_filter_trackers); - $('banned_IPs_textarea').setProperty('value', pref.banned_IPs); -+ $('auto_ban_unknown_peer_checkbox').setProperty('checked', pref.auto_ban_unknown_peer); - updateFilterSettings(); - - // Speed tab -@@ -1502,6 +1505,7 @@ - settings.set('ip_filter_path', $('ipfilter_text').getProperty('value')); - settings.set('ip_filter_trackers', $('ipfilter_trackers_checkbox').getProperty('checked')); - settings.set('banned_IPs', $('banned_IPs_textarea').getProperty('value')); -+ settings.set('auto_ban_unknown_peer', $('auto_ban_unknown_peer_checkbox').getProperty('checked')); - - // Speed tab - // Global Rate Limits From 12b558bbd4f82e3a47b61954b46fb0c889724d09 Mon Sep 17 00:00:00 2001 From: lean Date: Thu, 9 Apr 2020 00:30:15 +0800 Subject: [PATCH 09/27] amule: dyn linked --- package/lean/amule/Makefile | 4 ++-- .../lean/luci-app-music-remote-center/Makefile | 2 +- .../root/opt/music/Treat - idiots.mp3 | Bin 194100 -> 0 bytes target/linux/x86/Makefile | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) delete mode 100644 package/lean/luci-app-music-remote-center/root/opt/music/Treat - idiots.mp3 diff --git a/package/lean/amule/Makefile b/package/lean/amule/Makefile index 50ccca8a30..4fcdfd6045 100644 --- a/package/lean/amule/Makefile +++ b/package/lean/amule/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=aMule PKG_VERSION:=2.3.2 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_REV=4b87b20 @@ -28,7 +28,7 @@ include $(INCLUDE_DIR)/nls.mk define Package/amule/config config AMULE_CRYPTOPP_STATIC_LINKING bool "Link libcryptopp statically" - default y + default n endef define Package/amule diff --git a/package/lean/luci-app-music-remote-center/Makefile b/package/lean/luci-app-music-remote-center/Makefile index 9b65a68bb6..c409099259 100644 --- a/package/lean/luci-app-music-remote-center/Makefile +++ b/package/lean/luci-app-music-remote-center/Makefile @@ -10,7 +10,7 @@ LUCI_TITLE:=Luci for Music Remote Center LUCI_DEPENDS:=+alsa-utils +forked-daapd LUCI_PKGARCH:=all PKG_VERSION:=1 -PKG_RELEASE:=5 +PKG_RELEASE:=6 include $(TOPDIR)/feeds/luci/luci.mk diff --git a/package/lean/luci-app-music-remote-center/root/opt/music/Treat - idiots.mp3 b/package/lean/luci-app-music-remote-center/root/opt/music/Treat - idiots.mp3 deleted file mode 100644 index 616b70611a1bc2fd102ad4dcc523bb2bf99efc94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194100 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 &oefvH$vg?Fb-4NC@Mm<~ozj@{#(;z33JGA)&@2 zO3kM9OOiGLIGKZbY(nw!v3SF@uULzhSv>Zsy~D8_z+kzKe18>U6ujkVY!U!1D`Eta za-DmmFRjdrmDJG{LB!}Q;dY}9ipG*64O8>FcWb)(A=LSZVA3t+Su#(^-Wyie*z`r_ zFxQfHB=udn1sg@#!qJ?p@^_WsPYSPDwta(kQ=^pUqmM?mHoY~#Sokf?iweU*gAc*`LrzCK!~42kE>C7Egsx?4SO&hkd~-COSF^N zqSbeBs=)0*Sdwe+;)I-+uvo0+Dz7!X?+8I!LWt#x1^4-^y6$w*$n}K&s>HsP?FNHy z7tb-Qngn9YRj@dKF-t-R){9=3b>TT8Es(n=`om}2gXPYKWZkDexHxIFm`A(j*8c~) zBY+g-wZs2{8Rtj1qzJf)2)TS8l)l%wIdf!wp>gPQQVCTF3t7y#4W(A`I_{cpI1Wl` zpjhAS289Yi2hD!XU~i_h(2WlAP_*-3q2C@hTFd@c@QGI+Ao6xDWLp*vTqWMbdL!LO z@QH+4{&>$=F7Om*E*Z=%Oufa-7i&(vBxYl3qFqIZ5=E%gCrA=(I&sNvd4_9-ps2CE z`7>L}iE^xk$<)xDgf7f7`(UWD5uljU8uO8Hl`KAwqP9CUp>V81-HXa{Jy}#~GH-gJG@UwPU@pGYH2@yd1_1(Ck*a< z`6wFeLf5r7r&7V0XNN2H#)c+X$P&g>PD4DfdEWaIODDs=Iei-$2YGC}haa1sE-6Jv zhTpw{y}Kpj78tYXBZu!`jA%|@)Gd=o>TfPRm`Wz@dQ_c+=KIF(Ldh~u+O3sz#dYs~ z4!F_S6${=jl4-(@=WCv{Wd^9-3MxLM>%iqo0mL+DtMn>oqlb@rH*tOC3x%>>FYlUX zXJ#GzPO{0ld<=K> zbA3##E*|>c-yf;~{+ptZw~$!~sxXGxxl2RQ-M1d&aSR%|t-d(%dXxqT%`~PEMo>Pw z?61NN(PiqGsX6dGt}2bz{5f zEzuQ5Yn{1SsAPq|S^GCqrQxc*M8~y<1qPBk0D`PL> z4K3ji+-4lOV5a9_etU&OV~K-!-8(NJl)mez@sfRKS6uu~sQ2ujV9W2yyRW}E#glXG z+*dk=-%i&^tS3i+qeI&#u1`+s&n-6St)4KH3S0}TX8rSCj9!cQ`l_0ufK9J*Mw7L2 zgtlmvkpU#H%t(O;FYaN~Ur|iQ6ma`UC^sKY9{~wP>qFA~YMhT(O{=oyBdMa*gyfwn z)Wlqq`D9!O9fXk_CE93k!BC%ILqlNr^K9^IfRX{cxT3nyljDs?@YA5tAjZW|n2Edc zz_X$D?DTEy%>F+detZYPSGDlmH$k=BjfZ@mF@V|ulacrMf8XcQSg0BOvNOl2uqbRa zvCb>4{F26^t+BFA8|V8H8RD5HKs9biG!dsX#AABj}q^h z2UCLjZ)uBEcIlYTi&CV!N4WOp1XUL?0l%o_GbZK8|N4=qJTZNm

n;1;=E$5Xz!A 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

52hKDEtfWfgA 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%0D#}agnY;4Z0SOM{E-bj^AzB$y#sz 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 diff --git a/target/linux/x86/Makefile b/target/linux/x86/Makefile index f2cb459e8e..5599d02f43 100644 --- a/target/linux/x86/Makefile +++ b/target/linux/x86/Makefile @@ -21,8 +21,9 @@ include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += partx-utils mkf2fs fdisk e2fsprogs wpad kmod-usb-hid \ kmod-ath5k kmod-ath9k kmod-ath9k-htc kmod-ath10k kmod-rt2800-usb kmod-e1000e kmod-igb kmod-igbvf kmod-ixgbe kmod-pcnet32 kmod-tulip kmod-vmxnet3 kmod-i40e kmod-i40evf kmod-r8125 kmod-8139cp kmod-8139too kmod-fs-f2fs \ -htop lm-sensors autocore automount autosamba luci-app-ipsec-vpnd luci-proto-bonding luci-app-unblockmusic luci-app-zerotier luci-app-xlnetacc ddns-scripts_aliyun ddns-scripts_dnspod ca-certificates luci-app-airplay2 luci-app-music-remote-center \ -ath10k-firmware-qca988x ath10k-firmware-qca9888 ath10k-firmware-qca9984 brcmfmac-firmware-43602a1-pcie kmod-fs-cifs kmod-nls-utf8 \ +htop lm-sensors autocore automount autosamba luci-app-ipsec-vpnd luci-proto-bonding luci-app-unblockmusic luci-app-zerotier luci-app-xlnetacc ddns-scripts_aliyun ddns-scripts_dnspod ca-certificates \ +luci-app-airplay2 luci-app-music-remote-center luci-app-qbittorrent luci-app-amule luci-app-openvpn-server \ +ath10k-firmware-qca988x ath10k-firmware-qca9888 ath10k-firmware-qca9984 brcmfmac-firmware-43602a1-pcie \ kmod-sound-hda-core kmod-sound-hda-codec-realtek kmod-sound-hda-codec-via kmod-sound-via82xx kmod-sound-hda-intel kmod-sound-hda-codec-hdmi kmod-sound-i8x0 kmod-usb-audio \ kmod-usb-net kmod-usb-net-asix kmod-usb-net-asix-ax88179 kmod-usb-net-rtl8150 kmod-usb-net-rtl8152 From df49785a2d9a750f3d0ad605b2637975f33a9861 Mon Sep 17 00:00:00 2001 From: lean Date: Thu, 9 Apr 2020 00:44:22 +0800 Subject: [PATCH 10/27] openwrt-ci.yml: update --- .github/workflows/openwrt-ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/openwrt-ci.yml b/.github/workflows/openwrt-ci.yml index 814f682156..5ee6b72777 100644 --- a/.github/workflows/openwrt-ci.yml +++ b/.github/workflows/openwrt-ci.yml @@ -12,12 +12,15 @@ name: OpenWrt-CI on: schedule: - cron: 0 20 * * * + watch: + types: started jobs: build: runs-on: ubuntu-latest + if: github.event.repository.owner.id == github.event.sender.id steps: - name: Checkout @@ -80,5 +83,5 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@master with: - name: OpenWrt firmware + name: OpenWrt_firmware path: ./bin/targets/ From ae7a5d706026c70ff5236eef6d72211cfcac5642 Mon Sep 17 00:00:00 2001 From: dongjuanyong <38952488+dongjuanyong@users.noreply.github.com> Date: Thu, 9 Apr 2020 01:07:52 +0800 Subject: [PATCH 11/27] luci-app-ssr-plus: OpenWrt SNAPSHOT compatibility (#4154) * luci-app-ssr-plus: OpenWrt SNAPSHOT compatibility Fix #4143 * Modify getElementById to getElementsByName Luci modification for OpenWrt 19.07 or higher --- .../luasrc/view/shadowsocksr/ssrurl.htm | 142 +++++++++--------- .../root/usr/share/shadowsocksr/subscribe.lua | 2 +- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index 778de53bf2..e734af05a8 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -47,15 +47,15 @@ var s = document.getElementById(urlname + '-status'); if (!s) return false; - var v_server = document.getElementById('cbid.shadowsocksr.' + sid + '.server'); - var v_port = document.getElementById('cbid.shadowsocksr.' + sid + '.server_port'); - var v_protocol = document.getElementById('cbid.shadowsocksr.' + sid + '.protocol'); - var v_method = document.getElementById('cbid.shadowsocksr.' + sid + '.encrypt_method'); - var v_obfs = document.getElementById('cbid.shadowsocksr.' + sid + '.obfs'); - var v_password = document.getElementById('cbid.shadowsocksr.' + sid + '.password'); - var v_obfs_param = document.getElementById('cbid.shadowsocksr.' + sid + '.obfs_param'); - var v_protocol_param = document.getElementById('cbid.shadowsocksr.' + sid + '.protocol_param'); - var v_alias = document.getElementById('cbid.shadowsocksr.' + sid + '.alias'); + var v_server = document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0]; + var v_port = document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0]; + var v_protocol = document.getElementsByName('cbid.shadowsocksr.' + sid + '.protocol')[0]; + var v_method = document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method')[0]; + var v_obfs = document.getElementsByName('cbid.shadowsocksr.' + sid + '.obfs')[0]; + var v_password = document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0]; + var v_obfs_param = document.getElementsByName('cbid.shadowsocksr.' + sid + '.obfs_param')[0]; + var v_protocol_param = document.getElementsByName('cbid.shadowsocksr.' + sid + '.protocol_param')[0]; + var v_alias = document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0]; var ssr_str = v_server.value + ":" + v_port.value + ":" + v_protocol.value + ":" + @@ -104,8 +104,8 @@ if (ssu[0] == "ssr") { var sstr = b64decsafe(ssu[1]); var ploc = sstr.indexOf("/?"); - document.getElementById('cbid.shadowsocksr.' + sid + '.type').value = "ssr"; - document.getElementById('cbid.shadowsocksr.' + sid + '.type').dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "ssr"; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); var url0, param = ""; if (ploc > 0) { url0 = sstr.substr(0, ploc); @@ -123,17 +123,17 @@ pdict[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || ''); } } - document.getElementById('cbid.shadowsocksr.' + sid + '.server').value = ssm[1]; - document.getElementById('cbid.shadowsocksr.' + sid + '.server_port').value = ssm[2]; - document.getElementById('cbid.shadowsocksr.' + sid + '.protocol').value = ssm[3]; - document.getElementById('cbid.shadowsocksr.' + sid + '.encrypt_method').value = ssm[4]; - document.getElementById('cbid.shadowsocksr.' + sid + '.obfs').value = ssm[5]; - document.getElementById('cbid.shadowsocksr.' + sid + '.password').value = b64decsafe(ssm[6]); - document.getElementById('cbid.shadowsocksr.' + sid + '.obfs_param').value = dictvalue(pdict, 'obfsparam'); - document.getElementById('cbid.shadowsocksr.' + sid + '.protocol_param').value = dictvalue(pdict, 'protoparam'); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = ssm[1]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = ssm[2]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.protocol')[0].value = ssm[3]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method')[0].value = ssm[4]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.obfs')[0].value = ssm[5]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = b64decsafe(ssm[6]); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.obfs_param')[0].value = dictvalue(pdict, 'obfsparam'); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.protocol_param')[0].value = dictvalue(pdict, 'protoparam'); var rem = pdict['remarks']; if (typeof (rem) != 'undefined' && rem != '' && rem.length > 0) - document.getElementById('cbid.shadowsocksr.' + sid + '.alias').value = b64decutf8safe(rem); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = b64decutf8safe(rem); s.innerHTML = "导入ShadowsocksR配置信息成功"; return false; } else if (ssu[0] == "ss") { @@ -169,35 +169,35 @@ method = userInfo.substr(0, userInfoSplitIndex); password = userInfo.substr(userInfoSplitIndex + 1); } - document.getElementById('cbid.shadowsocksr.' + sid + '.type').value = "ss"; - document.getElementById('cbid.shadowsocksr.' + sid + '.type').dispatchEvent(event); - document.getElementById('cbid.shadowsocksr.' + sid + '.server').value = server; - document.getElementById('cbid.shadowsocksr.' + sid + '.server_port').value = port; - document.getElementById('cbid.shadowsocksr.' + sid + '.password').value = password || ""; - document.getElementById('cbid.shadowsocksr.' + sid + '.encrypt_method_ss').value = method || ""; - document.getElementById('cbid.shadowsocksr.' + sid + '.plugin').value = plugin || ""; - document.getElementById('cbid.shadowsocksr.' + sid + '.plugin_opts').value = pluginOpts || ""; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "ss"; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password || ""; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method || ""; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin || ""; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || ""; if (param != undefined) { - document.getElementById('cbid.shadowsocksr.' + sid + '.alias').value = decodeURI(param); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } s.innerHTML = "导入Shadowsocks配置信息成功"; } else { var sstr = b64decsafe(url0); - document.getElementById('cbid.shadowsocksr.' + sid + '.type').value = "ss"; - document.getElementById('cbid.shadowsocksr.' + sid + '.type').dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "ss"; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); var team = sstr.split('@'); console.log(param); var part1 = team[0].split(':'); var part2 = team[1].split(':'); - document.getElementById('cbid.shadowsocksr.' + sid + '.server').value = part2[0]; - document.getElementById('cbid.shadowsocksr.' + sid + '.server_port').value = part2[1]; - document.getElementById('cbid.shadowsocksr.' + sid + '.password').value = part1[1]; - document.getElementById('cbid.shadowsocksr.' + sid + '.encrypt_method_ss').value = part1[0]; - document.getElementById('cbid.shadowsocksr.' + sid + '.plugin').value = ""; - document.getElementById('cbid.shadowsocksr.' + sid + '.plugin_opts').value = ""; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = part2[0]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = part2[1]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = part1[1]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = part1[0]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = ""; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = ""; if (param != undefined) { - document.getElementById('cbid.shadowsocksr.' + sid + '.alias').value = decodeURI(param); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } s.innerHTML = "导入Shadowsocks配置信息成功"; } @@ -213,8 +213,8 @@ } var sstr = url0; - document.getElementById('cbid.shadowsocksr.' + sid + '.type').value = "trojan"; - document.getElementById('cbid.shadowsocksr.' + sid + '.type').dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan"; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); var team = sstr.split('@'); var password = team[0] var serverPart = team[1].split(':'); @@ -230,63 +230,63 @@ } } - document.getElementById('cbid.shadowsocksr.' + sid + '.server').value = serverPart[0]; - document.getElementById('cbid.shadowsocksr.' + sid + '.server_port').value = port; - document.getElementById('cbid.shadowsocksr.' + sid + '.password').value = password; - document.getElementById('cbid.shadowsocksr.' + sid + '.tls').checked = true; - document.getElementById('cbid.shadowsocksr.' + sid + '.tls').dispatchEvent(event); - document.getElementById('cbid.shadowsocksr.' + sid + '.tls_host').value = queryParam.peer || ''; - document.getElementById('cbid.shadowsocksr.' + sid + '.insecure').checked = queryParam.allowInsecure === '1'; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = serverPart[0]; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = queryParam.peer || ''; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = queryParam.allowInsecure === '1'; if (param != undefined) { - document.getElementById('cbid.shadowsocksr.' + sid + '.alias').value = decodeURI(param); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } s.innerHTML = "导入Trojan配置信息成功"; return false; } else if (ssu[0] == "vmess") { var sstr = b64DecodeUnicode(ssu[1]); var ploc = sstr.indexOf("/?"); - document.getElementById('cbid.shadowsocksr.' + sid + '.type').value = "v2ray"; - document.getElementById('cbid.shadowsocksr.' + sid + '.type').dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray"; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); var url0, param = ""; if (ploc > 0) { url0 = sstr.substr(0, ploc); param = sstr.substr(ploc + 2); } var ssm = JSON.parse(sstr); - document.getElementById('cbid.shadowsocksr.' + sid + '.alias').value = ssm.ps; - document.getElementById('cbid.shadowsocksr.' + sid + '.server').value = ssm.add; - document.getElementById('cbid.shadowsocksr.' + sid + '.server_port').value = ssm.port; - document.getElementById('cbid.shadowsocksr.' + sid + '.alter_id').value = ssm.aid; - document.getElementById('cbid.shadowsocksr.' + sid + '.vmess_id').value = ssm.id; - document.getElementById('cbid.shadowsocksr.' + sid + '.transport').value = ssm.net; - document.getElementById('cbid.shadowsocksr.' + sid + '.transport').dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = ssm.ps; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = ssm.add; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = ssm.port; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.alter_id')[0].value = ssm.aid; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.vmess_id')[0].value = ssm.id; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value = ssm.net; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event); if (ssm.net == "tcp") { - document.getElementById('cbid.shadowsocksr.' + sid + '.http_host').value = ssm.host; - document.getElementById('cbid.shadowsocksr.' + sid + '.http_path').value = ssm.path; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = ssm.host; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = ssm.path; } if (ssm.net == "ws") { - document.getElementById('cbid.shadowsocksr.' + sid + '.ws_host').value = ssm.host; - document.getElementById('cbid.shadowsocksr.' + sid + '.ws_path').value = ssm.path; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_host')[0].value = ssm.host; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_path')[0].value = ssm.path; } if (ssm.net == "h2") { - document.getElementById('cbid.shadowsocksr.' + sid + '.h2_host').value = ssm.host; - document.getElementById('cbid.shadowsocksr.' + sid + '.h2_path').value = ssm.path; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = ssm.host; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = ssm.path; } if (ssm.net == "quic") { - document.getElementById('cbid.shadowsocksr.' + sid + '.quic_security').value = ssm.securty; - document.getElementById('cbid.shadowsocksr.' + sid + '.quic_key').value = ssm.key; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = ssm.securty; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = ssm.key; } if (ssm.net == "kcp") { - document.getElementById('cbid.shadowsocksr.' + sid + '.kcp_guise').value = ssm.type; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = ssm.type; } if (ssm.tls == "tls") { - document.getElementById('cbid.shadowsocksr.' + sid + '.tls').checked = true; - document.getElementById('cbid.shadowsocksr.' + sid + '.tls').dispatchEvent(event); - document.getElementById('cbid.shadowsocksr.' + sid + '.tls_host').value = ssm.host; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = ssm.host; } - document.getElementById('cbid.shadowsocksr.' + sid + '.mux').checked = true; - document.getElementById('cbid.shadowsocksr.' + sid + '.mux').dispatchEvent(event); + document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].checked = true; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].dispatchEvent(event); s.innerHTML = "导入V2ray配置信息成功"; return false; } diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index 0ae7bbe688..7b05ce5cfc 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -19,7 +19,7 @@ local cache = {} local nodeResult = setmetatable({}, { __index = cache }) -- update result local name = 'shadowsocksr' local uciType = 'servers' -local ucic = uci.cursor() +local ucic = luci.model.uci.cursor() local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) From 2cdcee23fb22f62f9ccceaf6c3c9393ba09195a9 Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Thu, 9 Apr 2020 14:00:56 +0800 Subject: [PATCH 12/27] ipq40xx: device: switch to ath10k-ct (#4239) --- target/linux/ipq40xx/image/Makefile | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile index de624f0255..197d4a03f6 100644 --- a/target/linux/ipq40xx/image/Makefile +++ b/target/linux/ipq40xx/image/Makefile @@ -68,7 +68,7 @@ define Device/asus_map-ac2200 DEVICE_MODEL := Lyra (MAP-AC2200) DEVICE_DTS := qcom-ipq4019-map-ac2200 IMAGES := sysupgrade.bin - DEVICE_PACKAGES := ath10k-firmware-qca9888 kmod-ath3k + DEVICE_PACKAGES := ath10k-firmware-qca9888-ct kmod-ath3k endef TARGET_DEVICES += asus_map-ac2200 @@ -91,8 +91,8 @@ define Device/asus_rt-ac58u KERNEL_INITRAMFS := $$(KERNEL) | uImage none KERNEL_INITRAMFS_SUFFIX := -factory.trx IMAGES := sysupgrade.bin - DEVICE_PACKAGES := -kmod-ath10k -ath10k-firmware-qca4019 \ - kmod-ath10k-ct-smallbuffers ath10k-firmware-qca4019-ct kmod-usb-ledtrig-usbport + DEVICE_PACKAGES := -kmod-ath10k-ct kmod-ath10k-ct-smallbuffers \ + kmod-usb-ledtrig-usbport endef TARGET_DEVICES += asus_rt-ac58u @@ -110,7 +110,7 @@ define Device/asus_rt-acrh17 KERNEL_INITRAMFS := $$(KERNEL) | uImage none KERNEL_INITRAMFS_SUFFIX := -factory.trx IMAGES := sysupgrade.bin - DEVICE_PACKAGES := ipq-wifi-rt-acrh17 ath10k-firmware-qca9984 + DEVICE_PACKAGES := ipq-wifi-rt-acrh17 ath10k-firmware-qca9984-ct endef TARGET_DEVICES += asus_rt-acrh17 @@ -231,7 +231,7 @@ define Device/meraki_mr33 BLOCKSIZE := 128k PAGESIZE := 2048 IMAGES = sysupgrade.bin - DEVICE_PACKAGES := -swconfig ath10k-firmware-qca9887 + DEVICE_PACKAGES := -swconfig ath10k-firmware-qca9887-ct endef TARGET_DEVICES += meraki_mr33 @@ -300,7 +300,7 @@ define Device/openmesh_a62 IMAGES = factory.bin sysupgrade.bin IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=A62 IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata - DEVICE_PACKAGES := ath10k-firmware-qca9888 uboot-envtools + DEVICE_PACKAGES := ath10k-firmware-qca9888-ct uboot-envtools endef TARGET_DEVICES += openmesh_a62 @@ -392,8 +392,7 @@ define Device/zyxel_wre6606 DEVICE_DTS_CONFIG := config@4 IMAGES := sysupgrade.bin IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata - DEVICE_PACKAGES := -kmod-ath10k -ath10k-firmware-qca4019 \ - kmod-ath10k-ct-smallbuffers ath10k-firmware-qca4019-ct + DEVICE_PACKAGES := -kmod-ath10k-ct kmod-ath10k-ct-smallbuffers endef TARGET_DEVICES += zyxel_wre6606 From 3dd0a3e1771c4c01a02a998382be1057376724a2 Mon Sep 17 00:00:00 2001 From: xinxijishuwyq Date: Thu, 9 Apr 2020 14:01:14 +0800 Subject: [PATCH 13/27] simple-obfs: bump to latest version to Fix FTBFS under GCC-9 (#4241) Signed-off-by: Ken Wong --- package/lean/simple-obfs/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/lean/simple-obfs/Makefile b/package/lean/simple-obfs/Makefile index e5b0c9b365..744f47e13d 100644 --- a/package/lean/simple-obfs/Makefile +++ b/package/lean/simple-obfs/Makefile @@ -9,11 +9,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=simple-obfs PKG_VERSION:=0.0.5 -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/shadowsocks/simple-obfs.git -PKG_SOURCE_VERSION:=df8089c159bc63d4a10328b371177a96cb8d9f0b +PKG_SOURCE_VERSION:=486bebd9208539058e57e23a12f23103016e09b4 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION) PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz From 593d812a474564f09ebe561b0272e501dbd48a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=88=E6=9C=9B=E6=98=9F=E7=A9=BA?= <61259428+swxk521@users.noreply.github.com> Date: Thu, 9 Apr 2020 14:01:58 +0800 Subject: [PATCH 14/27] Update Kcptun (#4243) --- package/lean/kcptun/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/lean/kcptun/Makefile b/package/lean/kcptun/Makefile index f375f5d954..1e8d20ce7c 100644 --- a/package/lean/kcptun/Makefile +++ b/package/lean/kcptun/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=kcptun -PKG_VERSION:=20200321 +PKG_VERSION:=20200409 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/xtaci/kcptun/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=450e586528bd7b2e586605e3a664f77ebd9baa869918fcc6d6a41f84d4cfb4fd +PKG_HASH:=312b8f438549225dfd1eac95444dd6a4c50610578ddcf7ff21e19c73a855d4bc PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE.md From ce326f078bede954be9ade6811409acca77b29e5 Mon Sep 17 00:00:00 2001 From: ZhenYu Date: Fri, 10 Apr 2020 00:43:01 +0800 Subject: [PATCH 15/27] Update openwrt-ci.yml (#4254) --- .github/workflows/openwrt-ci.yml | 45 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/.github/workflows/openwrt-ci.yml b/.github/workflows/openwrt-ci.yml index 5ee6b72777..2e1641923a 100644 --- a/.github/workflows/openwrt-ci.yml +++ b/.github/workflows/openwrt-ci.yml @@ -12,22 +12,22 @@ name: OpenWrt-CI on: schedule: - cron: 0 20 * * * - watch: - types: started + push: + tags: + - '*' jobs: - build: + build_openwrt: - runs-on: ubuntu-latest - if: github.event.repository.owner.id == github.event.sender.id + name: Build OpenWrt and release + runs-on: ubuntu-18.04 steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v2 with: ref: master - fetch-depth: 1000000 - name: Space cleanup env: @@ -41,15 +41,6 @@ jobs: sudo -E apt-get -y autoremove --purge sudo -E apt-get clean - # 利用挂载在 /mnt/ 的 14G 额外空间: - # sudo mkdir -p -m 777 /mnt/openwrt/bin /mnt/openwrt/build_dir/host /mnt/openwrt/build_dir/hostpkg /mnt/openwrt/dl /mnt/openwrt/feeds /mnt/openwrt/staging_dir - # ln -s /mnt/openwrt/bin ./bin - # mkdir -p ./build_dir/host && ln -s /mnt/openwrt/build_dir/host ./build_dir/host - # mkdir -p ./build_dir/host && ln -s /mnt/openwrt/build_dir/hostpkg ./build_dir/hostpkg - # ln -s /mnt/openwrt/dl ./dl - # ln -s /mnt/openwrt/feeds ./feeds - # ln -s /mnt/openwrt/staging_dir ./staging_dir - df -h - name: Update feeds @@ -85,3 +76,25 @@ jobs: with: name: OpenWrt_firmware path: ./bin/targets/ + + - name: Create release + if: github.event == 'push' + id: create_release + uses: actions/create-release@v1.0.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: false + prerelease: false + + - name: Upload release asset + if: github.event == 'push' + id: upload-release-asset + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./bin/targets/*/*/ From a10390cc21a83cfc25a252d81f1cbd8ec3bc6a1a Mon Sep 17 00:00:00 2001 From: Mattraks <16359027+Mattraks@users.noreply.github.com> Date: Sat, 11 Apr 2020 21:53:11 +0800 Subject: [PATCH 16/27] luci-app-ssr-plus:Code optimization and Fix Bug (#4253) * luci-app-ssr-plus:Code optimization and Fix Bug * luci-app-ssr-plus:Adjust reference data location --- package/lean/luci-app-ssr-plus/Makefile | 26 +- .../luasrc/controller/shadowsocksr.lua | 124 +- .../model/cbi/shadowsocksr/advanced.lua | 1 + .../model/cbi/shadowsocksr/client-config.lua | 274 +++-- .../luasrc/model/cbi/shadowsocksr/client.lua | 6 +- .../luasrc/model/cbi/shadowsocksr/control.lua | 67 +- .../luasrc/model/cbi/shadowsocksr/log.lua | 26 +- .../model/cbi/shadowsocksr/server-config.lua | 57 +- .../luasrc/model/cbi/shadowsocksr/server.lua | 77 +- .../luasrc/model/cbi/shadowsocksr/servers.lua | 61 +- .../luasrc/model/cbi/shadowsocksr/status.lua | 120 +- .../luasrc/view/shadowsocksr/certupload.htm | 4 +- .../luasrc/view/shadowsocksr/checkport.htm | 10 - .../luasrc/view/shadowsocksr/server_list.htm | 10 - .../luasrc/view/shadowsocksr/ssrurl.htm | 9 - .../luci-app-ssr-plus/po/zh-cn/ssr-plus.po | 12 + .../root/etc/config/shadowsocksr | 17 +- .../root/etc/dnsmasq.ssr/gfw_list.conf | 266 +---- .../root/etc/init.d/shadowsocksr | 1038 ++++++++--------- .../root/etc/{ => ssr}/china_ssr.txt | 23 +- .../root/etc/{config => ssr}/netflix.list | 0 .../root/etc/{config => ssr}/netflixip.list | 0 .../root/etc/uci-defaults/luci-ssr-plus | 10 +- .../luci-app-ssr-plus/root/usr/bin/ssr-ad | 10 +- .../luci-app-ssr-plus/root/usr/bin/ssr-gfw | 5 +- .../root/usr/bin/ssr-monitor | 39 +- .../luci-app-ssr-plus/root/usr/bin/ssr-rules | 53 +- .../luci-app-ssr-plus/root/usr/bin/ssr-switch | 7 +- .../root/usr/share/shadowsocksr/chinaipset.sh | 6 +- .../usr/share/shadowsocksr/genred2config.sh | 117 +- .../share/shadowsocksr/gentrojanconfig.lua | 3 +- .../usr/share/shadowsocksr/genv2config.lua | 3 +- .../root/usr/share/shadowsocksr/gfw2ipset.sh | 37 +- .../usr/share/shadowsocksr/ssrplusupdate.sh | 6 +- .../root/usr/share/shadowsocksr/subscribe.lua | 270 +++-- .../root/usr/share/shadowsocksr/update.lua | 137 +-- 36 files changed, 1350 insertions(+), 1581 deletions(-) rename package/lean/luci-app-ssr-plus/root/etc/{ => ssr}/china_ssr.txt (99%) rename package/lean/luci-app-ssr-plus/root/etc/{config => ssr}/netflix.list (100%) rename package/lean/luci-app-ssr-plus/root/etc/{config => ssr}/netflixip.list (100%) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index aaef6b01a4..edf07317d5 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus -PKG_VERSION:=175 -PKG_RELEASE:=5 +PKG_VERSION:=176 +PKG_RELEASE:=1 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) @@ -38,10 +38,10 @@ define Package/$(PKG_NAME) SECTION:=luci CATEGORY:=LuCI SUBMENU:=3. Applications - TITLE:=SS/SSR/V2Ray/Trojan LuCI interface + TITLE:=SS/SSR/V2Ray/Trojan/Socks5/Tun LuCI interface PKGARCH:=all DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +pdnsd-alt +wget +lua +libuci-lua \ - +microsocks +dns2socks +shadowsocks-libev-ss-local +shadowsocksr-libev-ssr-local +shadowsocks-libev-ss-redir +simple-obfs +tcpping \ + +microsocks +dns2socks +shadowsocks-libev-ss-local +shadowsocksr-libev-ssr-local +shadowsocks-libev-ss-redir +simple-obfs +tcpping +resolveip \ +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_plugin:v2ray-plugin \ +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \ +PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \ @@ -58,23 +58,17 @@ define Build/Compile endef define Package/$(PKG_NAME)/conffiles -/etc/ssr_ip -/etc/china_ssr.txt /etc/config/shadowsocksr -/etc/config/white.list -/etc/config/black.list -/etc/config/netflix.list -/etc/dnsmasq.ssr/ad.conf -/etc/dnsmasq.ssr/gfw_list.conf +/etc/ssr/netflix.list +/etc/ssr/netflixip.list endef define Package/$(PKG_NAME)/install - $(INSTALL_DIR) $(1)/etc - $(INSTALL_DATA) ./root/etc/china_ssr.txt $(1)/etc/china_ssr.txt + $(INSTALL_DIR) $(1)/etc/ssr + $(INSTALL_DATA) ./root/etc/ssr/* $(1)/etc/ssr/ $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./root/etc/config/shadowsocksr $(1)/etc/config/shadowsocksr - $(INSTALL_DATA) ./root/etc/config/*.list $(1)/etc/config/ $(INSTALL_DIR) $(1)/etc/dnsmasq.oversea $(INSTALL_DATA) ./root/etc/dnsmasq.oversea/* $(1)/etc/dnsmasq.oversea/ @@ -110,8 +104,8 @@ endef define Package/$(PKG_NAME)/postrm #!/bin/sh -rm -rf /etc/china_ssr.txt /etc/dnsmasq.ssr /etc/dnsmasq.oversea /etc/config/shadowsocksr /etc/config/black.list \ - /etc/config/gfw.list /etc/config/white.list /etc/config/netflix.list /etc/config/netflixip.list 2>/dev/null +rm -rf /etc/ssl/private /etc/dnsmasq.ssr /etc/dnsmasq.oversea /etc/ssr /etc/config/shadowsocksr /etc/china_ssr.txt /etc/config/black.list /etc/config/white.list \ +/etc/config/netflix.list /etc/config/netflixip.list endef $(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua index 3176ad4562..dfe74557fc 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua @@ -1,6 +1,5 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. - module("luci.controller.shadowsocksr", package.seeall) function index() @@ -74,105 +73,50 @@ function refresh_data() local set = luci.http.formvalue("set") local uci = luci.model.uci.cursor() local icount = 0 - if set == "gfw_data" then - refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'gfwlist_url', 'https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt') .. ' > /tmp/gfw.b64' + local retstring = 0 + local function update(url, file, type, file2) + local Num = 1 + refresh_cmd = "wget-ssl --no-check-certificate -t 3 -T 10 -O- " .. url .. " > /tmp/ssr-update." .. type sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") if sret == 0 then - luci.sys.call("/usr/bin/ssr-gfw") - icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l") - if tonumber(icount) > 1000 then - if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then - oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf") - luci.sys.exec("cp -f /tmp/gfwnew.txt /tmp/dnsmasq.ssr/gfw_list.conf") - luci.sys.call("/etc/init.d/dnsmasq restart") - retstring = tostring(tonumber(icount)/2) - else - retstring = "0" - end - else - retstring = "-1" + if type == "gfw_data" then + luci.sys.call("/usr/bin/ssr-gfw " .. type) + Num = 2 + end + if type == "ad_data" then + luci.sys.call("/usr/bin/ssr-ad " .. type) + end + local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/ssr-update." .. type .. "' ] && md5sum /tmp/ssr-update." .. type .. " | awk '{print $1}')") + local old_md5 = luci.sys.exec("echo -n $([ -f '" .. file .. "' ] && md5sum " .. file .. " | awk '{print $1}')") + if new_md5 == old_md5 then + retstring = "0" + else + icount = luci.sys.exec("cat /tmp/ssr-update." .. type .. " | wc -l") + luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file) + if file2 then luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file2) end + retstring = tostring(tonumber(icount)/Num) + if type == "gfw_data" or type == "ad_data" then + luci.sys.exec("/usr/share/shadowsocksr/gfw2ipset.sh gfw_data") + else + luci.sys.exec("/etc/init.d/shadowsocksr restart &") + end end - luci.sys.exec("rm -f /tmp/gfwnew.txt") else retstring = "-1" end + luci.sys.exec("rm -f /tmp/ssr-update." .. type) + end + if set == "gfw_data" then + update(uci:get_first("shadowsocksr", "global", "gfwlist_url", "https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt"), "/etc/dnsmasq.ssr/gfw_list.conf", set, "/tmp/dnsmasq.ssr/gfw_list.conf") end if set == "ip_data" then - refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'chnroute_url', 'https://ispip.clang.cn/all_cn.txt') .. " > /tmp/china_ssr.txt" - sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") - icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") - if sret == 0 and tonumber(icount) > 1000 then - if nixio.fs.access("/etc/china_ssr.txt") then - oldcount = luci.sys.exec("cat /etc/china_ssr.txt | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt") - luci.sys.exec("/etc/init.d/shadowsocksr restart &") - retstring = tostring(tonumber(icount)) - else - retstring = "0" - end - else - retstring = "-1" - end - luci.sys.exec("rm -f /tmp/china_ssr.txt") - end - if set == "nfip_data" then - refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'nfip_url','https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt') .." > /tmp/netflixip.list" - sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") - icount = luci.sys.exec("cat /tmp/netflixip.list | wc -l") - if sret == 0 and tonumber(icount) > 5 then - if nixio.fs.access("/etc/config/netflixip.list") then - oldcount = luci.sys.exec("cat /etc/config/netflixip.list | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/netflixip.list /etc/config/netflixip.list") - luci.sys.exec("/etc/init.d/shadowsocksr restart &") - retstring = tostring(tonumber(icount)) - else - retstring = "0" - end - else - retstring = "-1" - end - luci.sys.exec("rm -f /tmp/netflixip.list") + update(uci:get_first("shadowsocksr", "global", "chnroute_url","https://ispip.clang.cn/all_cn.txt"), "/etc/ssr/china_ssr.txt", set) end if set == "ad_data" then - refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'adblock_url','https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt') .." > /tmp/adnew.conf" - sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") - if sret == 0 then - luci.sys.call("/usr/bin/ssr-ad") - icount = luci.sys.exec("cat /tmp/ad.conf | wc -l") - if tonumber(icount) > 100 then - if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then - oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf") - luci.sys.exec("cp -f /tmp/ad.conf /tmp/dnsmasq.ssr/ad.conf") - luci.sys.call("/etc/init.d/dnsmasq restart") - retstring = tostring(tonumber(icount)) - else - retstring = "0" - end - else - retstring = "-1" - end - luci.sys.exec("rm -f /tmp/ad.conf") - else - retstring = "-1" - end + update(uci:get_first("shadowsocksr", "global", "adblock_url","https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt"), "/etc/dnsmasq.ssr/ad.conf", set, "/tmp/dnsmasq.ssr/ad.conf") + end + if set == "nfip_data" then + update(uci:get_first("shadowsocksr", "global", "nfip_url","https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt"), "/etc/ssr/netflixip.list", set) end luci.http.prepare_content("application/json") luci.http.write_json({ret = retstring,retcount = icount}) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua index d7908e5e6e..ff05ae3db2 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua @@ -1,3 +1,4 @@ +require "luci.model.uci" local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() local server_table = {} diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index f42822f580..48e113359a 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -1,108 +1,105 @@ -- Copyright (C) 2017 yushi studio github.com/ywb94 -- Licensed to the public under the GNU General Public License v3. - +require "luci.model.uci" +require "nixio.fs" +require "luci.sys" +require "luci.http" local m, s, o,kcp_enable local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() -local fs = require "nixio.fs" -local sys = require "luci.sys" local sid = arg[1] local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid") -local http = require "luci.http" local function isKcptun(file) - if not fs.access(file, "rwx", "rx", "rx") then - fs.chmod(file, 755) + if not nixio.fs.access(file, "rwx", "rx", "rx") then + nixio.fs.chmod(file, 755) end - - local str = sys.exec(file .. " -v | awk '{printf $1}'") + local str = uci.sys.exec(file .. " -v | awk '{printf $1}'") return (str:lower() == "kcptun") end - local server_table = {} local encrypt_methods = { - "none", - "table", - "rc4", - "rc4-md5-6", - "rc4-md5", - "aes-128-cfb", - "aes-192-cfb", - "aes-256-cfb", - "aes-128-ctr", - "aes-192-ctr", - "aes-256-ctr", - "bf-cfb", - "camellia-128-cfb", - "camellia-192-cfb", - "camellia-256-cfb", - "cast5-cfb", - "des-cfb", - "idea-cfb", - "rc2-cfb", - "seed-cfb", - "salsa20", - "chacha20", - "chacha20-ietf", +"none", +"table", +"rc4", +"rc4-md5-6", +"rc4-md5", +"aes-128-cfb", +"aes-192-cfb", +"aes-256-cfb", +"aes-128-ctr", +"aes-192-ctr", +"aes-256-ctr", +"bf-cfb", +"camellia-128-cfb", +"camellia-192-cfb", +"camellia-256-cfb", +"cast5-cfb", +"des-cfb", +"idea-cfb", +"rc2-cfb", +"seed-cfb", +"salsa20", +"chacha20", +"chacha20-ietf", } local encrypt_methods_ss = { - -- aead - "aes-128-gcm", - "aes-192-gcm", - "aes-256-gcm", - "chacha20-ietf-poly1305", - "xchacha20-ietf-poly1305", - -- stream - "table", - "rc4", - "rc4-md5", - "aes-128-cfb", - "aes-192-cfb", - "aes-256-cfb", - "aes-128-ctr", - "aes-192-ctr", - "aes-256-ctr", - "bf-cfb", - "camellia-128-cfb", - "camellia-192-cfb", - "camellia-256-cfb", - "salsa20", - "chacha20", - "chacha20-ietf", +-- aead +"aes-128-gcm", +"aes-192-gcm", +"aes-256-gcm", +"chacha20-ietf-poly1305", +"xchacha20-ietf-poly1305", +-- stream +"table", +"rc4", +"rc4-md5", +"aes-128-cfb", +"aes-192-cfb", +"aes-256-cfb", +"aes-128-ctr", +"aes-192-ctr", +"aes-256-ctr", +"bf-cfb", +"camellia-128-cfb", +"camellia-192-cfb", +"camellia-256-cfb", +"salsa20", +"chacha20", +"chacha20-ietf", } local protocol = { - "origin", - "verify_deflate", - "auth_sha1_v4", - "auth_aes128_sha1", - "auth_aes128_md5", - "auth_chain_a", - "auth_chain_b", - "auth_chain_c", - "auth_chain_d", - "auth_chain_e", - "auth_chain_f", +"origin", +"verify_deflate", +"auth_sha1_v4", +"auth_aes128_sha1", +"auth_aes128_md5", +"auth_chain_a", +"auth_chain_b", +"auth_chain_c", +"auth_chain_d", +"auth_chain_e", +"auth_chain_f", } obfs = { - "plain", - "http_simple", - "http_post", - "random_head", - "tls1.2_ticket_auth", +"plain", +"http_simple", +"http_post", +"random_head", +"tls1.2_ticket_auth", } local securitys = { - "auto", - "none", - "aes-128-gcm", - "chacha20-poly1305" +"auto", +"none", +"aes-128-gcm", +"chacha20-poly1305" } - m = Map(shadowsocksr, translate("Edit ShadowSocksR Server")) m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/servers") if m.uci:get(shadowsocksr, sid) ~= "servers" then @@ -113,35 +110,35 @@ end -- [[ Servers Setting ]]-- s = m:section(NamedSection, sid, "servers") s.anonymous = true -s.addremove = false +s.addremove = false o = s:option(DummyValue,"ssr_url","SS/SSR/V2RAY/TROJAN URL") -o.rawhtml = true +o.rawhtml = true o.template = "shadowsocksr/ssrurl" o.value =sid o = s:option(ListValue, "type", translate("Server Node Type")) o:value("ssr", translate("ShadowsocksR")) if nixio.fs.access("/usr/bin/ss-redir") then -o:value("ss", translate("Shadowsocks New Version")) + o:value("ss", translate("Shadowsocks New Version")) end if nixio.fs.access("/usr/bin/v2ray/v2ray") or nixio.fs.access("/usr/bin/v2ray") then -o:value("v2ray", translate("V2Ray")) + o:value("v2ray", translate("V2Ray")) end if nixio.fs.access("/usr/sbin/trojan") then -o:value("trojan", translate("Trojan")) + o:value("trojan", translate("Trojan")) end if nixio.fs.access("/usr/sbin/redsocks2") then -o:value("socks5", translate("Socks5")) -o:value("tun", translate("Network Tunnel")) + o:value("socks5", translate("Socks5")) + o:value("tun", translate("Network Tunnel")) end o.description = translate("Using incorrect encryption mothod may causes service fail to start") o = s:option(Value, "alias", translate("Alias(optional)")) o = s:option(ListValue, "iface", translate("Network interface to use")) -for _, e in ipairs(sys.net.devices()) do - if e ~= "lo" then o:value(e) end +for _, e in ipairs(luci.sys.net.devices()) do + if e ~= "lo" then o:value(e) end end o:depends("type", "tun") o.description = translate("Redirect traffic to this network interface") @@ -369,6 +366,7 @@ o.rmempty = true o:depends("type", "v2ray") o:depends("type", "trojan") o.default = "1" +o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.") -- [[ TLS ]]-- o = s:option(Flag, "tls", translate("TLS")) @@ -409,31 +407,31 @@ o:depends("certificate", 1) cert_dir = "/etc/ssl/private/" local path -http.setfilehandler( - function(meta, chunk, eof) - if not fd then - if (not meta) or (not meta.name) or (not meta.file) then return end - fd = nixio.open(cert_dir .. meta.file, "w") - if not fd then - path = translate("Create upload file error.") - return - end - end - if chunk and fd then - fd:write(chunk) - end - if eof and fd then - fd:close() - fd = nil - path = '/etc/ssl/private/' .. meta.file .. '' - end - end - ) +luci.http.setfilehandler( +function(meta, chunk, eof) + if not fd then + if (not meta) or (not meta.name) or (not meta.file) then return end + fd = nixio.open(cert_dir .. meta.file, "w") + if not fd then + path = translate("Create upload file error.") + return + end + end + if chunk and fd then + fd:write(chunk) + end + if eof and fd then + fd:close() + fd = nil + path = '/etc/ssl/private/' .. meta.file .. '' + end +end +) if luci.http.formvalue("upload") then - local f = luci.http.formvalue("ulfile") - if #f <= 0 then - path = translate("No specify upload file.") - end + local f = luci.http.formvalue("ulfile") + if #f <= 0 then + path = translate("No specify upload file.") + end end o = s:option(Value, "certpath", translate("Current Certificate Path")) @@ -459,42 +457,36 @@ o.default = 1234 o.rmempty = false if nixio.fs.access("/usr/bin/kcptun-client") then - -kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/kcptun-client")) -kcp_enable.rmempty = true -kcp_enable.default = "0" -kcp_enable:depends("type", "ssr") -kcp_enable:depends("type", "ss") - -o = s:option(Value, "kcp_port", translate("KcpTun Port")) -o.datatype = "port" -o.default = 4000 -function o.validate(self, value, section) + kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/kcptun-client")) + kcp_enable.rmempty = true + kcp_enable.default = "0" + kcp_enable:depends("type", "ssr") + kcp_enable:depends("type", "ss") + o = s:option(Value, "kcp_port", translate("KcpTun Port")) + o.datatype = "port" + o.default = 4000 + function o.validate(self, value, section) local kcp_file="/usr/bin/kcptun-client" local enable = kcp_enable:formvalue(section) or kcp_enable.disabled if enable == kcp_enable.enabled then - if not fs.access(kcp_file) then - return nil, translate("Haven't a Kcptun executable file") - elseif not isKcptun(kcp_file) then - return nil, translate("Not a Kcptun executable file") + if not nixio.fs.access(kcp_file) then + return nil, translate("Haven't a Kcptun executable file") + elseif not isKcptun(kcp_file) then + return nil, translate("Not a Kcptun executable file") + end + end + return value end - end - - return value -end -o:depends("type", "ssr") -o:depends("type", "ss") - -o = s:option(Value, "kcp_password", translate("KcpTun Password")) -o.password = true -o:depends("type", "ssr") -o:depends("type", "ss") - -o = s:option(Value, "kcp_param", translate("KcpTun Param")) -o.default = "--nocomp" -o:depends("type", "ssr") -o:depends("type", "ss") - + o:depends("type", "ssr") + o:depends("type", "ss") + o = s:option(Value, "kcp_password", translate("KcpTun Password")) + o.password = true + o:depends("type", "ssr") + o:depends("type", "ss") + o = s:option(Value, "kcp_param", translate("KcpTun Param")) + o.default = "--nocomp" + o:depends("type", "ssr") + o:depends("type", "ss") end return m diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua index c73e5e21dd..9992d55bde 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua @@ -1,16 +1,14 @@ -- Copyright (C) 2017 yushi studio github.com/ywb94 -- Copyright (C) 2018 lean github.com/coolsnowwolf -- Licensed to the public under the GNU General Public License v3. - +require "luci.model.uci" local m, s, sec, o, kcp_enable local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() -local sys = require "luci.sys" - m = Map(shadowsocksr, translate("ShadowSocksR Plus+ Settings")) -m:section(SimpleSection).template = "shadowsocksr/status" +m:section(SimpleSection).template = "shadowsocksr/status" local server_table = {} uci:foreach(shadowsocksr, "servers", function(s) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua index 7a5e33b63c..9f2b39bf61 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua @@ -1,5 +1,6 @@ +require "luci.ip" +require "nixio.fs" local m, s, o -local NXFS = require "nixio.fs" m = Map("shadowsocksr", translate("IP black-and-white list")) @@ -27,9 +28,9 @@ o.rmempty = false o = s:taboption("lan_ac", DynamicList, "lan_ac_ips", translate("LAN Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) o:depends("lan_ac_mode", "w") o:depends("lan_ac_mode", "b") @@ -37,25 +38,25 @@ o:depends("lan_ac_mode", "b") o = s:taboption("lan_ac", DynamicList, "lan_bp_ips", translate("LAN Bypassed Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) o = s:taboption("lan_ac", DynamicList, "lan_fp_ips", translate("LAN Force Proxy Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) o = s:taboption("lan_ac", DynamicList, "lan_gm_ips", translate("Game Mode Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) -- Part of Self @@ -66,73 +67,73 @@ end) -- o:value("2", translatef("Forwarded Proxy")) -- o.rmempty = false -s:tab("esc", translate("Bypass Domain List")) +s:tab("esc", translate("Bypass Domain List")) -local escconf = "/etc/config/white.list" +local escconf = "/etc/ssr/white.list" o = s:taboption("esc", TextValue, "escconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return NXFS.readfile(escconf) or "" + return nixio.fs.readfile(escconf) or "" end o.write = function(self, section, value) - NXFS.writefile(escconf, value:gsub("\r\n", "\n")) + nixio.fs.writefile(escconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - NXFS.writefile(escconf, "") + nixio.fs.writefile(escconf, "") end -s:tab("block", translate("Black Domain List")) +s:tab("block", translate("Black Domain List")) -local blockconf = "/etc/config/black.list" +local blockconf = "/etc/ssr/black.list" o = s:taboption("block", TextValue, "blockconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return NXFS.readfile(blockconf) or " " + return nixio.fs.readfile(blockconf) or " " end o.write = function(self, section, value) - NXFS.writefile(blockconf, value:gsub("\r\n", "\n")) + nixio.fs.writefile(blockconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - NXFS.writefile(blockconf, "") + nixio.fs.writefile(blockconf, "") end -s:tab("netflix", translate("Netflix Domain List")) +s:tab("netflix", translate("Netflix Domain List")) -local netflixconf = "/etc/config/netflix.list" +local netflixconf = "/etc/ssr/netflix.list" o = s:taboption("netflix", TextValue, "netflixconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return NXFS.readfile(netflixconf) or " " + return nixio.fs.readfile(netflixconf) or " " end o.write = function(self, section, value) - NXFS.writefile(netflixconf, value:gsub("\r\n", "\n")) + nixio.fs.writefile(netflixconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - NXFS.writefile(netflixconf, "") + nixio.fs.writefile(netflixconf, "") end -s:tab("netflixip", translate("Netflix IP List")) +s:tab("netflixip", translate("Netflix IP List")) -local netflixipconf = "/etc/config/netflixip.list" +local netflixipconf = "/etc/ssr/netflixip.list" o = s:taboption("netflixip", TextValue, "netflixipconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return NXFS.readfile(netflixipconf) or " " + return nixio.fs.readfile(netflixipconf) or " " end o.write = function(self, section, value) - NXFS.writefile(netflixipconf, value:gsub("\r\n", "\n")) + nixio.fs.writefile(netflixipconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - NXFS.writefile(netflixipconf, "") + nixio.fs.writefile(netflixipconf, "") end return m diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua index 6c5938ed7f..a71d0003bf 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua @@ -1,20 +1,20 @@ -local fs = require "nixio.fs" - +require "luci.util" +require "nixio.fs" f = SimpleForm("logview") - +f.reset = false +f.submit = false t = f:field(TextValue, "conf") t.rmempty = true t.rows = 20 function t.cfgvalue() - if fs.access("/tmp/ssrplus.log") then - local logs = luci.util.execi("cat /tmp/ssrplus.log") - local s = "" - for line in logs do - s = line .. "\n" .. s - end - return s - end + if nixio.fs.access("/tmp/ssrplus.log") then + local logs = luci.util.execi("cat /tmp/ssrplus.log") + local s = "" + for line in logs do + s = line .. "\n" .. s + end + return s + end end t.readonly="readonly" - -return f \ No newline at end of file +return f diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua index c7d9021563..4e7e3cf65a 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua @@ -1,43 +1,44 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. - +require "luci.http" +require "luci.dispatcher" local m, s, o local shadowsocksr = "shadowsocksr" local sid = arg[1] local encrypt_methods = { - "rc4-md5", - "rc4-md5-6", - "rc4", - "table", - "aes-128-cfb", - "aes-192-cfb", - "aes-256-cfb", - "aes-128-ctr", - "aes-192-ctr", - "aes-256-ctr", - "bf-cfb", - "camellia-128-cfb", - "camellia-192-cfb", - "camellia-256-cfb", - "cast5-cfb", - "des-cfb", - "idea-cfb", - "rc2-cfb", - "seed-cfb", - "salsa20", - "chacha20", - "chacha20-ietf", +"rc4-md5", +"rc4-md5-6", +"rc4", +"table", +"aes-128-cfb", +"aes-192-cfb", +"aes-256-cfb", +"aes-128-ctr", +"aes-192-ctr", +"aes-256-ctr", +"bf-cfb", +"camellia-128-cfb", +"camellia-192-cfb", +"camellia-256-cfb", +"cast5-cfb", +"des-cfb", +"idea-cfb", +"rc2-cfb", +"seed-cfb", +"salsa20", +"chacha20", +"chacha20-ietf", } local protocol = { - "origin", +"origin", } obfs = { - "plain", - "http_simple", - "http_post", +"plain", +"http_simple", +"http_post", } m = Map(shadowsocksr, translate("Edit ShadowSocksR Server")) @@ -54,7 +55,7 @@ end -- [[ Server Setting ]]-- s = m:section(NamedSection, sid, "server_config") s.anonymous = true -s.addremove = false +s.addremove = false o = s:option(Flag, "enable", translate("Enable")) o.default = 1 diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua index ec273e0f3b..42f01055f2 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua @@ -1,56 +1,55 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. - +require "luci.http" +require "luci.dispatcher" local m, sec, o local shadowsocksr = "shadowsocksr" -local uci = luci.model.uci.cursor() - - -m = Map(shadowsocksr) local encrypt_methods = { - "table", - "rc4", - "rc4-md5", - "rc4-md5-6", - "aes-128-cfb", - "aes-192-cfb", - "aes-256-cfb", - "aes-128-ctr", - "aes-192-ctr", - "aes-256-ctr", - "bf-cfb", - "camellia-128-cfb", - "camellia-192-cfb", - "camellia-256-cfb", - "cast5-cfb", - "des-cfb", - "idea-cfb", - "rc2-cfb", - "seed-cfb", - "salsa20", - "chacha20", - "chacha20-ietf", +"table", +"rc4", +"rc4-md5", +"rc4-md5-6", +"aes-128-cfb", +"aes-192-cfb", +"aes-256-cfb", +"aes-128-ctr", +"aes-192-ctr", +"aes-256-ctr", +"bf-cfb", +"camellia-128-cfb", +"camellia-192-cfb", +"camellia-256-cfb", +"cast5-cfb", +"des-cfb", +"idea-cfb", +"rc2-cfb", +"seed-cfb", +"salsa20", +"chacha20", +"chacha20-ietf", } local protocol = { - "origin", - "verify_deflate", - "auth_sha1_v4", - "auth_aes128_sha1", - "auth_aes128_md5", - "auth_chain_a", +"origin", +"verify_deflate", +"auth_sha1_v4", +"auth_aes128_sha1", +"auth_aes128_md5", +"auth_chain_a", } obfs = { - "plain", - "http_simple", - "http_post", - "random_head", - "tls1.2_ticket_auth", - "tls1.2_ticket_fastauth", +"plain", +"http_simple", +"http_post", +"random_head", +"tls1.2_ticket_auth", +"tls1.2_ticket_fastauth", } +m = Map(shadowsocksr) + -- [[ Global Setting ]]-- sec = m:section(TypedSection, "server_global", translate("Global Setting")) sec.anonymous = true diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index d1ca504671..2378798172 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -1,20 +1,17 @@ -- Licensed to the public under the GNU General Public License v3. - +require "luci.http" +require "luci.dispatcher" +require "luci.model.uci" local m, s, o local shadowsocksr = "shadowsocksr" - local uci = luci.model.uci.cursor() local server_count = 0 + uci:foreach("shadowsocksr", "servers", function(s) - server_count = server_count + 1 + server_count = server_count + 1 end) -local fs = require "nixio.fs" -local sys = require "luci.sys" - -local ucic = luci.model.uci.cursor() - -m = Map(shadowsocksr, translate("Servers subscription and manage")) +m = Map(shadowsocksr, translate("Servers subscription and manage")) -- Server Subscribe @@ -28,7 +25,7 @@ o.description = translate("Auto Update Server subscription, GFW list and CHN rou o = s:option(ListValue, "auto_update_time", translate("Update time (every day)")) for t = 0,23 do -o:value(t, t..":00") + o:value(t, t..":00") end o.default=2 o.rmempty = false @@ -44,7 +41,7 @@ o = s:option(Button,"update_Sub",translate("Update Subscribe List")) o.inputstyle = "reload" o.description = translate("Update subscribe url list first") o.write = function() - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) end o = s:option(Flag, "switch", translate("Subscribe Default Auto-Switch")) @@ -58,25 +55,25 @@ o.description = translate("Through proxy update list, Not Recommended ") o = s:option(Button,"subscribe", translate("Update All Subscribe Severs")) -o.rawhtml = true +o.rawhtml = true o.template = "shadowsocksr/subscribe" o = s:option(Button,"delete",translate("Delete All Subscribe Severs")) o.inputstyle = "reset" -o.description = string.format(translate("Server Count") .. ": %d", server_count) +o.description = string.format(translate("Server Count") .. ": %d", server_count) o.write = function() -uci:delete_all("shadowsocksr", "servers", function(s) - if s.hashkey or s.isSubscribe then - return true - else - return false - end -end) -uci:save("shadowsocksr") -uci:commit("shadowsocksr") -luci.sys.exec("/etc/init.d/shadowsocksr restart") -luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) -return + uci:delete_all("shadowsocksr", "servers", function(s) + if s.hashkey or s.isSubscribe then + return true + else + return false + end + end) + uci:save("shadowsocksr") + uci:commit("shadowsocksr") + luci.sys.exec("/etc/init.d/shadowsocksr restart") + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) + return end -- [[ Servers Manage ]]-- @@ -85,12 +82,12 @@ s.anonymous = true s.addremove = true s.template = "cbi/tblsection" s.sortable = true -s.extedit = luci.dispatcher.build_url("admin/services/shadowsocksr/servers/%s") +s.extedit = luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers", "%s") function s.create(...) local sid = TypedSection.create(...) if sid then luci.http.redirect(s.extedit % sid) - return + return end end @@ -121,11 +118,11 @@ o.width="10%" node = s:option(Button,"apply_node",translate("Apply")) node.inputstyle = "apply" node.write = function(self, section) - ucic:set("shadowsocksr", '@global[0]', 'global_server', section) - ucic:save("shadowsocksr") - ucic:commit("shadowsocksr") - luci.sys.exec("/etc/init.d/shadowsocksr restart") - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "client")) + uci:set("shadowsocksr", '@global[0]', 'global_server', section) + uci:save("shadowsocksr") + uci:commit("shadowsocksr") + luci.sys.exec("/etc/init.d/shadowsocksr restart") + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "client")) end o = s:option(Flag, "switch_enable", translate("Auto Switch")) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua index 0ae5219eea..bd6c6d354b 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -1,6 +1,8 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. - +require "nixio.fs" +require "luci.sys" +require "luci.model.uci" local m, s, o local redir_run=0 local reudp_run=0 @@ -20,71 +22,69 @@ font_off = [[]] bold_on = [[]] bold_off = [[]] -local fs = require "nixio.fs" -local sys = require "luci.sys" local kcptun_version=translate("Unknown") local kcp_file="/usr/bin/kcptun-client" -if not fs.access(kcp_file) then -kcptun_version=translate("Not exist") +if not nixio.fs.access(kcp_file) then + kcptun_version=translate("Not exist") else -if not fs.access(kcp_file, "rwx", "rx", "rx") then -fs.chmod(kcp_file, 755) -end -kcptun_version=sys.exec(kcp_file .. " -v | awk '{printf $3}'") -if not kcptun_version or kcptun_version == "" then -kcptun_version = translate("Unknown") -end - + if not nixio.fs.access(kcp_file, "rwx", "rx", "rx") then + nixio.fs.chmod(kcp_file, 755) + end + kcptun_version=luci.sys.exec(kcp_file .. " -v | awk '{printf $3}'") + if not kcptun_version or kcptun_version == "" then + kcptun_version = translate("Unknown") + end + end if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then -gfw_count = tonumber(sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l"))/2 + gfw_count = tonumber(luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l"))/2 end if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then -ad_count = tonumber(sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")) + ad_count = tonumber(luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")) end -if nixio.fs.access("/etc/china_ssr.txt") then -ip_count = tonumber(sys.exec("cat /etc/china_ssr.txt | wc -l")) +if nixio.fs.access("/etc/ssr/china_ssr.txt") then + ip_count = tonumber(luci.sys.exec("cat /etc/china_ssr.txt | wc -l")) end -if nixio.fs.access("/etc/config/netflixip.list") then -nfip_count = tonumber(sys.exec("cat /etc/config/netflixip.list | wc -l")) +if nixio.fs.access("/etc/ssr/netflixip.list") then + nfip_count = tonumber(luci.sys.exec("cat /etc/ssr/netflixip.list | wc -l")) end -local icount=sys.exec("busybox ps -w | grep ssr-reudp |grep -v grep| wc -l") +local icount=luci.sys.exec("busybox ps -w | grep ssr-reudp |grep -v grep| wc -l") if tonumber(icount)>0 then -reudp_run=1 + reudp_run=1 else -icount=sys.exec("busybox ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l") -if tonumber(icount)>0 then -reudp_run=1 -end + icount=luci.sys.exec("busybox ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l") + if tonumber(icount)>0 then + reudp_run=1 + end end if luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null") == 0 then -redir_run=1 + redir_run=1 end if luci.sys.call("busybox ps -w | grep ssr-local | grep -v ssr-socksdns |grep -v grep >/dev/null") == 0 then -sock5_run=1 + sock5_run=1 end if luci.sys.call("pidof kcptun-client >/dev/null") == 0 then -kcptun_run=1 + kcptun_run=1 end if luci.sys.call("busybox ps -w | grep ssr-server | grep -v grep >/dev/null") == 0 then -server_run=1 + server_run=1 end if luci.sys.call("busybox ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then -tunnel_run=1 + tunnel_run=1 end if luci.sys.call("pidof pdnsd >/dev/null") == 0 or (luci.sys.call("busybox ps -w | grep ssr-dns |grep -v grep >/dev/null") == 0 and luci.sys.call("pidof dns2socks >/dev/null") == 0)then -pdnsd_run=1 + pdnsd_run=1 end m = SimpleForm("Version") @@ -94,56 +94,56 @@ m.submit = false s=m:field(DummyValue,"redir_run",translate("Global Client")) s.rawhtml = true if redir_run == 1 then -s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off + s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else -s.value = translate("Not Running") + s.value = translate("Not Running") end s=m:field(DummyValue,"reudp_run",translate("Game Mode UDP Relay")) s.rawhtml = true if reudp_run == 1 then -s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off + s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else -s.value = translate("Not Running") + s.value = translate("Not Running") end if uci:get_first(shadowsocksr, 'global', 'pdnsd_enable', '0') ~= '0' then -s=m:field(DummyValue,"pdnsd_run",translate("DNS Anti-pollution")) -s.rawhtml = true -if pdnsd_run == 1 then -s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off -else -s.value = translate("Not Running") -end + s=m:field(DummyValue,"pdnsd_run",translate("DNS Anti-pollution")) + s.rawhtml = true + if pdnsd_run == 1 then + s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off + else + s.value = translate("Not Running") + end end s=m:field(DummyValue,"sock5_run",translate("Global SOCKS5 Proxy Server")) s.rawhtml = true if sock5_run == 1 then -s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off + s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else -s.value = translate("Not Running") + s.value = translate("Not Running") end s=m:field(DummyValue,"server_run",translate("Local Servers")) s.rawhtml = true if server_run == 1 then -s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off + s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else -s.value = translate("Not Running") + s.value = translate("Not Running") end if nixio.fs.access("/usr/bin/kcptun-client") then -s=m:field(DummyValue,"kcp_version",translate("KcpTun Version")) -s.rawhtml = true -s.value =kcptun_version -s=m:field(DummyValue,"kcptun_run",translate("KcpTun")) -s.rawhtml = true -if kcptun_run == 1 then -s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off -else -s.value = translate("Not Running") -end + s=m:field(DummyValue,"kcp_version",translate("KcpTun Version")) + s.rawhtml = true + s.value =kcptun_version + s=m:field(DummyValue,"kcptun_run",translate("KcpTun")) + s.rawhtml = true + if kcptun_run == 1 then + s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off + else + s.value = translate("Not Running") + end end s=m:field(DummyValue,"google",translate("Google Connectivity")) @@ -170,10 +170,10 @@ s.template = "shadowsocksr/refresh" s.value = nfip_count .. " " .. translate("Records") if uci:get_first(shadowsocksr, 'global', 'adblock', '0') == '1' then -s=m:field(DummyValue,"ad_data",translate("Advertising Data")) -s.rawhtml = true -s.template = "shadowsocksr/refresh" -s.value = ad_count .. " " .. translate("Records") + s=m:field(DummyValue,"ad_data",translate("Advertising Data")) + s.rawhtml = true + s.template = "shadowsocksr/refresh" + s.value = ad_count .. " " .. translate("Records") end s=m:field(DummyValue,"check_port",translate("Check Server Port")) diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm index f34f04d7b8..55ed14ef80 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm @@ -1,4 +1,4 @@ <%+cbi/valueheader%> - - + + <%+cbi/valuefooter%> diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm index ed91a2f22c..e37b446e90 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm @@ -1,7 +1,5 @@ <%+cbi/valueheader%> - <%=self.value%> - - - <%+cbi/valuefooter%> \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm index 9c5ba66ac5..f5b3c079a8 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm @@ -81,47 +81,39 @@ local dsp = require "luci.dispatcher" return false; } - // set tr draggable function enableDragForTable(table_selecter, store) { var trs = document.querySelectorAll(table_selecter + " tr"); if (!trs || trs.length.length < 3) { return; } - function ondragstart(ev) { ev.dataTransfer.setData("Text", ev.target.id); } - function ondrop(ev) { var from = ev.dataTransfer.getData("Text"); cbi_row_drop(from, this.id, store); } - function ondragover(ev) { ev.preventDefault(); ev.dataTransfer.dropEffect = "move"; } - function moveToTop(id) { var top = document.querySelectorAll(table_selecter + " tr")[2]; cbi_row_drop(id, top.id, store); } - function moveToBottom(id) { console.log('moveToBottom:', id); var trList = document.querySelectorAll(table_selecter + " tr"); var bottom = trList[trList.length - 1]; cbi_row_drop(id, bottom.id, store, true); } - for (let index = 2; index < trs.length; index++) { const el = trs[index]; el.setAttribute("draggable", true); el.ondragstart = ondragstart; el.ondrop = ondrop; el.ondragover = ondragover; - // reset the behaviors of the btns var upBtns = el.querySelectorAll(".cbi-button.cbi-button-up"); if (upBtns && upBtns.length > 0) { @@ -131,7 +123,6 @@ local dsp = require "luci.dispatcher" }; }); } - var downBtns = el.querySelectorAll(".cbi-button.cbi-button-down"); if (downBtns && downBtns.length > 0) { downBtns.forEach(function (_el) { @@ -142,7 +133,6 @@ local dsp = require "luci.dispatcher" } } } - // enable enableDragForTable( "#cbi-shadowsocksr-servers table", diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index e734af05a8..aabc8b59fb 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -80,7 +80,6 @@ } return false; } - function import_ssr_url(btn, urlname, sid) { var s = document.getElementById(urlname + '-status'); if (!s) @@ -98,7 +97,6 @@ s.innerHTML = "无效格式"; return false; } - var event = document.createEvent("HTMLEvents"); event.initEvent("change", true, true); if (ssu[0] == "ssr") { @@ -137,7 +135,6 @@ s.innerHTML = "导入ShadowsocksR配置信息成功"; return false; } else if (ssu[0] == "ss") { - var url0, param = ""; var sipIndex = ssu[1].indexOf("@"); var ploc = ssu[1].indexOf("#"); @@ -147,7 +144,6 @@ } else { url0 = ssu[1]; } - if (sipIndex != -1) { // SIP002 var userInfo = b64decsafe(url0.substr(0, sipIndex)); @@ -163,7 +159,6 @@ plugin = pluginNameInfo.substr(pluginNameInfo.indexOf("=") + 1) pluginOpts = pluginInfo.substr(pluginIndex + 1); } - var userInfoSplitIndex = userInfo.indexOf(":"); if (userInfoSplitIndex != -1) { method = userInfo.substr(0, userInfoSplitIndex); @@ -177,7 +172,6 @@ document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method || ""; document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin || ""; document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || ""; - if (param != undefined) { document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } @@ -212,7 +206,6 @@ url0 = ssu[1] } var sstr = url0; - document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan"; document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); var team = sstr.split('@'); @@ -229,7 +222,6 @@ queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || ''); } } - document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = serverPart[0]; document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port; document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password; @@ -237,7 +229,6 @@ document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = queryParam.peer || ''; document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = queryParam.allowInsecure === '1'; - if (param != undefined) { document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } diff --git a/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po b/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po index 6052702dab..cf0a7aa503 100644 --- a/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po +++ b/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po @@ -61,9 +61,21 @@ msgstr "密码" msgid "Encrypt Method" msgstr "加密方式" +msgid "Transport" +msgstr "传输协议" + msgid "Protocol" msgstr "传输协议" +msgid "allowInsecure" +msgstr "允许不安全连接" + +msgid "Concurrency" +msgstr "最大并发连接数" + +msgid "If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates." +msgstr "是否允许不安全连接。当选择时,将不会检查远端主机所提供的 TLS 证书的有效性。" + msgid "Protocol param(optional)" msgstr "传输协议参数(可选)" diff --git a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr index 35207f08c3..7658938ae1 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr @@ -6,7 +6,6 @@ config global option dports '2' option pdnsd_enable '1' option monitor_enable '1' - option global_server 'nil' option enable_switch '1' option switch_timeout '5' option switch_time '667' @@ -15,16 +14,13 @@ config global option chnroute_url 'https://ispip.clang.cn/all_cn.txt' option nfip_url 'https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt' option adblock_url 'https://gitee.com/privacy-protection-tools/anti-ad/raw/master/anti-ad-for-dnsmasq.conf' - option netflix_server 'same' option threads '0' - -config socks5_proxy - option socks '0' - option local_port '1080' - option local_address '0.0.0.0' + option global_server 'nil' + option netflix_server 'nil' + option netflix_proxy '0' config access_control - option wan_bp_list '/etc/china_ssr.txt' + option wan_bp_list '/etc/ssr/china_ssr.txt' option lan_ac_mode 'b' option router_proxy '1' list wan_fw_ips '149.154.160.0/20' @@ -33,6 +29,11 @@ config access_control list wan_fw_ips '91.108.56.0/22' list wan_fw_ips '109.239.140.0/24' +config socks5_proxy + option socks '0' + option local_port '1080' + option local_address '0.0.0.0' + config server_global option enable_server '0' diff --git a/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf b/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf index cfeb42fc82..ccaf1bf863 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf +++ b/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf @@ -1,5 +1,5 @@ -server=/.030buy.com/127.0.0.1#5335 -ipset=/.030buy.com/gfwlist +server=/.0914.global.ssl.fastly.net/127.0.0.1#5335 +ipset=/.0914.global.ssl.fastly.net/gfwlist server=/.0rz.tw/127.0.0.1#5335 ipset=/.0rz.tw/gfwlist server=/.10.tt/127.0.0.1#5335 @@ -210,14 +210,10 @@ server=/.8news.com.tw/127.0.0.1#5335 ipset=/.8news.com.tw/gfwlist server=/.8z1.net/127.0.0.1#5335 ipset=/.8z1.net/gfwlist -server=/.9001700.com/127.0.0.1#5335 -ipset=/.9001700.com/gfwlist server=/.91porn.com/127.0.0.1#5335 ipset=/.91porn.com/gfwlist server=/.91vps.club/127.0.0.1#5335 ipset=/.91vps.club/gfwlist -server=/.92ccav.com/127.0.0.1#5335 -ipset=/.92ccav.com/gfwlist server=/.991.com/127.0.0.1#5335 ipset=/.991.com/gfwlist server=/.99btgc01.com/127.0.0.1#5335 @@ -236,6 +232,8 @@ server=/.a248.e.akamai.net/127.0.0.1#5335 ipset=/.a248.e.akamai.net/gfwlist server=/.a5.com.ru/127.0.0.1#5335 ipset=/.a5.com.ru/gfwlist +server=/.a771.dscq.akamai.net/127.0.0.1#5335 +ipset=/.a771.dscq.akamai.net/gfwlist server=/.aamacau.com/127.0.0.1#5335 ipset=/.aamacau.com/gfwlist server=/.abc.com/127.0.0.1#5335 @@ -248,8 +246,6 @@ server=/.abc.xyz/127.0.0.1#5335 ipset=/.abc.xyz/gfwlist server=/.abchinese.com/127.0.0.1#5335 ipset=/.abchinese.com/gfwlist -server=/.abclite.net/127.0.0.1#5335 -ipset=/.abclite.net/gfwlist server=/.abebooks.com/127.0.0.1#5335 ipset=/.abebooks.com/gfwlist server=/.abematv.akamaized.net/127.0.0.1#5335 @@ -260,20 +256,12 @@ server=/.aboluowang.com/127.0.0.1#5335 ipset=/.aboluowang.com/gfwlist server=/.about.google/127.0.0.1#5335 ipset=/.about.google/gfwlist -server=/.aboutgfw.com/127.0.0.1#5335 -ipset=/.aboutgfw.com/gfwlist -server=/.abs.edu/127.0.0.1#5335 -ipset=/.abs.edu/gfwlist server=/.ac.jiruan.net/127.0.0.1#5335 ipset=/.ac.jiruan.net/gfwlist -server=/.accim.org/127.0.0.1#5335 -ipset=/.accim.org/gfwlist server=/.aceros-de-hispania.com/127.0.0.1#5335 ipset=/.aceros-de-hispania.com/gfwlist server=/.acevpn.com/127.0.0.1#5335 ipset=/.acevpn.com/gfwlist -server=/.acg18.me/127.0.0.1#5335 -ipset=/.acg18.me/gfwlist server=/.acgkj.com/127.0.0.1#5335 ipset=/.acgkj.com/gfwlist server=/.acmedia365.com/127.0.0.1#5335 @@ -300,8 +288,6 @@ server=/.admob.com/127.0.0.1#5335 ipset=/.admob.com/gfwlist server=/.adpl.org.hk/127.0.0.1#5335 ipset=/.adpl.org.hk/gfwlist -server=/.ads-twitter.com/127.0.0.1#5335 -ipset=/.ads-twitter.com/gfwlist server=/.adsense.com/127.0.0.1#5335 ipset=/.adsense.com/gfwlist server=/.adult-sex-games.com/127.0.0.1#5335 @@ -320,8 +306,6 @@ server=/.aex.com/127.0.0.1#5335 ipset=/.aex.com/gfwlist server=/.af.mil/127.0.0.1#5335 ipset=/.af.mil/gfwlist -server=/.agnesb.fr/127.0.0.1#5335 -ipset=/.agnesb.fr/gfwlist server=/.agoogleaday.com/127.0.0.1#5335 ipset=/.agoogleaday.com/gfwlist server=/.agro.hk/127.0.0.1#5335 @@ -352,8 +336,6 @@ server=/.aiweiweiblog.com/127.0.0.1#5335 ipset=/.aiweiweiblog.com/gfwlist server=/.akiba-online.com/127.0.0.1#5335 ipset=/.akiba-online.com/gfwlist -server=/.akiba-web.com/127.0.0.1#5335 -ipset=/.akiba-web.com/gfwlist server=/.akow.org/127.0.0.1#5335 ipset=/.akow.org/gfwlist server=/.al-islam.com/127.0.0.1#5335 @@ -414,8 +396,6 @@ server=/.alphaporno.com/127.0.0.1#5335 ipset=/.alphaporno.com/gfwlist server=/.alternate-tools.com/127.0.0.1#5335 ipset=/.alternate-tools.com/gfwlist -server=/.altrec.com/127.0.0.1#5335 -ipset=/.altrec.com/gfwlist server=/.alvinalexander.com/127.0.0.1#5335 ipset=/.alvinalexander.com/gfwlist server=/.alwaysdata.com/127.0.0.1#5335 @@ -428,8 +408,8 @@ server=/.am730.com.hk/127.0.0.1#5335 ipset=/.am730.com.hk/gfwlist server=/.amazon.co.jp/127.0.0.1#5335 ipset=/.amazon.co.jp/gfwlist -server=/.ameblo.jp/127.0.0.1#5335 -ipset=/.ameblo.jp/gfwlist +server=/.ameba.jp/127.0.0.1#5335 +ipset=/.ameba.jp/gfwlist server=/.americangreencard.com/127.0.0.1#5335 ipset=/.americangreencard.com/gfwlist server=/.americanunfinished.com/127.0.0.1#5335 @@ -470,8 +450,6 @@ server=/.andygod.com/127.0.0.1#5335 ipset=/.andygod.com/gfwlist server=/.angela-merkel.de/127.0.0.1#5335 ipset=/.angela-merkel.de/gfwlist -server=/.angola.org/127.0.0.1#5335 -ipset=/.angola.org/gfwlist server=/.angularjs.org/127.0.0.1#5335 ipset=/.angularjs.org/gfwlist server=/.animecrazy.net/127.0.0.1#5335 @@ -518,10 +496,6 @@ server=/.aolchannels.aol.com/127.0.0.1#5335 ipset=/.aolchannels.aol.com/gfwlist server=/.aomiwang.com/127.0.0.1#5335 ipset=/.aomiwang.com/gfwlist -server=/.apartmentratings.com/127.0.0.1#5335 -ipset=/.apartmentratings.com/gfwlist -server=/.apartments.com/127.0.0.1#5335 -ipset=/.apartments.com/gfwlist server=/.apetube.com/127.0.0.1#5335 ipset=/.apetube.com/gfwlist server=/.api-secure.recaptcha.net/127.0.0.1#5335 @@ -598,8 +572,6 @@ server=/.arctosia.com/127.0.0.1#5335 ipset=/.arctosia.com/gfwlist server=/.areca-backup.org/127.0.0.1#5335 ipset=/.areca-backup.org/gfwlist -server=/.arena.taipei/127.0.0.1#5335 -ipset=/.arena.taipei/gfwlist server=/.arethusa.su/127.0.0.1#5335 ipset=/.arethusa.su/gfwlist server=/.arlingtoncemetery.mil/127.0.0.1#5335 @@ -644,16 +616,12 @@ server=/.assembla.com/127.0.0.1#5335 ipset=/.assembla.com/gfwlist server=/.assets.bwbx.io/127.0.0.1#5335 ipset=/.assets.bwbx.io/gfwlist -server=/.assimp.org/127.0.0.1#5335 -ipset=/.assimp.org/gfwlist server=/.astrill.com/127.0.0.1#5335 ipset=/.astrill.com/gfwlist server=/.atc.org.au/127.0.0.1#5335 ipset=/.atc.org.au/gfwlist server=/.atchinese.com/127.0.0.1#5335 ipset=/.atchinese.com/gfwlist -server=/.atdmt.com/127.0.0.1#5335 -ipset=/.atdmt.com/gfwlist server=/.atgfw.org/127.0.0.1#5335 ipset=/.atgfw.org/gfwlist server=/.athenaeizou.com/127.0.0.1#5335 @@ -716,8 +684,6 @@ server=/.azerbaycan.tv/127.0.0.1#5335 ipset=/.azerbaycan.tv/gfwlist server=/.azerimix.com/127.0.0.1#5335 ipset=/.azerimix.com/gfwlist -server=/.azubu.tv/127.0.0.1#5335 -ipset=/.azubu.tv/gfwlist server=/.b0ne.com/127.0.0.1#5335 ipset=/.b0ne.com/gfwlist server=/.babynet.com.hk/127.0.0.1#5335 @@ -732,8 +698,6 @@ server=/.badjojo.com/127.0.0.1#5335 ipset=/.badjojo.com/gfwlist server=/.badoo.com/127.0.0.1#5335 ipset=/.badoo.com/gfwlist -server=/.baidu.jp/127.0.0.1#5335 -ipset=/.baidu.jp/gfwlist server=/.baijie.org/127.0.0.1#5335 ipset=/.baijie.org/gfwlist server=/.bailandaily.com/127.0.0.1#5335 @@ -746,6 +710,8 @@ server=/.banana-vpn.com/127.0.0.1#5335 ipset=/.banana-vpn.com/gfwlist server=/.band.us/127.0.0.1#5335 ipset=/.band.us/gfwlist +server=/.bandpage.com/127.0.0.1#5335 +ipset=/.bandpage.com/gfwlist server=/.bandwagonhost.com/127.0.0.1#5335 ipset=/.bandwagonhost.com/gfwlist server=/.bangbrosnetwork.com/127.0.0.1#5335 @@ -756,14 +722,10 @@ server=/.bangdream.space/127.0.0.1#5335 ipset=/.bangdream.space/gfwlist server=/.bangyoulater.com/127.0.0.1#5335 ipset=/.bangyoulater.com/gfwlist -server=/.bankmobilevibe.com/127.0.0.1#5335 -ipset=/.bankmobilevibe.com/gfwlist server=/.bannedbook.org/127.0.0.1#5335 ipset=/.bannedbook.org/gfwlist server=/.bannednews.org/127.0.0.1#5335 ipset=/.bannednews.org/gfwlist -server=/.banorte.com/127.0.0.1#5335 -ipset=/.banorte.com/gfwlist server=/.baramangaonline.com/127.0.0.1#5335 ipset=/.baramangaonline.com/gfwlist server=/.barenakedislam.com/127.0.0.1#5335 @@ -774,8 +736,6 @@ server=/.barton.de/127.0.0.1#5335 ipset=/.barton.de/gfwlist server=/.bartvpn.com/127.0.0.1#5335 ipset=/.bartvpn.com/gfwlist -server=/.bash-hackers.org/127.0.0.1#5335 -ipset=/.bash-hackers.org/gfwlist server=/.bastillepost.com/127.0.0.1#5335 ipset=/.bastillepost.com/gfwlist server=/.bayvoice.net/127.0.0.1#5335 @@ -920,8 +880,6 @@ server=/.bfsh.hk/127.0.0.1#5335 ipset=/.bfsh.hk/gfwlist server=/.bgvpn.com/127.0.0.1#5335 ipset=/.bgvpn.com/gfwlist -server=/.bianlei.com/127.0.0.1#5335 -ipset=/.bianlei.com/gfwlist server=/.biantailajiao.com/127.0.0.1#5335 ipset=/.biantailajiao.com/gfwlist server=/.biantailajiao.in/127.0.0.1#5335 @@ -936,6 +894,8 @@ server=/.big.one/127.0.0.1#5335 ipset=/.big.one/gfwlist server=/.bigfools.com/127.0.0.1#5335 ipset=/.bigfools.com/gfwlist +server=/.biggo.com.tw/127.0.0.1#5335 +ipset=/.biggo.com.tw/gfwlist server=/.bigjapanesesex.com/127.0.0.1#5335 ipset=/.bigjapanesesex.com/gfwlist server=/.bigmoney.biz/127.0.0.1#5335 @@ -1122,8 +1082,6 @@ server=/.bolin.netfirms.com/127.0.0.1#5335 ipset=/.bolin.netfirms.com/gfwlist server=/.bonbonme.com/127.0.0.1#5335 ipset=/.bonbonme.com/gfwlist -server=/.bonbonsex.com/127.0.0.1#5335 -ipset=/.bonbonsex.com/gfwlist server=/.bonfoundation.org/127.0.0.1#5335 ipset=/.bonfoundation.org/gfwlist server=/.bongacams.com/127.0.0.1#5335 @@ -1352,8 +1310,6 @@ server=/.castbox.fm/127.0.0.1#5335 ipset=/.castbox.fm/gfwlist server=/.catch22.net/127.0.0.1#5335 ipset=/.catch22.net/gfwlist -server=/.catchgod.com/127.0.0.1#5335 -ipset=/.catchgod.com/gfwlist server=/.catfightpayperview.xxx/127.0.0.1#5335 ipset=/.catfightpayperview.xxx/gfwlist server=/.catholic.org.hk/127.0.0.1#5335 @@ -1602,8 +1558,6 @@ server=/.chinasoul.org/127.0.0.1#5335 ipset=/.chinasoul.org/gfwlist server=/.chinasucks.net/127.0.0.1#5335 ipset=/.chinasucks.net/gfwlist -server=/.chinatimes.com/127.0.0.1#5335 -ipset=/.chinatimes.com/gfwlist server=/.chinatopsex.com/127.0.0.1#5335 ipset=/.chinatopsex.com/gfwlist server=/.chinatown.com.au/127.0.0.1#5335 @@ -1656,8 +1610,6 @@ server=/.chithu.org/127.0.0.1#5335 ipset=/.chithu.org/gfwlist server=/.chn.chosun.com/127.0.0.1#5335 ipset=/.chn.chosun.com/gfwlist -server=/.chobit.cc/127.0.0.1#5335 -ipset=/.chobit.cc/gfwlist server=/.chrdnet.com/127.0.0.1#5335 ipset=/.chrdnet.com/gfwlist server=/.christianfreedom.org/127.0.0.1#5335 @@ -1754,6 +1706,8 @@ server=/.clinica-tibet.ru/127.0.0.1#5335 ipset=/.clinica-tibet.ru/gfwlist server=/.clipfish.de/127.0.0.1#5335 ipset=/.clipfish.de/gfwlist +server=/.clips4sale.com/127.0.0.1#5335 +ipset=/.clips4sale.com/gfwlist server=/.cloakpoint.com/127.0.0.1#5335 ipset=/.cloakpoint.com/gfwlist server=/.cloud.feedly.com/127.0.0.1#5335 @@ -1790,8 +1744,6 @@ server=/.cn.freeones.com/127.0.0.1#5335 ipset=/.cn.freeones.com/gfwlist server=/.cn.ibtimes.com/127.0.0.1#5335 ipset=/.cn.ibtimes.com/gfwlist -server=/.cn.nytstyle.com/127.0.0.1#5335 -ipset=/.cn.nytstyle.com/gfwlist server=/.cn.sandscotaicentral.com/127.0.0.1#5335 ipset=/.cn.sandscotaicentral.com/gfwlist server=/.cn.shafaqna.com/127.0.0.1#5335 @@ -1948,8 +1900,6 @@ server=/.cristyli.com/127.0.0.1#5335 ipset=/.cristyli.com/gfwlist server=/.crocotube.com/127.0.0.1#5335 ipset=/.crocotube.com/gfwlist -server=/.crossfire.co.kr/127.0.0.1#5335 -ipset=/.crossfire.co.kr/gfwlist server=/.crossthewall.net/127.0.0.1#5335 ipset=/.crossthewall.net/gfwlist server=/.crossvpn.net/127.0.0.1#5335 @@ -2116,8 +2066,6 @@ server=/.darktech.org/127.0.0.1#5335 ipset=/.darktech.org/gfwlist server=/.darktoy.net/127.0.0.1#5335 ipset=/.darktoy.net/gfwlist -server=/.darpa.mil/127.0.0.1#5335 -ipset=/.darpa.mil/gfwlist server=/.dastrassi.org/127.0.0.1#5335 ipset=/.dastrassi.org/gfwlist server=/.data-vocabulary.org/127.0.0.1#5335 @@ -2130,8 +2078,6 @@ server=/.daum.net/127.0.0.1#5335 ipset=/.daum.net/gfwlist server=/.david-kilgour.com/127.0.0.1#5335 ipset=/.david-kilgour.com/gfwlist -server=/.dawangidc.com/127.0.0.1#5335 -ipset=/.dawangidc.com/gfwlist server=/.daxa.cn/127.0.0.1#5335 ipset=/.daxa.cn/gfwlist server=/.db.tt/127.0.0.1#5335 @@ -2166,6 +2112,8 @@ server=/.deck.ly/127.0.0.1#5335 ipset=/.deck.ly/gfwlist server=/.decodet.co/127.0.0.1#5335 ipset=/.decodet.co/gfwlist +server=/.deepdiscount.com/127.0.0.1#5335 +ipset=/.deepdiscount.com/gfwlist server=/.deepmind.com/127.0.0.1#5335 ipset=/.deepmind.com/gfwlist server=/.deezer.com/127.0.0.1#5335 @@ -2228,8 +2176,6 @@ server=/.diigo.com/127.0.0.1#5335 ipset=/.diigo.com/gfwlist server=/.dilber.se/127.0.0.1#5335 ipset=/.dilber.se/gfwlist -server=/.dingchin.com.tw/127.0.0.1#5335 -ipset=/.dingchin.com.tw/gfwlist server=/.dipity.com/127.0.0.1#5335 ipset=/.dipity.com/gfwlist server=/.directcreative.com/127.0.0.1#5335 @@ -2270,14 +2216,10 @@ server=/.dlsite.com/127.0.0.1#5335 ipset=/.dlsite.com/gfwlist server=/.dlyoutube.com/127.0.0.1#5335 ipset=/.dlyoutube.com/gfwlist -server=/.dm530.net/127.0.0.1#5335 -ipset=/.dm530.net/gfwlist server=/.dmcdn.net/127.0.0.1#5335 ipset=/.dmcdn.net/gfwlist server=/.dmhy.org/127.0.0.1#5335 ipset=/.dmhy.org/gfwlist -server=/.dmm.co.jp/127.0.0.1#5335 -ipset=/.dmm.co.jp/gfwlist server=/.dns-dns.com/127.0.0.1#5335 ipset=/.dns-dns.com/gfwlist server=/.dns-stuff.com/127.0.0.1#5335 @@ -2302,8 +2244,6 @@ server=/.dnsrd.com/127.0.0.1#5335 ipset=/.dnsrd.com/gfwlist server=/.dnssec.net/127.0.0.1#5335 ipset=/.dnssec.net/gfwlist -server=/.dnvod.tv/127.0.0.1#5335 -ipset=/.dnvod.tv/gfwlist server=/.doctorvoice.org/127.0.0.1#5335 ipset=/.doctorvoice.org/gfwlist server=/.documentingreality.com/127.0.0.1#5335 @@ -2338,6 +2278,8 @@ server=/.dontmovetochina.com/127.0.0.1#5335 ipset=/.dontmovetochina.com/gfwlist server=/.dorjeshugden.com/127.0.0.1#5335 ipset=/.dorjeshugden.com/gfwlist +server=/.dotgov.gov/127.0.0.1#5335 +ipset=/.dotgov.gov/gfwlist server=/.dotplane.com/127.0.0.1#5335 ipset=/.dotplane.com/gfwlist server=/.dotsub.com/127.0.0.1#5335 @@ -2554,8 +2496,6 @@ server=/.edubridge.com/127.0.0.1#5335 ipset=/.edubridge.com/gfwlist server=/.edupro.org/127.0.0.1#5335 ipset=/.edupro.org/gfwlist -server=/.eesti.ee/127.0.0.1#5335 -ipset=/.eesti.ee/gfwlist server=/.eevpn.com/127.0.0.1#5335 ipset=/.eevpn.com/gfwlist server=/.efcc.org.hk/127.0.0.1#5335 @@ -2702,8 +2642,6 @@ server=/.eslite.com/127.0.0.1#5335 ipset=/.eslite.com/gfwlist server=/.esmtp.biz/127.0.0.1#5335 ipset=/.esmtp.biz/gfwlist -server=/.esurance.com/127.0.0.1#5335 -ipset=/.esurance.com/gfwlist server=/.etaa.org.au/127.0.0.1#5335 ipset=/.etaa.org.au/gfwlist server=/.etadult.com/127.0.0.1#5335 @@ -2910,8 +2848,6 @@ server=/.farwestchina.com/127.0.0.1#5335 ipset=/.farwestchina.com/gfwlist server=/.fast.wistia.com/127.0.0.1#5335 ipset=/.fast.wistia.com/gfwlist -server=/.fastpic.ru/127.0.0.1#5335 -ipset=/.fastpic.ru/gfwlist server=/.fastssh.com/127.0.0.1#5335 ipset=/.fastssh.com/gfwlist server=/.faststone.org/127.0.0.1#5335 @@ -2996,16 +2932,12 @@ server=/.fileflyer.com/127.0.0.1#5335 ipset=/.fileflyer.com/gfwlist server=/.files2me.com/127.0.0.1#5335 ipset=/.files2me.com/gfwlist -server=/.filesor.com/127.0.0.1#5335 -ipset=/.filesor.com/gfwlist server=/.fillthesquare.org/127.0.0.1#5335 ipset=/.fillthesquare.org/gfwlist server=/.filmingfortibet.org/127.0.0.1#5335 ipset=/.filmingfortibet.org/gfwlist server=/.filthdump.com/127.0.0.1#5335 ipset=/.filthdump.com/gfwlist -server=/.financetwitter.com/127.0.0.1#5335 -ipset=/.financetwitter.com/gfwlist server=/.finchvpn.com/127.0.0.1#5335 ipset=/.finchvpn.com/gfwlist server=/.findmespot.com/127.0.0.1#5335 @@ -3062,10 +2994,6 @@ server=/.flyvpn.com/127.0.0.1#5335 ipset=/.flyvpn.com/gfwlist server=/.flyzy2005.com/127.0.0.1#5335 ipset=/.flyzy2005.com/gfwlist -server=/.fnac.be/127.0.0.1#5335 -ipset=/.fnac.be/gfwlist -server=/.fnac.com/127.0.0.1#5335 -ipset=/.fnac.com/gfwlist server=/.fochk.org/127.0.0.1#5335 ipset=/.fochk.org/gfwlist server=/.focustaiwan.tw/127.0.0.1#5335 @@ -3318,8 +3246,6 @@ server=/.fw.cm/127.0.0.1#5335 ipset=/.fw.cm/gfwlist server=/.fxcm-chinese.com/127.0.0.1#5335 ipset=/.fxcm-chinese.com/gfwlist -server=/.fxnetworks.com/127.0.0.1#5335 -ipset=/.fxnetworks.com/gfwlist server=/.fzh999.com/127.0.0.1#5335 ipset=/.fzh999.com/gfwlist server=/.fzh999.net/127.0.0.1#5335 @@ -3470,10 +3396,6 @@ server=/.getsync.com/127.0.0.1#5335 ipset=/.getsync.com/gfwlist server=/.gettrials.com/127.0.0.1#5335 ipset=/.gettrials.com/gfwlist -server=/.gettyimages.com/127.0.0.1#5335 -ipset=/.gettyimages.com/gfwlist -server=/.getuploader.com/127.0.0.1#5335 -ipset=/.getuploader.com/gfwlist server=/.gfbv.de/127.0.0.1#5335 ipset=/.gfbv.de/gfwlist server=/.gfgold.com.hk/127.0.0.1#5335 @@ -3512,8 +3434,6 @@ server=/.gjczz.com/127.0.0.1#5335 ipset=/.gjczz.com/gfwlist server=/.glass8.eu/127.0.0.1#5335 ipset=/.glass8.eu/gfwlist -server=/.global.bing.com/127.0.0.1#5335 -ipset=/.global.bing.com/gfwlist server=/.globaljihad.net/127.0.0.1#5335 ipset=/.globaljihad.net/gfwlist server=/.globalmediaoutreach.com/127.0.0.1#5335 @@ -3536,8 +3456,6 @@ server=/.gloryhole.com/127.0.0.1#5335 ipset=/.gloryhole.com/gfwlist server=/.glorystar.me/127.0.0.1#5335 ipset=/.glorystar.me/gfwlist -server=/.glype.com/127.0.0.1#5335 -ipset=/.glype.com/gfwlist server=/.gmail.com/127.0.0.1#5335 ipset=/.gmail.com/gfwlist server=/.gmbd.cn/127.0.0.1#5335 @@ -4214,10 +4132,6 @@ server=/.hkzone.org/127.0.0.1#5335 ipset=/.hkzone.org/gfwlist server=/.hmonghot.com/127.0.0.1#5335 ipset=/.hmonghot.com/gfwlist -server=/.hmvdigital.ca/127.0.0.1#5335 -ipset=/.hmvdigital.ca/gfwlist -server=/.hmvdigital.com/127.0.0.1#5335 -ipset=/.hmvdigital.com/gfwlist server=/.hnjhj.com/127.0.0.1#5335 ipset=/.hnjhj.com/gfwlist server=/.hnntube.com/127.0.0.1#5335 @@ -4234,8 +4148,6 @@ server=/.holyspiritspeaks.org/127.0.0.1#5335 ipset=/.holyspiritspeaks.org/gfwlist server=/.home.sina.com/127.0.0.1#5335 ipset=/.home.sina.com/gfwlist -server=/.homedepot.com/127.0.0.1#5335 -ipset=/.homedepot.com/gfwlist server=/.homeperversion.com/127.0.0.1#5335 ipset=/.homeperversion.com/gfwlist server=/.homeservershow.com/127.0.0.1#5335 @@ -4248,8 +4160,6 @@ server=/.hongzhi.li/127.0.0.1#5335 ipset=/.hongzhi.li/gfwlist server=/.hootsuite.com/127.0.0.1#5335 ipset=/.hootsuite.com/gfwlist -server=/.hoovers.com/127.0.0.1#5335 -ipset=/.hoovers.com/gfwlist server=/.hopedialogue.org/127.0.0.1#5335 ipset=/.hopedialogue.org/gfwlist server=/.hopto.org/127.0.0.1#5335 @@ -4522,8 +4432,6 @@ server=/.illusionfactory.com/127.0.0.1#5335 ipset=/.illusionfactory.com/gfwlist server=/.ilove80.be/127.0.0.1#5335 ipset=/.ilove80.be/gfwlist -server=/.ilovelongtoes.com/127.0.0.1#5335 -ipset=/.ilovelongtoes.com/gfwlist server=/.im.tv/127.0.0.1#5335 ipset=/.im.tv/gfwlist server=/.im88.tw/127.0.0.1#5335 @@ -4536,8 +4444,6 @@ server=/.imageflea.com/127.0.0.1#5335 ipset=/.imageflea.com/gfwlist server=/.images-gaytube.com/127.0.0.1#5335 ipset=/.images-gaytube.com/gfwlist -server=/.images.comico.tw/127.0.0.1#5335 -ipset=/.images.comico.tw/gfwlist server=/.imageshack.us/127.0.0.1#5335 ipset=/.imageshack.us/gfwlist server=/.imagevenue.com/127.0.0.1#5335 @@ -4664,8 +4570,6 @@ server=/.isaacmao.com/127.0.0.1#5335 ipset=/.isaacmao.com/gfwlist server=/.isasecret.com/127.0.0.1#5335 ipset=/.isasecret.com/gfwlist -server=/.isc.sans.edu/127.0.0.1#5335 -ipset=/.isc.sans.edu/gfwlist server=/.isgreat.org/127.0.0.1#5335 ipset=/.isgreat.org/gfwlist server=/.islahhaber.net/127.0.0.1#5335 @@ -4770,6 +4674,8 @@ server=/.jav68.tv/127.0.0.1#5335 ipset=/.jav68.tv/gfwlist server=/.javakiba.org/127.0.0.1#5335 ipset=/.javakiba.org/gfwlist +server=/.javbus.co/127.0.0.1#5335 +ipset=/.javbus.co/gfwlist server=/.javbus.com/127.0.0.1#5335 ipset=/.javbus.com/gfwlist server=/.javfor.me/127.0.0.1#5335 @@ -4778,10 +4684,6 @@ server=/.javhd.com/127.0.0.1#5335 ipset=/.javhd.com/gfwlist server=/.javhip.com/127.0.0.1#5335 ipset=/.javhip.com/gfwlist -server=/.javhub.net/127.0.0.1#5335 -ipset=/.javhub.net/gfwlist -server=/.javhuge.com/127.0.0.1#5335 -ipset=/.javhuge.com/gfwlist server=/.javlibrary.com/127.0.0.1#5335 ipset=/.javlibrary.com/gfwlist server=/.javmobile.net/127.0.0.1#5335 @@ -4804,8 +4706,6 @@ server=/.jbtalks.com/127.0.0.1#5335 ipset=/.jbtalks.com/gfwlist server=/.jbtalks.my/127.0.0.1#5335 ipset=/.jbtalks.my/gfwlist -server=/.jcpenney.com/127.0.0.1#5335 -ipset=/.jcpenney.com/gfwlist server=/.jdwsy.com/127.0.0.1#5335 ipset=/.jdwsy.com/gfwlist server=/.jeanyim.com/127.0.0.1#5335 @@ -4838,8 +4738,6 @@ server=/.jihadology.net/127.0.0.1#5335 ipset=/.jihadology.net/gfwlist server=/.jiji.com/127.0.0.1#5335 ipset=/.jiji.com/gfwlist -server=/.jims.net/127.0.0.1#5335 -ipset=/.jims.net/gfwlist server=/.jinbushe.org/127.0.0.1#5335 ipset=/.jinbushe.org/gfwlist server=/.jingpin.org/127.0.0.1#5335 @@ -4974,8 +4872,6 @@ server=/.kawaiikawaii.jp/127.0.0.1#5335 ipset=/.kawaiikawaii.jp/gfwlist server=/.kawase.com/127.0.0.1#5335 ipset=/.kawase.com/gfwlist -server=/.kb.monitorware.com/127.0.0.1#5335 -ipset=/.kb.monitorware.com/gfwlist server=/.kba-tx.org/127.0.0.1#5335 ipset=/.kba-tx.org/gfwlist server=/.kcoolonline.com/127.0.0.1#5335 @@ -5002,8 +4898,6 @@ server=/.keycdn.com/127.0.0.1#5335 ipset=/.keycdn.com/gfwlist server=/.khabdha.org/127.0.0.1#5335 ipset=/.khabdha.org/gfwlist -server=/.khatrimaza.org/127.0.0.1#5335 -ipset=/.khatrimaza.org/gfwlist server=/.khmusic.com.tw/127.0.0.1#5335 ipset=/.khmusic.com.tw/gfwlist server=/.kichiku-doujinko.com/127.0.0.1#5335 @@ -5166,8 +5060,6 @@ server=/.leirentv.ca/127.0.0.1#5335 ipset=/.leirentv.ca/gfwlist server=/.leisurecafe.ca/127.0.0.1#5335 ipset=/.leisurecafe.ca/gfwlist -server=/.leisurepro.com/127.0.0.1#5335 -ipset=/.leisurepro.com/gfwlist server=/.lematin.ch/127.0.0.1#5335 ipset=/.lematin.ch/gfwlist server=/.lemonde.fr/127.0.0.1#5335 @@ -5208,8 +5100,6 @@ server=/.liberal.org.hk/127.0.0.1#5335 ipset=/.liberal.org.hk/gfwlist server=/.libertytimes.com.tw/127.0.0.1#5335 ipset=/.libertytimes.com.tw/gfwlist -server=/.lifemiles.com/127.0.0.1#5335 -ipset=/.lifemiles.com/gfwlist server=/.lighten.org.tw/127.0.0.1#5335 ipset=/.lighten.org.tw/gfwlist server=/.lighti.me/127.0.0.1#5335 @@ -5316,8 +5206,6 @@ server=/.longmusic.com/127.0.0.1#5335 ipset=/.longmusic.com/gfwlist server=/.longtermly.net/127.0.0.1#5335 ipset=/.longtermly.net/gfwlist -server=/.longtoes.com/127.0.0.1#5335 -ipset=/.longtoes.com/gfwlist server=/.lookpic.com/127.0.0.1#5335 ipset=/.lookpic.com/gfwlist server=/.looktoronto.com/127.0.0.1#5335 @@ -5376,8 +5264,6 @@ server=/.m.plixi.com/127.0.0.1#5335 ipset=/.m.plixi.com/gfwlist server=/.m.slandr.net/127.0.0.1#5335 ipset=/.m.slandr.net/gfwlist -server=/.macgamestore.com/127.0.0.1#5335 -ipset=/.macgamestore.com/gfwlist server=/.macrovpn.com/127.0.0.1#5335 ipset=/.macrovpn.com/gfwlist server=/.macts.com.tw/127.0.0.1#5335 @@ -5420,10 +5306,6 @@ server=/.mamingzhe.com/127.0.0.1#5335 ipset=/.mamingzhe.com/gfwlist server=/.manchukuo.net/127.0.0.1#5335 ipset=/.manchukuo.net/gfwlist -server=/.mangafox.com/127.0.0.1#5335 -ipset=/.mangafox.com/gfwlist -server=/.mangafox.me/127.0.0.1#5335 -ipset=/.mangafox.me/gfwlist server=/.maniash.com/127.0.0.1#5335 ipset=/.maniash.com/gfwlist server=/.manicur4ik.ru/127.0.0.1#5335 @@ -5574,8 +5456,6 @@ server=/.meyou.jp/127.0.0.1#5335 ipset=/.meyou.jp/gfwlist server=/.meyul.com/127.0.0.1#5335 ipset=/.meyul.com/gfwlist -server=/.mfxmedia.com/127.0.0.1#5335 -ipset=/.mfxmedia.com/gfwlist server=/.mgoon.com/127.0.0.1#5335 ipset=/.mgoon.com/gfwlist server=/.mgstage.com/127.0.0.1#5335 @@ -5746,8 +5626,6 @@ server=/.moodyz.com/127.0.0.1#5335 ipset=/.moodyz.com/gfwlist server=/.moonbbs.com/127.0.0.1#5335 ipset=/.moonbbs.com/gfwlist -server=/.moonbingo.com/127.0.0.1#5335 -ipset=/.moonbingo.com/gfwlist server=/.morningsun.org/127.0.0.1#5335 ipset=/.morningsun.org/gfwlist server=/.moroneta.com/127.0.0.1#5335 @@ -5824,8 +5702,6 @@ server=/.muzi.com/127.0.0.1#5335 ipset=/.muzi.com/gfwlist server=/.muzi.net/127.0.0.1#5335 ipset=/.muzi.net/gfwlist -server=/.muzu.tv/127.0.0.1#5335 -ipset=/.muzu.tv/gfwlist server=/.mvdis.gov.tw/127.0.0.1#5335 ipset=/.mvdis.gov.tw/gfwlist server=/.mvg.jp/127.0.0.1#5335 @@ -5986,6 +5862,8 @@ server=/.nccwatch.org.tw/127.0.0.1#5335 ipset=/.nccwatch.org.tw/gfwlist server=/.nch.com.tw/127.0.0.1#5335 ipset=/.nch.com.tw/gfwlist +server=/.nchrd.org/127.0.0.1#5335 +ipset=/.nchrd.org/gfwlist server=/.ncn.org/127.0.0.1#5335 ipset=/.ncn.org/gfwlist server=/.nde.de/127.0.0.1#5335 @@ -5996,8 +5874,6 @@ server=/.ned.org/127.0.0.1#5335 ipset=/.ned.org/gfwlist server=/.nekoslovakia.net/127.0.0.1#5335 ipset=/.nekoslovakia.net/gfwlist -server=/.neo-miracle.com/127.0.0.1#5335 -ipset=/.neo-miracle.com/gfwlist server=/.nepusoku.com/127.0.0.1#5335 ipset=/.nepusoku.com/gfwlist server=/.net-fits.pro/127.0.0.1#5335 @@ -6128,8 +6004,6 @@ server=/.nic.cz.cc/127.0.0.1#5335 ipset=/.nic.cz.cc/gfwlist server=/.nic.google/127.0.0.1#5335 ipset=/.nic.google/gfwlist -server=/.nic.gov/127.0.0.1#5335 -ipset=/.nic.gov/gfwlist server=/.nicovideo.jp/127.0.0.1#5335 ipset=/.nicovideo.jp/gfwlist server=/.nighost.org/127.0.0.1#5335 @@ -6176,16 +6050,14 @@ server=/.norbulingka.org/127.0.0.1#5335 ipset=/.norbulingka.org/gfwlist server=/.nordstrom.com/127.0.0.1#5335 ipset=/.nordstrom.com/gfwlist -server=/.nordstromimage.com/127.0.0.1#5335 -ipset=/.nordstromimage.com/gfwlist +server=/.nordstrommedia.com/127.0.0.1#5335 +ipset=/.nordstrommedia.com/gfwlist server=/.nordstromrack.com/127.0.0.1#5335 ipset=/.nordstromrack.com/gfwlist server=/.nordvpn.com/127.0.0.1#5335 ipset=/.nordvpn.com/gfwlist server=/.notify.dropboxapi.com/127.0.0.1#5335 ipset=/.notify.dropboxapi.com/gfwlist -server=/.nottinghampost.com/127.0.0.1#5335 -ipset=/.nottinghampost.com/gfwlist server=/.novelasia.com/127.0.0.1#5335 ipset=/.novelasia.com/gfwlist server=/.now.com/127.0.0.1#5335 @@ -6206,8 +6078,6 @@ server=/.npnt.me/127.0.0.1#5335 ipset=/.npnt.me/gfwlist server=/.nps.gov/127.0.0.1#5335 ipset=/.nps.gov/gfwlist -server=/.npsboost.com/127.0.0.1#5335 -ipset=/.npsboost.com/gfwlist server=/.nradio.me/127.0.0.1#5335 ipset=/.nradio.me/gfwlist server=/.nrk.no/127.0.0.1#5335 @@ -6246,8 +6116,6 @@ server=/.ntdtv.co.kr/127.0.0.1#5335 ipset=/.ntdtv.co.kr/gfwlist server=/.ntdtv.com/127.0.0.1#5335 ipset=/.ntdtv.com/gfwlist -server=/.ntdtv.cz/127.0.0.1#5335 -ipset=/.ntdtv.cz/gfwlist server=/.ntdtv.org/127.0.0.1#5335 ipset=/.ntdtv.org/gfwlist server=/.ntdtv.ru/127.0.0.1#5335 @@ -6260,14 +6128,14 @@ server=/.ntsna.gov.tw/127.0.0.1#5335 ipset=/.ntsna.gov.tw/gfwlist server=/.nubiles.net/127.0.0.1#5335 ipset=/.nubiles.net/gfwlist +server=/.nudezz.com/127.0.0.1#5335 +ipset=/.nudezz.com/gfwlist server=/.nuexpo.com/127.0.0.1#5335 ipset=/.nuexpo.com/gfwlist server=/.nukistream.com/127.0.0.1#5335 ipset=/.nukistream.com/gfwlist server=/.nurgo-software.com/127.0.0.1#5335 ipset=/.nurgo-software.com/gfwlist -server=/.nusatrip.com/127.0.0.1#5335 -ipset=/.nusatrip.com/gfwlist server=/.nutaku.net/127.0.0.1#5335 ipset=/.nutaku.net/gfwlist server=/.nuuvem.com/127.0.0.1#5335 @@ -6332,6 +6200,8 @@ server=/.ocreampies.com/127.0.0.1#5335 ipset=/.ocreampies.com/gfwlist server=/.ocry.com/127.0.0.1#5335 ipset=/.ocry.com/gfwlist +server=/.ocsp.int-x3.letsencrypt.org/127.0.0.1#5335 +ipset=/.ocsp.int-x3.letsencrypt.org/gfwlist server=/.october-review.org/127.0.0.1#5335 ipset=/.october-review.org/gfwlist server=/.oculus.com/127.0.0.1#5335 @@ -6382,8 +6252,6 @@ server=/.on.cc/127.0.0.1#5335 ipset=/.on.cc/gfwlist server=/.on2.com/127.0.0.1#5335 ipset=/.on2.com/gfwlist -server=/.onapp.com/127.0.0.1#5335 -ipset=/.onapp.com/gfwlist server=/.onedrive.live.com/127.0.0.1#5335 ipset=/.onedrive.live.com/gfwlist server=/.onedumb.com/127.0.0.1#5335 @@ -6416,8 +6284,6 @@ server=/.onmypc.us/127.0.0.1#5335 ipset=/.onmypc.us/gfwlist server=/.onthehunt.com/127.0.0.1#5335 ipset=/.onthehunt.com/gfwlist -server=/.ontrac.com/127.0.0.1#5335 -ipset=/.ontrac.com/gfwlist server=/.oopsforum.com/127.0.0.1#5335 ipset=/.oopsforum.com/gfwlist server=/.open.com.hk/127.0.0.1#5335 @@ -6552,8 +6418,8 @@ server=/.paradisehill.cc/127.0.0.1#5335 ipset=/.paradisehill.cc/gfwlist server=/.paradisepoker.com/127.0.0.1#5335 ipset=/.paradisepoker.com/gfwlist -server=/.parkansky.com/127.0.0.1#5335 -ipset=/.parkansky.com/gfwlist +server=/.parts.blog.livedoor.jp/127.0.0.1#5335 +ipset=/.parts.blog.livedoor.jp/gfwlist server=/.partycasino.com/127.0.0.1#5335 ipset=/.partycasino.com/gfwlist server=/.partypoker.com/127.0.0.1#5335 @@ -6906,6 +6772,8 @@ server=/.proxomitron.info/127.0.0.1#5335 ipset=/.proxomitron.info/gfwlist server=/.proxpn.com/127.0.0.1#5335 ipset=/.proxpn.com/gfwlist +server=/.proxy.org/127.0.0.1#5335 +ipset=/.proxy.org/gfwlist server=/.proxy1.xyz/127.0.0.1#5335 ipset=/.proxy1.xyz/gfwlist server=/.proxyanonimo.es/127.0.0.1#5335 @@ -6948,6 +6816,8 @@ server=/.pttvan.org/127.0.0.1#5335 ipset=/.pttvan.org/gfwlist server=/.pubu.com.tw/127.0.0.1#5335 ipset=/.pubu.com.tw/gfwlist +server=/.puffin.com/127.0.0.1#5335 +ipset=/.puffin.com/gfwlist server=/.puffinbrowser.com/127.0.0.1#5335 ipset=/.puffinbrowser.com/gfwlist server=/.puffstore.com/127.0.0.1#5335 @@ -6956,8 +6826,6 @@ server=/.pullfolio.com/127.0.0.1#5335 ipset=/.pullfolio.com/gfwlist server=/.pulse.yahoo.com/127.0.0.1#5335 ipset=/.pulse.yahoo.com/gfwlist -server=/.pure18.com/127.0.0.1#5335 -ipset=/.pure18.com/gfwlist server=/.pureconcepts.net/127.0.0.1#5335 ipset=/.pureconcepts.net/gfwlist server=/.pureinsight.org/127.0.0.1#5335 @@ -6984,8 +6852,6 @@ server=/.pwned.com/127.0.0.1#5335 ipset=/.pwned.com/gfwlist server=/.python.com/127.0.0.1#5335 ipset=/.python.com/gfwlist -server=/.pytorch.org/127.0.0.1#5335 -ipset=/.pytorch.org/gfwlist server=/.qanote.com/127.0.0.1#5335 ipset=/.qanote.com/gfwlist server=/.qgirl.com.tw/127.0.0.1#5335 @@ -7012,8 +6878,6 @@ server=/.qoos.com/127.0.0.1#5335 ipset=/.qoos.com/gfwlist server=/.qpoe.com/127.0.0.1#5335 ipset=/.qpoe.com/gfwlist -server=/.qq.co.za/127.0.0.1#5335 -ipset=/.qq.co.za/gfwlist server=/.qstatus.com/127.0.0.1#5335 ipset=/.qstatus.com/gfwlist server=/.qtrac.eu/127.0.0.1#5335 @@ -7046,8 +6910,6 @@ server=/.qxbbs.org/127.0.0.1#5335 ipset=/.qxbbs.org/gfwlist server=/.qz.com/127.0.0.1#5335 ipset=/.qz.com/gfwlist -server=/.r18.com/127.0.0.1#5335 -ipset=/.r18.com/gfwlist server=/.ra.gg/127.0.0.1#5335 ipset=/.ra.gg/gfwlist server=/.radicalparty.org/127.0.0.1#5335 @@ -7070,8 +6932,8 @@ server=/.raidtalk.com.tw/127.0.0.1#5335 ipset=/.raidtalk.com.tw/gfwlist server=/.raizoji.or.jp/127.0.0.1#5335 ipset=/.raizoji.or.jp/gfwlist -server=/.ramcity.com.au/127.0.0.1#5335 -ipset=/.ramcity.com.au/gfwlist +server=/.rakuten.co.jp/127.0.0.1#5335 +ipset=/.rakuten.co.jp/gfwlist server=/.rangwang.biz/127.0.0.1#5335 ipset=/.rangwang.biz/gfwlist server=/.rangzen.com/127.0.0.1#5335 @@ -7108,10 +6970,6 @@ server=/.rcinet.ca/127.0.0.1#5335 ipset=/.rcinet.ca/gfwlist server=/.rconversation.blogs.com/127.0.0.1#5335 ipset=/.rconversation.blogs.com/gfwlist -server=/.rd.com/127.0.0.1#5335 -ipset=/.rd.com/gfwlist -server=/.rdio.com/127.0.0.1#5335 -ipset=/.rdio.com/gfwlist server=/.read01.com/127.0.0.1#5335 ipset=/.read01.com/gfwlist server=/.read100.com/127.0.0.1#5335 @@ -7126,8 +6984,6 @@ server=/.realcourage.org/127.0.0.1#5335 ipset=/.realcourage.org/gfwlist server=/.realforum.zkiz.com/127.0.0.1#5335 ipset=/.realforum.zkiz.com/gfwlist -server=/.realitykings.com/127.0.0.1#5335 -ipset=/.realitykings.com/gfwlist server=/.realraptalk.com/127.0.0.1#5335 ipset=/.realraptalk.com/gfwlist server=/.realsexpass.com/127.0.0.1#5335 @@ -7298,8 +7154,6 @@ server=/.s-cute.com/127.0.0.1#5335 ipset=/.s-cute.com/gfwlist server=/.s-dragon.org/127.0.0.1#5335 ipset=/.s-dragon.org/gfwlist -server=/.s1.nudezz.com/127.0.0.1#5335 -ipset=/.s1.nudezz.com/gfwlist server=/.s1heng.com/127.0.0.1#5335 ipset=/.s1heng.com/gfwlist server=/.s1s1s1.com/127.0.0.1#5335 @@ -7472,8 +7326,6 @@ server=/.sexinsex.net/127.0.0.1#5335 ipset=/.sexinsex.net/gfwlist server=/.sextvx.com/127.0.0.1#5335 ipset=/.sextvx.com/gfwlist -server=/.sexxxy.biz/127.0.0.1#5335 -ipset=/.sexxxy.biz/gfwlist server=/.sfileydy.com/127.0.0.1#5335 ipset=/.sfileydy.com/gfwlist server=/.sfshibao.com/127.0.0.1#5335 @@ -7514,8 +7366,6 @@ server=/.shapeservices.com/127.0.0.1#5335 ipset=/.shapeservices.com/gfwlist server=/.share.america.gov/127.0.0.1#5335 ipset=/.share.america.gov/gfwlist -server=/.share.dmhy.org/127.0.0.1#5335 -ipset=/.share.dmhy.org/gfwlist server=/.share.youthwant.com.tw/127.0.0.1#5335 ipset=/.share.youthwant.com.tw/gfwlist server=/.sharebee.com/127.0.0.1#5335 @@ -7552,6 +7402,8 @@ server=/.shicheng.org/127.0.0.1#5335 ipset=/.shicheng.org/gfwlist server=/.shiksha.com/127.0.0.1#5335 ipset=/.shiksha.com/gfwlist +server=/.shiksha.ws/127.0.0.1#5335 +ipset=/.shiksha.ws/gfwlist server=/.shinychan.com/127.0.0.1#5335 ipset=/.shinychan.com/gfwlist server=/.shipcamouflage.com/127.0.0.1#5335 @@ -7670,8 +7522,6 @@ server=/.skyvegas.com/127.0.0.1#5335 ipset=/.skyvegas.com/gfwlist server=/.skyxvpn.com/127.0.0.1#5335 ipset=/.skyxvpn.com/gfwlist -server=/.slacker.com/127.0.0.1#5335 -ipset=/.slacker.com/gfwlist server=/.slaytizle.com/127.0.0.1#5335 ipset=/.slaytizle.com/gfwlist server=/.sleazydream.com/127.0.0.1#5335 @@ -7812,8 +7662,6 @@ server=/.southnews.com.tw/127.0.0.1#5335 ipset=/.southnews.com.tw/gfwlist server=/.sowers.org.hk/127.0.0.1#5335 ipset=/.sowers.org.hk/gfwlist -server=/.soylentnews.org/127.0.0.1#5335 -ipset=/.soylentnews.org/gfwlist server=/.spaces.hightail.com/127.0.0.1#5335 ipset=/.spaces.hightail.com/gfwlist server=/.spankbang.com/127.0.0.1#5335 @@ -7848,12 +7696,8 @@ server=/.spotflux.com/127.0.0.1#5335 ipset=/.spotflux.com/gfwlist server=/.spotify.com/127.0.0.1#5335 ipset=/.spotify.com/gfwlist -server=/.spreadshirt.es/127.0.0.1#5335 -ipset=/.spreadshirt.es/gfwlist server=/.spring4u.info/127.0.0.1#5335 ipset=/.spring4u.info/gfwlist -server=/.springboardplatform.com/127.0.0.1#5335 -ipset=/.springboardplatform.com/gfwlist server=/.sproutcore.com/127.0.0.1#5335 ipset=/.sproutcore.com/gfwlist server=/.sproxy.info/127.0.0.1#5335 @@ -7876,8 +7720,6 @@ server=/.ssglobal.me/127.0.0.1#5335 ipset=/.ssglobal.me/gfwlist server=/.ssh91.com/127.0.0.1#5335 ipset=/.ssh91.com/gfwlist -server=/.ssl.webpack.de/127.0.0.1#5335 -ipset=/.ssl.webpack.de/gfwlist server=/.ssl443.org/127.0.0.1#5335 ipset=/.ssl443.org/gfwlist server=/.sspanel.net/127.0.0.1#5335 @@ -7910,8 +7752,6 @@ server=/.stat.gov.tw/127.0.0.1#5335 ipset=/.stat.gov.tw/gfwlist server=/.static-economist.com/127.0.0.1#5335 ipset=/.static-economist.com/gfwlist -server=/.static.comico.tw/127.0.0.1#5335 -ipset=/.static.comico.tw/gfwlist server=/.static.shemalez.com/127.0.0.1#5335 ipset=/.static.shemalez.com/gfwlist server=/.static01.nyt.com/127.0.0.1#5335 @@ -8020,8 +7860,6 @@ server=/.supchina.com/127.0.0.1#5335 ipset=/.supchina.com/gfwlist server=/.superfreevpn.com/127.0.0.1#5335 ipset=/.superfreevpn.com/gfwlist -server=/.superokayama.com/127.0.0.1#5335 -ipset=/.superokayama.com/gfwlist server=/.superpages.com/127.0.0.1#5335 ipset=/.superpages.com/gfwlist server=/.supervpn.net/127.0.0.1#5335 @@ -8044,8 +7882,6 @@ server=/.suyangg.com/127.0.0.1#5335 ipset=/.suyangg.com/gfwlist server=/.svsfx.com/127.0.0.1#5335 ipset=/.svsfx.com/gfwlist -server=/.swagbucks.com/127.0.0.1#5335 -ipset=/.swagbucks.com/gfwlist server=/.swissinfo.ch/127.0.0.1#5335 ipset=/.swissinfo.ch/gfwlist server=/.swissvpn.net/127.0.0.1#5335 @@ -8164,8 +8000,6 @@ server=/.taoism.net/127.0.0.1#5335 ipset=/.taoism.net/gfwlist server=/.taolun.info/127.0.0.1#5335 ipset=/.taolun.info/gfwlist -server=/.tapanwap.com/127.0.0.1#5335 -ipset=/.tapanwap.com/gfwlist server=/.tapatalk.com/127.0.0.1#5335 ipset=/.tapatalk.com/gfwlist server=/.tascn.com.au/127.0.0.1#5335 @@ -9408,8 +9242,6 @@ server=/.vocn.tv/127.0.0.1#5335 ipset=/.vocn.tv/gfwlist server=/.vod-abematv.akamaized.net/127.0.0.1#5335 ipset=/.vod-abematv.akamaized.net/gfwlist -server=/.vod.wwe.com/127.0.0.1#5335 -ipset=/.vod.wwe.com/gfwlist server=/.vot.org/127.0.0.1#5335 ipset=/.vot.org/gfwlist server=/.vovo2000.com/127.0.0.1#5335 @@ -9690,8 +9522,6 @@ server=/.wheelockslatin.com/127.0.0.1#5335 ipset=/.wheelockslatin.com/gfwlist server=/.whereiswerner.com/127.0.0.1#5335 ipset=/.whereiswerner.com/gfwlist -server=/.wheretowatch.com/127.0.0.1#5335 -ipset=/.wheretowatch.com/gfwlist server=/.whichav.com/127.0.0.1#5335 ipset=/.whichav.com/gfwlist server=/.whippedass.com/127.0.0.1#5335 @@ -9744,6 +9574,8 @@ server=/.wikimapia.org/127.0.0.1#5335 ipset=/.wikimapia.org/gfwlist server=/.wikipedia.org/127.0.0.1#5335 ipset=/.wikipedia.org/gfwlist +server=/.wikiwand.com/127.0.0.1#5335 +ipset=/.wikiwand.com/gfwlist server=/.wikiwiki.jp/127.0.0.1#5335 ipset=/.wikiwiki.jp/gfwlist server=/.wildammo.com/127.0.0.1#5335 @@ -9756,8 +9588,6 @@ server=/.windowsphoneme.com/127.0.0.1#5335 ipset=/.windowsphoneme.com/gfwlist server=/.windscribe.com/127.0.0.1#5335 ipset=/.windscribe.com/gfwlist -server=/.wingamestore.com/127.0.0.1#5335 -ipset=/.wingamestore.com/gfwlist server=/.wingy.site/127.0.0.1#5335 ipset=/.wingy.site/gfwlist server=/.winning11.com/127.0.0.1#5335 @@ -9802,8 +9632,6 @@ server=/.wo3ttt.wordpress.com/127.0.0.1#5335 ipset=/.wo3ttt.wordpress.com/gfwlist server=/.woeser.com/127.0.0.1#5335 ipset=/.woeser.com/gfwlist -server=/.wokar.org/127.0.0.1#5335 -ipset=/.wokar.org/gfwlist server=/.wolfax.com/127.0.0.1#5335 ipset=/.wolfax.com/gfwlist server=/.woolyss.com/127.0.0.1#5335 @@ -9812,8 +9640,6 @@ server=/.woopie.jp/127.0.0.1#5335 ipset=/.woopie.jp/gfwlist server=/.woopie.tv/127.0.0.1#5335 ipset=/.woopie.tv/gfwlist -server=/.wordpress.com/127.0.0.1#5335 -ipset=/.wordpress.com/gfwlist server=/.workatruna.com/127.0.0.1#5335 ipset=/.workatruna.com/gfwlist server=/.workerdemo.org.hk/127.0.0.1#5335 @@ -9846,8 +9672,6 @@ server=/.woyaolian.org/127.0.0.1#5335 ipset=/.woyaolian.org/gfwlist server=/.wozy.in/127.0.0.1#5335 ipset=/.wozy.in/gfwlist -server=/.wp.com/127.0.0.1#5335 -ipset=/.wp.com/gfwlist server=/.wpoforum.com/127.0.0.1#5335 ipset=/.wpoforum.com/gfwlist server=/.wqyd.org/127.0.0.1#5335 @@ -9890,8 +9714,6 @@ server=/.wuyanblog.com/127.0.0.1#5335 ipset=/.wuyanblog.com/gfwlist server=/.wwitv.com/127.0.0.1#5335 ipset=/.wwitv.com/gfwlist -server=/.www.abclite.net/127.0.0.1#5335 -ipset=/.www.abclite.net/gfwlist server=/.www.ajsands.com/127.0.0.1#5335 ipset=/.www.ajsands.com/gfwlist server=/.www.americorps.gov/127.0.0.1#5335 @@ -9948,8 +9770,6 @@ server=/.www.websnapr.com/127.0.0.1#5335 ipset=/.www.websnapr.com/gfwlist server=/.www1.biz/127.0.0.1#5335 ipset=/.www1.biz/gfwlist -server=/.wwwhost.biz/127.0.0.1#5335 -ipset=/.wwwhost.biz/gfwlist server=/.x-art.com/127.0.0.1#5335 ipset=/.x-art.com/gfwlist server=/.x-berry.com/127.0.0.1#5335 @@ -10052,6 +9872,8 @@ server=/.xmovies.com/127.0.0.1#5335 ipset=/.xmovies.com/gfwlist server=/.xn--4gq171p.com/127.0.0.1#5335 ipset=/.xn--4gq171p.com/gfwlist +server=/.xn--90wwvt03e.com/127.0.0.1#5335 +ipset=/.xn--90wwvt03e.com/gfwlist server=/.xn--czq75pvv1aj5c.org/127.0.0.1#5335 ipset=/.xn--czq75pvv1aj5c.org/gfwlist server=/.xn--i2ru8q2qg.com/127.0.0.1#5335 @@ -10244,8 +10066,6 @@ server=/.youtubegaming.com/127.0.0.1#5335 ipset=/.youtubegaming.com/gfwlist server=/.youversion.com/127.0.0.1#5335 ipset=/.youversion.com/gfwlist -server=/.youwin.com/127.0.0.1#5335 -ipset=/.youwin.com/gfwlist server=/.youxu.info/127.0.0.1#5335 ipset=/.youxu.info/gfwlist server=/.yt.be/127.0.0.1#5335 @@ -10254,8 +10074,6 @@ server=/.ytht.net/127.0.0.1#5335 ipset=/.ytht.net/gfwlist server=/.ytimg.com/127.0.0.1#5335 ipset=/.ytimg.com/gfwlist -server=/.ytn.co.kr/127.0.0.1#5335 -ipset=/.ytn.co.kr/gfwlist server=/.yuanming.net/127.0.0.1#5335 ipset=/.yuanming.net/gfwlist server=/.yuanzhengtang.org/127.0.0.1#5335 @@ -10398,10 +10216,10 @@ server=/.zoozle.net/127.0.0.1#5335 ipset=/.zoozle.net/gfwlist server=/.zorrovpn.com/127.0.0.1#5335 ipset=/.zorrovpn.com/gfwlist -server=/.zozotown.com/127.0.0.1#5335 -ipset=/.zozotown.com/gfwlist server=/.zpn.im/127.0.0.1#5335 ipset=/.zpn.im/gfwlist +server=/.zsdxzk.com/127.0.0.1#5335 +ipset=/.zsdxzk.com/gfwlist server=/.zspeeder.me/127.0.0.1#5335 ipset=/.zspeeder.me/gfwlist server=/.zsrhao.com/127.0.0.1#5335 diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index f932fd216c..ff6082594b 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -10,10 +10,10 @@ START=95 STOP=15 - SERVICE_DAEMONIZE=1 -NAME=shadowsocksr EXTRA_COMMANDS=rules +NAME=shadowsocksr +LOCK_FILE=/var/lock/${NAME}.lock CONFIG_FILE=/var/etc/${NAME}.json CONFIG_UDP_FILE=/var/etc/${NAME}_u.json CONFIG_SOCK5_FILE=/var/etc/${NAME}_s.json @@ -28,7 +28,6 @@ kcp_flag=0 pdnsd_enable_flag=0 switch_enable=0 switch_server=$1 -MAXFD=32768 CRON_FILE=/etc/crontabs/root threads=1 @@ -42,33 +41,47 @@ uci_get_by_type() { echo ${ret:=$3} } +uci_set_by_name() { + uci set $NAME.$1.$2=$3 2>/dev/null + uci commit $NAME +} + +uci_set_by_type() { + uci set $NAME.@$1[0].$2=$3 2>/dev/null + uci commit $NAME +} + uci_get_by_cfgid() { local ret=$(uci show $NAME.@$1[0].$2 | awk -F '.' '{print $2}' 2>/dev/null) echo ${ret:=$3} } -check_host() { +get_host_ip() { local host=$1 - if echo $host | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - hostip=$host - elif [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then - hostip=$host - else - hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) - if echo $hostip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - hostip=$hostip + local isip="" + local ip=$host + isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}") + if [ -z "$isip" ]; then + if [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then + ip=$host else - hostip="127.0.0.1" + local ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}') + [ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$1 | awk -F ';' '{print $1}') fi fi - echo -e $hostip + echo ${ip:="127.0.0.1"} +} + +clean_log() { + logsnum=$(cat /tmp/ssrplus.log 2>/dev/null | wc -l) + [ "$logsnum" -gt 1000 ] && { + echo "$(date "+%Y-%m-%d %H:%M:%S") 日志文件过长,清空处理!" >/tmp/ssrplus.log + } } add_cron() { sed -i '/shadowsocksr/d' $CRON_FILE - sed -i '/ssrplus.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/ssrplus.log' >>$CRON_FILE - [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/ssrplusupdate.sh >> /tmp/ssrplus.log 2>&1" >>$CRON_FILE - + [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/ssrplusupdate.sh >>/tmp/ssrplus.log 2>&1" >>$CRON_FILE crontab $CRON_FILE } @@ -76,41 +89,58 @@ del_cron() { sed -i '/shadowsocksr/d' $CRON_FILE sed -i '/ssrplus.log/d' $CRON_FILE /etc/init.d/cron restart + clean_log } -run_mode=$(uci_get_by_type global run_mode) +unlock() { + failcount=1 + while [ "$failcount" -le 10 ]; do + if [ -f "$LOCK_FILE" ]; then + let "failcount++" + sleep 1s + [ "$failcount" -ge 10 ] && rm -f "$LOCK_FILE" + else + break + fi + done +} + +find_bin() { + case "$1" in + ss) ret="/usr/bin/ss-redir" ;; + ss-local) ret="/usr/bin/ss-local" ;; + ssr) ret="/usr/bin/ssr-redir" ;; + ssr-local) ret="/usr/bin/ssr-local" ;; + ssr-server) ret="/usr/bin/ssr-server" ;; + v2ray) ret="/usr/bin/v2ray/v2ray" && [ ! -f "$ret" ] && ret="/usr/bin/v2ray" ;; + trojan) ret="/usr/sbin/trojan" ;; + socks5 | tun) ret="/usr/sbin/redsocks2" ;; + esac + echo $ret +} gen_config_file() { - local host=$(uci_get_by_name $1 server) - if echo $host | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - hostip=$host - elif [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then - hostip=$host + local hostip=$(get_host_ip $(uci_get_by_name $1 server)) + if [ "$hostip" == "127.0.0.1" ]; then + hostip=$(uci_get_by_name $1 ip) else - hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) - if echo $hostip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - hostip=$hostip - else - hostip=$(cat /etc/ssr_ip) - fi + uci_set_by_name $1 ip $hostip fi [ "$2" == "0" -a "$kcp_flag" == "1" ] && hostip="127.0.0.1" - if [ "$2" == "0" ]; then - config_file=$CONFIG_FILE - elif [ "$2" == "1" ]; then - config_file=$CONFIG_UDP_FILE - elif [ "$2" == "2" ]; then - config_file=$CONFIG_NETFLIX_FILE - else - config_file=$CONFIG_SOCK5_FILE - fi + case "$2" in + 0) config_file=$CONFIG_FILE ;; + 1) config_file=$CONFIG_UDP_FILE ;; + 2) config_file=$CONFIG_NETFLIX_FILE ;; + *) config_file=$CONFIG_SOCK5_FILE ;; + esac if [ $(uci_get_by_name $1 fast_open 0) == "1" ]; then fastopen="true" else fastopen="false" fi - local stype=$(uci_get_by_name $1 type) - if [ "$stype" == "ss" ]; then + local type=$(uci_get_by_name $1 type) + case "$type" in + ss) cat <<-EOF >$config_file { "server": "$hostip", @@ -135,7 +165,8 @@ gen_config_file() { echo "$(date "+%Y-%m-%d %H:%M:%S") Warning!!! SIP003 plugin $plugin not found!!!" >>/tmp/ssrplus.log fi fi - elif [ "$stype" == "ssr" ]; then + ;; + ssr) cat <<-EOF >$config_file { "server": "$hostip", @@ -153,357 +184,18 @@ gen_config_file() { "fast_open": $fastopen } EOF - elif [ "$stype" == "v2ray" ]; then + ;; + v2ray) lua /usr/share/shadowsocksr/genv2config.lua $GLOBAL_SERVER tcp $(uci_get_by_name $1 local_port) >/var/etc/v2-ssr-retcp.json sed -i 's/\\//g' /var/etc/v2-ssr-retcp.json - elif [ "$stype" == "trojan" ]; then + ;; + trojan) lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER nat $(uci_get_by_name $1 local_port) >/var/etc/trojan-ssr-retcp.json sed -i 's/\\//g' /var/etc/trojan-ssr-retcp.json - fi -} - -get_arg_out() { - case "$(uci_get_by_type access_control router_proxy 1)" in - 1) echo "-o" ;; - 2) echo "-O" ;; + ;; esac } -start_rules() { - local server=$(uci_get_by_name $GLOBAL_SERVER server) - #resolve name - if echo $server | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - server=$server - elif [ "$server" != "${server#*:[0-9a-fA-F]}" ]; then - server=$server - else - server=$(ping $server -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) - if echo $server | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - echo $server >/etc/ssr_ip - else - server=$(cat /etc/ssr_ip) - fi - fi - kcp_server=$server - local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) - if [ $kcp_enable == "1" ]; then - kcp_flag=1 - fi - local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port) - local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) - local lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode) - local router_proxy=$(uci_get_by_type access_control router_proxy) - if [ "$GLOBAL_SERVER" == "$UDP_RELAY_SERVER" -a "$kcp_flag" == "0" ]; then - ARG_UDP="-u" - elif [ -n "$UDP_RELAY_SERVER" ]; then - ARG_UDP="-U" - local udp_server=$(uci_get_by_name $UDP_RELAY_SERVER server) - local udp_local_port=$(uci_get_by_name $UDP_RELAY_SERVER local_port) - fi - if [ -n "$lan_ac_ips" ]; then - case "$lan_ac_mode" in - w | W | b | B) local ac_ips="$lan_ac_mode$lan_ac_ips" ;; - esac - fi - - #deal gfw firewall rule - local gfwmode="" - if [ "$run_mode" == "gfw" ]; then - gfwmode="-g" - elif [ "$run_mode" == "router" ]; then - gfwmode="-r" - elif [ "$run_mode" == "oversea" ]; then - gfwmode="-c" - elif [ "$run_mode" == "all" ]; then - gfwmode="-z" - fi - local dports=$(uci_get_by_type global dports 1) - if [ $dports == "1" ]; then - proxyport=" " - else - proxyport="-m multiport --dports 22,53,587,465,995,993,143,80,443" - fi - if [ "$NETFLIX_SERVER" != "nil" ]; then - if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then - netflix="1" - else - netflix="2" - fi - else - netflix="0" - fi - netflix_ip=$(check_host $(uci_get_by_name $NETFLIX_SERVER server 127.0.0.1)) - /usr/bin/ssr-rules \ - -s "$server" \ - -l "$local_port" \ - -S "$udp_server" \ - -L "$udp_local_port" \ - -a "$ac_ips" \ - -i "$(uci_get_by_type access_control wan_bp_list)" \ - -b "$(uci_get_by_type access_control wan_bp_ips)" \ - -w "$(uci_get_by_type access_control wan_fw_ips)" \ - -B "$(uci_get_by_type access_control lan_bp_ips)" \ - -p "$(uci_get_by_type access_control lan_fp_ips)" \ - -G "$(uci_get_by_type access_control lan_gm_ips)" \ - -D "$proxyport" \ - -F "$netflix" \ - -N "$netflix_ip" \ - -M "$(uci_get_by_type global netflix_proxy 0)" \ - $(get_arg_out) $gfwmode $ARG_UDP - return $? -} - -start_pdnsd() { - local usr_dns="$1" - local usr_port="$2" - local tcp_dns_list="208.67.222.222, 208.67.220.220" - [ -z "$usr_dns" ] && usr_dns="8.8.8.8" - [ -z "$usr_port" ] && usr_port="53" - [ -d /var/etc ] || mkdir -p /var/etc - if [ ! -d /var/pdnsd ]; then - mkdir -p /var/pdnsd - echo -ne "pd13\000\000\000\000" >/var/pdnsd/pdnsd.cache - chown -R nobody:nogroup /var/pdnsd - fi - cat <<-EOF >/var/etc/pdnsd.conf - global{ - perm_cache=1024; - cache_dir="/var/pdnsd"; - pid_file="/var/run/pdnsd.pid"; - run_as="nobody"; - server_ip=127.0.0.1; - server_port=5335; - status_ctl=on; - query_method=tcp_only; - min_ttl=1h; - max_ttl=1w; - timeout=10; - neg_domain_pol=on; - proc_limit=2; - procq_limit=8; - par_queries=1; - } - server{ - label="ssr-usrdns"; - ip=$usr_dns; - port=$usr_port; - timeout=6; - uptest=none; - interval=10m; - purge_cache=off; - } - EOF - /usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d & -} - -start_redir() { - case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in - 1 | on | true | yes | enabled) ARG_OTA="-A" ;; - *) ARG_OTA="" ;; - esac - #deal kcp - local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) - if [ "$kcp_enable" == "1" ]; then - [ ! -f "/usr/bin/kcptun-client" ] && return 1 - local kcp_str=$(/usr/bin/kcptun-client -v | grep kcptun | wc -l) - [ "0" == "$kcp_str" ] && return 1 - local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) - local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) - local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password) - local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param) - [ "$password" != "" ] && password="--key "$password - service_start /usr/bin/kcptun-client \ - -r $kcp_server:$kcp_port \ - -l :$server_port $password $kcp_param - kcp_enable_flag=1 - fi - - gen_config_file $GLOBAL_SERVER 0 $(uci_get_by_name $GLOBAL_SERVER local_port 1234) - local stype=$(uci_get_by_name $GLOBAL_SERVER type) - if [ "$stype" == "ss" ]; then - sscmd="/usr/bin/ss-redir" - elif [ "$stype" == "ssr" ]; then - sscmd="/usr/bin/ssr-redir" - elif [ "$stype" == "v2ray" ]; then - sscmd="/usr/bin/v2ray/v2ray" - [ ! -f "$sscmd" ] && sscmd="/usr/bin/v2ray" - elif [ "$stype" == "trojan" ]; then - sscmd="/usr/sbin/trojan" - elif [ "$stype" == "socks5" ]; then - sscmd="/usr/sbin/redsocks2" - elif [ "$stype" == "tun" ]; then - sscmd="/usr/sbin/redsocks2" - fi - - local ntype=$(uci_get_by_name $NETFLIX_SERVER type) - if [ "$ntype" == "ss" ]; then - ncmd="/usr/bin/ss-redir" - sssock="/usr/bin/ss-local" - elif [ "$ntype" == "ssr" ]; then - ncmd="/usr/bin/ssr-redir" - sssock="/usr/bin/ssr-local" - elif [ "$ntype" == "v2ray" ]; then - ncmd="/usr/bin/v2ray/v2ray" - [ ! -f "$ncmd" ] && ncmd="/usr/bin/v2ray" - elif [ "$ntype" == "trojan" ]; then - ncmd="/usr/sbin/trojan" - elif [ "$ntype" == "socks5" ]; then - ncmd="/usr/sbin/redsocks2" - elif [ "$ntype" == "tun" ]; then - ncmd="/usr/sbin/redsocks2" - fi - - local utype=$(uci_get_by_name $UDP_RELAY_SERVER type) - if [ "$utype" == "ss" ]; then - ucmd="/usr/bin/ss-redir" - elif [ "$utype" == "ssr" ]; then - ucmd="/usr/bin/ssr-redir" - elif [ "$utype" == "v2ray" ]; then - ucmd="/usr/bin/v2ray/v2ray" - [ ! -f "$ucmd" ] && ucmd="/usr/bin/v2ray" - elif [ "$utype" == "trojan" ]; then - ucmd="/usr/sbin/trojan" - elif [ "$stype" == "socks5" ]; then - ucmd="/usr/sbin/redsocks2" - elif [ "$stype" == "tun" ]; then - ucmd="/usr/sbin/redsocks2" - fi - if [ "$(uci_get_by_type global threads 0)" == "0" ]; then - threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l) - else - threads=$(uci_get_by_type global threads) - fi - - if [ "$stype" == "ss" -o "$stype" == "ssr" ]; then - local last_config_file=$CONFIG_FILE - local pid_file="/var/run/ssr-retcp.pid" - for i in $(seq 1 $threads); do - $sscmd -c $CONFIG_FILE $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1 - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Shadowsocks/ShadowsocksR $threads Threads Started!" >>/tmp/ssrplus.log - elif [ "$stype" == "v2ray" ]; then - $sscmd -config /var/etc/v2-ssr-retcp.json >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) Started!" >>/tmp/ssrplus.log - elif [ "$stype" == "trojan" ]; then - for i in $(seq 1 $threads); do - $sscmd --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & - done - echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd --version 2>&1 | head -1) , $threads Threads Started!" >>/tmp/ssrplus.log - elif [ "$stype" == "socks5" ]; then - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" socks5 tcp $(uci_get_by_name $GLOBAL_SERVER local_port) \ - $(check_host $(uci_get_by_name $GLOBAL_SERVER server)) $(uci_get_by_name $GLOBAL_SERVER server_port) \ - $(uci_get_by_name $GLOBAL_SERVER auth_enable 0) $(uci_get_by_name $GLOBAL_SERVER username) $(uci_get_by_name $GLOBAL_SERVER password) - for i in $(seq 1 $threads); do - $sscmd -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Socks5 REDIRECT/TPROXY $threads Threads Started!" >>/tmp/ssrplus.log - elif [ "$stype" == "tun" ]; then - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" vpn $(uci_get_by_name $GLOBAL_SERVER iface "br-lan") $(uci_get_by_name $GLOBAL_SERVER local_port) - for i in $(seq 1 $threads); do - $sscmd -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Network Tunnel REDIRECT $threads Threads Started!" >>/tmp/ssrplus.log - fi - - if [ "$NETFLIX_SERVER" != "nil" ] && [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then - if [ "$ntype" == "ss" -o "$ntype" == "ssr" ]; then - gen_config_file $NETFLIX_SERVER 2 4321 - gen_config_file $NETFLIX_SERVER 3 1088 - $sssock -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/ssr-socksdns.pid >/dev/null 2>&1 - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - $ncmd -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/ssr-netflix.pid >/dev/null 2>&1 - elif [ "$ntype" == "v2ray" ]; then - lua /usr/share/shadowsocksr/genv2config.lua $NETFLIX_SERVER tcp 4321 1088 >/var/etc/v2-ssr-netflix.json - $ncmd -config /var/etc/v2-ssr-netflix.json >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - elif [ "$ntype" == "trojan" ]; then - lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER nat 4321 >/var/etc/trojan-ssr-netflix.json - sed -i 's/\\//g' /var/etc/trojan-ssr-netflix.json - $ncmd --config /var/etc/trojan-ssr-netflix.json >/dev/null 2>&1 & - lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER client 1088 >/var/etc/trojan-ssr-socksdns.json - sed -i 's/\\//g' /var/etc/trojan-ssr-socksdns.json - $ncmd --config /var/etc/trojan-ssr-socksdns.json >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - elif [ "$ntype" == "socks5" ]; then - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" socks5 tcp 4321 \ - $(check_host $(uci_get_by_name $NETFLIX_SERVER server)) $(uci_get_by_name $NETFLIX_SERVER server_port) \ - $(uci_get_by_name $NETFLIX_SERVER auth_enable 0) $(uci_get_by_name $NETFLIX_SERVER username) $(uci_get_by_name $NETFLIX_SERVER password) - $ncmd -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 - microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - elif [ "$ntype" == "tun" ]; then - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" vpn $(uci_get_by_name $NETFLIX_SERVER iface "br-lan") 4321 - $ncmd -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 - microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - fi - fi - - if [ -n "$UDP_RELAY_SERVER" ]; then - if [ "$utype" == "ss" -o "$utype" == "ssr" ]; then - case "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable)" in - 1 | on | true | yes | enabled) ARG_OTA="-A" ;; - *) ARG_OTA="" ;; - esac - gen_config_file $UDP_RELAY_SERVER 1 $(uci_get_by_name $UDP_RELAY_SERVER local_port 1234) - last_config_file=$CONFIG_UDP_FILE - pid_file="/var/run/ssr-reudp.pid" - $ucmd -c $last_config_file $ARG_OTA -U -f /var/run/ssr-reudp.pid >/dev/null 2>&1 - elif [ "$utype" == "v2ray" ]; then - lua /usr/share/shadowsocksr/genv2config.lua $UDP_RELAY_SERVER udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/var/etc/v2-ssr-reudp.json - sed -i 's/\\//g' /var/etc/v2-ssr-reudp.json - $ucmd -config /var/etc/v2-ssr-reudp.json >/dev/null 2>&1 & - elif [ "$stype" == "trojan" ]; then - lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER client 10801 >/var/etc/trojan-ssr-reudp.json - sed -i 's/\\//g' /var/etc/trojan-ssr-reudp.json - $ucmd --config /var/etc/trojan-ssr-reudp.json >/dev/null 2>&1 & - ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p 10801 -l $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/dev/null 2>&1 & - elif [ "$utype" == "socks5" ]; then - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-reudp.conf" socks5 udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) \ - $(check_host $(uci_get_by_name $UDP_RELAY_SERVER server)) $(uci_get_by_name $UDP_RELAY_SERVER server_port) \ - $(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0) $(uci_get_by_name $UDP_RELAY_SERVER username) $(uci_get_by_name $UDP_RELAY_SERVER password) - $ucmd -c /var/etc/redsocks-ssr-reudp.conf >/dev/null 2>&1 - elif [ "$stype" == "tun" ]; then - redir_udp=0 - echo "$(date "+%Y-%m-%d %H:%M:%S") Network Tunnel UDP TPROXY Relay not supported!" >>/tmp/ssrplus.log - fi - fi - #deal with dns - local ssr_dns="$(uci_get_by_type global pdnsd_enable 0)" - local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" - local dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') - local dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') - if [ "$ssr_dns" != "0" ]; then # not use custom dns service - if [ "$run_mode" == "gfw" ]; then - ipset add gfwlist $dnsserver 2>/dev/null - elif [ "$run_mode" == "oversea" ]; then - ipset add oversea $dnsserver 2>/dev/null - else - ipset add ss_spec_wan_ac $dnsserver nomatch 2>/dev/null - fi - fi - if [ "$ssr_dns" == "1" ]; then - start_pdnsd $dnsserver $dnsport - pdnsd_enable_flag=1 - elif [ "$ssr_dns" == "2" ]; then - microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & - dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & - pdnsd_enable_flag=2 - fi - if [ "$(uci_get_by_type global enable_switch)" == "1" ]; then - if [ "$(uci_get_by_name $GLOBAL_SERVER switch_enable 1)" == "1" ]; then - if [ -z "$switch_server" ]; then - local switch_time=$(uci_get_by_type global switch_time) - local switch_timeout=$(uci_get_by_type global switch_timeout) - service_start /usr/bin/ssr-switch start $switch_time $switch_timeout - switch_enable=1 - fi - fi - fi - add_cron - return $? -} - gen_service_file() { if [ $(uci_get_by_name $1 fast_open) == "1" ]; then fastopen="true" @@ -526,26 +218,6 @@ gen_service_file() { EOF } -start_service() { - [ $(uci_get_by_name $1 enable 0) == "0" ] && return 1 - let server_count=server_count+1 - if [ "$server_count" == "1" ]; then - if ! (iptables-save -t filter | grep SSR-SERVER-RULE >/dev/null); then - iptables -N SSR-SERVER-RULE && \ - iptables -t filter -I INPUT -j SSR-SERVER-RULE - fi - fi - if [ "$(uci_get_by_name $1 type ssr)" == "ssr" ]; then - gen_service_file $1 /var/etc/${NAME}_$server_count.json - /usr/bin/ssr-server -c /var/etc/${NAME}_$server_count.json -u -f /var/run/ssr-server$server_count.pid >/dev/null 2>&1 - else - microsocks -i :: -p $(uci_get_by_name $1 server_port) -1 -u $(uci_get_by_name $1 username) -P $(uci_get_by_name $1 password) ssr-server$server_count >/dev/null 2>&1 & - fi - iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $(uci_get_by_name $1 server_port) -j ACCEPT - iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server_port) -j ACCEPT - return 0 -} - gen_serv_include() { FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) [ -n "$FWI" ] || return 0 @@ -565,42 +237,426 @@ gen_serv_include() { EOF } -start_server() { - SERVER_ENABLE=$(uci_get_by_type server_global enable_server 0) - [ "$SERVER_ENABLE" == "0" ] && return 0 - mkdir -p /var/run /var/etc - config_load $NAME - config_foreach start_service server_config - gen_serv_include +start_dns() { + local ssr_dns="$(uci_get_by_type global pdnsd_enable 0)" + local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" + local dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') + local dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') + start_pdnsd() { + local usr_dns="$1" + local usr_port="$2" + [ -z "$usr_dns" ] && usr_dns="8.8.8.8" + [ -z "$usr_port" ] && usr_port="53" + [ -d /var/etc ] || mkdir -p /var/etc + if [ ! -d /var/pdnsd ]; then + mkdir -p /var/pdnsd + echo -ne "pd13\000\000\000\000" >/var/pdnsd/pdnsd.cache + chown -R nobody:nogroup /var/pdnsd + fi + cat <<-EOF >/var/etc/pdnsd.conf + global{ + perm_cache=1024; + cache_dir="/var/pdnsd"; + pid_file="/var/run/pdnsd.pid"; + run_as="nobody"; + server_ip=127.0.0.1; + server_port=5335; + status_ctl=on; + query_method=tcp_only; + min_ttl=1h; + max_ttl=1w; + timeout=10; + neg_domain_pol=on; + proc_limit=2; + procq_limit=8; + par_queries=1; + } + server{ + label="ssr-usrdns"; + ip=$usr_dns; + port=$usr_port; + timeout=6; + uptest=none; + interval=10m; + purge_cache=off; + } + EOF + /usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d & + } + if [ "$ssr_dns" != "0" ]; then + case "$run_mode" in + oversea) ipset add oversea $dnsserver 2>/dev/null ;; + *) ipset add gfwlist $dnsserver 2>/dev/null ;; + esac + fi + case "$ssr_dns" in + 1) + start_pdnsd $dnsserver $dnsport + pdnsd_enable_flag=1 + ;; + 2) + microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & + dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & + pdnsd_enable_flag=2 + ;; + esac +} + +start_redir_tcp() { + local type=$(uci_get_by_name $GLOBAL_SERVER type) + local bin=$(find_bin $type) + [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 + case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in + 1 | on | true | yes | enabled) ARG_OTA="-A" ;; + *) ARG_OTA="" ;; + esac + local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) + if [ "$kcp_enable" == "1" ]; then + [ ! -f "/usr/bin/kcptun-client" ] && return 1 + local kcp_str=$(/usr/bin/kcptun-client -v | grep kcptun | wc -l) + [ "0" == "$kcp_str" ] && return 1 + local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) + local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) + local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password) + local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param) + [ "$password" != "" ] && password="--key "$password + service_start /usr/bin/kcptun-client \ + -r $kcp_server:$kcp_port \ + -l :$server_port $password $kcp_param + kcp_enable_flag=1 + fi + gen_config_file $GLOBAL_SERVER 0 $(uci_get_by_name $GLOBAL_SERVER local_port 1234) + if [ "$(uci_get_by_type global threads 0)" == "0" ]; then + threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l) + else + threads=$(uci_get_by_type global threads) + fi + case "$type" in + ss | ssr) + local last_config_file=$CONFIG_FILE + local name="Shadowsocks" + [ "$type" == "ssr" ] && name="ShadowsocksR" + for i in $(seq 1 $threads); do + $bin -c $CONFIG_FILE $ARG_OTA -f /var/run/$type-retcp_$i.pid >/dev/null 2>&1 + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$name $threads Threads Started!" >>/tmp/ssrplus.log + ;; + v2ray) + $bin -config /var/etc/v2-ssr-retcp.json >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log + ;; + trojan) + for i in $(seq 1 $threads); do + $bin --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$($bin --version 2>&1 | head -1) , $threads Threads Started!" >>/tmp/ssrplus.log + ;; + socks5) + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" socks5 tcp $(uci_get_by_name $GLOBAL_SERVER local_port) \ + $(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server)) $(uci_get_by_name $GLOBAL_SERVER server_port) \ + $(uci_get_by_name $GLOBAL_SERVER auth_enable 0) $(uci_get_by_name $GLOBAL_SERVER username) $(uci_get_by_name $GLOBAL_SERVER password) + for i in $(seq 1 $threads); do + $bin -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:Socks5 REDIRECT/TPROXY $threads Threads Started!" >>/tmp/ssrplus.log + ;; + tun) + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" vpn $(uci_get_by_name $GLOBAL_SERVER iface "br-lan") $(uci_get_by_name $GLOBAL_SERVER local_port) + for i in $(seq 1 $threads); do + $bin -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:Network Tunnel REDIRECT $threads Threads Started!" >>/tmp/ssrplus.log + ;; + esac + return 0 +} + +start_redir_udp() { + if [ -n "$UDP_RELAY_SERVER" ]; then + local type=$(uci_get_by_name $UDP_RELAY_SERVER type) + local bin=$(find_bin $type) + [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 + case "$type" in + ss | ssr) + case "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable)" in + 1 | on | true | yes | enabled) ARG_OTA="-A" ;; + *) ARG_OTA="" ;; + esac + local name="Shadowsocks" + [ "$type" == "ssr" ] && name="ShadowsocksR" + gen_config_file $UDP_RELAY_SERVER 1 $(uci_get_by_name $UDP_RELAY_SERVER local_port 1234) + last_config_file=$CONFIG_UDP_FILE + $bin -c $last_config_file $ARG_OTA -U -f /var/run/$type-reudp.pid >/dev/null 2>&1 + echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$name Started!" >>/tmp/ssrplus.log + ;; + v2ray) + lua /usr/share/shadowsocksr/genv2config.lua $UDP_RELAY_SERVER udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/var/etc/v2-ssr-reudp.json + sed -i 's/\\//g' /var/etc/v2-ssr-reudp.json + $bin -config /var/etc/v2-ssr-reudp.json >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log + ;; + trojan) + lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER client 10801 >/var/etc/trojan-ssr-reudp.json + sed -i 's/\\//g' /var/etc/trojan-ssr-reudp.json + $bin --config /var/etc/trojan-ssr-reudp.json >/dev/null 2>&1 & + ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p 10801 -l $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log + ;; + socks5) + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-reudp.conf" socks5 udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) \ + $(get_host_ip $(uci_get_by_name $UDP_RELAY_SERVER server)) $(uci_get_by_name $UDP_RELAY_SERVER server_port) \ + $(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0) $(uci_get_by_name $UDP_RELAY_SERVER username) $(uci_get_by_name $UDP_RELAY_SERVER password) + $bin -c /var/etc/redsocks-ssr-reudp.conf >/dev/null 2>&1 + echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:Socks5 REDIRECT/TPROXY Started!" >>/tmp/ssrplus.log + ;; + tun) + redir_udp=0 + echo "$(date "+%Y-%m-%d %H:%M:%S") Network Tunnel UDP TPROXY Relay not supported!" >>/tmp/ssrplus.log + ;; + esac + fi + return 0 +} + +start_Bypass() { + if [ "$NETFLIX_SERVER" != "nil" ] && [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then + local type=$(uci_get_by_name $NETFLIX_SERVER type) + local bin=$(find_bin $type) + [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 + case "$type" in + ss | ssr) + local bin2=$(find_bin $type-local) + [ ! -f "$bin2" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin2 program, can't start!" >>/tmp/ssrplus.log && return 2 + local name="Shadowsocks" + [ "$type" == "ssr" ] && name="ShadowsocksR" + gen_config_file $NETFLIX_SERVER 2 4321 + gen_config_file $NETFLIX_SERVER 3 1088 + $bin -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/$type-netflix.pid >/dev/null 2>&1 + $bin2 -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/$type-socksdns.pid >/dev/null 2>&1 + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$name Started!" >>/tmp/ssrplus.log + ;; + v2ray) + lua /usr/share/shadowsocksr/genv2config.lua $NETFLIX_SERVER tcp 4321 1088 >/var/etc/v2-ssr-netflix.json + $bin -config /var/etc/v2-ssr-netflix.json >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log + ;; + trojan) + lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER nat 4321 >/var/etc/trojan-ssr-netflix.json + sed -i 's/\\//g' /var/etc/trojan-ssr-netflix.json + $bin --config /var/etc/trojan-ssr-netflix.json >/dev/null 2>&1 & + lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER client 1088 >/var/etc/trojan-ssr-socksdns.json + sed -i 's/\\//g' /var/etc/trojan-ssr-socksdns.json + $bin --config /var/etc/trojan-ssr-socksdns.json >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log + ;; + socks5) + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" socks5 tcp 4321 \ + $(get_host_ip $(uci_get_by_name $NETFLIX_SERVER server)) $(uci_get_by_name $NETFLIX_SERVER server_port) \ + $(uci_get_by_name $NETFLIX_SERVER auth_enable 0) $(uci_get_by_name $NETFLIX_SERVER username) $(uci_get_by_name $NETFLIX_SERVER password) + $bin -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 + microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:Socks5 Started!" >>/tmp/ssrplus.log + ;; + tun) + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" vpn $(uci_get_by_name $NETFLIX_SERVER iface "br-lan") 4321 + $bin -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 + microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:Network Tunnel REDIRECT Started!" >>/tmp/ssrplus.log + ;; + esac + fi return 0 } start_local() { local local_server=$(uci_get_by_type socks5_proxy server nil) - [ "$local_server" == "same" ] && local_server=$GLOBAL_SERVER [ "$local_server" == "nil" ] && return 1 - local local_type=$(uci_get_by_name $local_server type) - mkdir -p /var/run /var/etc - - if [ "$local_type" == "ssr" ]; then + [ "$local_server" == "same" ] && local_server=$GLOBAL_SERVER + local type=$(uci_get_by_name $local_server type) + local bin=$(find_bin $type) + [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 + case "$type" in + ss | ssr) + local name="Shadowsocks" + local bin=$(find_bin $type-local) + [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 + [ "$type" == "ssr" ] && name="ShadowsocksR" gen_config_file $local_server 3 $(uci_get_by_type socks5_proxy local_port 1080) - /usr/bin/ssr-local -c $CONFIG_SOCK5_FILE -u -f /var/run/ssr-local.pid >/dev/null 2>&1 - elif [ "$local_type" == "ss" ]; then - gen_config_file $local_server 3 $(uci_get_by_type socks5_proxy local_port 1080) - /usr/bin/ss-local -c $CONFIG_SOCK5_FILE -u -f /var/run/ssr-local.pid >/dev/null 2>&1 - elif [ "$local_type" == "v2ray" ]; then + $bin -c $CONFIG_SOCK5_FILE -u -f /var/run/$type-local.pid >/dev/null 2>&1 + echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$name Started!" >>/tmp/ssrplus.log + ;; + v2ray) lua /usr/share/shadowsocksr/genv2config.lua $local_server tcp 0 $(uci_get_by_type socks5_proxy local_port 1080) >/var/etc/v2-ssr-local.json sed -i 's/\\//g' /var/etc/v2-ssr-local.json - /usr/bin/v2ray/v2ray -config /var/etc/v2-ssr-local.json >/dev/null 2>&1 & - elif [ "$local_type" == "trojan" ]; then + $bin -config /var/etc/v2-ssr-local.json >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log + ;; + trojan) lua /usr/share/shadowsocksr/gentrojanconfig.lua $local_server client $(uci_get_by_type socks5_proxy local_port 1080) >/var/etc/trojan-ssr-local.json sed -i 's/\\//g' /var/etc/trojan-ssr-local.json - /usr/sbin/trojan --config /var/etc/trojan-ssr-local.json >/dev/null 2>&1 & - else - microsocks -i :: -p $(uci_get_by_type socks5_proxy local_port 1080) ssr-local >/dev/null 2>&1 & - fi - + $bin --config /var/etc/trojan-ssr-local.json >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log + ;; + *) + [ -f "/bin/ping6" ] && local listenip='-i ::' + microsocks $listenip -p $(uci_get_by_type socks5_proxy local_port 1080) ssr-local >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$type Started!" >>/tmp/ssrplus.log + ;; + esac local_enable=1 + return 0 +} + +start_server() { + SERVER_ENABLE=$(uci_get_by_type server_global enable_server 0) + [ "$SERVER_ENABLE" == "0" ] && return 0 + server_service() { + [ $(uci_get_by_name $1 enable 0) == "0" ] && return 1 + let server_count=server_count+1 + if [ "$server_count" == "1" ]; then + if ! (iptables-save -t filter | grep SSR-SERVER-RULE >/dev/null); then + iptables -N SSR-SERVER-RULE && \ + iptables -t filter -I INPUT -j SSR-SERVER-RULE + fi + fi + if [ "$(uci_get_by_name $1 type ssr)" == "ssr" ]; then + local bin=$(find_bin ssr-server) + [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 + gen_service_file $1 /var/etc/${NAME}_$server_count.json + $(find_bin ssr-server) -c /var/etc/${NAME}_$server_count.json -u -f /var/run/ssr-server$server_count.pid >/dev/null 2>&1 + echo "$(date "+%Y-%m-%d %H:%M:%S") Server:ShadowsocksR Server$server_count Started!" >>/tmp/ssrplus.log + else + [ -f "/bin/ping6" ] && local listenip='-i ::' + microsocks $listenip -p $(uci_get_by_name $1 server_port) -1 -u $(uci_get_by_name $1 username) -P $(uci_get_by_name $1 password) ssr-server$server_count >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") Server:Socks5 Server$server_count Started!" >>/tmp/ssrplus.log + fi + iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $(uci_get_by_name $1 server_port) -j ACCEPT + iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server_port) -j ACCEPT + return 0 + } + mkdir -p /var/run /var/etc + config_load $NAME + config_foreach server_service server_config + gen_serv_include + return 0 +} + +start_switch() { + if [ "$(uci_get_by_type global enable_switch 0)" == "1" ]; then + if [ -z "$switch_server" ]; then + local switch_time=$(uci_get_by_type global switch_time)s + local switch_timeout=$(uci_get_by_type global switch_timeout) + service_start /usr/bin/ssr-switch start $switch_time $switch_timeout + switch_enable=1 + fi + fi +} + +start_monitor() { + if [ $(uci_get_by_type global monitor_enable 1) == "1" ]; then + let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+switch_enable + if [ $total_count -gt 0 ]; then + service_start /usr/bin/ssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $switch_enable + fi + fi +} + +check_server() { + ENABLE_SERVER=$(uci_get_by_type global global_server nil) + if [ "$ENABLE_SERVER" == "nil" ]; then + return 1 + else + STYPE=$(uci_get_by_name $ENABLE_SERVER type nil) + if [ "$STYPE" == "nil" ]; then + CFGID=$(uci_get_by_cfgid servers type nil) + if [ "$CFGID" == "nil" ]; then + uci_set_by_type global global_server 'nil' + else + uci_set_by_type global global_server $CFGID + fi + /etc/init.d/shadowsocksr restart + fi + fi +} + +start_rules() { + local server=$(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server)) + [ "$server" == "127.0.0.1" ] && hostip=$(uci_get_by_name $GLOBAL_SERVER ip) + kcp_server=$server + local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) + if [ $kcp_enable == "1" ]; then + kcp_flag=1 + fi + local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port) + local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) + local lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode) + local router_proxy=$(uci_get_by_type access_control router_proxy) + if [ "$GLOBAL_SERVER" == "$UDP_RELAY_SERVER" -a "$kcp_flag" == "0" ]; then + ARG_UDP="-u" + elif [ -n "$UDP_RELAY_SERVER" ]; then + ARG_UDP="-U" + local udp_server=$(uci_get_by_name $UDP_RELAY_SERVER server) + local udp_local_port=$(uci_get_by_name $UDP_RELAY_SERVER local_port) + fi + if [ -n "$lan_ac_ips" ]; then + case "$lan_ac_mode" in + w | W | b | B) local ac_ips="$lan_ac_mode$lan_ac_ips" ;; + esac + fi + #deal gfw firewall rule + local gfwmode="" + case "$run_mode" in + gfw) gfwmode="-g" ;; + router) gfwmode="-r" ;; + oversea) gfwmode="-c" ;; + all) gfwmode="-z" ;; + esac + local dports=$(uci_get_by_type global dports 1) + if [ $dports == "1" ]; then + proxyport=" " + else + proxyport="-m multiport --dports 22,53,587,465,995,993,143,80,443" + fi + if [ "$NETFLIX_SERVER" != "nil" ]; then + if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then + netflix="1" + else + netflix="2" + fi + else + netflix="0" + fi + get_arg_out() { + case "$(uci_get_by_type access_control router_proxy 1)" in + 1) echo "-o" ;; + 2) echo "-O" ;; + esac + } + netflix_ip=$(get_host_ip $(uci_get_by_name $NETFLIX_SERVER server 127.0.0.1)) + /usr/bin/ssr-rules \ + -s "$server" \ + -l "$local_port" \ + -S "$udp_server" \ + -L "$udp_local_port" \ + -a "$ac_ips" \ + -i "$(uci_get_by_type access_control wan_bp_list)" \ + -b "$(uci_get_by_type access_control wan_bp_ips)" \ + -w "$(uci_get_by_type access_control wan_fw_ips)" \ + -B "$(uci_get_by_type access_control lan_bp_ips)" \ + -p "$(uci_get_by_type access_control lan_fp_ips)" \ + -G "$(uci_get_by_type access_control lan_gm_ips)" \ + -D "$proxyport" \ + -F "$netflix" \ + -N "$netflix_ip" \ + -M "$(uci_get_by_type global netflix_proxy 0)" \ + -I "/etc/ssr/netflixip.list" \ + $(get_arg_out) $gfwmode $ARG_UDP + return $? } rules() { @@ -610,6 +666,7 @@ rules() { redir_tcp=1 fi mkdir -p /var/run /var/etc + run_mode=$(uci_get_by_type global run_mode) UDP_RELAY_SERVER=$(uci_get_by_type global udp_relay_server) [ "$UDP_RELAY_SERVER" == "same" ] && UDP_RELAY_SERVER=$GLOBAL_SERVER [ -n "$UDP_RELAY_SERVER" ] && redir_udp=1 @@ -621,90 +678,48 @@ rules() { } start() { + [ -f "$LOCK_FILE" ] && exit 2 + touch "$LOCK_FILE" + echo "-------------------------start-------------------------" >>/tmp/ssrplus.log if [ -z "$switch_server" ]; then GLOBAL_SERVER=$(uci_get_by_type global global_server) else GLOBAL_SERVER=$switch_server switch_enable=1 fi - NETFLIX_SERVER=$(uci_get_by_type global netflix_server nil) if [ "$NETFLIX_SERVER" == "same" ]; then NETFLIX_SERVER=$GLOBAL_SERVER fi - if rules; then - start_redir - mkdir -p /tmp/dnsmasq.d && cp -a /etc/dnsmasq.ssr /tmp/ && cp -a /etc/dnsmasq.oversea /tmp/ - if ! [ "$run_mode" == "oversea" ]; then - cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf - conf-dir=/tmp/dnsmasq.ssr - EOF - else - cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf - conf-dir=/tmp/dnsmasq.oversea - EOF - fi - if [ $(uci_get_by_type global adblock 0) == "0" ]; then - rm -f /tmp/dnsmasq.ssr/ad.conf - fi - /usr/share/shadowsocksr/gfw2ipset.sh - - if [ "$NETFLIX_SERVER" != "nil" ]; then - if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then - cat /etc/config/netflix.list | while read line || [ -n "$line" ]; do - sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf - done - awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"netflix"'\n",$0)}' /etc/config/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf - awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5555"'\n",$0)}' /etc/config/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf - - ipset -N netflix hash:net 2>/dev/null - cat /etc/config/netflixip.list | while read nip || [ -n "$nip" ]; do - ipset add netflix $nip 2>/dev/null - done + if start_redir_tcp; then + start_redir_udp + start_Bypass + start_switch + start_dns + add_cron + mkdir -p /tmp/dnsmasq.d + if [ "$run_mode" == "oversea" ]; then + cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf + conf-dir=/tmp/dnsmasq.oversea + EOF else - cat /etc/config/netflix.list | while read line || [ -n "$line" ]; do - sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf - done - awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"netflix"'\n",$0)}' /etc/config/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf - awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/config/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf - ipset -N netflix hash:net 2>/dev/null - cat /etc/config/netflixip.list | while read nip || [ -n "$nip" ]; do - ipset add netflix $nip 2>/dev/null - done + cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf + conf-dir=/tmp/dnsmasq.ssr + EOF fi + /usr/share/shadowsocksr/gfw2ipset.sh else - rm -f /tmp/dnsmasq.ssr/netflix_forward.conf + /usr/bin/ssr-rules -f fi - - /etc/init.d/dnsmasq restart >/dev/null 2>&1 fi start_server start_local - if [ $(uci_get_by_type global monitor_enable 1) == "1" ]; then - let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+switch_enable - if [ $total_count -gt 0 ]; then - #param:server(count) redir_tcp(0:no,1:yes) redir_udp tunnel kcp local gfw - service_start /usr/bin/ssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $switch_enable - fi - fi - - ENABLE_SERVER=$(uci_get_by_type global global_server nil) - if [ "$ENABLE_SERVER" == "nil" ]; then - return 1 - else - STYPE=$(uci_get_by_name $ENABLE_SERVER type nil) - if [ "$STYPE" == "nil" ]; then - CFGID=$(uci_get_by_cfgid servers type nil) - if [ "$CFGID" == "nil" ]; then - uci set shadowsocksr.@global[0].global_server='nil' - else - uci set shadowsocksr.@global[0].global_server=$CFGID - fi - uci commit shadowsocksr - /etc/init.d/shadowsocksr restart - fi - fi + start_monitor + check_server + clean_log + echo "--------------------------end--------------------------" >>/tmp/ssrplus.log + rm -f $LOCK_FILE } boot() { @@ -712,6 +727,7 @@ boot() { } stop() { + unlock /usr/bin/ssr-rules -f srulecount=$(iptables -L | grep SSR-SERVER-RULE | wc -l) if [ $srulecount -gt 0 ]; then @@ -720,32 +736,14 @@ stop() { iptables -X SSR-SERVER-RULE 2>/dev/null fi if [ -z "$switch_server" ]; then - kill -9 $(busybox ps -w | grep ssr-switch | grep -v grep | awk '{print $1}') >/dev/null 2>&1 - fi - if [ $(uci_get_by_type global monitor_enable 0) == "1" ]; then - kill -9 $(busybox ps -w | grep ssr-monitor | grep -v grep | awk '{print $1}') >/dev/null 2>&1 - fi - killall -q -9 ssr-monitor - killall -q -9 ss-redir - killall -q -9 obfs-local - killall -q -9 v2ray-plugin - killall -q -9 ssr-redir - killall -q -9 v2ray - killall -q -9 trojan - killall -q -9 ipt2socks - kill -9 $(busybox ps -w | grep ssr-server | grep -v grep | awk '{print $1}') >/dev/null 2>&1 - kill -9 $(busybox ps -w | grep ssr-local | grep -v grep | awk '{print $1}') >/dev/null 2>&1 - killall -q -9 ssr-local - killall -q -9 ss-local - killall -q -9 kcptun-client - killall -q -9 dns2socks - killall -q -9 microsocks - killall -q -9 redsocks2 - if [ -f /var/run/pdnsd.pid ]; then - kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1 - else - kill -9 $(busybox ps -w | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + ps -w | grep -v "grep" | grep ssr-switch | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + rm -f /var/lock/ssr-switch.lock fi + ps -w | grep -v "grep" | grep ssr-monitor | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + ps -w | grep -v "grep" | grep "sleep $(uci_get_by_type global switch_time)s" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + ps -w | grep -v "grep" | grep "sleep 30s" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + killall -q -9 ss-redir ss-local obfs-local ssr-redir ssr-local ssr-server v2ray v2ray-plugin trojan microsocks ipt2socks dns2socks redsocks2 pdnsd + rm -f /var/lock/ssr-chinaipset.lock /var/lock/ssr-monitor.lock if [ -f "/tmp/dnsmasq.d/dnsmasq-ssr.conf" ]; then rm -f /tmp/dnsmasq.d/dnsmasq-ssr.conf /tmp/dnsmasq.ssr/* /tmp/dnsmasq.oversea/* /etc/init.d/dnsmasq restart >/dev/null 2>&1 diff --git a/package/lean/luci-app-ssr-plus/root/etc/china_ssr.txt b/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt similarity index 99% rename from package/lean/luci-app-ssr-plus/root/etc/china_ssr.txt rename to package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt index c152a07af2..b5e637c5b5 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/china_ssr.txt +++ b/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt @@ -1030,7 +1030,8 @@ 45.65.28.0/22 45.112.132.0/22 45.112.188.0/22 -45.112.208.0/21 +45.112.208.0/22 +45.112.212.0/22 45.112.216.0/22 45.112.220.0/22 45.112.228.0/22 @@ -1471,6 +1472,9 @@ 45.253.232.0/22 45.253.236.0/22 45.253.240.0/22 +45.253.244.0/22 +45.253.248.0/22 +45.253.252.0/22 45.254.0.0/22 45.254.4.0/22 45.254.8.0/22 @@ -1782,6 +1786,7 @@ 61.29.128.0/18 61.29.192.0/19 61.29.224.0/20 +61.29.240.0/20 61.45.128.0/18 61.45.224.0/20 61.47.128.0/18 @@ -4004,6 +4009,11 @@ 103.149.210.0/23 103.149.214.0/23 103.149.220.0/23 +103.149.242.0/23 +103.149.244.0/23 +103.149.246.0/23 +103.149.248.0/23 +103.150.24.0/23 103.192.0.0/22 103.192.4.0/22 103.192.8.0/22 @@ -5062,8 +5072,7 @@ 106.4.0.0/14 106.8.0.0/15 106.11.0.0/16 -106.12.0.0/15 -106.14.0.0/15 +106.12.0.0/14 106.16.0.0/12 106.32.0.0/12 106.48.0.0/15 @@ -5401,10 +5410,7 @@ 117.32.0.0/13 117.40.0.0/14 117.44.0.0/15 -117.48.0.0/17 -117.48.128.0/17 -117.49.0.0/16 -117.50.0.0/15 +117.48.0.0/14 117.53.48.0/20 117.53.176.0/20 117.57.0.0/16 @@ -5832,8 +5838,7 @@ 124.64.0.0/15 124.66.0.0/17 124.67.0.0/16 -124.68.0.0/15 -124.70.0.0/15 +124.68.0.0/14 124.72.0.0/16 124.73.0.0/16 124.74.0.0/15 diff --git a/package/lean/luci-app-ssr-plus/root/etc/config/netflix.list b/package/lean/luci-app-ssr-plus/root/etc/ssr/netflix.list similarity index 100% rename from package/lean/luci-app-ssr-plus/root/etc/config/netflix.list rename to package/lean/luci-app-ssr-plus/root/etc/ssr/netflix.list diff --git a/package/lean/luci-app-ssr-plus/root/etc/config/netflixip.list b/package/lean/luci-app-ssr-plus/root/etc/ssr/netflixip.list similarity index 100% rename from package/lean/luci-app-ssr-plus/root/etc/config/netflixip.list rename to package/lean/luci-app-ssr-plus/root/etc/ssr/netflixip.list diff --git a/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus b/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus index bd8d02a512..6419b43817 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus +++ b/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus @@ -13,11 +13,11 @@ uci -q batch <<-EOF >/dev/null commit firewall EOF -touch /etc/china_ssr.txt -touch /etc/config/white.list -touch /etc/config/black.list -touch /etc/config/netflix.list -touch /etc/config/netflixip.list +touch /etc/ssr/china_ssr.txt +touch /etc/ssr/white.list +touch /etc/ssr/black.list +touch /etc/ssr/netflix.list +touch /etc/ssr/netflixip.list touch /etc/dnsmasq.ssr/ad.conf touch /etc/dnsmasq.ssr/gfw_list.conf diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad index 2c7ffef057..1523ce6d3d 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad @@ -1,9 +1,9 @@ #!/bin/sh -e if [ -f /tmp/adnew.conf ]; then - if (grep -wq "address=" /tmp/adnew.conf) ; then - cp /tmp/adnew.conf /tmp/ad.conf - else - cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' > /tmp/ad.conf - fi + if (grep -wq "address=" /tmp/adnew.conf); then + cp /tmp/adnew.conf /tmp/ssr-update.$1 + else + cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' >/tmp/ssr-update.$1 + fi fi rm -f /tmp/adnew.conf diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw index 07ee49c458..44b85d29e2 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw @@ -1,5 +1,4 @@ #!/bin/sh -e - generate_china_banned() { cat $1 | base64 -d >/tmp/gfwlist.txt rm -f $1 @@ -19,7 +18,7 @@ generate_china_banned() { }' | sort -u } -generate_china_banned /tmp/gfw.b64 >/tmp/gfw.txt +generate_china_banned /tmp/ssr-update.$1 >/tmp/gfw.txt rm -f /tmp/gfwlist.txt -sed '/.*/s/.*/server=\/\.&\/127.0.0.1#5335\nipset=\/\.&\/gfwlist/' /tmp/gfw.txt >/tmp/gfwnew.txt +sed '/.*/s/.*/server=\/\.&\/127.0.0.1#5335\nipset=\/\.&\/gfwlist/' /tmp/gfw.txt >/tmp/ssr-update.$1 rm -f /tmp/gfw.txt diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor index 889f1d119a..4525a0d1f3 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor @@ -6,6 +6,9 @@ # This is free software, licensed under the GNU General Public License v3. # See /LICENSE for more information. # +LOCK_FILE="/var/lock/ssr-monitor.lock" +[ -f "$LOCK_FILE" ] && exit 2 +touch "$LOCK_FILE" NAME=shadowsocksr @@ -19,6 +22,23 @@ uci_get_by_type() { echo ${ret:=$3} } +get_host_ip() { + local host=$1 + local isip="" + local ip=$host + isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}") + if [ -z "$isip" ]; then + if [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then + ip=$host + else + local ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}') + # local hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) + [ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$1 | awk -F ';' '{print $1}') + fi + fi + echo ${ip:="127.0.0.1"} +} + server_process_count=$1 redir_tcp_process=$2 redir_udp_process=$3 @@ -29,25 +49,18 @@ pdnsd_process=$7 if [ -z "$pdnsd_process" ]; then pdnsd_process=0 fi - i=0 - GLOBAL_SERVER=$(uci_get_by_type global global_server) -server=$(uci_get_by_name $GLOBAL_SERVER server) +server=$(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server)) +[ "$server" == "127.0.0.1" ] && hostip=$(uci_get_by_name $GLOBAL_SERVER ip) lkcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) password=$(uci_get_by_name $GLOBAL_SERVER kcp_password) kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param) [ "$password" != "" ] && password="--key "${password} -if echo "$server" | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then - server=${server} -else - server=$(cat /etc/ssr_ip) -fi - while [ "1" == "1" ]; do #死循环 - sleep 30 + sleep 30s #redir tcp if [ "$redir_tcp_process" -gt 0 ]; then icount=$(busybox ps -w | grep ssr-retcp | grep -v grep | wc -l) @@ -82,6 +95,7 @@ while [ "1" == "1" ]; do #死循环 logger -t "$NAME" "ssr server error.restart!" kill -9 $(busybox ps -w | grep ssr-server | grep -v grep | awk '{print $1}') >/dev/null 2>&1 /etc/init.d/shadowsocksr restart + exit 0 fi fi #kcptun @@ -100,6 +114,7 @@ while [ "1" == "1" ]; do #死循环 logger -t "$NAME" "global socks server error.restart!" kill -9 $(busybox ps -w | grep ssr-local | grep -v grep | awk '{print $1}') >/dev/null 2>&1 /etc/init.d/shadowsocksr restart + exit 0 fi fi #pdnsd @@ -119,14 +134,14 @@ while [ "1" == "1" ]; do #死循环 if [ "$pdnsd_process" -eq 2 ]; then icount=$(busybox ps -w | grep -e ssr-dns -e dns2socks | grep -v grep | wc -l) if [ "$icount" -lt 2 ]; then #如果进程挂掉就重启它 - logger -t "$NAME" "dns2socks $dnsstr tunnel error.restart!" + logger -t "$NAME" "dns2socks $dnsstr tunnel error.restart!" dnsstr=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') killall -q -9 dns2socks kill -9 $(busybox ps -w | grep ssr-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & - dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & + dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & fi fi done diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules index 0279d926a7..087a74c140 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules @@ -33,6 +33,7 @@ Valid options are: -F netflix mode -N netflix server IP -M netflix proxy mode + -I a file content is bypassed netflix ip list -e extra options for iptables -o apply the rules to the OUTPUT chain -O apply the global rules to the OUTPUT chain @@ -82,7 +83,8 @@ flush_r() { ipset_r() { ipset -N gmlan hash:net 2>/dev/null for ip in $LAN_GM_IP; do ipset -! add gmlan $ip; done - if [ "$RUNMODE" == "router" ]; then + case "$RUNMODE" in + router) ipset -! -R <<-EOF || return 1 create ss_spec_wan_ac hash:net $(gen_iplist | sed -e "s/^/add ss_spec_wan_ac /") @@ -92,25 +94,29 @@ ipset_r() { $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN $IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW - elif [ "$RUNMODE" == "gfw" ]; then + ;; + gfw) ipset -N gfwlist hash:net 2>/dev/null $IPT -N SS_SPEC_WAN_AC $IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN - elif [ "$RUNMODE" == "oversea" ]; then + ;; + oversea) ipset -N oversea hash:net 2>/dev/null $IPT -N SS_SPEC_WAN_AC ipset -N gmlan hash:net 2>/dev/null for ip in $LAN_GM_IP; do ipset -! add gmlan $ip; done $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j SS_SPEC_WAN_FW $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN - elif [ "$RUNMODE" == "all" ]; then + ;; + all) $IPT -N SS_SPEC_WAN_AC $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN - fi + ;; + esac ipset -N fplan hash:net 2>/dev/null for ip in $LAN_FP_IP; do ipset -! add fplan $ip; done $IPT -I SS_SPEC_WAN_AC -m set --match-set fplan src -j SS_SPEC_WAN_FW @@ -123,23 +129,25 @@ ipset_r() { $IPT -I SS_SPEC_WAN_AC -m set --match-set whitelist dst -j RETURN for ip in $WAN_BP_IP; do ipset -! add whitelist $ip; done for ip in $WAN_FW_IP; do ipset -! add blacklist $ip; done - - if [ "$NETFLIX" == "1" ]; then + if [ "$NETFLIX" != "0" ]; then + ipset -N netflix hash:net 2>/dev/null + for ip in $(cat ${NETFLIX_LIST:=/dev/null} 2>/dev/null); do ipset -! add netflix $ip; done + fi + case "$NETFLIX" in + 1) $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports 4321 if [ "$NETFLIX_PROXY" == "1" ]; then $IPT -I SS_SPEC_WAN_AC -p tcp -d $NETFLIX_IP -j REDIRECT --to-ports $local_port else ipset -! add whitelist $NETFLIX_IP fi - elif [ "$NETFLIX" == "2" ]; then - $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port - fi - + ;; + 2) $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port ;; + esac return $? } fw_rule() { - ipset -N netflix hash:net 2>/dev/null $IPT -N SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_FW -d 0.0.0.0/8 -j RETURN $IPT -A SS_SPEC_WAN_FW -d 10.0.0.0/8 -j RETURN @@ -216,23 +224,26 @@ tp_rule() { $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - if [ "$RUNMODE" == "router" ]; then + case "$RUNMODE" in + router) $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - elif [ "$RUNMODE" == "gfw" ]; then + ;; + gfw) $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 $ipt -A SS_SPEC_TPROXY -p udp -m set $PROXY_PORTS --match-set gfwlist dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - elif [ "$RUNMODE" == "oversea" ]; then + ;; + oversea) $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - elif [ "$RUNMODE" == "all" ]; then - $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - fi + ;; + all) $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 ;; + esac $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET \ -m comment --comment "$TAG" -j SS_SPEC_TPROXY return $? @@ -309,7 +320,7 @@ gen_include() { return 0 } -while getopts ":s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:oOuUfgrczh" arg; do +while getopts ":s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do case "$arg" in s) server=$OPTARG @@ -359,6 +370,9 @@ while getopts ":s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:oOuUfgrczh" arg; do M) NETFLIX_PROXY=$OPTARG ;; + I) + NETFLIX_LIST=$OPTARG + ;; o) OUTPUT=1 ;; @@ -403,4 +417,3 @@ fi flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include [ "$?" == 0 ] || loger 3 "Start failed!" exit $? - diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch index 98d91dc962..15378a17f7 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch @@ -1,4 +1,4 @@ -#!/bin/sh /etc/rc.common +#!/bin/sh /etc/rc.common # # Copyright (C) 2017 openwrt-ssr # Copyright (C) 2017 yushi studio @@ -6,6 +6,9 @@ # This is free software, licensed under the GNU General Public License v3. # See /LICENSE for more information. # +LOCK_FILE="/var/lock/ssr-switch.lock" +[ -f "$LOCK_FILE" ] && exit 2 +touch "$LOCK_FILE" cycle_time=60 switch_time=3 @@ -162,7 +165,7 @@ start() { fi else normal_flag=0 - echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR No Problem." >>/tmp/ssrplus.log + # echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR No Problem." >>/tmp/ssrplus.log fi done } diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh index 044d524d94..d011c63ca8 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh @@ -1,5 +1,9 @@ +#!/bin/sh +LOCK_FILE="/var/lock/ssr-chinaipset.lock" +[ -f "$LOCK_FILE" ] && exit 2 +touch "$LOCK_FILE" echo "create china hash:net family inet hashsize 1024 maxelem 65536" > /tmp/china.ipset awk '!/^$/&&!/^#/{printf("add china %s'" "'\n",$0)}' /etc/china_ssr.txt >> /tmp/china.ipset ipset -! flush china ipset -! restore < /tmp/china.ipset 2>/dev/null -rm -f /tmp/china.ipset +rm -f /tmp/china.ipset $LOCK_FILE diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh index a36f48f897..480b8e3ef3 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh @@ -1,72 +1,71 @@ #!/bin/sh - cat <<-EOF >$1 -base { - log_debug = off; - log_info = off; - log = stderr; - daemon = on; - redirector = iptables; - reuseport = on; -} + base { + log_debug = off; + log_info = off; + log = stderr; + daemon = on; + redirector = iptables; + reuseport = on; + } EOF if [ "$2" == "socks5" ]; then if [ "$3" == "tcp" ]; then if [ "$7" == "0" ]; then - cat <<-EOF >>$1 -redsocks { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - autoproxy = 0; - timeout = 10; -} -EOF - else - cat <<-EOF >>$1 -redsocks { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - autoproxy = 0; - timeout = 10; - login = "$8"; - password = "$9"; -} -EOF + cat <<-EOF >>$1 + redsocks { + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + autoproxy = 0; + timeout = 10; + } + EOF + else + cat <<-EOF >>$1 + redsocks { + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + autoproxy = 0; + timeout = 10; + login = "$8"; + password = "$9"; + } + EOF fi else - if [ "$7" == "0" ]; then - cat <<-EOF >>$1 -redudp { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - udp_timeout = 10; -} -EOF - else - cat <<-EOF >>$1 -redudp { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - udp_timeout = 10; - login = "$8"; - password = "$9"; -} -EOF + if [ "$7" == "0" ]; then + cat <<-EOF >>$1 + redudp { + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + udp_timeout = 10; + } + EOF + else + cat <<-EOF >>$1 + redudp { + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + udp_timeout = 10; + login = "$8"; + password = "$9"; + } + EOF fi fi else - cat <<-EOF >>$1 -redsocks { - bind = "0.0.0.0:$4"; - type = direct; - interface = $3; - autoproxy = 0; - timeout = 10; -} -EOF + cat <<-EOF >>$1 + redsocks { + bind = "0.0.0.0:$4"; + type = direct; + interface = $3; + autoproxy = 0; + timeout = 10; + } + EOF fi diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua index 8cb979bef8..9474777d06 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua @@ -1,9 +1,8 @@ -local ucursor = require "luci.model.uci".cursor() +local ucursor = require "uci".cursor() local json = require "luci.jsonc" local server_section = arg[1] local proto = arg[2] local local_port = arg[3] - local server = ucursor:get_all("shadowsocksr", server_section) local trojan = { diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua index 2554ebd17b..36e7efae48 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua @@ -1,10 +1,9 @@ -local ucursor = require "luci.model.uci".cursor() +local ucursor = require "uci".cursor() local json = require "luci.jsonc" local server_section = arg[1] local proto = arg[2] local local_port = arg[3] or "0" local socks_port = arg[4] or "0" - local server = ucursor:get_all("shadowsocksr", server_section) local v2ray = { diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh index c5decd28ce..245bb8c88d 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh @@ -1,5 +1,34 @@ #!/bin/sh -mkdir -p /tmp/dnsmasq.ssr -awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"blacklist"'\n",$0)}' /etc/config/black.list > /tmp/dnsmasq.ssr/blacklist_forward.conf -awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/config/black.list >> /tmp/dnsmasq.ssr/blacklist_forward.conf -awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"whitelist"'\n",$0)}' /etc/config/white.list > /tmp/dnsmasq.ssr/whitelist_forward.conf +NAME=shadowsocksr +uci_get_by_type() { + local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null) + echo ${ret:=$3} +} +cp -a /etc/dnsmasq.ssr /tmp/ +cp -a /etc/dnsmasq.oversea /tmp/ +GLOBAL_SERVER=$(uci_get_by_type global global_server) +NETFLIX_SERVER=$(uci_get_by_type global netflix_server nil) +[ "$NETFLIX_SERVER" == "same" ] && NETFLIX_SERVER=$GLOBAL_SERVER +if [ "$NETFLIX_SERVER" != "nil" ]; then + netflix() { + for line in $(cat /etc/ssr/netflix.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf; done + awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"netflix"'\n",$0)}' /etc/ssr/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf + awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#$1"'\n",$0)}' /etc/ssr/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf + } + if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then + netflix 5555 + else + netflix 5335 + fi +else + rm -f /tmp/dnsmasq.ssr/netflix_forward.conf +fi +if [ "$1" == "" ]; then + awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"blacklist"'\n",$0)}' /etc/ssr/black.list >/tmp/dnsmasq.ssr/blacklist_forward.conf + awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/ssr/black.list >>/tmp/dnsmasq.ssr/blacklist_forward.conf + awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"whitelist"'\n",$0)}' /etc/ssr/white.list >/tmp/dnsmasq.ssr/whitelist_forward.conf + if [ "$(uci_get_by_type global adblock 0)" == "0" ]; then + rm -f /tmp/dnsmasq.ssr/ad.conf + fi +fi +/etc/init.d/dnsmasq restart >/dev/null 2>&1 diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh index 5db73ff880..818726a98b 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh @@ -1,6 +1,6 @@ #!/bin/sh - /usr/bin/lua /usr/share/shadowsocksr/update.lua +sleep 2s +/usr/share/shadowsocksr/chinaipset.sh +sleep 2s /usr/bin/lua /usr/share/shadowsocksr/subscribe.lua -sleep 10 -/etc/init.d/shadowsocksr restart \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index 7b05ce5cfc..b7cb1bce98 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -10,27 +10,56 @@ require 'luci.sys' require 'uci' -- these global functions are accessed all the time by the event handler -- so caching them is worth the effort -local luci = luci local tinsert = table.insert local ssub, slen, schar, sbyte, sformat, sgsub = string.sub, string.len, string.char, string.byte, string.format, string.gsub local jsonParse, jsonStringify = luci.jsonc.parse, luci.jsonc.stringify local b64decode = nixio.bin.b64decode -local cache = {} -local nodeResult = setmetatable({}, { __index = cache }) -- update result -local name = 'shadowsocksr' +local nodeResult = {} -- update result +local application = 'shadowsocksr' local uciType = 'servers' -local ucic = luci.model.uci.cursor() -local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') -local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') -local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) -local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', 'QQ群') +local ucic2 = uci.cursor() +local proxy = ucic2:get(application, '@server_subscribe[0]', 'proxy') or '0' +local switch = ucic2:get(application, '@server_subscribe[0]', 'switch') or '1' +local subscribe_url = ucic2:get(application, '@server_subscribe[0]', 'subscribe_url') or {} +local filter_words = ucic2:get(application, '@server_subscribe[0]', 'filter_words') or '过期时间/剩余流量' +ucic2:revert(application) local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) end + +-- 获取各项动态配置的当前服务器,可以用 get 和 set, get必须要获取到节点表 +local CONFIG = { + GLOBAL_SERVER = { + remarks = '主节点', + type = "global", option = "global_server", + set = function(server) + ucic2:set(application, '@global[0]', "global_server", server) + end + } +} +do + for k, v in pairs(CONFIG) do + local currentNode + if v.get then + currentNode = v.get() + else + local cfgid = ucic2:get(application, '@' .. v.type .. '[0]', v.option) + if cfgid then + currentNode = ucic2:get_all(application, cfgid) + end + end + if currentNode then + CONFIG[k].currentNode = currentNode + else + CONFIG[k] = nil + end + end +end + -- 分割字符串 local function split(full, sep) - full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 + full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 local off, result = 1, {} while true do local nStart, nEnd = full:find(sep, off) @@ -48,15 +77,15 @@ local function split(full, sep) return result end -- urlencode -local function get_urlencode(c) - return sformat("%%%02X", sbyte(c)) -end +-- local function get_urlencode(c) +-- return sformat("%%%02X", sbyte(c)) +-- end -local function urlEncode(szText) - local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) - str = str:gsub(" ", "+") - return str -end +-- local function urlEncode(szText) +-- local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) +-- str = str:gsub(" ", "+") +-- return str +-- end local function get_urldecode(h) return schar(tonumber(h, 16)) @@ -72,12 +101,7 @@ local function trim(text) end return (sgsub(text, "^%s*(.-)%s*$", "%1")) end --- md5 -local function md5(content) - local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1') - -- assert(nixio.errno() == 0) - return trim(stdout) -end + -- base64 local function base64Decode(text) local raw = text @@ -99,7 +123,8 @@ local function processData(szType, content) local result = { type = szType, local_port = 1234, - kcp_param = '--nocomp' + kcp_param = '--nocomp', + isSubscribe = 1, } if szType == 'ssr' then local dat = split(content, "/%?") @@ -119,7 +144,7 @@ local function processData(szType, content) result.protocol_param = base64Decode(params.protoparam) local group = base64Decode(params.group) if group then - result.alias = "[" .. group .. "] " + result.alias = "[" .. group .. "] " end result.alias = result.alias .. base64Decode(params.remarks) elseif szType == 'vmess' then @@ -263,14 +288,6 @@ local function processData(szType, content) if not result.alias then result.alias = result.server .. ':' .. result.server_port end - -- alias 不参与 hashkey 计算 - local alias = result.alias - result.alias = nil - local switch_enable = result.switch_enable - result.switch_enable = nil - result.hashkey = md5(jsonStringify(result)) - result.alias = alias - result.switch_enable = switch_enable return result end -- wget @@ -280,15 +297,67 @@ local function wget(url) end local function check_filer(result) - do - local filter_word = split(filter_words, "/") - for i, v in pairs(filter_word) do - if result.alias:find(v) then - log('订阅节点关键字过滤:“' .. v ..'” ,该节点被丢弃') - return true - end - end - end + do + local filter_word = split(filter_words, "/") + for i, v in pairs(filter_word) do + if result.alias:find(v) then + log('订阅节点关键字过滤:“' .. v ..'” ,该节点被丢弃') + return true + end + end + end +end + +local function select_node(nodes, config) + local server + -- 第一优先级 IP + 端口 + for id, node in pairs(nodes) do + if node.server .. ':' .. node.server_port == config.currentNode.server .. ':' .. config.currentNode.server_port then + log('选择【' .. config.remarks .. '】第一匹配节点:' .. node.alias) + server = id + break + end + end + -- 第二优先级 IP + if not server then + for id, node in pairs(nodes) do + if node.server == config.currentNode.server then + log('选择【' .. config.remarks .. '】第二匹配节点:' .. node.alias) + server = id + break + end + end + end + -- 第三优先级备注 + if not server then + for id, node in pairs(nodes) do + if node.alias == config.currentNode.alias then + log('选择【' .. config.remarks .. '】第三匹配节点:' .. node.alias) + server = id + break + end + end + end + -- 第四 cfgid + if not server then + for id, node in pairs(nodes) do + if id == config.currentNode['.name'] then + log('选择【' .. config.remarks .. '】第四匹配节点:' .. node.alias) + server = id + break + end + end + end + -- 还不行 随便找一个 + if not server then + server = ucic2:get(application, '@'.. uciType .. '[0]') + if server then + log('无法找到最匹配的节点,当前已更换为' .. ucic2:get_all(application, server).alias) + end + end + if server then + config.set(server) + end end local execute = function() @@ -296,15 +365,14 @@ local execute = function() do if proxy == '0' then -- 不使用代理更新的话先暂停 log('服务正在暂停') - luci.sys.init.stop(name) + luci.sys.init.stop(application) end for k, url in ipairs(subscribe_url) do local raw = wget(url) if #raw > 0 then local nodes, szType - local groupHash = md5(url) - cache[groupHash] = {} - tinsert(nodeResult, {}) + local all_odes = {} + tinsert(nodeResult, all_odes) local index = #nodeResult -- SSD 似乎是这种格式 ssd:// 开头的 if raw:find('ssd://') then @@ -313,10 +381,10 @@ local execute = function() nodes = base64Decode(raw:sub(nEnd + 1, #raw)) nodes = jsonParse(nodes) local extra = { - airport = nodes.airport, - port = nodes.port, - encryption = nodes.encryption, - password = nodes.password + airport = nodes.airport, + port = nodes.port, + encryption = nodes.encryption, + password = nodes.password } local servers = {} -- SS里面包着 干脆直接这样 @@ -349,16 +417,15 @@ local execute = function() -- log(result) if result then if - not result.server or - check_filer(result) or - result.server:match("[^0-9a-zA-Z%-%.%s]") -- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场 - then + not result.server or + not result.server_port or + check_filer(result) or + result.server:match("[^0-9a-zA-Z%-%.%s]") -- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场 + then log('丢弃无效节点: ' .. result.type ..' 节点, ' .. result.alias) else log('成功解析: ' .. result.type ..' 节点, ' .. result.alias) - result.grouphashkey = groupHash - tinsert(nodeResult[index], result) - cache[groupHash][result.hashkey] = nodeResult[index][#nodeResult[index]] + tinsert(all_odes, result) end end end @@ -371,61 +438,45 @@ local execute = function() end -- diff do - if next(nodeResult) == nil then - log("更新失败,没有可用的节点信息") - return - end - local add, del = 0, 0 - ucic:foreach(name, uciType, function(old) - if old.grouphashkey or old.hashkey then -- 没有 hash 的不参与删除 - if not nodeResult[old.grouphashkey] or not nodeResult[old.grouphashkey][old.hashkey] then - ucic:delete(name, old['.name']) - del = del + 1 - else - local dat = nodeResult[old.grouphashkey][old.hashkey] - ucic:tset(name, old['.name'], dat) - -- 标记一下 - setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } }) - end - else - if not old.alias then - old.alias = old.server .. ':' .. old.server_port - end - log('忽略手动添加的节点: ' .. old.alias) + assert(next(nodeResult), '更新失败,没有可用的节点信息') + -- delete all for subscribe nodes + ucic2:foreach(application, uciType, function(node) + if node.isSubscribe or node.hashkey then -- 兼容之前的hashkey + ucic2:delete(application, node['.name']) end - end) - for k, v in ipairs(nodeResult) do - for kk, vv in ipairs(v) do - if not vv._ignore then - local section = ucic:add(name, uciType) - ucic:tset(name, section, vv) - ucic:set(name, section, "switch_enable", switch) - add = add + 1 + for _, v in ipairs(nodeResult) do + for _, vv in ipairs(v) do + vv.switch_enable = switch + local cfgid = ucic2:add(application, uciType) + for kkk, vvv in pairs(vv) do + ucic2:set(application, cfgid, kkk, vvv) end end end - ucic:commit(name) - -- 如果原有服务器节点已经不见了就尝试换为第一个节点 - local globalServer = ucic:get_first(name, 'global', 'global_server', '') - local firstServer = ucic:get_first(name, uciType) - if firstServer then - if not ucic:get(name, globalServer) then - luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") - ucic:commit(name) - ucic:set(name, ucic:get_first(name, 'global'), 'global_server', ucic:get_first(name, uciType)) - ucic:commit(name) - log('当前主服务器节点已被删除,正在自动更换为第一个节点。') - luci.sys.call("/etc/init.d/" .. name .. " start > /dev/null 2>&1 &") - else - log('维持当前主服务器节点。') - luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") + ucic2:commit(application) + local ucic3 = uci.cursor() + -- repair configuration + if next(CONFIG) then + local nodes = {} + ucic3:foreach(application, uciType, function(node) + if node.server and node.server_port and node.alias then + nodes[node['.name']] = node + end + end) + for _, config in pairs(CONFIG) do + select_node(nodes, config) end - else - log('没有服务器节点了,停止服务') - luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") + ucic3:commit(application) end - log('新增节点数量: ' ..add, '删除节点数量: ' .. del) + -- select first server + local globalServer = ucic3:get(application, '@global[0]', 'global_server') or '' + if not globalServer or not ucic3:get_all(application, globalServer) then + ucic3:set(application, '@global[0]', 'global_server', select(2, ucic3:get(application, '@' .. uciType .. '[0]'))) + ucic3:commit(application) + log('当前没有主节点,自动选择第一个节点开启服务。') + end + luci.sys.call("/etc/init.d/" .. application .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('订阅更新成功') end end @@ -435,12 +486,11 @@ if subscribe_url and #subscribe_url > 0 then log(e) log(debug.traceback()) log('发生错误, 正在恢复服务') - local firstServer = ucic:get_first(name, uciType) - if firstServer then - luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + if CONFIG.GLOBAL_SERVER and CONFIG.GLOBAL_SERVER.currentNode then + luci.sys.call("/etc/init.d/" .. application .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('重启服务成功') else - luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + luci.sys.call("/etc/init.d/" .. application .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('停止服务成功') end end) diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua index 17341bd84c..bcf2568904 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua @@ -3,10 +3,8 @@ -- This file is part of the luci-app-ssr-plus update.lua -- By Mattraks ------------------------------------------------ -require 'nixio' -require 'luci.util' -require 'luci.jsonc' -require 'luci.sys' +require "luci.sys" +require "luci.model.uci" local icount = 0 local uci = luci.model.uci.cursor() @@ -14,112 +12,41 @@ local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) end -log('正在更新【GFW列表】数据库') -refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'gfwlist_url', 'https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt') .. " > /tmp/gfw.b64" -sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") -if sret == 0 then - luci.sys.call("/usr/bin/ssr-gfw") - icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l") - if tonumber(icount) > 1000 then - if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then - oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf") - luci.sys.exec("cp -f /tmp/gfwnew.txt /tmp/dnsmasq.ssr/gfw_list.conf") - log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount)/2)) - else - log('你已经是最新数据,无需更新!') - end - else - log('更新失败!') - end - luci.sys.exec("rm -f /tmp/gfwnew.txt") -else - log('更新失败!') -end - -log('正在更新【国内IP段】数据库') -refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'chnroute_url','https://ispip.clang.cn/all_cn.txt') .. " > /tmp/china_ssr.txt" -sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") -icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") -if sret == 0 then - icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") - if tonumber(icount) > 1000 then - if nixio.fs.access("/etc/china_ssr.txt") then - oldcount = luci.sys.exec("cat /etc/china_ssr.txt | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt") - log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount))) - else - log('你已经是最新数据,无需更新!') - end - else - log('更新失败!') - end - luci.sys.exec("rm -f /tmp/china_ssr.txt") -else - log('更新失败!') -end - -if uci:get_first('shadowsocksr', 'global', 'adblock','0') == "1" then - log('正在更新【广告屏蔽】数据库') - refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'adblock_url','https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt') .. " > /tmp/adnew.conf" +local function update(url, file, type, file2) + local Num = 1 + refresh_cmd = "wget-ssl --no-check-certificate -t 3 -T 10 -O- " .. url .. " > /tmp/ssr-update." .. type sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") if sret == 0 then - luci.sys.call("/usr/bin/ssr-ad") - icount = luci.sys.exec("cat /tmp/ad.conf | wc -l") - if tonumber(icount) > 100 then - if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then - oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf") - luci.sys.exec("cp -f /tmp/ad.conf /tmp/dnsmasq.ssr/ad.conf") - log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount))) - else - log('你已经是最新数据,无需更新!') - end - else - log('更新失败!') + if type == "gfw_data" then + luci.sys.call("/usr/bin/ssr-gfw " .. type) + Num = 2 + end + if type == "ad_data" then + luci.sys.call("/usr/bin/ssr-ad " .. type) + end + local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/ssr-update." .. type .. "' ] && md5sum /tmp/ssr-update." .. type .. " | awk '{print $1}')") + local old_md5 = luci.sys.exec("echo -n $([ -f '" .. file .. "' ] && md5sum " .. file .. " | awk '{print $1}')") + if new_md5 == old_md5 then + log("你已经是最新数据,无需更新!") + else + icount = luci.sys.exec("cat /tmp/ssr-update." .. type .. " | wc -l") + luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file) + if file2 then luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file2) end + log("更新成功! 新的总纪录数:" .. tostring(tonumber(icount)/Num)) end - luci.sys.exec("rm -f /tmp/ad.conf") else - log('更新失败!') + log("更新失败!") end + luci.sys.exec("rm -f /tmp/ssr-update." .. type) end ---[[ -log('正在更新【Netflix IP段】数据库') -refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'nfip_url','https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt') .. " > /tmp/netflixip.list" -sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") -if sret == 0 then - luci.sys.call("/usr/bin/ssr-gfw") - icount = luci.sys.exec("cat /tmp/netflixip.list | wc -l") - if tonumber(icount) > 5 then - if nixio.fs.access("/etc/config/netflixip.list") then - oldcount = luci.sys.exec("cat /etc/config/netflixip.list | wc -l") - else - oldcount = "0" - end - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/netflixip.list /etc/config/netflixip.list") - log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount))) - else - log('你已经是最新数据,无需更新!') - end - else - log('更新失败!') - end - luci.sys.exec("rm -f /tmp/netflixip.list") -else - log('更新失败!') +log("正在更新【GFW列表】数据库") +update(uci:get_first("shadowsocksr", "global", "gfwlist_url", "https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt"), "/etc/dnsmasq.ssr/gfw_list.conf", "gfw_data", "/tmp/dnsmasq.ssr/gfw_list.conf") +log("正在更新【国内IP段】数据库") +update(uci:get_first("shadowsocksr", "global", "chnroute_url","https://ispip.clang.cn/all_cn.txt"), "/etc/ssr/china_ssr.txt", "cnip") +if uci:get_first("shadowsocksr", "global", "adblock","0") == "1" then + log("正在更新【广告屏蔽】数据库") + update(uci:get_first("shadowsocksr", "global", "adblock_url","https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt"), "/etc/dnsmasq.ssr/ad.conf", "ad_data", "/tmp/dnsmasq.ssr/ad.conf") end ---]] +-- log("正在更新【Netflix IP段】数据库") +-- update(uci:get_first("shadowsocksr", "global", "nfip_url","https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt"), "/etc/ssr/netflixip.list", "nfip_data") From 00d40a40acf39555bab1ae67e733f0a62bb58bd5 Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Sun, 12 Apr 2020 12:04:02 +0800 Subject: [PATCH 17/27] ipq40xx: fix support for Asus RT-AC1300UHP in 4.19 (#4285) RT-AC1300UHP has 256M memory and does not need to use ath10k-ct-smallbuffers. Signed-off-by: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> --- .../arm/boot/dts/qcom-ipq4018-rt-ac58u.dts | 4 ++-- target/linux/ipq40xx/image/Makefile | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts index a0030f77ce..bf49e8b6a3 100644 --- a/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts +++ b/target/linux/ipq40xx/files-4.19/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts @@ -6,12 +6,12 @@ #include / { - model = "ASUS RT-AC58U"; + model = "ASUS RT-AC58U / RT-AC1300UHP"; compatible = "asus,rt-ac58u"; memory { device_type = "memory"; - reg = <0x80000000 0x8000000>; + reg = <0x80000000 0x10000000>; }; aliases { diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile index 197d4a03f6..f9c844b1d5 100644 --- a/target/linux/ipq40xx/image/Makefile +++ b/target/linux/ipq40xx/image/Makefile @@ -75,7 +75,7 @@ TARGET_DEVICES += asus_map-ac2200 define Device/asus_rt-ac58u $(call Device/FitImageLzma) DEVICE_VENDOR := ASUS - DEVICE_MODEL := RT-AC58U / RT-AC1300UHP + DEVICE_MODEL := RT-AC58U DEVICE_DTS := qcom-ipq4018-rt-ac58u BLOCKSIZE := 128k PAGESIZE := 2048 @@ -96,6 +96,24 @@ define Device/asus_rt-ac58u endef TARGET_DEVICES += asus_rt-ac58u +define Device/asus_rt-ac1300uhp + $(call Device/FitImageLzma) + DEVICE_VENDOR := ASUS + DEVICE_MODEL := RT-AC1300UHP + DEVICE_DTS := qcom-ipq4018-rt-ac58u + BLOCKSIZE := 128k + PAGESIZE := 2048 + DTB_SIZE := 65536 + IMAGE_SIZE := 20439364 + FILESYSTEMS := squashfs + UIMAGE_NAME:=$(shell echo -e '\03\01\01\01RT-AC58U') + KERNEL_INITRAMFS := $$(KERNEL) | uImage none + KERNEL_INITRAMFS_SUFFIX := -factory.trx + IMAGES := sysupgrade.bin + DEVICE_PACKAGES := kmod-usb-ledtrig-usbport +endef +TARGET_DEVICES += asus_rt-ac1300uhp + define Device/asus_rt-acrh17 $(call Device/FitImageLzma) DEVICE_VENDOR := ASUS From 66e6e853be60d2cb3d513e2bbb3b98135562de45 Mon Sep 17 00:00:00 2001 From: Mattraks <16359027+Mattraks@users.noreply.github.com> Date: Sun, 12 Apr 2020 12:04:25 +0800 Subject: [PATCH 18/27] luci-app-ssr-plus:revert subscribe.lua (#4282) * luci-app-ssr-plus:Code optimization and Fix Bug * luci-app-ssr-plus:Adjust reference data location * luci-app-ssr-plus:revert subscribe.lua --- package/lean/luci-app-ssr-plus/Makefile | 2 +- .../luasrc/model/cbi/shadowsocksr/status.lua | 2 +- .../root/etc/config/shadowsocksr | 1 - .../root/etc/init.d/shadowsocksr | 2 +- .../root/usr/share/shadowsocksr/subscribe.lua | 239 +++++++----------- 5 files changed, 97 insertions(+), 149 deletions(-) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index edf07317d5..19fe30e56a 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=176 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua index bd6c6d354b..d6edefeb1e 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -46,7 +46,7 @@ if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then end if nixio.fs.access("/etc/ssr/china_ssr.txt") then - ip_count = tonumber(luci.sys.exec("cat /etc/china_ssr.txt | wc -l")) + ip_count = tonumber(luci.sys.exec("cat /etc/ssr/china_ssr.txt | wc -l")) end if nixio.fs.access("/etc/ssr/netflixip.list") then diff --git a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr index 7658938ae1..f8aac0821e 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr @@ -20,7 +20,6 @@ config global option netflix_proxy '0' config access_control - option wan_bp_list '/etc/ssr/china_ssr.txt' option lan_ac_mode 'b' option router_proxy '1' list wan_fw_ips '149.154.160.0/20' diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index ff6082594b..0f6332eed8 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -644,7 +644,7 @@ start_rules() { -S "$udp_server" \ -L "$udp_local_port" \ -a "$ac_ips" \ - -i "$(uci_get_by_type access_control wan_bp_list)" \ + -i "/etc/ssr/china_ssr.txt" \ -b "$(uci_get_by_type access_control wan_bp_ips)" \ -w "$(uci_get_by_type access_control wan_fw_ips)" \ -B "$(uci_get_by_type access_control lan_bp_ips)" \ diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index b7cb1bce98..ff0a201bd7 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -3,60 +3,30 @@ -- This file is part of the luci-app-ssr-plus subscribe.lua -- @author William Chan ------------------------------------------------ -require 'nixio' -require 'luci.util' -require 'luci.jsonc' -require 'luci.sys' -require 'uci' +require "luci.model.uci" +require "nixio" +require "luci.util" +require "luci.sys" +require "luci.jsonc" -- these global functions are accessed all the time by the event handler -- so caching them is worth the effort local tinsert = table.insert local ssub, slen, schar, sbyte, sformat, sgsub = string.sub, string.len, string.char, string.byte, string.format, string.gsub local jsonParse, jsonStringify = luci.jsonc.parse, luci.jsonc.stringify local b64decode = nixio.bin.b64decode -local nodeResult = {} -- update result -local application = 'shadowsocksr' +local cache = {} +local nodeResult = setmetatable({}, { __index = cache }) -- update result +local name = 'shadowsocksr' local uciType = 'servers' -local ucic2 = uci.cursor() -local proxy = ucic2:get(application, '@server_subscribe[0]', 'proxy') or '0' -local switch = ucic2:get(application, '@server_subscribe[0]', 'switch') or '1' -local subscribe_url = ucic2:get(application, '@server_subscribe[0]', 'subscribe_url') or {} -local filter_words = ucic2:get(application, '@server_subscribe[0]', 'filter_words') or '过期时间/剩余流量' -ucic2:revert(application) +local ucic = luci.model.uci.cursor() +local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') +local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') +local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) +local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量') local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) end - --- 获取各项动态配置的当前服务器,可以用 get 和 set, get必须要获取到节点表 -local CONFIG = { - GLOBAL_SERVER = { - remarks = '主节点', - type = "global", option = "global_server", - set = function(server) - ucic2:set(application, '@global[0]', "global_server", server) - end - } -} -do - for k, v in pairs(CONFIG) do - local currentNode - if v.get then - currentNode = v.get() - else - local cfgid = ucic2:get(application, '@' .. v.type .. '[0]', v.option) - if cfgid then - currentNode = ucic2:get_all(application, cfgid) - end - end - if currentNode then - CONFIG[k].currentNode = currentNode - else - CONFIG[k] = nil - end - end -end - -- 分割字符串 local function split(full, sep) full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 @@ -77,15 +47,15 @@ local function split(full, sep) return result end -- urlencode --- local function get_urlencode(c) --- return sformat("%%%02X", sbyte(c)) --- end +local function get_urlencode(c) + return sformat("%%%02X", sbyte(c)) +end --- local function urlEncode(szText) --- local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) --- str = str:gsub(" ", "+") --- return str --- end +local function urlEncode(szText) + local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) + str = str:gsub(" ", "+") + return str +end local function get_urldecode(h) return schar(tonumber(h, 16)) @@ -101,7 +71,12 @@ local function trim(text) end return (sgsub(text, "^%s*(.-)%s*$", "%1")) end - +-- md5 +local function md5(content) + local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1') + -- assert(nixio.errno() == 0) + return trim(stdout) +end -- base64 local function base64Decode(text) local raw = text @@ -123,8 +98,7 @@ local function processData(szType, content) local result = { type = szType, local_port = 1234, - kcp_param = '--nocomp', - isSubscribe = 1, + kcp_param = '--nocomp' } if szType == 'ssr' then local dat = split(content, "/%?") @@ -288,6 +262,14 @@ local function processData(szType, content) if not result.alias then result.alias = result.server .. ':' .. result.server_port end + -- alias 不参与 hashkey 计算 + local alias = result.alias + result.alias = nil + local switch_enable = result.switch_enable + result.switch_enable = nil + result.hashkey = md5(jsonStringify(result)) + result.alias = alias + result.switch_enable = switch_enable return result end -- wget @@ -308,71 +290,20 @@ local function check_filer(result) end end -local function select_node(nodes, config) - local server - -- 第一优先级 IP + 端口 - for id, node in pairs(nodes) do - if node.server .. ':' .. node.server_port == config.currentNode.server .. ':' .. config.currentNode.server_port then - log('选择【' .. config.remarks .. '】第一匹配节点:' .. node.alias) - server = id - break - end - end - -- 第二优先级 IP - if not server then - for id, node in pairs(nodes) do - if node.server == config.currentNode.server then - log('选择【' .. config.remarks .. '】第二匹配节点:' .. node.alias) - server = id - break - end - end - end - -- 第三优先级备注 - if not server then - for id, node in pairs(nodes) do - if node.alias == config.currentNode.alias then - log('选择【' .. config.remarks .. '】第三匹配节点:' .. node.alias) - server = id - break - end - end - end - -- 第四 cfgid - if not server then - for id, node in pairs(nodes) do - if id == config.currentNode['.name'] then - log('选择【' .. config.remarks .. '】第四匹配节点:' .. node.alias) - server = id - break - end - end - end - -- 还不行 随便找一个 - if not server then - server = ucic2:get(application, '@'.. uciType .. '[0]') - if server then - log('无法找到最匹配的节点,当前已更换为' .. ucic2:get_all(application, server).alias) - end - end - if server then - config.set(server) - end -end - local execute = function() -- exec do if proxy == '0' then -- 不使用代理更新的话先暂停 log('服务正在暂停') - luci.sys.init.stop(application) + luci.sys.init.stop(name) end for k, url in ipairs(subscribe_url) do local raw = wget(url) if #raw > 0 then local nodes, szType - local all_odes = {} - tinsert(nodeResult, all_odes) + local groupHash = md5(url) + cache[groupHash] = {} + tinsert(nodeResult, {}) local index = #nodeResult -- SSD 似乎是这种格式 ssd:// 开头的 if raw:find('ssd://') then @@ -425,7 +356,9 @@ local execute = function() log('丢弃无效节点: ' .. result.type ..' 节点, ' .. result.alias) else log('成功解析: ' .. result.type ..' 节点, ' .. result.alias) - tinsert(all_odes, result) + result.grouphashkey = groupHash + tinsert(nodeResult[index], result) + cache[groupHash][result.hashkey] = nodeResult[index][#nodeResult[index]] end end end @@ -438,45 +371,60 @@ local execute = function() end -- diff do - assert(next(nodeResult), '更新失败,没有可用的节点信息') - -- delete all for subscribe nodes - ucic2:foreach(application, uciType, function(node) - if node.isSubscribe or node.hashkey then -- 兼容之前的hashkey - ucic2:delete(application, node['.name']) + if next(nodeResult) == nil then + log("更新失败,没有可用的节点信息") + return + end + local add, del = 0, 0 + ucic:foreach(name, uciType, function(old) + if old.grouphashkey or old.hashkey then -- 没有 hash 的不参与删除 + if not nodeResult[old.grouphashkey] or not nodeResult[old.grouphashkey][old.hashkey] then + ucic:delete(name, old['.name']) + del = del + 1 + else + local dat = nodeResult[old.grouphashkey][old.hashkey] + ucic:tset(name, old['.name'], dat) + -- 标记一下 + setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } }) + end + else + if not old.alias then + old.alias = old.server .. ':' .. old.server_port + end + log('忽略手动添加的节点: ' .. old.alias) end end) - for _, v in ipairs(nodeResult) do - for _, vv in ipairs(v) do - vv.switch_enable = switch - local cfgid = ucic2:add(application, uciType) - for kkk, vvv in pairs(vv) do - ucic2:set(application, cfgid, kkk, vvv) + for k, v in ipairs(nodeResult) do + for kk, vv in ipairs(v) do + if not vv._ignore then + local section = ucic:add(name, uciType) + ucic:tset(name, section, vv) + ucic:set(name, section, "switch_enable", switch) + add = add + 1 end end end - ucic2:commit(application) - local ucic3 = uci.cursor() - -- repair configuration - if next(CONFIG) then - local nodes = {} - ucic3:foreach(application, uciType, function(node) - if node.server and node.server_port and node.alias then - nodes[node['.name']] = node - end - end) - for _, config in pairs(CONFIG) do - select_node(nodes, config) + ucic:commit(name) + -- 如果原有服务器节点已经不见了就尝试换为第一个节点 + local globalServer = ucic:get_first(name, 'global', 'global_server', '') + local firstServer = ucic:get_first(name, uciType) + if firstServer then + if not ucic:get(name, globalServer) then + luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") + ucic:commit(name) + ucic:set(name, ucic:get_first(name, 'global'), 'global_server', ucic:get_first(name, uciType)) + ucic:commit(name) + log('当前主服务器节点已被删除,正在自动更换为第一个节点。') + luci.sys.call("/etc/init.d/" .. name .. " start > /dev/null 2>&1 &") + else + log('维持当前主服务器节点。') + luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") end - ucic3:commit(application) + else + log('没有服务器节点了,停止服务') + luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") end - -- select first server - local globalServer = ucic3:get(application, '@global[0]', 'global_server') or '' - if not globalServer or not ucic3:get_all(application, globalServer) then - ucic3:set(application, '@global[0]', 'global_server', select(2, ucic3:get(application, '@' .. uciType .. '[0]'))) - ucic3:commit(application) - log('当前没有主节点,自动选择第一个节点开启服务。') - end - luci.sys.call("/etc/init.d/" .. application .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + log('新增节点数量: ' ..add, '删除节点数量: ' .. del) log('订阅更新成功') end end @@ -486,11 +434,12 @@ if subscribe_url and #subscribe_url > 0 then log(e) log(debug.traceback()) log('发生错误, 正在恢复服务') - if CONFIG.GLOBAL_SERVER and CONFIG.GLOBAL_SERVER.currentNode then - luci.sys.call("/etc/init.d/" .. application .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + local firstServer = ucic:get_first(name, uciType) + if firstServer then + luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('重启服务成功') else - luci.sys.call("/etc/init.d/" .. application .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 log('停止服务成功') end end) From b97c4e8bb5707c90ba83885e115ba362c418d9b8 Mon Sep 17 00:00:00 2001 From: Mattraks <16359027+Mattraks@users.noreply.github.com> Date: Mon, 13 Apr 2020 01:44:03 +0800 Subject: [PATCH 19/27] luci-app-ssr-plus:Fix SS running status (#4289) * luci-app-ssr-plus:Code optimization and Fix Bug * luci-app-ssr-plus:Adjust reference data location * luci-app-ssr-plus:revert subscribe.lua * luci-app-ssr-plus:Fix SS running status * luci-app-ssr-plus:Updated version * luci-app-ssr-plus:Revised interpretation --- package/lean/luci-app-ssr-plus/Makefile | 2 +- .../luasrc/model/cbi/shadowsocksr/status.lua | 6 +++--- .../luci-app-ssr-plus/root/etc/init.d/shadowsocksr | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index 19fe30e56a..313b2dae53 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=176 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua index d6edefeb1e..c8225f3ebf 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -79,9 +79,9 @@ if luci.sys.call("busybox ps -w | grep ssr-server | grep -v grep >/dev/null") == server_run=1 end -if luci.sys.call("busybox ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then - tunnel_run=1 -end +-- if luci.sys.call("busybox ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then +-- tunnel_run=1 +-- end if luci.sys.call("pidof pdnsd >/dev/null") == 0 or (luci.sys.call("busybox ps -w | grep ssr-dns |grep -v grep >/dev/null") == 0 and luci.sys.call("pidof dns2socks >/dev/null") == 0)then pdnsd_run=1 diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 0f6332eed8..48910f018c 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -337,7 +337,7 @@ start_redir_tcp() { local name="Shadowsocks" [ "$type" == "ssr" ] && name="ShadowsocksR" for i in $(seq 1 $threads); do - $bin -c $CONFIG_FILE $ARG_OTA -f /var/run/$type-retcp_$i.pid >/dev/null 2>&1 + $bin -c $CONFIG_FILE $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1 done echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$name $threads Threads Started!" >>/tmp/ssrplus.log ;; @@ -386,7 +386,7 @@ start_redir_udp() { [ "$type" == "ssr" ] && name="ShadowsocksR" gen_config_file $UDP_RELAY_SERVER 1 $(uci_get_by_name $UDP_RELAY_SERVER local_port 1234) last_config_file=$CONFIG_UDP_FILE - $bin -c $last_config_file $ARG_OTA -U -f /var/run/$type-reudp.pid >/dev/null 2>&1 + $bin -c $last_config_file $ARG_OTA -U -f /var/run/ssr-reudp.pid >/dev/null 2>&1 echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$name Started!" >>/tmp/ssrplus.log ;; v2ray) @@ -418,7 +418,7 @@ start_redir_udp() { return 0 } -start_Bypass() { +start_shunt() { if [ "$NETFLIX_SERVER" != "nil" ] && [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then local type=$(uci_get_by_name $NETFLIX_SERVER type) local bin=$(find_bin $type) @@ -431,8 +431,8 @@ start_Bypass() { [ "$type" == "ssr" ] && name="ShadowsocksR" gen_config_file $NETFLIX_SERVER 2 4321 gen_config_file $NETFLIX_SERVER 3 1088 - $bin -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/$type-netflix.pid >/dev/null 2>&1 - $bin2 -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/$type-socksdns.pid >/dev/null 2>&1 + $bin -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/ssr-netflix.pid >/dev/null 2>&1 + $bin2 -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/ssr-socksdns.pid >/dev/null 2>&1 dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$name Started!" >>/tmp/ssrplus.log ;; @@ -487,7 +487,7 @@ start_local() { [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 [ "$type" == "ssr" ] && name="ShadowsocksR" gen_config_file $local_server 3 $(uci_get_by_type socks5_proxy local_port 1080) - $bin -c $CONFIG_SOCK5_FILE -u -f /var/run/$type-local.pid >/dev/null 2>&1 + $bin -c $CONFIG_SOCK5_FILE -u -f /var/run/ssr-local.pid >/dev/null 2>&1 echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$name Started!" >>/tmp/ssrplus.log ;; v2ray) @@ -694,7 +694,7 @@ start() { if rules; then if start_redir_tcp; then start_redir_udp - start_Bypass + start_shunt start_switch start_dns add_cron From f4a9966616fd4442b6c58e08e0cc44a3279c9ef2 Mon Sep 17 00:00:00 2001 From: hyird <31695447+hyird@users.noreply.github.com> Date: Tue, 14 Apr 2020 09:21:40 +0800 Subject: [PATCH 20/27] luci-app-unblockmusic: add flac switch for nodejs (#4302) * Update unblockmusic.lua * Update unblockmusic --- .../luasrc/model/cbi/unblockmusic.lua | 12 +++++++++--- .../root/etc/init.d/unblockmusic | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/package/lean/luci-app-unblockmusic/luasrc/model/cbi/unblockmusic.lua b/package/lean/luci-app-unblockmusic/luasrc/model/cbi/unblockmusic.lua index ca3a9fe7f5..68bfa674db 100644 --- a/package/lean/luci-app-unblockmusic/luasrc/model/cbi/unblockmusic.lua +++ b/package/lean/luci-app-unblockmusic/luasrc/model/cbi/unblockmusic.lua @@ -30,7 +30,7 @@ speedtype:value("qq", translate("QQ音乐")) speedtype:value("xiami", translate("虾米音乐")) speedtype:value("baidu", translate("百度音乐")) speedtype:value("kugou", translate("酷狗音乐")) -speedtype:value("kuwo", translate("酷我音乐(高音质/FLACの解锁可能性)")) +speedtype:value("kuwo", translate("酷我音乐")) speedtype:value("migu", translate("咕咪音乐")) speedtype:value("joox", translate("JOOX音乐")) speedtype.default = "kuwo" @@ -47,8 +47,11 @@ cloudserver.default = "cdn-shanghai.service.project-openwrt.eu.org:30000:30001" cloudserver.rmempty = true cloudserver:depends("apptype", "cloud") -download_certificate=s:option(DummyValue,"opennewwindow",translate("HTTPS 证书")) -download_certificate.description = translate("
Mac/iOS客户端需要安装 CA根证书并信任
iOS系统需要在“设置 -> 通用 -> 关于本机 -> 证书信任设置”中,信任 UnblockNeteaseMusic Root CA
Linux 设备请在启用时加入 --ignore-certificate-errors 参数") +flac = s:option(Flag, "flac_enabled", translate("启用无损音质")) +flac.default = 1 +flac.rmempty = false +flac.description = translate("目前仅支持酷我、QQ、咪咕") +flac:depends("apptype", "nodejs") o = s:option(Flag, "autoupdate") o.title = translate("自动检查更新主程序") @@ -57,6 +60,9 @@ o.rmempty = false o.description = translate("每天自动检测并更新到最新版本") o:depends("apptype", "nodejs") +download_certificate=s:option(DummyValue,"opennewwindow",translate("HTTPS 证书")) +download_certificate.description = translate("
Mac/iOS客户端需要安装 CA根证书并信任
iOS系统需要在“设置 -> 通用 -> 关于本机 -> 证书信任设置”中,信任 UnblockNeteaseMusic Root CA
Linux 设备请在启用时加入 --ignore-certificate-errors 参数") + local ver = fs.readfile("/usr/share/UnblockNeteaseMusic/core_ver") or "0.00" o = s:option(Button, "restart",translate("手动更新")) diff --git a/package/lean/luci-app-unblockmusic/root/etc/init.d/unblockmusic b/package/lean/luci-app-unblockmusic/root/etc/init.d/unblockmusic index 585291277b..3fdc4f9a72 100755 --- a/package/lean/luci-app-unblockmusic/root/etc/init.d/unblockmusic +++ b/package/lean/luci-app-unblockmusic/root/etc/init.d/unblockmusic @@ -65,6 +65,7 @@ ENABLE=$(uci_get_by_type unblockmusic enabled 0) TYPE=$(uci_get_by_type unblockmusic musicapptype default) AUTOUPDATE=$(uci_get_by_type unblockmusic autoupdate 0) APPTYPE=$(uci_get_by_type unblockmusic apptype go) +FLAC=$(uci_get_by_type unblockmusic flac_enabled 0) CLOUD=$(uci_get_by_type unblockmusic cloudserver "127.0.0.1:5200:5201") cloudadd=$(echo "$CLOUD" | awk -F ':' '{print $1}') @@ -168,7 +169,9 @@ start() fi if [ "$APPTYPE" == "nodejs" ]; then + if [ $FLAC -eq 1 ]; then export ENABLE_FLAC=true + fi node /usr/share/UnblockNeteaseMusic/app.js -e http://music.163.com -p 5200:5201 $musictype >>/tmp/unblockmusic.log 2>&1 & add_cron echo "$(date -R) # UnblockNeteaseMusic Nodejs Version (http:5200, https:5201)" >>/tmp/unblockmusic.log From f7cdc5460280173de9cdeb01dabf88836d948e4a Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Tue, 14 Apr 2020 09:22:11 +0800 Subject: [PATCH 21/27] ipq40xx: add missing device config for rt-ac1300uhp (#4300) --- .../ipq40xx/base-files/etc/board.d/01_leds | 3 +- .../ipq40xx/base-files/etc/board.d/02_network | 17 ++++----- .../etc/hotplug.d/firmware/11-ath10k-caldata | 36 ++++++++++--------- .../lib/preinit/05_set_iface_mac_ipq40xx.sh | 4 ++- .../preinit/06_set_preinit_iface_ipq40xx.sh | 1 + .../base-files/lib/upgrade/platform.sh | 3 +- 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/target/linux/ipq40xx/base-files/etc/board.d/01_leds b/target/linux/ipq40xx/base-files/etc/board.d/01_leds index a4d33c0dbe..d80c161a24 100755 --- a/target/linux/ipq40xx/base-files/etc/board.d/01_leds +++ b/target/linux/ipq40xx/base-files/etc/board.d/01_leds @@ -11,7 +11,8 @@ board=$(board_name) boardname="${board##*,}" case "$board" in -asus,rt-ac58u) +asus,rt-ac58u |\ +asus,rt-ac1300uhp) ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:blue:wlan2G" "phy0tpt" ucidef_set_led_wlan "wlan5g" "WLAN5G" "${boardname}:blue:wlan5G" "phy1tpt" ucidef_set_led_switch "wan" "WAN" "${boardname}:blue:wan" "switch0" "0x20" diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network index 3b1306ed4e..a6436ae048 100755 --- a/target/linux/ipq40xx/base-files/etc/board.d/02_network +++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network @@ -16,12 +16,6 @@ ipq40xx_setup_interfaces() ucidef_add_switch "switch0" \ "0t@eth0" "4:lan" "5:wan" ;; - p2w,r619ac|\ - p2w,r619ac-128m|\ - zyxel,nbg6617) - ucidef_add_switch "switch0" \ - "0t@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "5:wan:5" - ;; asus,map-ac2200|\ openmesh,a42|\ openmesh,a62) @@ -30,6 +24,7 @@ ipq40xx_setup_interfaces() ;; asus,rt-acrh17|\ asus,rt-ac58u|\ + asus,rt-ac1300uhp|\ avm,fritzbox-4040|\ linksys,ea6350v3) ucidef_add_switch "switch0" \ @@ -57,6 +52,12 @@ ipq40xx_setup_interfaces() ucidef_add_switch "switch0" \ "0t@eth0" "3:lan:2" "4:lan:1" "5:wan" ;; + p2w,r619ac|\ + p2w,r619ac-128m|\ + zyxel,nbg6617) + ucidef_add_switch "switch0" \ + "0t@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "5:wan:5" + ;; *) echo "Unsupported hardware. Network interfaces not initialized" ;; @@ -85,8 +86,8 @@ ipq40xx_setup_macs() ;; esac - [ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac - [ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac + [ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac + [ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac } board_config_update diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index e58e4d8e71..753595897e 100644 --- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -138,14 +138,22 @@ case "$FIRMWARE" in asus,map-ac2200) ath10kcal_ubi_extract "Factory" 4096 12064 ;; - asus,rt-acrh17|\ - asus,rt-ac58u) + asus,rt-acrh17 |\ + asus,rt-ac58u |\ + asus,rt-ac1300uhp) CI_UBIPART=UBI_DEV ath10kcal_ubi_extract "Factory" 4096 12064 ;; avm,fritzbox-4040) /usr/bin/fritz_cal_extract -i 1 -s 0x400 -e 0x207 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader_config") ;; + compex,wpj428 |\ + engenius,eap1300 |\ + hugo,ac1200 |\ + openmesh,a42 |\ + openmesh,a62) + ath10kcal_extract "0:ART" 4096 12064 + ;; meraki,mr33) ath10kcal_ubi_extract "ART" 4096 12064 ath10kcal_is_caldata_valid "202f" || ath10kcal_extract "ART" 4096 12064 @@ -156,13 +164,6 @@ case "$FIRMWARE" in ath10kcal_extract "ART" 4096 12064 ath10kcal_patch_mac_crc $(mtd_get_mac_binary dnidata 0) ;; - compex,wpj428 |\ - engenius,eap1300 |\ - hugo,ac1200 |\ - openmesh,a42 |\ - openmesh,a62) - ath10kcal_extract "0:ART" 4096 12064 - ;; zyxel,nbg6617 |\ zyxel,wre6606) ath10kcal_extract "ART" 4096 12064 @@ -184,13 +185,21 @@ case "$FIRMWARE" in asus,map-ac2200) ath10kcal_ubi_extract "Factory" 20480 12064 ;; - asus,rt-ac58u) + asus,rt-ac58u |\ + asus,rt-ac1300uhp) CI_UBIPART=UBI_DEV ath10kcal_ubi_extract "Factory" 20480 12064 ;; avm,fritzbox-4040) /usr/bin/fritz_cal_extract -i 1 -s 0x400 -e 0x208 -l 12064 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader_config") ;; + compex,wpj428 |\ + engenius,eap1300 |\ + hugo,ac1200 |\ + openmesh,a42 |\ + openmesh,a62) + ath10kcal_extract "0:ART" 20480 12064 + ;; meraki,mr33) ath10kcal_ubi_extract "ART" 20480 12064 ath10kcal_is_caldata_valid "202f" || ath10kcal_extract "ART" 20480 12064 @@ -201,13 +210,6 @@ case "$FIRMWARE" in ath10kcal_extract "ART" 20480 12064 ath10kcal_patch_mac_crc $(mtd_get_mac_binary dnidata 12) ;; - compex,wpj428 |\ - engenius,eap1300 |\ - hugo,ac1200 |\ - openmesh,a42 |\ - openmesh,a62) - ath10kcal_extract "0:ART" 20480 12064 - ;; zyxel,nbg6617 |\ zyxel,wre6606) ath10kcal_extract "ART" 20480 12064 diff --git a/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh b/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh index 44dc510a0f..14cc7fc41a 100644 --- a/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh +++ b/target/linux/ipq40xx/base-files/lib/preinit/05_set_iface_mac_ipq40xx.sh @@ -10,7 +10,8 @@ preinit_set_mac_address() { ip link set dev eth1 address $(macaddr_add "$base_mac" +3) ;; asus,rt-acrh17|\ - asus,rt-ac58u) + asus,rt-ac58u|\ + asus,rt-ac1300uhp) CI_UBIPART=UBI_DEV mac=$(macaddr_add $(mtd_get_mac_binary_ubi Factory 4102) +1) ifconfig eth0 hw ether $mac 2>/dev/null @@ -22,6 +23,7 @@ preinit_set_mac_address() { zyxel,nbg6617) base_mac=$(cat /sys/class/net/eth0/address) ip link set dev eth0 address $(macaddr_add "$base_mac" +2) + ip link set dev eth1 address $(macaddr_add "$base_mac" +3) ;; esac } diff --git a/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh b/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh index 578ddbe4c4..1ef1c9b159 100644 --- a/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh +++ b/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh @@ -5,6 +5,7 @@ set_preinit_iface() { case $(board_name) in asus,rt-ac58u| \ + asus,rt-ac1300uhp| \ avm,fritzbox-4040| \ glinet,gl-b1300| \ meraki,mr33| \ diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh index 29d60bd138..acbd633859 100644 --- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh +++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh @@ -172,7 +172,8 @@ platform_do_upgrade() { nand_do_upgrade "$1" ;; asus,rt-acrh17|\ - asus,rt-ac58u) + asus,rt-ac58u|\ + asus,rt-ac1300uhp) local magic=$(get_magic_long "$1") CI_UBIPART="UBI_DEV" CI_KERNPART="linux" From 9cf7ebae5faa6ad4a898a1085e91ba40afb2f23c Mon Sep 17 00:00:00 2001 From: Mattraks <16359027+Mattraks@users.noreply.github.com> Date: Tue, 14 Apr 2020 09:25:17 +0800 Subject: [PATCH 22/27] luci-app-ssr-plus:Fix kcptun startup errors (#4303) * Fix Errors * Updated version * luci-app-ssr-plus:require "luci.model.uci" * luci-app-ssr-plus:Revised explanation --- package/lean/luci-app-ssr-plus/Makefile | 2 +- .../model/cbi/shadowsocksr/client-config.lua | 2 +- .../root/etc/init.d/shadowsocksr | 20 +++++++++---------- .../share/shadowsocksr/gentrojanconfig.lua | 2 +- .../usr/share/shadowsocksr/genv2config.lua | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index 313b2dae53..dfcb59cb1a 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=176 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 48e113359a..a404d2824b 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -14,7 +14,7 @@ local function isKcptun(file) if not nixio.fs.access(file, "rwx", "rx", "rx") then nixio.fs.chmod(file, 755) end - local str = uci.sys.exec(file .. " -v | awk '{printf $1}'") + local str = luci.sys.exec(file .. " -v | awk '{printf $1}'") return (str:lower() == "kcptun") end diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 48910f018c..ec84911de8 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -339,17 +339,17 @@ start_redir_tcp() { for i in $(seq 1 $threads); do $bin -c $CONFIG_FILE $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1 done - echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$name $threads Threads Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:$name $threads Threads Started!" >>/tmp/ssrplus.log ;; v2ray) $bin -config /var/etc/v2-ssr-retcp.json >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log ;; trojan) for i in $(seq 1 $threads); do $bin --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & done - echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:$($bin --version 2>&1 | head -1) , $threads Threads Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:$($bin --version 2>&1 | head -1) , $threads Threads Started!" >>/tmp/ssrplus.log ;; socks5) /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" socks5 tcp $(uci_get_by_name $GLOBAL_SERVER local_port) \ @@ -358,14 +358,14 @@ start_redir_tcp() { for i in $(seq 1 $threads); do $bin -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 done - echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:Socks5 REDIRECT/TPROXY $threads Threads Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:Socks5 REDIRECT/TPROXY $threads Threads Started!" >>/tmp/ssrplus.log ;; tun) /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" vpn $(uci_get_by_name $GLOBAL_SERVER iface "br-lan") $(uci_get_by_name $GLOBAL_SERVER local_port) for i in $(seq 1 $threads); do $bin -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 done - echo "$(date "+%Y-%m-%d %H:%M:%S") Master node:Network Tunnel REDIRECT $threads Threads Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:Network Tunnel REDIRECT $threads Threads Started!" >>/tmp/ssrplus.log ;; esac return 0 @@ -434,13 +434,13 @@ start_shunt() { $bin -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/ssr-netflix.pid >/dev/null 2>&1 $bin2 -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/ssr-socksdns.pid >/dev/null 2>&1 dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$name Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:$name Started!" >>/tmp/ssrplus.log ;; v2ray) lua /usr/share/shadowsocksr/genv2config.lua $NETFLIX_SERVER tcp 4321 1088 >/var/etc/v2-ssr-netflix.json $bin -config /var/etc/v2-ssr-netflix.json >/dev/null 2>&1 & dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log ;; trojan) lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER nat 4321 >/var/etc/trojan-ssr-netflix.json @@ -450,7 +450,7 @@ start_shunt() { sed -i 's/\\//g' /var/etc/trojan-ssr-socksdns.json $bin --config /var/etc/trojan-ssr-socksdns.json >/dev/null 2>&1 & dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log ;; socks5) /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" socks5 tcp 4321 \ @@ -459,14 +459,14 @@ start_shunt() { $bin -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:Socks5 Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:Socks5 Started!" >>/tmp/ssrplus.log ;; tun) /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" vpn $(uci_get_by_name $NETFLIX_SERVER iface "br-lan") 4321 $bin -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix Bypass:Network Tunnel REDIRECT Started!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:Network Tunnel REDIRECT Started!" >>/tmp/ssrplus.log ;; esac fi diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua index 9474777d06..2758111744 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua @@ -1,4 +1,4 @@ -local ucursor = require "uci".cursor() +local ucursor = require "luci.model.uci".cursor() local json = require "luci.jsonc" local server_section = arg[1] local proto = arg[2] diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua index 36e7efae48..23d5bd9063 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua @@ -1,4 +1,4 @@ -local ucursor = require "uci".cursor() +local ucursor = require "luci.model.uci".cursor() local json = require "luci.jsonc" local server_section = arg[1] local proto = arg[2] From 3ad7a35c9131f0f3bfe5bd2208cc8aa924455b24 Mon Sep 17 00:00:00 2001 From: CN_SZTL <22235437+1715173329@users.noreply.github.com> Date: Tue, 14 Apr 2020 09:25:59 +0800 Subject: [PATCH 23/27] luci-app-ssr-plus: use "&" to instead of "-d" (daemon mode) (#4307) --- package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index ec84911de8..619b638216 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -281,7 +281,7 @@ start_dns() { purge_cache=off; } EOF - /usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d & + /usr/sbin/pdnsd -c /var/etc/pdnsd.conf & } if [ "$ssr_dns" != "0" ]; then case "$run_mode" in From 8a02b490780a56991fec382a8dfa8943b49d9b71 Mon Sep 17 00:00:00 2001 From: Mattraks <16359027+Mattraks@users.noreply.github.com> Date: Wed, 15 Apr 2020 00:48:29 +0800 Subject: [PATCH 24/27] luci-app-ssr-plus:Fix Socks5 startup errors (#4310) * luci-app-ssr-plus:Fix Socks5 startup errors * luci-app-ssr-plus:Fix pdnsd EOF warning errors * luci-app-ssr-plus: ssr-switch Adjust Output * luci-app-ssr-plus: Data Update --- package/lean/luci-app-ssr-plus/Makefile | 2 +- .../model/cbi/shadowsocksr/client-config.lua | 5 - .../luasrc/model/cbi/shadowsocksr/client.lua | 1 - .../luasrc/model/cbi/shadowsocksr/control.lua | 1 - .../model/cbi/shadowsocksr/server-config.lua | 3 - .../luasrc/model/cbi/shadowsocksr/servers.lua | 4 - .../root/etc/dnsmasq.ssr/gfw_list.conf | 40 +----- .../root/etc/init.d/shadowsocksr | 4 +- .../root/etc/ssr/china_ssr.txt | 2 + .../root/usr/bin/ssr-monitor | 2 +- .../luci-app-ssr-plus/root/usr/bin/ssr-switch | 6 +- .../usr/share/shadowsocksr/genred2config.sh | 129 +++++++++--------- 12 files changed, 77 insertions(+), 122 deletions(-) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index dfcb59cb1a..65d86a8a8d 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=176 -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index a404d2824b..580fbc6783 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -243,7 +243,6 @@ o.rmempty = true o:depends("type", "v2ray") -- [[ TCP部分 ]]-- - -- TCP伪装 o = s:option(ListValue, "tcp_guise", translate("Camouflage Type")) o:depends("transport", "tcp") @@ -262,7 +261,6 @@ o:depends("tcp_guise", "http") o.rmempty = true -- [[ WS部分 ]]-- - -- WS域名 o = s:option(Value, "ws_host", translate("WebSocket Host")) o:depends("transport", "ws") @@ -274,7 +272,6 @@ o:depends("transport", "ws") o.rmempty = true -- [[ H2部分 ]]-- - -- H2域名 o = s:option(Value, "h2_host", translate("HTTP/2 Host")) o:depends("transport", "h2") @@ -286,7 +283,6 @@ o:depends("transport", "h2") o.rmempty = true -- [[ QUIC部分 ]]-- - o = s:option(ListValue, "quic_security", translate("QUIC Security")) o:depends("transport", "quic") o.rmempty = true @@ -309,7 +305,6 @@ o:value("dtls", "DTLS 1.2") o:value("wireguard", "WireGuard") -- [[ mKCP部分 ]]-- - o = s:option(ListValue, "kcp_guise", translate("Camouflage Type")) o:depends("transport", "kcp") o:value("none", translate("None")) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua index 9992d55bde..7e09f4d366 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua @@ -7,7 +7,6 @@ local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() m = Map(shadowsocksr, translate("ShadowSocksR Plus+ Settings")) - m:section(SimpleSection).template = "shadowsocksr/status" local server_table = {} diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua index 9f2b39bf61..39da0e123e 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua @@ -84,7 +84,6 @@ o.remove = function(self, section, value) nixio.fs.writefile(escconf, "") end - s:tab("block", translate("Black Domain List")) local blockconf = "/etc/ssr/black.list" diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua index 4e7e3cf65a..2f7b21868a 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua @@ -49,9 +49,6 @@ if m.uci:get(shadowsocksr, sid) ~= "server_config" then return end - - - -- [[ Server Setting ]]-- s = m:section(NamedSection, sid, "server_config") s.anonymous = true diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index 2378798172..e95c85cc1a 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -14,7 +14,6 @@ end) m = Map(shadowsocksr, translate("Servers subscription and manage")) -- Server Subscribe - s = m:section(TypedSection, "server_subscribe") s.anonymous = true @@ -22,7 +21,6 @@ o = s:option(Flag, "auto_update", translate("Auto Update")) o.rmempty = false o.description = translate("Auto Update Server subscription, GFW list and CHN route") - o = s:option(ListValue, "auto_update_time", translate("Update time (every day)")) for t = 0,23 do o:value(t, t..":00") @@ -53,7 +51,6 @@ o = s:option(Flag, "proxy", translate("Through proxy update")) o.rmempty = false o.description = translate("Through proxy update list, Not Recommended ") - o = s:option(Button,"subscribe", translate("Update All Subscribe Severs")) o.rawhtml = true o.template = "shadowsocksr/subscribe" @@ -114,7 +111,6 @@ o = s:option(DummyValue, "server", translate("Ping Latency")) o.template="shadowsocksr/ping" o.width="10%" - node = s:option(Button,"apply_node",translate("Apply")) node.inputstyle = "apply" node.write = function(self, section) diff --git a/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf b/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf index ccaf1bf863..db07b2f022 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf +++ b/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf @@ -514,6 +514,8 @@ server=/.api.pureapk.com/127.0.0.1#5335 ipset=/.api.pureapk.com/gfwlist server=/.api.recaptcha.net/127.0.0.1#5335 ipset=/.api.recaptcha.net/gfwlist +server=/.api.tenor.com/127.0.0.1#5335 +ipset=/.api.tenor.com/gfwlist server=/.apiary.io/127.0.0.1#5335 ipset=/.apiary.io/gfwlist server=/.apidocs.linksalpha.com/127.0.0.1#5335 @@ -746,8 +748,6 @@ server=/.bbc.co.uk/127.0.0.1#5335 ipset=/.bbc.co.uk/gfwlist server=/.bbc.com/127.0.0.1#5335 ipset=/.bbc.com/gfwlist -server=/.bbc.in/127.0.0.1#5335 -ipset=/.bbc.in/gfwlist server=/.bbcchinese.com/127.0.0.1#5335 ipset=/.bbcchinese.com/gfwlist server=/.bbchat.tv/127.0.0.1#5335 @@ -4024,8 +4024,6 @@ server=/.hitbtc.com/127.0.0.1#5335 ipset=/.hitbtc.com/gfwlist server=/.hitomi.la/127.0.0.1#5335 ipset=/.hitomi.la/gfwlist -server=/.hiwifi.com/127.0.0.1#5335 -ipset=/.hiwifi.com/gfwlist server=/.hizb-ut-tahrir.info/127.0.0.1#5335 ipset=/.hizb-ut-tahrir.info/gfwlist server=/.hizb-ut-tahrir.org/127.0.0.1#5335 @@ -4894,8 +4892,6 @@ server=/.kepard.com/127.0.0.1#5335 ipset=/.kepard.com/gfwlist server=/.kex.com/127.0.0.1#5335 ipset=/.kex.com/gfwlist -server=/.keycdn.com/127.0.0.1#5335 -ipset=/.keycdn.com/gfwlist server=/.khabdha.org/127.0.0.1#5335 ipset=/.khabdha.org/gfwlist server=/.khmusic.com.tw/127.0.0.1#5335 @@ -4934,8 +4930,6 @@ server=/.kk-whys.co.jp/127.0.0.1#5335 ipset=/.kk-whys.co.jp/gfwlist server=/.kkbox.com/127.0.0.1#5335 ipset=/.kkbox.com/gfwlist -server=/.kknews.cc/127.0.0.1#5335 -ipset=/.kknews.cc/gfwlist server=/.kmuh.org.tw/127.0.0.1#5335 ipset=/.kmuh.org.tw/gfwlist server=/.kobo.com/127.0.0.1#5335 @@ -6306,8 +6300,6 @@ server=/.openvpn.org/127.0.0.1#5335 ipset=/.openvpn.org/gfwlist server=/.openwebster.com/127.0.0.1#5335 ipset=/.openwebster.com/gfwlist -server=/.openwrt.org.cn/127.0.0.1#5335 -ipset=/.openwrt.org.cn/gfwlist server=/.opml.radiotime.com/127.0.0.1#5335 ipset=/.opml.radiotime.com/gfwlist server=/.opus-gaming.com/127.0.0.1#5335 @@ -6678,6 +6670,8 @@ server=/.pornhub.com/127.0.0.1#5335 ipset=/.pornhub.com/gfwlist server=/.pornhubdeutsch.net/127.0.0.1#5335 ipset=/.pornhubdeutsch.net/gfwlist +server=/.pornhubpremium.com/127.0.0.1#5335 +ipset=/.pornhubpremium.com/gfwlist server=/.pornmm.net/127.0.0.1#5335 ipset=/.pornmm.net/gfwlist server=/.pornoxo.com/127.0.0.1#5335 @@ -6970,8 +6964,6 @@ server=/.rcinet.ca/127.0.0.1#5335 ipset=/.rcinet.ca/gfwlist server=/.rconversation.blogs.com/127.0.0.1#5335 ipset=/.rconversation.blogs.com/gfwlist -server=/.read01.com/127.0.0.1#5335 -ipset=/.read01.com/gfwlist server=/.read100.com/127.0.0.1#5335 ipset=/.read100.com/gfwlist server=/.readingtimes.com.tw/127.0.0.1#5335 @@ -7472,8 +7464,6 @@ server=/.sino-monthly.com/127.0.0.1#5335 ipset=/.sino-monthly.com/gfwlist server=/.sinoants.com/127.0.0.1#5335 ipset=/.sinoants.com/gfwlist -server=/.sinocast.com/127.0.0.1#5335 -ipset=/.sinocast.com/gfwlist server=/.sinocism.com/127.0.0.1#5335 ipset=/.sinocism.com/gfwlist server=/.sinomontreal.ca/127.0.0.1#5335 @@ -8872,8 +8862,6 @@ server=/.twitterrific.com/127.0.0.1#5335 ipset=/.twitterrific.com/gfwlist server=/.twittertim.es/127.0.0.1#5335 ipset=/.twittertim.es/gfwlist -server=/.twitthat.com/127.0.0.1#5335 -ipset=/.twitthat.com/gfwlist server=/.twitturk.com/127.0.0.1#5335 ipset=/.twitturk.com/gfwlist server=/.twitturly.com/127.0.0.1#5335 @@ -9084,8 +9072,6 @@ server=/.uyghurcongress.org/127.0.0.1#5335 ipset=/.uyghurcongress.org/gfwlist server=/.uyghurensemble.co.uk/127.0.0.1#5335 ipset=/.uyghurensemble.co.uk/gfwlist -server=/.uyghurpen.org/127.0.0.1#5335 -ipset=/.uyghurpen.org/gfwlist server=/.uyghurpress.com/127.0.0.1#5335 ipset=/.uyghurpress.com/gfwlist server=/.uyghurstudies.org/127.0.0.1#5335 @@ -9334,8 +9320,6 @@ server=/.vpnworldwide.com/127.0.0.1#5335 ipset=/.vpnworldwide.com/gfwlist server=/.vporn.com/127.0.0.1#5335 ipset=/.vporn.com/gfwlist -server=/.vpser.net/127.0.0.1#5335 -ipset=/.vpser.net/gfwlist server=/.vraiesagesse.net/127.0.0.1#5335 ipset=/.vraiesagesse.net/gfwlist server=/.vrmtr.com/127.0.0.1#5335 @@ -9504,8 +9488,6 @@ server=/.wezhiyong.org/127.0.0.1#5335 ipset=/.wezhiyong.org/gfwlist server=/.wezone.net/127.0.0.1#5335 ipset=/.wezone.net/gfwlist -server=/.wforum.com/127.0.0.1#5335 -ipset=/.wforum.com/gfwlist server=/.wha.la/127.0.0.1#5335 ipset=/.wha.la/gfwlist server=/.whatblocked.com/127.0.0.1#5335 @@ -9694,8 +9676,6 @@ server=/.wtbn.org/127.0.0.1#5335 ipset=/.wtbn.org/gfwlist server=/.wtfpeople.com/127.0.0.1#5335 ipset=/.wtfpeople.com/gfwlist -server=/.wuerkaixi.com/127.0.0.1#5335 -ipset=/.wuerkaixi.com/gfwlist server=/.wufafangwen.com/127.0.0.1#5335 ipset=/.wufafangwen.com/gfwlist server=/.wufi.org.tw/127.0.0.1#5335 @@ -9756,10 +9736,6 @@ server=/.www.powerpointninja.com/127.0.0.1#5335 ipset=/.www.powerpointninja.com/gfwlist server=/.www.s4miniarchive.com/127.0.0.1#5335 ipset=/.www.s4miniarchive.com/gfwlist -server=/.www.shadowsocks.com/127.0.0.1#5335 -ipset=/.www.shadowsocks.com/gfwlist -server=/.www.shwchurch.org/127.0.0.1#5335 -ipset=/.www.shwchurch.org/gfwlist server=/.www.taup.org.tw/127.0.0.1#5335 ipset=/.www.taup.org.tw/gfwlist server=/.www.wan-press.org/127.0.0.1#5335 @@ -10170,16 +10146,10 @@ server=/.zhongguorenquan.org/127.0.0.1#5335 ipset=/.zhongguorenquan.org/gfwlist server=/.zhongguotese.net/127.0.0.1#5335 ipset=/.zhongguotese.net/gfwlist -server=/.zhongmeng.org/127.0.0.1#5335 -ipset=/.zhongmeng.org/gfwlist server=/.zhoushuguang.com/127.0.0.1#5335 ipset=/.zhoushuguang.com/gfwlist server=/.zhreader.com/127.0.0.1#5335 ipset=/.zhreader.com/gfwlist -server=/.zhuangbi.me/127.0.0.1#5335 -ipset=/.zhuangbi.me/gfwlist -server=/.zhuanxing.cn/127.0.0.1#5335 -ipset=/.zhuanxing.cn/gfwlist server=/.zhuatieba.com/127.0.0.1#5335 ipset=/.zhuatieba.com/gfwlist server=/.zhuichaguoji.org/127.0.0.1#5335 @@ -10202,8 +10172,6 @@ server=/.zodgame.us/127.0.0.1#5335 ipset=/.zodgame.us/gfwlist server=/.zomobo.net/127.0.0.1#5335 ipset=/.zomobo.net/gfwlist -server=/.zonaeuropa.com/127.0.0.1#5335 -ipset=/.zonaeuropa.com/gfwlist server=/.zonghexinwen.com/127.0.0.1#5335 ipset=/.zonghexinwen.com/gfwlist server=/.zonghexinwen.net/127.0.0.1#5335 diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 619b638216..e46004cf85 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -248,9 +248,9 @@ start_dns() { [ -z "$usr_dns" ] && usr_dns="8.8.8.8" [ -z "$usr_port" ] && usr_port="53" [ -d /var/etc ] || mkdir -p /var/etc - if [ ! -d /var/pdnsd ]; then + if [ ! -f "/var/pdnsd/pdnsd.cache" ]; then mkdir -p /var/pdnsd - echo -ne "pd13\000\000\000\000" >/var/pdnsd/pdnsd.cache + touch /var/pdnsd/pdnsd.cache chown -R nobody:nogroup /var/pdnsd fi cat <<-EOF >/var/etc/pdnsd.conf diff --git a/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt b/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt index b5e637c5b5..4acc39721e 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt +++ b/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt @@ -4014,6 +4014,8 @@ 103.149.246.0/23 103.149.248.0/23 103.150.24.0/23 +103.150.66.0/23 +103.150.72.0/23 103.192.0.0/22 103.192.4.0/22 103.192.8.0/22 diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor index 4525a0d1f3..80bf559f6e 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor @@ -127,7 +127,7 @@ while [ "1" == "1" ]; do #死循环 else kill -9 $(ps | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1 fi - (/usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d &) + (/usr/sbin/pdnsd -c /var/etc/pdnsd.conf &) fi fi #dns2socks diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch index 15378a17f7..661506bf56 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch @@ -82,7 +82,7 @@ test_proxy() { search_proxy() { let server_count=server_count+1 [ "$normal_flag" == "1" -a "$server_count" -le "$server_locate" ] && return 0 - [ "$(uci_get_by_name $1 switch_enable)" != "1" ] && return 1 + [ "$(uci_get_by_name $1 switch_enable 0)" != "1" ] && return 1 [ $ENABLE_SERVER != nil ] && return 0 [ "$1" == "$CURRENT_SERVER" ] && return 0 local servername=$(uci_get_by_name $1 server) @@ -136,7 +136,7 @@ start() { #缺省服务器正常,切换回来 CURRENT_SERVER=$DEFAULT_SERVER switch_proxy $CURRENT_SERVER - echo "$(date "+%Y-%m-%d %H:%M:%S") switch to default ["$(uci_get_by_name $CURRENT_SERVER server)"] proxy!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") switch to default "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" >>/tmp/ssrplus.log else echo "$(date "+%Y-%m-%d %H:%M:%S") Main server is NOT avilable.Continue using current server." >>/tmp/ssrplus.log fi @@ -157,7 +157,7 @@ start() { CURRENT_SERVER=$ENABLE_SERVER switch_proxy $CURRENT_SERVER normal_flag=1 - echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR server switch OK" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Switch to "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" >>/tmp/ssrplus.log else switch_proxy $CURRENT_SERVER normal_flag=1 diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh index 480b8e3ef3..5e51003424 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh @@ -1,71 +1,70 @@ #!/bin/sh cat <<-EOF >$1 - base { - log_debug = off; - log_info = off; - log = stderr; - daemon = on; - redirector = iptables; - reuseport = on; - } +base { +log_debug = off; +log_info = off; +log = stderr; +daemon = on; +redirector = iptables; +reuseport = on; +} EOF - if [ "$2" == "socks5" ]; then - if [ "$3" == "tcp" ]; then - if [ "$7" == "0" ]; then - cat <<-EOF >>$1 - redsocks { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - autoproxy = 0; - timeout = 10; - } - EOF - else - cat <<-EOF >>$1 - redsocks { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - autoproxy = 0; - timeout = 10; - login = "$8"; - password = "$9"; - } - EOF - fi - else - if [ "$7" == "0" ]; then - cat <<-EOF >>$1 - redudp { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - udp_timeout = 10; - } - EOF - else - cat <<-EOF >>$1 - redudp { - bind = "0.0.0.0:$4"; - relay = "$5:$6"; - type = socks5; - udp_timeout = 10; - login = "$8"; - password = "$9"; - } - EOF - fi - fi +if [ "$3" == "tcp" ]; then +if [ "$7" == "0" ]; then +cat <<-EOF >>$1 +redsocks { +bind = "0.0.0.0:$4"; +relay = "$5:$6"; +type = socks5; +autoproxy = 0; +timeout = 10; +} +EOF else - cat <<-EOF >>$1 - redsocks { - bind = "0.0.0.0:$4"; - type = direct; - interface = $3; - autoproxy = 0; - timeout = 10; - } - EOF +cat <<-EOF >>$1 +redsocks { +bind = "0.0.0.0:$4"; +relay = "$5:$6"; +type = socks5; +autoproxy = 0; +timeout = 10; +login = "$8"; +password = "$9"; +} +EOF +fi +else +if [ "$7" == "0" ]; then +cat <<-EOF >>$1 +redudp { +bind = "0.0.0.0:$4"; +relay = "$5:$6"; +type = socks5; +udp_timeout = 10; +} +EOF +else +cat <<-EOF >>$1 +redudp { +bind = "0.0.0.0:$4"; +relay = "$5:$6"; +type = socks5; +udp_timeout = 10; +login = "$8"; +password = "$9"; +} +EOF +fi +fi +else +cat <<-EOF >>$1 +redsocks { +bind = "0.0.0.0:$4"; +type = direct; +interface = $3; +autoproxy = 0; +timeout = 10; +} +EOF fi From 2125e805d18fe4441f48748cb90e2ac3dae14785 Mon Sep 17 00:00:00 2001 From: lean Date: Wed, 15 Apr 2020 20:39:16 +0800 Subject: [PATCH 25/27] luci-app-ssr-plus: revert lock feature --- package/lean/luci-app-ssr-plus/Makefile | 24 +- .../luasrc/controller/shadowsocksr.lua | 124 +- .../model/cbi/shadowsocksr/advanced.lua | 1 - .../model/cbi/shadowsocksr/client-config.lua | 279 ++--- .../luasrc/model/cbi/shadowsocksr/client.lua | 7 +- .../luasrc/model/cbi/shadowsocksr/control.lua | 68 +- .../luasrc/model/cbi/shadowsocksr/log.lua | 26 +- .../model/cbi/shadowsocksr/server-config.lua | 60 +- .../luasrc/model/cbi/shadowsocksr/server.lua | 77 +- .../luasrc/model/cbi/shadowsocksr/servers.lua | 65 +- .../luasrc/model/cbi/shadowsocksr/status.lua | 124 +- .../luasrc/view/shadowsocksr/certupload.htm | 4 +- .../luasrc/view/shadowsocksr/checkport.htm | 10 + .../luasrc/view/shadowsocksr/server_list.htm | 10 + .../luasrc/view/shadowsocksr/ssrurl.htm | 9 + .../luci-app-ssr-plus/po/zh-cn/ssr-plus.po | 12 - .../root/etc/{ssr => }/china_ssr.txt | 25 +- .../root/etc/{ssr => config}/netflix.list | 0 .../root/etc/{ssr => config}/netflixip.list | 0 .../root/etc/config/shadowsocksr | 18 +- .../root/etc/dnsmasq.ssr/gfw_list.conf | 306 ++++- .../root/etc/init.d/shadowsocksr | 1042 +++++++++-------- .../root/etc/uci-defaults/luci-ssr-plus | 10 +- .../luci-app-ssr-plus/root/usr/bin/ssr-ad | 10 +- .../luci-app-ssr-plus/root/usr/bin/ssr-gfw | 5 +- .../root/usr/bin/ssr-monitor | 41 +- .../luci-app-ssr-plus/root/usr/bin/ssr-rules | 53 +- .../luci-app-ssr-plus/root/usr/bin/ssr-switch | 13 +- .../root/usr/share/shadowsocksr/chinaipset.sh | 6 +- .../usr/share/shadowsocksr/genred2config.sh | 96 +- .../share/shadowsocksr/gentrojanconfig.lua | 1 + .../usr/share/shadowsocksr/genv2config.lua | 1 + .../root/usr/share/shadowsocksr/gfw2ipset.sh | 37 +- .../usr/share/shadowsocksr/ssrplusupdate.sh | 6 +- .../root/usr/share/shadowsocksr/subscribe.lua | 59 +- .../root/usr/share/shadowsocksr/update.lua | 139 ++- 36 files changed, 1548 insertions(+), 1220 deletions(-) rename package/lean/luci-app-ssr-plus/root/etc/{ssr => }/china_ssr.txt (99%) rename package/lean/luci-app-ssr-plus/root/etc/{ssr => config}/netflix.list (100%) rename package/lean/luci-app-ssr-plus/root/etc/{ssr => config}/netflixip.list (100%) diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index 65d86a8a8d..17fa2180af 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=176 -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) @@ -38,10 +38,10 @@ define Package/$(PKG_NAME) SECTION:=luci CATEGORY:=LuCI SUBMENU:=3. Applications - TITLE:=SS/SSR/V2Ray/Trojan/Socks5/Tun LuCI interface + TITLE:=SS/SSR/V2Ray/Trojan LuCI interface PKGARCH:=all DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +pdnsd-alt +wget +lua +libuci-lua \ - +microsocks +dns2socks +shadowsocks-libev-ss-local +shadowsocksr-libev-ssr-local +shadowsocks-libev-ss-redir +simple-obfs +tcpping +resolveip \ + +microsocks +dns2socks +shadowsocks-libev-ss-local +shadowsocksr-libev-ssr-local +shadowsocks-libev-ss-redir +simple-obfs +tcpping \ +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_plugin:v2ray-plugin \ +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \ +PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \ @@ -58,17 +58,23 @@ define Build/Compile endef define Package/$(PKG_NAME)/conffiles +/etc/ssr_ip +/etc/china_ssr.txt /etc/config/shadowsocksr -/etc/ssr/netflix.list -/etc/ssr/netflixip.list +/etc/config/white.list +/etc/config/black.list +/etc/config/netflix.list +/etc/dnsmasq.ssr/ad.conf +/etc/dnsmasq.ssr/gfw_list.conf endef define Package/$(PKG_NAME)/install - $(INSTALL_DIR) $(1)/etc/ssr - $(INSTALL_DATA) ./root/etc/ssr/* $(1)/etc/ssr/ + $(INSTALL_DIR) $(1)/etc + $(INSTALL_DATA) ./root/etc/china_ssr.txt $(1)/etc/china_ssr.txt $(INSTALL_DIR) $(1)/etc/config $(INSTALL_CONF) ./root/etc/config/shadowsocksr $(1)/etc/config/shadowsocksr + $(INSTALL_DATA) ./root/etc/config/*.list $(1)/etc/config/ $(INSTALL_DIR) $(1)/etc/dnsmasq.oversea $(INSTALL_DATA) ./root/etc/dnsmasq.oversea/* $(1)/etc/dnsmasq.oversea/ @@ -104,8 +110,8 @@ endef define Package/$(PKG_NAME)/postrm #!/bin/sh -rm -rf /etc/ssl/private /etc/dnsmasq.ssr /etc/dnsmasq.oversea /etc/ssr /etc/config/shadowsocksr /etc/china_ssr.txt /etc/config/black.list /etc/config/white.list \ -/etc/config/netflix.list /etc/config/netflixip.list +rm -rf /etc/china_ssr.txt /etc/dnsmasq.ssr /etc/dnsmasq.oversea /etc/config/shadowsocksr /etc/config/black.list \ + /etc/config/gfw.list /etc/config/white.list /etc/config/netflix.list /etc/config/netflixip.list 2>/dev/null endef $(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua index dfe74557fc..3176ad4562 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua @@ -1,5 +1,6 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. + module("luci.controller.shadowsocksr", package.seeall) function index() @@ -73,50 +74,105 @@ function refresh_data() local set = luci.http.formvalue("set") local uci = luci.model.uci.cursor() local icount = 0 - local retstring = 0 - local function update(url, file, type, file2) - local Num = 1 - refresh_cmd = "wget-ssl --no-check-certificate -t 3 -T 10 -O- " .. url .. " > /tmp/ssr-update." .. type + if set == "gfw_data" then + refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'gfwlist_url', 'https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt') .. ' > /tmp/gfw.b64' sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") if sret == 0 then - if type == "gfw_data" then - luci.sys.call("/usr/bin/ssr-gfw " .. type) - Num = 2 - end - if type == "ad_data" then - luci.sys.call("/usr/bin/ssr-ad " .. type) - end - local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/ssr-update." .. type .. "' ] && md5sum /tmp/ssr-update." .. type .. " | awk '{print $1}')") - local old_md5 = luci.sys.exec("echo -n $([ -f '" .. file .. "' ] && md5sum " .. file .. " | awk '{print $1}')") - if new_md5 == old_md5 then - retstring = "0" - else - icount = luci.sys.exec("cat /tmp/ssr-update." .. type .. " | wc -l") - luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file) - if file2 then luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file2) end - retstring = tostring(tonumber(icount)/Num) - if type == "gfw_data" or type == "ad_data" then - luci.sys.exec("/usr/share/shadowsocksr/gfw2ipset.sh gfw_data") + luci.sys.call("/usr/bin/ssr-gfw") + icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l") + if tonumber(icount) > 1000 then + if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then + oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l") else - luci.sys.exec("/etc/init.d/shadowsocksr restart &") + oldcount = "0" end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf") + luci.sys.exec("cp -f /tmp/gfwnew.txt /tmp/dnsmasq.ssr/gfw_list.conf") + luci.sys.call("/etc/init.d/dnsmasq restart") + retstring = tostring(tonumber(icount)/2) + else + retstring = "0" + end + else + retstring = "-1" + end + luci.sys.exec("rm -f /tmp/gfwnew.txt") + else + retstring = "-1" + end + end + if set == "ip_data" then + refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'chnroute_url', 'https://ispip.clang.cn/all_cn.txt') .. " > /tmp/china_ssr.txt" + sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") + icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") + if sret == 0 and tonumber(icount) > 1000 then + if nixio.fs.access("/etc/china_ssr.txt") then + oldcount = luci.sys.exec("cat /etc/china_ssr.txt | wc -l") + else + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt") + luci.sys.exec("/etc/init.d/shadowsocksr restart &") + retstring = tostring(tonumber(icount)) + else + retstring = "0" end else retstring = "-1" end - luci.sys.exec("rm -f /tmp/ssr-update." .. type) - end - if set == "gfw_data" then - update(uci:get_first("shadowsocksr", "global", "gfwlist_url", "https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt"), "/etc/dnsmasq.ssr/gfw_list.conf", set, "/tmp/dnsmasq.ssr/gfw_list.conf") - end - if set == "ip_data" then - update(uci:get_first("shadowsocksr", "global", "chnroute_url","https://ispip.clang.cn/all_cn.txt"), "/etc/ssr/china_ssr.txt", set) - end - if set == "ad_data" then - update(uci:get_first("shadowsocksr", "global", "adblock_url","https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt"), "/etc/dnsmasq.ssr/ad.conf", set, "/tmp/dnsmasq.ssr/ad.conf") + luci.sys.exec("rm -f /tmp/china_ssr.txt") end if set == "nfip_data" then - update(uci:get_first("shadowsocksr", "global", "nfip_url","https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt"), "/etc/ssr/netflixip.list", set) + refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'nfip_url','https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt') .." > /tmp/netflixip.list" + sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") + icount = luci.sys.exec("cat /tmp/netflixip.list | wc -l") + if sret == 0 and tonumber(icount) > 5 then + if nixio.fs.access("/etc/config/netflixip.list") then + oldcount = luci.sys.exec("cat /etc/config/netflixip.list | wc -l") + else + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/netflixip.list /etc/config/netflixip.list") + luci.sys.exec("/etc/init.d/shadowsocksr restart &") + retstring = tostring(tonumber(icount)) + else + retstring = "0" + end + else + retstring = "-1" + end + luci.sys.exec("rm -f /tmp/netflixip.list") + end + if set == "ad_data" then + refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'adblock_url','https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt') .." > /tmp/adnew.conf" + sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") + if sret == 0 then + luci.sys.call("/usr/bin/ssr-ad") + icount = luci.sys.exec("cat /tmp/ad.conf | wc -l") + if tonumber(icount) > 100 then + if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then + oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l") + else + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf") + luci.sys.exec("cp -f /tmp/ad.conf /tmp/dnsmasq.ssr/ad.conf") + luci.sys.call("/etc/init.d/dnsmasq restart") + retstring = tostring(tonumber(icount)) + else + retstring = "0" + end + else + retstring = "-1" + end + luci.sys.exec("rm -f /tmp/ad.conf") + else + retstring = "-1" + end end luci.http.prepare_content("application/json") luci.http.write_json({ret = retstring,retcount = icount}) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua index ff05ae3db2..d7908e5e6e 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua @@ -1,4 +1,3 @@ -require "luci.model.uci" local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() local server_table = {} diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 580fbc6783..f42822f580 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -1,105 +1,108 @@ -- Copyright (C) 2017 yushi studio github.com/ywb94 -- Licensed to the public under the GNU General Public License v3. -require "luci.model.uci" -require "nixio.fs" -require "luci.sys" -require "luci.http" + local m, s, o,kcp_enable local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() +local fs = require "nixio.fs" +local sys = require "luci.sys" local sid = arg[1] local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid") +local http = require "luci.http" local function isKcptun(file) - if not nixio.fs.access(file, "rwx", "rx", "rx") then - nixio.fs.chmod(file, 755) + if not fs.access(file, "rwx", "rx", "rx") then + fs.chmod(file, 755) end - local str = luci.sys.exec(file .. " -v | awk '{printf $1}'") + + local str = sys.exec(file .. " -v | awk '{printf $1}'") return (str:lower() == "kcptun") end + local server_table = {} local encrypt_methods = { -"none", -"table", -"rc4", -"rc4-md5-6", -"rc4-md5", -"aes-128-cfb", -"aes-192-cfb", -"aes-256-cfb", -"aes-128-ctr", -"aes-192-ctr", -"aes-256-ctr", -"bf-cfb", -"camellia-128-cfb", -"camellia-192-cfb", -"camellia-256-cfb", -"cast5-cfb", -"des-cfb", -"idea-cfb", -"rc2-cfb", -"seed-cfb", -"salsa20", -"chacha20", -"chacha20-ietf", + "none", + "table", + "rc4", + "rc4-md5-6", + "rc4-md5", + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "bf-cfb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "cast5-cfb", + "des-cfb", + "idea-cfb", + "rc2-cfb", + "seed-cfb", + "salsa20", + "chacha20", + "chacha20-ietf", } local encrypt_methods_ss = { --- aead -"aes-128-gcm", -"aes-192-gcm", -"aes-256-gcm", -"chacha20-ietf-poly1305", -"xchacha20-ietf-poly1305", --- stream -"table", -"rc4", -"rc4-md5", -"aes-128-cfb", -"aes-192-cfb", -"aes-256-cfb", -"aes-128-ctr", -"aes-192-ctr", -"aes-256-ctr", -"bf-cfb", -"camellia-128-cfb", -"camellia-192-cfb", -"camellia-256-cfb", -"salsa20", -"chacha20", -"chacha20-ietf", + -- aead + "aes-128-gcm", + "aes-192-gcm", + "aes-256-gcm", + "chacha20-ietf-poly1305", + "xchacha20-ietf-poly1305", + -- stream + "table", + "rc4", + "rc4-md5", + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "bf-cfb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "salsa20", + "chacha20", + "chacha20-ietf", } local protocol = { -"origin", -"verify_deflate", -"auth_sha1_v4", -"auth_aes128_sha1", -"auth_aes128_md5", -"auth_chain_a", -"auth_chain_b", -"auth_chain_c", -"auth_chain_d", -"auth_chain_e", -"auth_chain_f", + "origin", + "verify_deflate", + "auth_sha1_v4", + "auth_aes128_sha1", + "auth_aes128_md5", + "auth_chain_a", + "auth_chain_b", + "auth_chain_c", + "auth_chain_d", + "auth_chain_e", + "auth_chain_f", } obfs = { -"plain", -"http_simple", -"http_post", -"random_head", -"tls1.2_ticket_auth", + "plain", + "http_simple", + "http_post", + "random_head", + "tls1.2_ticket_auth", } local securitys = { -"auto", -"none", -"aes-128-gcm", -"chacha20-poly1305" + "auto", + "none", + "aes-128-gcm", + "chacha20-poly1305" } + m = Map(shadowsocksr, translate("Edit ShadowSocksR Server")) m.redirect = luci.dispatcher.build_url("admin/services/shadowsocksr/servers") if m.uci:get(shadowsocksr, sid) ~= "servers" then @@ -110,35 +113,35 @@ end -- [[ Servers Setting ]]-- s = m:section(NamedSection, sid, "servers") s.anonymous = true -s.addremove = false +s.addremove = false o = s:option(DummyValue,"ssr_url","SS/SSR/V2RAY/TROJAN URL") -o.rawhtml = true +o.rawhtml = true o.template = "shadowsocksr/ssrurl" o.value =sid o = s:option(ListValue, "type", translate("Server Node Type")) o:value("ssr", translate("ShadowsocksR")) if nixio.fs.access("/usr/bin/ss-redir") then - o:value("ss", translate("Shadowsocks New Version")) +o:value("ss", translate("Shadowsocks New Version")) end if nixio.fs.access("/usr/bin/v2ray/v2ray") or nixio.fs.access("/usr/bin/v2ray") then - o:value("v2ray", translate("V2Ray")) +o:value("v2ray", translate("V2Ray")) end if nixio.fs.access("/usr/sbin/trojan") then - o:value("trojan", translate("Trojan")) +o:value("trojan", translate("Trojan")) end if nixio.fs.access("/usr/sbin/redsocks2") then - o:value("socks5", translate("Socks5")) - o:value("tun", translate("Network Tunnel")) +o:value("socks5", translate("Socks5")) +o:value("tun", translate("Network Tunnel")) end o.description = translate("Using incorrect encryption mothod may causes service fail to start") o = s:option(Value, "alias", translate("Alias(optional)")) o = s:option(ListValue, "iface", translate("Network interface to use")) -for _, e in ipairs(luci.sys.net.devices()) do - if e ~= "lo" then o:value(e) end +for _, e in ipairs(sys.net.devices()) do + if e ~= "lo" then o:value(e) end end o:depends("type", "tun") o.description = translate("Redirect traffic to this network interface") @@ -243,6 +246,7 @@ o.rmempty = true o:depends("type", "v2ray") -- [[ TCP部分 ]]-- + -- TCP伪装 o = s:option(ListValue, "tcp_guise", translate("Camouflage Type")) o:depends("transport", "tcp") @@ -261,6 +265,7 @@ o:depends("tcp_guise", "http") o.rmempty = true -- [[ WS部分 ]]-- + -- WS域名 o = s:option(Value, "ws_host", translate("WebSocket Host")) o:depends("transport", "ws") @@ -272,6 +277,7 @@ o:depends("transport", "ws") o.rmempty = true -- [[ H2部分 ]]-- + -- H2域名 o = s:option(Value, "h2_host", translate("HTTP/2 Host")) o:depends("transport", "h2") @@ -283,6 +289,7 @@ o:depends("transport", "h2") o.rmempty = true -- [[ QUIC部分 ]]-- + o = s:option(ListValue, "quic_security", translate("QUIC Security")) o:depends("transport", "quic") o.rmempty = true @@ -305,6 +312,7 @@ o:value("dtls", "DTLS 1.2") o:value("wireguard", "WireGuard") -- [[ mKCP部分 ]]-- + o = s:option(ListValue, "kcp_guise", translate("Camouflage Type")) o:depends("transport", "kcp") o:value("none", translate("None")) @@ -361,7 +369,6 @@ o.rmempty = true o:depends("type", "v2ray") o:depends("type", "trojan") o.default = "1" -o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.") -- [[ TLS ]]-- o = s:option(Flag, "tls", translate("TLS")) @@ -402,31 +409,31 @@ o:depends("certificate", 1) cert_dir = "/etc/ssl/private/" local path -luci.http.setfilehandler( -function(meta, chunk, eof) - if not fd then - if (not meta) or (not meta.name) or (not meta.file) then return end - fd = nixio.open(cert_dir .. meta.file, "w") - if not fd then - path = translate("Create upload file error.") - return - end - end - if chunk and fd then - fd:write(chunk) - end - if eof and fd then - fd:close() - fd = nil - path = '/etc/ssl/private/' .. meta.file .. '' - end -end -) +http.setfilehandler( + function(meta, chunk, eof) + if not fd then + if (not meta) or (not meta.name) or (not meta.file) then return end + fd = nixio.open(cert_dir .. meta.file, "w") + if not fd then + path = translate("Create upload file error.") + return + end + end + if chunk and fd then + fd:write(chunk) + end + if eof and fd then + fd:close() + fd = nil + path = '/etc/ssl/private/' .. meta.file .. '' + end + end + ) if luci.http.formvalue("upload") then - local f = luci.http.formvalue("ulfile") - if #f <= 0 then - path = translate("No specify upload file.") - end + local f = luci.http.formvalue("ulfile") + if #f <= 0 then + path = translate("No specify upload file.") + end end o = s:option(Value, "certpath", translate("Current Certificate Path")) @@ -452,36 +459,42 @@ o.default = 1234 o.rmempty = false if nixio.fs.access("/usr/bin/kcptun-client") then - kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/kcptun-client")) - kcp_enable.rmempty = true - kcp_enable.default = "0" - kcp_enable:depends("type", "ssr") - kcp_enable:depends("type", "ss") - o = s:option(Value, "kcp_port", translate("KcpTun Port")) - o.datatype = "port" - o.default = 4000 - function o.validate(self, value, section) + +kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"), translate("bin:/usr/bin/kcptun-client")) +kcp_enable.rmempty = true +kcp_enable.default = "0" +kcp_enable:depends("type", "ssr") +kcp_enable:depends("type", "ss") + +o = s:option(Value, "kcp_port", translate("KcpTun Port")) +o.datatype = "port" +o.default = 4000 +function o.validate(self, value, section) local kcp_file="/usr/bin/kcptun-client" local enable = kcp_enable:formvalue(section) or kcp_enable.disabled if enable == kcp_enable.enabled then - if not nixio.fs.access(kcp_file) then - return nil, translate("Haven't a Kcptun executable file") - elseif not isKcptun(kcp_file) then - return nil, translate("Not a Kcptun executable file") - end - end - return value + if not fs.access(kcp_file) then + return nil, translate("Haven't a Kcptun executable file") + elseif not isKcptun(kcp_file) then + return nil, translate("Not a Kcptun executable file") end - o:depends("type", "ssr") - o:depends("type", "ss") - o = s:option(Value, "kcp_password", translate("KcpTun Password")) - o.password = true - o:depends("type", "ssr") - o:depends("type", "ss") - o = s:option(Value, "kcp_param", translate("KcpTun Param")) - o.default = "--nocomp" - o:depends("type", "ssr") - o:depends("type", "ss") + end + + return value +end +o:depends("type", "ssr") +o:depends("type", "ss") + +o = s:option(Value, "kcp_password", translate("KcpTun Password")) +o.password = true +o:depends("type", "ssr") +o:depends("type", "ss") + +o = s:option(Value, "kcp_param", translate("KcpTun Param")) +o.default = "--nocomp" +o:depends("type", "ssr") +o:depends("type", "ss") + end return m diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua index 7e09f4d366..c73e5e21dd 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua @@ -1,13 +1,16 @@ -- Copyright (C) 2017 yushi studio github.com/ywb94 -- Copyright (C) 2018 lean github.com/coolsnowwolf -- Licensed to the public under the GNU General Public License v3. -require "luci.model.uci" + local m, s, sec, o, kcp_enable local shadowsocksr = "shadowsocksr" local uci = luci.model.uci.cursor() +local sys = require "luci.sys" + m = Map(shadowsocksr, translate("ShadowSocksR Plus+ Settings")) -m:section(SimpleSection).template = "shadowsocksr/status" + +m:section(SimpleSection).template = "shadowsocksr/status" local server_table = {} uci:foreach(shadowsocksr, "servers", function(s) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua index 39da0e123e..7a5e33b63c 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua @@ -1,6 +1,5 @@ -require "luci.ip" -require "nixio.fs" local m, s, o +local NXFS = require "nixio.fs" m = Map("shadowsocksr", translate("IP black-and-white list")) @@ -28,9 +27,9 @@ o.rmempty = false o = s:taboption("lan_ac", DynamicList, "lan_ac_ips", translate("LAN Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) o:depends("lan_ac_mode", "w") o:depends("lan_ac_mode", "b") @@ -38,25 +37,25 @@ o:depends("lan_ac_mode", "b") o = s:taboption("lan_ac", DynamicList, "lan_bp_ips", translate("LAN Bypassed Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) o = s:taboption("lan_ac", DynamicList, "lan_fp_ips", translate("LAN Force Proxy Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) o = s:taboption("lan_ac", DynamicList, "lan_gm_ips", translate("Game Mode Host List")) o.datatype = "ipaddr" luci.ip.neighbors({ family = 4 }, function(entry) - if entry.reachable then - o:value(entry.dest:string()) - end + if entry.reachable then + o:value(entry.dest:string()) + end end) -- Part of Self @@ -67,72 +66,73 @@ end) -- o:value("2", translatef("Forwarded Proxy")) -- o.rmempty = false -s:tab("esc", translate("Bypass Domain List")) +s:tab("esc", translate("Bypass Domain List")) -local escconf = "/etc/ssr/white.list" +local escconf = "/etc/config/white.list" o = s:taboption("esc", TextValue, "escconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return nixio.fs.readfile(escconf) or "" + return NXFS.readfile(escconf) or "" end o.write = function(self, section, value) - nixio.fs.writefile(escconf, value:gsub("\r\n", "\n")) + NXFS.writefile(escconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - nixio.fs.writefile(escconf, "") + NXFS.writefile(escconf, "") end -s:tab("block", translate("Black Domain List")) -local blockconf = "/etc/ssr/black.list" +s:tab("block", translate("Black Domain List")) + +local blockconf = "/etc/config/black.list" o = s:taboption("block", TextValue, "blockconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return nixio.fs.readfile(blockconf) or " " + return NXFS.readfile(blockconf) or " " end o.write = function(self, section, value) - nixio.fs.writefile(blockconf, value:gsub("\r\n", "\n")) + NXFS.writefile(blockconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - nixio.fs.writefile(blockconf, "") + NXFS.writefile(blockconf, "") end -s:tab("netflix", translate("Netflix Domain List")) +s:tab("netflix", translate("Netflix Domain List")) -local netflixconf = "/etc/ssr/netflix.list" +local netflixconf = "/etc/config/netflix.list" o = s:taboption("netflix", TextValue, "netflixconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return nixio.fs.readfile(netflixconf) or " " + return NXFS.readfile(netflixconf) or " " end o.write = function(self, section, value) - nixio.fs.writefile(netflixconf, value:gsub("\r\n", "\n")) + NXFS.writefile(netflixconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - nixio.fs.writefile(netflixconf, "") + NXFS.writefile(netflixconf, "") end -s:tab("netflixip", translate("Netflix IP List")) +s:tab("netflixip", translate("Netflix IP List")) -local netflixipconf = "/etc/ssr/netflixip.list" +local netflixipconf = "/etc/config/netflixip.list" o = s:taboption("netflixip", TextValue, "netflixipconf") o.rows = 13 o.wrap = "off" o.rmempty = true o.cfgvalue = function(self, section) - return nixio.fs.readfile(netflixipconf) or " " + return NXFS.readfile(netflixipconf) or " " end o.write = function(self, section, value) - nixio.fs.writefile(netflixipconf, value:gsub("\r\n", "\n")) + NXFS.writefile(netflixipconf, value:gsub("\r\n", "\n")) end o.remove = function(self, section, value) - nixio.fs.writefile(netflixipconf, "") + NXFS.writefile(netflixipconf, "") end return m diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua index a71d0003bf..6c5938ed7f 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua @@ -1,20 +1,20 @@ -require "luci.util" -require "nixio.fs" +local fs = require "nixio.fs" + f = SimpleForm("logview") -f.reset = false -f.submit = false + t = f:field(TextValue, "conf") t.rmempty = true t.rows = 20 function t.cfgvalue() - if nixio.fs.access("/tmp/ssrplus.log") then - local logs = luci.util.execi("cat /tmp/ssrplus.log") - local s = "" - for line in logs do - s = line .. "\n" .. s - end - return s - end + if fs.access("/tmp/ssrplus.log") then + local logs = luci.util.execi("cat /tmp/ssrplus.log") + local s = "" + for line in logs do + s = line .. "\n" .. s + end + return s + end end t.readonly="readonly" -return f + +return f \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua index 2f7b21868a..c7d9021563 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua @@ -1,44 +1,43 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. -require "luci.http" -require "luci.dispatcher" + local m, s, o local shadowsocksr = "shadowsocksr" local sid = arg[1] local encrypt_methods = { -"rc4-md5", -"rc4-md5-6", -"rc4", -"table", -"aes-128-cfb", -"aes-192-cfb", -"aes-256-cfb", -"aes-128-ctr", -"aes-192-ctr", -"aes-256-ctr", -"bf-cfb", -"camellia-128-cfb", -"camellia-192-cfb", -"camellia-256-cfb", -"cast5-cfb", -"des-cfb", -"idea-cfb", -"rc2-cfb", -"seed-cfb", -"salsa20", -"chacha20", -"chacha20-ietf", + "rc4-md5", + "rc4-md5-6", + "rc4", + "table", + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "bf-cfb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "cast5-cfb", + "des-cfb", + "idea-cfb", + "rc2-cfb", + "seed-cfb", + "salsa20", + "chacha20", + "chacha20-ietf", } local protocol = { -"origin", + "origin", } obfs = { -"plain", -"http_simple", -"http_post", + "plain", + "http_simple", + "http_post", } m = Map(shadowsocksr, translate("Edit ShadowSocksR Server")) @@ -49,10 +48,13 @@ if m.uci:get(shadowsocksr, sid) ~= "server_config" then return end + + + -- [[ Server Setting ]]-- s = m:section(NamedSection, sid, "server_config") s.anonymous = true -s.addremove = false +s.addremove = false o = s:option(Flag, "enable", translate("Enable")) o.default = 1 diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua index 42f01055f2..ec273e0f3b 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua @@ -1,55 +1,56 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. -require "luci.http" -require "luci.dispatcher" + local m, sec, o local shadowsocksr = "shadowsocksr" +local uci = luci.model.uci.cursor() + + +m = Map(shadowsocksr) local encrypt_methods = { -"table", -"rc4", -"rc4-md5", -"rc4-md5-6", -"aes-128-cfb", -"aes-192-cfb", -"aes-256-cfb", -"aes-128-ctr", -"aes-192-ctr", -"aes-256-ctr", -"bf-cfb", -"camellia-128-cfb", -"camellia-192-cfb", -"camellia-256-cfb", -"cast5-cfb", -"des-cfb", -"idea-cfb", -"rc2-cfb", -"seed-cfb", -"salsa20", -"chacha20", -"chacha20-ietf", + "table", + "rc4", + "rc4-md5", + "rc4-md5-6", + "aes-128-cfb", + "aes-192-cfb", + "aes-256-cfb", + "aes-128-ctr", + "aes-192-ctr", + "aes-256-ctr", + "bf-cfb", + "camellia-128-cfb", + "camellia-192-cfb", + "camellia-256-cfb", + "cast5-cfb", + "des-cfb", + "idea-cfb", + "rc2-cfb", + "seed-cfb", + "salsa20", + "chacha20", + "chacha20-ietf", } local protocol = { -"origin", -"verify_deflate", -"auth_sha1_v4", -"auth_aes128_sha1", -"auth_aes128_md5", -"auth_chain_a", + "origin", + "verify_deflate", + "auth_sha1_v4", + "auth_aes128_sha1", + "auth_aes128_md5", + "auth_chain_a", } obfs = { -"plain", -"http_simple", -"http_post", -"random_head", -"tls1.2_ticket_auth", -"tls1.2_ticket_fastauth", + "plain", + "http_simple", + "http_post", + "random_head", + "tls1.2_ticket_auth", + "tls1.2_ticket_fastauth", } -m = Map(shadowsocksr) - -- [[ Global Setting ]]-- sec = m:section(TypedSection, "server_global", translate("Global Setting")) sec.anonymous = true diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index e95c85cc1a..d1ca504671 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -1,19 +1,23 @@ -- Licensed to the public under the GNU General Public License v3. -require "luci.http" -require "luci.dispatcher" -require "luci.model.uci" + local m, s, o local shadowsocksr = "shadowsocksr" + local uci = luci.model.uci.cursor() local server_count = 0 - uci:foreach("shadowsocksr", "servers", function(s) - server_count = server_count + 1 + server_count = server_count + 1 end) -m = Map(shadowsocksr, translate("Servers subscription and manage")) +local fs = require "nixio.fs" +local sys = require "luci.sys" + +local ucic = luci.model.uci.cursor() + +m = Map(shadowsocksr, translate("Servers subscription and manage")) -- Server Subscribe + s = m:section(TypedSection, "server_subscribe") s.anonymous = true @@ -21,9 +25,10 @@ o = s:option(Flag, "auto_update", translate("Auto Update")) o.rmempty = false o.description = translate("Auto Update Server subscription, GFW list and CHN route") + o = s:option(ListValue, "auto_update_time", translate("Update time (every day)")) for t = 0,23 do - o:value(t, t..":00") +o:value(t, t..":00") end o.default=2 o.rmempty = false @@ -39,7 +44,7 @@ o = s:option(Button,"update_Sub",translate("Update Subscribe List")) o.inputstyle = "reload" o.description = translate("Update subscribe url list first") o.write = function() - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) end o = s:option(Flag, "switch", translate("Subscribe Default Auto-Switch")) @@ -51,26 +56,27 @@ o = s:option(Flag, "proxy", translate("Through proxy update")) o.rmempty = false o.description = translate("Through proxy update list, Not Recommended ") + o = s:option(Button,"subscribe", translate("Update All Subscribe Severs")) -o.rawhtml = true +o.rawhtml = true o.template = "shadowsocksr/subscribe" o = s:option(Button,"delete",translate("Delete All Subscribe Severs")) o.inputstyle = "reset" -o.description = string.format(translate("Server Count") .. ": %d", server_count) +o.description = string.format(translate("Server Count") .. ": %d", server_count) o.write = function() - uci:delete_all("shadowsocksr", "servers", function(s) - if s.hashkey or s.isSubscribe then - return true - else - return false - end - end) - uci:save("shadowsocksr") - uci:commit("shadowsocksr") - luci.sys.exec("/etc/init.d/shadowsocksr restart") - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) - return +uci:delete_all("shadowsocksr", "servers", function(s) + if s.hashkey or s.isSubscribe then + return true + else + return false + end +end) +uci:save("shadowsocksr") +uci:commit("shadowsocksr") +luci.sys.exec("/etc/init.d/shadowsocksr restart") +luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) +return end -- [[ Servers Manage ]]-- @@ -79,12 +85,12 @@ s.anonymous = true s.addremove = true s.template = "cbi/tblsection" s.sortable = true -s.extedit = luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers", "%s") +s.extedit = luci.dispatcher.build_url("admin/services/shadowsocksr/servers/%s") function s.create(...) local sid = TypedSection.create(...) if sid then luci.http.redirect(s.extedit % sid) - return + return end end @@ -111,14 +117,15 @@ o = s:option(DummyValue, "server", translate("Ping Latency")) o.template="shadowsocksr/ping" o.width="10%" + node = s:option(Button,"apply_node",translate("Apply")) node.inputstyle = "apply" node.write = function(self, section) - uci:set("shadowsocksr", '@global[0]', 'global_server', section) - uci:save("shadowsocksr") - uci:commit("shadowsocksr") - luci.sys.exec("/etc/init.d/shadowsocksr restart") - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "client")) + ucic:set("shadowsocksr", '@global[0]', 'global_server', section) + ucic:save("shadowsocksr") + ucic:commit("shadowsocksr") + luci.sys.exec("/etc/init.d/shadowsocksr restart") + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "client")) end o = s:option(Flag, "switch_enable", translate("Auto Switch")) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua index c8225f3ebf..0ae5219eea 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua @@ -1,8 +1,6 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. -require "nixio.fs" -require "luci.sys" -require "luci.model.uci" + local m, s, o local redir_run=0 local reudp_run=0 @@ -22,69 +20,71 @@ font_off = [[]] bold_on = [[]] bold_off = [[]] +local fs = require "nixio.fs" +local sys = require "luci.sys" local kcptun_version=translate("Unknown") local kcp_file="/usr/bin/kcptun-client" -if not nixio.fs.access(kcp_file) then - kcptun_version=translate("Not exist") +if not fs.access(kcp_file) then +kcptun_version=translate("Not exist") else - if not nixio.fs.access(kcp_file, "rwx", "rx", "rx") then - nixio.fs.chmod(kcp_file, 755) - end - kcptun_version=luci.sys.exec(kcp_file .. " -v | awk '{printf $3}'") - if not kcptun_version or kcptun_version == "" then - kcptun_version = translate("Unknown") - end - +if not fs.access(kcp_file, "rwx", "rx", "rx") then +fs.chmod(kcp_file, 755) +end +kcptun_version=sys.exec(kcp_file .. " -v | awk '{printf $3}'") +if not kcptun_version or kcptun_version == "" then +kcptun_version = translate("Unknown") +end + end if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then - gfw_count = tonumber(luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l"))/2 +gfw_count = tonumber(sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l"))/2 end if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then - ad_count = tonumber(luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")) +ad_count = tonumber(sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l")) end -if nixio.fs.access("/etc/ssr/china_ssr.txt") then - ip_count = tonumber(luci.sys.exec("cat /etc/ssr/china_ssr.txt | wc -l")) +if nixio.fs.access("/etc/china_ssr.txt") then +ip_count = tonumber(sys.exec("cat /etc/china_ssr.txt | wc -l")) end -if nixio.fs.access("/etc/ssr/netflixip.list") then - nfip_count = tonumber(luci.sys.exec("cat /etc/ssr/netflixip.list | wc -l")) +if nixio.fs.access("/etc/config/netflixip.list") then +nfip_count = tonumber(sys.exec("cat /etc/config/netflixip.list | wc -l")) end -local icount=luci.sys.exec("busybox ps -w | grep ssr-reudp |grep -v grep| wc -l") +local icount=sys.exec("busybox ps -w | grep ssr-reudp |grep -v grep| wc -l") if tonumber(icount)>0 then - reudp_run=1 +reudp_run=1 else - icount=luci.sys.exec("busybox ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l") - if tonumber(icount)>0 then - reudp_run=1 - end +icount=sys.exec("busybox ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l") +if tonumber(icount)>0 then +reudp_run=1 +end end if luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null") == 0 then - redir_run=1 +redir_run=1 end if luci.sys.call("busybox ps -w | grep ssr-local | grep -v ssr-socksdns |grep -v grep >/dev/null") == 0 then - sock5_run=1 +sock5_run=1 end if luci.sys.call("pidof kcptun-client >/dev/null") == 0 then - kcptun_run=1 +kcptun_run=1 end if luci.sys.call("busybox ps -w | grep ssr-server | grep -v grep >/dev/null") == 0 then - server_run=1 +server_run=1 end --- if luci.sys.call("busybox ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then --- tunnel_run=1 --- end +if luci.sys.call("busybox ps -w | grep ssr-tunnel |grep -v grep >/dev/null") == 0 then +tunnel_run=1 +end if luci.sys.call("pidof pdnsd >/dev/null") == 0 or (luci.sys.call("busybox ps -w | grep ssr-dns |grep -v grep >/dev/null") == 0 and luci.sys.call("pidof dns2socks >/dev/null") == 0)then - pdnsd_run=1 +pdnsd_run=1 end m = SimpleForm("Version") @@ -94,56 +94,56 @@ m.submit = false s=m:field(DummyValue,"redir_run",translate("Global Client")) s.rawhtml = true if redir_run == 1 then - s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else - s.value = translate("Not Running") +s.value = translate("Not Running") end s=m:field(DummyValue,"reudp_run",translate("Game Mode UDP Relay")) s.rawhtml = true if reudp_run == 1 then - s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else - s.value = translate("Not Running") +s.value = translate("Not Running") end if uci:get_first(shadowsocksr, 'global', 'pdnsd_enable', '0') ~= '0' then - s=m:field(DummyValue,"pdnsd_run",translate("DNS Anti-pollution")) - s.rawhtml = true - if pdnsd_run == 1 then - s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off - else - s.value = translate("Not Running") - end +s=m:field(DummyValue,"pdnsd_run",translate("DNS Anti-pollution")) +s.rawhtml = true +if pdnsd_run == 1 then +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +else +s.value = translate("Not Running") +end end s=m:field(DummyValue,"sock5_run",translate("Global SOCKS5 Proxy Server")) s.rawhtml = true if sock5_run == 1 then - s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else - s.value = translate("Not Running") +s.value = translate("Not Running") end s=m:field(DummyValue,"server_run",translate("Local Servers")) s.rawhtml = true if server_run == 1 then - s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off else - s.value = translate("Not Running") +s.value = translate("Not Running") end if nixio.fs.access("/usr/bin/kcptun-client") then - s=m:field(DummyValue,"kcp_version",translate("KcpTun Version")) - s.rawhtml = true - s.value =kcptun_version - s=m:field(DummyValue,"kcptun_run",translate("KcpTun")) - s.rawhtml = true - if kcptun_run == 1 then - s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off - else - s.value = translate("Not Running") - end +s=m:field(DummyValue,"kcp_version",translate("KcpTun Version")) +s.rawhtml = true +s.value =kcptun_version +s=m:field(DummyValue,"kcptun_run",translate("KcpTun")) +s.rawhtml = true +if kcptun_run == 1 then +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +else +s.value = translate("Not Running") +end end s=m:field(DummyValue,"google",translate("Google Connectivity")) @@ -170,10 +170,10 @@ s.template = "shadowsocksr/refresh" s.value = nfip_count .. " " .. translate("Records") if uci:get_first(shadowsocksr, 'global', 'adblock', '0') == '1' then - s=m:field(DummyValue,"ad_data",translate("Advertising Data")) - s.rawhtml = true - s.template = "shadowsocksr/refresh" - s.value = ad_count .. " " .. translate("Records") +s=m:field(DummyValue,"ad_data",translate("Advertising Data")) +s.rawhtml = true +s.template = "shadowsocksr/refresh" +s.value = ad_count .. " " .. translate("Records") end s=m:field(DummyValue,"check_port",translate("Check Server Port")) diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm index 55ed14ef80..f34f04d7b8 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm @@ -1,4 +1,4 @@ <%+cbi/valueheader%> - - + + <%+cbi/valuefooter%> diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm index e37b446e90..ed91a2f22c 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/checkport.htm @@ -1,5 +1,7 @@ <%+cbi/valueheader%> + <%=self.value%> + + + <%+cbi/valuefooter%> \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm index f5b3c079a8..9c5ba66ac5 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm @@ -81,39 +81,47 @@ local dsp = require "luci.dispatcher" return false; } + // set tr draggable function enableDragForTable(table_selecter, store) { var trs = document.querySelectorAll(table_selecter + " tr"); if (!trs || trs.length.length < 3) { return; } + function ondragstart(ev) { ev.dataTransfer.setData("Text", ev.target.id); } + function ondrop(ev) { var from = ev.dataTransfer.getData("Text"); cbi_row_drop(from, this.id, store); } + function ondragover(ev) { ev.preventDefault(); ev.dataTransfer.dropEffect = "move"; } + function moveToTop(id) { var top = document.querySelectorAll(table_selecter + " tr")[2]; cbi_row_drop(id, top.id, store); } + function moveToBottom(id) { console.log('moveToBottom:', id); var trList = document.querySelectorAll(table_selecter + " tr"); var bottom = trList[trList.length - 1]; cbi_row_drop(id, bottom.id, store, true); } + for (let index = 2; index < trs.length; index++) { const el = trs[index]; el.setAttribute("draggable", true); el.ondragstart = ondragstart; el.ondrop = ondrop; el.ondragover = ondragover; + // reset the behaviors of the btns var upBtns = el.querySelectorAll(".cbi-button.cbi-button-up"); if (upBtns && upBtns.length > 0) { @@ -123,6 +131,7 @@ local dsp = require "luci.dispatcher" }; }); } + var downBtns = el.querySelectorAll(".cbi-button.cbi-button-down"); if (downBtns && downBtns.length > 0) { downBtns.forEach(function (_el) { @@ -133,6 +142,7 @@ local dsp = require "luci.dispatcher" } } } + // enable enableDragForTable( "#cbi-shadowsocksr-servers table", diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index aabc8b59fb..e734af05a8 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -80,6 +80,7 @@ } return false; } + function import_ssr_url(btn, urlname, sid) { var s = document.getElementById(urlname + '-status'); if (!s) @@ -97,6 +98,7 @@ s.innerHTML = "无效格式"; return false; } + var event = document.createEvent("HTMLEvents"); event.initEvent("change", true, true); if (ssu[0] == "ssr") { @@ -135,6 +137,7 @@ s.innerHTML = "导入ShadowsocksR配置信息成功"; return false; } else if (ssu[0] == "ss") { + var url0, param = ""; var sipIndex = ssu[1].indexOf("@"); var ploc = ssu[1].indexOf("#"); @@ -144,6 +147,7 @@ } else { url0 = ssu[1]; } + if (sipIndex != -1) { // SIP002 var userInfo = b64decsafe(url0.substr(0, sipIndex)); @@ -159,6 +163,7 @@ plugin = pluginNameInfo.substr(pluginNameInfo.indexOf("=") + 1) pluginOpts = pluginInfo.substr(pluginIndex + 1); } + var userInfoSplitIndex = userInfo.indexOf(":"); if (userInfoSplitIndex != -1) { method = userInfo.substr(0, userInfoSplitIndex); @@ -172,6 +177,7 @@ document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method || ""; document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin || ""; document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || ""; + if (param != undefined) { document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } @@ -206,6 +212,7 @@ url0 = ssu[1] } var sstr = url0; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan"; document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event); var team = sstr.split('@'); @@ -222,6 +229,7 @@ queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || ''); } } + document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = serverPart[0]; document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port; document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password; @@ -229,6 +237,7 @@ document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event); document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = queryParam.peer || ''; document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = queryParam.allowInsecure === '1'; + if (param != undefined) { document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURI(param); } diff --git a/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po b/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po index cf0a7aa503..6052702dab 100644 --- a/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po +++ b/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po @@ -61,21 +61,9 @@ msgstr "密码" msgid "Encrypt Method" msgstr "加密方式" -msgid "Transport" -msgstr "传输协议" - msgid "Protocol" msgstr "传输协议" -msgid "allowInsecure" -msgstr "允许不安全连接" - -msgid "Concurrency" -msgstr "最大并发连接数" - -msgid "If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates." -msgstr "是否允许不安全连接。当选择时,将不会检查远端主机所提供的 TLS 证书的有效性。" - msgid "Protocol param(optional)" msgstr "传输协议参数(可选)" diff --git a/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt b/package/lean/luci-app-ssr-plus/root/etc/china_ssr.txt similarity index 99% rename from package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt rename to package/lean/luci-app-ssr-plus/root/etc/china_ssr.txt index 4acc39721e..c152a07af2 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/ssr/china_ssr.txt +++ b/package/lean/luci-app-ssr-plus/root/etc/china_ssr.txt @@ -1030,8 +1030,7 @@ 45.65.28.0/22 45.112.132.0/22 45.112.188.0/22 -45.112.208.0/22 -45.112.212.0/22 +45.112.208.0/21 45.112.216.0/22 45.112.220.0/22 45.112.228.0/22 @@ -1472,9 +1471,6 @@ 45.253.232.0/22 45.253.236.0/22 45.253.240.0/22 -45.253.244.0/22 -45.253.248.0/22 -45.253.252.0/22 45.254.0.0/22 45.254.4.0/22 45.254.8.0/22 @@ -1786,7 +1782,6 @@ 61.29.128.0/18 61.29.192.0/19 61.29.224.0/20 -61.29.240.0/20 61.45.128.0/18 61.45.224.0/20 61.47.128.0/18 @@ -4009,13 +4004,6 @@ 103.149.210.0/23 103.149.214.0/23 103.149.220.0/23 -103.149.242.0/23 -103.149.244.0/23 -103.149.246.0/23 -103.149.248.0/23 -103.150.24.0/23 -103.150.66.0/23 -103.150.72.0/23 103.192.0.0/22 103.192.4.0/22 103.192.8.0/22 @@ -5074,7 +5062,8 @@ 106.4.0.0/14 106.8.0.0/15 106.11.0.0/16 -106.12.0.0/14 +106.12.0.0/15 +106.14.0.0/15 106.16.0.0/12 106.32.0.0/12 106.48.0.0/15 @@ -5412,7 +5401,10 @@ 117.32.0.0/13 117.40.0.0/14 117.44.0.0/15 -117.48.0.0/14 +117.48.0.0/17 +117.48.128.0/17 +117.49.0.0/16 +117.50.0.0/15 117.53.48.0/20 117.53.176.0/20 117.57.0.0/16 @@ -5840,7 +5832,8 @@ 124.64.0.0/15 124.66.0.0/17 124.67.0.0/16 -124.68.0.0/14 +124.68.0.0/15 +124.70.0.0/15 124.72.0.0/16 124.73.0.0/16 124.74.0.0/15 diff --git a/package/lean/luci-app-ssr-plus/root/etc/ssr/netflix.list b/package/lean/luci-app-ssr-plus/root/etc/config/netflix.list similarity index 100% rename from package/lean/luci-app-ssr-plus/root/etc/ssr/netflix.list rename to package/lean/luci-app-ssr-plus/root/etc/config/netflix.list diff --git a/package/lean/luci-app-ssr-plus/root/etc/ssr/netflixip.list b/package/lean/luci-app-ssr-plus/root/etc/config/netflixip.list similarity index 100% rename from package/lean/luci-app-ssr-plus/root/etc/ssr/netflixip.list rename to package/lean/luci-app-ssr-plus/root/etc/config/netflixip.list diff --git a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr index f8aac0821e..faaa2348b4 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/config/shadowsocksr @@ -6,20 +6,25 @@ config global option dports '2' option pdnsd_enable '1' option monitor_enable '1' + option global_server 'nil' option enable_switch '1' option switch_timeout '5' option switch_time '667' option switch_try_count '3' - option gfwlist_url 'https://raw.githubusercontent.com/Loukky/gfwlist-by-loukky/master/gfwlist.txt' + option gfwlist_url 'https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt' option chnroute_url 'https://ispip.clang.cn/all_cn.txt' option nfip_url 'https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt' option adblock_url 'https://gitee.com/privacy-protection-tools/anti-ad/raw/master/anti-ad-for-dnsmasq.conf' + option netflix_server 'same' option threads '0' - option global_server 'nil' - option netflix_server 'nil' - option netflix_proxy '0' + +config socks5_proxy + option socks '0' + option local_port '1080' + option local_address '0.0.0.0' config access_control + option wan_bp_list '/etc/china_ssr.txt' option lan_ac_mode 'b' option router_proxy '1' list wan_fw_ips '149.154.160.0/20' @@ -28,11 +33,6 @@ config access_control list wan_fw_ips '91.108.56.0/22' list wan_fw_ips '109.239.140.0/24' -config socks5_proxy - option socks '0' - option local_port '1080' - option local_address '0.0.0.0' - config server_global option enable_server '0' diff --git a/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf b/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf index db07b2f022..cfeb42fc82 100644 --- a/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf +++ b/package/lean/luci-app-ssr-plus/root/etc/dnsmasq.ssr/gfw_list.conf @@ -1,5 +1,5 @@ -server=/.0914.global.ssl.fastly.net/127.0.0.1#5335 -ipset=/.0914.global.ssl.fastly.net/gfwlist +server=/.030buy.com/127.0.0.1#5335 +ipset=/.030buy.com/gfwlist server=/.0rz.tw/127.0.0.1#5335 ipset=/.0rz.tw/gfwlist server=/.10.tt/127.0.0.1#5335 @@ -210,10 +210,14 @@ server=/.8news.com.tw/127.0.0.1#5335 ipset=/.8news.com.tw/gfwlist server=/.8z1.net/127.0.0.1#5335 ipset=/.8z1.net/gfwlist +server=/.9001700.com/127.0.0.1#5335 +ipset=/.9001700.com/gfwlist server=/.91porn.com/127.0.0.1#5335 ipset=/.91porn.com/gfwlist server=/.91vps.club/127.0.0.1#5335 ipset=/.91vps.club/gfwlist +server=/.92ccav.com/127.0.0.1#5335 +ipset=/.92ccav.com/gfwlist server=/.991.com/127.0.0.1#5335 ipset=/.991.com/gfwlist server=/.99btgc01.com/127.0.0.1#5335 @@ -232,8 +236,6 @@ server=/.a248.e.akamai.net/127.0.0.1#5335 ipset=/.a248.e.akamai.net/gfwlist server=/.a5.com.ru/127.0.0.1#5335 ipset=/.a5.com.ru/gfwlist -server=/.a771.dscq.akamai.net/127.0.0.1#5335 -ipset=/.a771.dscq.akamai.net/gfwlist server=/.aamacau.com/127.0.0.1#5335 ipset=/.aamacau.com/gfwlist server=/.abc.com/127.0.0.1#5335 @@ -246,6 +248,8 @@ server=/.abc.xyz/127.0.0.1#5335 ipset=/.abc.xyz/gfwlist server=/.abchinese.com/127.0.0.1#5335 ipset=/.abchinese.com/gfwlist +server=/.abclite.net/127.0.0.1#5335 +ipset=/.abclite.net/gfwlist server=/.abebooks.com/127.0.0.1#5335 ipset=/.abebooks.com/gfwlist server=/.abematv.akamaized.net/127.0.0.1#5335 @@ -256,12 +260,20 @@ server=/.aboluowang.com/127.0.0.1#5335 ipset=/.aboluowang.com/gfwlist server=/.about.google/127.0.0.1#5335 ipset=/.about.google/gfwlist +server=/.aboutgfw.com/127.0.0.1#5335 +ipset=/.aboutgfw.com/gfwlist +server=/.abs.edu/127.0.0.1#5335 +ipset=/.abs.edu/gfwlist server=/.ac.jiruan.net/127.0.0.1#5335 ipset=/.ac.jiruan.net/gfwlist +server=/.accim.org/127.0.0.1#5335 +ipset=/.accim.org/gfwlist server=/.aceros-de-hispania.com/127.0.0.1#5335 ipset=/.aceros-de-hispania.com/gfwlist server=/.acevpn.com/127.0.0.1#5335 ipset=/.acevpn.com/gfwlist +server=/.acg18.me/127.0.0.1#5335 +ipset=/.acg18.me/gfwlist server=/.acgkj.com/127.0.0.1#5335 ipset=/.acgkj.com/gfwlist server=/.acmedia365.com/127.0.0.1#5335 @@ -288,6 +300,8 @@ server=/.admob.com/127.0.0.1#5335 ipset=/.admob.com/gfwlist server=/.adpl.org.hk/127.0.0.1#5335 ipset=/.adpl.org.hk/gfwlist +server=/.ads-twitter.com/127.0.0.1#5335 +ipset=/.ads-twitter.com/gfwlist server=/.adsense.com/127.0.0.1#5335 ipset=/.adsense.com/gfwlist server=/.adult-sex-games.com/127.0.0.1#5335 @@ -306,6 +320,8 @@ server=/.aex.com/127.0.0.1#5335 ipset=/.aex.com/gfwlist server=/.af.mil/127.0.0.1#5335 ipset=/.af.mil/gfwlist +server=/.agnesb.fr/127.0.0.1#5335 +ipset=/.agnesb.fr/gfwlist server=/.agoogleaday.com/127.0.0.1#5335 ipset=/.agoogleaday.com/gfwlist server=/.agro.hk/127.0.0.1#5335 @@ -336,6 +352,8 @@ server=/.aiweiweiblog.com/127.0.0.1#5335 ipset=/.aiweiweiblog.com/gfwlist server=/.akiba-online.com/127.0.0.1#5335 ipset=/.akiba-online.com/gfwlist +server=/.akiba-web.com/127.0.0.1#5335 +ipset=/.akiba-web.com/gfwlist server=/.akow.org/127.0.0.1#5335 ipset=/.akow.org/gfwlist server=/.al-islam.com/127.0.0.1#5335 @@ -396,6 +414,8 @@ server=/.alphaporno.com/127.0.0.1#5335 ipset=/.alphaporno.com/gfwlist server=/.alternate-tools.com/127.0.0.1#5335 ipset=/.alternate-tools.com/gfwlist +server=/.altrec.com/127.0.0.1#5335 +ipset=/.altrec.com/gfwlist server=/.alvinalexander.com/127.0.0.1#5335 ipset=/.alvinalexander.com/gfwlist server=/.alwaysdata.com/127.0.0.1#5335 @@ -408,8 +428,8 @@ server=/.am730.com.hk/127.0.0.1#5335 ipset=/.am730.com.hk/gfwlist server=/.amazon.co.jp/127.0.0.1#5335 ipset=/.amazon.co.jp/gfwlist -server=/.ameba.jp/127.0.0.1#5335 -ipset=/.ameba.jp/gfwlist +server=/.ameblo.jp/127.0.0.1#5335 +ipset=/.ameblo.jp/gfwlist server=/.americangreencard.com/127.0.0.1#5335 ipset=/.americangreencard.com/gfwlist server=/.americanunfinished.com/127.0.0.1#5335 @@ -450,6 +470,8 @@ server=/.andygod.com/127.0.0.1#5335 ipset=/.andygod.com/gfwlist server=/.angela-merkel.de/127.0.0.1#5335 ipset=/.angela-merkel.de/gfwlist +server=/.angola.org/127.0.0.1#5335 +ipset=/.angola.org/gfwlist server=/.angularjs.org/127.0.0.1#5335 ipset=/.angularjs.org/gfwlist server=/.animecrazy.net/127.0.0.1#5335 @@ -496,6 +518,10 @@ server=/.aolchannels.aol.com/127.0.0.1#5335 ipset=/.aolchannels.aol.com/gfwlist server=/.aomiwang.com/127.0.0.1#5335 ipset=/.aomiwang.com/gfwlist +server=/.apartmentratings.com/127.0.0.1#5335 +ipset=/.apartmentratings.com/gfwlist +server=/.apartments.com/127.0.0.1#5335 +ipset=/.apartments.com/gfwlist server=/.apetube.com/127.0.0.1#5335 ipset=/.apetube.com/gfwlist server=/.api-secure.recaptcha.net/127.0.0.1#5335 @@ -514,8 +540,6 @@ server=/.api.pureapk.com/127.0.0.1#5335 ipset=/.api.pureapk.com/gfwlist server=/.api.recaptcha.net/127.0.0.1#5335 ipset=/.api.recaptcha.net/gfwlist -server=/.api.tenor.com/127.0.0.1#5335 -ipset=/.api.tenor.com/gfwlist server=/.apiary.io/127.0.0.1#5335 ipset=/.apiary.io/gfwlist server=/.apidocs.linksalpha.com/127.0.0.1#5335 @@ -574,6 +598,8 @@ server=/.arctosia.com/127.0.0.1#5335 ipset=/.arctosia.com/gfwlist server=/.areca-backup.org/127.0.0.1#5335 ipset=/.areca-backup.org/gfwlist +server=/.arena.taipei/127.0.0.1#5335 +ipset=/.arena.taipei/gfwlist server=/.arethusa.su/127.0.0.1#5335 ipset=/.arethusa.su/gfwlist server=/.arlingtoncemetery.mil/127.0.0.1#5335 @@ -618,12 +644,16 @@ server=/.assembla.com/127.0.0.1#5335 ipset=/.assembla.com/gfwlist server=/.assets.bwbx.io/127.0.0.1#5335 ipset=/.assets.bwbx.io/gfwlist +server=/.assimp.org/127.0.0.1#5335 +ipset=/.assimp.org/gfwlist server=/.astrill.com/127.0.0.1#5335 ipset=/.astrill.com/gfwlist server=/.atc.org.au/127.0.0.1#5335 ipset=/.atc.org.au/gfwlist server=/.atchinese.com/127.0.0.1#5335 ipset=/.atchinese.com/gfwlist +server=/.atdmt.com/127.0.0.1#5335 +ipset=/.atdmt.com/gfwlist server=/.atgfw.org/127.0.0.1#5335 ipset=/.atgfw.org/gfwlist server=/.athenaeizou.com/127.0.0.1#5335 @@ -686,6 +716,8 @@ server=/.azerbaycan.tv/127.0.0.1#5335 ipset=/.azerbaycan.tv/gfwlist server=/.azerimix.com/127.0.0.1#5335 ipset=/.azerimix.com/gfwlist +server=/.azubu.tv/127.0.0.1#5335 +ipset=/.azubu.tv/gfwlist server=/.b0ne.com/127.0.0.1#5335 ipset=/.b0ne.com/gfwlist server=/.babynet.com.hk/127.0.0.1#5335 @@ -700,6 +732,8 @@ server=/.badjojo.com/127.0.0.1#5335 ipset=/.badjojo.com/gfwlist server=/.badoo.com/127.0.0.1#5335 ipset=/.badoo.com/gfwlist +server=/.baidu.jp/127.0.0.1#5335 +ipset=/.baidu.jp/gfwlist server=/.baijie.org/127.0.0.1#5335 ipset=/.baijie.org/gfwlist server=/.bailandaily.com/127.0.0.1#5335 @@ -712,8 +746,6 @@ server=/.banana-vpn.com/127.0.0.1#5335 ipset=/.banana-vpn.com/gfwlist server=/.band.us/127.0.0.1#5335 ipset=/.band.us/gfwlist -server=/.bandpage.com/127.0.0.1#5335 -ipset=/.bandpage.com/gfwlist server=/.bandwagonhost.com/127.0.0.1#5335 ipset=/.bandwagonhost.com/gfwlist server=/.bangbrosnetwork.com/127.0.0.1#5335 @@ -724,10 +756,14 @@ server=/.bangdream.space/127.0.0.1#5335 ipset=/.bangdream.space/gfwlist server=/.bangyoulater.com/127.0.0.1#5335 ipset=/.bangyoulater.com/gfwlist +server=/.bankmobilevibe.com/127.0.0.1#5335 +ipset=/.bankmobilevibe.com/gfwlist server=/.bannedbook.org/127.0.0.1#5335 ipset=/.bannedbook.org/gfwlist server=/.bannednews.org/127.0.0.1#5335 ipset=/.bannednews.org/gfwlist +server=/.banorte.com/127.0.0.1#5335 +ipset=/.banorte.com/gfwlist server=/.baramangaonline.com/127.0.0.1#5335 ipset=/.baramangaonline.com/gfwlist server=/.barenakedislam.com/127.0.0.1#5335 @@ -738,6 +774,8 @@ server=/.barton.de/127.0.0.1#5335 ipset=/.barton.de/gfwlist server=/.bartvpn.com/127.0.0.1#5335 ipset=/.bartvpn.com/gfwlist +server=/.bash-hackers.org/127.0.0.1#5335 +ipset=/.bash-hackers.org/gfwlist server=/.bastillepost.com/127.0.0.1#5335 ipset=/.bastillepost.com/gfwlist server=/.bayvoice.net/127.0.0.1#5335 @@ -748,6 +786,8 @@ server=/.bbc.co.uk/127.0.0.1#5335 ipset=/.bbc.co.uk/gfwlist server=/.bbc.com/127.0.0.1#5335 ipset=/.bbc.com/gfwlist +server=/.bbc.in/127.0.0.1#5335 +ipset=/.bbc.in/gfwlist server=/.bbcchinese.com/127.0.0.1#5335 ipset=/.bbcchinese.com/gfwlist server=/.bbchat.tv/127.0.0.1#5335 @@ -880,6 +920,8 @@ server=/.bfsh.hk/127.0.0.1#5335 ipset=/.bfsh.hk/gfwlist server=/.bgvpn.com/127.0.0.1#5335 ipset=/.bgvpn.com/gfwlist +server=/.bianlei.com/127.0.0.1#5335 +ipset=/.bianlei.com/gfwlist server=/.biantailajiao.com/127.0.0.1#5335 ipset=/.biantailajiao.com/gfwlist server=/.biantailajiao.in/127.0.0.1#5335 @@ -894,8 +936,6 @@ server=/.big.one/127.0.0.1#5335 ipset=/.big.one/gfwlist server=/.bigfools.com/127.0.0.1#5335 ipset=/.bigfools.com/gfwlist -server=/.biggo.com.tw/127.0.0.1#5335 -ipset=/.biggo.com.tw/gfwlist server=/.bigjapanesesex.com/127.0.0.1#5335 ipset=/.bigjapanesesex.com/gfwlist server=/.bigmoney.biz/127.0.0.1#5335 @@ -1082,6 +1122,8 @@ server=/.bolin.netfirms.com/127.0.0.1#5335 ipset=/.bolin.netfirms.com/gfwlist server=/.bonbonme.com/127.0.0.1#5335 ipset=/.bonbonme.com/gfwlist +server=/.bonbonsex.com/127.0.0.1#5335 +ipset=/.bonbonsex.com/gfwlist server=/.bonfoundation.org/127.0.0.1#5335 ipset=/.bonfoundation.org/gfwlist server=/.bongacams.com/127.0.0.1#5335 @@ -1310,6 +1352,8 @@ server=/.castbox.fm/127.0.0.1#5335 ipset=/.castbox.fm/gfwlist server=/.catch22.net/127.0.0.1#5335 ipset=/.catch22.net/gfwlist +server=/.catchgod.com/127.0.0.1#5335 +ipset=/.catchgod.com/gfwlist server=/.catfightpayperview.xxx/127.0.0.1#5335 ipset=/.catfightpayperview.xxx/gfwlist server=/.catholic.org.hk/127.0.0.1#5335 @@ -1558,6 +1602,8 @@ server=/.chinasoul.org/127.0.0.1#5335 ipset=/.chinasoul.org/gfwlist server=/.chinasucks.net/127.0.0.1#5335 ipset=/.chinasucks.net/gfwlist +server=/.chinatimes.com/127.0.0.1#5335 +ipset=/.chinatimes.com/gfwlist server=/.chinatopsex.com/127.0.0.1#5335 ipset=/.chinatopsex.com/gfwlist server=/.chinatown.com.au/127.0.0.1#5335 @@ -1610,6 +1656,8 @@ server=/.chithu.org/127.0.0.1#5335 ipset=/.chithu.org/gfwlist server=/.chn.chosun.com/127.0.0.1#5335 ipset=/.chn.chosun.com/gfwlist +server=/.chobit.cc/127.0.0.1#5335 +ipset=/.chobit.cc/gfwlist server=/.chrdnet.com/127.0.0.1#5335 ipset=/.chrdnet.com/gfwlist server=/.christianfreedom.org/127.0.0.1#5335 @@ -1706,8 +1754,6 @@ server=/.clinica-tibet.ru/127.0.0.1#5335 ipset=/.clinica-tibet.ru/gfwlist server=/.clipfish.de/127.0.0.1#5335 ipset=/.clipfish.de/gfwlist -server=/.clips4sale.com/127.0.0.1#5335 -ipset=/.clips4sale.com/gfwlist server=/.cloakpoint.com/127.0.0.1#5335 ipset=/.cloakpoint.com/gfwlist server=/.cloud.feedly.com/127.0.0.1#5335 @@ -1744,6 +1790,8 @@ server=/.cn.freeones.com/127.0.0.1#5335 ipset=/.cn.freeones.com/gfwlist server=/.cn.ibtimes.com/127.0.0.1#5335 ipset=/.cn.ibtimes.com/gfwlist +server=/.cn.nytstyle.com/127.0.0.1#5335 +ipset=/.cn.nytstyle.com/gfwlist server=/.cn.sandscotaicentral.com/127.0.0.1#5335 ipset=/.cn.sandscotaicentral.com/gfwlist server=/.cn.shafaqna.com/127.0.0.1#5335 @@ -1900,6 +1948,8 @@ server=/.cristyli.com/127.0.0.1#5335 ipset=/.cristyli.com/gfwlist server=/.crocotube.com/127.0.0.1#5335 ipset=/.crocotube.com/gfwlist +server=/.crossfire.co.kr/127.0.0.1#5335 +ipset=/.crossfire.co.kr/gfwlist server=/.crossthewall.net/127.0.0.1#5335 ipset=/.crossthewall.net/gfwlist server=/.crossvpn.net/127.0.0.1#5335 @@ -2066,6 +2116,8 @@ server=/.darktech.org/127.0.0.1#5335 ipset=/.darktech.org/gfwlist server=/.darktoy.net/127.0.0.1#5335 ipset=/.darktoy.net/gfwlist +server=/.darpa.mil/127.0.0.1#5335 +ipset=/.darpa.mil/gfwlist server=/.dastrassi.org/127.0.0.1#5335 ipset=/.dastrassi.org/gfwlist server=/.data-vocabulary.org/127.0.0.1#5335 @@ -2078,6 +2130,8 @@ server=/.daum.net/127.0.0.1#5335 ipset=/.daum.net/gfwlist server=/.david-kilgour.com/127.0.0.1#5335 ipset=/.david-kilgour.com/gfwlist +server=/.dawangidc.com/127.0.0.1#5335 +ipset=/.dawangidc.com/gfwlist server=/.daxa.cn/127.0.0.1#5335 ipset=/.daxa.cn/gfwlist server=/.db.tt/127.0.0.1#5335 @@ -2112,8 +2166,6 @@ server=/.deck.ly/127.0.0.1#5335 ipset=/.deck.ly/gfwlist server=/.decodet.co/127.0.0.1#5335 ipset=/.decodet.co/gfwlist -server=/.deepdiscount.com/127.0.0.1#5335 -ipset=/.deepdiscount.com/gfwlist server=/.deepmind.com/127.0.0.1#5335 ipset=/.deepmind.com/gfwlist server=/.deezer.com/127.0.0.1#5335 @@ -2176,6 +2228,8 @@ server=/.diigo.com/127.0.0.1#5335 ipset=/.diigo.com/gfwlist server=/.dilber.se/127.0.0.1#5335 ipset=/.dilber.se/gfwlist +server=/.dingchin.com.tw/127.0.0.1#5335 +ipset=/.dingchin.com.tw/gfwlist server=/.dipity.com/127.0.0.1#5335 ipset=/.dipity.com/gfwlist server=/.directcreative.com/127.0.0.1#5335 @@ -2216,10 +2270,14 @@ server=/.dlsite.com/127.0.0.1#5335 ipset=/.dlsite.com/gfwlist server=/.dlyoutube.com/127.0.0.1#5335 ipset=/.dlyoutube.com/gfwlist +server=/.dm530.net/127.0.0.1#5335 +ipset=/.dm530.net/gfwlist server=/.dmcdn.net/127.0.0.1#5335 ipset=/.dmcdn.net/gfwlist server=/.dmhy.org/127.0.0.1#5335 ipset=/.dmhy.org/gfwlist +server=/.dmm.co.jp/127.0.0.1#5335 +ipset=/.dmm.co.jp/gfwlist server=/.dns-dns.com/127.0.0.1#5335 ipset=/.dns-dns.com/gfwlist server=/.dns-stuff.com/127.0.0.1#5335 @@ -2244,6 +2302,8 @@ server=/.dnsrd.com/127.0.0.1#5335 ipset=/.dnsrd.com/gfwlist server=/.dnssec.net/127.0.0.1#5335 ipset=/.dnssec.net/gfwlist +server=/.dnvod.tv/127.0.0.1#5335 +ipset=/.dnvod.tv/gfwlist server=/.doctorvoice.org/127.0.0.1#5335 ipset=/.doctorvoice.org/gfwlist server=/.documentingreality.com/127.0.0.1#5335 @@ -2278,8 +2338,6 @@ server=/.dontmovetochina.com/127.0.0.1#5335 ipset=/.dontmovetochina.com/gfwlist server=/.dorjeshugden.com/127.0.0.1#5335 ipset=/.dorjeshugden.com/gfwlist -server=/.dotgov.gov/127.0.0.1#5335 -ipset=/.dotgov.gov/gfwlist server=/.dotplane.com/127.0.0.1#5335 ipset=/.dotplane.com/gfwlist server=/.dotsub.com/127.0.0.1#5335 @@ -2496,6 +2554,8 @@ server=/.edubridge.com/127.0.0.1#5335 ipset=/.edubridge.com/gfwlist server=/.edupro.org/127.0.0.1#5335 ipset=/.edupro.org/gfwlist +server=/.eesti.ee/127.0.0.1#5335 +ipset=/.eesti.ee/gfwlist server=/.eevpn.com/127.0.0.1#5335 ipset=/.eevpn.com/gfwlist server=/.efcc.org.hk/127.0.0.1#5335 @@ -2642,6 +2702,8 @@ server=/.eslite.com/127.0.0.1#5335 ipset=/.eslite.com/gfwlist server=/.esmtp.biz/127.0.0.1#5335 ipset=/.esmtp.biz/gfwlist +server=/.esurance.com/127.0.0.1#5335 +ipset=/.esurance.com/gfwlist server=/.etaa.org.au/127.0.0.1#5335 ipset=/.etaa.org.au/gfwlist server=/.etadult.com/127.0.0.1#5335 @@ -2848,6 +2910,8 @@ server=/.farwestchina.com/127.0.0.1#5335 ipset=/.farwestchina.com/gfwlist server=/.fast.wistia.com/127.0.0.1#5335 ipset=/.fast.wistia.com/gfwlist +server=/.fastpic.ru/127.0.0.1#5335 +ipset=/.fastpic.ru/gfwlist server=/.fastssh.com/127.0.0.1#5335 ipset=/.fastssh.com/gfwlist server=/.faststone.org/127.0.0.1#5335 @@ -2932,12 +2996,16 @@ server=/.fileflyer.com/127.0.0.1#5335 ipset=/.fileflyer.com/gfwlist server=/.files2me.com/127.0.0.1#5335 ipset=/.files2me.com/gfwlist +server=/.filesor.com/127.0.0.1#5335 +ipset=/.filesor.com/gfwlist server=/.fillthesquare.org/127.0.0.1#5335 ipset=/.fillthesquare.org/gfwlist server=/.filmingfortibet.org/127.0.0.1#5335 ipset=/.filmingfortibet.org/gfwlist server=/.filthdump.com/127.0.0.1#5335 ipset=/.filthdump.com/gfwlist +server=/.financetwitter.com/127.0.0.1#5335 +ipset=/.financetwitter.com/gfwlist server=/.finchvpn.com/127.0.0.1#5335 ipset=/.finchvpn.com/gfwlist server=/.findmespot.com/127.0.0.1#5335 @@ -2994,6 +3062,10 @@ server=/.flyvpn.com/127.0.0.1#5335 ipset=/.flyvpn.com/gfwlist server=/.flyzy2005.com/127.0.0.1#5335 ipset=/.flyzy2005.com/gfwlist +server=/.fnac.be/127.0.0.1#5335 +ipset=/.fnac.be/gfwlist +server=/.fnac.com/127.0.0.1#5335 +ipset=/.fnac.com/gfwlist server=/.fochk.org/127.0.0.1#5335 ipset=/.fochk.org/gfwlist server=/.focustaiwan.tw/127.0.0.1#5335 @@ -3246,6 +3318,8 @@ server=/.fw.cm/127.0.0.1#5335 ipset=/.fw.cm/gfwlist server=/.fxcm-chinese.com/127.0.0.1#5335 ipset=/.fxcm-chinese.com/gfwlist +server=/.fxnetworks.com/127.0.0.1#5335 +ipset=/.fxnetworks.com/gfwlist server=/.fzh999.com/127.0.0.1#5335 ipset=/.fzh999.com/gfwlist server=/.fzh999.net/127.0.0.1#5335 @@ -3396,6 +3470,10 @@ server=/.getsync.com/127.0.0.1#5335 ipset=/.getsync.com/gfwlist server=/.gettrials.com/127.0.0.1#5335 ipset=/.gettrials.com/gfwlist +server=/.gettyimages.com/127.0.0.1#5335 +ipset=/.gettyimages.com/gfwlist +server=/.getuploader.com/127.0.0.1#5335 +ipset=/.getuploader.com/gfwlist server=/.gfbv.de/127.0.0.1#5335 ipset=/.gfbv.de/gfwlist server=/.gfgold.com.hk/127.0.0.1#5335 @@ -3434,6 +3512,8 @@ server=/.gjczz.com/127.0.0.1#5335 ipset=/.gjczz.com/gfwlist server=/.glass8.eu/127.0.0.1#5335 ipset=/.glass8.eu/gfwlist +server=/.global.bing.com/127.0.0.1#5335 +ipset=/.global.bing.com/gfwlist server=/.globaljihad.net/127.0.0.1#5335 ipset=/.globaljihad.net/gfwlist server=/.globalmediaoutreach.com/127.0.0.1#5335 @@ -3456,6 +3536,8 @@ server=/.gloryhole.com/127.0.0.1#5335 ipset=/.gloryhole.com/gfwlist server=/.glorystar.me/127.0.0.1#5335 ipset=/.glorystar.me/gfwlist +server=/.glype.com/127.0.0.1#5335 +ipset=/.glype.com/gfwlist server=/.gmail.com/127.0.0.1#5335 ipset=/.gmail.com/gfwlist server=/.gmbd.cn/127.0.0.1#5335 @@ -4024,6 +4106,8 @@ server=/.hitbtc.com/127.0.0.1#5335 ipset=/.hitbtc.com/gfwlist server=/.hitomi.la/127.0.0.1#5335 ipset=/.hitomi.la/gfwlist +server=/.hiwifi.com/127.0.0.1#5335 +ipset=/.hiwifi.com/gfwlist server=/.hizb-ut-tahrir.info/127.0.0.1#5335 ipset=/.hizb-ut-tahrir.info/gfwlist server=/.hizb-ut-tahrir.org/127.0.0.1#5335 @@ -4130,6 +4214,10 @@ server=/.hkzone.org/127.0.0.1#5335 ipset=/.hkzone.org/gfwlist server=/.hmonghot.com/127.0.0.1#5335 ipset=/.hmonghot.com/gfwlist +server=/.hmvdigital.ca/127.0.0.1#5335 +ipset=/.hmvdigital.ca/gfwlist +server=/.hmvdigital.com/127.0.0.1#5335 +ipset=/.hmvdigital.com/gfwlist server=/.hnjhj.com/127.0.0.1#5335 ipset=/.hnjhj.com/gfwlist server=/.hnntube.com/127.0.0.1#5335 @@ -4146,6 +4234,8 @@ server=/.holyspiritspeaks.org/127.0.0.1#5335 ipset=/.holyspiritspeaks.org/gfwlist server=/.home.sina.com/127.0.0.1#5335 ipset=/.home.sina.com/gfwlist +server=/.homedepot.com/127.0.0.1#5335 +ipset=/.homedepot.com/gfwlist server=/.homeperversion.com/127.0.0.1#5335 ipset=/.homeperversion.com/gfwlist server=/.homeservershow.com/127.0.0.1#5335 @@ -4158,6 +4248,8 @@ server=/.hongzhi.li/127.0.0.1#5335 ipset=/.hongzhi.li/gfwlist server=/.hootsuite.com/127.0.0.1#5335 ipset=/.hootsuite.com/gfwlist +server=/.hoovers.com/127.0.0.1#5335 +ipset=/.hoovers.com/gfwlist server=/.hopedialogue.org/127.0.0.1#5335 ipset=/.hopedialogue.org/gfwlist server=/.hopto.org/127.0.0.1#5335 @@ -4430,6 +4522,8 @@ server=/.illusionfactory.com/127.0.0.1#5335 ipset=/.illusionfactory.com/gfwlist server=/.ilove80.be/127.0.0.1#5335 ipset=/.ilove80.be/gfwlist +server=/.ilovelongtoes.com/127.0.0.1#5335 +ipset=/.ilovelongtoes.com/gfwlist server=/.im.tv/127.0.0.1#5335 ipset=/.im.tv/gfwlist server=/.im88.tw/127.0.0.1#5335 @@ -4442,6 +4536,8 @@ server=/.imageflea.com/127.0.0.1#5335 ipset=/.imageflea.com/gfwlist server=/.images-gaytube.com/127.0.0.1#5335 ipset=/.images-gaytube.com/gfwlist +server=/.images.comico.tw/127.0.0.1#5335 +ipset=/.images.comico.tw/gfwlist server=/.imageshack.us/127.0.0.1#5335 ipset=/.imageshack.us/gfwlist server=/.imagevenue.com/127.0.0.1#5335 @@ -4568,6 +4664,8 @@ server=/.isaacmao.com/127.0.0.1#5335 ipset=/.isaacmao.com/gfwlist server=/.isasecret.com/127.0.0.1#5335 ipset=/.isasecret.com/gfwlist +server=/.isc.sans.edu/127.0.0.1#5335 +ipset=/.isc.sans.edu/gfwlist server=/.isgreat.org/127.0.0.1#5335 ipset=/.isgreat.org/gfwlist server=/.islahhaber.net/127.0.0.1#5335 @@ -4672,8 +4770,6 @@ server=/.jav68.tv/127.0.0.1#5335 ipset=/.jav68.tv/gfwlist server=/.javakiba.org/127.0.0.1#5335 ipset=/.javakiba.org/gfwlist -server=/.javbus.co/127.0.0.1#5335 -ipset=/.javbus.co/gfwlist server=/.javbus.com/127.0.0.1#5335 ipset=/.javbus.com/gfwlist server=/.javfor.me/127.0.0.1#5335 @@ -4682,6 +4778,10 @@ server=/.javhd.com/127.0.0.1#5335 ipset=/.javhd.com/gfwlist server=/.javhip.com/127.0.0.1#5335 ipset=/.javhip.com/gfwlist +server=/.javhub.net/127.0.0.1#5335 +ipset=/.javhub.net/gfwlist +server=/.javhuge.com/127.0.0.1#5335 +ipset=/.javhuge.com/gfwlist server=/.javlibrary.com/127.0.0.1#5335 ipset=/.javlibrary.com/gfwlist server=/.javmobile.net/127.0.0.1#5335 @@ -4704,6 +4804,8 @@ server=/.jbtalks.com/127.0.0.1#5335 ipset=/.jbtalks.com/gfwlist server=/.jbtalks.my/127.0.0.1#5335 ipset=/.jbtalks.my/gfwlist +server=/.jcpenney.com/127.0.0.1#5335 +ipset=/.jcpenney.com/gfwlist server=/.jdwsy.com/127.0.0.1#5335 ipset=/.jdwsy.com/gfwlist server=/.jeanyim.com/127.0.0.1#5335 @@ -4736,6 +4838,8 @@ server=/.jihadology.net/127.0.0.1#5335 ipset=/.jihadology.net/gfwlist server=/.jiji.com/127.0.0.1#5335 ipset=/.jiji.com/gfwlist +server=/.jims.net/127.0.0.1#5335 +ipset=/.jims.net/gfwlist server=/.jinbushe.org/127.0.0.1#5335 ipset=/.jinbushe.org/gfwlist server=/.jingpin.org/127.0.0.1#5335 @@ -4870,6 +4974,8 @@ server=/.kawaiikawaii.jp/127.0.0.1#5335 ipset=/.kawaiikawaii.jp/gfwlist server=/.kawase.com/127.0.0.1#5335 ipset=/.kawase.com/gfwlist +server=/.kb.monitorware.com/127.0.0.1#5335 +ipset=/.kb.monitorware.com/gfwlist server=/.kba-tx.org/127.0.0.1#5335 ipset=/.kba-tx.org/gfwlist server=/.kcoolonline.com/127.0.0.1#5335 @@ -4892,8 +4998,12 @@ server=/.kepard.com/127.0.0.1#5335 ipset=/.kepard.com/gfwlist server=/.kex.com/127.0.0.1#5335 ipset=/.kex.com/gfwlist +server=/.keycdn.com/127.0.0.1#5335 +ipset=/.keycdn.com/gfwlist server=/.khabdha.org/127.0.0.1#5335 ipset=/.khabdha.org/gfwlist +server=/.khatrimaza.org/127.0.0.1#5335 +ipset=/.khatrimaza.org/gfwlist server=/.khmusic.com.tw/127.0.0.1#5335 ipset=/.khmusic.com.tw/gfwlist server=/.kichiku-doujinko.com/127.0.0.1#5335 @@ -4930,6 +5040,8 @@ server=/.kk-whys.co.jp/127.0.0.1#5335 ipset=/.kk-whys.co.jp/gfwlist server=/.kkbox.com/127.0.0.1#5335 ipset=/.kkbox.com/gfwlist +server=/.kknews.cc/127.0.0.1#5335 +ipset=/.kknews.cc/gfwlist server=/.kmuh.org.tw/127.0.0.1#5335 ipset=/.kmuh.org.tw/gfwlist server=/.kobo.com/127.0.0.1#5335 @@ -5054,6 +5166,8 @@ server=/.leirentv.ca/127.0.0.1#5335 ipset=/.leirentv.ca/gfwlist server=/.leisurecafe.ca/127.0.0.1#5335 ipset=/.leisurecafe.ca/gfwlist +server=/.leisurepro.com/127.0.0.1#5335 +ipset=/.leisurepro.com/gfwlist server=/.lematin.ch/127.0.0.1#5335 ipset=/.lematin.ch/gfwlist server=/.lemonde.fr/127.0.0.1#5335 @@ -5094,6 +5208,8 @@ server=/.liberal.org.hk/127.0.0.1#5335 ipset=/.liberal.org.hk/gfwlist server=/.libertytimes.com.tw/127.0.0.1#5335 ipset=/.libertytimes.com.tw/gfwlist +server=/.lifemiles.com/127.0.0.1#5335 +ipset=/.lifemiles.com/gfwlist server=/.lighten.org.tw/127.0.0.1#5335 ipset=/.lighten.org.tw/gfwlist server=/.lighti.me/127.0.0.1#5335 @@ -5200,6 +5316,8 @@ server=/.longmusic.com/127.0.0.1#5335 ipset=/.longmusic.com/gfwlist server=/.longtermly.net/127.0.0.1#5335 ipset=/.longtermly.net/gfwlist +server=/.longtoes.com/127.0.0.1#5335 +ipset=/.longtoes.com/gfwlist server=/.lookpic.com/127.0.0.1#5335 ipset=/.lookpic.com/gfwlist server=/.looktoronto.com/127.0.0.1#5335 @@ -5258,6 +5376,8 @@ server=/.m.plixi.com/127.0.0.1#5335 ipset=/.m.plixi.com/gfwlist server=/.m.slandr.net/127.0.0.1#5335 ipset=/.m.slandr.net/gfwlist +server=/.macgamestore.com/127.0.0.1#5335 +ipset=/.macgamestore.com/gfwlist server=/.macrovpn.com/127.0.0.1#5335 ipset=/.macrovpn.com/gfwlist server=/.macts.com.tw/127.0.0.1#5335 @@ -5300,6 +5420,10 @@ server=/.mamingzhe.com/127.0.0.1#5335 ipset=/.mamingzhe.com/gfwlist server=/.manchukuo.net/127.0.0.1#5335 ipset=/.manchukuo.net/gfwlist +server=/.mangafox.com/127.0.0.1#5335 +ipset=/.mangafox.com/gfwlist +server=/.mangafox.me/127.0.0.1#5335 +ipset=/.mangafox.me/gfwlist server=/.maniash.com/127.0.0.1#5335 ipset=/.maniash.com/gfwlist server=/.manicur4ik.ru/127.0.0.1#5335 @@ -5450,6 +5574,8 @@ server=/.meyou.jp/127.0.0.1#5335 ipset=/.meyou.jp/gfwlist server=/.meyul.com/127.0.0.1#5335 ipset=/.meyul.com/gfwlist +server=/.mfxmedia.com/127.0.0.1#5335 +ipset=/.mfxmedia.com/gfwlist server=/.mgoon.com/127.0.0.1#5335 ipset=/.mgoon.com/gfwlist server=/.mgstage.com/127.0.0.1#5335 @@ -5620,6 +5746,8 @@ server=/.moodyz.com/127.0.0.1#5335 ipset=/.moodyz.com/gfwlist server=/.moonbbs.com/127.0.0.1#5335 ipset=/.moonbbs.com/gfwlist +server=/.moonbingo.com/127.0.0.1#5335 +ipset=/.moonbingo.com/gfwlist server=/.morningsun.org/127.0.0.1#5335 ipset=/.morningsun.org/gfwlist server=/.moroneta.com/127.0.0.1#5335 @@ -5696,6 +5824,8 @@ server=/.muzi.com/127.0.0.1#5335 ipset=/.muzi.com/gfwlist server=/.muzi.net/127.0.0.1#5335 ipset=/.muzi.net/gfwlist +server=/.muzu.tv/127.0.0.1#5335 +ipset=/.muzu.tv/gfwlist server=/.mvdis.gov.tw/127.0.0.1#5335 ipset=/.mvdis.gov.tw/gfwlist server=/.mvg.jp/127.0.0.1#5335 @@ -5856,8 +5986,6 @@ server=/.nccwatch.org.tw/127.0.0.1#5335 ipset=/.nccwatch.org.tw/gfwlist server=/.nch.com.tw/127.0.0.1#5335 ipset=/.nch.com.tw/gfwlist -server=/.nchrd.org/127.0.0.1#5335 -ipset=/.nchrd.org/gfwlist server=/.ncn.org/127.0.0.1#5335 ipset=/.ncn.org/gfwlist server=/.nde.de/127.0.0.1#5335 @@ -5868,6 +5996,8 @@ server=/.ned.org/127.0.0.1#5335 ipset=/.ned.org/gfwlist server=/.nekoslovakia.net/127.0.0.1#5335 ipset=/.nekoslovakia.net/gfwlist +server=/.neo-miracle.com/127.0.0.1#5335 +ipset=/.neo-miracle.com/gfwlist server=/.nepusoku.com/127.0.0.1#5335 ipset=/.nepusoku.com/gfwlist server=/.net-fits.pro/127.0.0.1#5335 @@ -5998,6 +6128,8 @@ server=/.nic.cz.cc/127.0.0.1#5335 ipset=/.nic.cz.cc/gfwlist server=/.nic.google/127.0.0.1#5335 ipset=/.nic.google/gfwlist +server=/.nic.gov/127.0.0.1#5335 +ipset=/.nic.gov/gfwlist server=/.nicovideo.jp/127.0.0.1#5335 ipset=/.nicovideo.jp/gfwlist server=/.nighost.org/127.0.0.1#5335 @@ -6044,14 +6176,16 @@ server=/.norbulingka.org/127.0.0.1#5335 ipset=/.norbulingka.org/gfwlist server=/.nordstrom.com/127.0.0.1#5335 ipset=/.nordstrom.com/gfwlist -server=/.nordstrommedia.com/127.0.0.1#5335 -ipset=/.nordstrommedia.com/gfwlist +server=/.nordstromimage.com/127.0.0.1#5335 +ipset=/.nordstromimage.com/gfwlist server=/.nordstromrack.com/127.0.0.1#5335 ipset=/.nordstromrack.com/gfwlist server=/.nordvpn.com/127.0.0.1#5335 ipset=/.nordvpn.com/gfwlist server=/.notify.dropboxapi.com/127.0.0.1#5335 ipset=/.notify.dropboxapi.com/gfwlist +server=/.nottinghampost.com/127.0.0.1#5335 +ipset=/.nottinghampost.com/gfwlist server=/.novelasia.com/127.0.0.1#5335 ipset=/.novelasia.com/gfwlist server=/.now.com/127.0.0.1#5335 @@ -6072,6 +6206,8 @@ server=/.npnt.me/127.0.0.1#5335 ipset=/.npnt.me/gfwlist server=/.nps.gov/127.0.0.1#5335 ipset=/.nps.gov/gfwlist +server=/.npsboost.com/127.0.0.1#5335 +ipset=/.npsboost.com/gfwlist server=/.nradio.me/127.0.0.1#5335 ipset=/.nradio.me/gfwlist server=/.nrk.no/127.0.0.1#5335 @@ -6110,6 +6246,8 @@ server=/.ntdtv.co.kr/127.0.0.1#5335 ipset=/.ntdtv.co.kr/gfwlist server=/.ntdtv.com/127.0.0.1#5335 ipset=/.ntdtv.com/gfwlist +server=/.ntdtv.cz/127.0.0.1#5335 +ipset=/.ntdtv.cz/gfwlist server=/.ntdtv.org/127.0.0.1#5335 ipset=/.ntdtv.org/gfwlist server=/.ntdtv.ru/127.0.0.1#5335 @@ -6122,14 +6260,14 @@ server=/.ntsna.gov.tw/127.0.0.1#5335 ipset=/.ntsna.gov.tw/gfwlist server=/.nubiles.net/127.0.0.1#5335 ipset=/.nubiles.net/gfwlist -server=/.nudezz.com/127.0.0.1#5335 -ipset=/.nudezz.com/gfwlist server=/.nuexpo.com/127.0.0.1#5335 ipset=/.nuexpo.com/gfwlist server=/.nukistream.com/127.0.0.1#5335 ipset=/.nukistream.com/gfwlist server=/.nurgo-software.com/127.0.0.1#5335 ipset=/.nurgo-software.com/gfwlist +server=/.nusatrip.com/127.0.0.1#5335 +ipset=/.nusatrip.com/gfwlist server=/.nutaku.net/127.0.0.1#5335 ipset=/.nutaku.net/gfwlist server=/.nuuvem.com/127.0.0.1#5335 @@ -6194,8 +6332,6 @@ server=/.ocreampies.com/127.0.0.1#5335 ipset=/.ocreampies.com/gfwlist server=/.ocry.com/127.0.0.1#5335 ipset=/.ocry.com/gfwlist -server=/.ocsp.int-x3.letsencrypt.org/127.0.0.1#5335 -ipset=/.ocsp.int-x3.letsencrypt.org/gfwlist server=/.october-review.org/127.0.0.1#5335 ipset=/.october-review.org/gfwlist server=/.oculus.com/127.0.0.1#5335 @@ -6246,6 +6382,8 @@ server=/.on.cc/127.0.0.1#5335 ipset=/.on.cc/gfwlist server=/.on2.com/127.0.0.1#5335 ipset=/.on2.com/gfwlist +server=/.onapp.com/127.0.0.1#5335 +ipset=/.onapp.com/gfwlist server=/.onedrive.live.com/127.0.0.1#5335 ipset=/.onedrive.live.com/gfwlist server=/.onedumb.com/127.0.0.1#5335 @@ -6278,6 +6416,8 @@ server=/.onmypc.us/127.0.0.1#5335 ipset=/.onmypc.us/gfwlist server=/.onthehunt.com/127.0.0.1#5335 ipset=/.onthehunt.com/gfwlist +server=/.ontrac.com/127.0.0.1#5335 +ipset=/.ontrac.com/gfwlist server=/.oopsforum.com/127.0.0.1#5335 ipset=/.oopsforum.com/gfwlist server=/.open.com.hk/127.0.0.1#5335 @@ -6300,6 +6440,8 @@ server=/.openvpn.org/127.0.0.1#5335 ipset=/.openvpn.org/gfwlist server=/.openwebster.com/127.0.0.1#5335 ipset=/.openwebster.com/gfwlist +server=/.openwrt.org.cn/127.0.0.1#5335 +ipset=/.openwrt.org.cn/gfwlist server=/.opml.radiotime.com/127.0.0.1#5335 ipset=/.opml.radiotime.com/gfwlist server=/.opus-gaming.com/127.0.0.1#5335 @@ -6410,8 +6552,8 @@ server=/.paradisehill.cc/127.0.0.1#5335 ipset=/.paradisehill.cc/gfwlist server=/.paradisepoker.com/127.0.0.1#5335 ipset=/.paradisepoker.com/gfwlist -server=/.parts.blog.livedoor.jp/127.0.0.1#5335 -ipset=/.parts.blog.livedoor.jp/gfwlist +server=/.parkansky.com/127.0.0.1#5335 +ipset=/.parkansky.com/gfwlist server=/.partycasino.com/127.0.0.1#5335 ipset=/.partycasino.com/gfwlist server=/.partypoker.com/127.0.0.1#5335 @@ -6670,8 +6812,6 @@ server=/.pornhub.com/127.0.0.1#5335 ipset=/.pornhub.com/gfwlist server=/.pornhubdeutsch.net/127.0.0.1#5335 ipset=/.pornhubdeutsch.net/gfwlist -server=/.pornhubpremium.com/127.0.0.1#5335 -ipset=/.pornhubpremium.com/gfwlist server=/.pornmm.net/127.0.0.1#5335 ipset=/.pornmm.net/gfwlist server=/.pornoxo.com/127.0.0.1#5335 @@ -6766,8 +6906,6 @@ server=/.proxomitron.info/127.0.0.1#5335 ipset=/.proxomitron.info/gfwlist server=/.proxpn.com/127.0.0.1#5335 ipset=/.proxpn.com/gfwlist -server=/.proxy.org/127.0.0.1#5335 -ipset=/.proxy.org/gfwlist server=/.proxy1.xyz/127.0.0.1#5335 ipset=/.proxy1.xyz/gfwlist server=/.proxyanonimo.es/127.0.0.1#5335 @@ -6810,8 +6948,6 @@ server=/.pttvan.org/127.0.0.1#5335 ipset=/.pttvan.org/gfwlist server=/.pubu.com.tw/127.0.0.1#5335 ipset=/.pubu.com.tw/gfwlist -server=/.puffin.com/127.0.0.1#5335 -ipset=/.puffin.com/gfwlist server=/.puffinbrowser.com/127.0.0.1#5335 ipset=/.puffinbrowser.com/gfwlist server=/.puffstore.com/127.0.0.1#5335 @@ -6820,6 +6956,8 @@ server=/.pullfolio.com/127.0.0.1#5335 ipset=/.pullfolio.com/gfwlist server=/.pulse.yahoo.com/127.0.0.1#5335 ipset=/.pulse.yahoo.com/gfwlist +server=/.pure18.com/127.0.0.1#5335 +ipset=/.pure18.com/gfwlist server=/.pureconcepts.net/127.0.0.1#5335 ipset=/.pureconcepts.net/gfwlist server=/.pureinsight.org/127.0.0.1#5335 @@ -6846,6 +6984,8 @@ server=/.pwned.com/127.0.0.1#5335 ipset=/.pwned.com/gfwlist server=/.python.com/127.0.0.1#5335 ipset=/.python.com/gfwlist +server=/.pytorch.org/127.0.0.1#5335 +ipset=/.pytorch.org/gfwlist server=/.qanote.com/127.0.0.1#5335 ipset=/.qanote.com/gfwlist server=/.qgirl.com.tw/127.0.0.1#5335 @@ -6872,6 +7012,8 @@ server=/.qoos.com/127.0.0.1#5335 ipset=/.qoos.com/gfwlist server=/.qpoe.com/127.0.0.1#5335 ipset=/.qpoe.com/gfwlist +server=/.qq.co.za/127.0.0.1#5335 +ipset=/.qq.co.za/gfwlist server=/.qstatus.com/127.0.0.1#5335 ipset=/.qstatus.com/gfwlist server=/.qtrac.eu/127.0.0.1#5335 @@ -6904,6 +7046,8 @@ server=/.qxbbs.org/127.0.0.1#5335 ipset=/.qxbbs.org/gfwlist server=/.qz.com/127.0.0.1#5335 ipset=/.qz.com/gfwlist +server=/.r18.com/127.0.0.1#5335 +ipset=/.r18.com/gfwlist server=/.ra.gg/127.0.0.1#5335 ipset=/.ra.gg/gfwlist server=/.radicalparty.org/127.0.0.1#5335 @@ -6926,8 +7070,8 @@ server=/.raidtalk.com.tw/127.0.0.1#5335 ipset=/.raidtalk.com.tw/gfwlist server=/.raizoji.or.jp/127.0.0.1#5335 ipset=/.raizoji.or.jp/gfwlist -server=/.rakuten.co.jp/127.0.0.1#5335 -ipset=/.rakuten.co.jp/gfwlist +server=/.ramcity.com.au/127.0.0.1#5335 +ipset=/.ramcity.com.au/gfwlist server=/.rangwang.biz/127.0.0.1#5335 ipset=/.rangwang.biz/gfwlist server=/.rangzen.com/127.0.0.1#5335 @@ -6964,6 +7108,12 @@ server=/.rcinet.ca/127.0.0.1#5335 ipset=/.rcinet.ca/gfwlist server=/.rconversation.blogs.com/127.0.0.1#5335 ipset=/.rconversation.blogs.com/gfwlist +server=/.rd.com/127.0.0.1#5335 +ipset=/.rd.com/gfwlist +server=/.rdio.com/127.0.0.1#5335 +ipset=/.rdio.com/gfwlist +server=/.read01.com/127.0.0.1#5335 +ipset=/.read01.com/gfwlist server=/.read100.com/127.0.0.1#5335 ipset=/.read100.com/gfwlist server=/.readingtimes.com.tw/127.0.0.1#5335 @@ -6976,6 +7126,8 @@ server=/.realcourage.org/127.0.0.1#5335 ipset=/.realcourage.org/gfwlist server=/.realforum.zkiz.com/127.0.0.1#5335 ipset=/.realforum.zkiz.com/gfwlist +server=/.realitykings.com/127.0.0.1#5335 +ipset=/.realitykings.com/gfwlist server=/.realraptalk.com/127.0.0.1#5335 ipset=/.realraptalk.com/gfwlist server=/.realsexpass.com/127.0.0.1#5335 @@ -7146,6 +7298,8 @@ server=/.s-cute.com/127.0.0.1#5335 ipset=/.s-cute.com/gfwlist server=/.s-dragon.org/127.0.0.1#5335 ipset=/.s-dragon.org/gfwlist +server=/.s1.nudezz.com/127.0.0.1#5335 +ipset=/.s1.nudezz.com/gfwlist server=/.s1heng.com/127.0.0.1#5335 ipset=/.s1heng.com/gfwlist server=/.s1s1s1.com/127.0.0.1#5335 @@ -7318,6 +7472,8 @@ server=/.sexinsex.net/127.0.0.1#5335 ipset=/.sexinsex.net/gfwlist server=/.sextvx.com/127.0.0.1#5335 ipset=/.sextvx.com/gfwlist +server=/.sexxxy.biz/127.0.0.1#5335 +ipset=/.sexxxy.biz/gfwlist server=/.sfileydy.com/127.0.0.1#5335 ipset=/.sfileydy.com/gfwlist server=/.sfshibao.com/127.0.0.1#5335 @@ -7358,6 +7514,8 @@ server=/.shapeservices.com/127.0.0.1#5335 ipset=/.shapeservices.com/gfwlist server=/.share.america.gov/127.0.0.1#5335 ipset=/.share.america.gov/gfwlist +server=/.share.dmhy.org/127.0.0.1#5335 +ipset=/.share.dmhy.org/gfwlist server=/.share.youthwant.com.tw/127.0.0.1#5335 ipset=/.share.youthwant.com.tw/gfwlist server=/.sharebee.com/127.0.0.1#5335 @@ -7394,8 +7552,6 @@ server=/.shicheng.org/127.0.0.1#5335 ipset=/.shicheng.org/gfwlist server=/.shiksha.com/127.0.0.1#5335 ipset=/.shiksha.com/gfwlist -server=/.shiksha.ws/127.0.0.1#5335 -ipset=/.shiksha.ws/gfwlist server=/.shinychan.com/127.0.0.1#5335 ipset=/.shinychan.com/gfwlist server=/.shipcamouflage.com/127.0.0.1#5335 @@ -7464,6 +7620,8 @@ server=/.sino-monthly.com/127.0.0.1#5335 ipset=/.sino-monthly.com/gfwlist server=/.sinoants.com/127.0.0.1#5335 ipset=/.sinoants.com/gfwlist +server=/.sinocast.com/127.0.0.1#5335 +ipset=/.sinocast.com/gfwlist server=/.sinocism.com/127.0.0.1#5335 ipset=/.sinocism.com/gfwlist server=/.sinomontreal.ca/127.0.0.1#5335 @@ -7512,6 +7670,8 @@ server=/.skyvegas.com/127.0.0.1#5335 ipset=/.skyvegas.com/gfwlist server=/.skyxvpn.com/127.0.0.1#5335 ipset=/.skyxvpn.com/gfwlist +server=/.slacker.com/127.0.0.1#5335 +ipset=/.slacker.com/gfwlist server=/.slaytizle.com/127.0.0.1#5335 ipset=/.slaytizle.com/gfwlist server=/.sleazydream.com/127.0.0.1#5335 @@ -7652,6 +7812,8 @@ server=/.southnews.com.tw/127.0.0.1#5335 ipset=/.southnews.com.tw/gfwlist server=/.sowers.org.hk/127.0.0.1#5335 ipset=/.sowers.org.hk/gfwlist +server=/.soylentnews.org/127.0.0.1#5335 +ipset=/.soylentnews.org/gfwlist server=/.spaces.hightail.com/127.0.0.1#5335 ipset=/.spaces.hightail.com/gfwlist server=/.spankbang.com/127.0.0.1#5335 @@ -7686,8 +7848,12 @@ server=/.spotflux.com/127.0.0.1#5335 ipset=/.spotflux.com/gfwlist server=/.spotify.com/127.0.0.1#5335 ipset=/.spotify.com/gfwlist +server=/.spreadshirt.es/127.0.0.1#5335 +ipset=/.spreadshirt.es/gfwlist server=/.spring4u.info/127.0.0.1#5335 ipset=/.spring4u.info/gfwlist +server=/.springboardplatform.com/127.0.0.1#5335 +ipset=/.springboardplatform.com/gfwlist server=/.sproutcore.com/127.0.0.1#5335 ipset=/.sproutcore.com/gfwlist server=/.sproxy.info/127.0.0.1#5335 @@ -7710,6 +7876,8 @@ server=/.ssglobal.me/127.0.0.1#5335 ipset=/.ssglobal.me/gfwlist server=/.ssh91.com/127.0.0.1#5335 ipset=/.ssh91.com/gfwlist +server=/.ssl.webpack.de/127.0.0.1#5335 +ipset=/.ssl.webpack.de/gfwlist server=/.ssl443.org/127.0.0.1#5335 ipset=/.ssl443.org/gfwlist server=/.sspanel.net/127.0.0.1#5335 @@ -7742,6 +7910,8 @@ server=/.stat.gov.tw/127.0.0.1#5335 ipset=/.stat.gov.tw/gfwlist server=/.static-economist.com/127.0.0.1#5335 ipset=/.static-economist.com/gfwlist +server=/.static.comico.tw/127.0.0.1#5335 +ipset=/.static.comico.tw/gfwlist server=/.static.shemalez.com/127.0.0.1#5335 ipset=/.static.shemalez.com/gfwlist server=/.static01.nyt.com/127.0.0.1#5335 @@ -7850,6 +8020,8 @@ server=/.supchina.com/127.0.0.1#5335 ipset=/.supchina.com/gfwlist server=/.superfreevpn.com/127.0.0.1#5335 ipset=/.superfreevpn.com/gfwlist +server=/.superokayama.com/127.0.0.1#5335 +ipset=/.superokayama.com/gfwlist server=/.superpages.com/127.0.0.1#5335 ipset=/.superpages.com/gfwlist server=/.supervpn.net/127.0.0.1#5335 @@ -7872,6 +8044,8 @@ server=/.suyangg.com/127.0.0.1#5335 ipset=/.suyangg.com/gfwlist server=/.svsfx.com/127.0.0.1#5335 ipset=/.svsfx.com/gfwlist +server=/.swagbucks.com/127.0.0.1#5335 +ipset=/.swagbucks.com/gfwlist server=/.swissinfo.ch/127.0.0.1#5335 ipset=/.swissinfo.ch/gfwlist server=/.swissvpn.net/127.0.0.1#5335 @@ -7990,6 +8164,8 @@ server=/.taoism.net/127.0.0.1#5335 ipset=/.taoism.net/gfwlist server=/.taolun.info/127.0.0.1#5335 ipset=/.taolun.info/gfwlist +server=/.tapanwap.com/127.0.0.1#5335 +ipset=/.tapanwap.com/gfwlist server=/.tapatalk.com/127.0.0.1#5335 ipset=/.tapatalk.com/gfwlist server=/.tascn.com.au/127.0.0.1#5335 @@ -8862,6 +9038,8 @@ server=/.twitterrific.com/127.0.0.1#5335 ipset=/.twitterrific.com/gfwlist server=/.twittertim.es/127.0.0.1#5335 ipset=/.twittertim.es/gfwlist +server=/.twitthat.com/127.0.0.1#5335 +ipset=/.twitthat.com/gfwlist server=/.twitturk.com/127.0.0.1#5335 ipset=/.twitturk.com/gfwlist server=/.twitturly.com/127.0.0.1#5335 @@ -9072,6 +9250,8 @@ server=/.uyghurcongress.org/127.0.0.1#5335 ipset=/.uyghurcongress.org/gfwlist server=/.uyghurensemble.co.uk/127.0.0.1#5335 ipset=/.uyghurensemble.co.uk/gfwlist +server=/.uyghurpen.org/127.0.0.1#5335 +ipset=/.uyghurpen.org/gfwlist server=/.uyghurpress.com/127.0.0.1#5335 ipset=/.uyghurpress.com/gfwlist server=/.uyghurstudies.org/127.0.0.1#5335 @@ -9228,6 +9408,8 @@ server=/.vocn.tv/127.0.0.1#5335 ipset=/.vocn.tv/gfwlist server=/.vod-abematv.akamaized.net/127.0.0.1#5335 ipset=/.vod-abematv.akamaized.net/gfwlist +server=/.vod.wwe.com/127.0.0.1#5335 +ipset=/.vod.wwe.com/gfwlist server=/.vot.org/127.0.0.1#5335 ipset=/.vot.org/gfwlist server=/.vovo2000.com/127.0.0.1#5335 @@ -9320,6 +9502,8 @@ server=/.vpnworldwide.com/127.0.0.1#5335 ipset=/.vpnworldwide.com/gfwlist server=/.vporn.com/127.0.0.1#5335 ipset=/.vporn.com/gfwlist +server=/.vpser.net/127.0.0.1#5335 +ipset=/.vpser.net/gfwlist server=/.vraiesagesse.net/127.0.0.1#5335 ipset=/.vraiesagesse.net/gfwlist server=/.vrmtr.com/127.0.0.1#5335 @@ -9488,6 +9672,8 @@ server=/.wezhiyong.org/127.0.0.1#5335 ipset=/.wezhiyong.org/gfwlist server=/.wezone.net/127.0.0.1#5335 ipset=/.wezone.net/gfwlist +server=/.wforum.com/127.0.0.1#5335 +ipset=/.wforum.com/gfwlist server=/.wha.la/127.0.0.1#5335 ipset=/.wha.la/gfwlist server=/.whatblocked.com/127.0.0.1#5335 @@ -9504,6 +9690,8 @@ server=/.wheelockslatin.com/127.0.0.1#5335 ipset=/.wheelockslatin.com/gfwlist server=/.whereiswerner.com/127.0.0.1#5335 ipset=/.whereiswerner.com/gfwlist +server=/.wheretowatch.com/127.0.0.1#5335 +ipset=/.wheretowatch.com/gfwlist server=/.whichav.com/127.0.0.1#5335 ipset=/.whichav.com/gfwlist server=/.whippedass.com/127.0.0.1#5335 @@ -9556,8 +9744,6 @@ server=/.wikimapia.org/127.0.0.1#5335 ipset=/.wikimapia.org/gfwlist server=/.wikipedia.org/127.0.0.1#5335 ipset=/.wikipedia.org/gfwlist -server=/.wikiwand.com/127.0.0.1#5335 -ipset=/.wikiwand.com/gfwlist server=/.wikiwiki.jp/127.0.0.1#5335 ipset=/.wikiwiki.jp/gfwlist server=/.wildammo.com/127.0.0.1#5335 @@ -9570,6 +9756,8 @@ server=/.windowsphoneme.com/127.0.0.1#5335 ipset=/.windowsphoneme.com/gfwlist server=/.windscribe.com/127.0.0.1#5335 ipset=/.windscribe.com/gfwlist +server=/.wingamestore.com/127.0.0.1#5335 +ipset=/.wingamestore.com/gfwlist server=/.wingy.site/127.0.0.1#5335 ipset=/.wingy.site/gfwlist server=/.winning11.com/127.0.0.1#5335 @@ -9614,6 +9802,8 @@ server=/.wo3ttt.wordpress.com/127.0.0.1#5335 ipset=/.wo3ttt.wordpress.com/gfwlist server=/.woeser.com/127.0.0.1#5335 ipset=/.woeser.com/gfwlist +server=/.wokar.org/127.0.0.1#5335 +ipset=/.wokar.org/gfwlist server=/.wolfax.com/127.0.0.1#5335 ipset=/.wolfax.com/gfwlist server=/.woolyss.com/127.0.0.1#5335 @@ -9622,6 +9812,8 @@ server=/.woopie.jp/127.0.0.1#5335 ipset=/.woopie.jp/gfwlist server=/.woopie.tv/127.0.0.1#5335 ipset=/.woopie.tv/gfwlist +server=/.wordpress.com/127.0.0.1#5335 +ipset=/.wordpress.com/gfwlist server=/.workatruna.com/127.0.0.1#5335 ipset=/.workatruna.com/gfwlist server=/.workerdemo.org.hk/127.0.0.1#5335 @@ -9654,6 +9846,8 @@ server=/.woyaolian.org/127.0.0.1#5335 ipset=/.woyaolian.org/gfwlist server=/.wozy.in/127.0.0.1#5335 ipset=/.wozy.in/gfwlist +server=/.wp.com/127.0.0.1#5335 +ipset=/.wp.com/gfwlist server=/.wpoforum.com/127.0.0.1#5335 ipset=/.wpoforum.com/gfwlist server=/.wqyd.org/127.0.0.1#5335 @@ -9676,6 +9870,8 @@ server=/.wtbn.org/127.0.0.1#5335 ipset=/.wtbn.org/gfwlist server=/.wtfpeople.com/127.0.0.1#5335 ipset=/.wtfpeople.com/gfwlist +server=/.wuerkaixi.com/127.0.0.1#5335 +ipset=/.wuerkaixi.com/gfwlist server=/.wufafangwen.com/127.0.0.1#5335 ipset=/.wufafangwen.com/gfwlist server=/.wufi.org.tw/127.0.0.1#5335 @@ -9694,6 +9890,8 @@ server=/.wuyanblog.com/127.0.0.1#5335 ipset=/.wuyanblog.com/gfwlist server=/.wwitv.com/127.0.0.1#5335 ipset=/.wwitv.com/gfwlist +server=/.www.abclite.net/127.0.0.1#5335 +ipset=/.www.abclite.net/gfwlist server=/.www.ajsands.com/127.0.0.1#5335 ipset=/.www.ajsands.com/gfwlist server=/.www.americorps.gov/127.0.0.1#5335 @@ -9736,6 +9934,10 @@ server=/.www.powerpointninja.com/127.0.0.1#5335 ipset=/.www.powerpointninja.com/gfwlist server=/.www.s4miniarchive.com/127.0.0.1#5335 ipset=/.www.s4miniarchive.com/gfwlist +server=/.www.shadowsocks.com/127.0.0.1#5335 +ipset=/.www.shadowsocks.com/gfwlist +server=/.www.shwchurch.org/127.0.0.1#5335 +ipset=/.www.shwchurch.org/gfwlist server=/.www.taup.org.tw/127.0.0.1#5335 ipset=/.www.taup.org.tw/gfwlist server=/.www.wan-press.org/127.0.0.1#5335 @@ -9746,6 +9948,8 @@ server=/.www.websnapr.com/127.0.0.1#5335 ipset=/.www.websnapr.com/gfwlist server=/.www1.biz/127.0.0.1#5335 ipset=/.www1.biz/gfwlist +server=/.wwwhost.biz/127.0.0.1#5335 +ipset=/.wwwhost.biz/gfwlist server=/.x-art.com/127.0.0.1#5335 ipset=/.x-art.com/gfwlist server=/.x-berry.com/127.0.0.1#5335 @@ -9848,8 +10052,6 @@ server=/.xmovies.com/127.0.0.1#5335 ipset=/.xmovies.com/gfwlist server=/.xn--4gq171p.com/127.0.0.1#5335 ipset=/.xn--4gq171p.com/gfwlist -server=/.xn--90wwvt03e.com/127.0.0.1#5335 -ipset=/.xn--90wwvt03e.com/gfwlist server=/.xn--czq75pvv1aj5c.org/127.0.0.1#5335 ipset=/.xn--czq75pvv1aj5c.org/gfwlist server=/.xn--i2ru8q2qg.com/127.0.0.1#5335 @@ -10042,6 +10244,8 @@ server=/.youtubegaming.com/127.0.0.1#5335 ipset=/.youtubegaming.com/gfwlist server=/.youversion.com/127.0.0.1#5335 ipset=/.youversion.com/gfwlist +server=/.youwin.com/127.0.0.1#5335 +ipset=/.youwin.com/gfwlist server=/.youxu.info/127.0.0.1#5335 ipset=/.youxu.info/gfwlist server=/.yt.be/127.0.0.1#5335 @@ -10050,6 +10254,8 @@ server=/.ytht.net/127.0.0.1#5335 ipset=/.ytht.net/gfwlist server=/.ytimg.com/127.0.0.1#5335 ipset=/.ytimg.com/gfwlist +server=/.ytn.co.kr/127.0.0.1#5335 +ipset=/.ytn.co.kr/gfwlist server=/.yuanming.net/127.0.0.1#5335 ipset=/.yuanming.net/gfwlist server=/.yuanzhengtang.org/127.0.0.1#5335 @@ -10146,10 +10352,16 @@ server=/.zhongguorenquan.org/127.0.0.1#5335 ipset=/.zhongguorenquan.org/gfwlist server=/.zhongguotese.net/127.0.0.1#5335 ipset=/.zhongguotese.net/gfwlist +server=/.zhongmeng.org/127.0.0.1#5335 +ipset=/.zhongmeng.org/gfwlist server=/.zhoushuguang.com/127.0.0.1#5335 ipset=/.zhoushuguang.com/gfwlist server=/.zhreader.com/127.0.0.1#5335 ipset=/.zhreader.com/gfwlist +server=/.zhuangbi.me/127.0.0.1#5335 +ipset=/.zhuangbi.me/gfwlist +server=/.zhuanxing.cn/127.0.0.1#5335 +ipset=/.zhuanxing.cn/gfwlist server=/.zhuatieba.com/127.0.0.1#5335 ipset=/.zhuatieba.com/gfwlist server=/.zhuichaguoji.org/127.0.0.1#5335 @@ -10172,6 +10384,8 @@ server=/.zodgame.us/127.0.0.1#5335 ipset=/.zodgame.us/gfwlist server=/.zomobo.net/127.0.0.1#5335 ipset=/.zomobo.net/gfwlist +server=/.zonaeuropa.com/127.0.0.1#5335 +ipset=/.zonaeuropa.com/gfwlist server=/.zonghexinwen.com/127.0.0.1#5335 ipset=/.zonghexinwen.com/gfwlist server=/.zonghexinwen.net/127.0.0.1#5335 @@ -10184,10 +10398,10 @@ server=/.zoozle.net/127.0.0.1#5335 ipset=/.zoozle.net/gfwlist server=/.zorrovpn.com/127.0.0.1#5335 ipset=/.zorrovpn.com/gfwlist +server=/.zozotown.com/127.0.0.1#5335 +ipset=/.zozotown.com/gfwlist server=/.zpn.im/127.0.0.1#5335 ipset=/.zpn.im/gfwlist -server=/.zsdxzk.com/127.0.0.1#5335 -ipset=/.zsdxzk.com/gfwlist server=/.zspeeder.me/127.0.0.1#5335 ipset=/.zspeeder.me/gfwlist server=/.zsrhao.com/127.0.0.1#5335 diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index e46004cf85..f45565ecd6 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -10,10 +10,10 @@ START=95 STOP=15 + SERVICE_DAEMONIZE=1 -EXTRA_COMMANDS=rules NAME=shadowsocksr -LOCK_FILE=/var/lock/${NAME}.lock +EXTRA_COMMANDS=rules CONFIG_FILE=/var/etc/${NAME}.json CONFIG_UDP_FILE=/var/etc/${NAME}_u.json CONFIG_SOCK5_FILE=/var/etc/${NAME}_s.json @@ -28,6 +28,7 @@ kcp_flag=0 pdnsd_enable_flag=0 switch_enable=0 switch_server=$1 +MAXFD=32768 CRON_FILE=/etc/crontabs/root threads=1 @@ -41,47 +42,33 @@ uci_get_by_type() { echo ${ret:=$3} } -uci_set_by_name() { - uci set $NAME.$1.$2=$3 2>/dev/null - uci commit $NAME -} - -uci_set_by_type() { - uci set $NAME.@$1[0].$2=$3 2>/dev/null - uci commit $NAME -} - uci_get_by_cfgid() { local ret=$(uci show $NAME.@$1[0].$2 | awk -F '.' '{print $2}' 2>/dev/null) echo ${ret:=$3} } -get_host_ip() { +check_host() { local host=$1 - local isip="" - local ip=$host - isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}") - if [ -z "$isip" ]; then - if [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then - ip=$host + if echo $host | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + hostip=$host + elif [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then + hostip=$host + else + hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) + if echo $hostip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + hostip=$hostip else - local ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}') - [ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$1 | awk -F ';' '{print $1}') + hostip="127.0.0.1" fi fi - echo ${ip:="127.0.0.1"} -} - -clean_log() { - logsnum=$(cat /tmp/ssrplus.log 2>/dev/null | wc -l) - [ "$logsnum" -gt 1000 ] && { - echo "$(date "+%Y-%m-%d %H:%M:%S") 日志文件过长,清空处理!" >/tmp/ssrplus.log - } + echo -e $hostip } add_cron() { sed -i '/shadowsocksr/d' $CRON_FILE - [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/ssrplusupdate.sh >>/tmp/ssrplus.log 2>&1" >>$CRON_FILE + sed -i '/ssrplus.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/ssrplus.log' >>$CRON_FILE + [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/shadowsocksr/ssrplusupdate.sh >> /tmp/ssrplus.log 2>&1" >>$CRON_FILE + crontab $CRON_FILE } @@ -89,58 +76,41 @@ del_cron() { sed -i '/shadowsocksr/d' $CRON_FILE sed -i '/ssrplus.log/d' $CRON_FILE /etc/init.d/cron restart - clean_log } -unlock() { - failcount=1 - while [ "$failcount" -le 10 ]; do - if [ -f "$LOCK_FILE" ]; then - let "failcount++" - sleep 1s - [ "$failcount" -ge 10 ] && rm -f "$LOCK_FILE" - else - break - fi - done -} - -find_bin() { - case "$1" in - ss) ret="/usr/bin/ss-redir" ;; - ss-local) ret="/usr/bin/ss-local" ;; - ssr) ret="/usr/bin/ssr-redir" ;; - ssr-local) ret="/usr/bin/ssr-local" ;; - ssr-server) ret="/usr/bin/ssr-server" ;; - v2ray) ret="/usr/bin/v2ray/v2ray" && [ ! -f "$ret" ] && ret="/usr/bin/v2ray" ;; - trojan) ret="/usr/sbin/trojan" ;; - socks5 | tun) ret="/usr/sbin/redsocks2" ;; - esac - echo $ret -} +run_mode=$(uci_get_by_type global run_mode) gen_config_file() { - local hostip=$(get_host_ip $(uci_get_by_name $1 server)) - if [ "$hostip" == "127.0.0.1" ]; then - hostip=$(uci_get_by_name $1 ip) + local host=$(uci_get_by_name $1 server) + if echo $host | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + hostip=$host + elif [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then + hostip=$host else - uci_set_by_name $1 ip $hostip + hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) + if echo $hostip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + hostip=$hostip + else + hostip=$(cat /etc/ssr_ip) + fi fi [ "$2" == "0" -a "$kcp_flag" == "1" ] && hostip="127.0.0.1" - case "$2" in - 0) config_file=$CONFIG_FILE ;; - 1) config_file=$CONFIG_UDP_FILE ;; - 2) config_file=$CONFIG_NETFLIX_FILE ;; - *) config_file=$CONFIG_SOCK5_FILE ;; - esac + if [ "$2" == "0" ]; then + config_file=$CONFIG_FILE + elif [ "$2" == "1" ]; then + config_file=$CONFIG_UDP_FILE + elif [ "$2" == "2" ]; then + config_file=$CONFIG_NETFLIX_FILE + else + config_file=$CONFIG_SOCK5_FILE + fi if [ $(uci_get_by_name $1 fast_open 0) == "1" ]; then fastopen="true" else fastopen="false" fi - local type=$(uci_get_by_name $1 type) - case "$type" in - ss) + local stype=$(uci_get_by_name $1 type) + if [ "$stype" == "ss" ]; then cat <<-EOF >$config_file { "server": "$hostip", @@ -165,8 +135,7 @@ gen_config_file() { echo "$(date "+%Y-%m-%d %H:%M:%S") Warning!!! SIP003 plugin $plugin not found!!!" >>/tmp/ssrplus.log fi fi - ;; - ssr) + elif [ "$stype" == "ssr" ]; then cat <<-EOF >$config_file { "server": "$hostip", @@ -184,18 +153,357 @@ gen_config_file() { "fast_open": $fastopen } EOF - ;; - v2ray) + elif [ "$stype" == "v2ray" ]; then lua /usr/share/shadowsocksr/genv2config.lua $GLOBAL_SERVER tcp $(uci_get_by_name $1 local_port) >/var/etc/v2-ssr-retcp.json sed -i 's/\\//g' /var/etc/v2-ssr-retcp.json - ;; - trojan) + elif [ "$stype" == "trojan" ]; then lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER nat $(uci_get_by_name $1 local_port) >/var/etc/trojan-ssr-retcp.json sed -i 's/\\//g' /var/etc/trojan-ssr-retcp.json - ;; + fi +} + +get_arg_out() { + case "$(uci_get_by_type access_control router_proxy 1)" in + 1) echo "-o" ;; + 2) echo "-O" ;; esac } +start_rules() { + local server=$(uci_get_by_name $GLOBAL_SERVER server) + #resolve name + if echo $server | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + server=$server + elif [ "$server" != "${server#*:[0-9a-fA-F]}" ]; then + server=$server + else + server=$(ping $server -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) + if echo $server | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + echo $server >/etc/ssr_ip + else + server=$(cat /etc/ssr_ip) + fi + fi + kcp_server=$server + local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) + if [ $kcp_enable == "1" ]; then + kcp_flag=1 + fi + local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port) + local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) + local lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode) + local router_proxy=$(uci_get_by_type access_control router_proxy) + if [ "$GLOBAL_SERVER" == "$UDP_RELAY_SERVER" -a "$kcp_flag" == "0" ]; then + ARG_UDP="-u" + elif [ -n "$UDP_RELAY_SERVER" ]; then + ARG_UDP="-U" + local udp_server=$(uci_get_by_name $UDP_RELAY_SERVER server) + local udp_local_port=$(uci_get_by_name $UDP_RELAY_SERVER local_port) + fi + if [ -n "$lan_ac_ips" ]; then + case "$lan_ac_mode" in + w | W | b | B) local ac_ips="$lan_ac_mode$lan_ac_ips" ;; + esac + fi + + #deal gfw firewall rule + local gfwmode="" + if [ "$run_mode" == "gfw" ]; then + gfwmode="-g" + elif [ "$run_mode" == "router" ]; then + gfwmode="-r" + elif [ "$run_mode" == "oversea" ]; then + gfwmode="-c" + elif [ "$run_mode" == "all" ]; then + gfwmode="-z" + fi + local dports=$(uci_get_by_type global dports 1) + if [ $dports == "1" ]; then + proxyport=" " + else + proxyport="-m multiport --dports 22,53,587,465,995,993,143,80,443" + fi + if [ "$NETFLIX_SERVER" != "nil" ]; then + if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then + netflix="1" + else + netflix="2" + fi + else + netflix="0" + fi + netflix_ip=$(check_host $(uci_get_by_name $NETFLIX_SERVER server 127.0.0.1)) + /usr/bin/ssr-rules \ + -s "$server" \ + -l "$local_port" \ + -S "$udp_server" \ + -L "$udp_local_port" \ + -a "$ac_ips" \ + -i "$(uci_get_by_type access_control wan_bp_list)" \ + -b "$(uci_get_by_type access_control wan_bp_ips)" \ + -w "$(uci_get_by_type access_control wan_fw_ips)" \ + -B "$(uci_get_by_type access_control lan_bp_ips)" \ + -p "$(uci_get_by_type access_control lan_fp_ips)" \ + -G "$(uci_get_by_type access_control lan_gm_ips)" \ + -D "$proxyport" \ + -F "$netflix" \ + -N "$netflix_ip" \ + -M "$(uci_get_by_type global netflix_proxy 0)" \ + $(get_arg_out) $gfwmode $ARG_UDP + return $? +} + +start_pdnsd() { + local usr_dns="$1" + local usr_port="$2" + local tcp_dns_list="208.67.222.222, 208.67.220.220" + [ -z "$usr_dns" ] && usr_dns="8.8.8.8" + [ -z "$usr_port" ] && usr_port="53" + [ -d /var/etc ] || mkdir -p /var/etc + if [ ! -d /var/pdnsd ]; then + mkdir -p /var/pdnsd + echo -ne "pd13\000\000\000\000" >/var/pdnsd/pdnsd.cache + chown -R nobody:nogroup /var/pdnsd + fi + cat <<-EOF >/var/etc/pdnsd.conf + global{ + perm_cache=1024; + cache_dir="/var/pdnsd"; + pid_file="/var/run/pdnsd.pid"; + run_as="nobody"; + server_ip=127.0.0.1; + server_port=5335; + status_ctl=on; + query_method=tcp_only; + min_ttl=1h; + max_ttl=1w; + timeout=10; + neg_domain_pol=on; + proc_limit=2; + procq_limit=8; + par_queries=1; + } + server{ + label="ssr-usrdns"; + ip=$usr_dns; + port=$usr_port; + timeout=6; + uptest=none; + interval=10m; + purge_cache=off; + } + EOF + /usr/sbin/pdnsd -c /var/etc/pdnsd.conf & +} + +start_redir() { + case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in + 1 | on | true | yes | enabled) ARG_OTA="-A" ;; + *) ARG_OTA="" ;; + esac + #deal kcp + local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) + if [ "$kcp_enable" == "1" ]; then + [ ! -f "/usr/bin/kcptun-client" ] && return 1 + local kcp_str=$(/usr/bin/kcptun-client -v | grep kcptun | wc -l) + [ "0" == "$kcp_str" ] && return 1 + local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) + local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) + local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password) + local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param) + [ "$password" != "" ] && password="--key "$password + service_start /usr/bin/kcptun-client \ + -r $kcp_server:$kcp_port \ + -l :$server_port $password $kcp_param + kcp_enable_flag=1 + fi + + gen_config_file $GLOBAL_SERVER 0 $(uci_get_by_name $GLOBAL_SERVER local_port 1234) + local stype=$(uci_get_by_name $GLOBAL_SERVER type) + if [ "$stype" == "ss" ]; then + sscmd="/usr/bin/ss-redir" + elif [ "$stype" == "ssr" ]; then + sscmd="/usr/bin/ssr-redir" + elif [ "$stype" == "v2ray" ]; then + sscmd="/usr/bin/v2ray/v2ray" + [ ! -f "$sscmd" ] && sscmd="/usr/bin/v2ray" + elif [ "$stype" == "trojan" ]; then + sscmd="/usr/sbin/trojan" + elif [ "$stype" == "socks5" ]; then + sscmd="/usr/sbin/redsocks2" + elif [ "$stype" == "tun" ]; then + sscmd="/usr/sbin/redsocks2" + fi + + local ntype=$(uci_get_by_name $NETFLIX_SERVER type) + if [ "$ntype" == "ss" ]; then + ncmd="/usr/bin/ss-redir" + sssock="/usr/bin/ss-local" + elif [ "$ntype" == "ssr" ]; then + ncmd="/usr/bin/ssr-redir" + sssock="/usr/bin/ssr-local" + elif [ "$ntype" == "v2ray" ]; then + ncmd="/usr/bin/v2ray/v2ray" + [ ! -f "$ncmd" ] && ncmd="/usr/bin/v2ray" + elif [ "$ntype" == "trojan" ]; then + ncmd="/usr/sbin/trojan" + elif [ "$ntype" == "socks5" ]; then + ncmd="/usr/sbin/redsocks2" + elif [ "$ntype" == "tun" ]; then + ncmd="/usr/sbin/redsocks2" + fi + + local utype=$(uci_get_by_name $UDP_RELAY_SERVER type) + if [ "$utype" == "ss" ]; then + ucmd="/usr/bin/ss-redir" + elif [ "$utype" == "ssr" ]; then + ucmd="/usr/bin/ssr-redir" + elif [ "$utype" == "v2ray" ]; then + ucmd="/usr/bin/v2ray/v2ray" + [ ! -f "$ucmd" ] && ucmd="/usr/bin/v2ray" + elif [ "$utype" == "trojan" ]; then + ucmd="/usr/sbin/trojan" + elif [ "$stype" == "socks5" ]; then + ucmd="/usr/sbin/redsocks2" + elif [ "$stype" == "tun" ]; then + ucmd="/usr/sbin/redsocks2" + fi + if [ "$(uci_get_by_type global threads 0)" == "0" ]; then + threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l) + else + threads=$(uci_get_by_type global threads) + fi + + if [ "$stype" == "ss" -o "$stype" == "ssr" ]; then + local last_config_file=$CONFIG_FILE + local pid_file="/var/run/ssr-retcp.pid" + for i in $(seq 1 $threads); do + $sscmd -c $CONFIG_FILE $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1 + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Shadowsocks/ShadowsocksR $threads Threads Started!" >>/tmp/ssrplus.log + elif [ "$stype" == "v2ray" ]; then + $sscmd -config /var/etc/v2-ssr-retcp.json >/dev/null 2>&1 & + echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) Started!" >>/tmp/ssrplus.log + elif [ "$stype" == "trojan" ]; then + for i in $(seq 1 $threads); do + $sscmd --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & + done + echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd --version 2>&1 | head -1) , $threads Threads Started!" >>/tmp/ssrplus.log + elif [ "$stype" == "socks5" ]; then + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" socks5 tcp $(uci_get_by_name $GLOBAL_SERVER local_port) \ + $(check_host $(uci_get_by_name $GLOBAL_SERVER server)) $(uci_get_by_name $GLOBAL_SERVER server_port) \ + $(uci_get_by_name $GLOBAL_SERVER auth_enable 0) $(uci_get_by_name $GLOBAL_SERVER username) $(uci_get_by_name $GLOBAL_SERVER password) + for i in $(seq 1 $threads); do + $sscmd -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Socks5 REDIRECT/TPROXY $threads Threads Started!" >>/tmp/ssrplus.log + elif [ "$stype" == "tun" ]; then + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" vpn $(uci_get_by_name $GLOBAL_SERVER iface "br-lan") $(uci_get_by_name $GLOBAL_SERVER local_port) + for i in $(seq 1 $threads); do + $sscmd -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 + done + echo "$(date "+%Y-%m-%d %H:%M:%S") Network Tunnel REDIRECT $threads Threads Started!" >>/tmp/ssrplus.log + fi + + if [ "$NETFLIX_SERVER" != "nil" ] && [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then + if [ "$ntype" == "ss" -o "$ntype" == "ssr" ]; then + gen_config_file $NETFLIX_SERVER 2 4321 + gen_config_file $NETFLIX_SERVER 3 1088 + $sssock -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/ssr-socksdns.pid >/dev/null 2>&1 + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + $ncmd -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/ssr-netflix.pid >/dev/null 2>&1 + elif [ "$ntype" == "v2ray" ]; then + lua /usr/share/shadowsocksr/genv2config.lua $NETFLIX_SERVER tcp 4321 1088 >/var/etc/v2-ssr-netflix.json + $ncmd -config /var/etc/v2-ssr-netflix.json >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + elif [ "$ntype" == "trojan" ]; then + lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER nat 4321 >/var/etc/trojan-ssr-netflix.json + sed -i 's/\\//g' /var/etc/trojan-ssr-netflix.json + $ncmd --config /var/etc/trojan-ssr-netflix.json >/dev/null 2>&1 & + lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER client 1088 >/var/etc/trojan-ssr-socksdns.json + sed -i 's/\\//g' /var/etc/trojan-ssr-socksdns.json + $ncmd --config /var/etc/trojan-ssr-socksdns.json >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + elif [ "$ntype" == "socks5" ]; then + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" socks5 tcp 4321 \ + $(check_host $(uci_get_by_name $NETFLIX_SERVER server)) $(uci_get_by_name $NETFLIX_SERVER server_port) \ + $(uci_get_by_name $NETFLIX_SERVER auth_enable 0) $(uci_get_by_name $NETFLIX_SERVER username) $(uci_get_by_name $NETFLIX_SERVER password) + $ncmd -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 + microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + elif [ "$ntype" == "tun" ]; then + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" vpn $(uci_get_by_name $NETFLIX_SERVER iface "br-lan") 4321 + $ncmd -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 + microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & + dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & + fi + fi + + if [ -n "$UDP_RELAY_SERVER" ]; then + if [ "$utype" == "ss" -o "$utype" == "ssr" ]; then + case "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable)" in + 1 | on | true | yes | enabled) ARG_OTA="-A" ;; + *) ARG_OTA="" ;; + esac + gen_config_file $UDP_RELAY_SERVER 1 $(uci_get_by_name $UDP_RELAY_SERVER local_port 1234) + last_config_file=$CONFIG_UDP_FILE + pid_file="/var/run/ssr-reudp.pid" + $ucmd -c $last_config_file $ARG_OTA -U -f /var/run/ssr-reudp.pid >/dev/null 2>&1 + elif [ "$utype" == "v2ray" ]; then + lua /usr/share/shadowsocksr/genv2config.lua $UDP_RELAY_SERVER udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/var/etc/v2-ssr-reudp.json + sed -i 's/\\//g' /var/etc/v2-ssr-reudp.json + $ucmd -config /var/etc/v2-ssr-reudp.json >/dev/null 2>&1 & + elif [ "$stype" == "trojan" ]; then + lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER client 10801 >/var/etc/trojan-ssr-reudp.json + sed -i 's/\\//g' /var/etc/trojan-ssr-reudp.json + $ucmd --config /var/etc/trojan-ssr-reudp.json >/dev/null 2>&1 & + ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p 10801 -l $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/dev/null 2>&1 & + elif [ "$utype" == "socks5" ]; then + /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-reudp.conf" socks5 udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) \ + $(check_host $(uci_get_by_name $UDP_RELAY_SERVER server)) $(uci_get_by_name $UDP_RELAY_SERVER server_port) \ + $(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0) $(uci_get_by_name $UDP_RELAY_SERVER username) $(uci_get_by_name $UDP_RELAY_SERVER password) + $ucmd -c /var/etc/redsocks-ssr-reudp.conf >/dev/null 2>&1 + elif [ "$stype" == "tun" ]; then + redir_udp=0 + echo "$(date "+%Y-%m-%d %H:%M:%S") Network Tunnel UDP TPROXY Relay not supported!" >>/tmp/ssrplus.log + fi + fi + #deal with dns + local ssr_dns="$(uci_get_by_type global pdnsd_enable 0)" + local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" + local dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') + local dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') + if [ "$ssr_dns" != "0" ]; then # not use custom dns service + if [ "$run_mode" == "gfw" ]; then + ipset add gfwlist $dnsserver 2>/dev/null + elif [ "$run_mode" == "oversea" ]; then + ipset add oversea $dnsserver 2>/dev/null + else + ipset add ss_spec_wan_ac $dnsserver nomatch 2>/dev/null + fi + fi + if [ "$ssr_dns" == "1" ]; then + start_pdnsd $dnsserver $dnsport + pdnsd_enable_flag=1 + elif [ "$ssr_dns" == "2" ]; then + microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & + dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & + pdnsd_enable_flag=2 + fi + if [ "$(uci_get_by_type global enable_switch)" == "1" ]; then + if [ "$(uci_get_by_name $GLOBAL_SERVER switch_enable 1)" == "1" ]; then + if [ -z "$switch_server" ]; then + local switch_time=$(uci_get_by_type global switch_time) + local switch_timeout=$(uci_get_by_type global switch_timeout) + service_start /usr/bin/ssr-switch start $switch_time $switch_timeout + switch_enable=1 + fi + fi + fi + add_cron + return $? +} + gen_service_file() { if [ $(uci_get_by_name $1 fast_open) == "1" ]; then fastopen="true" @@ -218,6 +526,26 @@ gen_service_file() { EOF } +start_service() { + [ $(uci_get_by_name $1 enable 0) == "0" ] && return 1 + let server_count=server_count+1 + if [ "$server_count" == "1" ]; then + if ! (iptables-save -t filter | grep SSR-SERVER-RULE >/dev/null); then + iptables -N SSR-SERVER-RULE && \ + iptables -t filter -I INPUT -j SSR-SERVER-RULE + fi + fi + if [ "$(uci_get_by_name $1 type ssr)" == "ssr" ]; then + gen_service_file $1 /var/etc/${NAME}_$server_count.json + /usr/bin/ssr-server -c /var/etc/${NAME}_$server_count.json -u -f /var/run/ssr-server$server_count.pid >/dev/null 2>&1 + else + microsocks -i :: -p $(uci_get_by_name $1 server_port) -1 -u $(uci_get_by_name $1 username) -P $(uci_get_by_name $1 password) ssr-server$server_count >/dev/null 2>&1 & + fi + iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $(uci_get_by_name $1 server_port) -j ACCEPT + iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server_port) -j ACCEPT + return 0 +} + gen_serv_include() { FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) [ -n "$FWI" ] || return 0 @@ -237,426 +565,42 @@ gen_serv_include() { EOF } -start_dns() { - local ssr_dns="$(uci_get_by_type global pdnsd_enable 0)" - local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" - local dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') - local dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') - start_pdnsd() { - local usr_dns="$1" - local usr_port="$2" - [ -z "$usr_dns" ] && usr_dns="8.8.8.8" - [ -z "$usr_port" ] && usr_port="53" - [ -d /var/etc ] || mkdir -p /var/etc - if [ ! -f "/var/pdnsd/pdnsd.cache" ]; then - mkdir -p /var/pdnsd - touch /var/pdnsd/pdnsd.cache - chown -R nobody:nogroup /var/pdnsd - fi - cat <<-EOF >/var/etc/pdnsd.conf - global{ - perm_cache=1024; - cache_dir="/var/pdnsd"; - pid_file="/var/run/pdnsd.pid"; - run_as="nobody"; - server_ip=127.0.0.1; - server_port=5335; - status_ctl=on; - query_method=tcp_only; - min_ttl=1h; - max_ttl=1w; - timeout=10; - neg_domain_pol=on; - proc_limit=2; - procq_limit=8; - par_queries=1; - } - server{ - label="ssr-usrdns"; - ip=$usr_dns; - port=$usr_port; - timeout=6; - uptest=none; - interval=10m; - purge_cache=off; - } - EOF - /usr/sbin/pdnsd -c /var/etc/pdnsd.conf & - } - if [ "$ssr_dns" != "0" ]; then - case "$run_mode" in - oversea) ipset add oversea $dnsserver 2>/dev/null ;; - *) ipset add gfwlist $dnsserver 2>/dev/null ;; - esac - fi - case "$ssr_dns" in - 1) - start_pdnsd $dnsserver $dnsport - pdnsd_enable_flag=1 - ;; - 2) - microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & - dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & - pdnsd_enable_flag=2 - ;; - esac -} - -start_redir_tcp() { - local type=$(uci_get_by_name $GLOBAL_SERVER type) - local bin=$(find_bin $type) - [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 - case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in - 1 | on | true | yes | enabled) ARG_OTA="-A" ;; - *) ARG_OTA="" ;; - esac - local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) - if [ "$kcp_enable" == "1" ]; then - [ ! -f "/usr/bin/kcptun-client" ] && return 1 - local kcp_str=$(/usr/bin/kcptun-client -v | grep kcptun | wc -l) - [ "0" == "$kcp_str" ] && return 1 - local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) - local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) - local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password) - local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param) - [ "$password" != "" ] && password="--key "$password - service_start /usr/bin/kcptun-client \ - -r $kcp_server:$kcp_port \ - -l :$server_port $password $kcp_param - kcp_enable_flag=1 - fi - gen_config_file $GLOBAL_SERVER 0 $(uci_get_by_name $GLOBAL_SERVER local_port 1234) - if [ "$(uci_get_by_type global threads 0)" == "0" ]; then - threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l) - else - threads=$(uci_get_by_type global threads) - fi - case "$type" in - ss | ssr) - local last_config_file=$CONFIG_FILE - local name="Shadowsocks" - [ "$type" == "ssr" ] && name="ShadowsocksR" - for i in $(seq 1 $threads); do - $bin -c $CONFIG_FILE $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1 - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:$name $threads Threads Started!" >>/tmp/ssrplus.log - ;; - v2ray) - $bin -config /var/etc/v2-ssr-retcp.json >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log - ;; - trojan) - for i in $(seq 1 $threads); do - $bin --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:$($bin --version 2>&1 | head -1) , $threads Threads Started!" >>/tmp/ssrplus.log - ;; - socks5) - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" socks5 tcp $(uci_get_by_name $GLOBAL_SERVER local_port) \ - $(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server)) $(uci_get_by_name $GLOBAL_SERVER server_port) \ - $(uci_get_by_name $GLOBAL_SERVER auth_enable 0) $(uci_get_by_name $GLOBAL_SERVER username) $(uci_get_by_name $GLOBAL_SERVER password) - for i in $(seq 1 $threads); do - $bin -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:Socks5 REDIRECT/TPROXY $threads Threads Started!" >>/tmp/ssrplus.log - ;; - tun) - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-retcp.conf" vpn $(uci_get_by_name $GLOBAL_SERVER iface "br-lan") $(uci_get_by_name $GLOBAL_SERVER local_port) - for i in $(seq 1 $threads); do - $bin -c /var/etc/redsocks-ssr-retcp.conf >/dev/null 2>&1 - done - echo "$(date "+%Y-%m-%d %H:%M:%S") Main node:Network Tunnel REDIRECT $threads Threads Started!" >>/tmp/ssrplus.log - ;; - esac - return 0 -} - -start_redir_udp() { - if [ -n "$UDP_RELAY_SERVER" ]; then - local type=$(uci_get_by_name $UDP_RELAY_SERVER type) - local bin=$(find_bin $type) - [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 - case "$type" in - ss | ssr) - case "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable)" in - 1 | on | true | yes | enabled) ARG_OTA="-A" ;; - *) ARG_OTA="" ;; - esac - local name="Shadowsocks" - [ "$type" == "ssr" ] && name="ShadowsocksR" - gen_config_file $UDP_RELAY_SERVER 1 $(uci_get_by_name $UDP_RELAY_SERVER local_port 1234) - last_config_file=$CONFIG_UDP_FILE - $bin -c $last_config_file $ARG_OTA -U -f /var/run/ssr-reudp.pid >/dev/null 2>&1 - echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$name Started!" >>/tmp/ssrplus.log - ;; - v2ray) - lua /usr/share/shadowsocksr/genv2config.lua $UDP_RELAY_SERVER udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/var/etc/v2-ssr-reudp.json - sed -i 's/\\//g' /var/etc/v2-ssr-reudp.json - $bin -config /var/etc/v2-ssr-reudp.json >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log - ;; - trojan) - lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER client 10801 >/var/etc/trojan-ssr-reudp.json - sed -i 's/\\//g' /var/etc/trojan-ssr-reudp.json - $bin --config /var/etc/trojan-ssr-reudp.json >/dev/null 2>&1 & - ipt2socks -U -b 0.0.0.0 -4 -s 127.0.0.1 -p 10801 -l $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log - ;; - socks5) - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-reudp.conf" socks5 udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) \ - $(get_host_ip $(uci_get_by_name $UDP_RELAY_SERVER server)) $(uci_get_by_name $UDP_RELAY_SERVER server_port) \ - $(uci_get_by_name $UDP_RELAY_SERVER auth_enable 0) $(uci_get_by_name $UDP_RELAY_SERVER username) $(uci_get_by_name $UDP_RELAY_SERVER password) - $bin -c /var/etc/redsocks-ssr-reudp.conf >/dev/null 2>&1 - echo "$(date "+%Y-%m-%d %H:%M:%S") UDP TPROXY Relay:Socks5 REDIRECT/TPROXY Started!" >>/tmp/ssrplus.log - ;; - tun) - redir_udp=0 - echo "$(date "+%Y-%m-%d %H:%M:%S") Network Tunnel UDP TPROXY Relay not supported!" >>/tmp/ssrplus.log - ;; - esac - fi - return 0 -} - -start_shunt() { - if [ "$NETFLIX_SERVER" != "nil" ] && [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then - local type=$(uci_get_by_name $NETFLIX_SERVER type) - local bin=$(find_bin $type) - [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 - case "$type" in - ss | ssr) - local bin2=$(find_bin $type-local) - [ ! -f "$bin2" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin2 program, can't start!" >>/tmp/ssrplus.log && return 2 - local name="Shadowsocks" - [ "$type" == "ssr" ] && name="ShadowsocksR" - gen_config_file $NETFLIX_SERVER 2 4321 - gen_config_file $NETFLIX_SERVER 3 1088 - $bin -c /var/etc/shadowsocksr_n.json $ARG_OTA -f /var/run/ssr-netflix.pid >/dev/null 2>&1 - $bin2 -c /var/etc/shadowsocksr_s.json $ARG_OTA -f /var/run/ssr-socksdns.pid >/dev/null 2>&1 - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:$name Started!" >>/tmp/ssrplus.log - ;; - v2ray) - lua /usr/share/shadowsocksr/genv2config.lua $NETFLIX_SERVER tcp 4321 1088 >/var/etc/v2-ssr-netflix.json - $bin -config /var/etc/v2-ssr-netflix.json >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log - ;; - trojan) - lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER nat 4321 >/var/etc/trojan-ssr-netflix.json - sed -i 's/\\//g' /var/etc/trojan-ssr-netflix.json - $bin --config /var/etc/trojan-ssr-netflix.json >/dev/null 2>&1 & - lua /usr/share/shadowsocksr/gentrojanconfig.lua $NETFLIX_SERVER client 1088 >/var/etc/trojan-ssr-socksdns.json - sed -i 's/\\//g' /var/etc/trojan-ssr-socksdns.json - $bin --config /var/etc/trojan-ssr-socksdns.json >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log - ;; - socks5) - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" socks5 tcp 4321 \ - $(get_host_ip $(uci_get_by_name $NETFLIX_SERVER server)) $(uci_get_by_name $NETFLIX_SERVER server_port) \ - $(uci_get_by_name $NETFLIX_SERVER auth_enable 0) $(uci_get_by_name $NETFLIX_SERVER username) $(uci_get_by_name $NETFLIX_SERVER password) - $bin -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 - microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:Socks5 Started!" >>/tmp/ssrplus.log - ;; - tun) - /usr/share/shadowsocksr/genred2config.sh "/var/etc/redsocks-ssr-netflix.conf" vpn $(uci_get_by_name $NETFLIX_SERVER iface "br-lan") 4321 - $bin -c /var/etc/redsocks-ssr-netflix.conf >/dev/null 2>&1 - microsocks -i 127.0.0.1 -p 1088 ssr-socksdns >/dev/null 2>&1 & - dns2socks 127.0.0.1:1088 8.8.8.8:53 127.0.0.1:5555 -q >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Netflix shunt:Network Tunnel REDIRECT Started!" >>/tmp/ssrplus.log - ;; - esac - fi +start_server() { + SERVER_ENABLE=$(uci_get_by_type server_global enable_server 0) + [ "$SERVER_ENABLE" == "0" ] && return 0 + mkdir -p /var/run /var/etc + config_load $NAME + config_foreach start_service server_config + gen_serv_include return 0 } start_local() { local local_server=$(uci_get_by_type socks5_proxy server nil) - [ "$local_server" == "nil" ] && return 1 [ "$local_server" == "same" ] && local_server=$GLOBAL_SERVER - local type=$(uci_get_by_name $local_server type) - local bin=$(find_bin $type) - [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 - case "$type" in - ss | ssr) - local name="Shadowsocks" - local bin=$(find_bin $type-local) - [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 - [ "$type" == "ssr" ] && name="ShadowsocksR" + [ "$local_server" == "nil" ] && return 1 + local local_type=$(uci_get_by_name $local_server type) + mkdir -p /var/run /var/etc + + if [ "$local_type" == "ssr" ]; then gen_config_file $local_server 3 $(uci_get_by_type socks5_proxy local_port 1080) - $bin -c $CONFIG_SOCK5_FILE -u -f /var/run/ssr-local.pid >/dev/null 2>&1 - echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$name Started!" >>/tmp/ssrplus.log - ;; - v2ray) + /usr/bin/ssr-local -c $CONFIG_SOCK5_FILE -u -f /var/run/ssr-local.pid >/dev/null 2>&1 + elif [ "$local_type" == "ss" ]; then + gen_config_file $local_server 3 $(uci_get_by_type socks5_proxy local_port 1080) + /usr/bin/ss-local -c $CONFIG_SOCK5_FILE -u -f /var/run/ssr-local.pid >/dev/null 2>&1 + elif [ "$local_type" == "v2ray" ]; then lua /usr/share/shadowsocksr/genv2config.lua $local_server tcp 0 $(uci_get_by_type socks5_proxy local_port 1080) >/var/etc/v2-ssr-local.json sed -i 's/\\//g' /var/etc/v2-ssr-local.json - $bin -config /var/etc/v2-ssr-local.json >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$($bin -version | head -1) Started!" >>/tmp/ssrplus.log - ;; - trojan) + /usr/bin/v2ray/v2ray -config /var/etc/v2-ssr-local.json >/dev/null 2>&1 & + elif [ "$local_type" == "trojan" ]; then lua /usr/share/shadowsocksr/gentrojanconfig.lua $local_server client $(uci_get_by_type socks5_proxy local_port 1080) >/var/etc/trojan-ssr-local.json sed -i 's/\\//g' /var/etc/trojan-ssr-local.json - $bin --config /var/etc/trojan-ssr-local.json >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$($bin --version 2>&1 | head -1) Started!" >>/tmp/ssrplus.log - ;; - *) - [ -f "/bin/ping6" ] && local listenip='-i ::' - microsocks $listenip -p $(uci_get_by_type socks5_proxy local_port 1080) ssr-local >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Global_Socks5:$type Started!" >>/tmp/ssrplus.log - ;; - esac + /usr/sbin/trojan --config /var/etc/trojan-ssr-local.json >/dev/null 2>&1 & + else + microsocks -i :: -p $(uci_get_by_type socks5_proxy local_port 1080) ssr-local >/dev/null 2>&1 & + fi + local_enable=1 - return 0 -} - -start_server() { - SERVER_ENABLE=$(uci_get_by_type server_global enable_server 0) - [ "$SERVER_ENABLE" == "0" ] && return 0 - server_service() { - [ $(uci_get_by_name $1 enable 0) == "0" ] && return 1 - let server_count=server_count+1 - if [ "$server_count" == "1" ]; then - if ! (iptables-save -t filter | grep SSR-SERVER-RULE >/dev/null); then - iptables -N SSR-SERVER-RULE && \ - iptables -t filter -I INPUT -j SSR-SERVER-RULE - fi - fi - if [ "$(uci_get_by_name $1 type ssr)" == "ssr" ]; then - local bin=$(find_bin ssr-server) - [ ! -f "$bin" ] && echo "$(date "+%Y-%m-%d %H:%M:%S") Can't find $bin program, can't start!" >>/tmp/ssrplus.log && return 1 - gen_service_file $1 /var/etc/${NAME}_$server_count.json - $(find_bin ssr-server) -c /var/etc/${NAME}_$server_count.json -u -f /var/run/ssr-server$server_count.pid >/dev/null 2>&1 - echo "$(date "+%Y-%m-%d %H:%M:%S") Server:ShadowsocksR Server$server_count Started!" >>/tmp/ssrplus.log - else - [ -f "/bin/ping6" ] && local listenip='-i ::' - microsocks $listenip -p $(uci_get_by_name $1 server_port) -1 -u $(uci_get_by_name $1 username) -P $(uci_get_by_name $1 password) ssr-server$server_count >/dev/null 2>&1 & - echo "$(date "+%Y-%m-%d %H:%M:%S") Server:Socks5 Server$server_count Started!" >>/tmp/ssrplus.log - fi - iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $(uci_get_by_name $1 server_port) -j ACCEPT - iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server_port) -j ACCEPT - return 0 - } - mkdir -p /var/run /var/etc - config_load $NAME - config_foreach server_service server_config - gen_serv_include - return 0 -} - -start_switch() { - if [ "$(uci_get_by_type global enable_switch 0)" == "1" ]; then - if [ -z "$switch_server" ]; then - local switch_time=$(uci_get_by_type global switch_time)s - local switch_timeout=$(uci_get_by_type global switch_timeout) - service_start /usr/bin/ssr-switch start $switch_time $switch_timeout - switch_enable=1 - fi - fi -} - -start_monitor() { - if [ $(uci_get_by_type global monitor_enable 1) == "1" ]; then - let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+switch_enable - if [ $total_count -gt 0 ]; then - service_start /usr/bin/ssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $switch_enable - fi - fi -} - -check_server() { - ENABLE_SERVER=$(uci_get_by_type global global_server nil) - if [ "$ENABLE_SERVER" == "nil" ]; then - return 1 - else - STYPE=$(uci_get_by_name $ENABLE_SERVER type nil) - if [ "$STYPE" == "nil" ]; then - CFGID=$(uci_get_by_cfgid servers type nil) - if [ "$CFGID" == "nil" ]; then - uci_set_by_type global global_server 'nil' - else - uci_set_by_type global global_server $CFGID - fi - /etc/init.d/shadowsocksr restart - fi - fi -} - -start_rules() { - local server=$(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server)) - [ "$server" == "127.0.0.1" ] && hostip=$(uci_get_by_name $GLOBAL_SERVER ip) - kcp_server=$server - local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) - if [ $kcp_enable == "1" ]; then - kcp_flag=1 - fi - local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port) - local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) - local lan_ac_mode=$(uci_get_by_type access_control lan_ac_mode) - local router_proxy=$(uci_get_by_type access_control router_proxy) - if [ "$GLOBAL_SERVER" == "$UDP_RELAY_SERVER" -a "$kcp_flag" == "0" ]; then - ARG_UDP="-u" - elif [ -n "$UDP_RELAY_SERVER" ]; then - ARG_UDP="-U" - local udp_server=$(uci_get_by_name $UDP_RELAY_SERVER server) - local udp_local_port=$(uci_get_by_name $UDP_RELAY_SERVER local_port) - fi - if [ -n "$lan_ac_ips" ]; then - case "$lan_ac_mode" in - w | W | b | B) local ac_ips="$lan_ac_mode$lan_ac_ips" ;; - esac - fi - #deal gfw firewall rule - local gfwmode="" - case "$run_mode" in - gfw) gfwmode="-g" ;; - router) gfwmode="-r" ;; - oversea) gfwmode="-c" ;; - all) gfwmode="-z" ;; - esac - local dports=$(uci_get_by_type global dports 1) - if [ $dports == "1" ]; then - proxyport=" " - else - proxyport="-m multiport --dports 22,53,587,465,995,993,143,80,443" - fi - if [ "$NETFLIX_SERVER" != "nil" ]; then - if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then - netflix="1" - else - netflix="2" - fi - else - netflix="0" - fi - get_arg_out() { - case "$(uci_get_by_type access_control router_proxy 1)" in - 1) echo "-o" ;; - 2) echo "-O" ;; - esac - } - netflix_ip=$(get_host_ip $(uci_get_by_name $NETFLIX_SERVER server 127.0.0.1)) - /usr/bin/ssr-rules \ - -s "$server" \ - -l "$local_port" \ - -S "$udp_server" \ - -L "$udp_local_port" \ - -a "$ac_ips" \ - -i "/etc/ssr/china_ssr.txt" \ - -b "$(uci_get_by_type access_control wan_bp_ips)" \ - -w "$(uci_get_by_type access_control wan_fw_ips)" \ - -B "$(uci_get_by_type access_control lan_bp_ips)" \ - -p "$(uci_get_by_type access_control lan_fp_ips)" \ - -G "$(uci_get_by_type access_control lan_gm_ips)" \ - -D "$proxyport" \ - -F "$netflix" \ - -N "$netflix_ip" \ - -M "$(uci_get_by_type global netflix_proxy 0)" \ - -I "/etc/ssr/netflixip.list" \ - $(get_arg_out) $gfwmode $ARG_UDP - return $? } rules() { @@ -666,7 +610,6 @@ rules() { redir_tcp=1 fi mkdir -p /var/run /var/etc - run_mode=$(uci_get_by_type global run_mode) UDP_RELAY_SERVER=$(uci_get_by_type global udp_relay_server) [ "$UDP_RELAY_SERVER" == "same" ] && UDP_RELAY_SERVER=$GLOBAL_SERVER [ -n "$UDP_RELAY_SERVER" ] && redir_udp=1 @@ -678,48 +621,90 @@ rules() { } start() { - [ -f "$LOCK_FILE" ] && exit 2 - touch "$LOCK_FILE" - echo "-------------------------start-------------------------" >>/tmp/ssrplus.log if [ -z "$switch_server" ]; then GLOBAL_SERVER=$(uci_get_by_type global global_server) else GLOBAL_SERVER=$switch_server switch_enable=1 fi + NETFLIX_SERVER=$(uci_get_by_type global netflix_server nil) if [ "$NETFLIX_SERVER" == "same" ]; then NETFLIX_SERVER=$GLOBAL_SERVER fi + if rules; then - if start_redir_tcp; then - start_redir_udp - start_shunt - start_switch - start_dns - add_cron - mkdir -p /tmp/dnsmasq.d - if [ "$run_mode" == "oversea" ]; then - cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf - conf-dir=/tmp/dnsmasq.oversea - EOF - else - cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf - conf-dir=/tmp/dnsmasq.ssr - EOF - fi - /usr/share/shadowsocksr/gfw2ipset.sh + start_redir + mkdir -p /tmp/dnsmasq.d && cp -a /etc/dnsmasq.ssr /tmp/ && cp -a /etc/dnsmasq.oversea /tmp/ + if ! [ "$run_mode" == "oversea" ]; then + cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf + conf-dir=/tmp/dnsmasq.ssr + EOF else - /usr/bin/ssr-rules -f + cat <<-EOF >/tmp/dnsmasq.d/dnsmasq-ssr.conf + conf-dir=/tmp/dnsmasq.oversea + EOF fi + if [ $(uci_get_by_type global adblock 0) == "0" ]; then + rm -f /tmp/dnsmasq.ssr/ad.conf + fi + /usr/share/shadowsocksr/gfw2ipset.sh + + if [ "$NETFLIX_SERVER" != "nil" ]; then + if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then + cat /etc/config/netflix.list | while read line || [ -n "$line" ]; do + sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf + done + awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"netflix"'\n",$0)}' /etc/config/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf + awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5555"'\n",$0)}' /etc/config/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf + + ipset -N netflix hash:net 2>/dev/null + cat /etc/config/netflixip.list | while read nip || [ -n "$nip" ]; do + ipset add netflix $nip 2>/dev/null + done + else + cat /etc/config/netflix.list | while read line || [ -n "$line" ]; do + sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf + done + awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"netflix"'\n",$0)}' /etc/config/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf + awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/config/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf + ipset -N netflix hash:net 2>/dev/null + cat /etc/config/netflixip.list | while read nip || [ -n "$nip" ]; do + ipset add netflix $nip 2>/dev/null + done + fi + else + rm -f /tmp/dnsmasq.ssr/netflix_forward.conf + fi + + /etc/init.d/dnsmasq restart >/dev/null 2>&1 fi start_server start_local - start_monitor - check_server - clean_log - echo "--------------------------end--------------------------" >>/tmp/ssrplus.log - rm -f $LOCK_FILE + if [ $(uci_get_by_type global monitor_enable 1) == "1" ]; then + let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+switch_enable + if [ $total_count -gt 0 ]; then + #param:server(count) redir_tcp(0:no,1:yes) redir_udp tunnel kcp local gfw + service_start /usr/bin/ssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $switch_enable + fi + fi + + ENABLE_SERVER=$(uci_get_by_type global global_server nil) + if [ "$ENABLE_SERVER" == "nil" ]; then + return 1 + else + STYPE=$(uci_get_by_name $ENABLE_SERVER type nil) + if [ "$STYPE" == "nil" ]; then + CFGID=$(uci_get_by_cfgid servers type nil) + if [ "$CFGID" == "nil" ]; then + uci set shadowsocksr.@global[0].global_server='nil' + else + uci set shadowsocksr.@global[0].global_server=$CFGID + fi + uci commit shadowsocksr + /etc/init.d/shadowsocksr restart + fi + fi } boot() { @@ -727,7 +712,6 @@ boot() { } stop() { - unlock /usr/bin/ssr-rules -f srulecount=$(iptables -L | grep SSR-SERVER-RULE | wc -l) if [ $srulecount -gt 0 ]; then @@ -736,14 +720,32 @@ stop() { iptables -X SSR-SERVER-RULE 2>/dev/null fi if [ -z "$switch_server" ]; then - ps -w | grep -v "grep" | grep ssr-switch | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - rm -f /var/lock/ssr-switch.lock + kill -9 $(busybox ps -w | grep ssr-switch | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + fi + if [ $(uci_get_by_type global monitor_enable 0) == "1" ]; then + kill -9 $(busybox ps -w | grep ssr-monitor | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + fi + killall -q -9 ssr-monitor + killall -q -9 ss-redir + killall -q -9 obfs-local + killall -q -9 v2ray-plugin + killall -q -9 ssr-redir + killall -q -9 v2ray + killall -q -9 trojan + killall -q -9 ipt2socks + kill -9 $(busybox ps -w | grep ssr-server | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + kill -9 $(busybox ps -w | grep ssr-local | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + killall -q -9 ssr-local + killall -q -9 ss-local + killall -q -9 kcptun-client + killall -q -9 dns2socks + killall -q -9 microsocks + killall -q -9 redsocks2 + if [ -f /var/run/pdnsd.pid ]; then + kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1 + else + kill -9 $(busybox ps -w | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1 fi - ps -w | grep -v "grep" | grep ssr-monitor | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - ps -w | grep -v "grep" | grep "sleep $(uci_get_by_type global switch_time)s" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - ps -w | grep -v "grep" | grep "sleep 30s" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & - killall -q -9 ss-redir ss-local obfs-local ssr-redir ssr-local ssr-server v2ray v2ray-plugin trojan microsocks ipt2socks dns2socks redsocks2 pdnsd - rm -f /var/lock/ssr-chinaipset.lock /var/lock/ssr-monitor.lock if [ -f "/tmp/dnsmasq.d/dnsmasq-ssr.conf" ]; then rm -f /tmp/dnsmasq.d/dnsmasq-ssr.conf /tmp/dnsmasq.ssr/* /tmp/dnsmasq.oversea/* /etc/init.d/dnsmasq restart >/dev/null 2>&1 diff --git a/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus b/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus index 6419b43817..bd8d02a512 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus +++ b/package/lean/luci-app-ssr-plus/root/etc/uci-defaults/luci-ssr-plus @@ -13,11 +13,11 @@ uci -q batch <<-EOF >/dev/null commit firewall EOF -touch /etc/ssr/china_ssr.txt -touch /etc/ssr/white.list -touch /etc/ssr/black.list -touch /etc/ssr/netflix.list -touch /etc/ssr/netflixip.list +touch /etc/china_ssr.txt +touch /etc/config/white.list +touch /etc/config/black.list +touch /etc/config/netflix.list +touch /etc/config/netflixip.list touch /etc/dnsmasq.ssr/ad.conf touch /etc/dnsmasq.ssr/gfw_list.conf diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad index 1523ce6d3d..2c7ffef057 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-ad @@ -1,9 +1,9 @@ #!/bin/sh -e if [ -f /tmp/adnew.conf ]; then - if (grep -wq "address=" /tmp/adnew.conf); then - cp /tmp/adnew.conf /tmp/ssr-update.$1 - else - cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' >/tmp/ssr-update.$1 - fi + if (grep -wq "address=" /tmp/adnew.conf) ; then + cp /tmp/adnew.conf /tmp/ad.conf + else + cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' > /tmp/ad.conf + fi fi rm -f /tmp/adnew.conf diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw index 44b85d29e2..07ee49c458 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-gfw @@ -1,4 +1,5 @@ #!/bin/sh -e + generate_china_banned() { cat $1 | base64 -d >/tmp/gfwlist.txt rm -f $1 @@ -18,7 +19,7 @@ generate_china_banned() { }' | sort -u } -generate_china_banned /tmp/ssr-update.$1 >/tmp/gfw.txt +generate_china_banned /tmp/gfw.b64 >/tmp/gfw.txt rm -f /tmp/gfwlist.txt -sed '/.*/s/.*/server=\/\.&\/127.0.0.1#5335\nipset=\/\.&\/gfwlist/' /tmp/gfw.txt >/tmp/ssr-update.$1 +sed '/.*/s/.*/server=\/\.&\/127.0.0.1#5335\nipset=\/\.&\/gfwlist/' /tmp/gfw.txt >/tmp/gfwnew.txt rm -f /tmp/gfw.txt diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor index 80bf559f6e..889f1d119a 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-monitor @@ -6,9 +6,6 @@ # This is free software, licensed under the GNU General Public License v3. # See /LICENSE for more information. # -LOCK_FILE="/var/lock/ssr-monitor.lock" -[ -f "$LOCK_FILE" ] && exit 2 -touch "$LOCK_FILE" NAME=shadowsocksr @@ -22,23 +19,6 @@ uci_get_by_type() { echo ${ret:=$3} } -get_host_ip() { - local host=$1 - local isip="" - local ip=$host - isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}") - if [ -z "$isip" ]; then - if [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then - ip=$host - else - local ip=$(resolveip -4 -t 3 $host | awk 'NR==1{print}') - # local hostip=$(ping $host -W 1 -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1) - [ -z "$ip" ] && ip=$(wget -q -O- http://119.29.29.29/d?dn=$1 | awk -F ';' '{print $1}') - fi - fi - echo ${ip:="127.0.0.1"} -} - server_process_count=$1 redir_tcp_process=$2 redir_udp_process=$3 @@ -49,18 +29,25 @@ pdnsd_process=$7 if [ -z "$pdnsd_process" ]; then pdnsd_process=0 fi + i=0 + GLOBAL_SERVER=$(uci_get_by_type global global_server) -server=$(get_host_ip $(uci_get_by_name $GLOBAL_SERVER server)) -[ "$server" == "127.0.0.1" ] && hostip=$(uci_get_by_name $GLOBAL_SERVER ip) +server=$(uci_get_by_name $GLOBAL_SERVER server) lkcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port) server_port=$(uci_get_by_name $GLOBAL_SERVER server_port) password=$(uci_get_by_name $GLOBAL_SERVER kcp_password) kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param) [ "$password" != "" ] && password="--key "${password} +if echo "$server" | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then + server=${server} +else + server=$(cat /etc/ssr_ip) +fi + while [ "1" == "1" ]; do #死循环 - sleep 30s + sleep 30 #redir tcp if [ "$redir_tcp_process" -gt 0 ]; then icount=$(busybox ps -w | grep ssr-retcp | grep -v grep | wc -l) @@ -95,7 +82,6 @@ while [ "1" == "1" ]; do #死循环 logger -t "$NAME" "ssr server error.restart!" kill -9 $(busybox ps -w | grep ssr-server | grep -v grep | awk '{print $1}') >/dev/null 2>&1 /etc/init.d/shadowsocksr restart - exit 0 fi fi #kcptun @@ -114,7 +100,6 @@ while [ "1" == "1" ]; do #死循环 logger -t "$NAME" "global socks server error.restart!" kill -9 $(busybox ps -w | grep ssr-local | grep -v grep | awk '{print $1}') >/dev/null 2>&1 /etc/init.d/shadowsocksr restart - exit 0 fi fi #pdnsd @@ -127,21 +112,21 @@ while [ "1" == "1" ]; do #死循环 else kill -9 $(ps | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1 fi - (/usr/sbin/pdnsd -c /var/etc/pdnsd.conf &) + (/usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d &) fi fi #dns2socks if [ "$pdnsd_process" -eq 2 ]; then icount=$(busybox ps -w | grep -e ssr-dns -e dns2socks | grep -v grep | wc -l) if [ "$icount" -lt 2 ]; then #如果进程挂掉就重启它 - logger -t "$NAME" "dns2socks $dnsstr tunnel error.restart!" + logger -t "$NAME" "dns2socks $dnsstr tunnel error.restart!" dnsstr=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') killall -q -9 dns2socks kill -9 $(busybox ps -w | grep ssr-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & - dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & + dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & fi fi done diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules index 087a74c140..0279d926a7 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-rules @@ -33,7 +33,6 @@ Valid options are: -F netflix mode -N netflix server IP -M netflix proxy mode - -I a file content is bypassed netflix ip list -e extra options for iptables -o apply the rules to the OUTPUT chain -O apply the global rules to the OUTPUT chain @@ -83,8 +82,7 @@ flush_r() { ipset_r() { ipset -N gmlan hash:net 2>/dev/null for ip in $LAN_GM_IP; do ipset -! add gmlan $ip; done - case "$RUNMODE" in - router) + if [ "$RUNMODE" == "router" ]; then ipset -! -R <<-EOF || return 1 create ss_spec_wan_ac hash:net $(gen_iplist | sed -e "s/^/add ss_spec_wan_ac /") @@ -94,29 +92,25 @@ ipset_r() { $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN $IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW - ;; - gfw) + elif [ "$RUNMODE" == "gfw" ]; then ipset -N gfwlist hash:net 2>/dev/null $IPT -N SS_SPEC_WAN_AC $IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN - ;; - oversea) + elif [ "$RUNMODE" == "oversea" ]; then ipset -N oversea hash:net 2>/dev/null $IPT -N SS_SPEC_WAN_AC ipset -N gmlan hash:net 2>/dev/null for ip in $LAN_GM_IP; do ipset -! add gmlan $ip; done $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j SS_SPEC_WAN_FW $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN - ;; - all) + elif [ "$RUNMODE" == "all" ]; then $IPT -N SS_SPEC_WAN_AC $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN - ;; - esac + fi ipset -N fplan hash:net 2>/dev/null for ip in $LAN_FP_IP; do ipset -! add fplan $ip; done $IPT -I SS_SPEC_WAN_AC -m set --match-set fplan src -j SS_SPEC_WAN_FW @@ -129,25 +123,23 @@ ipset_r() { $IPT -I SS_SPEC_WAN_AC -m set --match-set whitelist dst -j RETURN for ip in $WAN_BP_IP; do ipset -! add whitelist $ip; done for ip in $WAN_FW_IP; do ipset -! add blacklist $ip; done - if [ "$NETFLIX" != "0" ]; then - ipset -N netflix hash:net 2>/dev/null - for ip in $(cat ${NETFLIX_LIST:=/dev/null} 2>/dev/null); do ipset -! add netflix $ip; done - fi - case "$NETFLIX" in - 1) + + if [ "$NETFLIX" == "1" ]; then $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports 4321 if [ "$NETFLIX_PROXY" == "1" ]; then $IPT -I SS_SPEC_WAN_AC -p tcp -d $NETFLIX_IP -j REDIRECT --to-ports $local_port else ipset -! add whitelist $NETFLIX_IP fi - ;; - 2) $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port ;; - esac + elif [ "$NETFLIX" == "2" ]; then + $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port + fi + return $? } fw_rule() { + ipset -N netflix hash:net 2>/dev/null $IPT -N SS_SPEC_WAN_FW $IPT -A SS_SPEC_WAN_FW -d 0.0.0.0/8 -j RETURN $IPT -A SS_SPEC_WAN_FW -d 10.0.0.0/8 -j RETURN @@ -224,26 +216,23 @@ tp_rule() { $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - case "$RUNMODE" in - router) + if [ "$RUNMODE" == "router" ]; then $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - ;; - gfw) + elif [ "$RUNMODE" == "gfw" ]; then $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 $ipt -A SS_SPEC_TPROXY -p udp -m set $PROXY_PORTS --match-set gfwlist dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - ;; - oversea) + elif [ "$RUNMODE" == "oversea" ]; then $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst \ -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 - ;; - all) $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 ;; - esac + elif [ "$RUNMODE" == "all" ]; then + $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01 + fi $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET \ -m comment --comment "$TAG" -j SS_SPEC_TPROXY return $? @@ -320,7 +309,7 @@ gen_include() { return 0 } -while getopts ":s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do +while getopts ":s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:oOuUfgrczh" arg; do case "$arg" in s) server=$OPTARG @@ -370,9 +359,6 @@ while getopts ":s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do M) NETFLIX_PROXY=$OPTARG ;; - I) - NETFLIX_LIST=$OPTARG - ;; o) OUTPUT=1 ;; @@ -417,3 +403,4 @@ fi flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include [ "$?" == 0 ] || loger 3 "Start failed!" exit $? + diff --git a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch index 661506bf56..98d91dc962 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch +++ b/package/lean/luci-app-ssr-plus/root/usr/bin/ssr-switch @@ -1,4 +1,4 @@ -#!/bin/sh /etc/rc.common +#!/bin/sh /etc/rc.common # # Copyright (C) 2017 openwrt-ssr # Copyright (C) 2017 yushi studio @@ -6,9 +6,6 @@ # This is free software, licensed under the GNU General Public License v3. # See /LICENSE for more information. # -LOCK_FILE="/var/lock/ssr-switch.lock" -[ -f "$LOCK_FILE" ] && exit 2 -touch "$LOCK_FILE" cycle_time=60 switch_time=3 @@ -82,7 +79,7 @@ test_proxy() { search_proxy() { let server_count=server_count+1 [ "$normal_flag" == "1" -a "$server_count" -le "$server_locate" ] && return 0 - [ "$(uci_get_by_name $1 switch_enable 0)" != "1" ] && return 1 + [ "$(uci_get_by_name $1 switch_enable)" != "1" ] && return 1 [ $ENABLE_SERVER != nil ] && return 0 [ "$1" == "$CURRENT_SERVER" ] && return 0 local servername=$(uci_get_by_name $1 server) @@ -136,7 +133,7 @@ start() { #缺省服务器正常,切换回来 CURRENT_SERVER=$DEFAULT_SERVER switch_proxy $CURRENT_SERVER - echo "$(date "+%Y-%m-%d %H:%M:%S") switch to default "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") switch to default ["$(uci_get_by_name $CURRENT_SERVER server)"] proxy!" >>/tmp/ssrplus.log else echo "$(date "+%Y-%m-%d %H:%M:%S") Main server is NOT avilable.Continue using current server." >>/tmp/ssrplus.log fi @@ -157,7 +154,7 @@ start() { CURRENT_SERVER=$ENABLE_SERVER switch_proxy $CURRENT_SERVER normal_flag=1 - echo "$(date "+%Y-%m-%d %H:%M:%S") Switch to "$(uci_get_by_name $CURRENT_SERVER alias)" proxy!" >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR server switch OK" >>/tmp/ssrplus.log else switch_proxy $CURRENT_SERVER normal_flag=1 @@ -165,7 +162,7 @@ start() { fi else normal_flag=0 - # echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR No Problem." >>/tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") ShadowsocksR No Problem." >>/tmp/ssrplus.log fi done } diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh index d011c63ca8..044d524d94 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/chinaipset.sh @@ -1,9 +1,5 @@ -#!/bin/sh -LOCK_FILE="/var/lock/ssr-chinaipset.lock" -[ -f "$LOCK_FILE" ] && exit 2 -touch "$LOCK_FILE" echo "create china hash:net family inet hashsize 1024 maxelem 65536" > /tmp/china.ipset awk '!/^$/&&!/^#/{printf("add china %s'" "'\n",$0)}' /etc/china_ssr.txt >> /tmp/china.ipset ipset -! flush china ipset -! restore < /tmp/china.ipset 2>/dev/null -rm -f /tmp/china.ipset $LOCK_FILE +rm -f /tmp/china.ipset diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh index 5e51003424..a36f48f897 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genred2config.sh @@ -1,70 +1,72 @@ #!/bin/sh + cat <<-EOF >$1 base { -log_debug = off; -log_info = off; -log = stderr; -daemon = on; -redirector = iptables; -reuseport = on; + log_debug = off; + log_info = off; + log = stderr; + daemon = on; + redirector = iptables; + reuseport = on; } EOF + if [ "$2" == "socks5" ]; then -if [ "$3" == "tcp" ]; then -if [ "$7" == "0" ]; then -cat <<-EOF >>$1 + if [ "$3" == "tcp" ]; then + if [ "$7" == "0" ]; then + cat <<-EOF >>$1 redsocks { -bind = "0.0.0.0:$4"; -relay = "$5:$6"; -type = socks5; -autoproxy = 0; -timeout = 10; + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + autoproxy = 0; + timeout = 10; } EOF -else -cat <<-EOF >>$1 + else + cat <<-EOF >>$1 redsocks { -bind = "0.0.0.0:$4"; -relay = "$5:$6"; -type = socks5; -autoproxy = 0; -timeout = 10; -login = "$8"; -password = "$9"; + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + autoproxy = 0; + timeout = 10; + login = "$8"; + password = "$9"; } EOF -fi -else -if [ "$7" == "0" ]; then -cat <<-EOF >>$1 + fi + else + if [ "$7" == "0" ]; then + cat <<-EOF >>$1 redudp { -bind = "0.0.0.0:$4"; -relay = "$5:$6"; -type = socks5; -udp_timeout = 10; + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + udp_timeout = 10; } EOF -else -cat <<-EOF >>$1 + else + cat <<-EOF >>$1 redudp { -bind = "0.0.0.0:$4"; -relay = "$5:$6"; -type = socks5; -udp_timeout = 10; -login = "$8"; -password = "$9"; + bind = "0.0.0.0:$4"; + relay = "$5:$6"; + type = socks5; + udp_timeout = 10; + login = "$8"; + password = "$9"; } EOF -fi -fi + fi + fi else -cat <<-EOF >>$1 + cat <<-EOF >>$1 redsocks { -bind = "0.0.0.0:$4"; -type = direct; -interface = $3; -autoproxy = 0; -timeout = 10; + bind = "0.0.0.0:$4"; + type = direct; + interface = $3; + autoproxy = 0; + timeout = 10; } EOF fi diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua index 2758111744..8cb979bef8 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gentrojanconfig.lua @@ -3,6 +3,7 @@ local json = require "luci.jsonc" local server_section = arg[1] local proto = arg[2] local local_port = arg[3] + local server = ucursor:get_all("shadowsocksr", server_section) local trojan = { diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua index 23d5bd9063..2554ebd17b 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/genv2config.lua @@ -4,6 +4,7 @@ local server_section = arg[1] local proto = arg[2] local local_port = arg[3] or "0" local socks_port = arg[4] or "0" + local server = ucursor:get_all("shadowsocksr", server_section) local v2ray = { diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh index 245bb8c88d..c5decd28ce 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/gfw2ipset.sh @@ -1,34 +1,5 @@ #!/bin/sh -NAME=shadowsocksr -uci_get_by_type() { - local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null) - echo ${ret:=$3} -} -cp -a /etc/dnsmasq.ssr /tmp/ -cp -a /etc/dnsmasq.oversea /tmp/ -GLOBAL_SERVER=$(uci_get_by_type global global_server) -NETFLIX_SERVER=$(uci_get_by_type global netflix_server nil) -[ "$NETFLIX_SERVER" == "same" ] && NETFLIX_SERVER=$GLOBAL_SERVER -if [ "$NETFLIX_SERVER" != "nil" ]; then - netflix() { - for line in $(cat /etc/ssr/netflix.list); do sed -i "/$line/d" /tmp/dnsmasq.ssr/gfw_list.conf; done - awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"netflix"'\n",$0)}' /etc/ssr/netflix.list >/tmp/dnsmasq.ssr/netflix_forward.conf - awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#$1"'\n",$0)}' /etc/ssr/netflix.list >>/tmp/dnsmasq.ssr/netflix_forward.conf - } - if [ "$NETFLIX_SERVER" != "$GLOBAL_SERVER" ]; then - netflix 5555 - else - netflix 5335 - fi -else - rm -f /tmp/dnsmasq.ssr/netflix_forward.conf -fi -if [ "$1" == "" ]; then - awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"blacklist"'\n",$0)}' /etc/ssr/black.list >/tmp/dnsmasq.ssr/blacklist_forward.conf - awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/ssr/black.list >>/tmp/dnsmasq.ssr/blacklist_forward.conf - awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"whitelist"'\n",$0)}' /etc/ssr/white.list >/tmp/dnsmasq.ssr/whitelist_forward.conf - if [ "$(uci_get_by_type global adblock 0)" == "0" ]; then - rm -f /tmp/dnsmasq.ssr/ad.conf - fi -fi -/etc/init.d/dnsmasq restart >/dev/null 2>&1 +mkdir -p /tmp/dnsmasq.ssr +awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"blacklist"'\n",$0)}' /etc/config/black.list > /tmp/dnsmasq.ssr/blacklist_forward.conf +awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/config/black.list >> /tmp/dnsmasq.ssr/blacklist_forward.conf +awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"whitelist"'\n",$0)}' /etc/config/white.list > /tmp/dnsmasq.ssr/whitelist_forward.conf diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh index 818726a98b..5db73ff880 100755 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/ssrplusupdate.sh @@ -1,6 +1,6 @@ #!/bin/sh + /usr/bin/lua /usr/share/shadowsocksr/update.lua -sleep 2s -/usr/share/shadowsocksr/chinaipset.sh -sleep 2s /usr/bin/lua /usr/share/shadowsocksr/subscribe.lua +sleep 10 +/etc/init.d/shadowsocksr restart \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index ff0a201bd7..7b05ce5cfc 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -3,33 +3,34 @@ -- This file is part of the luci-app-ssr-plus subscribe.lua -- @author William Chan ------------------------------------------------ -require "luci.model.uci" -require "nixio" -require "luci.util" -require "luci.sys" -require "luci.jsonc" +require 'nixio' +require 'luci.util' +require 'luci.jsonc' +require 'luci.sys' +require 'uci' -- these global functions are accessed all the time by the event handler -- so caching them is worth the effort +local luci = luci local tinsert = table.insert local ssub, slen, schar, sbyte, sformat, sgsub = string.sub, string.len, string.char, string.byte, string.format, string.gsub local jsonParse, jsonStringify = luci.jsonc.parse, luci.jsonc.stringify local b64decode = nixio.bin.b64decode local cache = {} -local nodeResult = setmetatable({}, { __index = cache }) -- update result +local nodeResult = setmetatable({}, { __index = cache }) -- update result local name = 'shadowsocksr' local uciType = 'servers' local ucic = luci.model.uci.cursor() local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') local switch = ucic:get_first(name, 'server_subscribe', 'switch', '1') local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) -local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', '过期时间/剩余流量') +local filter_words = ucic:get_first(name, 'server_subscribe', 'filter_words', 'QQ群') local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) end -- 分割字符串 local function split(full, sep) - full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 + full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 local off, result = 1, {} while true do local nStart, nEnd = full:find(sep, off) @@ -73,7 +74,7 @@ local function trim(text) end -- md5 local function md5(content) - local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1') + local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1') -- assert(nixio.errno() == 0) return trim(stdout) end @@ -118,7 +119,7 @@ local function processData(szType, content) result.protocol_param = base64Decode(params.protoparam) local group = base64Decode(params.group) if group then - result.alias = "[" .. group .. "] " + result.alias = "[" .. group .. "] " end result.alias = result.alias .. base64Decode(params.remarks) elseif szType == 'vmess' then @@ -279,15 +280,15 @@ local function wget(url) end local function check_filer(result) - do - local filter_word = split(filter_words, "/") - for i, v in pairs(filter_word) do - if result.alias:find(v) then - log('订阅节点关键字过滤:“' .. v ..'” ,该节点被丢弃') - return true - end - end - end + do + local filter_word = split(filter_words, "/") + for i, v in pairs(filter_word) do + if result.alias:find(v) then + log('订阅节点关键字过滤:“' .. v ..'” ,该节点被丢弃') + return true + end + end + end end local execute = function() @@ -312,10 +313,10 @@ local execute = function() nodes = base64Decode(raw:sub(nEnd + 1, #raw)) nodes = jsonParse(nodes) local extra = { - airport = nodes.airport, - port = nodes.port, - encryption = nodes.encryption, - password = nodes.password + airport = nodes.airport, + port = nodes.port, + encryption = nodes.encryption, + password = nodes.password } local servers = {} -- SS里面包着 干脆直接这样 @@ -348,11 +349,10 @@ local execute = function() -- log(result) if result then if - not result.server or - not result.server_port or - check_filer(result) or - result.server:match("[^0-9a-zA-Z%-%.%s]") -- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场 - then + not result.server or + check_filer(result) or + result.server:match("[^0-9a-zA-Z%-%.%s]") -- 中文做地址的 也没有人拿中文域名搞,就算中文域也有Puny Code SB 机场 + then log('丢弃无效节点: ' .. result.type ..' 节点, ' .. result.alias) else log('成功解析: ' .. result.type ..' 节点, ' .. result.alias) @@ -385,7 +385,7 @@ local execute = function() local dat = nodeResult[old.grouphashkey][old.hashkey] ucic:tset(name, old['.name'], dat) -- 标记一下 - setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } }) + setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } }) end else if not old.alias then @@ -393,6 +393,7 @@ local execute = function() end log('忽略手动添加的节点: ' .. old.alias) end + end) for k, v in ipairs(nodeResult) do for kk, vv in ipairs(v) do diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua index bcf2568904..17341bd84c 100644 --- a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/update.lua @@ -3,8 +3,10 @@ -- This file is part of the luci-app-ssr-plus update.lua -- By Mattraks ------------------------------------------------ -require "luci.sys" -require "luci.model.uci" +require 'nixio' +require 'luci.util' +require 'luci.jsonc' +require 'luci.sys' local icount = 0 local uci = luci.model.uci.cursor() @@ -12,41 +14,112 @@ local log = function(...) print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) end -local function update(url, file, type, file2) - local Num = 1 - refresh_cmd = "wget-ssl --no-check-certificate -t 3 -T 10 -O- " .. url .. " > /tmp/ssr-update." .. type - sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") - if sret == 0 then - if type == "gfw_data" then - luci.sys.call("/usr/bin/ssr-gfw " .. type) - Num = 2 - end - if type == "ad_data" then - luci.sys.call("/usr/bin/ssr-ad " .. type) - end - local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/ssr-update." .. type .. "' ] && md5sum /tmp/ssr-update." .. type .. " | awk '{print $1}')") - local old_md5 = luci.sys.exec("echo -n $([ -f '" .. file .. "' ] && md5sum " .. file .. " | awk '{print $1}')") - if new_md5 == old_md5 then - log("你已经是最新数据,无需更新!") +log('正在更新【GFW列表】数据库') +refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'gfwlist_url', 'https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt') .. " > /tmp/gfw.b64" +sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") +if sret == 0 then + luci.sys.call("/usr/bin/ssr-gfw") + icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l") + if tonumber(icount) > 1000 then + if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then + oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l") else - icount = luci.sys.exec("cat /tmp/ssr-update." .. type .. " | wc -l") - luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file) - if file2 then luci.sys.exec("cp -f /tmp/ssr-update." .. type .. " " .. file2) end - log("更新成功! 新的总纪录数:" .. tostring(tonumber(icount)/Num)) + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf") + luci.sys.exec("cp -f /tmp/gfwnew.txt /tmp/dnsmasq.ssr/gfw_list.conf") + log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount)/2)) + else + log('你已经是最新数据,无需更新!') end else - log("更新失败!") + log('更新失败!') end - luci.sys.exec("rm -f /tmp/ssr-update." .. type) + luci.sys.exec("rm -f /tmp/gfwnew.txt") +else + log('更新失败!') end -log("正在更新【GFW列表】数据库") -update(uci:get_first("shadowsocksr", "global", "gfwlist_url", "https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt"), "/etc/dnsmasq.ssr/gfw_list.conf", "gfw_data", "/tmp/dnsmasq.ssr/gfw_list.conf") -log("正在更新【国内IP段】数据库") -update(uci:get_first("shadowsocksr", "global", "chnroute_url","https://ispip.clang.cn/all_cn.txt"), "/etc/ssr/china_ssr.txt", "cnip") -if uci:get_first("shadowsocksr", "global", "adblock","0") == "1" then - log("正在更新【广告屏蔽】数据库") - update(uci:get_first("shadowsocksr", "global", "adblock_url","https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt"), "/etc/dnsmasq.ssr/ad.conf", "ad_data", "/tmp/dnsmasq.ssr/ad.conf") +log('正在更新【国内IP段】数据库') +refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'chnroute_url','https://ispip.clang.cn/all_cn.txt') .. " > /tmp/china_ssr.txt" +sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") +icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") +if sret == 0 then + icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") + if tonumber(icount) > 1000 then + if nixio.fs.access("/etc/china_ssr.txt") then + oldcount = luci.sys.exec("cat /etc/china_ssr.txt | wc -l") + else + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt") + log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount))) + else + log('你已经是最新数据,无需更新!') + end + else + log('更新失败!') + end + luci.sys.exec("rm -f /tmp/china_ssr.txt") +else + log('更新失败!') end --- log("正在更新【Netflix IP段】数据库") --- update(uci:get_first("shadowsocksr", "global", "nfip_url","https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt"), "/etc/ssr/netflixip.list", "nfip_data") + +if uci:get_first('shadowsocksr', 'global', 'adblock','0') == "1" then + log('正在更新【广告屏蔽】数据库') + refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'adblock_url','https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt') .. " > /tmp/adnew.conf" + sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") + if sret == 0 then + luci.sys.call("/usr/bin/ssr-ad") + icount = luci.sys.exec("cat /tmp/ad.conf | wc -l") + if tonumber(icount) > 100 then + if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then + oldcount = luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l") + else + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf") + luci.sys.exec("cp -f /tmp/ad.conf /tmp/dnsmasq.ssr/ad.conf") + log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount))) + else + log('你已经是最新数据,无需更新!') + end + else + log('更新失败!') + end + luci.sys.exec("rm -f /tmp/ad.conf") + else + log('更新失败!') + end +end + +--[[ +log('正在更新【Netflix IP段】数据库') +refresh_cmd = "wget-ssl --no-check-certificate -O- " .. uci:get_first('shadowsocksr', 'global', 'nfip_url','https://raw.githubusercontent.com/QiuSimons/Netflix_IP/master/NF_only.txt') .. " > /tmp/netflixip.list" +sret = luci.sys.call(refresh_cmd .. " 2>/dev/null") +if sret == 0 then + luci.sys.call("/usr/bin/ssr-gfw") + icount = luci.sys.exec("cat /tmp/netflixip.list | wc -l") + if tonumber(icount) > 5 then + if nixio.fs.access("/etc/config/netflixip.list") then + oldcount = luci.sys.exec("cat /etc/config/netflixip.list | wc -l") + else + oldcount = "0" + end + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/netflixip.list /etc/config/netflixip.list") + log('更新成功! 新的总纪录数:' .. tostring(tonumber(icount))) + else + log('你已经是最新数据,无需更新!') + end + else + log('更新失败!') + end + luci.sys.exec("rm -f /tmp/netflixip.list") +else + log('更新失败!') +end +--]] From 2284f0da80b8afe5bd3a8fc0b8593e4a875993e1 Mon Sep 17 00:00:00 2001 From: HQ Ong Date: Wed, 15 Apr 2020 20:40:07 +0800 Subject: [PATCH 26/27] Add ACL rule to compatible with trunk Luci requirement (#4323) Add ACL rule to compatible with trunk Luci requirement --- package/lean/luci-app-ssr-plus/Makefile | 3 +++ .../root/usr/share/rpcd/acl.d/luci-app-ssr-plus.json | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 package/lean/luci-app-ssr-plus/root/usr/share/rpcd/acl.d/luci-app-ssr-plus.json diff --git a/package/lean/luci-app-ssr-plus/Makefile b/package/lean/luci-app-ssr-plus/Makefile index 17fa2180af..8e64aa7d03 100644 --- a/package/lean/luci-app-ssr-plus/Makefile +++ b/package/lean/luci-app-ssr-plus/Makefile @@ -94,6 +94,9 @@ define Package/$(PKG_NAME)/install $(INSTALL_DIR) $(1)/usr/share/shadowsocksr $(INSTALL_BIN) ./root/usr/share/shadowsocksr/*.sh $(1)/usr/share/shadowsocksr/ $(INSTALL_DATA) ./root/usr/share/shadowsocksr/*.lua $(1)/usr/share/shadowsocksr/ + + $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d + $(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/* $(1)/usr/share/rpcd/acl.d $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller $(INSTALL_DATA) ./luasrc/controller/*.lua $(1)/usr/lib/lua/luci/controller/ diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/rpcd/acl.d/luci-app-ssr-plus.json b/package/lean/luci-app-ssr-plus/root/usr/share/rpcd/acl.d/luci-app-ssr-plus.json new file mode 100644 index 0000000000..4efc8fc531 --- /dev/null +++ b/package/lean/luci-app-ssr-plus/root/usr/share/rpcd/acl.d/luci-app-ssr-plus.json @@ -0,0 +1,11 @@ +{ + "luci-app-ssr-plus": { + "description": "Grant UCI access for luci-app-ssr-plus", + "read": { + "uci": [ "shadowsocksr" ] + }, + "write": { + "uci": [ "shadowsocksr" ] + } + } +} From 7262d9503e38573fa24cb3ab7d3425d7e1895b62 Mon Sep 17 00:00:00 2001 From: lean Date: Wed, 15 Apr 2020 20:42:20 +0800 Subject: [PATCH 27/27] luci-app-ssr-plus:hide ssr server option when shadowsocks-libev-ss-server is not installed --- .../luasrc/model/cbi/shadowsocksr/server-config.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua index c7d9021563..8fa5024d74 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua @@ -1,5 +1,8 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. +require "luci.http" +require "luci.dispatcher" +require "nixio.fs" local m, s, o local shadowsocksr = "shadowsocksr" @@ -61,8 +64,10 @@ o.default = 1 o.rmempty = false o = s:option(ListValue, "type", translate("Server Type")) -o:value("ssr", translate("ShadowsocksR")) o:value("socks5", translate("Socks5")) +if nixio.fs.access("/usr/bin/ss-server") then +o:value("ssr", translate("ShadowsocksR")) +end o.default = "socks5" o = s:option(Value, "server_port", translate("Server Port"))