diff --git a/bpftools/Makefile b/bpftools/Makefile new file mode 100644 index 000000000..f044cc81f --- /dev/null +++ b/bpftools/Makefile @@ -0,0 +1,169 @@ +# +# Copyright (C) 2020 Tony Ambardar +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=bpftools +PKG_VERSION:=5.11.16 +PKG_RELEASE:=1 + +PKG_SOURCE:=linux-$(PKG_VERSION).tar.xz +PKG_SOURCE_URL:=@KERNEL/linux/kernel/v5.x +PKG_HASH:=21163681d130cbce5a6be39019e2c69e44f284855ddd70b1a3bd039249540f43 + +PKG_MAINTAINER:=Tony Ambardar + +PKG_USE_MIPS16:=0 +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +LINUX_VERSION:=$(PKG_VERSION) +LINUX_TLD:=linux-$(LINUX_VERSION) + +BPF_FILES:= \ + kernel/bpf scripts tools/Makefile tools/bpf tools/perf/perf-sys.h \ + tools/arch tools/build tools/include tools/lib tools/scripts +TAR_OPTIONS+= \ + --transform="s;$(LINUX_TLD)/;$(PKG_NAME)-$(PKG_VERSION)/;" \ + $(addprefix $(LINUX_TLD)/,$(BPF_FILES)) + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/nls.mk + +define Package/bpftool/Default + SECTION:=net + CATEGORY:=Network + TITLE:=bpftool - eBPF subsystem utility + LICENSE:=GPL-2.0-only OR BSD-2-Clause + URL:=http://www.kernel.org + DEPENDS:=+libelf +endef + +define Package/bpftool-minimal + $(call Package/bpftool/Default) + TITLE+= (Minimal) + VARIANT:=minimal + DEFAULT_VARIANT:=1 + PROVIDES:=bpftool + ALTERNATIVES:=200:/usr/sbin/bpftool:/usr/libexec/bpftool-minimal +endef + +define Package/bpftool-full + $(call Package/bpftool/Default) + TITLE+= (Full) + VARIANT:=full + PROVIDES:=bpftool + ALTERNATIVES:=300:/usr/sbin/bpftool:/usr/libexec/bpftool-full + DEPENDS+= +libbfd +libopcodes +endef + +define Package/bpftool-minimal/description + A tool for inspection and simple manipulation of eBPF programs and maps. +endef + +define Package/bpftool-full/description + A tool for inspection and simple manipulation of eBPF programs and maps. + This full version uses libbfd and libopcodes to support disassembly of + eBPF programs and jited code. +endef + +define Package/libbpf + SECTION:=libs + CATEGORY:=Libraries + TITLE:=libbpf - eBPF helper library + VARIANT:=lib + LICENSE:=LGPL-2.1 OR BSD-2-Clause + ABI_VERSION:=0 + URL:=http://www.kernel.org + DEPENDS:=+libelf +endef + +define Package/libbpf/description + libbpf is a library for loading eBPF programs and reading and manipulating eBPF objects from user-space. +endef + + +# LTO not compatible with DSO using PIC +ifneq ($(BUILD_VARIANT),lib) + TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto + TARGET_LDFLAGS += -Wl,--gc-sections +endif + +MAKE_VARS = \ + EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" + +MAKE_FLAGS += \ + BPFTOOL_VERSION="$(LINUX_VERSION)" \ + FEATURES_DUMP="$(PKG_BUILD_DIR)/FEATURE-DUMP.openwrt" \ + OUTPUT="$(PKG_BUILD_DIR)/" \ + prefix="/usr" \ + $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') + +ifeq ($(BUILD_VARIANT),full) + HAVE_LIBBFD:=1 + HAVE_LIBCAP:=0 + HAVE_CLANG:=0 + MAKE_PATH:=tools/bpf/bpftool +else ifeq ($(BUILD_VARIANT),minimal) + HAVE_LIBBFD:=0 + HAVE_LIBCAP:=0 + HAVE_CLANG:=0 + MAKE_PATH:=tools/bpf/bpftool +else ifeq ($(BUILD_VARIANT),lib) + HAVE_LIBBFD:=0 + HAVE_LIBCAP:=0 + HAVE_CLANG:=0 + MAKE_PATH:=tools/lib/bpf +endif + +# Perform a "throw-away" make to create a FEATURE-DUMP.* file to edit later. +# The "//" in the make target is actually needed, very unPOSIXly. +define Build/Configure + +$(MAKE_VARS) $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/tools/bpf/bpftool \ + $(MAKE_FLAGS) FEATURES_DUMP= $(PKG_BUILD_DIR)//libbpf/libbpf.a + (cd $(PKG_BUILD_DIR); cat FEATURE-DUMP.bpftool libbpf/FEATURE-DUMP.libbpf \ + | sort | uniq > FEATURE-DUMP.openwrt) + $(SED) 's/feature-libbfd=1/feature-libbfd=$(HAVE_LIBBFD)/' \ + -e 's/feature-libcap=1/feature-libcap=$(HAVE_LIBCAP)/' \ + -e 's/feature-clang-bpf-co-re=1/feature-clang-bpf-co-re=$(HAVE_CLANG)/' \ + $(PKG_BUILD_DIR)/FEATURE-DUMP.openwrt +endef + +define Build/InstallDev/libbpf + $(INSTALL_DIR) $(1)/usr/include/bpf + $(CP) $(PKG_INSTALL_DIR)/usr/include/bpf/*.h $(1)/usr/include/bpf/ + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib$(LIB_SUFFIX)/libbpf.{a,so*} \ + $(1)/usr/lib/ + $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(CP) $(PKG_INSTALL_DIR)/usr/lib$(LIB_SUFFIX)/pkgconfig/libbpf.pc \ + $(1)/usr/lib/pkgconfig/ + $(SED) 's,/usr/include,$$$${prefix}/include,g' \ + $(1)/usr/lib/pkgconfig/libbpf.pc + $(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \ + $(1)/usr/lib/pkgconfig/libbpf.pc +endef + +ifeq ($(BUILD_VARIANT),lib) + Build/InstallDev=$(Build/InstallDev/libbpf) +endif + +define Package/bpftool-$(BUILD_VARIANT)/install + $(INSTALL_DIR) $(1)/usr/libexec + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/bpftool \ + $(1)/usr/libexec/bpftool-$(BUILD_VARIANT) +endef + +define Package/libbpf/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib$(LIB_SUFFIX)/libbpf.so.* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libbpf)) +$(eval $(call BuildPackage,bpftool-full)) +$(eval $(call BuildPackage,bpftool-minimal)) diff --git a/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch b/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch new file mode 100644 index 000000000..996ffc43e --- /dev/null +++ b/bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch @@ -0,0 +1,51 @@ +From afe3f4c765b17ced23811fe652c7f7adf7a0c0cf Mon Sep 17 00:00:00 2001 +From: Tony Ambardar +Date: Mon, 14 Sep 2020 23:05:26 -0700 +Subject: [PATCH] tools/arch/powerpc: fix EDEADLOCK redefinition errors in + errno.h + +A few archs like powerpc have different errno.h values for macros +EDEADLOCK and EDEADLK. In code including both libc and linux versions of +errno.h, this can result in multiple definitions of EDEADLOCK in the +include chain. Definitions to the same value (e.g. seen with mips) do +not raise warnings, but on powerpc there are redefinitions changing the +value, which raise warnings and errors (with "-Werror"). + +Guard against these redefinitions to avoid build errors like the following, +first seen cross-compiling libbpf v5.8.9 for powerpc using GCC 8.4.0 with +musl 1.1.24: + + In file included from ../../arch/powerpc/include/uapi/asm/errno.h:5, + from ../../include/linux/err.h:8, + from libbpf.c:29: + ../../include/uapi/asm-generic/errno.h:40: error: "EDEADLOCK" redefined [-Werror] + #define EDEADLOCK EDEADLK + + In file included from toolchain-powerpc_8540_gcc-8.4.0_musl/include/errno.h:10, + from libbpf.c:26: + toolchain-powerpc_8540_gcc-8.4.0_musl/include/bits/errno.h:58: note: this is the location of the previous definition + #define EDEADLOCK 58 + + cc1: all warnings being treated as errors + make[5]: *** [target-powerpc_8540_musl/bpftools-5.8.9/tools/build/Makefile.build:97: /home/kodidev/openwrt-project/build_dir/target-powerpc_8540_musl/bpftools-minimal/bpftools-5.8.9//libbpf/staticobjs/libbpf.o] Error 1 + +Fixes: 95f28190aa01 ("tools include arch: Grab a copy of errno.h for arch's + supported by perf") +Fixes: c3617f72036c ("UAPI: (Scripted) Disintegrate arch/powerpc/include/asm") + +Reported-by: Rosen Penev +Signed-off-by: Tony Ambardar +--- + tools/arch/powerpc/include/uapi/asm/errno.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/tools/arch/powerpc/include/uapi/asm/errno.h ++++ b/tools/arch/powerpc/include/uapi/asm/errno.h +@@ -2,6 +2,7 @@ + #ifndef _ASM_POWERPC_ERRNO_H + #define _ASM_POWERPC_ERRNO_H + ++#undef EDEADLOCK + #include + + #undef EDEADLOCK diff --git a/dnsforwarder/Makefile b/dnsforwarder/Makefile new file mode 100644 index 000000000..05e7370a0 --- /dev/null +++ b/dnsforwarder/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (C) 2021 ImmortalWrt +# +# +# This is free software, licensed under the GNU General Public License v3. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=dnsforwarder +PKG_VERSION:=6.1.15 +PKG_RELEASE:=11 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/1715173329/dnsforwarder.git +PKG_SOURCE_DATE:=2018-06-26 +PKG_SOURCE_VERSION:=587e61ae4d75dc976f538088b715a3c8ee26c144 +PKG_MIRROR_HASH:=7c141040ae384d254d90b3c3ee502d87330c9fdcd201ff29a669336a27b176d4 + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILE:=LICENSE +PKG_MAINTAINER:=Dennis + +PKG_FIXUP:=autoreconf +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/dnsforwarder + SECTION:=net + CATEGORY:=Network + TITLE:=A simple DNS forwarder + URL:=https://github.com/holmium/dnsforwarder + DEPENDS:=+coreutils +coreutils-base64 +dnsmasq-full +libpthread +wget-ssl +endef + +define Package/dnsforwarder/description + Forwarding queries to customized domains (and their subdomains) to specified servers + over a specified protocol (UDP or TCP). non-standard ports are supported. +endef + +CONFIGURE_ARGS+= --enable-downloader=wget + +define Package/dnsforwarder/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dnsforwarder $(1)/usr/bin/dnsforwarder + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) files/etc/config/dnsforwarder $(1)/etc/config/dnsforwarder + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) files/etc/init.d/dnsforwarder $(1)/etc/init.d/dnsforwarder + + $(INSTALL_DIR) $(1)/etc/dnsforwarder + $(INSTALL_CONF) files/etc/dnsforwarder/gfw.txt $(1)/etc/dnsforwarder/gfw.txt + $(INSTALL_DIR) $(1)/usr/share/dnsforwarder + $(INSTALL_BIN) files/usr/share/dnsforwarder/gfwlist.sh $(1)/usr/share/dnsforwarder/gfwlist.sh +endef + +$(eval $(call BuildPackage,dnsforwarder)) diff --git a/dnsforwarder/files/etc/config/dnsforwarder b/dnsforwarder/files/etc/config/dnsforwarder new file mode 100644 index 000000000..da025f7a8 --- /dev/null +++ b/dnsforwarder/files/etc/config/dnsforwarder @@ -0,0 +1,79 @@ + +config arguments + option enabled '0' + option addr '127.0.0.1:5053' + +config config + option cache 'true' + option cache_size '102400' + option cache_ignore 'false' + option gfw 'true' + list block_ip '74.125.127.102' + list block_ip '74.125.155.102' + list block_ip '74.125.39.102' + list block_ip '74.125.39.113' + list block_ip '209.85.229.138' + list block_ip '128.121.126.139' + list block_ip '159.106.121.75' + list block_ip '169.132.13.103' + list block_ip '192.67.198.6' + list block_ip '202.106.1.2' + list block_ip '202.181.7.85' + list block_ip '203.161.230.171' + list block_ip '203.98.7.65' + list block_ip '207.12.88.98' + list block_ip '208.56.31.43' + list block_ip '209.145.54.50' + list block_ip '209.220.30.174' + list block_ip '209.36.73.33' + list block_ip '211.94.66.147' + list block_ip '213.169.251.35' + list block_ip '216.221.188.182' + list block_ip '216.234.179.13' + list block_ip '243.185.187.39' + list block_ip '37.61.54.158' + list block_ip '4.36.66.178' + list block_ip '46.82.174.68' + list block_ip '59.24.3.173' + list block_ip '64.33.88.161' + list block_ip '64.33.99.47' + list block_ip '64.66.163.251' + list block_ip '65.104.202.252' + list block_ip '65.160.219.113' + list block_ip '66.45.252.237' + list block_ip '69.55.52.253' + list block_ip '72.14.205.104' + list block_ip '72.14.205.99' + list block_ip '78.16.49.15' + list block_ip '8.7.198.45' + list block_ip '93.46.8.89' + list block_ip '37.61.54.158' + list block_ip '243.185.187.39' + list block_ip '190.93.247.4' + list block_ip '190.93.246.4' + list block_ip '190.93.245.4' + list block_ip '190.93.244.4' + list block_ip '65.49.2.178' + list block_ip '189.163.17.5' + list block_ip '23.89.5.60' + list block_ip '49.2.123.56' + list block_ip '54.76.135.1' + list block_ip '77.4.7.92' + list block_ip '118.5.49.6' + list block_ip '159.24.3.173' + list block_ip '188.5.4.96' + list block_ip '197.4.4.12' + list block_ip '220.250.64.24' + list block_ip '243.185.187.30' + list block_ip '249.129.46.48' + list block_ip '253.157.14.165' + option block_ipv6 'false' + list cache_control 'tossp.com $orig' + list cache_control '* fixed 3600' + option log 'false' + list udp_group '9.9.9.9,119.29.29.29,223.5.5.5,114.114.114.114 * on' + option block_negative_resp 'true' + list udp_local '0.0.0.0:5053' + list udp_local '[::0]:5053' + option domain_statistic 'false' + diff --git a/dnsforwarder/files/etc/dnsforwarder/gfw.txt b/dnsforwarder/files/etc/dnsforwarder/gfw.txt new file mode 100644 index 000000000..0bd285173 --- /dev/null +++ b/dnsforwarder/files/etc/dnsforwarder/gfw.txt @@ -0,0 +1,5605 @@ +# GenerationAt 2018-12-09 23:29:36 +protocol tcp +server 8.8.8.8,8.8.4.4,1.1.1.1,1.0.0.1,208.67.222.222,208.67.220.220,209.244.0.3,209.244.0.4,8.26.56.26,8.20.247.20,156.154.70.1,156.154.71.1,199.85.126.10 +proxy no + + +030buy.com +0rz.tw +1-apple.com.tw +10.tt +1000giri.net +100ke.org +10conditionsoflove.com +10musume.com +123rf.com +12bet.com +12vpn.com +12vpn.net +138.com +141hongkong.com +141jj.com +141tube.com +1688.com.au +173ng.com +177pic.info +17t17p.com +18board.com +18board.info +18onlygirls.com +18p2p.com +18virginsex.com +1949er.org +1984bbs.com +1984bbs.org +1989report.hkja.org.hk +1991way.com +1998cdp.org +1bao.org +1dumb.com +1e100.net +1eew.com +1mobile.com +1mobile.tw +1pondo.tv +2-hand.info +2000fun.com +2008xianzhang.info +2017.hk +21andy.com +21pron.com +21sextury.com +228.net.tw +233abc.com +24hrs.ca +24smile.org +25u.com +2lipstube.com +2shared.com +2waky.com +3-a.net +30boxes.com +315lz.com +32red.com +36rain.com +3a5a.com +3arabtv.com +3boys2girls.com +3d-game.com +3proxy.ru +3ren.ca +3tui.net +466453.com +4bluestones.biz +4chan.com +4dq.com +4everproxy.com +4irc.com +4mydomain.com +4pu.com +4rbtv.com +4shared.com +4sqi.net +51.ca +51jav.org +51luoben.com +5278.cc +56cun04.jigsy.com +5aimiku.com +5i01.com +5isotoi5.org +5maodang.com +63i.com +64museum.org +64tianwang.com +64wiki.com +66.ca +666kb.com +6park.com +6parker.com +7capture.com +7cow.com +8-d.com +85cc.net +85cc.us +85st.com +881903.com +888.com +888poker.com +89-64.org +89.64.charter.constitutionalism.solutions +8news.com.tw +8z1.net +9001700.com +908taiwan.org +91porn.com +91vps.club +92ccav.com +991.com +99btgc01.com +99cn.info +9bis.com +9bis.net +a-normal-day.com +a248.e.akamai.net +a5.com.ru +aamacau.com +abc.com +abc.net.au +abc.pp.ru +abc.xyz +abchinese.com +abclite.net +abematv.akamaized.net +abitno.linpie.com +ablwang.com +aboluowang.com +aboutgfw.com +abs.edu +ac.jiruan.net +accim.org +aceros-de-hispania.com +acevpn.com +acg18.me +acgkj.com +acmedia365.com +acmetoy.com +acnw.com.au +actfortibet.org +actimes.com.au +activpn.com +aculo.us +adcex.com +addictedtocoffee.de +adelaidebbs.com +admin.recaptcha.net +admob.com +adpl.org.hk +ads-twitter.com +adsense.com +adult-sex-games.com +adult.friendfinder.com +adultfriendfinder.com +adultkeep.net +advanscene.com +advertfan.com +ae.hao123.com +ae.org +aenhancers.com +af.mil +afantibbs.com +agnesb.fr +agoogleaday.com +agro.hk +ai-kan.net +ai-wen.net +ai.binwang.me +ai.google +aiph.net +airasia.com +airconsole.com +airvpn.org +aisex.com +aiss.anws.gov.tw +ait.org.tw +aiweiwei.com +aiweiweiblog.com +akademiye.org +akamaihd.net +akiba-online.com +akiba-web.com +akow.org +al-islam.com +al-qimmah.net +alabout.com +alanhou.com +alarab.qa +alasbarricadas.org +alexlur.org +alforattv.net +alhayat.com +alicejapan.co.jp +aliengu.com +alkasir.com +allcoin.com +allconnected.co +alldrawnsex.com +allervpn.com +allfinegirls.com +allgirlmassage.com +allgirlsallowed.org +allgravure.com +alliance.org.hk +allinfa.com +alljackpotscasino.com +allmovie.com +allowed.org +almasdarnews.com +almostmy.com +alphaporno.com +alternate-tools.com +alternativeto.net +altrec.com +alvinalexander.com +alwaysdata.com +alwaysdata.net +alwaysvpn.com +am730.com.hk +amazon.co.jp +amazon.com +ameblo.jp +americangreencard.com +americanunfinished.com +amiblockedornot.com +amigobbs.net +amitabhafoundation.us +amnesty.org +amnesty.org.hk +amnesty.tw +amnestyusa.org +amnyemachen.org +amoiist.com +ampproject.org +amtb-taipei.org +anchorfree.com +ancsconf.org +andfaraway.net +android-x86.org +android.com +androidify.com +androidplus.co +andygod.com +angelfire.com +angularjs.org +animecrazy.net +animeshippuuden.com +aniscartujo.com +annatam.com +anobii.com +anontext.com +anonymise.us +anonymitynetwork.com +anonymizer.com +anpopo.com +answering-islam.org +anthonycalzadilla.com +anti1984.com +antichristendom.com +antiwave.net +anyporn.com +anysex.com +aobo.com.au +aofriend.com +aofriend.com.au +aojiao.org +aolchannels.aol.com +aomiwang.com +apartmentratings.com +apartments.com +apetube.com +api-secure.recaptcha.net +api-verify.recaptcha.net +api.ai +api.dropboxapi.com +api.linksalpha.com +api.proxlet.com +api.pureapk.com +api.recaptcha.net +apiary.io +apidocs.linksalpha.com +apigee.com +apk-dl.com +apkdler.com +apkmirror.com +apkmonk.com +apkplz.com +apkpure.com +aplusvpn.com +app.box.com +app.heywire.com +app.smartmailcloud.com +app.tutanota.com +appdownloader.net +appledaily.com +appledaily.com.hk +appledaily.com.tw +appshopper.com +appsocks.net +appspot.com +appsto.re +aptoide.com +ar.hao123.com +archive.fo +archive.is +archive.li +archive.org +archive.today +archives.gov +archives.gov.tw +arctosia.com +areca-backup.org +arena.taipei +arethusa.su +arlingtoncemetery.mil +army.mil +art4tibet1998.org +artofpeacefoundation.org +artsy.net +asacp.org +asahichinese.com +asdfg.jp +asg.to +asia-gaming.com +asiaharvest.org +asianews.it +asiansexdiary.com +asianspiss.com +asianwomensfilm.de +asiatgp.com +asiatoday.us +askstudent.com +askynz.net +assembla.com +assimp.org +astrill.com +atc.org.au +atchinese.com +atdmt.com +atgfw.org +athenaeizou.com +atlanta168.com +atlaspost.com +atnext.com +authorizeddns.net +authorizeddns.org +authorizeddns.us +autodraw.com +av-e-body.com +av.com +av.movie +av.nightlife141.com +avaaz.org +avbody.tv +avcity.tv +avcool.com +avdb.in +avdb.tv +avfantasy.com +avgle.com +avidemux.org +avmo.pw +avmoo.com +avmoo.net +avmoo.pw +avoision.com +avyahoo.com +axureformac.com +azerbaycan.tv +azerimix.com +azubu.tv +azurewebsites.net +b0ne.com +babynet.com.hk +backchina.com +backpackers.com.tw +backtotiananmen.com +badiucao.com +badjojo.com +badoo.com +bahamut.com.tw +baidu.jp +baijie.org +bailandaily.com +baixing.me +bakgeekhome.tk +banana-vpn.com +bandwagonhost.com +bangbrosnetwork.com +bangchen.net +bangyoulater.com +bankmobilevibe.com +bannedbook.org +bannednews.org +banorte.com +baramangaonline.com +barenakedislam.com +barnabu.co.uk +bartvpn.com +bash-hackers.org +bastillepost.com +bayvoice.net +bb-chat.tv +bb.ttv.com.tw +bbc.co.uk +bbc.com +bbc.in +bbcchinese.com +bbchat.tv +bbci.co.uk +bbg.gov +bbkz.com +bbnradio.org +bbs-tw.com +bbs.brockbbs.com +bbs.cantonese.asia +bbs.ecstart.com +bbs.hanminzu.org +bbs.hasi.wang +bbs.huasing.org +bbs.junglobal.net +bbs.kimy.com.tw +bbs.morbell.com +bbs.mychat.to +bbs.netbig.com +bbs.ozchinese.com +bbs.qmzdd.com +bbs.sina.com +bbs.skykiwi.com +bbs.sou-tong.org +bbs.tuitui.info +bbsdigest.com +bbsfeed.com +bbsland.com +bbsmo.com +bbsone.com +bbtoystore.com +bcast.co.nz +bcc.com.tw +bcchinese.net +bcex.ca +bcmorning.com +bdsmvideos.net +beaconevents.com +bebo.com +beeg.com +beevpn.com +behance.net +behindkink.com +beijing1989.com +beijingspring.com +beijingzx.org +belamionline.com +bell.wiki +bemywife.cc +beric.me +berlintwitterwall.com +berm.co.nz +bestforchina.org +bestgore.com +bestpornstardb.com +bestvpn.com +bestvpnanalysis.com +bestvpnserver.com +bestvpnservice.com +bestvpnusa.com +bet365.com +betfair.com +betternet.co +bettervpn.com +bettween.com +betvictor.com +bewww.net +beyondfirewall.com +bfnn.org +bfsh.hk +bgvpn.com +bianlei.com +biantailajiao.com +biantailajiao.in +biblesforamerica.org +bibox.com +bic2011.org +big.one +bigfools.com +bigjapanesesex.com +bigmoney.biz +bignews.org +bigsound.org +biliworld.com +billypan.com +binance.com +binux.me +bipic.net +bird.so +bit-z.com +bit.do +bit.ly +bitc.bme.emory.edu +bitcointalk.org +bitcoinworld.com +bitfinex.com +bitinka.com.ar +bitmex.com +bitshare.com +bitsnoop.com +bitvise.com +bizhat.com +bjnewlife.org +bjs.org +bjzc.org +bl-doujinsouko.com +blacklogic.com +blackvpn.com +blewpass.com +blinkx.com +blinw.com +blip.tv +blockcn.com +blockless.com +blog.calibre-ebook.com +blog.cnyes.com +blog.daum.net +blog.de +blog.exblog.co.jp +blog.excite.co.jp +blog.expofutures.com +blog.fizzik.com +blog.foolsmountain.com +blog.fuckgfw233.org +blog.goo.ne.jp +blog.google +blog.inoreader.com +blog.istef.info +blog.jackjia.com +blog.jp +blog.kangye.org +blog.lester850.info +blog.martinoei.com +blog.pathtosharepoint.com +blog.pentalogic.net +blog.qooza.hk +blog.ranxiang.com +blog.sina.com.tw +blog.sogoo.org +blog.soylent.com +blog.syx86.cn +blog.syx86.com +blog.taragana.com +blog.tiney.com +blog.xuite.net +blog.youthwant.com.tw +blog.youxu.info +blogblog.com +blogcatalog.com +blogcity.me +blogdns.org +blogger.com +blogimg.jp +bloglines.com +bloglovin.com +blogs.icerocket.com +blogs.libraryinformationtechnology.com +blogs.tampabay.com +blogs.yahoo.co.jp +blogspot.ae +blogspot.al +blogspot.am +blogspot.ba +blogspot.be +blogspot.bg +blogspot.ca +blogspot.cat +blogspot.ch +blogspot.cl +blogspot.co.uk +blogspot.com +blogspot.com.ar +blogspot.com.au +blogspot.com.br +blogspot.com.by +blogspot.com.co +blogspot.com.cy +blogspot.com.ee +blogspot.com.eg +blogspot.com.es +blogspot.com.mt +blogspot.com.ng +blogspot.com.tr +blogspot.com.uy +blogspot.cz +blogspot.de +blogspot.dk +blogspot.fi +blogspot.fr +blogspot.gr +blogspot.hk +blogspot.hr +blogspot.hu +blogspot.ie +blogspot.in +blogspot.is +blogspot.it +blogspot.jp +blogspot.kr +blogspot.li +blogspot.lt +blogspot.lu +blogspot.md +blogspot.mk +blogspot.mx +blogspot.my +blogspot.nl +blogspot.no +blogspot.pe +blogspot.pt +blogspot.qa +blogspot.ro +blogspot.ru +blogspot.se +blogspot.sg +blogspot.si +blogspot.sk +blogspot.sn +blogspot.tw +blogspot.ug +blogtd.net +blogtd.org +bloodshed.net +bloomberg.cn +bloomberg.com +bloomberg.de +bloombergview.com +bloomfortune.com +blueangellive.com +bmfinn.com +bnews.co +bnrmetal.com +boardreader.com +bod.asia +bodog88.com +bolehvpn.net +bolin.netfirms.com +bonbonme.com +bonbonsex.com +bonfoundation.org +bongacams.com +boobstagram.com +book.com.tw +book.zi5.me +bookepub.com +books.com.tw +booktopia.com.au +boomssr.com +bot.nu +botanwang.com +bowenpress.com +boxpn.com +boxun.com +boxun.tv +boxunblog.com +boxunclub.com +boyangu.com +boyfriendtv.com +boysfood.com +boysmaster.com +br.hao123.com +br.st +brainyquote.com +brandonhutchinson.com +braumeister.org +bravotube.net +brazzers.com +break.com +breakgfw.com +breaking911.com +breakingtweets.com +breakwall.net +briefdream.com +briian.com +brizzly.com +brkmd.com +broadbook.com +broadpressinc.com +brucewang.net +brutaltgp.com +bt2mag.com +bt95.com +btaia.com +btbtav.com +btcbank.bank +btctrade.im +btdigg.org +btku.me +btku.org +btspread.com +btsynckeys.com +budaedu.org +buddhanet.com.tw +buddhistchannel.tv +buffered.com +bullog.org +bullogger.com +bunbunhk.com +busayari.com +businessinsider.com +businessweek.com +busu.org +busytrade.com +buugaa.com +buy.yahoo.com.tw +buzzhand.com +buzzhand.net +buzzorange.com +bvpn.com +bwh1.net +bwsj.hk +bx.in.th +bx.tl +bynet.co.il +c-est-simple.com +c-spanvideo.org +c100tibet.org +c1522.mooo.com +c2cx.com +cablegatesearch.net +cachinese.com +cacnw.com +cactusvpn.com +cafepress.com +cahr.org.tw +calameo.com +calebelston.com +calgarychinese.ca +calgarychinese.com +calgarychinese.net +cam4.com +cam4.jp +cam4.sg +camfrog.com +cams.com +cams.org.sg +canadameet.com +canalporno.com +canyu.org +cao.im +caobian.info +caochangqing.com +cap.org.hk +carabinasypistolas.com +cardinalkungfoundation.org +carfax.com +cari.com.my +caribbeancom.com +carmotorshow.com +cartoonmovement.com +casadeltibetbcn.org +casatibet.org.mx +casino.williamhill.com +casinobellini.com +casinoking.com +casinoriva.com +castbox.fm +catch22.net +catchgod.com +catfightpayperview.xxx +catholic.org.hk +catholic.org.tw +cathvoice.org.tw +cattt.com +cbc.ca +cbs.ntu.edu.tw +cbsnews.com +cbtc.org.hk +cccat.cc +cccat.co +ccdtr.org +cchere.com +ccim.org +cclife.ca +cclife.org +cclifefl.org +ccthere.com +cctmweb.net +cctongbao.com +ccue.ca +ccue.com +ccvoice.ca +ccw.org.tw +cdbook.org +cdcparty.com +cdef.org +cdig.info +cdjp.org +cdn-apple.com +cdn-images.mailchimp.com +cdn.assets.lfpcontent.com +cdn.helixstudios.net +cdn.printfriendly.com +cdn.seatguru.com +cdn.softlayer.net +cdn1.lp.saboom.com +cdnews.com.tw +cdninstagram.com +cdp1989.org +cdp1998.org +cdp2006.org +cdpa.url.tw +cdpeu.org +cdpusa.org +cdpweb.org +cdpwu.org +cdw.com +cecc.gov +cellulo.info +cenews.eu +centauro.com.br +centerforhumanreprod.com +centralnation.com +centurys.net +certificate-transparency.org +certificate.revocationcheck.com +cfhks.org.hk +cfos.de +cftfc.com +cgdepot.org +cgst.edu +ch.shvoong.com +change.org +changeip.name +changeip.net +changeip.org +changp.com +changsa.net +channel8news.sg +chaoex.com +chapm25.com +chatnook.com +chaturbate.com +chengmingmag.com +chenguangcheng.com +chenpokong.com +chenpokong.net +chenshan20042005.wordpress.com +cherrysave.com +chhongbi.org +chicagoncmtv.com +china-mmm.jp.net +china-mmm.net +china-mmm.sa.com +china-review.com.ua +china-week.com +china.hket.com +china.ucanews.com +china101.com +china18.org +china21.com +china21.org +china5000.us +chinaaffairs.org +chinaaid.me +chinaaid.net +chinaaid.org +chinaaid.us +chinachange.org +chinachannel.hk +chinacitynews.be +chinacomments.org +chinadialogue.net +chinadigitaltimes.net +chinaelections.org +chinaeweekly.com +chinafreepress.org +chinagate.com +chinageeks.org +chinagfw.org +chinagonet.com +chinagreenparty.org +chinahorizon.org +chinahush.com +chinainperspective.com +chinainterimgov.org +chinalaborwatch.org +chinalawandpolicy.com +chinalawtranslate.com +chinamule.com +chinamz.org +chinapost.com.tw +chinapress.com.my +chinarightsia.org +chinasmile.net +chinasocialdemocraticparty.com +chinasoul.org +chinasucks.net +chinatimes.com +chinatopsex.com +chinatown.com.au +chinatweeps.com +chinaview.wordpress.com +chinaway.org +chinaworker.info +chinaxchina.com +chinayouth.org.hk +chinayuanmin.org +chinese-hermit.net +chinese-leaders.org +chinese-memorial.org +chinese.donga.com +chinese.engadget.com +chinese.irib.ir +chinese.soifind.com +chinesedaily.com +chinesedailynews.com +chinesedemocracy.com +chinesegay.org +chinesen.de +chinesenews.net.au +chinesepen.org +chinesetalks.net +chineseupress.com +chingcheong.com +chinman.net +chithu.org +chn.chosun.com +chobit.cc +chrdnet.com +christianfreedom.org +christianstudy.com +christiantimes.org.hk +christusrex.org +chrlawyers.hk +chrome.com +chromecast.com +chromeexperiments.com +chromercise.com +chromestatus.com +chromium.org +chuang-yen.org +chubold.com +chubun.com +chuizi.net +churchinhongkong.org +chushigangdrug.ch +cienen.com +cineastentreff.de +cipfg.org +circlethebayfortibet.org +cirosantilli.com +citizencn.com +citizenlab.org +citizenscommission.hk +citizensradio.org +city365.ca +city9x.com +citypopulation.de +citytalk.tw +civicparty.hk +civildisobediencemovement.org +civilhrfront.org +civiliangunner.com +civilmedia.tw +ck101.com +cl.d0z.net +clarionproject.org +classicalguitarblog.net +clb.org.hk +cldr.unicode.org +cleansite.biz +cleansite.info +cleansite.us +clearharmony.net +clearsurance.com +clearwisdom.net +clementine-player.org +cling.omy.sg +clinica-tibet.ru +clipfish.de +cloakpoint.com +cloud.mail.ru +club1069.com +cmcn.org +cmi.org.tw +cmp.hku.hk +cms.gov +cmule.com +cmule.org +cmx.im +cn-proxy.com +cn.calameo.com +cn.dayabook.com +cn.fmnnow.com +cn.freeones.com +cn.giganews.com +cn.ibtimes.com +cn.nytstyle.com +cn.sandscotaicentral.com +cn.shafaqna.com +cn.streetvoice.com +cn.thegay.com +cn.uncyclopedia.wikia.com +cn.uptodown.com +cn.voa.mobi +cn2.streetvoice.com +cn6.eu +cna.com.tw +cnabc.com +cnbbnews.wordpress.com +cnd.org +cnex.org.cn +cnineu.com +cnn.com +cnnews.chosun.com +cnpolitics.org +cnproxy.com +co.ng.mil +coat.co.jp +cochina.co +cochina.org +code1984.com +codeshare.io +codeskulptor.org +coin2co.in +coinegg.com +coinex.com +coingi.com +coinrail.co.kr +cointobe.com +coinut.com +collateralmurder.com +collateralmurder.org +com.google +comefromchina.com +comic-mega.me +commandarms.com +commentshk.com +communistcrimes.org +community.windy.com +communitychoicecu.com +compileheart.com +compress.to +connect.facebook.net +conoha.jp +contactmagazine.net +contests.twilio.com +convio.net +coobay.com +coolaler.com +coolder.com +coolloud.org.tw +coolncute.com +coolstuffinc.com +corumcollege.com +cos-moe.com +cosmic.monar.ch +cosplayjav.pl +costco.com +cotweet.com +coursehero.com +cpj.org +cq99.us +crackle.com +crazys.cc +crazyshit.com +crbug.com +crchina.org +crd-net.org +creaders.net +creadersnet.com +creativelab5.com +crisisresponse.google +cristyli.com +crocotube.com +crossfire.co.kr +crossthewall.net +crossvpn.net +crrev.com +crucial.com +csdparty.com +css.pixnet.in +csuchen.de +csw.org.uk +ct.org.tw +ctao.org +ctfriend.net +cthlo.github.io +ctitv.com.tw +cts.com.tw +cuhkacs.org +cuihua.org +cuiweiping.net +culture.tw +cumlouder.com +curvefish.com +cusu.hk +cutscenes.net +cw.com.tw +cyberghost.natado.com +cyberghostvpn.com +cynscribe.com +cytode.us +d-fukyu.com +d100.net +d1b183sg0nvnuh.cloudfront.net +d1c37gjwa26taa.cloudfront.net +d2bay.com +d2pass.com +d3c33hcgiwev3.cloudfront.net +d3rhr7kgmtrq1v.cloudfront.net +dabr.co.uk +dabr.eu +dabr.me +dabr.mobi +dadazim.com +dadi360.com +dafabet.com +dafagood.com +dafahao.com +dafoh.org +daftporn.com +dagelijksestandaard.nl +daidostup.ru +dailidaili.com +dailymotion.com +dailynews.sina.com +daiphapinfo.net +dajiyuan.com +dajiyuan.de +dajiyuan.eu +dajusha.baywords.com +dalailama-archives.org +dalailama.com +dalailama.mn +dalailama.ru +dalailama.usc.edu +dalailama80.org +dalailamacenter.org +dalailamafellows.org +dalailamafilm.com +dalailamafoundation.org +dalailamahindi.com +dalailamainaustralia.org +dalailamajapanese.com +dalailamaprotesters.info +dalailamaquotes.org +dalailamatrust.org +dalailamavisit.org.nz +dalailamaworld.com +dalianmeng.org +daliulian.org +danbooru.donmai.us +danke4china.net +danwei.org +daodu14.jigsy.com +daolan.net +daozhongxing.org +darktech.org +darktoy.net +darpa.mil +dastrassi.org +data-vocabulary.org +data.flurry.com +data.gov.tw +david-kilgour.com +dawangidc.com +daxa.cn +daylife.com +db.tt +dbc.hk +dcard.tw +dcmilitary.com +ddc.com.tw +ddhw.info +ddns.info +ddns.me.uk +ddns.mobi +ddns.ms +ddns.name +ddns.net +ddns.us +de-sci.org +deaftone.com +debug.com +deck.ly +decodet.co +deepmind.com +deezer.com +definebabe.com +deja.com +delcamp.net +delicious.com +demo.opera-mini.net +democrats.org +depositphotos.com +derekhsu.homeip.net +desc.se +design.google +desipro.de +dessci.com +destiny.xfiles.to +destroy-china.jp +deutsche-welle.de +developers.box.net +devio.us +devpn.com +dfas.mil +dfn.org +dharamsalanet.com +dharmakara.net +dhcp.biz +diaoyuislands.org +dictionary.goo.ne.jp +difangwenge.org +digiland.tw +digisfera.com +digitalnomadsproject.org +diigo.com +dilber.se +dingchin.com.tw +dipity.com +directcreative.com +discoins.com +discordapp.com +discordapp.net +discuss.com.hk +discuss4u.com +dish.com +disp.cc +disqus.com +dit-inc.us +dizhidizhi.com +dizhuzhishang.com +djangosnippets.org +djorz.com +dl-laby.jp +dl.box.net +dlsite.com +dlyoutube.com +dm530.net +dmcdn.net +dmm.co.jp +dns-dns.com +dns-stuff.com +dns04.com +dns05.com +dns1.us +dns2.us +dns2go.com +dnscrypt.org +dnset.com +dnsrd.com +dnssec.net +dnvod.tv +doctorvoice.org +dogfartnetwork.com +dojin.com +dok-forum.net +dolc.de +dolf.org.hk +dollf.com +domain.club.tw +domainhelp.search.com +domains.google +domaintoday.com.au +dongtaiwang.com +dongtaiwang.net +dongyangjing.com +dontfilter.us +dontmovetochina.com +dorjeshugden.com +dotplane.com +dotsub.com +dotvpn.com +doub.io +dougscripts.com +douhokanko.net +doujincafe.com +dowei.org +download.aircrack-ng.org +download.cnet.com +download.ithome.com.tw +dphk.org +dpp.org.tw +dpr.info +dragonex.io +dragonsprings.org +dreamamateurs.com +drepung.org +drgan.net +drmingxia.org +dropbooks.tv +dropbox.com +dropboxusercontent.com +drsunacademy.com +drtuber.com +dscn.info +dsmtp.com +dstk.dk +dtdns.net +dtiblog.com +dtic.mil +dtwang.org +duanzhihu.com +duck.com +duckdns.org +duckduckgo-owned-server.yahoo.net +duckduckgo.com +duckload.com +duckmylife.com +duga.jp +duihua.org +duihuahrjournal.org +dumb1.com +dunyabulteni.net +duoweitimes.com +duping.net +duplicati.com +dupola.com +dupola.net +dushi.ca +dvdpac.com +dvorak.org +dw-world.com +dw-world.de +dw.com +dw.de +dwnews.com +dwnews.net +dynamic-dns.net +dynamicdns.biz +dynamicdns.co.uk +dynamicdns.me.uk +dynamicdns.org.uk +dynawebinc.com +dyndns-ip.com +dyndns-pics.com +dyndns.org +dyndns.pro +dynssl.com +dynu.com +dynu.net +dynupdate.no-ip.com +dzze.com +e-classical.com.tw +e-gold.com +e-hentai.org +e-hentaidb.com +e-info.org.tw +e-traderland.net +e-zone.com.hk +e123.hk +earlytibet.com +earthcam.com +earthvpn.com +eastern-ark.com +easternlightning.org +eastturkestan.com +eastturkistan-gov.org +eastturkistancc.org +eastturkistangovernmentinexile.us +easyca.ca +easypic.com +ebony-beauty.com +ebook.hyread.com.tw +ebookbrowse.com +ebookee.com +ebtcbank.com +ecfa.org.tw +echofon.com +ecimg.tw +ecministry.net +economist.com +ecsm.vs.com +edgecastcdn.net +edicypages.com +edmontonchina.cn +edmontonservice.com +edns.biz +edoors.com +edubridge.com +edupro.org +eeas.europa.eu +eesti.ee +eevpn.com +efcc.org.hk +effers.com +efksoft.com +efukt.com +eic-av.com +eireinikotaerukai.com +eisbb.com +eksisozluk.com +electionsmeter.com +elgoog.im +elpais.com +eltondisney.com +emaga.com +emanna.com +embr.in +emilylau.org.hk +empfil.com +emule-ed2k.com +emulefans.com +emuparadise.me +en.favotter.net +en.hao123.com +enanyang.my +enewstree.com +enfal.de +engagedaily.org +englishforeveryone.org +englishfromengland.co.uk +englishpen.org +enlighten.org.tw +entermap.com +entnt.com +environment.google +epa.gov.tw +epac.to +episcopalchurch.org +epochhk.com +epochtimes-bg.com +epochtimes-romania.com +epochtimes.co.il +epochtimes.co.kr +epochtimes.com +epochtimes.cz +epochtimes.de +epochtimes.fr +epochtimes.ie +epochtimes.it +epochtimes.jp +epochtimes.ru +epochtimes.se +epochtimestr.com +epochweek.com +epochweekly.com +eporner.com +equinenow.com +erabaru.net +eracom.com.tw +eraysoft.com.tr +erepublik.com +erights.net +eriversoft.com +erktv.com +ernestmandel.org +erodaizensyu.com +erodoujinlog.com +erodoujinworld.com +eromanga-kingdom.com +eromangadouzin.com +eromon.net +eroprofile.com +eroticsaloon.net +eslite.com +esmtp.biz +esurance.com +etaa.org.au +etadult.com +etaiwannews.com +etcd.io +etherdelta.com +etizer.org +etokki.com +etools.ncol.com +etowns.net +etowns.org +ettoday.net +etvonline.hk +eu.org +eucasino.com +eulam.com +eurekavpt.com +evchk.wikia.com +evschool.net +exblog.jp +exchristian.hk +exmo.com +exmormon.org +expatshield.com +expecthim.com +expekt.com +experts-univers.com +exploader.net +expressvpn.com +exrates.me +extmatrix.com +extremetube.com +exx.com +eyevio.jp +eyny.com +ezpc.tk +ezpeer.com +ezua.com +fa.gov.tw +facebook.br +facebook.com +facebook.design +facebook.hu +facebook.in +facebook.nl +facebook.se +facebookquotes4u.com +faceless.me +facesofnyfw.com +facesoftibetanselfimmolators.info +fail.hk +faith100.org +faithfuleye.com +faiththedog.info +fakku.net +falsefire.com +falun-co.org +falun-ny.net +falun.caltech.edu +falunart.org +falunasia.info +falunau.org +falunaz.net +falundafa-dc.org +falundafa-florida.org +falundafa-nc.org +falundafa-pa.net +falundafa-sacramento.org +falundafa.org +falundafaindia.org +falundafamuseum.org +falungong.club +falungong.de +falungong.org.uk +falunhr.org +faluninfo.de +faluninfo.net +falunpilipinas.net +falunworld.net +familyfed.org +famunion.com +fan-qiang.com +fangbinxing.com +fangeming.com +fangeqiang.com +fanglizhi.info +fangmincn.org +fangong.forums-free.com +fangong.org +fangongheike.com +fanhaodang.com +fanqiang.tk +fanqianghou.com +fanqiangyakexi.net +fanqiangzhe.com +fanswong.com +fanyue.info +fapdu.com +faproxy.com +faqserv.com +fartit.com +farwestchina.com +fast.wistia.com +fastpic.ru +fastssh.com +faststone.org +fatbtc.com +favstar.fm +fawanghuihui.org +faydao.com +fb.com +fb.me +fbaddins.com +fbcdn.net +fbsbx.com +fbworkmail.com +fc2.com +fc2blog.net +fc2china.com +fc2cn.com +fda.gov.tw +fdc64.de +fdc64.org +fdc89.jp +feedburner.com +feeds.fileforum.com +feelssh.com +feer.com +feifeiss.com +feitian-california.org +feitianacademy.org +feministteacher.com +fengzhenghu.com +fengzhenghu.net +fevernet.com +ff.im +fffff.at +fflick.com +ffvpn.com +fgmtv.net +fgmtv.org +fhreports.net +figprayer.com +fileflyer.com +files2me.com +fileserve.com +filesor.com +fillthesquare.org +filmingfortibet.org +filmy.olabloga.pl +filthdump.com +financetwitter.com +finchvpn.com +findmespot.com +findyoutube.com +findyoutube.net +fingerdaily.com +finler.net +firearmsworld.net +firebaseio.com +fireofliberty.org +firetweet.io +firstfivefollowers.com +flagsonline.it +flecheinthepeche.fr +fleshbot.com +fleursdeslettres.com +flgg.us +flgjustice.org +flickr.com +flickrhivemind.net +flickriver.com +fling.com +flipboard.com +flipkart.com +flitto.com +flnet.org +flog.tw +flyvpn.com +flyzy2005.com +fnac.be +fnac.com +fochk.org +focustaiwan.tw +focusvpn.com +fofg-europe.net +fofg.org +fofldfradio.org +fooooo.com +footwiball.com +foreignpolicy.com +forum.baby-kingdom.com +forum.cyberctm.com +forum.idsam.com +forum.my903.com +forum.mymaji.com +forum.omy.sg +forum.palmislife.com +forum.setty.com.tw +forum.sina.com.hk +forum.slime.com.tw +forum.tvb.com +forum.xinbao.de +forum4hk.com +fotile.me +fourface.nodesnoop.com +fourthinternational.org +foxdie.us +foxgay.com +foxsub.com +foxtang.com +fpmt-osel.org +fpmt.org +fpmt.tw +fpmtmexico.org +fq.wikia.com +fqok.org +fqrouter.com +franklc.com +freakshare.com +free-gate.org +free-hada-now.org +free-proxy.cz +free-ss.site +free-ssh.com +free.fr +free4u.com.ar +freealim.com +freebrowser.org +freechal.com +freechina.net +freechina.news +freechinaforum.org +freechinaweibo.com +freeddns.com +freeddns.org +freedomchina.info +freedomcollection.org +freedomhouse.org +freedominfonetweb.wordpress.com +freedomsherald.org +freeforums.org +freefq.com +freefuckvids.com +freegao.com +freeilhamtohti.org +freekwonpyong.org +freelotto.com +freeman2.com +freemoren.com +freemorenews.com +freemuse.org +freenet-china.org +freenetproject.org +freenewscn.com +freeopenvpn.com +freeoz.org +freessh.us +freetcp.com +freetibet.net +freetibet.org +freetibetanheroes.org +freeviewmovies.com +freevpn.me +freevpn.nl +freewallpaper4.me +freewebs.com +freewechat.com +freeweibo.com +freewww.biz +freewww.info +freexinwen.com +freeyellow.com +freeyoutubeproxy.net +friendfeed-media.com +friendfeed.com +friends-of-tibet.org +friendsoftibet.org +fring.com +fringenetwork.com +from-pr.com +from-sd.com +fromchinatousa.net +frommel.net +frontlinedefenders.org +frootvpn.com +fscked.org +fsurf.com +ftchinese.com +ftp1.biz +ftpserver.biz +ftv.com.tw +fucd.com +fuckcnnic.net +fuckgfw.org +fullerconsideration.com +fulue.com +funf.tw +funkyimg.com +funp.com +fuq.com +furbo.org +furhhdl.org +furinkan.com +furl.net +futurechinaforum.org +futuremessage.org +fux.com +fuyin.net +fuyindiantai.org +fuyu.org.tw +fw.cm +fxcm-chinese.com +fxnetworks.com +fzh999.com +fzh999.net +fzlm.com +g-area.org +g-queen.com +g.co +g6hentai.com +gabocorp.com +gaeproxy.com +gaforum.org +galaxymacau.com +galenwu.com +galstars.net +game735.com +gamebase.com.tw +gamejolt.com +gamer.com.tw +gamez.com.tw +gamousa.com +ganges.com +gaoming.net +gaopi.net +gaozhisheng.net +gaozhisheng.org +gardennetworks.com +gardennetworks.org +gartlive.com +gate-project.com +gate.io +gatecoin.com +gather.com +gatherproxy.com +gati.org.tw +gaybubble.com +gaycn.net +gayhub.com +gaymap.cc +gaymenring.com +gaytube.com +gaywatch.com +gazotube.com +gcc.org.hk +gclooney.com +gcmasia.com +gcpnews.com +gcr.io +gdbt.net +gdzf.org +geek-art.net +geekerhome.com +geekheart.info +gekikame.com +gelbooru.com +geocities.co.jp +geocities.com +geocities.jp +gerefoundation.org +get.app +get.how +get.page +getastrill.com +getchu.com +getcloak.com +getfoxyproxy.org +getfreedur.com +getgom.com +geti2p.net +getiton.com +getjetso.com +getlantern.org +getmdl.io +getoutline.org +getsocialscope.com +getsync.com +gettrials.com +gettyimages.com +getuploader.com +gfbv.de +gfgold.com.hk +gfsale.com +gfw.org.ua +gfw.press +ggpht.com +ggssl.com +ghostpath.com +ghut.org +giantessnight.com +gifree.com +giga-web.jp +gigporno.ru +girlbanker.com +gist.github.com +git.io +github.com +githubusercontent.com +gizlen.net +gjczz.com +glass8.eu +global.bing.com +globaljihad.net +globalmediaoutreach.com +globalmuseumoncommunism.org +globalrescue.net +globaltm.org +globalvoices.org +globalvoicesonline.org +globalvpn.net +glock.com +gloryhole.com +glorystar.me +gluckman.com +glype.com +gmail.com +gmbd.cn +gmhz.org +gmll.org +gmodules.com +gmozomg.izihost.org +gnci.org.hk +go-pki.com +go.nesnode.com +go141.com +goagent.biz +goagent.codeplex.com +goagentplus.com +gobet.cc +godfootsteps.org +godns.work +godoc.org +godsdirectcontact.co.uk +godsdirectcontact.org +godsdirectcontact.org.tw +godsimmediatecontact.com +gogotunnel.com +gohappy.com.tw +gojet.krtco.com.tw +gokbayrak.com +golang.org +goldbet.com +goldbetsports.com +goldeneyevault.com +goldenfrog.com +goldjizz.com +goldstep.net +goldwave.com +gongm.in +gongmeng.info +gongminliliang.com +gongwt.com +goo.gl +gooday.xyz +gooddns.info +goodreaders.com +goodreads.com +goodtv.com.tw +goodtv.tv +goofind.com +google.ad +google.ae +google.al +google.am +google.as +google.at +google.az +google.ba +google.be +google.bf +google.bg +google.bi +google.bj +google.bs +google.bt +google.by +google.ca +google.calstate.edu +google.cat +google.cd +google.cf +google.cg +google.ch +google.ci +google.cl +google.cm +google.cn +google.co.ao +google.co.bw +google.co.ck +google.co.cr +google.co.id +google.co.il +google.co.in +google.co.jp +google.co.ke +google.co.kr +google.co.ls +google.co.ma +google.co.mz +google.co.nz +google.co.th +google.co.tz +google.co.ug +google.co.uk +google.co.uz +google.co.ve +google.co.vi +google.co.za +google.co.zm +google.co.zw +google.com +google.com.af +google.com.ag +google.com.ai +google.com.ar +google.com.au +google.com.bd +google.com.bh +google.com.bn +google.com.bo +google.com.br +google.com.bz +google.com.co +google.com.cu +google.com.cy +google.com.do +google.com.ec +google.com.eg +google.com.et +google.com.fj +google.com.gh +google.com.gi +google.com.gt +google.com.hk +google.com.jm +google.com.kh +google.com.kw +google.com.lb +google.com.ly +google.com.mm +google.com.mt +google.com.mx +google.com.my +google.com.na +google.com.nf +google.com.ng +google.com.ni +google.com.np +google.com.om +google.com.pa +google.com.pe +google.com.pg +google.com.ph +google.com.pk +google.com.pr +google.com.py +google.com.qa +google.com.sa +google.com.sb +google.com.sg +google.com.sl +google.com.sv +google.com.tj +google.com.tr +google.com.tw +google.com.ua +google.com.uy +google.com.vc +google.com.vn +google.cv +google.cz +google.de +google.dj +google.dk +google.dm +google.dz +google.ee +google.es +google.fi +google.fm +google.fr +google.ga +google.ge +google.gg +google.gl +google.gm +google.gp +google.gr +google.gy +google.hn +google.hr +google.ht +google.hu +google.ie +google.im +google.iq +google.is +google.it +google.je +google.jo +google.kg +google.ki +google.kz +google.la +google.li +google.lk +google.lt +google.lu +google.lv +google.md +google.me +google.mg +google.mk +google.ml +google.mn +google.ms +google.mu +google.mv +google.mw +google.ne +google.nl +google.no +google.nr +google.nu +google.pl +google.pn +google.ps +google.pt +google.ro +google.rs +google.ru +google.rw +google.sc +google.se +google.sh +google.si +google.sk +google.sm +google.sn +google.so +google.sr +google.st +google.td +google.tg +google.tk +google.tl +google.tm +google.tn +google.to +google.tt +google.vg +google.vu +google.ws +googleapis.cn +googleapis.com +googleapps.com +googlearth.com +googleartproject.com +googleblog.com +googlebot.com +googlechinawebmaster.com +googlecode.com +googlecommerce.com +googledomains.com +googledrive.com +googleearth.com +googlegroups.com +googlehosted.com +googleideas.com +googleinsidesearch.com +googlelabs.com +googlemail.com +googlemashups.com +googlepagecreator.com +googleplay.com +googleplus.com +googlescholar.com +googlesile.com +googlesource.com +googleusercontent.com +googlevideo.com +googleweblight.com +googlezip.net +gopetition.com +goproxing.net +goregrish.com +gospelherald.com +got-game.org +gotdns.ch +gotgeeks.com +gotrusted.com +gotw.ca +gov.taipei +gov.tw +gr8domain.biz +gr8name.biz +grammaly.com +grandtrial.org +grangorz.org +graphis.ne.jp +graphql.org +greasespot.net +great-firewall.com +great-roc.org +greatfire.org +greatfire.us7.list-manage.com +greatfirewall.biz +greatfirewallofchina.net +greatfirewallofchina.org +greatroc.org +greatroc.tw +greatzhonghua.org +greenfieldbookstore.com.hk +greenparty.org.tw +greenpeace.com.tw +greenpeace.org +greenreadings.com +greenvpn.net +greenvpn.org +grotty-monday.com +groups.google.cn +grow.google +gs-discuss.com +gsp.target.com +gstatic.com +gtricks.com +gts-vpn.com +gu-chu-sum.org +guaguass.com +guaguass.org +guancha.org +guaneryu.com +guangming.com.my +guardster.com +guishan.org +gumroad.com +gun-world.net +gunsamerica.com +gunsandammo.com +guo.media +guruonline.hk +gutteruncensored.com +gvlib.com +gvm.com.tw +gvt0.com +gvt1.com +gvt3.com +gwtproject.org +gyalwarinpoche.com +gyatsostudio.com +gzm.tv +gzone-anime.info +h-china.org +h-moe.com +h1n1china.org +h528.com +h5dm.com +h5galgame.me +hacg.club +hacg.in +hacg.li +hacg.me +hacg.red +hacken.cc +hacker.org +hackthatphone.net +hahaxixi.github.io +hahlo.com +hakkatv.org.tw +handcraftedsoftware.org +hanunyi.com +hao.news +haoel.github.io +happy-vpn.com +haproxy.org +hardsextube.com +harunyahya.com +hautelook.com +hautelookcdn.com +have8.com +hbo.com +hclips.com +hd.stheadline.com +hdlt.me +hdtvb.net +hdzog.com +heartyit.com +heavy-r.com +hec.su +hecaitou.net +hechaji.com +heeact.edu.tw +hegre-art.com +heix.pp.ru +helloandroid.com +helloqueer.com +helloss.pw +hellotxt.com +hellouk.org +help.linksalpha.com +helpeachpeople.com +helplinfen.com +helpster.de +helpzhuling.org +hentai.to +hentaitube.tv +hentaivideoworld.com +heqinglian.net +heungkongdiscuss.com +hexieshe.com +hexieshe.xyz +hexxeh.net +heyzo.com +hgseav.com +hhdcb3office.org +hhthesakyatrizin.org +hi-on.org.tw +hidden-advent.org +hide.me +hidecloud.com +hidein.net +hideipvpn.com +hideman.net +hideme.nl +hidemy.name +hidemyass.com +hidemycomp.com +higfw.com +highpeakspureearth.com +highrockmedia.com +hihiforum.com +hihistory.net +hiitch.com +hikinggfw.org +hilive.tv +himalayan-foundation.org +himalayanglacier.com +himemix.com +himemix.net +hitbtc.com +hitomi.la +hiwifi.com +hizb-ut-tahrir.info +hizb-ut-tahrir.org +hizbuttahrir.org +hjclub.info +hk-pub.com +hk.frienddy.com +hk.geocities.com +hk.gradconnection.com +hk.hao123img.com +hk.jiepang.com +hk.knowledge.yahoo.com +hk.myblog.yahoo.com +hk.news.yahoo.com +hk.rd.yahoo.com +hk.search.yahoo.com +hk.video.news.yahoo.com +hk.yahoo.com +hk01.com +hk32168.com +hka8964.wordpress.com +hkacg.com +hkacg.net +hkanews.wordpress.com +hkatvnews.com +hkbc.net +hkbf.org +hkbookcity.com +hkchurch.org +hkci.org.hk +hkcmi.edu +hkcnews.com +hkcoc.com +hkcoc.weather.com.hk +hkdailynews.com.hk +hkday.net +hkdf.org +hkej.com +hkepc.com +hkfaa.com +hkfreezone.com +hkfront.org +hkgolden.com +hkgreenradio.org +hkheadline.com +hkheadline.comblog +hkhkhk.com +hkhrc.org.hk +hkhrm.org.hk +hkip.org.uk +hkjc.com +hkjp.org +hklft.com +hklts.org.hk +hkptu.org +hkreporter.com +hkreporter.loved.hk +hkupop.hku.hk +hkusu.net +hkvwet.com +hkwcc.org.hk +hkzone.org +hmonghot.com +hmv.co.jp +hmvdigital.ca +hmvdigital.com +hnjhj.com +hnntube.com +hola.com +hola.org +holymountaincn.com +holyspiritspeaks.org +home.sina.com +home.so-net.net.tw +homedepot.com +homeperversion.com +homeservershow.com +hongkongfp.com +hongmeimei.com +hongzhi.li +hootsuite.com +hoovers.com +hopedialogue.org +hopto.org +hornygamer.com +hornytrip.com +hotav.tv +hotels.cn +hotfrog.com.tw +hotgoo.com +hotpornshow.com +hotpot.hk +hotshame.com +hotspotshield.com +hotvpn.com +hougaige.com +howtoforge.com +hoxx.com +hpa.gov.tw +hqcdp.org +hqjapanesesex.com +hqmovies.com +hqsbnet.wordpress.com +hqsbonline.wordpress.com +hrcchina.org +hrcir.com +hrea.org +hrichina.org +hrtsea.com +hrw.org +hrweb.org +hsjp.net +hsselite.com +hst.net.tw +hstern.net +hstt.net +ht.ly +htkou.net +htl.li +html5rocks.com +https443.net +https443.org +hua-yue.net +huaglad.com +huanghuagang.org +huangyiyu.com +huaren.us +huaren4us.com +huashangnews.com +huaxia-news.com +huaxiabao.org +huaxin.ph +huayuworld.org +hudatoriq.web.id +hudson.org +huffingtonpost.com +hugoroy.eu +huhaitai.com +huhamhire.com +huiyi.in +hulkshare.com +hulu.com +huluim.com +humanrightsbriefing.org +hung-ya.com +hungerstrikeforaids.org +huobi.com +huobi.pro +huobipro.com +huping.net +hurgokbayrak.com +hurriyet.com.tr +hustlercash.com +hut2.ru +hutianyi.net +hutong9.net +huyandex.com +hwadzan.tw +hwayue.org.tw +hwinfo.com +hxwk.org +hxwq.org +hybrid-analysis.com +hyperrate.com +i-cable.com +i-part.com.tw +i-scmp.com +i.lithium.com +i1.hk +i2p2.de +i2runner.com +i818hk.com +iam.soy +iamtopone.com +iask.bz +iask.ca +iav19.com +ibiblio.org +iblist.com +iblogserv-f.net +ibros.org +ibvpn.com +icams.com +ice.audionow.com +icij.org +icl-fi.org +icoco.com +iconpaper.org +icu-project.org +id.hao123.com +id.heroku.com +iddddg.com +idemocracy.asia +identi.ca +idiomconnection.com +idouga.com +idreamx.com +idv.tw +ieasy5.com +ied2k.net +ienergy1.com +if.ttt +ifan.cz.cc +ifanqiang.com +ifcss.org +ifjc.org +ifreewares.com +ift.tt +igcd.net +igfw.net +igfw.tech +igmg.de +ignitedetroit.net +igoogle.com +igotmail.com.tw +igvita.com +ihakka.net +ihao.org +iicns.com +iipdigital.usembassy.gov +ikstar.com +ikwb.com +illusionfactory.com +ilove80.be +ilovelongtoes.com +im.tv +im88.tw +imageab.com +imagefap.com +imageflea.com +images-gaytube.com +images.comico.tw +imageshack.us +imagevenue.com +imagezilla.net +imb.org +imdb.com +img.dlsite.jp +img.ly +imgchili.net +imgmega.com +imgur.com +imkev.com +imlive.com +immigration.gov.tw +immoral.jp +impact.org.au +impp.mn +in-disguise.com +in99.org +incapdns.net +incloak.com +incredibox.fr +indiandefensenews.in +indiemerch.com +info-graf.fr +initiativesforchina.org +inkui.com +inmediahk.net +innermongolia.org +inote.tw +insecam.org +insidevoa.com +instagram.com +instanthq.com +institut-tibetain.org +international-news.newsmagazine.asia +internet.org +internetdefenseleague.org +internetfreedom.org +internetpopculture.com +inthenameofconfuciusmovie.com +investigating.wordpress.com +inxian.com +iownyour.biz +iownyour.org +ipalter.com +ipfire.org +ipfs.io +iphone4hongkong.com +iphonehacks.com +iphonetaiwan.org +iphonix.fr +ipicture.ru +ipjetable.net +ipobar.com +ipoock.com +iportal.me +ippotv.com +ipredator.se +iptv.com.tw +iptvbin.com +ipvanish.com +iredmail.org +ironbigfools.compython.net +ironpython.net +ironsocket.com +is-a-hunter.com +is.gd +isaacmao.com +isasecret.com +isgreat.org +islahhaber.net +islam.org.hk +islamawareness.net +islamhouse.com +islamicity.com +islamicpluralism.org +islamtoday.net +ismaelan.com +ismalltits.com +ismprofessional.net +isohunt.com +israbox.com +issuu.com +istars.co.nz +istiqlalhewer.com +istockphoto.com +isunaffairs.com +isuntv.com +itaboo.info +itaiwan.gov.tw +italiatibet.org +itasoftware.com +itemdb.com +ithelp.ithome.com.tw +its.caltech.edu +itsaol.com +itshidden.com +itsky.it +itweet.net +iu45.com +iuhrdf.org +iuksky.com +ivacy.com +iverycd.com +ivpn.net +ixquick.com +ixxx.com +iyouport.com +izaobao.us +izles.net +izlesem.org +j.mp +ja.wikipedia.org +jamaat.org +jamyangnorbu.com +jandyx.com +janwongphoto.com +japan-whores.com +japanfirst.asianfreeforum.com +japantimes.co.jp +jav.com +jav101.com +jav2be.com +jav68.tv +javakiba.org +javbus.com +javfor.me +javhd.com +javhip.com +javhub.net +javhuge.com +javlibrary.com +javmobile.net +javmoo.com +javmoo.xyz +javseen.com +javtag.com +javzoo.com +jbtalks.cc +jbtalks.com +jbtalks.my +jcpenney.com +jdwsy.com +jeanyim.com +jetos.com +jex.com +jfqu36.club +jfqu37.xyz +jgoodies.com +jiangweiping.com +jiaoyou8.com +jiehua.cz +jieshibaobao.com +jigglegifs.com +jigong1024.com +jihadintel.meforum.org +jihadology.net +jiji.com +jims.net +jinbushe.org +jingpin.org +jingsim.org +jinpianwang.com +jinroukong.com +jinx.com +jitouch.com +jizzthis.com +jjgirls.com +jkb.cc +jkforum.net +jkub.com +jma.go.jp +jmscult.com +joachims.org +jobnewera.wordpress.com +jobso.tv +journalchretien.net +journalofdemocracy.org +joymiihub.com +joyourself.com +jp.hao123.com +jpl.nasa.gov +jpopforum.net +jtvnw.net +jubushoushen.com +juhuaren.com +jukujo-club.com +juliepost.com +juliereyc.com +junauza.com +june4commemoration.org +junefourth-20.net +jungleheart.com +juoaa.com +justdied.com +justfreevpn.com +justicefortenzin.org +justpaste.it +justtristan.com +juyuange.org +juziyue.com +jwmusic.org +jyxf.net +k-doujin.net +ka-wai.com +kagyu.org +kagyu.org.za +kagyumonlam.org +kagyunews.com.hk +kagyuoffice.org +kagyuoffice.org.tw +kaiyuan.de +kakao.com +kalachakralugano.org +kankan.today +kannewyork.com +kanshifang.com +kantie.org +kanzhongguo.com +kanzhongguo.eu +kaotic.com +karayou.com +karkhung.com +karmapa-teachings.org +karmapa.org +kawaiikawaii.jp +kawase.com +kb.monitorware.com +kba-tx.org +kcoolonline.com +kebrum.com +kechara.com +keepandshare.com +keezmovies.com +kendatire.com +kendincos.net +kenengba.com +keontech.net +kepard.com +kex.com +keycdn.com +khabdha.org +khatrimaza.org +khmusic.com.tw +kichiku-doujinko.com +kik.com +killwall.com +kindleren.com +kineox.free.fr +kingdomsalvation.org +kinghost.com +kingstone.com.tw +kink.com +kinmen.org.tw +kinmen.travel +kir.jp +kissbbao.cn +kiwi.kz +kk-whys.co.jp +kkbox.com +kknews.cc +kmuh.org.tw +knowledgerush.com +kobo.com +kobobooks.com +kodingen.com +kompozer.net +konachan.com +kone.com +koolsolutions.com +koornk.com +koranmandarin.com +korenan2.com +ksdl.org +ksnews.com.tw +kspcoin.com +ktzhk.com +kucoin.com +kui.name +kun.im +kurashsultan.com +kurtmunger.com +kusocity.com +kwcg.ca +kwongwah.com.my +kxsw.life +kyofun.com +kyohk.net +kyoyue.com +kyzyhello.com +kzeng.info +la-forum.org +labiennale.org +ladbrokes.com +lagranepoca.com +lalulalu.com +lama.com.tw +lamayeshe.com +lamnia.co.uk +lamrim.com +lanterncn.cn +lantosfoundation.org +laod.cn +laogai.org +laomiu.com +laoyang.info +laptoplockdown.com +laqingdan.net +larsgeorge.com +lastcombat.com +lastfm.es +latelinenews.com +latibet.org +lbank.info +ld.hao123img.com +le-vpn.com +leafyvpn.net +lecloud.net +leeao.com.cn +lefora.com +left21.hk +legalporno.com +legaltech.law.com +legsjapan.com +leirentv.ca +leisurecafe.ca +leisurepro.com +lematin.ch +lemonde.fr +lenwhite.com +lerosua.org +lers.google +lesoir.be +letou.com +letscorp.net +lflink.com +lflinkup.com +lflinkup.net +lflinkup.org +lhakar.org +lhasocialwork.org +liangyou.net +liangzhichuanmei.com +lianyue.net +liaowangxizang.net +liberal.org.hk +libertytimes.com.tw +library.usc.cuhk.edu.hk +lidecheng.com +lifemiles.com +lighten.org.tw +lightnovel.cn +like.com +limiao.net +line-apps.com +line-scdn.net +line.me +line.naver.jp +linear-abematv.akamaized.net +linglingfa.com +lingvodics.com +link-o-rama.com +linkideo.com +linkuswell.com +linux.org.hk +linuxtoy.org +lionsroar.com +lipuman.com +liquidvpn.com +listentoyoutube.com +listorious.com +lists.w3.org +liu-xiaobo.org +liudejun.com +liuhanyu.com +liujianshu.com +liuxiaobo.net +liuxiaotong.com +livecoin.net +livedoor.jp +liveleak.com +livestation.com +livestream.com +livevideo.com +livingonline.us +livingstream.com +liwangyang.com +lizhizhuangbi.com +lkcn.net +llss.me +load.to +lobsangwangyal.com +localdomain.ws +localpresshk.com +lockestek.com +logbot.net +login.target.com +logiqx.com +londonchinese.ca +longhair.hk +longmusic.com +longtermly.net +longtoes.com +lookpic.com +looktoronto.com +lotsawahouse.org +lotuslight.org.hk +lotuslight.org.tw +lovetvshow.com +lpsg.com +lrfz.com +lrip.org +lsd.org.hk +lsforum.net +lsm.org +lsmchinese.org +lsmkorean.org +lsmradio.com +lsmwebcast.com +lsxszzg.com +ltn.com.tw +luke54.com +luke54.org +lupm.org +lushstories.com +luxebc.com +lvhai.org +lvv2.com +lyfhk.net +lzmtnews.org +m-team.cc +m.hkgalden.com +m.me +m.plixi.com +m.slandr.net +ma.hao123.com +macgamestore.com +macrovpn.com +macts.com.tw +mad-ar.ch +madewithcode.com +madonna-av.com +madrau.com +madthumbs.com +magazines.sina.com.tw +magic-net.info +mahabodhi.org +maiio.net +mail-archive.com +maildns.xyz +maiplus.com +maizhong.org +makemymood.com +makkahnewspaper.com +makzhou.warehouse333.com +malaysiakini.com +mamingzhe.com +manchukuo.net +mangafox.com +mangafox.me +maniash.com +manicur4ik.ru +mansion.com +mansionpoker.com +manta.com +maplew.com +marc.info +marguerite.su +martau.com +martincartoons.com +martsangkagyuofficial.org +maruta.be +marxist.com +marxist.net +marxists.org +mash.to +maskedip.com +mastodon.host +matainja.com +material.io +mathable.io +mathiew-badimon.com +matome-plus.com +matome-plus.net +matsushimakaede.com +mattwilcox.net +maturejp.com +maxing.jp +mayimayi.com +mcadforums.com +mcaf.ee +mcfog.com +mcreasite.com +md-t.org +me.youthwant.com.tw +meansys.com +media.nu.nl +media.org.hk +mediachinese.com +mediafire.com +mediafreakcity.com +medium.com +meetav.com +meetup.com +mefeedia.com +mefound.com +mega.nz +megaproxy.com +megarotic.com +megavideo.com +megurineluka.com +meirixiaochao.com +meltoday.com +meme.yahoo.com +memehk.com +memorybbs.com +memri.org +memrijttm.org +mercyprophet.org +meridian-trust.org +meripet.biz +meripet.com +merit-times.com.tw +meshrep.com +mesotw.com +messenger.com +metacafe.com +metarthunter.com +meteorshowersonline.com +metrohk.com.hk +metrolife.ca +metroradio.com.hk +meyou.jp +meyul.com +mfxmedia.com +mgoon.com +mgstage.com +mh4u.org +mhradio.org +michaelanti.com +michaelmarketl.com +microvpn.com +middle-way.net +mihk.hk +mihr.com +mihua.org +mike.cz.cc +mikesoltys.com +milph.net +milsurps.com +mimiai.net +mimivip.com +mimivv.com +mindrolling.org +minghui-a.org +minghui-b.org +minghui-school.org +minghui.or.kr +minghui.org +minghuiyw.wordpress.com +mingjinglishi.com +mingjingnews.com +mingjingtimes.com +mingpao.com +mingpaocanada.com +mingpaomonthly.com +mingpaonews.com +mingpaony.com +mingpaosf.com +mingpaotor.com +mingpaovan.com +mingshengbao.com +minhhue.net +miniforum.org +ministrybooks.org +minzhuhua.net +minzhuzhanxian.com +minzhuzhongguo.org +miroguide.com +mirrorbooks.com +mist.vip +mitao.com.tw +mitbbs.com +mitbbsau.com +mixero.com +mixpod.com +mixx.com +mizzmona.com +mjib.gov.tw +mjlsh.usc.cuhk.edu.hk +mk5000.com +mlcool.com +mlzs.work +mm-cg.com +mmaaxx.com +mmmca.com +mnewstv.com +mo.nightlife141.com +mobatek.net +mobile01.com +mobileways.de +moby.to +mobypicture.com +moeaic.gov.tw +moeerolibrary.com +mofa.gov.tw +mofaxiehui.com +mofos.com +mog.com +mohu.club +mohu.ml +mol.gov.tw +molihua.org +mondex.org +money-link.com.tw +moneyhome.biz +monitorchina.org +monster.com +moodyz.com +moonbbs.com +moonbingo.com +morningsun.org +moroneta.com +mos.ru +motherless.com +motiyun.com +motor4ik.ru +mousebreaker.com +movements.org +moviefap.com +mp3buscador.com +mp3ye.eu +mpettis.com +mpfinance.com +mpinews.com +mponline.hk +mqxd.org +mrbasic.com +mrbonus.com +mrface.com +mrslove.com +mrtweet.com +msa-it.org +msguancha.com +msha.gov +mswe1.org +mthruf.com +mtw.tl +muchosucko.com +mullvad.net +multiply.com +multiproxy.org +multiupload.com +mummysgold.com +murmur.tw +musicade.net +muslimvideo.com +muzi.com +muzi.net +muzu.tv +mvdis.gov.tw +mvg.jp +mx.hao123.com +mx981.com +my-formosa.com +my-private-network.co.uk +my-proxy.com +my.mail.ru +my.opera.com +my.pcloud.com +my03.com +myactimes.com +myanniu.com +myaudiocast.com +myav.com.tw +mybbs.us +mybet.com +myca168.com +mycanadanow.com +mychinamyhome.com +mychinanet.com +mychinanews.com +mychinese.news +mycnnews.com +mycould.com +mydad.info +myddns.com +myeasytv.com +myeclipseide.com +myforum.com.hk +myforum.com.uk +myfreecams.com +myfreepaysite.com +myfreshnet.com +myftp.info +myftp.name +myiphide.com +mykomica.org +mylftv.com +mymediarom.com +mymoe.moe +mymom.info +mymusic.net.tw +mynetav.net +mynetav.org +mynumber.org +myparagliding.com +mypicture.info +mypop3.net +mypop3.org +mypopescu.com +myradio.hk +myreadingmanga.info +mysecondarydns.com +myshare.url.com.tw +mysinablog.com +mysite.verizon.net +myspace.com +myspacecdn.com +mytalkbox.com +mytizi.com +mywww.biz +myz.info +naacoalition.org +naitik.net +nakido.com +nakuz.com +nalandabodhi.org +nalandawest.org +namgyal.org +namgyalmonastery.org +namsisi.com +nanyang.com +nanyangpost.com +nanzao.com +naol.ca +naol.cc +nat.gov.tw +nat.moe +national-lottery.co.uk +nationsonline.org +nationwide.com +naughtyamerica.com +navyfamily.navy.mil +navyreserve.navy.mil +naweeklytimes.com +nbtvpn.com +nccwatch.org.tw +nch.com.tw +ncn.org +nde.de +ndr.de +ned.org +nekoslovakia.net +nemesis2.qx.net +neo-miracle.com +nepusoku.com +net-fits.pro +netbirds.com +netcolony.com +netflix.com +netme.cc +netsneak.com +network54.com +networkedblogs.com +networktunnel.net +neverforget8964.org +new-3lunch.net +new-akiba.com +new96.ca +newcenturymc.com +newcenturynews.com +newchen.com +newgrounds.com +newipnow.com +newlandmagazine.com.au +newnews.ca +news.cnyes.com +news.hk.msn.com +news.hkpeanut.com +news.msn.com.tw +news.nationalgeographic.com +news.now.com +news.omy.sg +news.seehua.com +news.sina.com.hk +news.sina.com.tw +news.sinchew.com.my +news.singtao.ca +news.tvb.com +news.tvbs.com.tw +news.yahoo.com +news100.com.tw +newsancai.com +newschinacomment.org +newscn.org +newsdetox.ca +newsdh.com +newspeak.cc +newstamago.com +newstapa.org +newstarnet.com +newtaiwan.com.tw +newtalk.tw +newyorktimes.com +nexon.com +next11.co.jp +nextmag.com.tw +nextmedia.com +nexton-net.jp +nexttv.com.tw +nf.id.au +nfjtyd.com +nflxext.com +nflximg.com +nflximg.net +nflxso.net +nflxvideo.net +nga.mil +ngensis.com +nhentai.net +nhi.gov.tw +nhk-ondemand.jp +nic.cz.cc +nic.google +nic.gov +nicovideo.jp +nighost.org +nikkei.com +ninecommentaries.com +ninjacloak.com +ninjaproxy.ninja +nintendium.com +ninth.biz +niusnews.com +njactb.org +njuice.com +nko.navy.mil +nlfreevpn.com +no-ip.org +nobel.se +nobelprize.org +nobodycanstop.us +nofile.io +nokogiri.org +nokola.com +noodlevpn.com +norbulingka.org +nordstrom.com +nordstromimage.com +nordstromrack.com +nordvpn.com +notify.dropboxapi.com +nottinghampost.com +novelasia.com +now.com +now.im +nownews.com +nowtorrents.com +noypf.com +npa.go.jp +npa.gov.tw +npnt.me +nps.gov +nradio.me +nrk.no +ns01.biz +ns01.info +ns01.us +ns02.biz +ns02.info +ns02.us +ns1.name +ns2.name +ns3.name +nsc.gov.tw +ntbk.gov.tw +ntbna.gov.tw +ntbt.gov.tw +ntd.tv +ntdtv.ca +ntdtv.co.kr +ntdtv.com +ntdtv.cz +ntdtv.org +ntdtv.ru +ntdtvla.com +ntrfun.com +ntsna.gov.tw +nubiles.net +nuexpo.com +nukistream.com +nurgo-software.com +nusatrip.com +nutaku.net +nuuvem.com +nuvid.com +nuzcom.com +nvdst.com +nvquan.org +nvtongzhisheng.org +nwtca.org +ny.stgloballink.com +ny.visiontimes.com +nyaa.eu +nydus.ca +nylon-angel.com +nylonstockingsonline.com +nyt.com +nytchina.com +nytcn.me +nytco.com +nyti.ms +nytimes.com +nytimes.map.fastly.net +nytimg.com +nytstyle.com +nzchinese.com +nzchinese.net.nz +observechina.net +obutu.com +ocaspro.com +occupytiananmen.com +oclp.hk +ocreampies.com +ocry.com +october-review.org +oculus.com +oculuscdn.com +oex.com +offbeatchina.com +officeoftibet.com +ofile.org +ogaoga.org +ogate.org +oikos.com.tw +oiktv.com +oizoblog.com +ok.ru +okayfreedom.com +okex.com +okk.tw +old-cat.net +old.honeynet.org +old.nabble.com +olumpo.com +olympicwatch.org +omgili.com +omni7.jp +omnitalk.com +omnitalk.org +on.cc +on2.com +onapp.com +onedrive.live.com +onedumb.com +onejav.com +onion.city +online.recoveryversion.org +onlinecha.com +onlineyoutube.com +onlytweets.com +onmoon.com +onmoon.net +onmypc.biz +onmypc.info +onmypc.net +onmypc.org +onmypc.us +onthehunt.com +ontrac.com +oopsforum.com +open.com.hk +openallweb.com +opendemocracy.net +opendn.xyz +openervpn.in +openid.net +openleaks.org +openvpn.net +openwebster.com +openwrt.org.cn +opml.radiotime.com +opus-gaming.com +organcare.org.tw +organharvestinvestigation.net +organiccrap.com +orgasm.com +orgfree.com +orient-doll.com +orientaldaily.com.my +orn.jp +orzistic.org +osfoora.com +otcbtc.com +otnd.org +otto.de +otzo.com +ourdearamy.com +ourhobby.com +oursogo.com +oursteps.com.au +oursweb.net +ourtv.hk +overplay.net +oversea.istarshine.com +ow.ly +owl.li +oyax.com +oyghan.com +ozchinese.com +ozvoice.org +ozxw.com +ozyoyo.com +pachosting.com +pacificpoker.com +packages.debian.org +packetix.net +pacopacomama.com +padmanet.com +page.bid.yahoo.com +page2rss.com +pagodabox.com +palacemoon.com +paldengyal.com +paljorpublications.com +paltalk.com +panamapapers.sueddeutsche.de +pandapow.co +pandapow.net +pandavpn-jp.com +pandora.com +pandora.tv +panluan.net +panoramio.com +pao-pao.net +paper.li +paperb.us +paradisehill.cc +paradisepoker.com +parkansky.com +partycasino.com +partypoker.com +passion.com +passiontimes.hk +paste.ee +pastebin.com +pastie.org +pbs.org +pbwiki.com +pbworks.com +pbxes.com +pbxes.org +pcanywhere.net +pcc.gov.tw +pcdvd.com.tw +pchome.com.tw +pcij.org +pcstore.com.tw +pct.org.tw +pdetails.com +pdproxy.com +pds.nasa.gov +peace.ca +peacefire.org +peacehall.com +pearlher.org +peeasian.com +pekingduck.org +pemulihan.or.id +pen.io +penchinese.com +penchinese.net +pengyulong.com +penisbot.com +penthouse.com +pentoy.hk +peoplebookcafe.com +peoplenews.tw +peopo.org +percy.in +perfectgirls.net +perfectvpn.net +periscope.tv +persecutionblog.com +persiankitty.com +pfd.org.hk +phapluan.org +phayul.com +philborges.com +philly.com +phmsociety.org +phncdn.com +phobos.apple.com +phosphation13.rssing.com +photodharma.net +photofocus.com +phuquocservices.com +picacomic.com +picacomiccn.com +picasaweb.com +picidae.net +picturedip.com +pictures.playboy.com +picturesocial.com +pimg.tw +pin-cong.com +pin6.com +ping.fm +pinimg.com +pinkrod.com +pinoy-n.com +pinterest.at +pinterest.co.kr +pinterest.co.uk +pinterest.com +pinterest.de +pinterest.dk +pinterest.fr +pinterest.jp +pinterest.nl +pinterest.se +pioneer-worker.forums-free.com +pipii.tv +piposay.com +piraattilahti.org +piring.com +pixelqi.com +pixiv.net +pixnet.net +pk.com +pki.goog +placemix.com +playboy.com +playboyplus.com +player.fm +playno1.com +playpcesor.com +plays.com.tw +plm.org.hk +plunder.com +plurk.com +plus28.com +plusbb.com +pmatehunter.com +pmates.com +po2b.com +pobieramy.top +podictionary.com +pokerstars.com +pokerstars.net +politicalchina.org +politicalconsultation.org +politiscales.net +poloniex.com +polymer-project.org +polymerhk.com +popo.tw +popvote.hk +popyard.com +popyard.org +porn.com +porn2.com +porn5.com +pornbase.org +pornerbros.com +pornhd.com +pornhost.com +pornhub.com +pornhubdeutsch.net +pornmm.net +pornoxo.com +pornrapidshare.com +pornsharing.com +pornsocket.com +pornstarclub.com +porntube.com +porntubenews.com +porntvblog.com +pornvisit.com +port25.biz +portablevpn.nl +poskotanews.com +post01.com +post76.com +post852.com +postadult.com +postimg.org +potvpn.com +power.com +powerapple.com +powercx.com +powerphoto.org +prayforchina.net +premeforwindows7.com +premproxy.com +presentationzen.com +presidentlee.tw +prestige-av.com +pride.google +prisoneralert.com +pritunl.com +privacybox.de +private.com +privateinternetaccess.com +privatepaste.com +privatetunnel.com +privatevpn.com +procopytips.com +prosiben.de +protonvpn.com +provideocoalition.com +provpnaccounts.com +proxfree.com +proxifier.com +proxomitron.info +proxpn.com +proxyanonimo.es +proxydns.com +proxylist.org.uk +proxynetwork.org.uk +proxypy.net +proxyroad.com +proxytunnel.net +proyectoclubes.com +prozz.net +psblog.name +pscp.tv +psiphon.ca +psiphon.civisec.org +psiphon3.com +psiphontoday.com +pts.org.tw +ptt.cc +pttvan.org +pubu.com.tw +puffinbrowser.com +puffstore.com +pullfolio.com +pulse.yahoo.com +punyu.com +pure18.com +pureconcepts.net +pureinsight.org +purepdf.com +purevpn.com +purplelotus.org +pursuestar.com +pushchinawall.com +pussyspace.com +putihome.org +putlocker.com +putty.org +puuko.com +pwned.com +python.com +python.com.tw +pythonhackers.com +pytorch.org +qanote.com +qgirl.com.tw +qhigh.com +qi-gong.me +qiandao.today +qiangyou.org +qidian.ca +qienkuen.org +qiwen.lu +qixianglu.cn +qkshare.com +qoos.com +qpoe.com +qq.co.za +qstatus.com +qtrac.eu +qtweeter.com +quannengshen.org +quantumbooter.net +questvisual.com +quitccp.net +quitccp.org +quora.com +quran.com +quranexplorer.com +qusi8.net +qvodzy.org +qxbbs.org +r18.com +ra.gg +radicalparty.org +radiko.jp +radioaustralia.net.au +radiohilight.net +radiovaticana.org +radiovncr.com +rael.org +raggedbanner.com +raidcall.com.tw +raidtalk.com.tw +rainbowplan.org +raindrop.io +raizoji.or.jp +ramcity.com.au +rangwang.biz +rangzen.com +rangzen.net +rangzen.org +ranyunfei.com +rapbull.net +rapidgator.net +rapidmoviez.com +rapidvpn.com +raremovie.cc +raremovie.net +raw.githubusercontent.com +rawgit.com +rawgithub.com +razyboard.com +rcam.target.com +rcinet.ca +rconversation.blogs.com +rd.com +rdio.com +read01.com +read100.com +readingtimes.com.tw +readmoo.com +readydown.com +realcourage.org +realforum.zkiz.com +realitykings.com +realraptalk.com +realsexpass.com +rebatesrule.net +recordhistory.org +recovery.org.tw +recoveryversion.com.tw +red-lang.org +redballoonsolidarity.org +redchinacn.net +redchinacn.org +redd.it +reddit.com +redditmedia.com +redditstatic.com +redhotlabs.com +redtube.com +referer.us +reflectivecode.com +registry.google +relaxbbs.com +relay.com.tw +releaseinternational.org +religioustolerance.org +renminbao.com +renyurenquan.org +research.jmsc.hku.hk +resilio.com +retweeteffect.com +retweetist.com +retweetrank.com +reuters.com +reutersmedia.net +revleft.com +revver.com +rfa.org +rfachina.com +rfalive1.akacast.akamaistream.net +rfamobile.org +rfaweb.org +rferl.org +rfi.fr +rfi.my +rightbtc.com +rigpa.org +riku.me +rileyguide.com +riseup.net +ritouki.jp +ritter.vg +rixcloud.com +rixcloud.us +rlwlw.com +rmjdw.com +rmjdw132.info +roadshow.hk +roboforex.com +robustnessiskey.com +rocket-inc.net +rocksdb.org +rojo.com +rolia.net +ronjoneswriter.com +roodo.com +rosechina.net +rotten.com +rsdlmonitor.com +rsf-chinese.org +rsf.org +rsgamen.org +rssmeme.com +rtalabel.org +rthk.hk +rthk.org.hk +rthklive2-lh.akamaihd.net +rti.org.tw +rtycminnesota.org +ruanyifeng.com +rukor.org +runbtx.com +rushbee.com +ruten.com.tw +rutube.ru +ruyiseek.com +rxhj.net +s-cute.com +s-dragon.org +s1.nudezz.com +s1heng.com +s1s1s1.com +s3-ap-northeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3.amazonaws.com +s8forum.com +sa.hao123.com +sacks.com +sacom.hk +sadistic-v.com +sadpanda.us +safervpn.com +safety.google +saintyculture.com +saiq.me +sakuralive.com +sakya.org +salvation.org.hk +samair.ru +sambhota.org +sanmin.com.tw +sapikachu.net +saveliuxiaobo.com +savemedia.com +savethedate.foo +savetibet.de +savetibet.fr +savetibet.nl +savetibet.org +savetibet.ru +savetibetstore.org +savevid.com +say2.info +sbme.me +sbs.com.au +scache.vzw.com +scache1.vzw.com +scache2.vzw.com +scasino.com +schema.org +sciencenets.com +scieron.com +scmp.com +scmpchinese.com +scramble.io +scribd.com +scriptspot.com +seapuff.com +search.aol.com +search.disconnect.me +search.xxx +search.yahoo.co.jp +searchtruth.com +secretchina.com +secretgarden.no +secretsline.biz +secure.hustler.com +secure.logmein.com +secure.raxcdn.com +securetunnel.com +securityinabox.org +securitykiss.com +seed4.me +seesmic.com +seevpn.com +seezone.net +sejie.com +sellclassics.com +sendsmtp.com +sendspace.com +servehttp.com +serveuser.com +serveusers.com +services.googleapis.cn +services.googleapis.com +sesawe.net +sesawe.org +sethwklein.net +setn.com +settv.com.tw +sevenload.com +sex-11.com +sex.com +sex3.com +sex8.cc +sexandsubmission.com +sexbot.com +sexhu.com +sexhuang.com +sexidude.com +sexinsex.net +sextvx.com +sexxxy.biz +sf.net +sfileydy.com +sfshibao.com +sftindia.org +sftuk.org +shadeyouvpn.com +shadow.ma +shadowsky.xyz +shadowsocks-r.com +shadowsocks.asia +shadowsocks.be +shadowsocks.com +shadowsocks.com.hk +shadowsocks.org +shadowsocks9.com +shambalapost.com +shambhalasun.com +shangfang.org +shapeservices.com +share.dmhy.org +share.ovi.com +share.youthwant.com.tw +sharebee.com +sharecool.org +sharpdaily.com.hk +sharpdaily.hk +sharpdaily.tw +shat-tibet.com +shattered.io +sheikyermami.com +shellfire.de +shenshou.org +shenyun.com +shenyunperformingarts.org +shenzhoufilm.com +sherabgyaltsen.com +shiatv.net +shicheng.org +shiksha.com +shinychan.com +shipcamouflage.com +shireyishunjian.com +shitaotv.org +shixiao.org +shizhao.org +shkspr.mobi +shodanhq.com +shooshtime.com +shop2000.com.tw +shopping.com +showbiz.omy.sg +showhaotu.com +showtime.jp +shutterstock.com +shwchurch.org +shwchurch3.com +siddharthasintent.org +sidelinesnews.com +sidelinessportseatery.com +sierrafriendsoftibet.org +sijihuisuo.club +sijihuisuo.com +sikaozhe1997.github.io +silkbook.com +simbolostwitter.com +simplecd.org +simpleproductivityblog.com +sinchew.com.my +singaporepools.com.sg +singfortibet.com +singpao.com.hk +singtao.com +singtaousa.com +sino-monthly.com +sinoants.com +sinocast.com +sinocism.com +sinomontreal.ca +sinonet.ca +sinopitt.info +sinoquebec.com +sipml5.org +sis.xxx +sis001.com +sis001.us +site2unblock.com +site90.net +sitebro.tw +sitekreator.com +siteks.uk.to +sitemaps.org +sixth.biz +sjrt.org +sjum.cn +sketchappsources.com +skimtube.com +skybet.com +skyking.com.tw +skyvegas.com +skyxvpn.com +slacker.com +slaytizle.com +sleazydream.com +slheng.com +slickvpn.com +slideshare.net +slinkset.com +slutload.com +slutmoonbeam.com +slyip.com +slyip.net +sm-miracle.com +smartdnsproxy.com +smarthide.com +smchbooks.com +smh.com.au +smhric.org +smith.edu +smyxy.org +snapchat.com +snaptu.com +sndcdn.com +sneakme.net +snowlionpub.com +sobees.com +soc.mil +socialwhale.com +socks-proxy.net +sockscap64.com +sockslist.net +socrec.org +sod.co.jp +sodatea.github.io +softether-download.com +softether.co.jp +softether.org +softwarebychuck.com +softwaredownload.gitbooks.io +sogclub.com +sogrady.me +soh.tw +sohcradio.com +sohfrance.org +sokamonline.com +sokmil.com +solarsystem.nasa.gov +solidaritetibet.org +solidfiles.com +somee.com +songjianjun.com +sonicbbs.cc +sonidodelaesperanza.org +sopcast.com +sopcast.org +sorazone.net +sorting-algorithms.com +sos.org +sosreader.com +sostibet.org +soubory.com +soul-plus.net +soulcaliburhentai.net +soumo.info +soundcloud.com +soundofhope.kr +soundofhope.org +soup.io +soupofmedia.com +sourceforge.net +sourcewadio.com +southnews.com.tw +sowers.org.hk +soylentnews.org +spankbang.com +spankingtube.com +spankwire.com +spb.com +speakerdeck.com +specxinzl.jigsy.com +speedify.com +spem.at +spencertipping.com +spendee.com +spicevpn.com +spideroak.com +spike.com +sports.williamhill.com +spotflux.com +spotify.com +spreadshirt.es +spring4u.info +springboardplatform.com +sprite.org +sproutcore.com +sproxy.info +squirly.info +srcf.ucam.org +srocket.us +ss-link.com +ss.carryzhou.com +ss.levyhsu.com +ss.pythonic.life +ss7.vzw.com +ssglobal.co +ssglobal.me +ssh91.com +ssl.webpack.de +ssl443.org +sspanel.net +sspro.ml +ssr.tools +ssrshare.com +sss.camp +sstmlt.moe +sstmlt.net +stackoverflow.com +stage64.hk +standupfortibet.org +stanford.edu +starfishfx.com +starp2p.com +startpage.com +startuplivingchina.com +stat.gov.tw +static-economist.com +static.comico.tw +static.shemalez.com +static01.nyt.com +staticflickr.com +statueofdemocracy.org +stc.com.sa +steamcommunity.com +steel-storm.com +steganos.com +steganos.net +stepchina.com +stephaniered.com +sthoo.com +stickam.com +stickeraction.com +stileproject.com +sto.cc +stoporganharvesting.org +stoptibetcrisis.net +storagenewsletter.com +store.steampowered.com +stories.google +storify.com +storm.mg +stormmediagroup.com +stoweboyd.com +stranabg.com +straplessdildo.com +streamingthe.net +streema.com +strikingly.com +strongvpn.com +strongwindpress.com +student.tw +studentsforafreetibet.org +stumbleupon.com +stupidvideos.com +subacme.rerouted.org +successfn.com +sugarsync.com +sugobbs.com +sugumiru18.com +suissl.com +sujiatun.wordpress.com +sukebei.nyaa.si +sulian.me +summify.com +sumrando.com +sun1911.com +sunmedia.ca +sunporno.com +sunskyforum.com +sunta.com.tw +sunvpn.net +sunwinism.joinbbs.net +suoluo.org +supchina.com +superfreevpn.com +superokayama.com +superpages.com +supervpn.net +superzooi.com +suppig.net +suprememastertv.com +surfeasy.com +surfeasy.com.au +suroot.com +surrenderat20.net +sustainability.google +suyangg.com +svsfx.com +swagbucks.com +swissvpn.net +switch1.jp +switchvpn.net +sydneytoday.com +sylfoundation.org +syncback.com +synergyse.com +sysresccd.org +sytes.net +szbbs.net +szetowah.org.hk +t-g.com +t.co +t.me +t.orzdream.com +t35.com +t66y.com +taa-usa.org +taaze.tw +tabtter.jp +tacc.cwb.gov.tw +tacem.org +taconet.com.tw +taedp.org.tw +tafm.org +tagwa.org.au +tagwalk.com +tahr.org.tw +taipei.gov.tw +taipeisociety.org +taiwan-sex.com +taiwanbible.com +taiwancon.com +taiwandaily.net +taiwandc.org +taiwanjobs.gov.tw +taiwanjustice.com +taiwanjustice.net +taiwankiss.com +taiwannation.50webs.com +taiwannation.com +taiwannation.com.tw +taiwanncf.org.tw +taiwannews.com.tw +taiwantp.net +taiwantt.org.tw +taiwanus.net +taiwanyes.com +taiwanyes.ning.com +talk853.com +talkboxapp.com +talkonly.net +tamiaode.tk +tanc.org +tangben.com +tangren.us +taoism.net +taolun.info +tapanwap.com +tapatalk.com +tarr.uspto.gov +tascn.com.au +taup.net +taweet.com +tbcollege.org +tbi.org.hk +tbicn.org +tbjyt.org +tbpic.info +tbrc.org +tbs-rainbow.org +tbsec.org +tbskkinabalu.page.tl +tbsmalaysia.org +tbsn.org +tbsseattle.org +tbssqh.org +tbswd.org +tbtemple.org.uk +tbthouston.org +tccwonline.org +tcewf.org +tchrd.org +tcnynj.org +tcpspeed.co +tcpspeed.com +tcsofbc.org +tcsovi.org +tdm.com.mo +teachparentstech.org +teamamericany.com +tech2.in.com +techviz.net +teck.in +teco-hk.org +teco-mo.org +teddysun.com +teeniefuck.net +teensinasia.com +telecomspace.com +telegram.dog +telegram.me +telegram.org +telegramdownload.com +telegraph.co.uk +telesco.pe +tellme.pw +tenacy.com +tensorflow.org +tenzinpalmo.com +terminus2049.github.io +tew.org +textnow.me +th.hao123.com +thaicn.com +thb.gov.tw +theatrum-belli.com +thebcomplex.com +theblemish.com +thebobs.com +thebodyshop-usa.com +thecenter.mit.edu +thechinabeat.org +thedalailamamovie.com +thedw.us +thefacebook.com +thefrontier.hk +thegioitinhoc.vn +thegly.com +thehots.info +thehousenews.com +thehun.net +theinitium.com +thenewslens.com +thepiratebay.org +theportalwiki.com +thereallove.kr +therock.net.nz +thespeeder.com +thestandnews.com +thetibetcenter.org +thetibetconnection.org +thetibetmuseum.org +thetibetpost.com +thetinhat.com +thetrotskymovie.com +thevivekspot.com +thewgo.org +theync.com +thinkingtaiwan.com +thinkwithgoogle.com +thisav.com +thlib.org +thomasbernhard.org +thongdreams.com +threatchaos.com +throughnightsfire.com +thumbzilla.com +thywords.com +thywords.com.tw +tiananmenduizhi.com +tiananmenmother.org +tiananmenuniv.com +tiananmenuniv.net +tiandixing.org +tianhuayuan.com +tianlawoffice.com +tianti.io +tiantibooks.org +tianyantong.org.cn +tianzhu.org +tibet-envoy.eu +tibet-foundation.org +tibet-house-trust.co.uk +tibet-info.net +tibet-initiative.de +tibet-munich.de +tibet.a.se +tibet.at +tibet.ca +tibet.com +tibet.fr +tibet.net +tibet.nu +tibet.org +tibet.org.tw +tibet.sk +tibet.to +tibet3rdpole.org +tibetaction.net +tibetaid.org +tibetalk.com +tibetan-alliance.org +tibetan.fr +tibetanaidproject.org +tibetanarts.org +tibetanbuddhistinstitute.org +tibetancommunity.org +tibetancommunityuk.net +tibetanculture.org +tibetanfeministcollective.org +tibetanjournal.com +tibetanlanguage.org +tibetanliberation.org +tibetanpaintings.com +tibetanphotoproject.com +tibetanpoliticalreview.org +tibetanreview.net +tibetansports.org +tibetanwomen.org +tibetanyouth.org +tibetanyouthcongress.org +tibetcharity.dk +tibetcharity.in +tibetchild.org +tibetcity.com +tibetcollection.com +tibetcorps.org +tibetexpress.net +tibetfocus.com +tibetfund.org +tibetgermany.com +tibetgermany.de +tibethaus.com +tibetheritagefund.org +tibethouse.jp +tibethouse.org +tibethouse.us +tibetinfonet.net +tibetjustice.org +tibetkomite.dk +tibetlibre.free.fr +tibetmuseum.org +tibetnetwork.org +tibetoffice.ch +tibetoffice.com.au +tibetoffice.eu +tibetoffice.org +tibetonline.com +tibetonline.tv +tibetoralhistory.org +tibetpolicy.eu +tibetrelieffund.co.uk +tibetsites.com +tibetsociety.com +tibetsun.com +tibetsupportgroup.org +tibetswiss.ch +tibettelegraph.com +tibettimes.net +tibetwrites.org +ticket.com.tw +tigervpn.com +tiltbrush.com +timdir.com +time.com +times.hinet.net +timesofindia.indiatimes.com +timsah.com +tineye.com +tintuc101.com +tiny.cc +tinychat.com +tinypaste.com +tipo.gov.tw +tistory.com +tkcs-collins.com +tl.gd +tma.co.jp +tmagazine.com +tmdfish.com +tmi.me +tmpp.org +tn1.shemalez.com +tn2.shemalez.com +tn3.shemalez.com +tnaflix.com +tngrnow.com +tngrnow.net +tnp.org +to-porno.com +togetter.com +toh.info +tokyo-247.com +tokyo-hot.com +tokyo-porn-tube.com +tokyocn.com +tongil.or.kr +tono-oka.jp +tonyyan.net +toodoc.com +toonel.net +top.tv +top81.ws +topbtc.com +topic.youthwant.com.tw +topnews.in +toppornsites.com +topshareware.com +topsy.com +toptip.ca +tor.blingblingsquad.net +tor.cn.uptodown.com +tor.updatestar.com +tora.to +torcn.com +torguard.net +torproject.org +torrentprivacy.com +torrentproject.se +torrenty.org +torrentz.eu +torvpn.com +tosh.comedycentral.com +totalvpn.com +toutiaoabc.com +towngain.com +toypark.in +toythieves.com +toytractorshow.com +tparents.org +tpi.org.tw +tracfone.com +traffichaus.com +trans.wenweipo.com +transparency.org +treemall.com.tw +trendsmap.com +trialofccp.org +trickip.net +trickip.org +trimondi.de +trouw.nl +trt.net.tr +trtc.com.tw +truebuddha-md.org +trulyergonomic.com +truth101.co.tv +truthontour.org +truveo.com +tryheart.jp +tsctv.net +tsdr.uspto.gov +tsemtulku.com +tsquare.tv +tsu.org.tw +tsunagarumon.com +tt-rss.org +tt1069.com +tttan.com +ttvnw.net +tu8964.com +tubaholic.com +tube.com +tube8.com +tube911.com +tubecup.com +tubegals.com +tubeislam.com +tubepornclassic.com +tubestack.com +tubewolf.com +tui.orzdream.com +tuibeitu.net +tuidang.net +tuidang.org +tuidang.se +tuitwit.com +tumblr.com +tumutanzi.com +tumview.com +tunein.com +tunnelbear.com +tunnelr.com +tuo8.blue +tuo8.cc +tuo8.club +tuo8.fit +tuo8.hk +tuo8.in +tuo8.ninja +tuo8.org +tuo8.pw +tuo8.red +tuo8.space +turansam.org +turbobit.net +turbohide.com +turbotwitter.com +turntable.fm +tushycash.com +tuvpn.com +tuzaijidi.com +tv.com +tvants.com +tvboxnow.com +tvider.com +tvmost.com.hk +tvplayvideos.com +tvunetworks.com +tw-blog.com +tw-npo.org +tw.answers.yahoo.com +tw.bid.yahoo.com +tw.gigacircle.com +tw.hao123.com +tw.jiepang.com +tw.knowledge.yahoo.com +tw.mall.yahoo.com +tw.mobi.yahoo.com +tw.money.yahoo.com +tw.myblog.yahoo.com +tw.news.yahoo.com +tw.streetvoice.com +tw.tomonews.net +tw.voa.mobi +tw.yahoo.com +tw01.org +twaitter.com +twapperkeeper.com +twaud.io +twavi.com +twbbs.net.tw +twbbs.org +twbbs.tw +twblogger.com +tweepguide.com +tweeplike.me +tweepmag.com +tweepml.org +tweetbackup.com +tweetboard.com +tweetboner.biz +tweetcs.com +tweetdeck.com +tweetedtimes.com +tweetmylast.fm +tweetphoto.com +tweetrans.com +tweetree.com +tweets.seraph.me +tweettunnel.com +tweetwally.com +tweetymail.com +tweez.net +twelve.today +twerkingbutt.com +twftp.org +twgreatdaily.com +twibase.com +twibble.de +twibbon.com +twibs.com +twicountry.org +twicsy.com +twiends.com +twifan.com +twiffo.com +twiggit.org +twilightsex.com +twilog.org +twimbow.com +twimg.com +twimg.edgesuite.net +twindexx.com +twip.me +twipple.jp +twishort.com +twistar.cc +twister.net.co +twisterio.com +twisternow.com +twistory.net +twit2d.com +twitbrowser.net +twitcause.com +twitch.tv +twitchcdn.net +twitgether.com +twitgoo.com +twitiq.com +twitlonger.com +twitmania.com +twitoaster.com +twitonmsn.com +twitpic.com +twitstat.com +twittbot.net +twitter.com +twitter.jp +twitter4j.org +twittercounter.com +twitterfeed.com +twittergadget.com +twitterkr.com +twittermail.com +twitterrific.com +twittertim.es +twitthat.com +twitturk.com +twitturly.com +twitvid.com +twitzap.com +twiyia.com +twnorth.org.tw +twskype.com +twstar.net +twt.tl +twtkr.com +twtr2src.ogaoga.org +twtrland.com +twttr.com +twurl.nl +twyac.org +txxx.com +tycool.com +typepad.com +u9un.com +ub0.cc +ubddns.org +uberproxy.net +uc-japan.org +ucdc1998.org +uchicago.edu +uderzo.it +udn.com +udn.com.tw +udnbkk.com +uforadio.com.tw +ufreevpn.com +ug.m.wikipedia.org +ugo.com +uhdwallpapers.org +uhrp.org +uighur.narod.ru +uighur.nl +uighurbiz.net +ukcdp.co.uk +ukliferadio.co.uk +uku.im +ulike.net +ulop.net +ultravpn.fr +ultraxs.com +umich.edu +unblock-us.com +unblock.cn.com +unblockdmm.com +unblocker.yt +unblocksit.es +uncyclomedia.org +uncyclopedia.hk +uncyclopedia.tw +underwoodammo.com +unholyknight.com +uni.cc +unification.net +unification.org.tw +unirule.cloud +unitedsocialpress.com +unix100.com +unknownspace.org +unodedos.com +unpo.org +unseen.is +untraceable.us +uocn.org +upcoming.yahoo.com +updates.tdesktop.com +upholdjustice.org +upload4u.info +uploaded.net +uploaded.to +uploadstation.com +upmedia.mg +upornia.com +uproxy.org +upwill.org +ur7s.com +uraban.me +urbansurvival.com +urchin.com +urlborg.com +urlparser.com +us.to +usacn.com +usaip.eu +userapi.nytlog.com +users.skynet.be +usfk.mil +ushuarencity.echainhost.com +usinfo.state.gov +usma.edu +usmc.mil +usmgtcg.ning.com +usno.navy.mil +usocctn.com +ustream.tv +usunitednews.com +usus.cc +utopianpal.com +uu-gg.com +uvwxyz.xyz +uwants.com +uwants.net +uyghur-j.org +uyghur.co.uk +uyghuramerican.org +uyghurcanadiansociety.org +uyghurcongress.org +uyghurensemble.co.uk +uyghurpen.org +uyghurpress.com +uyghurstudies.org +uygur.fc2web.com +uygur.org +uymaarip.com +v2ex.com +v2ray.com +van001.com +van698.com +vanemu.cn +vanilla-jp.com +vanpeople.com +vansky.com +vatn.org +vcf-online.org +vcfbuilder.org +vds.rightster.com +vegas.williamhill.com +vegasred.com +velkaepocha.sk +venbbs.com +venchina.com +venetianmacao.com +ventureswell.com +veoh.com +vermonttibet.org +versavpn.com +verybs.com +vevo.com +vft.com.tw +viber.com +vica.info +victimsofcommunism.org +vid.me +vidble.com +video.aol.ca +video.aol.co.uk +video.aol.com +video.ap.org +video.fdbox.com +video.foxbusiness.com +video.pbs.org +video.yahoo.com +videobam.com +videodetective.com +videomega.tv +videomo.com +videopediaworld.com +videopress.com +vidinfo.org +vietdaikynguyen.com +vijayatemple.org +vimeo.com +vimperator.org +vincnd.com +vine.co +vinniev.com +vip-enterprise.com +virtualrealporn.com +visibletweets.com +vital247.org +viu.com +viu.tv +vivahentai4u.net +vivatube.com +vivthomas.com +vizvaz.com +vjav.com +vjmedia.com.hk +vllcs.org +vlog.xuite.net +vmixcore.com +vmpsoft.com +vn.hao123.com +vnet.link +voa-11.akacast.akamaistream.net +voacantonese.com +voachinese.com +voachineseblog.com +voagd.com +voanews.com +voatibetan.com +voatibetanenglish.com +vocativ.com +vocn.tv +vod-abematv.akamaized.net +vod.wwe.com +vot.org +vovo2000.com +voxer.com +voy.com +vpn.ac +vpn.cjb.net +vpn.cmu.edu +vpn.sv.cmu.edu +vpn4all.com +vpnaccount.org +vpnaccounts.com +vpnbook.com +vpncomparison.org +vpncoupons.com +vpncup.com +vpndada.com +vpnfan.com +vpnfire.com +vpnfires.biz +vpnforgame.net +vpngate.jp +vpngate.net +vpngratis.net +vpnhq.com +vpninja.net +vpnintouch.com +vpnintouch.net +vpnjack.com +vpnmaster.com +vpnmentor.com +vpnpick.com +vpnpop.com +vpnpronet.com +vpnreactor.com +vpnreviewz.com +vpnsecure.me +vpnshazam.com +vpnshieldapp.com +vpnsp.com +vpntraffic.com +vpntunnel.com +vpnuk.info +vpnunlimitedapp.com +vpnvip.com +vpnworldwide.com +vporn.com +vpser.net +vraiesagesse.net +vrmtr.com +vrsmash.com +vtunnel.com +vuku.cc +w.idaiwan.com +w3schools.com +waffle1999.com +wahas.com +waigaobu.com +waikeung.org +wailaike.net +waiwaier.com +wallmama.com +wallornot.org +wallpapercasa.com +wallproxy.com +waltermartin.com +waltermartin.org +wanderinghorse.net +wangafu.net +wangjinbo.org +wanglixiong.com +wango.org +wangruoshui.net +want-daily.com +wanz-factory.com +wapedia.mobi +warbler.iconfactory.net +waselpro.com +washeng.net +watch8x.com +watchinese.com +watchmygf.net +wattpad.com +wav.tv +waveprotocol.org +waymo.com +wda.gov.tw +wdf5.com +wearehairy.com +wearn.com +web.dev +web2project.net +webbang.net +webevader.org +webfreer.com +webjb.org +weblagu.com +webmproject.org +webrtc.org +webrush.net +webs-tv.net +website.informer.com +websitepulse.com +webwarper.net +webworkerdaily.com +weekmag.info +wefightcensorship.org +wefong.com +wego.here.com +weiboleak.com +weiboscope.jmsc.hku.hk +weihuo.org +weijingsheng.org +weiming.info +weiquanwang.org +weisuo.ws +welovecock.com +wemigrate.org +wengewang.com +wengewang.org +wenhui.ch +wenxuecity.com +wenyunchao.com +wenzhao.ca +westca.com +westernshugdensociety.org +westernwolves.com +westkit.net +westpoint.edu +wetplace.com +wetpussygames.com +wexiaobo.org +wezhiyong.org +wezone.net +wforum.com +wha.la +whatblocked.com +whatbrowser.org +whatsapp.com +whatsapp.net +whatsonweibo.com +wheatseeds.org +wheelockslatin.com +whereiswerner.com +wheretowatch.com +whippedass.com +whitebear.freebearblog.org +whodns.xyz +whoer.net +whotalking.com +whylover.com +whyx.org +widevine.com +wikaba.com +wiki.cnitter.com +wiki.esu.im +wiki.gamerp.jp +wiki.jqueryui.com +wiki.keso.cn +wiki.moegirl.org +wiki.oauth.net +wiki.phonegap.com +wikileaks-forum.com +wikileaks.ch +wikileaks.com +wikileaks.de +wikileaks.eu +wikileaks.lu +wikileaks.org +wikileaks.pl +wikilivres.info +wikimapia.org +wikiwiki.jp +wildammo.com +williamhill.com +willw.net +windowsphoneme.com +windscribe.com +wingamestore.com +wingy.site +winning11.com +winwhispers.info +wire.com +wiredbytes.com +wiredpen.com +wisdompubs.org +wisevid.com +withgoogle.com +withyoutube.com +witnessleeteaching.com +witopia.net +wizcrafts.net +wjbk.org +wlcnew.jigsy.com +wlx.sowiki.net +wn.com +wnacg.com +wnacg.org +wo.tc +wo3ttt.wordpress.com +woeser.com +woesermiddle-way.net +wokar.org +wolfax.com +woolyss.com +woopie.jp +woopie.tv +wordpress.com +workatruna.com +workerdemo.org.hk +workerempowerment.org +workersthebig.net +worldcat.org +worldjournal.com +worldvpn.net +wow-life.net +wow.com +wowgirls.com +wowlegacy.ml +wowporn.com +wowrk.com +woxinghuiguo.com +woyaolian.org +wozy.in +wp.com +wpoforum.com +wqyd.org +wrchina.org +wretch.cc +writer.zoho.com +wsgzao.github.io +wsj.com +wsj.net +wsjhk.com +wtbn.org +wtfpeople.com +wuerkaixi.com +wufafangwen.com +wufi.org.tw +wuguoguang.com +wujie.net +wujieliulan.com +wukangrui.net +wuu.wikipedia.org +wuw.red +wuyanblog.com +wwitv.com +www.abclite.net +www.ajsands.com +www.americorps.gov +www.antd.org +www.aolnews.com +www.businessinsider.com.au +www.citizenlab.org +www.cmoinc.org +www.cool18.com +www.dmm.com +www.dwheeler.com +www.eastturkistan.net +www.ftchinese.com +www.gmiddle.com +www.gmiddle.net +www.hustlercash.com +www.idlcoyote.com +www.imdb.com +www.kindleren.com +www.klip.me +www.lamenhu.com +www.lib.virginia.edu +www.linksalpha.com +www.m-sport.co.uk +www.metro.taipei +www.monlamit.org +www.moztw.org +www.nbc.com +www.orchidbbs.com +www.owind.com +www.oxid.it +www.powerpointninja.com +www.s4miniarchive.com +www.sciencemag.org +www.shadowsocks.com +www.shwchurch.org +www.skype.com +www.tablesgenerator.com +www.taiwanonline.cc +www.taup.org.tw +www.thechinastory.org +www.wan-press.org +www.wangruowang.org +www.websnapr.com +www.zensur.freerk.com +www1.american.edu +www1.biz +www2.ohchr.org +www2.rocketbbs.com +wwwhost.biz +wzyboy.im +x-art.com +x-berry.com +x-wall.org +x.company +x1949x.com +x24hr.com +x365x.com +xa.yimg.com +xanga.com +xbabe.com +xbookcn.com +xbtce.com +xcafe.in +xcity.jp +xcritic.com +xda-developers.com +xerotica.com +xfinity.com +xfm.pp.ru +xgmyd.com +xhamster.com +xianba.net +xianchawang.net +xianjian.tw +xianqiao.net +xiaobaiwu.com +xiaochuncnjp.com +xiaod.in +xiaohexie.com +xiaolan.me +xiaoma.org +xiezhua.com +xihua.es +xijie.wordpress.com +xing.com +xinhuanet.org +xinmiao.com.hk +xinqimeng.over-blog.com +xinsheng.net +xinshijue.com +xinyubbs.net +xiongpian.com +xiuren.org +xizang-zhiye.org +xjp.cc +xjtravelguide.com +xkiwi.tk +xlfmtalk.com +xlfmwz.info +xm.com +xml-training-guide.com +xmovies.com +xn--4gq171p.com +xn--czq75pvv1aj5c.org +xn--i2ru8q2qg.com +xn--ngstr-lra8j.com +xn--oiq.cc +xn--p8j9a0d9c9a.xn--q9jyb4c +xnxx.com +xpdo.net +xpenology.com +xpud.org +xrentdvd.com +xskywalker.com +xskywalker.net +xtube.com +xuchao.net +xuchao.org +xuehua.us +xuzhiyong.net +xvideo.cc +xvideos.com +xvideos.es +xxbbx.com +xxlmovies.com +xxuz.com +xxx.com +xxx.xxx +xxxfuckmom.com +xxxx.com.au +xxxy.biz +xxxy.info +xxxymovies.com +xys.dxiong.com +xys.org +xysblogs.org +xyy69.com +xyy69.info +yahoo.com.hk +yakbutterblues.com +yam.com +yam.org.tw +yanghengjun.com +yangjianli.com +yasni.co.uk +yayabay.com +ydy.com +yeahteentube.com +yecl.net +yeelou.com +yeeyi.com +yegle.net +yes-news.com +yes.xxx +yes123.com.tw +yesasia.com +yesasia.com.hk +yespornplease.com +yeyeclub.com +ygto.com +yhcw.net +yibada.com +yibaochina.com +yidio.com +yilubbs.com +yingsuoss.com +yinlei.org +yipub.com +yizhihongxing.com +yobit.net +yobt.com +yobt.tv +yogichen.org +yolasite.com +yomiuri.co.jp +yong.hu +yorkbbs.ca +youdontcare.com +youjizz.com +youmaker.com +youngpornvideos.com +youngspiration.hk +youpai.org +youporn.com +youporngay.com +your-freedom.net +yourepeat.com +yourlisten.com +yourlust.com +yourprivatevpn.com +yourtrap.com +yousendit.com +youshun12.com +youthnetradio.org +youtu.be +youtube-nocookie.com +youtube.com +youtubecn.com +youtubeeducation.com +youtubegaming.com +youversion.com +youwin.com +youxu.info +yt.be +ytht.net +ytimg.com +ytn.co.kr +yuanming.net +yuanzhengtang.org +yulghun.com +yunchao.net +yuntipub.com +yuvutu.com +yvesgeleyn.com +ywpw.com +yx51.net +yyii.org +yzzk.com +zacebook.com +zalmos.com +zannel.com +zaobao.com +zaobao.com.sg +zaozon.com +zapto.org +zattoo.com +zb.com +zdnet.com.tw +zello.com +zengjinyan.org +zenmate.com +zenmate.com.ru +zeronet.io +zeutch.com +zfreet.com +zgsddh.com +zgzcjj.net +zh-yue.wikipedia.org +zh.bitterwinter.org +zh.ecdm.wikia.com +zh.m.wikipedia.org +zh.pokerstrategy.com +zh.pttpedia.wikia.com +zh.uncyclopedia.wikia.com +zh.wikinews.org +zh.wikipedia.org +zh.wikisource.org +zhanbin.net +zhangboli.net +zhangtianliang.com +zhanlve.org +zhao.1984.city +zhao.jinhai.de +zhenghui.org +zhengjian.org +zhengwunet.org +zhenlibu.info +zhenlibu1984.com +zhenxiang.biz +zhinengluyou.com +zhongguo.ca +zhongguorenquan.org +zhongguotese.net +zhongmeng.org +zhoushuguang.com +zhreader.com +zhuangbi.me +zhuanxing.cn +zhuatieba.com +zhuichaguoji.org +ziddu.com +zillionk.com +zim.vn +zinio.com +ziporn.com +zippyshare.com +zkaip.com +zmw.cn +zodgame.us +zomobo.net +zonaeuropa.com +zonghexinwen.com +zonghexinwen.net +zoogvpn.com +zootool.com +zoozle.net +zorrovpn.com +zozotown.com +zpn.im +zspeeder.me +zsrhao.com +zuo.la +zuobiao.me +zuola.com +zvereff.com +zynaima.com +zynamics.com +zyns.com +zyzc9.com +zzcartoon.com +zzcloud.me +zzux.com diff --git a/dnsforwarder/files/etc/init.d/dnsforwarder b/dnsforwarder/files/etc/init.d/dnsforwarder new file mode 100755 index 000000000..5cfceb8d4 --- /dev/null +++ b/dnsforwarder/files/etc/init.d/dnsforwarder @@ -0,0 +1,260 @@ +#!/bin/sh /etc/rc.common + +START=60 + +EXTRA_COMMANDS="makeconfig makegfwlist health" + +CRON_FILE=/etc/crontabs/root +PID_PATH=/var/run/dnsforwarder +PID_FILE=${PID_PATH}/dns.pid +DNSFORWARDER_CONF=/tmp/dnsforwarder.conf + +add_cron() +{ + sed -i '/dnsforwarder/d' $CRON_FILE + echo '*/5 * * * * /etc/init.d/dnsforwarder health' >> $CRON_FILE + echo '0 1 * * 0 /etc/init.d/dnsforwarder makegfwlist' >> $CRON_FILE + crontab $CRON_FILE +} + +del_cron() +{ + sed -i '/dnsforwarder/d' $CRON_FILE + /etc/init.d/cron restart +} + +fixturboacc(){ + dns=$(uci get turboacc.config.dns_caching 2>/dev/null) + if [ $dns -eq 1 ]; then + uci set turboacc.config.dns_caching=0 && uci commit turboacc + /etc/init.d/turboacc restart + fi +} + +makelist() { + [ -z "$2" ] && return + local i + local t="$1"; shift + for i in "$@" + do + echo "$t $i" + done +} + +health(){ + rm /var/log/dnsforwarder.log.* 2>/dev/null + local pid=$(cat ${PID_FILE} 2>/dev/null) + if [ -n "${pid}" -a -d /proc/$pid ]; then + echo "[health] process exists ${pid}" + else + echo "[health] Dnsforwarder is not running ${pid}" + start + fi +} + + +makegfwlist(){ + local GFW_FILE='/etc/dnsforwarder/gfw.txt' + local GFW_TMP_FILE='/tmp/dnsforwarder-gfw.old' + local TSTIME=`date '+%Y-%m-%d %H:%M:%S'` + touch ${GFW_TMP_FILE} + cat /etc/config/gfw.list 2>/dev/null > /tmp/edf.ts + cat /etc/dnsmasq.ssr/gfw_base.conf 2>/dev/null | awk -F '/' '{print $2}' | sed 's/^.//g' >> /tmp/edf.ts + cat /etc/dnsmasq.ssr/gfw_list.conf 2>/dev/null | awk -F '/' '{print $2}' | sed 's/^.//g' >> /tmp/edf.ts + sort /tmp/edf.ts | uniq > /tmp/edf.ts + /usr/share/dnsforwarder/gfwlist.sh -i -l -o /tmp/dnsforwarder-gfw.tmp --extra-domain-file /tmp/edf.ts + if [ $? != 0 ]; then + echo 'Failed to fetch gfwlist' + logger -t Failed to fetch gfwlist + return 2 + fi + local gfw=$(cat /tmp/dnsforwarder-gfw.tmp) + echo "# GenerationAt TS_BUILD_TIME" > ${GFW_TMP_FILE}.new + echo "protocol tcp" >> ${GFW_TMP_FILE}.new + echo "server 8.8.8.8,8.8.4.4,1.1.1.1,1.0.0.1,208.67.222.222,208.67.220.220,209.244.0.3,209.244.0.4,8.26.56.26,8.20.247.20,156.154.70.1,156.154.71.1,199.85.126.10" >> ${GFW_TMP_FILE}.new + echo -e 'proxy no\n\n\n' >> ${GFW_TMP_FILE}.new + echo "${gfw}" >> ${GFW_TMP_FILE}.new + if [ "`cat ${GFW_TMP_FILE}.new | md5sum`" == "`cat ${GFW_TMP_FILE} | md5sum`" ]; then + printf "[\e[32m%s\e[0m]\n" "hold" + else + cp ${GFW_TMP_FILE}.new ${GFW_TMP_FILE} + cp ${GFW_TMP_FILE} ${GFW_FILE} + sed -i "s/TS_BUILD_TIME/${TSTIME}/g" ${GFW_FILE} + printf "[\e[33m%s\e[0m]" "PID" + restart + fi +} + +makeconfig () { + config_load dnsforwarder + + local log=$(uci get dnsforwarder.@config[0].log 2>/dev/null) + local log_size=$(uci get dnsforwarder.@config[0].log_size 2>/dev/null) + + local gfw=$(uci get dnsforwarder.@config[0].gfw 2>/dev/null) + + local udp_local=$(uci -d ',' get dnsforwarder.@config[0].udp_local 2>/dev/null) + local udp_local_list=$(uci get dnsforwarder.@config[0].udp_local 2>/dev/null) + local tcp_group=$(uci get dnsforwarder.@config[0].tcp_group 2>/dev/null) + local udp_group=$(uci get dnsforwarder.@config[0].udp_group 2>/dev/null) + local group_file=$(uci get dnsforwarder.@config[0].group_file 2>/dev/null) + local block_ip=$(uci -d ',' get dnsforwarder.@config[0].block_ip 2>/dev/null) + local ip_substituting=$(uci -d ',' get dnsforwarder.@config[0].ip_substituting 2>/dev/null) + local block_negative_resp=$(uci get dnsforwarder.@config[0].block_negative_resp 2>/dev/null) + local append_host=$(uci get dnsforwarder.@config[0].append_host 2>/dev/null) + local block_ipv6=$(uci get dnsforwarder.@config[0].block_ipv6 2>/dev/null) + + local cache=$(uci get dnsforwarder.@config[0].cache 2>/dev/null) + local cache_size=$(uci get dnsforwarder.@config[0].cache_size 2>/dev/null) + local cache_ignore=$(uci get dnsforwarder.@config[0].cache_ignore 2>/dev/null) + local cache_control=$(uci get dnsforwarder.@config[0].cache_control 2>/dev/null) + + local domain_statistic=$(uci get dnsforwarder.@config[0].domain_statistic 2>/dev/null) + local udp_local_addr=$(uci get dnsforwarder.@arguments[0].addr 2>/dev/null) + udp_local_addr=${udp_local_addr/:/#} + + echo "LogOn ${log}" > $DNSFORWARDER_CONF + if [ $log = "true" ]; then + rm /var/log/dnsforwarder.log.* 2>/dev/null + echo '' > /var/log/dnsforwarder.log + echo "LogFileThresholdLength ${log_size}" >> $DNSFORWARDER_CONF + echo "LogFileFolder /var/log" >> $DNSFORWARDER_CONF + fi + + [ -n "$udp_local" ] && echo "UDPLocal ${udp_local}" >> $DNSFORWARDER_CONF + [ -n "$udp_local_addr" ] && eval "makelist 'server=' $udp_local_addr" > /tmp/dnsmasq.dnsforwarder.conf + sed -i "s/ //g" /tmp/dnsmasq.dnsforwarder.conf + + eval "makelist 'TCPGroup' $tcp_group" >> $DNSFORWARDER_CONF + eval "makelist 'UDPGroup' $udp_group" >> $DNSFORWARDER_CONF + eval "makelist 'GroupFile' $group_file" >> $DNSFORWARDER_CONF + + if [ $gfw = "true" ]; then + echo 'GroupFile /etc/dnsforwarder/gfw.txt' >> $DNSFORWARDER_CONF + fi + + echo "BlockIP ${block_ip}" >> $DNSFORWARDER_CONF + eval "makelist 'IPSubstituting' $ip_substituting" >> $DNSFORWARDER_CONF + echo "BlockNegativeResponse ${block_negative_resp}" >> $DNSFORWARDER_CONF + eval "makelist 'AppendHosts' $append_host" >> $DNSFORWARDER_CONF + echo "BlockIpv6WhenIpv4Exists ${block_ipv6}" >> $DNSFORWARDER_CONF + + echo "UseCache ${cache}" >> $DNSFORWARDER_CONF + if [ $cache = "true" ]; then + echo "CacheSize ${cache_size}" >> $DNSFORWARDER_CONF + echo "MemoryCache false" >> $DNSFORWARDER_CONF + echo "CacheFile /tmp/dnsforwarder.cache" >> $DNSFORWARDER_CONF + echo "IgnoreTTL ${cache_ignore}" >> $DNSFORWARDER_CONF + eval "makelist 'CacheControl' $cache_control" >> $DNSFORWARDER_CONF + echo "ReloadCache true" >> $DNSFORWARDER_CONF + echo "OverwriteCache true" >> $DNSFORWARDER_CONF + fi + echo "DomainStatistic ${domain_statistic}" >> $DNSFORWARDER_CONF + if [ $domain_statistic = "true" ]; then + touch /tmp/dnsforwarder-statistic.html + mkdir -p /root/.dnsforwarder + rm /root/.dnsforwarder/statistic.html 2 > /dev/null + ln -s /tmp/dnsforwarder-statistic.html /root/.dnsforwarder/statistic.html + local domain_statistic_tag='' + echo "DomainStatisticTempletFile /tmp/dnsforwarder-statistic.html" >> $DNSFORWARDER_CONF + echo "StatisticInsertionPosition ${domain_statistic_tag}" >> $DNSFORWARDER_CONF + echo "StatisticUpdateInterval 60" >> $DNSFORWARDER_CONF + echo "${domain_statistic_tag}" > /tmp/dnsforwarder-statistic.html + fi +} + +start() +{ + echo luci for dnsforwarder + local vt_enabled=$(uci get dnsforwarder.@arguments[0].enabled 2>/dev/null) + if [ $vt_enabled = 0 ]; then + echo dnsforwarder is not enabled + exit + fi + makeconfig + fixturboacc + dnsforwarder -f $DNSFORWARDER_CONF -d + sleep 10 + mkdir -p ${PID_PATH} + pid=$(ps | awk '$5 ~ /\[dnsforwarder\]/ {print $1}') + echo "dnsforwarder running pid is ${pid}" + logger -t The pid of dnsforwarder is ${PID_FILE} ${pid} + echo ${pid} > ${PID_FILE} + /etc/init.d/dnsforwarder enable + local dnsmasq=$(uci get dnsforwarder.@arguments[0].dnsmasq 2>/dev/null) + local addr=$(uci get dnsforwarder.@arguments[0].addr 2>/dev/null) + [ -n "${addr}" ] && addr=${addr/:/#} + + if [ "${dnsmasq}" = "1" ]; then + uci delete dhcp.@dnsmasq[0].server 2>/dev/null + # uci add_list dhcp.@dnsmasq[0].server=$addr + uci delete dhcp.@dnsmasq[0].resolvfile 2>/dev/null + uci set dhcp.@dnsmasq[0].noresolv=1 + uci set dhcp.@dnsmasq[0].serversfile=/tmp/dnsmasq.dnsforwarder.conf + uci commit dhcp + /etc/init.d/dnsmasq restart + fi + local dnsmasq_server_addr=$(uci get dhcp.@dnsmasq[0].server 2>/dev/null) + if [ -n "${dnsmasq_server_addr}" ]; then + uci set dhcp.@dnsmasq[0].noresolv=1 + uci commit dhcp + /etc/init.d/dnsmasq restart + fi + add_cron +} + +stop() +{ + del_cron + logger -t stopping dnsforwarder + local addr=$(uci get dnsforwarder.@arguments[0].addr 2>/dev/null) + local dnsmasq=$(uci get dnsforwarder.@arguments[0].dnsmasq 2>/dev/null) + addr=${addr/:/#} + if [ "${dnsmasq}" = "1" ]; then + uci del_list dhcp.@dnsmasq[0].server=$addr 2>/dev/null + fi + uci set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.d/resolv.conf.auto 2>/dev/null + uci delete dhcp.@dnsmasq[0].noresolv 2>/dev/null + uci delete dhcp.@dnsmasq[0].serversfile 2>/dev/null + uci commit dhcp + /etc/init.d/dnsmasq restart + [ -e ${PID_FILE} ] && { + pid=$(cat ${PID_FILE}) + logger -t killing dnsforwarder pid ${pid} + echo killing dnsforwarder pid ${pid} + kill ${pid} + rm -f ${PID_FILE} + } || { + logger -t Cannot find dnsforwarder pid file + } +} + +restart() +{ + pid=$(cat ${PID_FILE} 2>/dev/null) + echo Dnsforwarder pid file is ${pid} + [ -n "$pid" ] && { + echo stopping pid ${pid} + logger -t There is dnsforwarder pid ${pid} + stop + } || { + logger -t Dnsforwarder is not running + } + sleep 7 + local vt_enabled=$(uci get dnsforwarder.@arguments[0].enabled 2>/dev/null) + echo dnsforwarder status is ${vt_enabled} + logger -t Dnsforwarder is initializing enabled is ${vt_enabled} + if [ ${vt_enabled} = 1 ]; then + [ -n "$pid" ] && { + logger -t There is dnsforwarder pid ${pid} + stop + } || { + logger -t Dnsforwarder is not running + } + + logger -t Restarting dnsforwarder + start + else + /etc/init.d/dnsforwarder disable + fi +} diff --git a/dnsforwarder/files/usr/share/dnsforwarder/gfwlist.sh b/dnsforwarder/files/usr/share/dnsforwarder/gfwlist.sh new file mode 100755 index 000000000..7bcbaec7d --- /dev/null +++ b/dnsforwarder/files/usr/share/dnsforwarder/gfwlist.sh @@ -0,0 +1,313 @@ +#/bin/sh + +# Name: gfwlist2dnsmasq.sh +# Desription: A shell script which convert gfwlist into dnsmasq rules. +# Version: 0.8.0 (2017.12.25) +# Author: Cokebar Chi +# Website: https://github.com/cokebar + +_green() { + printf '\033[1;31;32m' + printf -- "%b" "$1" + printf '\033[0m' +} + +_red() { + printf '\033[1;31;31m' + printf -- "%b" "$1" + printf '\033[0m' +} + +_yellow() { + printf '\033[1;31;33m' + printf -- "%b" "$1" + printf '\033[0m' +} + +usage() { + cat <<-EOF + +Name: gfwlist2dnsmasq.sh +Desription: A shell script which convert gfwlist into dnsmasq rules. +Version: 0.8.0 (2017.12.25) +Author: Cokebar Chi +Website: https://github.com/cokebar + +Usage: sh gfwlist2dnsmasq.sh [options] -o FILE +Valid options are: + -d, --dns + DNS IP address for the GfwList Domains (Default: 127.0.0.1) + -p, --port + DNS Port for the GfwList Domains (Default: 5353) + -s, --ipset + Ipset name for the GfwList domains + (If not given, ipset rules will not be generated.) + -o, --output + /path/to/output_filename + -i, --insecure + Force bypass certificate validation (insecure) + -l, --domain-list + Convert Gfwlist into domain list instead of dnsmasq rules + (If this option is set, DNS IP/Port & ipset are not needed) + --exclude-domain-file + Delete specific domains in the result from a domain list text file + Please put one domain per line + --extra-domain-file + Include extra domains to the result from a domain list text file + This file will be processed after the exclude-domain-file + Please put one domain per line + -h, --help + Usage +EOF + exit $1 +} + +clean_and_exit(){ + # Clean up temp files + printf 'Cleaning up... ' + rm -rf $TMP_DIR + _green 'Done\n\n' + [ $1 -eq 0 ] && _green 'Job Finished.\n\n' || _red 'Exit with Error code '$1'.\n' + exit $1 +} + +check_depends(){ + which sed base64 curl >/dev/null + if [ $? != 0 ]; then + _red 'Error: Missing Dependency.\nPlease check whether you have the following binaries on you system:\nwhich, sed, base64, curl.\n' + exit 3 + fi + + SYS_KERNEL=`uname -s` + if [ $SYS_KERNEL = "Darwin" -o $SYS_KERNEL = "FreeBSD" ]; then + BASE64_DECODE='base64 -D' + SED_ERES='sed -E' + else + BASE64_DECODE='base64 -d' + SED_ERES='sed -r' + fi +} + +get_args(){ + OUT_TYPE='DNSMASQ_RULES' + DNS_IP='127.0.0.1' + DNS_PORT='5353' + IPSET_NAME='' + FILE_FULLPATH='' + CURL_EXTARG='' + WITH_IPSET=0 + EXTRA_DOMAIN_FILE='' + EXCLUDE_DOMAIN_FILE='' + IPV4_PATTERN='^((2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)\.){3}(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)$' + IPV6_PATTERN='^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(%.+)?$' + + while [ ${#} -gt 0 ]; do + case "${1}" in + --help | -h) + usage 0 + ;; + --domain-list | -l) + OUT_TYPE='DOMAIN_LIST' + ;; + --insecure | -i) + CURL_EXTARG='--insecure' + ;; + --dns | -d) + DNS_IP="$2" + shift + ;; + --port | -p) + DNS_PORT="$2" + shift + ;; + --ipset | -s) + IPSET_NAME="$2" + shift + ;; + --output | -o) + OUT_FILE="$2" + shift + ;; + --extra-domain-file) + EXTRA_DOMAIN_FILE="$2" + shift + ;; + --exclude-domain-file) + EXCLUDE_DOMAIN_FILE="$2" + shift + ;; + *) + _red "Invalid argument: $1" + usage 1 + ;; + esac + shift 1 + done + + # Check path & file name + if [ -z $OUT_FILE ]; then + _red 'Error: Please specify the path to the output file(using -o/--output argument).\n' + exit 1 + else + if [ -z ${OUT_FILE##*/} ]; then + _red 'Error: '$OUT_FILE' is a path, not a file.\n' + exit 1 + else + if [ ${OUT_FILE}a != ${OUT_FILE%/*}a ] && [ ! -d ${OUT_FILE%/*} ]; then + _red 'Error: Folder do not exist: '${OUT_FILE%/*}'\n' + exit 1 + fi + fi + fi + + if [ $OUT_TYPE = 'DNSMASQ_RULES' ]; then + # Check DNS IP + IPV4_TEST=$(echo $DNS_IP | grep -E $IPV4_PATTERN) + IPV6_TEST=$(echo $DNS_IP | grep -E $IPV6_PATTERN) + if [ "$IPV4_TEST" != "$DNS_IP" -a "$IPV6_TEST" != "$DNS_IP" ]; then + _red 'Error: Please enter a valid DNS server IP address.\n' + exit 1 + fi + + # Check DNS port + if [ $DNS_PORT -lt 1 -o $DNS_PORT -gt 65535 ]; then + _red 'Error: Please enter a valid DNS server port.\n' + exit 1 + fi + + # Check ipset name + if [ -z $IPSET_NAME ]; then + WITH_IPSET=0 + else + IPSET_TEST=$(echo $IPSET_NAME | grep -E '^\w+$') + if [ "$IPSET_TEST" != "$IPSET_NAME" ]; then + _red 'Error: Please enter a valid IP set name.\n' + exit 1 + else + WITH_IPSET=1 + fi + fi + fi + + if [ ! -z $EXTRA_DOMAIN_FILE ] && [ ! -f $EXTRA_DOMAIN_FILE ]; then + _yellow 'WARNING:\nExtra domain file does not exist, ignored.\n\n' + EXTRA_DOMAIN_FILE='' + fi + + if [ ! -z $EXCLUDE_DOMAIN_FILE ] && [ ! -f $EXCLUDE_DOMAIN_FILE ]; then + _yellow 'WARNING:\nExclude domain file does not exist, ignored.\n\n' + EXCLUDE_DOMAIN_FILE='' + fi +} + + + +process(){ + # Set Global Var + BASE_URL='https://github.com/gfwlist/gfwlist/raw/master/gfwlist.txt' + TMP_DIR=`mktemp -d /tmp/gfwlist2dnsmasq.XXXXXX` + BASE64_FILE="$TMP_DIR/base64.txt" + GFWLIST_FILE="$TMP_DIR/gfwlist.txt" + DOMAIN_TEMP_FILE="$TMP_DIR/gfwlist2domain.tmp" + DOMAIN_FILE="$TMP_DIR/gfwlist2domain.txt" + CONF_TMP_FILE="$TMP_DIR/gfwlist.conf.tmp" + OUT_TMP_FILE="$TMP_DIR/gfwlist.out.tmp" + + # Fetch GfwList and decode it into plain text + printf 'Fetching GfwList... ' + local tscurl='curl -L --connect-timeout 5 -m 300 --retry 3 --retry-delay 1' + $tscurl $CURL_EXTARG -o$BASE64_FILE $BASE_URL \ + || $tscurl $CURL_EXTARG -o$BASE64_FILE https://gitlab.com/gfwlist/gfwlist/raw/master/gfwlist.txt \ + || $tscurl $CURL_EXTARG -o$BASE64_FILE https://git.tuxfamily.org/gfwlist/gfwlist.git/plain/gfwlist.txt \ + || $tscurl $CURL_EXTARG -o$BASE64_FILE https://pagure.io/gfwlist/raw/master/f/gfwlist.txt \ + || $tscurl $CURL_EXTARG -o$BASE64_FILE http://repo.or.cz/gfwlist.git/blob_plain/HEAD:/gfwlist.txt \ + || $tscurl $CURL_EXTARG -o$BASE64_FILE https://bitbucket.org/gfwlist/gfwlist/raw/HEAD/gfwlist.txt \ + || $tscurl $CURL_EXTARG -o$BASE64_FILE $BASE_URL + if [ $? != 0 ]; then + _red '\nFailed to fetch gfwlist.txt. Please check your Internet connection.\n' + clean_and_exit 2 + fi + $BASE64_DECODE $BASE64_FILE > $GFWLIST_FILE || ( _red 'Failed to decode gfwlist.txt. Quit.\n'; clean_and_exit 2 ) + _green 'Done.\n\n' + + # Convert + IGNORE_PATTERN='^\!|\[|^@@|(https?://){0,1}[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' + HEAD_FILTER_PATTERN='s#^(\|\|?)?(https?://)?##g' + TAIL_FILTER_PATTERN='s#/.*$|%2F.*$##g' + DOMAIN_PATTERN='([a-zA-Z0-9][-a-zA-Z0-9]*(\.[a-zA-Z0-9][-a-zA-Z0-9]*)+)' + HANDLE_WILDCARD_PATTERN='s#^(([a-zA-Z0-9]*\*[-a-zA-Z0-9]*)?(\.))?([a-zA-Z0-9][-a-zA-Z0-9]*(\.[a-zA-Z0-9][-a-zA-Z0-9]*)+)(\*)?#\4#g' + + printf 'Converting GfwList to ' && _green $OUT_TYPE && printf ' ...\n' + _yellow '\nWARNING:\nThe following lines in GfwList contain regex, and might be ignored:\n\n' + cat $GFWLIST_FILE | grep -n '^/.*$' + _yellow "\nThis script will try to convert some of the regex rules. But you should know this may not be a equivalent conversion.\nIf there's regex rules which this script do not deal with, you should add the domain manually to the list.\n\n" + grep -vE $IGNORE_PATTERN $GFWLIST_FILE | $SED_ERES $HEAD_FILTER_PATTERN | $SED_ERES $TAIL_FILTER_PATTERN | grep -E $DOMAIN_PATTERN | $SED_ERES $HANDLE_WILDCARD_PATTERN > $DOMAIN_TEMP_FILE + + printf 'google.com\ngoogle.ad\ngoogle.ae\ngoogle.com.af\ngoogle.com.ag\ngoogle.com.ai\ngoogle.al\ngoogle.am\ngoogle.co.ao\ngoogle.com.ar\ngoogle.as\ngoogle.at\ngoogle.com.au\ngoogle.az\ngoogle.ba\ngoogle.com.bd\ngoogle.be\ngoogle.bf\ngoogle.bg\ngoogle.com.bh\ngoogle.bi\ngoogle.bj\ngoogle.com.bn\ngoogle.com.bo\ngoogle.com.br\ngoogle.bs\ngoogle.bt\ngoogle.co.bw\ngoogle.by\ngoogle.com.bz\ngoogle.ca\ngoogle.cd\ngoogle.cf\ngoogle.cg\ngoogle.ch\ngoogle.ci\ngoogle.co.ck\ngoogle.cl\ngoogle.cm\ngoogle.cn\ngoogle.com.co\ngoogle.co.cr\ngoogle.com.cu\ngoogle.cv\ngoogle.com.cy\ngoogle.cz\ngoogle.de\ngoogle.dj\ngoogle.dk\ngoogle.dm\ngoogle.com.do\ngoogle.dz\ngoogle.com.ec\ngoogle.ee\ngoogle.com.eg\ngoogle.es\ngoogle.com.et\ngoogle.fi\ngoogle.com.fj\ngoogle.fm\ngoogle.fr\ngoogle.ga\ngoogle.ge\ngoogle.gg\ngoogle.com.gh\ngoogle.com.gi\ngoogle.gl\ngoogle.gm\ngoogle.gp\ngoogle.gr\ngoogle.com.gt\ngoogle.gy\ngoogle.com.hk\ngoogle.hn\ngoogle.hr\ngoogle.ht\ngoogle.hu\ngoogle.co.id\ngoogle.ie\ngoogle.co.il\ngoogle.im\ngoogle.co.in\ngoogle.iq\ngoogle.is\ngoogle.it\ngoogle.je\ngoogle.com.jm\ngoogle.jo\ngoogle.co.jp\ngoogle.co.ke\ngoogle.com.kh\ngoogle.ki\ngoogle.kg\ngoogle.co.kr\ngoogle.com.kw\ngoogle.kz\ngoogle.la\ngoogle.com.lb\ngoogle.li\ngoogle.lk\ngoogle.co.ls\ngoogle.lt\ngoogle.lu\ngoogle.lv\ngoogle.com.ly\ngoogle.co.ma\ngoogle.md\ngoogle.me\ngoogle.mg\ngoogle.mk\ngoogle.ml\ngoogle.com.mm\ngoogle.mn\ngoogle.ms\ngoogle.com.mt\ngoogle.mu\ngoogle.mv\ngoogle.mw\ngoogle.com.mx\ngoogle.com.my\ngoogle.co.mz\ngoogle.com.na\ngoogle.com.nf\ngoogle.com.ng\ngoogle.com.ni\ngoogle.ne\ngoogle.nl\ngoogle.no\ngoogle.com.np\ngoogle.nr\ngoogle.nu\ngoogle.co.nz\ngoogle.com.om\ngoogle.com.pa\ngoogle.com.pe\ngoogle.com.pg\ngoogle.com.ph\ngoogle.com.pk\ngoogle.pl\ngoogle.pn\ngoogle.com.pr\ngoogle.ps\ngoogle.pt\ngoogle.com.py\ngoogle.com.qa\ngoogle.ro\ngoogle.ru\ngoogle.rw\ngoogle.com.sa\ngoogle.com.sb\ngoogle.sc\ngoogle.se\ngoogle.com.sg\ngoogle.sh\ngoogle.si\ngoogle.sk\ngoogle.com.sl\ngoogle.sn\ngoogle.so\ngoogle.sm\ngoogle.sr\ngoogle.st\ngoogle.com.sv\ngoogle.td\ngoogle.tg\ngoogle.co.th\ngoogle.com.tj\ngoogle.tk\ngoogle.tl\ngoogle.tm\ngoogle.tn\ngoogle.to\ngoogle.com.tr\ngoogle.tt\ngoogle.com.tw\ngoogle.co.tz\ngoogle.com.ua\ngoogle.co.ug\ngoogle.co.uk\ngoogle.com.uy\ngoogle.co.uz\ngoogle.com.vc\ngoogle.co.ve\ngoogle.vg\ngoogle.co.vi\ngoogle.com.vn\ngoogle.vu\ngoogle.ws\ngoogle.rs\ngoogle.co.za\ngoogle.co.zm\ngoogle.co.zw\ngoogle.cat\n' >> $DOMAIN_TEMP_FILE + printf 'Google search domains... ' && _green 'Added\n' + + # Add blogspot domains + printf 'blogspot.ca\nblogspot.co.uk\nblogspot.com\nblogspot.com.ar\nblogspot.com.au\nblogspot.com.br\nblogspot.com.by\nblogspot.com.co\nblogspot.com.cy\nblogspot.com.ee\nblogspot.com.eg\nblogspot.com.es\nblogspot.com.mt\nblogspot.com.ng\nblogspot.com.tr\nblogspot.com.uy\nblogspot.de\nblogspot.gr\nblogspot.in\nblogspot.mx\nblogspot.ch\nblogspot.fr\nblogspot.ie\nblogspot.it\nblogspot.pt\nblogspot.ro\nblogspot.sg\nblogspot.be\nblogspot.no\nblogspot.se\nblogspot.jp\nblogspot.in\nblogspot.ae\nblogspot.al\nblogspot.am\nblogspot.ba\nblogspot.bg\nblogspot.ch\nblogspot.cl\nblogspot.cz\nblogspot.dk\nblogspot.fi\nblogspot.gr\nblogspot.hk\nblogspot.hr\nblogspot.hu\nblogspot.ie\nblogspot.is\nblogspot.kr\nblogspot.li\nblogspot.lt\nblogspot.lu\nblogspot.md\nblogspot.mk\nblogspot.my\nblogspot.nl\nblogspot.no\nblogspot.pe\nblogspot.qa\nblogspot.ro\nblogspot.ru\nblogspot.se\nblogspot.sg\nblogspot.si\nblogspot.sk\nblogspot.sn\nblogspot.tw\nblogspot.ug\nblogspot.cat\n' >> $DOMAIN_TEMP_FILE + printf 'Blogspot domains... ' && _green 'Added\n' + + # Add twimg.edgesuite.net + printf 'twimg.edgesuite.net\n' >> $DOMAIN_TEMP_FILE + printf 'twimg.edgesuite.net... ' && _green 'Added\n' + + # Delete exclude domains + if [ ! -z $EXCLUDE_DOMAIN_FILE ]; then + for line in $(cat $EXCLUDE_DOMAIN_FILE) + do + cat $DOMAIN_TEMP_FILE | grep -vF -f $EXCLUDE_DOMAIN_FILE > $DOMAIN_FILE + done + printf 'Domains in exclude domain file '$EXCLUDE_DOMAIN_FILE'... ' && _green 'Deleted\n' + else + cat $DOMAIN_TEMP_FILE > $DOMAIN_FILE + fi + + # Add extra domains + if [ ! -z $EXTRA_DOMAIN_FILE ]; then + cat $EXTRA_DOMAIN_FILE >> $DOMAIN_FILE + printf 'Extra domain file '$EXTRA_DOMAIN_FILE'... ' && _green 'Added\n' + fi + + if [ $OUT_TYPE = 'DNSMASQ_RULES' ]; then + # Convert domains into dnsmasq rules + if [ $WITH_IPSET -eq 1 ]; then + _green 'Ipset rules included.' + sort -u $DOMAIN_FILE | $SED_ERES 's#(.+)#server=/\1/'$DNS_IP'\#'$DNS_PORT'\ + ipset=/\1/'$IPSET_NAME'#g' > $CONF_TMP_FILE + else + _green 'Ipset rules not included.' + sort -u $DOMAIN_FILE | $SED_ERES 's#(.+)#server=/\1/'$DNS_IP'\#'$DNS_PORT'#g' > $CONF_TMP_FILE + fi + + # Generate output file + echo '# dnsmasq rules generated by gfwlist' > $OUT_TMP_FILE + echo "# Last Updated on $(date "+%Y-%m-%d %H:%M:%S")" >> $OUT_TMP_FILE + echo '# ' >> $OUT_TMP_FILE + cat $CONF_TMP_FILE >> $OUT_TMP_FILE + cp $OUT_TMP_FILE $OUT_FILE + else + sort -u $DOMAIN_FILE > $OUT_TMP_FILE + fi + + cp $OUT_TMP_FILE $OUT_FILE + printf '\nConverting GfwList to '$OUT_TYPE'... ' && _green 'Done\n\n' + + # Clean up + clean_and_exit 0 +} + +main() { + if [ -z "$1" ]; then + usage 0 + else + check_depends + get_args "$@" + _green '\nJob Started.\n\n' + process + fi +} + +main "$@" diff --git a/dnsproxy/Makefile b/dnsproxy/Makefile new file mode 100644 index 000000000..9da19835b --- /dev/null +++ b/dnsproxy/Makefile @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-3.0-only +# +# Copyright (C) 2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=dnsproxy +PKG_VERSION:=0.42.2 +PKG_RELEASE:=$(AUTORELEASE) + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/dnsproxy/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=399a7a1f7d1afef85d8557bbe445541872bfe005e15c36e242f69b78fa94f1ca + +PKG_MAINTAINER:=Tianling Shen +PKG_LICENSE:=Apache-2.0 +PKG_LICENSE_FILES:=LICENSE + +PKG_BUILD_DEPENDS:=golang/host +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 + +GO_PKG:=github.com/AdguardTeam/dnsproxy +GO_PKG_LDFLAGS_X:=main.VersionString=v$(PKG_VERSION) + +include $(INCLUDE_DIR)/package.mk +include $(TOPDIR)/feeds/openmptcprouter/golang/golang-package.mk + +define Package/dnsproxy + SECTION:=net + CATEGORY:=Network + SUBMENU:=IP Addresses and Names + TITLE:=Simple DNS proxy with DoH, DoT, DoQ and DNSCrypt support + URL:=https://github.com/AdguardTeam/dnsproxy + DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle + USERID:=dnsproxy=411:dnsproxy=411 +endef + +define Package/dnsproxy/description + A simple DNS proxy server that supports all existing DNS protocols including + DNS-over-TLS, DNS-over-HTTPS, DNSCrypt, and DNS-over-QUIC.Moreover, it can + work as a DNS-over-HTTPS, DNS-over-TLS or DNS-over-QUIC server. +endef + +define Package/dnsproxy/install + $(call GoPackage/Package/Install/Bin,$(1)) + + $(INSTALL_DIR) $(1)/etc/config/ + $(INSTALL_CONF) $(CURDIR)/files/dnsproxy.config $(1)/etc/config/dnsproxy + $(INSTALL_DIR) $(1)/etc/init.d/ + $(INSTALL_BIN) $(CURDIR)/files/dnsproxy.init $(1)/etc/init.d/dnsproxy +endef + +define Package/dnsproxy/conffiles +/etc/config/dnsproxy +endef + +$(eval $(call GoBinPackage,dnsproxy)) +$(eval $(call BuildPackage,dnsproxy)) diff --git a/dnsproxy/files/dnsproxy.config b/dnsproxy/files/dnsproxy.config new file mode 100644 index 000000000..a9fa02028 --- /dev/null +++ b/dnsproxy/files/dnsproxy.config @@ -0,0 +1,41 @@ + +# For documents, please see https://github.com/AdguardTeam/dnsproxy#usage + +config dnsproxy 'global' + option enabled '0' + option listen_addr '127.0.0.1' + option listen_port '5353' + option log_file '' + option all_servers '0' + option fastest_addr '0' + option insecure '0' + option ipv6_disabled '0' + option max_go_routines '' + option rate_limit '' + option refuse_any '0' + option udp_buf_size '' + option verbose '0' + +config dnsproxy 'bogus_nxdomain' + list ip_addr '' + +config dnsproxy 'cache' + option enabled '0' + option cache_optimistic '0' + option size '65535' + option min_ttl '' + option max_ttl '' + +config dnsproxy 'dns64' + option enabled '0' + option dns64_prefix '64:ff9b::' + +config dnsproxy 'edns' + option enabled '0' + option edns_addr '' + +config dnsproxy 'servers' + list bootstrap 'tls://8.8.8.8' + list fallback 'tls://9.9.9.9' + list upstream 'tls://1.1.1.1' + diff --git a/dnsproxy/files/dnsproxy.init b/dnsproxy/files/dnsproxy.init new file mode 100644 index 000000000..9ac2751b3 --- /dev/null +++ b/dnsproxy/files/dnsproxy.init @@ -0,0 +1,115 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2021 Tianling Shen + +USE_PROCD=1 +START=90 + +CONF="dnsproxy" +PROG="/usr/bin/dnsproxy" + +is_enabled() { + local enabled + config_get enabled "$1" "$2" "0" + if [ "$enabled" -eq "1" ]; then + return 0 + else + return 1 + fi +} + +is_empty() { + local empty + config_get empty "$1" "$2" $3 + if [ -z "$empty" ]; then + return 0 + else + return 1 + fi +} + +append_param() { + procd_append_param command "$1" $2 +} + +append_param_arg() { + local value + config_get value "$1" "$2" $4 + [ -n "$value" ] && append_param "$3" "$value" +} + +append_param_bool() { + is_enabled "$1" "$2" && append_param "--${2//_/-}" +} + +load_config_arg() { + append_param_bool "$1" "all_servers" + append_param_bool "$1" "fastest_addr" + append_param_bool "$1" "insecure" + append_param_bool "$1" "ipv6_disabled" + append_param_bool "$1" "refuse_any" + append_param_bool "$1" "verbose" +} + +load_config_list() { + is_empty "bogus_nxdomain" "ip_addr" || config_list_foreach "bogus_nxdomain" "ip_addr" "append_param '--bogus-nxdomain'" + + for i in "bootstrap" "fallback" "upstream"; do + is_empty "servers" "$i" || config_list_foreach "servers" "$i" "append_param '--$i'" + done +} + +load_config_param() { + append_param_arg "global" "listen_addr" "--listen" "127.0.0.1" + append_param_arg "global" "listen_port" "--port" "5353" + append_param_arg "global" "log_file" "--output" + append_param_arg "global" "max_go_routines" "--max-go-routines" + append_param_arg "global" "rate_limit" "--ratelimit" + append_param_arg "global" "udp_buf_size" "--udp-buf-size" + + is_enabled "cache" "enabled" && { + append_param "--cache" + append_param_bool "cache" "cache_optimistic" + append_param_arg "cache" "size" "--cache-size" + append_param_arg "cache" "min_ttl" "--cache-min-ttl" + append_param_arg "cache" "max_ttl" "--cache-max-ttl" + } + + is_enabled "dns64" "enabled" && { + append_param "--dns64" + append_param_arg "dns64" "dns64_prefix" "--dns64-prefix" + } + + is_enabled "edns" "enabled" && { + append_param "--edns" + append_param_arg "edns" "edns_addr" "--edns-addr" + } +} + +start_service() { + config_load "$CONF" + + is_enabled "global" "enabled" || exit 1 + + procd_open_instance "$CONF" + procd_set_param command "$PROG" + + load_config_arg "global" + load_config_list + load_config_param + + procd_set_param respawn + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param user dnsproxy + + procd_close_instance +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "$CONF" +} diff --git a/dnsproxy/test.sh b/dnsproxy/test.sh new file mode 100644 index 000000000..60e06a25d --- /dev/null +++ b/dnsproxy/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +dnsproxy --version | grep "$PKG_VERSION" diff --git a/luci-app-cpufreq/Makefile b/luci-app-cpufreq/Makefile new file mode 100644 index 000000000..676cbf2d3 --- /dev/null +++ b/luci-app-cpufreq/Makefile @@ -0,0 +1,19 @@ + +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI for CPU Freq Setting +LUCI_DEPENDS:=@(aarch64||arm) +LUCI_PKGARCH:=all + +PKG_NAME:=luci-app-cpufreq +PKG_VERSION:=1 +PKG_RELEASE:=7 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-cpufreq/luasrc/controller/cpufreq.lua b/luci-app-cpufreq/luasrc/controller/cpufreq.lua new file mode 100644 index 000000000..1f288a81b --- /dev/null +++ b/luci-app-cpufreq/luasrc/controller/cpufreq.lua @@ -0,0 +1,9 @@ +module("luci.controller.cpufreq", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/cpufreq") then + return + end + + entry({"admin", "services", "cpufreq"}, cbi("cpufreq"), _("CPU Freq"), 900).dependent = true +end diff --git a/luci-app-cpufreq/luasrc/model/cbi/cpufreq.lua b/luci-app-cpufreq/luasrc/model/cbi/cpufreq.lua new file mode 100644 index 000000000..ff252bd51 --- /dev/null +++ b/luci-app-cpufreq/luasrc/model/cbi/cpufreq.lua @@ -0,0 +1,60 @@ +local fs = require "nixio.fs" + +cpu_freqs = fs.readfile("/sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies") or "100000" +cpu_freqs = string.sub(cpu_freqs, 1, -3) + +cpu_governors = fs.readfile("/sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors") or "performance" +cpu_governors = string.sub(cpu_governors, 1, -3) + +function string.split(input, delimiter) + input = tostring(input) + delimiter = tostring(delimiter) + if (delimiter=='') then return false end + local pos,arr = 0, {} + for st,sp in function() return string.find(input, delimiter, pos, true) end do + table.insert(arr, string.sub(input, pos, st - 1)) + pos = sp + 1 + end + table.insert(arr, string.sub(input, pos)) + return arr +end + +freq_array = string.split(cpu_freqs, " ") +governor_array = string.split(cpu_governors, " ") + +mp = Map("cpufreq", translate("CPU Freq Settings")) +mp.description = translate("Set CPU Scaling Governor to Max Performance or Balance Mode") + +s = mp:section(NamedSection, "cpufreq", "settings") +s.anonymouse = true + +governor = s:option(ListValue, "governor", translate("CPU Scaling Governor")) +for _, e in ipairs(governor_array) do + if e ~= "" then governor:value(e, translate(e,string.upper(e))) end +end + +minfreq = s:option(ListValue, "minifreq", translate("Min Idle CPU Freq")) +for _, e in ipairs(freq_array) do + if e ~= "" then minfreq:value(e) end +end + +maxfreq = s:option(ListValue, "maxfreq", translate("Max Turbo Boost CPU Freq")) +for _, e in ipairs(freq_array) do + if e ~= "" then maxfreq:value(e) end +end + +upthreshold = s:option(Value, "upthreshold", translate("CPU Switching Threshold")) +upthreshold.datatype="range(1,99)" +upthreshold.rmempty = false +upthreshold.description = translate("Kernel make a decision on whether it should increase the frequency (%)") +upthreshold.placeholder = 50 +upthreshold.default = 50 + +factor = s:option(Value, "factor", translate("CPU Switching Sampling rate")) +factor.datatype="range(1,100000)" +factor.rmempty = false +factor.description = translate("The sampling rate determines how frequently the governor checks to tune the CPU (ms)") +factor.placeholder = 10 +factor.default = 10 + +return mp diff --git a/luci-app-cpufreq/po/zh-cn/cpufreq.po b/luci-app-cpufreq/po/zh-cn/cpufreq.po new file mode 100644 index 000000000..60fd39ff7 --- /dev/null +++ b/luci-app-cpufreq/po/zh-cn/cpufreq.po @@ -0,0 +1,57 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: dingpengyu \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"X-Generator: Poedit 2.3.1\n" + +msgid "CPU Freq" +msgstr "CPU 性能优化调节" + +msgid "CPU Freq Settings" +msgstr "CPU 性能优化调节设置" + +msgid "Set CPU Scaling Governor to Max Performance or Balance Mode" +msgstr "设置路由器的 CPU 性能模式(高性能/均衡省电)" + +msgid "CPU Scaling Governor" +msgstr "CPU 工作模式" + +msgid "Ondemand Balance Mode" +msgstr "Ondemand 自动平衡模式" + +msgid "Performance Mode" +msgstr "Performance 高性能模式(降低游戏转发延迟)" + +msgid "ondemand" +msgstr "ondemand 自动平衡模式" + +msgid "performance" +msgstr "performance 高性能模式(降低游戏转发延迟)" + +msgid "CPU Freq from 48000 to 716000 (Khz)" +msgstr "CPU 频率范围为 48000 到 716000 (Khz)" + +msgid "Min Idle CPU Freq" +msgstr "待机 CPU 最小频率" + +msgid "Max Turbo Boost CPU Freq" +msgstr "最大 Turbo Boost CPU 频率" + +msgid "CPU Switching Threshold" +msgstr "CPU 切换频率触发阈值" + +msgid "Kernel make a decision on whether it should increase the frequency (%)" +msgstr "当 CPU 占用率超过 (%) 的情况下触发内核切换频率" + +msgid "CPU Switching Sampling rate" +msgstr "CPU 切换周期" + +msgid "The sampling rate determines how frequently the governor checks to tune the CPU (ms)" +msgstr "CPU 检查切换的周期 (ms) 。注意:过于频繁的切换频率会引起网络延迟抖动" diff --git a/luci-app-cpufreq/root/etc/config/cpufreq b/luci-app-cpufreq/root/etc/config/cpufreq new file mode 100644 index 000000000..0443dc770 --- /dev/null +++ b/luci-app-cpufreq/root/etc/config/cpufreq @@ -0,0 +1,8 @@ + +config settings 'cpufreq' + option maxfreq '716000' + option upthreshold '50' + option factor '10' + option minifreq '300000' + option governor 'ondemand' + diff --git a/luci-app-cpufreq/root/etc/init.d/cpufreq b/luci-app-cpufreq/root/etc/init.d/cpufreq new file mode 100755 index 000000000..4ccc65776 --- /dev/null +++ b/luci-app-cpufreq/root/etc/init.d/cpufreq @@ -0,0 +1,30 @@ +#!/bin/sh /etc/rc.common +START=50 + +NAME=cpufreq + +uci_get_by_type() { + local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null) + echo ${ret:=$3} +} + +start() +{ + local min=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies | awk -F ' ' '{print $1 }') + local max=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies | awk -F ' ' '{print $NF }') + + config_load cpufreq + local governor=$(uci_get_by_type settings governor schedutil) + local minifreq=$(uci_get_by_type settings minifreq $min) + local maxfreq=$(uci_get_by_type settings maxfreq $max) + local upthreshold=$(uci_get_by_type settings upthreshold 50) + local factor=$(uci_get_by_type settings factor 10) + + echo $governor > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor + echo $minifreq > /sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq + echo $maxfreq > /sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq + if [ "$governor" == "ondemand" ]; then + echo $upthreshold > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold + echo $factor > /sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor + fi +} diff --git a/luci-app-cpufreq/root/etc/uci-defaults/luci-cpufreq b/luci-app-cpufreq/root/etc/uci-defaults/luci-cpufreq new file mode 100755 index 000000000..8443be579 --- /dev/null +++ b/luci-app-cpufreq/root/etc/uci-defaults/luci-cpufreq @@ -0,0 +1,11 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@cpufreq[-1] + add ucitrack cpufreq + set ucitrack.@cpufreq[-1].init=cpufreq + commit ucitrack +EOF + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/luci-app-diskman/Makefile b/luci-app-diskman/Makefile new file mode 100644 index 000000000..0fc535f4b --- /dev/null +++ b/luci-app-diskman/Makefile @@ -0,0 +1,53 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-diskman +PKG_VERSION:=v0.2.11 +PKG_RELEASE:=2 + +PKG_MAINTAINER:=lisaac +PKG_LICENSE:=AGPL-3.0 + +LUCI_TITLE:=Disk Manager interface for LuCI +LUCI_DEPENDS:=+blkid +e2fsprogs +parted +smartmontools \ + +PACKAGE_$(PKG_NAME)_INCLUDE_btrfs_progs:btrfs-progs \ + +PACKAGE_$(PKG_NAME)_INCLUDE_lsblk:lsblk \ + +PACKAGE_$(PKG_NAME)_INCLUDE_mdadm:mdadm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_raid456:mdadm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_raid456:kmod-md-raid456 \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_linears:mdadm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_linears:kmod-md-linear + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME)/config +config PACKAGE_$(PKG_NAME)_INCLUDE_btrfs_progs + bool "Include btrfs-progs" + default y + +config PACKAGE_$(PKG_NAME)_INCLUDE_lsblk + bool "Include lsblk" + default y + +config PACKAGE_$(PKG_NAME)_INCLUDE_mdadm + bool "Include mdadm" + default n + +config PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_raid456 + depends on PACKAGE_$(PKG_NAME)_INCLUDE_mdadm + bool "Include kmod-md-raid456" + default n + +config PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_linear + depends on PACKAGE_$(PKG_NAME)_INCLUDE_mdadm + bool "Include kmod-md-linear" + default n +endef + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +rm -fr /tmp/luci-indexcache /tmp/luci-modulecache +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-diskman/luasrc/controller/diskman.lua b/luci-app-diskman/luasrc/controller/diskman.lua new file mode 100644 index 000000000..258120430 --- /dev/null +++ b/luci-app-diskman/luasrc/controller/diskman.lua @@ -0,0 +1,155 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +module("luci.controller.diskman",package.seeall) + +function index() + -- check all used executables in disk management are existed + local CMD = {"parted", "blkid", "smartctl"} + local executables_all_existed = true + for _, cmd in ipairs(CMD) do + local command = luci.sys.exec("/usr/bin/which " .. cmd) + if not command:match(cmd) then + executables_all_existed = false + break + end + end + + if not executables_all_existed then return end + -- entry(path, target, title, order) + -- set leaf attr to true to pass argument throughe url (e.g. admin/system/disk/partition/sda) + entry({"admin", "system", "diskman"}, alias("admin", "system", "diskman", "disks"), _("Disk Man"), 55) + entry({"admin", "system", "diskman", "disks"}, form("diskman/disks"), nil).leaf = true + entry({"admin", "system", "diskman", "partition"}, form("diskman/partition"), nil).leaf = true + entry({"admin", "system", "diskman", "btrfs"}, form("diskman/btrfs"), nil).leaf = true + entry({"admin", "system", "diskman", "format_partition"}, call("format_partition"), nil).leaf = true + entry({"admin", "system", "diskman", "get_disk_info"}, call("get_disk_info"), nil).leaf = true + entry({"admin", "system", "diskman", "mk_p_table"}, call("mk_p_table"), nil).leaf = true + entry({"admin", "system", "diskman", "smartdetail"}, call("smart_detail"), nil).leaf = true + entry({"admin", "system", "diskman", "smartattr"}, call("smart_attr"), nil).leaf = true +end + +function format_partition() + local partation_name = luci.http.formvalue("partation_name") + local fs = luci.http.formvalue("file_system") + if not partation_name then + luci.http.status(500, "Partition NOT found!") + luci.http.write_json("Partition NOT found!") + return + elseif not nixio.fs.access("/dev/"..partation_name) then + luci.http.status(500, "Partition NOT found!") + luci.http.write_json("Partition NOT found!") + return + elseif not fs then + luci.http.status(500, "no file system") + luci.http.write_json("no file system") + return + end + local dm = require "luci.model.diskman" + code, msg = dm.format_partition(partation_name, fs) + luci.http.status(code, msg) + luci.http.write_json(msg) +end + +function get_disk_info(dev) + if not dev then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + elseif not nixio.fs.access("/dev/"..dev) then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + end + local dm = require "luci.model.diskman" + local device_info = dm.get_disk_info(dev) + luci.http.status(200, "ok") + luci.http.prepare_content("application/json") + luci.http.write_json(device_info) +end + +function mk_p_table() + local p_table = luci.http.formvalue("p_table") + local dev = luci.http.formvalue("dev") + if not dev then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + elseif not nixio.fs.access("/dev/"..dev) then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + end + local dm = require "luci.model.diskman" + if p_table == "GPT" or p_table == "MBR" then + p_table = p_table == "MBR" and "msdos" or "gpt" + local res = luci.sys.call(dm.command.parted .. " -s /dev/" .. dev .. " mktable ".. p_table) + if res == 0 then + luci.http.status(200, "ok") + else + luci.http.status(500, "command exec error") + end + luci.http.prepare_content("application/json") + luci.http.write_json({code=res}) + else + luci.http.status(404, "not support") + luci.http.prepare_content("application/json") + luci.http.write_json({code="1"}) + end +end + +function smart_detail(dev) + luci.template.render("diskman/smart_detail", {dev=dev}) +end + +function smart_attr(dev) + local dm = require "luci.model.diskman" + local cmd = io.popen(dm.command.smartctl .. " -H -A -i /dev/%s" % dev) + if cmd then + local attr = { } + if cmd:match("NVMe Version:")then + while true do + local ln = cmd:read("*l") + if not ln then + break + elseif ln:match("^(.-):%s+(.+)") then + local key, value = ln:match("^(.-):%s+(.+)") + attr[#attr+1]= { + key = key, + value = value + } + end + end + else + while true do + local ln = cmd:read("*l") + if not ln then + break + elseif ln:match("^.*%d+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+") then + local id,attrbute,flag,value,worst,thresh,type,updated,raw = ln:match("^%s*(%d+)%s+([%a%p]+)%s+(%w+)%s+(%d+)%s+(%d+)%s+(%d+)%s+([%a%p]+)%s+(%a+)%s+[%w%p]+%s+(.+)") + id= "%x" % id + if not id:match("^%w%w") then + id = "0%s" % id + end + attr[#attr+1]= { + id = id:upper(), + attrbute = attrbute, + flag = flag, + value = value, + worst = worst, + thresh = thresh, + type = type, + updated = updated, + raw = raw + } + end + end + end + cmd:close() + luci.http.prepare_content("application/json") + luci.http.write_json(attr) + end +end diff --git a/luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua b/luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua new file mode 100644 index 000000000..006007853 --- /dev/null +++ b/luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua @@ -0,0 +1,210 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +require("luci.tools.webadmin") +local dm = require "luci.model.diskman" +local uuid = arg[1] + +if not uuid then luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) end + +-- mount subv=/ to tempfs +mount_point = "/tmp/.btrfs_tmp" +nixio.fs.mkdirr(mount_point) +luci.util.exec(dm.command.umount .. " "..mount_point .. " >/dev/null 2>&1") +luci.util.exec(dm.command.mount .. " -t btrfs -o subvol=/ UUID="..uuid.." "..mount_point) + +m = SimpleForm("btrfs", translate("Btrfs"), translate("Manage Btrfs")) +m.template = "diskman/cbi/xsimpleform" +m.redirect = luci.dispatcher.build_url("admin/system/diskman") +m.submit = false +m.reset = false + +-- info +local btrfs_info = dm.get_btrfs_info(mount_point) +local table_btrfs_info = m:section(Table, {btrfs_info}, translate("Btrfs Info")) +table_btrfs_info:option(DummyValue, "uuid", translate("UUID")) +table_btrfs_info:option(DummyValue, "members", translate("Members")) +table_btrfs_info:option(DummyValue, "data_raid_level", translate("Data")) +table_btrfs_info:option(DummyValue, "metadata_raid_lavel", translate("Metadata")) +table_btrfs_info:option(DummyValue, "size_formated", translate("Size")) +table_btrfs_info:option(DummyValue, "used_formated", translate("Used")) +table_btrfs_info:option(DummyValue, "free_formated", translate("Free Space")) +table_btrfs_info:option(DummyValue, "usage", translate("Usage")) +local v_btrfs_label = table_btrfs_info:option(Value, "label", translate("Label")) +local value_btrfs_label = "" +v_btrfs_label.write = function(self, section, value) + value_btrfs_label = value or "" +end +local btn_update_label = table_btrfs_info:option(Button, "_update_label") +btn_update_label.inputtitle = translate("Update") +btn_update_label.inputstyle = "edit" +btn_update_label.write = function(self, section, value) + local cmd = dm.command.btrfs .. " filesystem label " .. mount_point .. " " .. value_btrfs_label + local res = luci.util.exec(cmd) + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) +end +-- subvolume +local subvolume_list = dm.get_btrfs_subv(mount_point) +subvolume_list["_"] = { ID = 0 } +table_subvolume = m:section(Table, subvolume_list, translate("SubVolumes")) +table_subvolume:option(DummyValue, "id", translate("ID")) +table_subvolume:option(DummyValue, "top_level", translate("Top Level")) +table_subvolume:option(DummyValue, "uuid", translate("UUID")) +table_subvolume:option(DummyValue, "otime", translate("Otime")) +table_subvolume:option(DummyValue, "snapshots", translate("Snapshots")) +local v_path = table_subvolume:option(Value, "path", translate("Path")) +v_path.forcewrite = true +v_path.render = function(self, section, scope) + if subvolume_list[section].ID == 0 then + self.template = "cbi/value" + self.placeholder = "/my_subvolume" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +local value_path +v_path.write = function(self, section, value) + value_path = value +end +local btn_set_default = table_subvolume:option(Button, "_subv_set_default", translate("Set Default")) +btn_set_default.forcewrite = true +btn_set_default.inputstyle = "edit" +btn_set_default.template = "diskman/cbi/disabled_button" +btn_set_default.render = function(self, section, scope) + if subvolume_list[section].default_subvolume then + self.view_disabled = true + self.inputtitle = translate("Set Default") + elseif subvolume_list[section].ID == 0 then + self.template = "cbi/dvalue" + else + self.inputtitle = translate("Set Default") + self.view_disabled = false + end + Button.render(self, section, scope) +end +btn_set_default.write = function(self, section, value) + local cmd + if value == translate("Set Default") then + cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point..subvolume_list[section].path + else + cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point.."/" + end + local res = luci.util.exec(cmd.. " 2>&1") + if res and (res:match("ERR") or res:match("not enough arguments")) then + m.errmessage = res + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) + end +end +local btn_remove = table_subvolume:option(Button, "_subv_remove") +btn_remove.template = "diskman/cbi/disabled_button" +btn_remove.forcewrite = true +btn_remove.render = function(self, section, scope) + if subvolume_list[section].ID == 0 then + btn_remove.inputtitle = translate("Create") + btn_remove.inputstyle = "add" + self.view_disabled = false + elseif subvolume_list[section].path == "/" or subvolume_list[section].default_subvolume then + btn_remove.inputtitle = translate("Delete") + btn_remove.inputstyle = "remove" + self.view_disabled = true + else + btn_remove.inputtitle = translate("Delete") + btn_remove.inputstyle = "remove" + self.view_disabled = false + end + Button.render(self, section, scope) +end + +btn_remove.write = function(self, section, value) + local cmd + if value == translate("Delete") then + cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. subvolume_list[section].path + elseif value == translate("Create") then + if value_path and value_path:match("^/") then + cmd = dm.command.btrfs .. " subvolume create " .. mount_point .. value_path + else + m.errmessage = translate("Please input Subvolume Path, Subvolume must start with '/'") + return + end + end + local res = luci.util.exec(cmd.. " 2>&1") + if res and (res:match("ERR") or res:match("not enough arguments")) then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) + end +end +-- snapshot +-- local snapshot_list = dm.get_btrfs_subv(mount_point, 1) +-- table_snapshot = m:section(Table, snapshot_list, translate("Snapshots")) +-- table_snapshot:option(DummyValue, "id", translate("ID")) +-- table_snapshot:option(DummyValue, "top_level", translate("Top Level")) +-- table_snapshot:option(DummyValue, "uuid", translate("UUID")) +-- table_snapshot:option(DummyValue, "otime", translate("Otime")) +-- table_snapshot:option(DummyValue, "path", translate("Path")) +-- local snp_remove = table_snapshot:option(Button, "_snp_remove") +-- snp_remove.inputtitle = translate("Delete") +-- snp_remove.inputstyle = "remove" +-- snp_remove.write = function(self, section, value) +-- local cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. snapshot_list[section].path +-- local res = luci.util.exec(cmd.. " 2>&1") +-- if res and (res:match("ERR") or res:match("not enough arguments")) then +-- m.errmessage = luci.util.pcdata(res) +-- else +-- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) +-- end +-- end + +-- new snapshots +local s_snapshot = m:section(SimpleSection, translate("New Snapshot")) +local value_sorce, value_dest, value_readonly +local v_sorce = s_snapshot:option(Value, "_source", translate("Source Path"), translate("The source path for create the snapshot")) +v_sorce.placeholder = "/data" +v_sorce.forcewrite = true +v_sorce.write = function(self, section, value) + value_sorce = value +end + +local v_readonly = s_snapshot:option(Flag, "_readonly", translate("Readonly"), translate("The path where you want to store the snapshot")) +v_readonly.forcewrite = true +v_readonly.rmempty = false +v_readonly.disabled = 0 +v_readonly.enabled = 1 +v_readonly.default = 1 +v_readonly.write = function(self, section, value) + value_readonly = value +end +local v_dest = s_snapshot:option(Value, "_dest", translate("Destination Path (optional)")) +v_dest.forcewrite = true +v_dest.placeholder = "/.snapshot/202002051538" +v_dest.write = function(self, section, value) + value_dest = value +end +local btn_snp_create = s_snapshot:option(Button, "_snp_create") +btn_snp_create.title = " " +btn_snp_create.inputtitle = translate("New Snapshot") +btn_snp_create.inputstyle = "add" +btn_snp_create.write = function(self, section, value) + if value_sorce and value_sorce:match("^/") then + if not value_dest then value_dest = "/.snapshot"..value_sorce.."/"..os.date("%Y%m%d%H%M%S") end + nixio.fs.mkdirr(mount_point..value_dest:match("(.-)[^/]+$")) + local cmd = dm.command.btrfs .. " subvolume snapshot" .. (value_readonly == 1 and " -r " or " ") .. mount_point..value_sorce .. " " .. mount_point..value_dest + local res = luci.util.exec(cmd .. " 2>&1") + if res and (res:match("ERR") or res:match("not enough arguments")) then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) + end + else + m.errmessage = translate("Please input Source Path of snapshot, Source Path must start with '/'") + end +end + +return m diff --git a/luci-app-diskman/luasrc/model/cbi/diskman/disks.lua b/luci-app-diskman/luasrc/model/cbi/diskman/disks.lua new file mode 100644 index 000000000..c209df0aa --- /dev/null +++ b/luci-app-diskman/luasrc/model/cbi/diskman/disks.lua @@ -0,0 +1,327 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +require("luci.tools.webadmin") +local dm = require "luci.model.diskman" + +-- Use (non-UCI) SimpleForm since we have no related config file +m = SimpleForm("diskman", translate("DiskMan"), translate("Manage Disks over LuCI.")) +m.template = "diskman/cbi/xsimpleform" +m:append(Template("diskman/disk_info")) +-- disable submit and reset button +m.submit = false +m.reset = false +-- rescan disks +rescan = m:section(SimpleSection) +rescan_button = rescan:option(Button, "_rescan") +rescan_button.inputtitle= translate("Rescan Disks") +rescan_button.template = "diskman/cbi/inlinebutton" +rescan_button.inputstyle = "add" +rescan_button.forcewrite = true +rescan_button.write = function(self, section, value) + luci.util.exec("echo '- - -' | tee /sys/class/scsi_host/host*/scan > /dev/null") + if dm.command.mdadm then + luci.util.exec(dm.command.mdadm .. " --assemble --scan") + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end + +-- disks +local disks = dm.list_devices() +d = m:section(Table, disks, translate("Disks")) +d.config = "disk" +-- option(type, id(key of table), text) +d:option(DummyValue, "path", translate("Path")) +d:option(DummyValue, "model", translate("Model")) +d:option(DummyValue, "sn", translate("Serial Number")) +d:option(DummyValue, "size_formated", translate("Size")) +d:option(DummyValue, "temp", translate("Temp")) +-- d:option(DummyValue, "sec_size", translate("Sector Size ")) +d:option(DummyValue, "p_table", translate("Partition Table")) +d:option(DummyValue, "sata_ver", translate("SATA Version")) +-- d:option(DummyValue, "rota_rate", translate("Rotation Rate")) +d:option(DummyValue, "health", translate("Health")) +d:option(DummyValue, "status", translate("Status")) + +d.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s") + +-- raid devices +if dm.command.mdadm then + local raid_devices = dm.list_raid_devices() + -- raid_devices = diskmanager.getRAIDdevices() + if next(raid_devices) ~= nil then + local r = m:section(Table, raid_devices, translate("RAID Devices")) + r.config = "_raid" + r:option(DummyValue, "path", translate("Path")) + r:option(DummyValue, "level", translate("RAID mode")) + r:option(DummyValue, "size_formated", translate("Size")) + r:option(DummyValue, "p_table", translate("Partition Table")) + r:option(DummyValue, "status", translate("Status")) + r:option(DummyValue, "members_str", translate("Members")) + r:option(DummyValue, "active", translate("Active")) + r.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s") + end +end + +-- btrfs devices +if dm.command.btrfs then + btrfs_devices = dm.list_btrfs_devices() + if next(btrfs_devices) ~= nil then + local table_btrfs = m:section(Table, btrfs_devices, translate("Btrfs")) + table_btrfs:option(DummyValue, "uuid", translate("UUID")) + table_btrfs:option(DummyValue, "label", translate("Label")) + table_btrfs:option(DummyValue, "members", translate("Members")) + -- sieze is error, since there is RAID + -- table_btrfs:option(DummyValue, "size_formated", translate("Size")) + table_btrfs:option(DummyValue, "used_formated", translate("Usage")) + table_btrfs.extedit = luci.dispatcher.build_url("admin/system/diskman/btrfs/%s") + end +end + +-- mount point +local mount_point = dm.get_mount_points() +local _mount_point = {} +table.insert( mount_point, { device = 0 } ) +local table_mp = m:section(Table, mount_point, translate("Mount Point")) +local v_device = table_mp:option(Value, "device", translate("Device")) +v_device.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self.forcewrite = true + for dev, info in pairs(disks) do + for i, v in ipairs(info.partitions) do + self:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated) + end + end + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +v_device.write = function(self, section, value) + _mount_point.device = value and value:gsub("%s+", "") or "" +end +local v_fs = table_mp:option(Value, "fs", translate("File System")) +v_fs.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self:value("auto", "auto") + self.default = "auto" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +v_fs.write = function(self, section, value) + _mount_point.fs = value and value:gsub("%s+", "") or "" +end +local v_mount_option = table_mp:option(Value, "mount_options", translate("Mount Options")) +v_mount_option.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self.placeholder = "rw,noauto" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + local mp = mount_point[section].mount_options + mount_point[section].mount_options = nil + local length = 0 + for k in mp:gmatch("([^,]+)") do + mount_point[section].mount_options = mount_point[section].mount_options and (mount_point[section].mount_options .. ",") or "" + if length > 20 then + mount_point[section].mount_options = mount_point[section].mount_options.. "
" + length = 0 + end + mount_point[section].mount_options = mount_point[section].mount_options .. k + length = length + #k + end + self.rawhtml = true + -- mount_point[section].mount_options = #mount_point[section].mount_options > 50 and mount_point[section].mount_options:sub(1,50) .. "..." or mount_point[section].mount_options + DummyValue.render(self, section, scope) + end +end +v_mount_option.write = function(self, section, value) + _mount_point.mount_options = value and value:gsub("%s+", "") or "" +end +local v_mount_point = table_mp:option(Value, "mount_point", translate("Mount Point")) +v_mount_point.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self.placeholder = "/media/diskX" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + local new_mp = "" + local v_mp_d + for v_mp_d in self["section"]["data"][section]["mount_point"]:gmatch('[^/]+') do + if #v_mp_d > 12 then + new_mp = new_mp .. "/" .. v_mp_d:sub(1,7) .. ".." .. v_mp_d:sub(-4) + else + new_mp = new_mp .."/".. v_mp_d + end + end + self["section"]["data"][section]["mount_point"] = ''..new_mp..'' + self.rawhtml = true + DummyValue.render(self, section, scope) + end +end +v_mount_point.write = function(self, section, value) + _mount_point.mount_point = value +end +local btn_umount = table_mp:option(Button, "_mount", translate("Mount")) +btn_umount.forcewrite = true +btn_umount.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.inputtitle = translate("Mount") + btn_umount.inputstyle = "add" + else + self.inputtitle = translate("Umount") + btn_umount.inputstyle = "remove" + end + Button.render(self, section, scope) +end +btn_umount.write = function(self, section, value) + local res + if value == translate("Mount") then + if not _mount_point.mount_point or not _mount_point.device then return end + luci.util.exec("mkdir -p ".. _mount_point.mount_point) + res = luci.util.exec(dm.command.mount .. " ".. _mount_point.device .. (_mount_point.fs and (" -t ".. _mount_point.fs )or "") .. (_mount_point.mount_options and (" -o " .. _mount_point.mount_options.. " ") or " ").._mount_point.mount_point .. " 2>&1") + elseif value == translate("Umount") then + res = luci.util.exec(dm.command.umount .. " "..mount_point[section].mount_point .. " 2>&1") + end + if res:match("^mount:") or res:match("^umount:") then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) + end +end + +if dm.command.mdadm or dm.command.btrfs then +local creation_section = m:section(TypedSection, "_creation") +creation_section.cfgsections=function() + return {translate("Creation")} +end +creation_section:tab("raid", translate("RAID"), translate("RAID Creation")) +creation_section:tab("btrfs", translate("Btrfs"), translate("Multiple Devices Btrfs Creation")) + +-- raid functions +if dm.command.mdadm then + + local rname, rmembers, rlevel + local r_name = creation_section:taboption("raid", Value, "_rname", translate("Raid Name")) + r_name.placeholder = "/dev/md0" + r_name.write = function(self, section, value) + rname = value + end + local r_level = creation_section:taboption("raid", ListValue, "_rlevel", translate("Raid Level")) + local valid_raid = luci.util.exec("lsmod | grep md_mod") + if valid_raid:match("linear") then + r_level:value("linear", "Linear") + end + if valid_raid:match("raid456") then + r_level:value("5", "Raid 5") + r_level:value("6", "Raid 6") + end + if valid_raid:match("raid1") then + r_level:value("1", "Raid 1") + end + if valid_raid:match("raid0") then + r_level:value("0", "Raid 0") + end + if valid_raid:match("raid10") then + r_level:value("10", "Raid 10") + end + r_level.write = function(self, section, value) + rlevel = value + end + local r_member = creation_section:taboption("raid", DynamicList, "_rmember", translate("Raid Member")) + for dev, info in pairs(disks) do + if not info.inuse and #info.partitions == 0 then + r_member:value(info.path, info.path.. " ".. info.size_formated) + end + for i, v in ipairs(info.partitions) do + if not v.inuse then + r_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated) + end + end + end + r_member.write = function(self, section, value) + rmembers = value + end + local r_create = creation_section:taboption("raid", Button, "_rcreate") + r_create.render = function(self, section, scope) + self.title = " " + self.inputtitle = translate("Create Raid") + self.inputstyle = "add" + Button.render(self, section, scope) + end + r_create.write = function(self, section, value) + -- mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 /dev/sdb6 /dev/sdc5 + local res = dm.create_raid(rname, rlevel, rmembers) + if res and res:match("^ERR") then + m.errmessage = luci.util.pcdata(res) + return + end + dm.gen_mdadm_config() + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) + end +end + +-- btrfs +if dm.command.btrfs then + local blabel, bmembers, blevel + local btrfs_label = creation_section:taboption("btrfs", Value, "_blabel", translate("Btrfs Label")) + btrfs_label.write = function(self, section, value) + blabel = value + end + local btrfs_level = creation_section:taboption("btrfs", ListValue, "_blevel", translate("Btrfs Raid Level")) + btrfs_level:value("single", "Single") + btrfs_level:value("raid0", "Raid 0") + btrfs_level:value("raid1", "Raid 1") + btrfs_level:value("raid10", "Raid 10") + btrfs_level.write = function(self, section, value) + blevel = value + end + + local btrfs_member = creation_section:taboption("btrfs", DynamicList, "_bmember", translate("Btrfs Member")) + for dev, info in pairs(disks) do + if not info.inuse and #info.partitions == 0 then + btrfs_member:value(info.path, info.path.. " ".. info.size_formated) + end + for i, v in ipairs(info.partitions) do + if not v.inuse then + btrfs_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated) + end + end + end + btrfs_member.write = function(self, section, value) + bmembers = value + end + local btrfs_create = creation_section:taboption("btrfs", Button, "_bcreate") + btrfs_create.render = function(self, section, scope) + self.title = " " + self.inputtitle = translate("Create Btrfs") + self.inputstyle = "add" + Button.render(self, section, scope) + end + btrfs_create.write = function(self, section, value) + -- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb + local res = dm.create_btrfs(blabel, blevel, bmembers) + if res and res:match("^ERR") then + m.errmessage = luci.util.pcdata(res) + return + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) + end +end +end + +return m diff --git a/luci-app-diskman/luasrc/model/cbi/diskman/partition.lua b/luci-app-diskman/luasrc/model/cbi/diskman/partition.lua new file mode 100644 index 000000000..1428eb6b2 --- /dev/null +++ b/luci-app-diskman/luasrc/model/cbi/diskman/partition.lua @@ -0,0 +1,366 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +require("luci.tools.webadmin") +local dm = require "luci.model.diskman" +local dev = arg[1] + +if not dev then + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +elseif not nixio.fs.access("/dev/"..dev) then + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end + +m = SimpleForm("partition", translate("Partition Management"), translate("Partition Disk over LuCI.")) +m.template = "diskman/cbi/xsimpleform" +m.redirect = luci.dispatcher.build_url("admin/system/diskman") +m:append(Template("diskman/partition_info")) +-- disable submit and reset button +m.submit = false +m.reset = false + +local disk_info = dm.get_disk_info(dev, true) +local format_cmd = dm.get_format_cmd() + +s = m:section(Table, {disk_info}, translate("Device Info")) +-- s:option(DummyValue, "key") +-- s:option(DummyValue, "value") +s:option(DummyValue, "path", translate("Path")) +s:option(DummyValue, "model", translate("Model")) +s:option(DummyValue, "sn", translate("Serial Number")) +s:option(DummyValue, "size_formated", translate("Size")) +s:option(DummyValue, "sec_size", translate("Sector Size")) +local dv_p_table = s:option(ListValue, "p_table", translate("Partition Table")) +dv_p_table.render = function(self, section, scope) + -- create table only if not used by raid and no partitions on disk + if not disk_info.p_table:match("Raid") and (#disk_info.partitions == 0 or (#disk_info.partitions == 1 and disk_info.partitions[1].number == -1) or (disk_info.p_table:match("LOOP") and not disk_info.partitions[1].inuse)) then + self:value(disk_info.p_table, disk_info.p_table) + self:value("GPT", "GPT") + self:value("MBR", "MBR") + self.default = disk_info.p_table + ListValue.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +if disk_info.type:match("md") then + s:option(DummyValue, "level", translate("Level")) + s:option(DummyValue, "members_str", translate("Members")) +else + s:option(DummyValue, "temp", translate("Temp")) + s:option(DummyValue, "sata_ver", translate("SATA Version")) + s:option(DummyValue, "rota_rate", translate("Rotation Rate")) +end +s:option(DummyValue, "status", translate("Status")) +local btn_health = s:option(Button, "health", translate("Health")) +btn_health.render = function(self, section, scope) + if disk_info.health then + self.inputtitle = disk_info.health + if disk_info.health == "PASSED" then + self.inputstyle = "add" + else + self.inputstyle = "remove" + end + Button.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end + +local btn_eject = s:option(Button, "_eject") +btn_eject.template = "diskman/cbi/disabled_button" +btn_eject.inputstyle = "remove" +btn_eject.render = function(self, section, scope) + for i, p in ipairs(disk_info.partitions) do + if p.mount_point ~= "-" then + self.view_disabled = true + break + end + end + if disk_info.p_table:match("Raid") then + self.view_disabled = true + end + if disk_info.type:match("md") then + btn_eject.inputtitle = translate("Remove") + else + btn_eject.inputtitle = translate("Eject") + end + Button.render(self, section, scope) +end +btn_eject.forcewrite = true +btn_eject.write = function(self, section, value) + for i, p in ipairs(disk_info.partitions) do + if p.mount_point ~= "-" then + m.errmessage = p.name .. translate("is in use! please unmount it first!") + return + end + end + if disk_info.type:match("md") then + luci.util.exec(dm.command.mdadm .. " --stop /dev/" .. dev) + luci.util.exec(dm.command.mdadm .. " --remove /dev/" .. dev) + for _, disk in ipairs(disk_info.members) do + luci.util.exec(dm.command.mdadm .. " --zero-superblock " .. disk) + end + dm.gen_mdadm_config() + else + luci.util.exec("echo 1 > /sys/block/" .. dev .. "/device/delete") + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end +-- eject: echo 1 > /sys/block/(device)/device/delete +-- rescan: echo '- - -' | tee /sys/class/scsi_host/host*/scan > /dev/null + + +-- partitions info +if not disk_info.p_table:match("Raid") then + s_partition_table = m:section(Table, disk_info.partitions, translate("Partitions Info"), translate("Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector")) + + -- s_partition_table:option(DummyValue, "number", translate("Number")) + s_partition_table:option(DummyValue, "name", translate("Name")) + local val_sec_start = s_partition_table:option(Value, "sec_start", translate("Start Sector")) + val_sec_start.render = function(self, section, scope) + -- could create new partition + if disk_info.partitions[section].number == -1 and disk_info.partitions[section].size > 1 * 1024 * 1024 then + self.template = "cbi/value" + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end + end + local val_sec_end = s_partition_table:option(Value, "sec_end", translate("End Sector")) + val_sec_end.render = function(self, section, scope) + -- could create new partition + if disk_info.partitions[section].number == -1 and disk_info.partitions[section].size > 1 * 1024 * 1024 then + self.template = "cbi/value" + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end + end + val_sec_start.forcewrite = true + val_sec_start.write = function(self, section, value) + disk_info.partitions[section]._sec_start = value + end + val_sec_end.forcewrite = true + val_sec_end.write = function(self, section, value) + disk_info.partitions[section]._sec_end = value + end + s_partition_table:option(DummyValue, "size_formated", translate("Size")) + if disk_info.p_table == "MBR" then + s_partition_table:option(DummyValue, "type", translate("Type")) + end + s_partition_table:option(DummyValue, "used_formated", translate("Used")) + s_partition_table:option(DummyValue, "free_formated", translate("Free Space")) + s_partition_table:option(DummyValue, "usage", translate("Usage")) + local dv_mount_point = s_partition_table:option(DummyValue, "mount_point", translate("Mount Point")) + dv_mount_point.rawhtml = true + dv_mount_point.render = function(self, section, scope) + local new_mp = "" + local v_mp_d + for line in self["section"]["data"][section]["mount_point"]:gmatch("[^%s]+") do + if line == '-' then + new_mp = line + break + end + for v_mp_d in line:gmatch('[^/]+') do + if #v_mp_d > 12 then + new_mp = new_mp .. "/" .. v_mp_d:sub(1,7) .. ".." .. v_mp_d:sub(-4) + else + new_mp = new_mp .."/".. v_mp_d + end + end + new_mp = '' ..new_mp ..'' .. "
" + end + self["section"]["data"][section]["mount_point"] = new_mp + DummyValue.render(self, section, scope) + end + local val_fs = s_partition_table:option(Value, "fs", translate("File System")) + val_fs.forcewrite = true + val_fs.partitions = disk_info.partitions + for k, v in pairs(format_cmd) do + val_fs.format_cmd = val_fs.format_cmd and (val_fs.format_cmd .. "," .. k) or k + end + + val_fs.write = function(self, section, value) + disk_info.partitions[section]._fs = value + end + val_fs.render = function(self, section, scope) + -- use listvalue when partition not mounted + if disk_info.partitions[section].mount_point == "-" and disk_info.partitions[section].number ~= -1 and disk_info.partitions[section].type ~= "extended" then + self.template = "diskman/cbi/format_button" + self.inputstyle = "reset" + self.inputtitle = disk_info.partitions[section].fs == "raw" and translate("Format") or disk_info.partitions[section].fs + Button.render(self, section, scope) + -- self:reset_values() + -- self.keylist = {} + -- self.vallist = {} + -- for k, v in pairs(format_cmd) do + -- self:value(k,k) + -- end + -- self.default = disk_info.partitions[section].fs + else + -- self:reset_values() + -- self.keylist = {} + -- self.vallist = {} + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end + end + -- btn_format = s_partition_table:option(Button, "_format") + -- btn_format.template = "diskman/cbi/format_button" + -- btn_format.partitions = disk_info.partitions + -- btn_format.render = function(self, section, scope) + -- if disk_info.partitions[section].mount_point == "-" and disk_info.partitions[section].number ~= -1 and disk_info.partitions[section].type ~= "extended" then + -- self.inputtitle = translate("Format") + -- self.template = "diskman/cbi/disabled_button" + -- self.view_disabled = false + -- self.inputstyle = "reset" + -- for k, v in pairs(format_cmd) do + -- self:depends("val_fs", "k") + -- end + -- -- elseif disk_info.partitions[section].mount_point ~= "-" and disk_info.partitions[section].number ~= -1 then + -- -- self.inputtitle = "Format" + -- -- self.template = "diskman/cbi/disabled_button" + -- -- self.view_disabled = true + -- -- self.inputstyle = "reset" + -- else + -- self.inputtitle = "" + -- self.template = "cbi/dvalue" + -- end + -- Button.render(self, section, scope) + -- end + -- btn_format.forcewrite = true + -- btn_format.write = function(self, section, value) + -- local partition_name = "/dev/".. disk_info.partitions[section].name + -- if not nixio.fs.access(partition_name) then + -- m.errmessage = translate("Partition NOT found!") + -- return + -- end + -- local fs = disk_info.partitions[section]._fs + -- if not format_cmd[fs] then + -- m.errmessage = translate("Filesystem NOT support!") + -- return + -- end + -- local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name + -- local res = luci.util.exec(cmd .. " 2>&1") + -- if res and res:lower():match("error+") then + -- m.errmessage = luci.util.pcdata(res) + -- else + -- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev)) + -- end + -- end + + local btn_action = s_partition_table:option(Button, "_action") + btn_action.forcewrite = true + btn_action.template = "diskman/cbi/disabled_button" + btn_action.render = function(self, section, scope) + -- if partition is mounted or the size < 1mb, then disable the add action + if disk_info.partitions[section].mount_point ~= "-" or (disk_info.partitions[section].type ~= "extended" and disk_info.partitions[section].number == -1 and disk_info.partitions[section].size <= 1 * 1024 * 1024) then + self.view_disabled = true + -- self.inputtitle = "" + -- self.template = "cbi/dvalue" + elseif disk_info.partitions[section].type == "extended" and next(disk_info.partitions[section]["logicals"]) ~= nil then + self.view_disabled = true + else + -- self.template = "diskman/cbi/disabled_button" + self.view_disabled = false + end + if disk_info.partitions[section].number ~= -1 then + self.inputtitle = translate("Remove") + self.inputstyle = "remove" + else + self.inputtitle = translate("New") + self.inputstyle = "add" + end + Button.render(self, section, scope) + end + btn_action.write = function(self, section, value) + if value == translate("New") then + local start_sec = disk_info.partitions[section]._sec_start and tonumber(disk_info.partitions[section]._sec_start) or tonumber(disk_info.partitions[section].sec_start) + local end_sec = disk_info.partitions[section]._sec_end + + if start_sec then + -- for sector alignment + local align = tonumber(disk_info.phy_sec) / tonumber(disk_info.logic_sec) + align = (align < 2048) and 2048 + if start_sec < 2048 then + start_sec = "2048" .. "s" + elseif math.fmod( start_sec, align ) ~= 0 then + start_sec = tostring(start_sec + align - math.fmod( start_sec, align )) .. "s" + else + start_sec = start_sec .. "s" + end + else + m.errmessage = translate("Invalid Start Sector!") + return + end + -- support +size format for End sector + local end_size, end_unit = end_sec:match("^+(%d-)([bkmgtsBKMGTS])$") + if tonumber(end_size) and end_unit then + local unit ={ + B=1, + S=512, + K=1024, + M=1048576, + G=1073741824, + T=1099511627776 + } + end_unit = end_unit:upper() + end_sec = tostring(tonumber(end_size) * unit[end_unit] / unit["S"] + tonumber(start_sec:sub(1,-2)) - 1 ) .. "s" + elseif tonumber(end_sec) then + end_sec = end_sec .. "s" + else + m.errmessage = translate("Invalid End Sector!") + return + end + local part_type = "primary" + + if disk_info.p_table == "MBR" and disk_info["extended_partition_index"] then + if tonumber(disk_info.partitions[disk_info["extended_partition_index"]].sec_start) <= tonumber(start_sec:sub(1,-2)) and tonumber(disk_info.partitions[disk_info["extended_partition_index"]].sec_end) >= tonumber(end_sec:sub(1,-2)) then + part_type = "logical" + if tonumber(start_sec:sub(1,-2)) - tonumber(disk_info.partitions[section].sec_start) < 2048 then + start_sec = tonumber(start_sec:sub(1,-2)) + 2048 + start_sec = start_sec .."s" + end + end + elseif disk_info.p_table == "GPT" then + -- AUTOMATIC FIX GPT PARTITION TABLE + -- Not all of the space available to /dev/sdb appears to be used, you can fix the GPT to use all of the space (an extra 16123870 blocks) or continue with the current setting? + local cmd = ' printf "ok\nfix\n" | parted ---pretend-input-tty /dev/'.. dev ..' print' + luci.util.exec(cmd .. " 2>&1") + end + + -- partiton + local cmd = dm.command.parted .. " -s -a optimal /dev/" .. dev .. " mkpart " .. part_type .." " .. start_sec .. " " .. end_sec + local res = luci.util.exec(cmd .. " 2>&1") + if res and res:lower():match("error+") then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev)) + end + elseif value == translate("Remove") then + -- remove partition + local number = tostring(disk_info.partitions[section].number) + if (not number) or (number == "") then + m.errmessage = translate("Partition not exists!") + return + end + local cmd = dm.command.parted .. " -s /dev/" .. dev .. " rm " .. number + local res = luci.util.exec(cmd .. " 2>&1") + if res and res:lower():match("error+") then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev)) + end + end + end +end + +return m diff --git a/luci-app-diskman/luasrc/model/diskman.lua b/luci-app-diskman/luasrc/model/diskman.lua new file mode 100644 index 000000000..b29308c31 --- /dev/null +++ b/luci-app-diskman/luasrc/model/diskman.lua @@ -0,0 +1,738 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +local ver = require "luci.version" + +local CMD = {"parted", "mdadm", "blkid", "smartctl", "df", "btrfs", "lsblk"} + +local d = {command ={}} +for _, cmd in ipairs(CMD) do + local command = luci.sys.exec("/usr/bin/which " .. cmd) + d.command[cmd] = command:match("^.+"..cmd) or nil +end + +d.command.mount = nixio.fs.access("/usr/bin/mount") and "/usr/bin/mount" or "/bin/mount" +d.command.umount = nixio.fs.access("/usr/bin/umount") and "/usr/bin/umount" or "/bin/umount" + +local proc_mounts = nixio.fs.readfile("/proc/mounts") or "" +local mounts = luci.util.exec(d.command.mount .. " 2>/dev/null") or "" +local swaps = nixio.fs.readfile("/proc/swaps") or "" +local df = luci.sys.exec(d.command.df .. " 2>/dev/null") or "" + +function byte_format(byte) + local suff = {"B", "KB", "MB", "GB", "TB"} + for i=1, 5 do + if byte > 1024 and i < 5 then + byte = byte / 1024 + else + return string.format("%.2f %s", byte, suff[i]) + end + end +end + +local get_smart_info = function(device) + local section + local smart_info = {} + for _, line in ipairs(luci.util.execl(d.command.smartctl .. " -H -A -i -n standby -f brief /dev/" .. device)) do + local attrib, val + if section == 1 then + attrib, val = line:match "^(.-):%s+(.+)" + elseif section == 2 and smart_info.nvme_ver then + attrib, val = line:match("^(.-):%s+(.+)") + if not smart_info.health then smart_info.health = line:match(".-overall%-health.-: (.+)") end + elseif section == 2 then + attrib, val = line:match("^([0-9 ]+)%s+[^ ]+%s+[POSRCK-]+%s+[0-9-]+%s+[0-9-]+%s+[0-9-]+%s+[0-9-]+%s+([0-9-]+)") + if not smart_info.health then smart_info.health = line:match(".-overall%-health.-: (.+)") end + else + attrib = line:match "^=== START OF (.*) SECTION ===" + if attrib and attrib:match("INFORMATION") then + section = 1 + elseif attrib and attrib:match("SMART DATA") then + section = 2 + elseif not smart_info.status then + val = line:match "^Device is in (.*) mode" + if val then smart_info.status = val end + end + end + + if not attrib then + if section ~= 2 then section = 0 end + elseif (attrib == "Power mode is") or + (attrib == "Power mode was") then + smart_info.status = val:match("(%S+)") + -- elseif attrib == "Sector Sizes" then + -- -- 512 bytes logical, 4096 bytes physical + -- smart_info.phy_sec = val:match "([0-9]*) bytes physical" + -- smart_info.logic_sec = val:match "([0-9]*) bytes logical" + -- elseif attrib == "Sector Size" then + -- -- 512 bytes logical/physical + -- smart_info.phy_sec = val:match "([0-9]*)" + -- smart_info.logic_sec = smart_info.phy_sec + elseif attrib == "Serial Number" then + smart_info.sn = val + elseif attrib == "194" or attrib == "Temperature" then + smart_info.temp = val:match("(%d+)") .. "°C" + elseif attrib == "Rotation Rate" then + smart_info.rota_rate = val + elseif attrib == "SATA Version is" then + smart_info.sata_ver = val + elseif attrib == "NVMe Version" then + smart_info.nvme_ver = val + end + end + return smart_info +end + +local parse_parted_info = function(keys, line) + -- parse the output of parted command (machine parseable format) + -- /dev/sda:5860533168s:scsi:512:4096:gpt:ATA ST3000DM001-1ER1:; + -- 1:34s:2047s:2014s:free; + -- 1:2048s:1073743872s:1073741825s:ext4:primary:; + local result = {} + local values = {} + + for value in line:gmatch("(.-)[:;]") do table.insert(values, value) end + for i = 1,#keys do + result[keys[i]] = values[i] or "" + end + return result +end + +local is_raid_member = function(partition) + -- check if inuse as raid member + if nixio.fs.access("/proc/mdstat") then + for _, result in ipairs(luci.util.execl("grep md /proc/mdstat | sed 's/[][]//g'")) do + local md, buf + md, buf = result:match("(md.-):(.+)") + if buf:match(partition) then + return "Raid Member: ".. md + end + end + end + return nil +end + +local get_mount_point = function(partition) + local mount_point + for m in mounts:gmatch("/dev/"..partition.." on ([^ ]*)") do + mount_point = (mount_point and (mount_point .. " ") or "") .. m + end + if mount_point then return mount_point end + -- result = luci.sys.exec('cat /proc/mounts | awk \'{if($1=="/dev/'.. partition ..'") print $2}\'') + -- if result ~= "" then return result end + + if swaps:match("\n/dev/" .. partition .."%s") then return "swap" end + -- result = luci.sys.exec("cat /proc/swaps | grep /dev/" .. partition) + -- if result ~= "" then return "swap" end + + return is_raid_member(partition) + +end + +-- return used, free, usage +local get_partition_usage = function(partition) + if not nixio.fs.access("/dev/"..partition) then return false end + local used, free, usage = df:match("\n/dev/" .. partition .. "%s+%d+%s+(%d+)%s+(%d+)%s+(%d+)%%%s-") + + usage = usage and (usage .. "%") or "-" + used = used and (tonumber(used) * 1024) or 0 + free = free and (tonumber(free) * 1024) or 0 + + return used, free, usage +end + +local get_parted_info = function(device) + if not device then return end + local result = {partitions={}} + local DEVICE_INFO_KEYS = { "path", "size", "type", "logic_sec", "phy_sec", "p_table", "model", "flags" } + local PARTITION_INFO_KEYS = { "number", "sec_start", "sec_end", "size", "fs", "tag_name", "flags" } + local partition_temp + local partitions_temp = {} + local disk_temp + + for line in luci.util.execi(d.command.parted .. " -s -m /dev/" .. device .. " unit s print free", "r") do + if line:find("^/dev/"..device..":.+") then + disk_temp = parse_parted_info(DEVICE_INFO_KEYS, line) + disk_temp.partitions = {} + if disk_temp["size"] then + local length = disk_temp["size"]:gsub("^(%d+)s$", "%1") + local newsize = tostring(tonumber(length)*tonumber(disk_temp["logic_sec"])) + disk_temp["size"] = newsize + end + if disk_temp["p_table"] == "msdos" then + disk_temp["p_table"] = "MBR" + else + disk_temp["p_table"] = disk_temp["p_table"]:upper() + end + elseif line:find("^%d-:.+") then + partition_temp = parse_parted_info(PARTITION_INFO_KEYS, line) + -- use human-readable form instead of sector number + if partition_temp["size"] then + local length = partition_temp["size"]:gsub("^(%d+)s$", "%1") + local newsize = (tonumber(length) * tonumber(disk_temp["logic_sec"])) + partition_temp["size"] = newsize + partition_temp["size_formated"] = byte_format(newsize) + end + partition_temp["number"] = tonumber(partition_temp["number"]) or -1 + if partition_temp["fs"] == "free" then + partition_temp["number"] = -1 + partition_temp["fs"] = "Free Space" + partition_temp["name"] = "-" + elseif device:match("sd") or device:match("sata") then + partition_temp["name"] = device..partition_temp["number"] + elseif device:match("mmcblk") or device:match("md") or device:match("nvme") then + partition_temp["name"] = device.."p"..partition_temp["number"] + end + if partition_temp["number"] > 0 and partition_temp["fs"] == "" and d.command.lsblk then + partition_temp["fs"] = luci.util.exec(d.command.lsblk .. " /dev/"..device.. tostring(partition_temp["number"]) .. " -no fstype"):match("([^%s]+)") or "" + end + partition_temp["fs"] = partition_temp["fs"] == "" and "raw" or partition_temp["fs"] + partition_temp["sec_start"] = partition_temp["sec_start"] and partition_temp["sec_start"]:sub(1,-2) + partition_temp["sec_end"] = partition_temp["sec_end"] and partition_temp["sec_end"]:sub(1,-2) + partition_temp["mount_point"] = partition_temp["name"]~="-" and get_mount_point(partition_temp["name"]) or "-" + if partition_temp["mount_point"]~="-" then + partition_temp["used"], partition_temp["free"], partition_temp["usage"] = get_partition_usage(partition_temp["name"]) + partition_temp["used_formated"] = partition_temp["used"] and byte_format(partition_temp["used"]) or "-" + partition_temp["free_formated"] = partition_temp["free"] and byte_format(partition_temp["free"]) or "-" + else + partition_temp["used"], partition_temp["free"], partition_temp["usage"] = 0,0,"-" + partition_temp["used_formated"] = "-" + partition_temp["free_formated"] = "-" + end + -- if disk_temp["p_table"] == "MBR" and (partition_temp["number"] < 4) and (partition_temp["number"] > 0) then + -- local real_size_sec = tonumber(nixio.fs.readfile("/sys/block/"..device.."/"..partition_temp["name"].."/size")) * tonumber(disk_temp.phy_sec) + -- if real_size_sec ~= partition_temp["size"] then + -- disk_temp["extended_partition_index"] = partition_temp["number"] + -- partition_temp["type"] = "extended" + -- partition_temp["size"] = real_size_sec + -- partition_temp["fs"] = "-" + -- partition_temp["logicals"] = {} + -- else + -- partition_temp["type"] = "primary" + -- end + -- end + + table.insert(partitions_temp, partition_temp) + end + end + if disk_temp and disk_temp["p_table"] == "MBR" then + for i, p in ipairs(partitions_temp) do + if disk_temp["extended_partition_index"] and p["number"] > 4 then + if tonumber(p["sec_end"]) <= tonumber(partitions_temp[disk_temp["extended_partition_index"]]["sec_end"]) and tonumber(p["sec_start"]) >= tonumber(partitions_temp[disk_temp["extended_partition_index"]]["sec_start"]) then + p["type"] = "logical" + table.insert(partitions_temp[disk_temp["extended_partition_index"]]["logicals"], i) + end + elseif (p["number"] < 4) and (p["number"] > 0) then + local s = nixio.fs.readfile("/sys/block/"..device.."/"..p["name"].."/size") + if s then + local real_size_sec = tonumber(s) * tonumber(disk_temp.phy_sec) + -- if size not equal, it's an extended + if real_size_sec ~= p["size"] then + disk_temp["extended_partition_index"] = i + p["type"] = "extended" + p["size"] = real_size_sec + p["fs"] = "-" + p["logicals"] = {} + else + p["type"] = "primary" + end + else + -- if not found in "/sys/block" + p["type"] = "primary" + end + end + end + end + result = disk_temp + result.partitions = partitions_temp + + return result +end + +local mddetail = function(mdpath) + local detail = {} + local path = mdpath:match("^/dev/md%d+$") + if path then + local mdadm = io.popen(d.command.mdadm .. " --detail "..path, "r") + for line in mdadm:lines() do + local key, value = line:match("^%s*(.+) : (.+)") + if key then + detail[key] = value + end + end + mdadm:close() + end + return detail +end + +-- return {{device="", mount_points="", fs="", mount_options="", dump="", pass=""}..} +d.get_mount_points = function() + local mount + local res = {} + local h ={"device", "mount_point", "fs", "mount_options", "dump", "pass"} + for mount in proc_mounts:gmatch("[^\n]+") do + local device = mount:match("^([^%s]+)%s+.+") + -- only show /dev/xxx device + if device and device:match("/dev/") then + res[#res+1] = {} + local i = 0 + for v in mount:gmatch("[^%s]+") do + i = i + 1 + res[#res][h[i]] = v + end + end + end + return res +end + +d.get_disk_info = function(device, wakeup) + --[[ return: + { + path, model, sn, size, size_mounted, flags, type, temp, p_table, logic_sec, phy_sec, sec_size, sata_ver, rota_rate, status, health, + partitions = { + 1 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated}, + 2 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated}, + ... + } + --raid devices only + level, members, members_str + } + --]] + if not device then return end + local disk_info + local smart_info = get_smart_info(device) + + -- check if divice is the member of raid + smart_info["p_table"] = is_raid_member(device..'0') + -- if status is not active(standby), only check smart_info. + -- if only weakup == true, weakup the disk and check parted_info. + if smart_info.status ~= "STANDBY" or wakeup or (smart_info["p_table"] and not smart_info["p_table"]:match("Raid")) or device:match("^md") then + disk_info = get_parted_info(device) + disk_info["sec_size"] = disk_info["logic_sec"] .. "/" .. disk_info["phy_sec"] + disk_info["size_formated"] = byte_format(tonumber(disk_info["size"])) + -- if status is standby, after get part info, the disk is weakuped, then get smart_info again for more informations + if smart_info.status ~= "ACTIVE" then smart_info = get_smart_info(device) end + else + disk_info = {} + end + + for k, v in pairs(smart_info) do + disk_info[k] = v + end + + if disk_info.type and disk_info.type:match("md") then + local raid_info = d.list_raid_devices()[disk_info["path"]:match("/dev/(.+)")] + for k, v in pairs(raid_info) do + disk_info[k] = v + end + end + return disk_info +end + +d.list_raid_devices = function() + local fs = require "nixio.fs" + + local raid_devices = {} + if not fs.access("/proc/mdstat") then return raid_devices end + local mdstat = io.open("/proc/mdstat", "r") + for line in mdstat:lines() do + + -- md1 : active raid1 sdb2[1] sda2[0] + -- md127 : active raid5 sdh1[6] sdg1[4] sdf1[3] sde1[2] sdd1[1] sdc1[0] + local device_info = {} + local mdpath, list = line:match("^(md%d+) : (.+)") + if mdpath then + local members = {} + for member in string.gmatch(list, "%S+") do + member_path = member:match("^(%S+)%[%d+%]") + if member_path then + member = '/dev/'..member_path + end + table.insert(members, member) + end + local active = table.remove(members, 1) + local level = "-" + if active == "active" then + level = table.remove(members, 1) + end + + local size = tonumber(fs.readfile(string.format("/sys/class/block/%s/size", mdpath))) + local ss = tonumber(fs.readfile(string.format("/sys/class/block/%s/queue/logical_block_size", mdpath))) + + device_info["path"] = "/dev/"..mdpath + device_info["size"] = size*ss + device_info["size_formated"] = byte_format(size*ss) + device_info["active"] = active:upper() + device_info["level"] = level + device_info["members"] = members + device_info["members_str"] = table.concat(members, ", ") + + -- Get more info from output of mdadm --detail + local detail = mddetail(device_info["path"]) + device_info["status"] = detail["State"]:upper() + + raid_devices[mdpath] = device_info + end + end + mdstat:close() + + return raid_devices +end + +-- Collect Devices information + --[[ return: + { + sda={ + path, model, inuse, size_formated, + partitions={ + { name, inuse, size_formated } + ... + } + } + .. + } + --]] +d.list_devices = function() + local fs = require "nixio.fs" + + -- get all device names (sdX and mmcblkX) + local target_devnames = {} + for dev in fs.dir("/dev") do + if dev:match("^sd[a-z]$") + or dev:match("^mmcblk%d+$") + or dev:match("^sata[a-z]$") + or dev:match("^nvme%d+n%d+$") + then + table.insert(target_devnames, dev) + end + end + + local devices = {} + for i, bname in pairs(target_devnames) do + local device_info = {} + local device = "/dev/" .. bname + local size = tonumber(fs.readfile(string.format("/sys/class/block/%s/size", bname)) or "0") + local ss = tonumber(fs.readfile(string.format("/sys/class/block/%s/queue/logical_block_size", bname)) or "0") + local model = fs.readfile(string.format("/sys/class/block/%s/device/model", bname)) + local partitions = {} + for part in nixio.fs.glob("/sys/block/" .. bname .."/" .. bname .. "*") do + local pname = nixio.fs.basename(part) + local psize = byte_format(tonumber(nixio.fs.readfile(part .. "/size"))*ss) + local mount_point = get_mount_point(pname) + if mount_point then device_info["inuse"] = true end + table.insert(partitions, {name = pname, size_formated = psize, inuse = mount_point}) + end + + device_info["path"] = device + device_info["size_formated"] = byte_format(size*ss) + device_info["model"] = model + device_info["partitions"] = partitions + -- true or false + device_info["inuse"] = device_info["inuse"] or get_mount_point(bname) + + local udevinfo = {} + if luci.sys.exec("which udevadm") ~= "" then + local udevadm = io.popen("udevadm info --query=property --name="..device) + for attr in udevadm:lines() do + local k, v = attr:match("(%S+)=(%S+)") + udevinfo[k] = v + end + udevadm:close() + + device_info["info"] = udevinfo + if udevinfo["ID_MODEL"] then device_info["model"] = udevinfo["ID_MODEL"] end + end + devices[bname] = device_info + end + -- luci.util.perror(luci.util.serialize_json(devices)) + return devices +end + +-- get formart cmd +d.get_format_cmd = function() + local AVAILABLE_FMTS = { + ext2 = { cmd = "mkfs.ext2", option = "-F -E lazy_itable_init=1" }, + ext3 = { cmd = "mkfs.ext3", option = "-F -E lazy_itable_init=1" }, + ext4 = { cmd = "mkfs.ext4", option = "-F -E lazy_itable_init=1" }, + fat32 = { cmd = "mkfs.vfat", option = "-F" }, + exfat = { cmd = "mkexfat", option = "-f" }, + hfsplus = { cmd = "mkhfs", option = "-f" }, + ntfs = { cmd = "mkntfs", option = "-f" }, + swap = { cmd = "mkswap", option = "" }, + btrfs = { cmd = "mkfs.btrfs", option = "-f" } + } + result = {} + for fmt, obj in pairs(AVAILABLE_FMTS) do + local cmd = luci.sys.exec("/usr/bin/which " .. obj["cmd"]) + if cmd:match(obj["cmd"]) then + result[fmt] = { cmd = cmd:match("^.+"..obj["cmd"]) ,option = obj["option"] } + end + end + return result +end + +d.create_raid = function(rname, rlevel, rmembers) + local mb = {} + for _, v in ipairs(rmembers) do + mb[v]=v + end + rmembers = {} + for _, v in pairs(mb) do + table.insert(rmembers, v) + end + if type(rname) == "string" then + if rname:match("^md%d-%s+") then + rname = "/dev/"..rname:match("^(md%d-)%s+") + elseif rname:match("^/dev/md%d-%s+") then + rname = "/dev/"..rname:match("^(/dev/md%d-)%s+") + elseif not rname:match("/") then + rname = "/dev/md/".. rname + else + return "ERR: Invalid raid name" + end + else + local mdnum = 0 + for num=1,127 do + local md = io.open("/dev/md"..tostring(num), "r") + if md == nil then + mdnum = num + break + else + io.close(md) + end + end + if mdnum == 0 then return "ERR: Cannot find proper md number" end + rname = "/dev/md"..mdnum + end + + if rlevel == "5" or rlevel == "6" then + if #rmembers < 3 then return "ERR: Not enough members" end + end + if rlevel == "10" then + if #rmembers < 4 then return "ERR: Not enough members" end + end + if #rmembers < 2 then return "ERR: Not enough members" end + local cmd = d.command.mdadm .. " --create "..rname.." --run --assume-clean --homehost=any --level=" .. rlevel .. " --raid-devices=" .. #rmembers .. " " .. table.concat(rmembers, " ") + local res = luci.util.exec(cmd) + return res +end + +d.gen_mdadm_config = function() + if not nixio.fs.access("/etc/config/mdadm") then return end + local uci = require "luci.model.uci" + local x = uci.cursor() + -- delete all array sections + x:foreach("mdadm", "array", function(s) x:delete("mdadm",s[".name"]) end) + local cmd = d.command.mdadm .. " -D -s" + --ARRAY /dev/md1 metadata=1.2 name=any:1 UUID=f998ae14:37621b27:5c49e850:051f6813 + --ARRAY /dev/md3 metadata=1.2 name=any:3 UUID=c068c141:4b4232ca:f48cbf96:67d42feb + for _, v in ipairs(luci.util.execl(cmd)) do + local device, uuid = v:match("^ARRAY%s-([^%s]+)%s-[^%s]-%s-[^%s]-%s-UUID=([^%s]+)%s-") + if device and uuid then + local section_name = x:add("mdadm", "array") + x:set("mdadm", section_name, "device", device) + x:set("mdadm", section_name, "uuid", uuid) + end + end + x:commit("mdadm") + -- enable mdadm + luci.util.exec("/etc/init.d/mdadm enable") +end + +-- list btrfs filesystem device +-- {uuid={uuid, label, members, size, used}...} +d.list_btrfs_devices = function() + local btrfs_device = {} + if not d.command.btrfs then return btrfs_device end + local line, _uuid + for _, line in ipairs(luci.util.execl(d.command.btrfs .. " filesystem show -d --raw")) + do + local label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^%s]+)") + if label and uuid then + _uuid = uuid + local _label = label:match("^'([^']+)'") + btrfs_device[_uuid] = {label = _label or label, uuid = uuid} + -- table.insert(btrfs_device, {label = label, uuid = uuid}) + end + local used = line:match("Total devices[%w%s]+used%s+(%d+)$") + if used then + btrfs_device[_uuid]["used"] = tonumber(used) + btrfs_device[_uuid]["used_formated"] = byte_format(tonumber(used)) + end + local size, device = line:match("devid[%w.%s]+size%s+(%d+)[%w.%s]+path%s+([^%s]+)$") + if size and device then + btrfs_device[_uuid]["size"] = btrfs_device[_uuid]["size"] and btrfs_device[_uuid]["size"] + tonumber(size) or tonumber(size) + btrfs_device[_uuid]["size_formated"] = byte_format(btrfs_device[_uuid]["size"]) + btrfs_device[_uuid]["members"] = btrfs_device[_uuid]["members"] and btrfs_device[_uuid]["members"]..", "..device or device + end + end + return btrfs_device +end + +d.create_btrfs = function(blabel, blevel, bmembers) + -- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb + if not d.command.btrfs or type(bmembers) ~= "table" or next(bmembers) == nil then return "ERR no btrfs support or no members" end + local label = blabel and " -L " .. blabel or "" + local cmd = "mkfs.btrfs -f " .. label .. " -d " .. blevel .. " " .. table.concat(bmembers, " ") + return luci.util.exec(cmd) +end + +-- get btrfs info +-- {uuid, label, members, data_raid_level,metadata_raid_lavel, size, used, size_formated, used_formated, free, free_formated, usage} +d.get_btrfs_info = function(m_point) + local btrfs_info = {} + if not m_point or not d.command.btrfs then return btrfs_info end + local cmd = d.command.btrfs .. " filesystem show --raw " .. m_point + local _, line, uuid, _label, members + for _, line in ipairs(luci.util.execl(cmd)) do + if not uuid and not _label then + _label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^s]+)") + else + local mb = line:match("%s+devid.+path%s+([^%s]+)") + if mb then + members = members and (members .. ", ".. mb) or mb + end + end + end + + if not _label or not uuid then return btrfs_info end + local label = _label:match("^'([^']+)'") + cmd = d.command.btrfs .. " filesystem usage -b " .. m_point + local used, free, data_raid_level, metadata_raid_lavel + for _, line in ipairs(luci.util.execl(cmd)) do + if not used then + used = line:match("^%s+Used:%s+(%d+)") + elseif not free then + free = line:match("^%s+Free %(estimated%):%s+(%d+)") + elseif not data_raid_level then + data_raid_level = line:match("^Data,%s-(%w+)") + elseif not metadata_raid_lavel then + metadata_raid_lavel = line:match("^Metadata,%s-(%w+)") + end + end + if used and free and data_raid_level and metadata_raid_lavel then + used = tonumber(used) + free = tonumber(free) + btrfs_info = { + uuid = uuid, + label = label, + data_raid_level = data_raid_level, + metadata_raid_lavel = metadata_raid_lavel, + used = used, + free = free, + size = used + free, + size_formated = byte_format(used + free), + used_formated = byte_format(used), + free_formated = byte_format(free), + members = members, + usage = string.format("%.2f",(used / (free+used) * 100)) .. "%" + } + end + return btrfs_info +end + +-- get btrfs subvolume +-- {id={id, gen, top_level, path, snapshots, otime, default_subvolume}...} +d.get_btrfs_subv = function(m_point, snapshot) +local subvolume = {} +if not m_point or not d.command.btrfs then return subvolume end + +-- get default subvolume +local cmd = d.command.btrfs .. " subvolume get-default " .. m_point +local res = luci.util.exec(cmd) +local default_subvolume_id = res:match("^ID%s+([^%s]+)") + +-- get the root subvolume +if not snapshot then + local _, line, section_snap, _uuid, _otime, _id, _snap + cmd = d.command.btrfs .. " subvolume show ".. m_point + for _, line in ipairs(luci.util.execl(cmd)) do + if not section_snap then + if not _uuid then + _uuid = line:match("^%s-UUID:%s+([^%s]+)") + elseif not _otime then + _otime = line:match("^%s+Creation time:%s+(.+)") + elseif not _id then + _id = line:match("^%s+Subvolume ID:%s+([^%s]+)") + elseif line:match("^%s+(Snapshot%(s%):)") then + section_snap = true + end + else + local snapshot = line:match("^%s+(.+)") + if snapshot then + _snap = _snap and (_snap ..", /".. snapshot) or ("/"..snapshot) + end + end + end + if _uuid and _otime and _id then + subvolume["0".._id] = {id = _id , uuid = _uuid, otime = _otime, snapshots = _snap, path = "/"} + if default_subvolume_id == _id then + subvolume["0".._id].default_subvolume = 1 + end + end +end + +-- get subvolume of btrfs +cmd = d.command.btrfs .. " subvolume list -gcu" .. (snapshot and "s " or " ") .. m_point +for _, line in ipairs(luci.util.execl(cmd)) do + -- ID 259 gen 11 top level 258 uuid 26ae0c59-199a-cc4d-bd58-644eb4f65d33 path 1a/2b' + local id, gen, top_level, uuid, path, otime, otime2 + if snapshot then + id, gen, top_level, otime, otime2, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+otime%s+([^%s]+)%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$") + else + id, gen, top_level, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$") + end + if id and gen and top_level and uuid and path then + subvolume[id] = {id = id, gen = gen, top_level = top_level, otime = (otime and otime or "") .." ".. (otime2 and otime2 or ""), uuid = uuid, path = '/'.. path} + if not snapshot then + -- use btrfs subv show to get snapshots + local show_cmd = d.command.btrfs .. " subvolume show "..m_point.."/"..path + local __, line_show, section_snap + for __, line_show in ipairs(luci.util.execl(show_cmd)) do + if not section_snap then + local create_time = line_show:match("^%s+Creation time:%s+(.+)") + if create_time then + subvolume[id]["otime"] = create_time + elseif line_show:match("^%s+(Snapshot%(s%):)") then + section_snap = "true" + end + else + local snapshot = line_show:match("^%s+(.+)") + subvolume[id]["snapshots"] = subvolume[id]["snapshots"] and (subvolume[id]["snapshots"] .. ", /".. snapshot) or ("/"..snapshot) + end + end + end + end +end +if subvolume[default_subvolume_id] then + subvolume[default_subvolume_id].default_subvolume = 1 +end +-- if m_point == "/tmp/.btrfs_tmp" then +-- luci.util.exec("umount " .. m_point) +-- end +return subvolume +end + +d.format_partition = function(partition, fs) + local partition_name = "/dev/".. partition + if not nixio.fs.access(partition_name) then + return 500, "Partition NOT found!" + end + + local format_cmd = d.get_format_cmd() + if not format_cmd[fs] then + return 500, "Filesystem NOT support!" + end + local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name + local res = luci.util.exec(cmd .. " 2>&1") + if res and res:lower():match("error+") then + return 500, res + else + return 200, "OK" + end +end + +return d diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm b/luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm new file mode 100644 index 000000000..1ad4eca3b --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> <% if self.view_disabled then %> disabled <% end %>/> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> \ No newline at end of file diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm b/luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm new file mode 100644 index 000000000..18e306e27 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " onclick="event.preventDefault();partition_format('<%=self.partitions[section].name%>', '<%=self.format_cmd%>', '<%=self.inputtitle%>');" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> <% if self.view_disabled then %> disabled <% end %>/> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm b/luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm new file mode 100644 index 000000000..b1b193257 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm @@ -0,0 +1,7 @@ +
+ <% if self:cfgvalue(section) ~= false then %> + " type="submit"" <% if self.disable then %>disabled <% end %><%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> + <% else %> + - + <% end %> +
diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm b/luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm new file mode 100644 index 000000000..69aa65e00 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm @@ -0,0 +1,37 @@ +
+ <% if self.title and #self.title > 0 then -%> + <%=self.title%> + <%- end %> + <% if self.description and #self.description > 0 then -%> +
<%=self.description%>
+ <%- end %> +
+
+ <% self:render_children(1, scope or {}) %> +
+ <% if self.error and self.error[1] then -%> +
+
    <% for _, e in ipairs(self.error[1]) do -%> +
  • + <%- if e == "invalid" then -%> + <%:One or more fields contain invalid values!%> + <%- elseif e == "missing" then -%> + <%:One or more required fields have no value!%> + <%- else -%> + <%=pcdata(e)%> + <%- end -%> +
  • + <%- end %>
+
+ <%- end %> +
+
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> \ No newline at end of file diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm b/luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm new file mode 100644 index 000000000..a831bfc77 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm @@ -0,0 +1,88 @@ +<% if not self.embedded then %> +
> + + + <% + end + + %>
<% + + if self.title and #self.title > 0 then + %>

<%=self.title%>

<% + end + + if self.description and #self.description > 0 then + %>
<%=self.description%>
<% + end + + self:render_children() + + %>
<% + + if self.message then + %>
<%=self.message%>
<% + end + + if self.errmessage then + %>
<%=self.errmessage%>
<% + end + + if not self.embedded then + if type(self.hidden) == "table" then + local k, v + for k, v in pairs(self.hidden) do + %><% + end + end + + local display_back = (self.redirect) + local display_cancel = (self.cancel ~= false and self.on_cancel) + local display_skip = (self.flow and self.flow.skip) + local display_submit = (self.submit ~= false) + local display_reset = (self.reset ~= false) + + if display_back or display_cancel or display_skip or display_submit or display_reset then + %>
<% + + if display_back then + %> <% + end + + if display_cancel then + local label = pcdata(self.cancel or translate("Cancel")) + %> <% + end + + if display_skip then + %> <% + end + + if display_submit then + local label = pcdata(self.submit or translate("Submit")) + %> <% + end + + if display_reset then + local label = pcdata(self.reset or translate("Reset")) + %> <% + end + + %>
<% + end + + %>
<% + end +%> + + diff --git a/luci-app-diskman/luasrc/view/diskman/disk_info.htm b/luci-app-diskman/luasrc/view/diskman/disk_info.htm new file mode 100644 index 000000000..118acd50d --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/disk_info.htm @@ -0,0 +1,108 @@ + diff --git a/luci-app-diskman/luasrc/view/diskman/partition_info.htm b/luci-app-diskman/luasrc/view/diskman/partition_info.htm new file mode 100644 index 000000000..78f5c1bd7 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/partition_info.htm @@ -0,0 +1,129 @@ + + \ No newline at end of file diff --git a/luci-app-diskman/luasrc/view/diskman/smart_detail.htm b/luci-app-diskman/luasrc/view/diskman/smart_detail.htm new file mode 100644 index 000000000..56a9139f0 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/smart_detail.htm @@ -0,0 +1,79 @@ + + + S.M.A.R.T detail of <%=dev%> + + + + +
+
+ <%:S.M.A.R.T Attrbutes%>: /dev/<%=dev%> + + + <% if dev:match("nvme") then %> + + <% else %> + + + + + + + + + + <% end %> + + + + +
<%:ID%><%:Attrbute%><%:Flag%><%:Value%><%:Worst%><%:Thresh%><%:Type%><%:Updated%><%:Raw%>

<%:Collecting data...%>
+
+
+ + \ No newline at end of file diff --git a/luci-app-diskman/po/zh-cn/diskman.po b/luci-app-diskman/po/zh-cn/diskman.po new file mode 100644 index 000000000..f380fc586 --- /dev/null +++ b/luci-app-diskman/po/zh-cn/diskman.po @@ -0,0 +1,239 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8\n" + +msgid "DiskMan" +msgstr "DiskMan 磁盘管理" + +msgid "Manage Disks over LuCI." +msgstr "通过 LuCI 管理磁盘" + +msgid "Rescan Disks" +msgstr "重新扫描磁盘" + +msgid "Disks" +msgstr "磁盘" + +msgid "Path" +msgstr "路径" + +msgid "Serial Number" +msgstr "序列号" + +msgid "Temp" +msgstr "温度" + +msgid "Partition Table" +msgstr "分区表" + +msgid "SATA Version" +msgstr "SATA 版本" + +msgid "Health" +msgstr "健康" + +msgid "File System" +msgstr "文件系统" + +msgid "Mount Options" +msgstr "挂载选项" + +msgid "Mount" +msgstr "挂载" + +msgid "Umount" +msgstr "卸载" + +msgid "Eject" +msgstr "弹出" + +msgid "New" +msgstr "创建" + +msgid "Remove" +msgstr "移除" + +msgid "Format" +msgstr "格式化" + +msgid "Start Sector" +msgstr "起始扇区" + +msgid "End Sector" +msgstr "中止扇区" + +msgid "Usage" +msgstr "用量" + +msgid "Used" +msgstr "已使用" + +msgid "Free Space" +msgstr "空闲空间" + +msgid "Model" +msgstr "型号" + +msgid "Size" +msgstr "容量" + +msgid "Status" +msgstr "状态" + +msgid "Mount Point" +msgstr "挂载点" + +msgid "Sector Size" +msgstr "扇区/物理扇区大小" + +msgid "Rotation Rate" +msgstr "转速" + +msgid "RAID Devices" +msgstr "RAID 设备" + +msgid "RAID mode" +msgstr "RAID 模式" + +msgid "Members" +msgstr "成员" + +msgid "Active" +msgstr "活动" + +msgid "RAID Creation" +msgstr "RAID 创建" + +msgid "Raid Name" +msgstr "RAID 名称" + +msgid "Raid Level" +msgstr "RAID 级别" + +msgid "Raid Member" +msgstr "磁盘阵列成员" + +msgid "Create Raid" +msgstr "创建 RAID" + +msgid "Partition Management" +msgstr "分区管理" + +msgid "Partition Disk over LuCI." +msgstr "通过LuCI分区磁盘。" + +msgid "Device Info" +msgstr "设备信息" + +msgid "Disk Man" +msgstr "磁盘管理" + +msgid "Partitions Info" +msgstr "分区信息" + +msgid "Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector" +msgstr "默认2048扇区对齐,【中止扇区】支持 +容量{b,k,m,g,t} 格式,例:+500m +10g +1t" + +msgid "Multiple Devices Btrfs Creation" +msgstr "Btrfs 阵列创建" + +msgid "Label" +msgstr "卷标" + +msgid "Btrfs Label" +msgstr "Btrfs 卷标" + +msgid "Btrfs Raid Level" +msgstr "Btrfs Raid 级别" + +msgid "Btrfs Member" +msgstr "Btrfs 整列成员" + +msgid "Create Btrfs" +msgstr "创建 Btrfs" + +msgid "New Snapshot" +msgstr "新建快照" + +msgid "SubVolumes" +msgstr "子卷" + +msgid "Top Level" +msgstr "父ID" + +msgid "Manage Btrfs" +msgstr "Btrfs 管理" + +msgid "Otime" +msgstr "创建时间" + +msgid "Snapshots" +msgstr "快照" + +msgid "Set Default" +msgstr "默认子卷" + +msgid "Source Path" +msgstr "源目录" + +msgid "Readonly" +msgstr "只读" + +msgid "Delete" +msgstr "删除" + +msgid "Create" +msgstr "创建" + +msgid "Destination Path (optional)" +msgstr "目标目录(可选)" + +msgid "Metadata" +msgstr "元数据" + +msgid "Data" +msgstr "数据" + +msgid "Btrfs Info" +msgstr "Btrfs 信息" + +msgid "The source path for create the snapshot" +msgstr "创建快照的源数据目录" + +msgid "The path where you want to store the snapshot" +msgstr "存放快照数据目录" + +msgid "Please input Source Path of snapshot, Source Path must start with '/'" +msgstr "请输入快照源路径,源路径必须以'/'开头" + +msgid "Please input Subvolume Path, Subvolume must start with '/'" +msgstr "请输入子卷路径,子卷路径必须以'/'开头" + +msgid "is in use! please unmount it first!" +msgstr "正在被使用!请先卸载!" + +msgid "Partition NOT found!" +msgstr "分区未找到!" + +msgid "Filesystem NOT support!" +msgstr "文件系统不支持!" + +msgid "Invalid Start Sector!" +msgstr "无效的起始扇区!" + +msgid "Invalid End Sector" +msgstr "无效的终止扇区!" + +msgid "Partition not exists!" +msgstr "分区不存在!" + +msgid "Creation" +msgstr "创建" + +msgid "Please select file system!" +msgstr "请选择文件系统!" + +msgid "Format partation:" +msgstr "格式化分区:" + +msgid "Warnning !! \nTHIS WILL OVERWRITE EXISTING PARTITIONS!! \nModify the partition table?" +msgstr "警告!!\n此操作会覆盖现有分区\n确定修改分区表?" diff --git a/luci-app-netdata/Makefile b/luci-app-netdata/Makefile new file mode 100644 index 000000000..de3b86671 --- /dev/null +++ b/luci-app-netdata/Makefile @@ -0,0 +1,18 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for Netdata +LUCI_DEPENDS:=+netdata +LUCI_PKGARCH:=all + +PKG_NAME:=luci-app-netdata +PKG_VERSION:=1.0 +PKG_RELEASE:=3 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-netdata/luasrc/controller/netdata.lua b/luci-app-netdata/luasrc/controller/netdata.lua new file mode 100644 index 000000000..09e9943b2 --- /dev/null +++ b/luci-app-netdata/luasrc/controller/netdata.lua @@ -0,0 +1,6 @@ +module("luci.controller.netdata", package.seeall) + +function index() + + entry({"admin", "status", "netdata"}, template("netdata/netdata"), _("NetData"), 10).leaf = true +end diff --git a/luci-app-netdata/luasrc/view/netdata/netdata.htm b/luci-app-netdata/luasrc/view/netdata/netdata.htm new file mode 100644 index 000000000..a6620e64d --- /dev/null +++ b/luci-app-netdata/luasrc/view/netdata/netdata.htm @@ -0,0 +1,9 @@ +<%+header%> +
+

<%=translate("NetData")%>

+ +
+ +<%+footer%> diff --git a/luci-app-netdata/po/zh-cn/netdata.po b/luci-app-netdata/po/zh-cn/netdata.po new file mode 100644 index 000000000..e8966b815 --- /dev/null +++ b/luci-app-netdata/po/zh-cn/netdata.po @@ -0,0 +1,5 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "NetData" +msgstr "实时监控" diff --git a/luci-app-turboacc/Makefile b/luci-app-turboacc/Makefile new file mode 100644 index 000000000..eb707831a --- /dev/null +++ b/luci-app-turboacc/Makefile @@ -0,0 +1,72 @@ +# SPDX-Identifier-License: GPL-3.0-only +# +# Copyright (C) 2018 Lean +# Copyright (C) 2019-2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-turboacc +PKG_RELEASE:=$(COMMITCOUNT) + +PKG_LICENSE:=GPL-3.0-only +PKG_MAINTAINER:=Tianling Shen + +PKG_CONFIG_DEPENDS:= \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_BBR_CCA \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_DNSFORWARDER \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_DNSPROXY \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_OFFLOADING \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE_DRV + +LUCI_TITLE:=LuCI support for Flow Offload / Shortcut-FE +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+pdnsd-alt \ + +PACKAGE_$(PKG_NAME)_INCLUDE_BBR_CCA:kmod-tcp-bbr \ + +PACKAGE_$(PKG_NAME)_INCLUDE_DNSFORWARDER:dnsforwarder \ + +PACKAGE_$(PKG_NAME)_INCLUDE_DNSPROXY:dnsproxy \ + +PACKAGE_$(PKG_NAME)_INCLUDE_OFFLOADING:kmod-ipt-offload \ + +PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE:kmod-shortcut-fe-cm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE_DRV:kmod-shortcut-fe-drv + +define Package/$(PKG_NAME)/config +config PACKAGE_$(PKG_NAME)_INCLUDE_OFFLOADING + bool "Include Flow Offload" + depends on (PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE=n && PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE_DRV=n) + default y if TARGET_ramips + +config PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE_DRV + bool "Include Shortcut-FE for ECM" + depends on PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE=n + default y if (TARGET_ipq60xxx||TARGET_ipq806x||TARGET_ipq807x) + +config PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE + bool "Include Shortcut-FE" + default y if !(TARGET_ipq60xxx||TARGET_ipq806x||TARGET_ipq807x||TARGET_ramips) + +config PACKAGE_$(PKG_NAME)_INCLUDE_BBR_CCA + bool "Include BBR CCA" + default y + +config PACKAGE_$(PKG_NAME)_INCLUDE_DNSFORWARDER + bool "Include DNSForwarder" + default n + +config PACKAGE_$(PKG_NAME)_INCLUDE_DNSPROXY + bool "Include DNSProxy" + default n +endef + +define Package/$(PKG_NAME)/preinst +#!/bin/sh +sed -i 's/s:option(Flag, "fullcone", translate("Enable FullCone NAT"))/-- e:option(Flag,"fullcone",translate("Enable FullCone NAT"))/g' $${IPKG_INSTROOT}/usr/lib/lua/luci/model/cbi/firewall/zones.lua +endef + +define Package/$(PKG_NAME)/postrm +#!/bin/sh +sed -i 's/-- s:option(Flag, "fullcone", translate("Enable FullCone NAT"))/s:option(Flag, "fullcone", translate("Enable FullCone NAT"))/g' $${IPKG_INSTROOT}/usr/lib/lua/luci/model/cbi/firewall/zones.lua +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-turboacc/luasrc/controller/turboacc.lua b/luci-app-turboacc/luasrc/controller/turboacc.lua new file mode 100644 index 000000000..4197ad241 --- /dev/null +++ b/luci-app-turboacc/luasrc/controller/turboacc.lua @@ -0,0 +1,39 @@ +module("luci.controller.turboacc", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/turboacc") then + return + end + local page + page = entry({"admin", "network", "turboacc"}, cbi("turboacc"), _("Turbo ACC Center"), 1000) + page.i18n = "turboacc" + page.dependent = true + + entry({"admin", "network", "turboacc", "status"}, call("action_status")) +end + +local function fastpath_status() + return luci.sys.call("/etc/init.d/turboacc check_status fastpath") == 0 +end + +local function bbr_status() + return luci.sys.call("/etc/init.d/turboacc check_status bbr") == 0 +end + +local function fullconenat_status() + return luci.sys.call("/etc/init.d/turboacc check_status fullconenat") == 0 +end + +local function dnscaching_status() + return luci.sys.call("/etc/init.d/turboacc check_status dns") == 0 +end + +function action_status() + luci.http.prepare_content("application/json") + luci.http.write_json({ + fastpath_state = fastpath_status(), + fullconenat_state = fullconenat_status(), + bbr_state = bbr_status(), + dnscaching_state = dnscaching_status() + }) +end diff --git a/luci-app-turboacc/luasrc/model/cbi/turboacc.lua b/luci-app-turboacc/luasrc/model/cbi/turboacc.lua new file mode 100644 index 000000000..cb8ea97a5 --- /dev/null +++ b/luci-app-turboacc/luasrc/model/cbi/turboacc.lua @@ -0,0 +1,67 @@ +local kernel_version = luci.sys.exec("echo -n $(uname -r)") + +m = Map("turboacc") +m.title = translate("Turbo ACC Acceleration Settings") +m.description = translate("Opensource Flow Offloading driver (Fast Path or Hardware NAT)") + +m:append(Template("turboacc/turboacc_status")) + +s = m:section(TypedSection, "turboacc", "") +s.addremove = false +s.anonymous = true + +if nixio.fs.access("/lib/modules/" .. kernel_version .. "/xt_FLOWOFFLOAD.ko") then +sw_flow = s:option(Flag, "sw_flow", translate("Software flow offloading")) +sw_flow.default = 0 +sw_flow.description = translate("Software based offloading for routing/NAT") +sw_flow:depends("sfe_flow", 0) +end + +if luci.sys.call("cat /etc/openwrt_release | grep -q mt762") == 0 then +hw_flow = s:option(Flag, "hw_flow", translate("Hardware flow offloading")) +hw_flow.default = 0 +hw_flow.description = translate("Requires hardware NAT support. Implemented at least for mt762x") +hw_flow:depends("sw_flow", 1) +end + +if nixio.fs.access("/lib/modules/" .. kernel_version .. "/shortcut-fe-cm.ko") then +sfe_flow = s:option(Flag, "sfe_flow", translate("Shortcut-FE flow offloading")) +sfe_flow.default = 0 +sfe_flow.description = translate("Shortcut-FE based offloading for routing/NAT") +sfe_flow:depends("sw_flow", 0) +end + +if nixio.fs.access("/lib/modules/" .. kernel_version .. "/tcp_bbr.ko") then +bbr_cca = s:option(Flag, "bbr_cca", translate("BBR CCA")) +bbr_cca.default = 0 +bbr_cca.description = translate("Using BBR CCA can improve TCP network performance effectively") +end + +if nixio.fs.access("/lib/modules/" .. kernel_version .. "/xt_FULLCONENAT.ko") then +fullcone_nat = s:option(Flag, "fullcone_nat", translate("FullCone NAT")) +fullcone_nat.default = 0 +fullcone_nat.description = translate("Using FullCone NAT can improve gaming performance effectively") +end + +dns_caching = s:option(Flag, "dns_caching", translate("DNS Caching")) +dns_caching.default = 0 +dns_caching.rmempty = false +dns_caching.description = translate("Enable DNS Caching and anti ISP DNS pollution") + +dns_caching_mode = s:option(ListValue, "dns_caching_mode", translate("Resolve DNS Mode"), translate("DNS Program")) +dns_caching_mode:value("1", translate("Using PDNSD to query and cache")) +if nixio.fs.access("/usr/bin/dnsforwarder") then +dns_caching_mode:value("2", translate("Using DNSForwarder to query and cache")) +end +if nixio.fs.access("/usr/bin/dnsproxy") then +dns_caching_mode:value("3", translate("Using DNSProxy to query and cache")) +end +dns_caching_mode.default = 1 +dns_caching_mode:depends("dns_caching", 1) + +dns_caching_dns = s:option(Value, "dns_caching_dns", translate("Upsteam DNS Server")) +dns_caching_dns.default = "114.114.114.114,114.114.115.115,223.5.5.5,223.6.6.6,180.76.76.76,119.29.29.29,119.28.28.28,1.2.4.8,210.2.4.8" +dns_caching_dns.description = translate("Muitiple DNS server can saperate with ','") +dns_caching_dns:depends("dns_caching", 1) + +return m diff --git a/luci-app-turboacc/luasrc/view/turboacc/turboacc_status.htm b/luci-app-turboacc/luasrc/view/turboacc/turboacc_status.htm new file mode 100644 index 000000000..90de3884b --- /dev/null +++ b/luci-app-turboacc/luasrc/view/turboacc/turboacc_status.htm @@ -0,0 +1,25 @@ +
+ <%:Running Status%> + + + + + +
<%:Flow Offloading%><%:Collecting data...%>
<%:FullCone NAT%><%:Collecting data...%>
<%:BBR CCA%><%:Collecting data...%>
<%:DNS Caching%><%:Collecting data...%>
+
+ + diff --git a/luci-app-turboacc/po/zh-cn/turboacc.po b/luci-app-turboacc/po/zh-cn/turboacc.po new file mode 100644 index 000000000..cbd9d6ab9 --- /dev/null +++ b/luci-app-turboacc/po/zh-cn/turboacc.po @@ -0,0 +1,99 @@ +msgid "Turbo ACC Center" +msgstr "Turbo ACC 网络加速" + +msgid "Turbo ACC Acceleration Settings" +msgstr "Turbo ACC 网络加速设置" + +msgid "Linux Flow Offload Forwarding Engine Settings" +msgstr "Linux Flow Offload Forwarding 转发加速引擎设置" + +msgid "Opensource Flow Offloading driver (Fast Path or Hardware NAT)" +msgstr "开源流量分载驱动 (支持 Fast Path 或者 硬件 NAT)" + +msgid "Software flow offloading" +msgstr "软件流量分载" + +msgid "Software based offloading for routing/NAT" +msgstr "基于软件的 Routing/NAT 分载" + +msgid "Hardware flow offloading" +msgstr "硬件流量分载" + +msgid "Requires hardware NAT support. Implemented at least for mt762x" +msgstr "需要硬件 NAT 支持。目前 mt762x 已实现" + +msgid "Shortcut-FE flow offloading" +msgstr "Shortcut-FE 流量分载" + +msgid "Shortcut-FE based offloading for routing/NAT" +msgstr "基于 Shortcut-FE 的 Routing/NAT 分载" + +msgid "Bridge Acceleration" +msgstr "桥接加速" + +msgid "Enable Bridge Acceleration (may be functional conflict with bridge-mode VPN server)" +msgstr "启用桥接加速 (可能会和路由器上桥接模式的VPN服务器冲突)" + +msgid "IPv6 Acceleration" +msgstr "IPv6 加速" + +msgid "Enable IPv6 Acceleration" +msgstr "启用 IPv6 加速" + +msgid "BBR CCA" +msgstr "BBR 拥塞控制算法" + +msgid "Using BBR CCA can improve TCP network performance effectively" +msgstr "使用 BBR 拥塞控制算法可以有效提升 TCP 网络性能" + +msgid "FullCone NAT" +msgstr "全锥形 NAT" + +msgid "Using FullCone NAT can improve gaming performance effectively" +msgstr "使用全锥形 NAT 可以有效提升游戏体验" + +msgid "DNS Caching" +msgstr "DNS 缓存" + +msgid "Enable DNS Caching and anti ISP DNS pollution" +msgstr "启用 DNS 多线程查询、缓存,并防止 ISP 的 DNS 广告和域名劫持" + +msgid "Resolve DNS Mode" +msgstr "DNS 解析方式" + +msgid "DNS Program" +msgstr "DNS 解析程序" + +msgid "Using PDNSD to query and cache" +msgstr "使用 PDNSD 解析" + + +msgid "Using DNSForwarder to query and cache" +msgstr "使用 DNSForwarder 解析" + +msgid "Using DNSProxy to query and cache" +msgstr "使用 DNSProxy 解析" + +msgid "Upsteam DNS Server" +msgstr "上游 DNS 服务器" + +msgid "Muitiple DNS server can saperate with ','" +msgstr "多个上游 DNS 服务器请用 ',' 分隔(注意用英文逗号)" + +msgid "Running Status" +msgstr "运行状态" + +msgid "Flow Offloading" +msgstr "流量分载" + +msgid "BBR CCA" +msgstr "BBR 拥塞控制算法" + +msgid "FullCone NAT" +msgstr "全锥型 NAT" + +msgid "DNS Caching" +msgstr "DNS 缓存" + +msgid "Open Web Interface" +msgstr "打开 Web 界面" diff --git a/luci-app-turboacc/root/etc/config/turboacc b/luci-app-turboacc/root/etc/config/turboacc new file mode 100644 index 000000000..a2d4c0bdf --- /dev/null +++ b/luci-app-turboacc/root/etc/config/turboacc @@ -0,0 +1,10 @@ + +config turboacc 'config' + option sw_flow '1' + option hw_flow '1' + option sfe_flow '1' + option fullcone_nat '1' + option bbr_cca '0' + option dns_caching '0' + option dns_caching_mode '1' + option dns_caching_dns '114.114.114.114,114.114.115.115,223.5.5.5,223.6.6.6,180.76.76.76,119.29.29.29,119.28.28.28,1.2.4.8,210.2.4.8' diff --git a/luci-app-turboacc/root/etc/init.d/turboacc b/luci-app-turboacc/root/etc/init.d/turboacc new file mode 100755 index 000000000..f842c7fb3 --- /dev/null +++ b/luci-app-turboacc/root/etc/init.d/turboacc @@ -0,0 +1,364 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2018 Lean +# Copyright (C) 2019-2021 Tianling Shen + +START=90 +STOP=10 + +EXTRA_COMMANDS="check_status" +EXTRA_HELP=" check_status Check running status of utils" + +restart_utils="true" + +PS="/bin/busybox ps" + +inital_conf(){ + config_load "turboacc" + config_get "sw_flow" "config" "sw_flow" "0" + config_get "hw_flow" "config" "hw_flow" "0" + config_get "sfe_flow" "config" "sfe_flow" "0" + config_get "bbr_cca" "config" "bbr_cca" "0" + config_get "fullcone_nat" "config" "fullcone_nat" "0" + config_get "dns_caching" "config" "dns_caching" "0" + config_get "dns_caching_mode" "config" "dns_caching_mode" "0" + config_get "dns_caching_dns" "config" "dns_caching_dns" + + [ ! -e "/lib/modules/$(uname -r)/xt_FLOWOFFLOAD.ko" ] && { sw_flow="0"; hw_flow="0"; } + [ ! -e "/lib/modules/$(uname -r)/shortcut-fe-cm.ko" ] && sfe_flow="0" + [ ! -e "/lib/modules/$(uname -r)/tcp_bbr.ko" ] && bbr_cca="0" + [ ! -e "/lib/modules/$(uname -r)/xt_FULLCONENAT.ko" ] && fullcone_nat="0" +} + +start_pdnsd() { + [ -d "/var/run/dnscache" ] || mkdir -p "/var/run/dnscache" + cat > "/var/run/dnscache/dnscache.conf" < "/var/dnscache/pdnsd.cache" + chown -R nobody.nogroup "/var/dnscache" + fi + + [ -d "/var/sbin" ] || mkdir -p "/var/sbin" + cp -a "/usr/sbin/pdnsd" "/var/sbin/dnscache" + /var/sbin/dnscache -c "/var/run/dnscache/dnscache.conf" > "/var/log/dnscache.file" 2>&1 & + echo "PDNSD: Start DNS Caching" +} + +start_dnsforwarder() { + mkdir -p "/var/run/dnscache" + cat > "/var/run/dnscache/dnscache.conf" < "/var/log/dnscache.file" 2>&1 & + echo "DnsForwarder: Start DNS Caching" + +} + +start_dnsproxy() { + [ -d "/var/run/dnscache" ] || mkdir -p "/var/run/dnscache" + echo -e "${dns_caching_dns//,/\\n}" > "/var/run/dnscache/dnscache.conf" + + [ -d "/var/sbin" ] || mkdir -p "/var/sbin" + cp -a "/usr/bin/dnsproxy" "/var/sbin/dnscache" + /var/sbin/dnscache -l "127.0.0.1" -p "5333" -b "tls://9.9.9.9" -f "tls://8.8.8.8" -u "/var/run/dnscache/dnscache.conf" --all-servers --cache --cache-min-ttl=3600 > "/var/log/dnscache.file" 2>&1 & + echo "DNSProxy: Start DNS Caching" +} + +stop_dnscache() { + $PS -w | grep dnscache | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + $PS -w | grep dnscache-while.sh | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + killall -q -9 dnscache + rm -rf "/var/dnscache" "/var/run/dnscache" + echo "Stop DNS Caching" +} + +change_dns() { + uci -q delete dhcp.@dnsmasq[0].server + uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#5333" + uci set dhcp.@dnsmasq[0].noresolv="1" + uci commit dhcp + +} + +revert_dns() { + uci -q del_list dhcp.@dnsmasq[0].server="127.0.0.1#5333" + uci set dhcp.@dnsmasq[0].resolvfile="/tmp/resolv.conf.d/resolv.conf.auto" + uci set dhcp.@dnsmasq[0].noresolv="0" + uci commit dhcp +} + +start(){ + inital_conf + + uci set firewall.@defaults[0].flow_offloading="${sw_flow}" + uci set firewall.@defaults[0].flow_offloading_hw="${hw_flow}" + uci set firewall.@defaults[0].fullcone="${fullcone_nat}" + uci commit firewall + + [ "${sw_flow}" -ne "1" ] && { + [ "${sfe_flow}" -eq "1" ] && { + [ "$(have_ecm_init)" = "0" ] && { + /etc/init.d/shortcut-fe enabled || /etc/init.d/shortcut-fe enable + /etc/init.d/shortcut-fe start + } + } + [ "${sfe_flow}" -eq "0" ] && [ -e "/etc/init.d/shortcut-fe" ] && [ "$(have_ecm_init)" = "0" ] && \ + /etc/init.d/shortcut-fe enabled && { + /etc/init.d/shortcut-fe stop 2>"/dev/null" + /etc/init.d/shortcut-fe disable + } + } + + if [ "${bbr_cca}" -eq "1" ]; then + sysctl -w net.ipv4.tcp_congestion_control="bbr" + else + sysctl -w net.ipv4.tcp_congestion_control="cubic" + fi + + if [ "${dns_caching}" -eq "1" ]; then + stop_dnscache + sleep 1 + + rm -f "/var/log/dnscache.file" + if [ "${dns_caching_mode}" = "1" ]; then + start_pdnsd + elif [ "${dns_caching_mode}" = "2" ]; then + start_dnsforwarder + elif [ "${dns_caching_mode}" = "3" ]; then + start_dnsproxy + fi + + change_dns + /usr/share/dnscache/dnscache-while.sh > "/var/log/dnscache.file" 2>&1 & + else + stop_dnscache + revert_dns + fi + + if [ "${restart_utils}" = "true" ]; then + /etc/init.d/dnsmasq restart >"/dev/null" 2>&1 && echo "DNSMASQ change" + /etc/init.d/firewall restart >"/dev/null" 2>&1 + fi +} + +stop(){ + inital_conf + + uci set firewall.@defaults[0].flow_offloading="${sw_flow}" + uci set firewall.@defaults[0].flow_offloading_hw="${hw_flow}" + uci set firewall.@defaults[0].fullcone="${fullcone_nat}" + uci commit firewall + + [ "${sfe_flow}" -ne "1" ] && { + [ -e "/etc/init.d/shortcut-fe" ] && [ "$(have_ecm_init)" = "0" ] && { + /etc/init.d/shortcut-fe stop 2>"/dev/null" + /etc/init.d/shortcut-fe enabled && /etc/init.d/shortcut-fe disable + } + } + + stop_dnscache + revert_dns + + if [ "${restart_utils}" = "true" ]; then + /etc/init.d/dnsmasq restart >"/dev/null" 2>&1 && echo "DNSMASQ revert" + /etc/init.d/firewall restart >"/dev/null" 2>&1 + fi +} + +restart(){ + restart_utils="false" + stop + start + /etc/init.d/dnsmasq restart >"/dev/null" 2>&1 && echo "DNSMASQ restart" + /etc/init.d/firewall restart >"/dev/null" 2>&1 +} + +have_ecm_init() { + [ -e "/etc/init.d/qca-nss-ecm" ] && echo 1 && return + echo 0 +} + +ecm_mode(){ + config_load "ecm" + config_get front_end global acceleration_engine + case $front_end in + auto | nss | sfe | hybrid) + [ -d /sys/kernel/debug/ecm/ecm_nss_ipv4 ] && echo 'NSS: Enabled ' || echo 'NSS: Disabled ' + [ -d /sys/kernel/debug/ecm/ecm_sfe_ipv4 ] && echo 'SFE: Enabled' || echo 'SFE: Disabled' + ;; + *) + echo 'Unknown' + esac +} + + +check_status(){ + case "$1" in + "fastpath") + if [ "$(cat "/sys/module/xt_FLOWOFFLOAD/refcnt" 2>"/dev/null" || echo 0)" -ne "0" ]; then + echo -n "Flow Offloading" + exit 0 + elif lsmod | grep -q "ecm"; then + echo -n "QCA-ECM Engine: "$(ecm_mode) + exit 0 + elif lsmod | grep -q "shortcut_fe_cm"; then + echo -n "Shortcut-FE" + exit 0 + else + exit 1 + fi + ;; + "fullconenat") + [ "$(cat "/sys/module/xt_FULLCONENAT/refcnt" 2>"/dev/null" || echo 0)" -ne "0" ] && \ + exit 0 || exit 1 + ;; + "bbr") + [ "x$(cat "/proc/sys/net/ipv4/tcp_congestion_control" 2>"/dev/null")" = "xbbr" ] && \ + exit 0 || exit 1 + ;; + "dns") + pgrep "dnscache" >"/dev/null" && exit 0 || exit 1 + ;; + *) + exit 2 + ;; + esac +} diff --git a/luci-app-turboacc/root/etc/uci-defaults/luci-turboacc b/luci-app-turboacc/root/etc/uci-defaults/luci-turboacc new file mode 100755 index 000000000..37a556f42 --- /dev/null +++ b/luci-app-turboacc/root/etc/uci-defaults/luci-turboacc @@ -0,0 +1,10 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@turboacc[-1] + add ucitrack turboacc + set ucitrack.@turboacc[-1].init=turboacc + commit ucitrack +EOF + +exit 0 diff --git a/luci-app-turboacc/root/usr/share/dnscache/dnscache-while.sh b/luci-app-turboacc/root/usr/share/dnscache/dnscache-while.sh new file mode 100755 index 000000000..63a94bbd8 --- /dev/null +++ b/luci-app-turboacc/root/usr/share/dnscache/dnscache-while.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +sleeptime=60 + +dnsconf="/var/run/dnscache/dnscache.conf" +dnsprogram="/var/sbin/dnscache" +logfile="/var/log/dnscache.file" + +dns_caching="$(uci -q get turboacc.config.dns_caching)" +dns_caching_mode="$(uci -q get turboacc.config.dns_caching_mode)" + +clean_log() { + logrow="$(grep -c "" "${logfile}")" + [ "${logrow}" -lt "500" ] || echo "${curtime} Log 条数超限,清空处理!" > "${logfile}" +} + +while [ "${dns_caching}" -eq "1" ]; +do + curtime="$(date "+%H:%M:%S")" + + clean_log + + if pidof dnscache > "/dev/null"; then + echo -e "${curtime} online!" >> "${logfile}" + else + if [ "${dns_caching_mode}" = "1" ]; then + ${dnsprogram} -c "${dnsconf}" > "${logfile}" 2>&1 & + elif [ "${dns_caching_mode}" = "2" ]; then + ${dnsprogram} -f "${dnsconf}" > "${logfile}" 2>&1 & + elif [ "${dns_caching_mode}" = "3" ]; then + ${dnsprogram} -o "${logfile}" -l "127.0.0.1" -p "5333" -b "tls://9.9.9.9" -f "tls://8.8.8.8" -u "${dnsconf}" --all-servers --cache --cache-min-ttl=3600 > "${logfile}" 2>&1 & + fi + echo "${curtime} 重启服务!" >> ${logfile} + fi + + sleep "${sleeptime}" + continue +done diff --git a/luci-app-zerotier/Makefile b/luci-app-zerotier/Makefile index 80fa08c2a..11c26ca4f 100644 --- a/luci-app-zerotier/Makefile +++ b/luci-app-zerotier/Makefile @@ -9,6 +9,8 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI for Zerotier LUCI_DEPENDS:=+zerotier LUCI_PKGARCH:=all + +PKG_NAME:=luci-app-zerotier PKG_VERSION:=1.0 PKG_RELEASE:=20 diff --git a/luci-app-zerotier/luasrc/controller/zerotier.lua b/luci-app-zerotier/luasrc/controller/zerotier.lua index 9c69c063e..0b9d55178 100644 --- a/luci-app-zerotier/luasrc/controller/zerotier.lua +++ b/luci-app-zerotier/luasrc/controller/zerotier.lua @@ -1,14 +1,13 @@ -module("luci.controller.zerotier",package.seeall) +module("luci.controller.zerotier", package.seeall) function index() if not nixio.fs.access("/etc/config/zerotier") then return end - entry({"admin","vpn"}, firstchild(), "VPN", 45).dependent = false - - entry({"admin", "vpn", "zerotier"},firstchild(), _("ZeroTier")).dependent = false + entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false + entry({"admin", "vpn", "zerotier"}, alias("admin", "vpn", "zerotier", "general"), _("ZeroTier"), 99) entry({"admin", "vpn", "zerotier", "general"}, cbi("zerotier/settings"), _("Base Setting"), 1) entry({"admin", "vpn", "zerotier", "log"}, form("zerotier/info"), _("Interface Info"), 2) diff --git a/luci-app-zerotier/luasrc/model/cbi/zerotier/info.lua b/luci-app-zerotier/luasrc/model/cbi/zerotier/info.lua index 199c468dd..e392cb0f4 100644 --- a/luci-app-zerotier/luasrc/model/cbi/zerotier/info.lua +++ b/luci-app-zerotier/luasrc/model/cbi/zerotier/info.lua @@ -7,9 +7,9 @@ t = f:field(TextValue, "conf") t.rmempty = true t.rows = 19 function t.cfgvalue() - luci.sys.exec("for i in $(ifconfig | grep 'zt' | awk '{print $1}'); do ifconfig $i; done > /tmp/zero.info") + luci.sys.exec("for i in $(ifconfig | grep 'zt' | awk '{print $1}'); do ifconfig $i; done > /tmp/zero.info") return fs.readfile(conffile) or "" end -t.readonly="readonly" +t.readonly = "readonly" return f diff --git a/luci-app-zerotier/luasrc/model/cbi/zerotier/settings.lua b/luci-app-zerotier/luasrc/model/cbi/zerotier/settings.lua index 32ef1bbfc..8e6102cc5 100644 --- a/luci-app-zerotier/luasrc/model/cbi/zerotier/settings.lua +++ b/luci-app-zerotier/luasrc/model/cbi/zerotier/settings.lua @@ -2,7 +2,7 @@ a = Map("zerotier") a.title = translate("ZeroTier") a.description = translate("Zerotier is an open source, cross-platform and easy to use virtual LAN") -a:section(SimpleSection).template = "zerotier/zerotier_status" +a:section(SimpleSection).template = "zerotier/zerotier_status" t = a:section(NamedSection, "sample_config", "zerotier") t.anonymous = true @@ -10,7 +10,7 @@ t.addremove = false e = t:option(Flag, "enabled", translate("Enable")) e.default = 0 -e.rmempty=false +e.rmempty = false e = t:option(DynamicList, "join", translate('ZeroTier Network ID')) e.password = true diff --git a/luci-app-zerotier/po/zh-cn/zerotier.po b/luci-app-zerotier/po/zh-cn/zerotier.po index 9ed1270b3..dd3cd714a 100644 --- a/luci-app-zerotier/po/zh-cn/zerotier.po +++ b/luci-app-zerotier/po/zh-cn/zerotier.po @@ -1,11 +1,3 @@ -msgid "" -msgstr "" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Gtranslator 2.91.7\n" -"Plural-Forms: nplurals=1; plural=0;\n" - msgid "Zerotier is an open source, cross-platform and easy to use virtual LAN" msgstr "Zerotier 是一个开源,跨平台,而且适合内网穿透互联的傻瓜配置虚拟 VPN LAN" diff --git a/luci-app-zerotier/root/etc/init.d/zerotier b/luci-app-zerotier/root/etc/init.d/zerotier index 0403e5d17..666d67533 100755 --- a/luci-app-zerotier/root/etc/init.d/zerotier +++ b/luci-app-zerotier/root/etc/init.d/zerotier @@ -110,4 +110,4 @@ stop_service() { reload_service() { stop start -} \ No newline at end of file +} diff --git a/luci-app-zerotier/root/etc/uci-defaults/40_luci-zerotier b/luci-app-zerotier/root/etc/uci-defaults/40_luci-zerotier index 95f0ccfc9..616824562 100755 --- a/luci-app-zerotier/root/etc/uci-defaults/40_luci-zerotier +++ b/luci-app-zerotier/root/etc/uci-defaults/40_luci-zerotier @@ -5,7 +5,8 @@ uci -q batch <<-EOF >/dev/null add ucitrack zerotier set ucitrack.@zerotier[-1].init=zerotier commit ucitrack - delete firewall.zerotier + + delete firewall.zerotier set firewall.zerotier=include set firewall.zerotier.type=script set firewall.zerotier.path=/etc/zerotier.start diff --git a/luci-app-zerotier/root/etc/zerotier.stop b/luci-app-zerotier/root/etc/zerotier.stop index 07450183e..cbe7ec4b6 100755 --- a/luci-app-zerotier/root/etc/zerotier.stop +++ b/luci-app-zerotier/root/etc/zerotier.stop @@ -12,4 +12,4 @@ do ip_segment="$(ip route | grep "dev $i proto" | awk '{print $1}')" iptables -t nat -D POSTROUTING -s "${ip_segment}" -j MASQUERADE 2>/dev/null echo "zt interface $i is stopped!" -done \ No newline at end of file +done diff --git a/luci-app-zerotier/root/usr/share/rpcd/acl.d/luci-app-zerotier.json b/luci-app-zerotier/root/usr/share/rpcd/acl.d/luci-app-zerotier.json deleted file mode 100644 index 2724e99bf..000000000 --- a/luci-app-zerotier/root/usr/share/rpcd/acl.d/luci-app-zerotier.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "luci-app-zerotier": { - "description": "Grant UCI access for luci-app-zerotier", - "read": { - "uci": [ "zerotier" ] - }, - "write": { - "uci": [ "zerotier" ] - } - } -} diff --git a/luci-theme-ezengreen/Makefile b/luci-theme-ezengreen/Makefile new file mode 100755 index 000000000..ee17e224f --- /dev/null +++ b/luci-theme-ezengreen/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# Copyright (C) 2018-2019 Ycarus (Yannick Chabanois) +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=ezengreen Theme (default) +LUCI_DEPENDS:= + +#include ../luci/luci.mk +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/1omr-logo-apple.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/1omr-logo-apple.png new file mode 100755 index 000000000..7ee777910 Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/1omr-logo-apple.png differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css new file mode 100755 index 000000000..740adc320 --- /dev/null +++ b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css @@ -0,0 +1,2027 @@ +/*! + * LuCI Bootstrap Theme + * Copyright 2012 Nut & Bolt + * By David Menting + * Based on Bootstrap v1.4.0 + * + * Copyright 2011 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +/* Reset.less + * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc). + * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ +html { + margin: 0; + padding: 0; +} + +body { + margin: 0; + padding: 5px; +} + +h1, h2, h3, h4, h5, h6, p, pre, a, abbr, acronym, code, del, em, img, ins, q, s, +small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, +form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td, +.table, .tbody, .tfoot, .thead, .tr, .th, .td { + margin: 0; + padding: 0; + border: 0; + font-weight: normal; + font-style: normal; + font-size: 100%; + line-height: 1; + font-family: inherit; +} + +abbr[title], acronym[title] { + border-bottom: 1px dotted; + font-weight: inherit; + cursor: help; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +ol, ul { + list-style: none; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +html { + overflow-y: scroll; + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted; +} + +a:hover, a:active { + outline: 0; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + border: 0; + -ms-interpolation-mode: bicubic; +} + +button, +input, +select, +option, +textarea { + font-size: 100%; + margin: 0; + box-sizing: border-box; + vertical-align: baseline; + *vertical-align: middle; +} + +button, input { + line-height: normal; + *overflow: visible; +} + +button::-moz-focus-inner, input::-moz-focus-inner { + border: 0; + padding: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +button[disabled], +input[type="button"][disabled], +input[type="reset"][disabled], +input[type="submit"][disabled] { + opacity: 0.7; +} + +input[type="search"] { + -webkit-appearance: textfield; + box-sizing: content-box; +} + +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +/* + * Scaffolding + * Basic and global styles for generating a grid system, structural layout, and page templates + * ------------------------------------------------------------------------------------------- */ +body { + background-color: #fff; + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 12px; + font-weight: normal; + line-height: 18px; + color: #404040; + padding-top: 75px; +} + +.container { + width: 100%; + max-width: 940px; + margin-left: auto; + margin-right: auto; + zoom: 1; +} + +.container:before, .container:after { + display: table; + content: ""; + zoom: 1; +} + +.container:after { + clear: both; +} + +a { + color: #215e21; + text-decoration: none; + line-height: inherit; + font-weight: inherit; +} + +a:hover { + color: #000000; + text-decoration: none; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +/* Typography.less + * Headings, body text, lists, code, and more for a versatile and durable typography system + * ---------------------------------------------------------------------------------------- */ +p, +.cbi-map-descr, +.cbi-section-descr, +.table .tr.cbi-section-table-descr .th { + font-size: 12px; + font-weight: normal; + line-height: 18px; + margin-bottom: 9px; +} + +p small { + font-size: 11px; + color: #bfbfbf; +} + +h1, +h2, +h3, legend, +h4, +h5, +h6 { + font-weight: normal; + color: #404040; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + color: #bfbfbf; +} + +h1 { + margin-bottom: 18px; + font-size: 30px; + line-height: 36px; +} + +h1 small { + font-size: 18px; +} + +h2 { + font-size: 24px; + line-height: 58px; + text-transform: uppercase; + font-weight: normal; +} + +h2 small { + font-size: 14px; +} + +h3, legend, +h4, +h5, +h6 { + line-height: 48px; +} + +h3, legend { + font-size: 18px; +} + +h3 small { + font-size: 14px; +} + +h4 { + font-size: 16px; +} + +h4 small { + font-size: 12px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 13px; + color: #bfbfbf; + text-transform: uppercase; +} + +ul, ol { + margin: 0 0 18px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li { + line-height: 18px; + color: #808080; +} + +ul.unstyled { + list-style: none; + margin-left: 0; +} + +dl { + margin-bottom: 18px; +} + +dl dt, dl dd { + line-height: 18px; +} + +dl dt { + font-weight: bold; +} + +dl dd { + margin-left: 9px; +} + +hr { + margin: 20px 0 19px; + border: 0; + border-bottom: 1px solid #eee; +} + +strong { + font-style: inherit; + font-weight: bold; +} + +em { + font-style: italic; + font-weight: inherit; + line-height: inherit; +} + +small { font-size: 0.9em } + +address { + display: block; + line-height: 18px; + margin-bottom: 18px; +} + +code, pre { + padding: 0 3px 2px; + font-family: Monaco, Andale Mono, Courier New, monospace; + font-size: 12px; + border-radius: 2px; +} + +code { + background-color: #fee9cc; + color: rgba(0, 0, 0, 0.75); + padding: 1px 3px; +} + +pre { + background-color: #f5f5f5; + display: block; + padding: 8.5px; + margin: 0 0 18px; + line-height: 18px; + font-size: 12px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 2px; + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +/* Forms.less + * Base styles for various input types, form layouts, and states + * ------------------------------------------------------------- */ +form { + margin-bottom: 18px; +} + +fieldset { + margin-bottom: 9px; + padding-top: 9px; +} + +fieldset legend { + display: block; + font-size: 19.5px; + line-height: 1; + color: #404040; + padding-top: 20px; + *padding: 0 0 5px 0px; + /* IE6-7 */ + + *line-height: 1.5; + /* IE6-7 */ + +} +form .cbi-tab-descr { + line-height: 18px; + margin-bottom: 18px; +} + +form .clearfix, +form .cbi-value { + margin-bottom: 15px; + margin-top: 15px; + zoom: 1; +} + +form .clearfix:before, form .clearfix:after, +form .cbi-value:before, form .cbi-value:after { + display: table; + content: ""; + zoom: 1; +} + +form .clearfix:after, +form .cbi-value:after { + clear: both; +} + +label, +input, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 12px; + font-weight: normal; + line-height: normal; +} + +form .input, +form .cbi-value-field { + margin-left: 120px; +} + +form .cbi-value label.cbi-value-title { + padding-top: 6px; + font-size: 12px; + line-height: 18px; + float: left; + width: 111px; + text-align: left; + color: #404040; +} + +input[type=checkbox], input[type=radio] { + cursor: pointer; +} + +input, +textarea, +select, +.cbi-dropdown, +.uneditable-input { + display: inline-block; + width: 200px; + height: 30px; + padding: 4px; + font-size: 12px; + line-height: 18px; + color: #808080; + border: 1px solid #ccc; + border-radius: 2px; + box-sizing: border-box; + margin: 2px 0; +} + +.cbi-dropdown { + min-width: 210px; + max-width: 400px; + width: auto; +} + +select { + padding: initial; + background: #fff; + box-shadow: inset 0 -1px 3px rgba(0, 0, 0, 0.1); +} + +input[type=checkbox], input[type=radio] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE6-7 */ + + line-height: normal; + border: none; +} + +input[type=file] { + background-color: #fff; + padding: initial; + border: initial; + line-height: initial; + box-shadow: none; + width: auto !important; +} + +input[type=button], input[type=reset], input[type=submit] { + width: auto; + height: auto; +} + +select, input[type=file] { + *height: auto; + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ +} + +select[multiple] { + height: inherit; + background-color: #fff; +} + +textarea { + height: auto; +} + +.td > input[type=text], +.td > input[type=password], +.td > select, +.td > .cbi-dropdown { + width: 100%; +} + +.uneditable-input { + background-color: #fff; + display: block; + border-color: #eee; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} + +::-moz-placeholder { + color: #bfbfbf; +} + +::-webkit-input-placeholder { + color: #bfbfbf; +} + +.btn, .cbi-button, input, textarea { + transition: border linear 0.2s, box-shadow linear 0.2s; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); + padding: 12px 6px; +} + +.btn:hover, .cbi-button:hover, +input:focus, textarea:focus { + outline: 0; + border-color: rgba(82, 168, 236, 0.8) !important; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); + text-decoration: none; +} + +input[type=file]:focus, input[type=checkbox]:focus, select:focus { + box-shadow: none; + outline: 1px dotted #666; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #194119; + border-color: #ccc; + padding: 5px; + pointer-events: none; + cursor: default; +} + +select[readonly], +textarea[readonly] { + pointer-events: auto; + cursor: auto; +} + +.cbi-optionals, +.cbi-section-create { + padding: 0 0 10px 10px; +} + +.cbi-section-create { + margin: 10px 0 0 -10px; + display: inline-flex; + align-items: center; +} + +.cbi-section-create > * { + margin: 3px; + flex: 1 1 auto; +} + +.cbi-section-create > * > input { + width: 100%; +} + +.actions, +.cbi-page-actions { + background: #f5f5f5; + margin-bottom: 20px; + margin-top: 40px; + padding: 15px 20px 15px 20px; + border-radius: 0 0 2px 2px; + text-align: right; +} + +.actions .secondary-action, +.cbi-page-actions .secondary-action{ + float: right; +} + +.actions .secondary-action a, +.cbi-page-actions .secondary-action a { + line-height: 30px; +} + +.actions .secondary-action a:hover, +.cbi-page-actions .secondary-action a:hover { + text-decoration: none; +} + +.cbi-page-actions > form { + display: inline; + margin: 0; +} + +.help-inline, .help-block { + font-size: 12px; + line-height: 18px; + color: #bfbfbf; +} + +.help-inline { + padding-left: 5px; + *position: relative; + /* IE6-7 */ + + *top: -5px; + /* IE6-7 */ + +} + +.help-block { + display: block; + max-width: 600px; +} + +/* + * Tables.less + * Tables for, you guessed it, tabular data + * ---------------------------------------- */ +.tr { display: table-row; } +.table[width="33%"], .th[width="33%"], .td[width="33%"] { width: 33%; } +.table[width="100%"], .th[width="100%"], .td[width="100%"] { width: 100%; } + +.table { + display: table; + width: 100%; + margin: 12px 0 24px 0; + padding: 0; + font-size: 12px; + border-collapse: collapse; + position: relative; +} + +.table .th, .table .td { + display: table-cell; + vertical-align: middle; /* Fixme */ + padding: 6px 6px 6px 2px; + line-height: 18px; + text-align: left; +} + +.table .tr:first-child .th { + padding-top: 9px; + font-weight: normal; + vertical-align: top; +} + +.table .td, .table .th { + border-top: 1px solid #e7e7e7; +} + +.tr.placeholder { + height: calc(3em + 20px); +} + +.tr.placeholder > .td { + position: absolute; + left: 0; + right: 0; + bottom: 0; + text-align: center; + line-height: 3em; +} + +/* Patterns.less + * Repeatable UI elements outside the base styles provided from the scaffolding + * ---------------------------------------------------------------------------- */ +header { + height: 40px; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 10000; + overflow: visible; + color: #BFBFBF; +} + +header a { + color: #c4c4c4; +} + +header h3 a:hover, header .brand:hover, header ul .active > a { + background-color: #333; + background-color: rgba(0, 0, 0, 0.33); + color: #fff; + text-decoration: none; +} + +header h3 { + position: relative; +} + +header h3 a, header .brand { + float: left; + display: block; + padding: 16px 20px 16px; + margin-left: -20px; + color: #fff; + font-size: 24px; + font-weight: 333; + line-height: 1; +} + +header p { + margin: 0; + line-height: 40px; +} + +header .fill { + background-color: #215e21; + background-repeat: repeat-x; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.33), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + padding: 0 5px; +} + +header div > ul, .nav { + display: block; + float: left; + margin: 0 10px 0 20px; + position: relative; + left: 0; +} + +header div > ul > li, .nav > li { + display: block; + float: left; +} + +header div > ul a, .nav a { + display: block; + float: none; + padding: 22px 12px 14px 12px; + line-height: 19px; + letter-spacing: 0.4px; + text-decoration: none; + text-transform: uppercase; +} + +header div > ul a:hover, .nav a:hover { + color: #fff; + text-decoration: none; +} + +header div > ul .active > a, .nav .active > a { + background-color: #222; + background-color: rgba(0, 0, 0, 0.33); +} + +header div > ul.secondary-nav, .nav.secondary-nav { + float: right; + margin-left: 10px; + margin-right: 0; +} + +header div > ul.secondary-nav .menu-dropdown, +.nav.secondary-nav .menu-dropdown, +header div > ul.secondary-nav .dropdown-menu, +.nav.secondary-nav .dropdown-menu { + right: 0; + border: 0; +} + +header div > ul a.menu:hover, +.nav a.menu:hover, +header div > ul li.open .menu, +.nav li.open .menu, +header div > ul .dropdown-toggle:hover, +.nav .dropdown-toggle:hover, +header div > ul .dropdown.open .dropdown-toggle, +.nav .dropdown.open .dropdown-toggle { + background: #444; + background: rgba(0, 0, 0, 0.3); +} + +header div > ul .menu-dropdown, +.nav .menu-dropdown, +header div > ul .dropdown-menu, +.nav .dropdown-menu { + background-color: #003300; +} + +header div > ul .menu-dropdown a.menu, +.nav .menu-dropdown a.menu, +header div > ul .dropdown-menu a.menu, +.nav .dropdown-menu a.menu, +header div > ul .menu-dropdown .dropdown-toggle, +.nav .menu-dropdown .dropdown-toggle, +header div > ul .dropdown-menu .dropdown-toggle, +.nav .dropdown-menu .dropdown-toggle { + color: #fff; +} + +header div > ul .menu-dropdown a.menu.open, +.nav .menu-dropdown a.menu.open, +header div > ul .dropdown-menu a.menu.open, +.nav .dropdown-menu a.menu.open, +header div > ul .menu-dropdown .dropdown-toggle.open, +.nav .menu-dropdown .dropdown-toggle.open, +header div > ul .dropdown-menu .dropdown-toggle.open, +.nav .dropdown-menu .dropdown-toggle.open { + background: #444; + background: rgba(255, 255, 255, 0.05); +} + +header div > ul .menu-dropdown li a, +.nav .menu-dropdown li a, +header div > ul .dropdown-menu li a, +.nav .dropdown-menu li a { + color: #bfbfbf; +} + +header div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +header div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #215e21; + background-repeat: repeat-x; + color: #fff; +} + +header div > ul .menu-dropdown .active a, +.nav .menu-dropdown .active a, +header div > ul .dropdown-menu .active a, +.nav .dropdown-menu .active a { + color: #fff; +} + +header div > ul .menu-dropdown .divider, +.nav .menu-dropdown .divider, +header div > ul .dropdown-menu .divider, +.nav .dropdown-menu .divider { + background-color: #222; + border-color: #444; +} + +header ul .menu-dropdown li a, header ul .dropdown-menu li a { + padding: 6px 12px; +} + +li.menu, .dropdown { + position: relative; +} + +.menu-dropdown, .dropdown-menu { + background-color: #fff; + float: left; + position: absolute; + top: 55px; + left: -9999px; + z-index: 900; + min-width: 200px; + max-width: 300px; + _width: 160px; + margin-left: 0; + margin-right: 0; + padding: 6px 0; + zoom: 1; + border-radius: 0 0 2px 2px; + background-clip: padding-box; +} + +.menu-dropdown li, .dropdown-menu li { + float: none; + display: block; + background-color: transparent; +} + +.menu-dropdown .divider, .dropdown-menu .divider { + height: 1px; + margin: 5px 0; + overflow: hidden; + background-color: #eee; + border-bottom: 1px solid #fff; +} + +header .dropdown-menu a, .dropdown-menu a { + display: block; + padding: 4px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + text-transform: capitalize; + letter-spacing: 0.2px; + color: #808080; + zoom: 1.1; +} + +header .dropdown-menu a:hover, +.dropdown-menu a:hover, +header .dropdown-menu a.hover, +.dropdown-menu a.hover { + background-color: #ddd; + background-repeat: repeat-x; + color: #404040; + text-decoration: none; + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025); +} + +.open .menu, +.dropdown.open .menu, +.open .dropdown-toggle, +.dropdown.open .dropdown-toggle { + color: #fff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} + +.open .menu-dropdown, +.dropdown.open .menu-dropdown, +.open .dropdown-menu, +.dropdown.open .dropdown-menu { + left: 0; +} + +.dropdown:hover ul.dropdown-menu { + left: 0; +} + +.dropdown-menu .dropdown-menu { + position: absolute; + left: 159px; +} + +.dropdown-menu li { + position: relative; +} + +.tabs, .cbi-tabmenu { + margin: 0 0 18px; + padding: 0; + list-style: none; + zoom: 1; +} + +.tabs:before, +.cbi-tabmenu:before, +.tabs:after, +.cbi-tabmenu:after { + display: table; + content: ""; + zoom: 1; +} + +.tabs:after, .cbi-tabmenu:after { + clear: both; +} + +.tabs > li, .cbi-tabmenu > li { + float: left; +} + +.tabs > li > a, .cbi-tabmenu > li > a { + display: block; +} + +.tabs, +.cbi-tabmenu { + border-color: #ddd; + border-style: solid; + border-width: 0 0 1px; +} + +.tabs > li, +.cbi-tabmenu > li { + position: relative; + margin-bottom: -1px; +} + +.cbi-tabmenu.map { + margin: 0; +} + +.cbi-tabmenu.map > li { + font-size: 16.5px; + font-weight: bold; +} + +.cbi-tabcontainer > fieldset.cbi-section[id] > legend { + display: none; +} + +.tabs > li > a, +.cbi-tabmenu > li > a { + padding: 0 15px; + margin-right: 2px; + line-height: 34px; + border: 1px solid transparent; + border-radius: 2px 2px 0 0; +} + +.tabs > li > a:hover, +.cbi-tabmenu > li > a:hover { + text-decoration: none; + background-color: #eee; + border-color: #eee #eee #ddd; +} + +.tabs .active > a, .tabs .active > a:hover, +.cbi-tabmenu .active > a, .cbi-tabmenu .active > a:hover, +.cbi-tab > a:link, .cbi-tab > a:hover { + color: #000000; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} + +.tabs .menu-dropdown, .tabs .dropdown-menu, +.cbi-tabmenu .menu-dropdown, .cbi-tabmenu .dropdown-menu { + top: 35px; + border-width: 1px; + border-radius: 0 2px 2px 2px; +} + +.tabs a.menu:after, .tabs .dropdown-toggle:after, +.cbi-tabmenu a.menu:after, .cbi-tabmenu .dropdown-toggle:after { + border-top-color: #999; + margin-top: 15px; + margin-left: 5px; +} + +.tabs li.open.menu .menu, .tabs .open.dropdown .dropdown-toggle, +.cbi-tabmenu li.open.menu .menu, .cbi-tabmenu .open.dropdown .dropdown-toggle { + border-color: #999; +} + +.tabs li.open a.menu:after, .tabs .dropdown.open .dropdown-toggle:after, +.cbi-tabmenu li.open a.menu:after, .cbi-tabmenu .dropdown.open .dropdown-toggle:after { + border-top-color: #555; +} + +.tab-content > .tab-pane, +.tab-content > div { + display: none; +} + +.tab-content > .active { + display: block; +} + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #f5f5f5; + background-repeat: repeat-x; + border: 1px solid #ddd; + border-radius: 2px; + box-shadow: inset 0 1px 0 #fff; +} + +.breadcrumb li { + display: inline; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #bfbfbf; +} + +.breadcrumb .active a { + color: #404040; +} + +footer { + margin-top: 30px; + padding-top: 20px; + padding-bottom: 20px; + border-top: 1px solid #404040; +} + +.btn.danger, +.alert-message.danger, +.btn.danger:hover, +.alert-message.danger:hover, +.btn.error, +.alert-message.error, +.btn.error:hover, +.alert-message.error:hover, +.btn.success, +.alert-message.success, +.btn.success:hover, +.alert-message.success:hover, +.btn.info, +.alert-message.info, +.btn.info:hover, +.alert-message.info:hover { + color: #fff; +} + +.btn .close, .alert-message .close { + font-family: Arial, sans-serif; + line-height: 18px; +} + +.btn.danger, +.alert-message.danger, +.btn.error, +.alert-message.error { + background: linear-gradient(to bottom, #ee5f5b, #c43c35) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn.success, .alert-message.success { + background: linear-gradient(to bottom, #62c462, #57a957) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn.info, .alert-message.info { + background: linear-gradient(to bottom, #5bc0de, #339bb9) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.alert-message.notice { + background: linear-gradient(to bottom, #efefef, #fefefe) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn, +.cbi-button { + cursor: pointer; + display: inline-block; + background: linear-gradient(#fff, #fff 25%, #e6e6e6) no-repeat; + padding: 5px 14px 6px; + color: #333; + font-size: 12px; + line-height: normal; + border: 1px solid #ccc; + border-bottom-color: #bbb; + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:focus, +.cbi-button:focus { + outline: 1px dotted #666; +} + +.cbi-input-invalid, +.cbi-value-error input { + color: #f00; + border-color: #f00; +} + +.cbi-button-positive, +.cbi-button-fieldadd, +.cbi-button-add, +.cbi-button-save { + border-color: #4a4; + color: #4a4; +} + +.cbi-button-neutral, +.cbi-button-download, +.cbi-button-find, +.cbi-button-link, +.cbi-button-up, +.cbi-button-down { + color: #444; +} + +.btn.primary, +.cbi-button-action, +.cbi-button-apply, +.cbi-button-reload, +.cbi-button-edit { + border-color: #4aa44b; + color: #4aa44b; +} + +.cbi-button-negative, +.cbi-section-remove .cbi-button, +.cbi-button-reset, +.cbi-button-remove { + border-color: #c44; + color: #c44; +} + +.cbi-page-actions::after { + display: table; + content: ""; + clear: both; +} + +.cbi-page-actions > :not([method="post"]):not(.cbi-button-apply):not(.cbi-button-save):not(.cbi-button-reset) { + float: left; + margin-right: .4em; +} + +.btn.primary, +.cbi-button-action.important, +.cbi-page-actions .cbi-button-apply, +.cbi-section-actions .cbi-button-edit { + color: #fff; + background: #4aa44b; +} + +.cbi-button-positive.important, +.cbi-page-actions .cbi-button-save { + color: #fff; + background: linear-gradient(to bottom, #4a4, #484) no-repeat; +} + +.cbi-button-negative.important { + color: #fff; + background: linear-gradient(to bottom, #c44, #c00) no-repeat; +} + +.cbi-page-actions .cbi-button-apply + .cbi-button-save { + background: linear-gradient(#fff, #fff 25%, #e6e6e6); + color: #4a4; +} + +.cbi-dropdown { + border: 1px solid #ccc; + border-radius: 2px; + display: inline-flex; + padding: 0; + cursor: pointer; + height: auto; + background: linear-gradient(#fff 0%, #e9e8e6 100%); + position: relative; + color: #404040; +} + +.cbi-dropdown:focus { + outline: 2px solid #4b6e9b; +} + +.cbi-dropdown > ul { + margin: 0 !important; + padding: 0; + list-style: none; + overflow-x: hidden; + overflow-y: auto; + display: flex; + width: 100%; +} + +.cbi-dropdown > ul.preview { + display: none; +} + +.cbi-dropdown > .open, +.cbi-dropdown > .more { + flex-grow: 0; + flex-shrink: 0; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + line-height: 2em; + padding: 0 .25em; +} + +.cbi-dropdown > .more, +.cbi-dropdown > ul > li[placeholder] { + color: #777; + font-weight: bold; + display: none; +} + +.cbi-dropdown > ul > li { + display: none; + padding: .25em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex-shrink: 1; + flex-grow: 1; + align-items: center; + align-self: center; + color: #404040; + min-height: 20px; +} + +.cbi-dropdown > ul > li .hide-open { display: block; display: initial; } +.cbi-dropdown > ul > li .hide-close { display: none; } + +.cbi-dropdown > ul > li[display]:not([display="0"]) { + border-left: 1px solid #ccc; +} + +.cbi-dropdown[empty] > ul { + max-width: 1px; +} + +.cbi-dropdown > ul > li > form { + display: none; + margin: 0; + padding: 0; + pointer-events: none; +} + +.cbi-dropdown > ul > li img { + vertical-align: middle; + margin-right: .25em; +} + +.cbi-dropdown > ul > li > form > input[type="checkbox"] { + margin: 0; +} + +.cbi-dropdown > ul > li input[type="text"] { + height: 20px; +} + +.cbi-dropdown[open] { + position: relative; +} + +.cbi-dropdown[open] > ul.dropdown { + display: block; + background: #f6f6f5; + border: 1px solid #918e8c; + box-shadow: 0 0 4px #918e8c; + position: absolute; + z-index: 1000; + max-width: none; + min-width: 100%; + width: auto; +} + +.cbi-dropdown > ul > li[display], +.cbi-dropdown[open] > ul.preview, +.cbi-dropdown[open] > ul.dropdown > li, +.cbi-dropdown[multiple] > ul > li > label, +.cbi-dropdown[multiple][open] > ul.dropdown > li, +.cbi-dropdown[multiple][more] > .more, +.cbi-dropdown[multiple][empty] > .more { + flex-grow: 1; + display: flex; +} + +.cbi-dropdown[empty] > ul > li, +.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder], +.cbi-dropdown[multiple][open] > ul.dropdown > li > form { + display: block; +} + +.cbi-dropdown[open] > ul.dropdown > li .hide-open { display: none; } +.cbi-dropdown[open] > ul.dropdown > li .hide-close { display: block; display: initial; } + +.cbi-dropdown[open] > ul.dropdown > li { + border-bottom: 1px solid #ccc; +} + +.cbi-dropdown[open] > ul.dropdown > li[selected] { + background: #b0d0f0; +} + +.cbi-dropdown[open] > ul.dropdown > li.focus { + background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%); +} + +.cbi-dropdown[open] > ul.dropdown > li:last-child { + margin-bottom: 0; + border-bottom: none; +} + +.cbi-dropdown[disabled] { + pointer-events: none; + opacity: .6; +} + +input[type="text"] + .cbi-button, +input[type="password"] + .cbi-button, +select + .cbi-button { + border-radius: 2px; + border-color: #ccc; + margin: 2px 0 2px 3px; + padding: 0 12px; + vertical-align: top; + height: 28px; + font-size: 13px; + font-weight: normal; + line-height: 28px; +} + +select + .cbi-button { + #border-left-color: transparent; +} + +.cbi-title-ref { + color: #f39800; +} + +.cbi-title-ref::after { + content: " ➙ "; +} + +.cbi-tooltip-container { + cursor: help; + padding: 5px 3px 5px 3px; +} + +.cbi-tooltip { + position: absolute; + z-index: 1000; + left: -1000px; + opacity: 0; + transition: opacity .25s ease-out; +} + +.cbi-tooltip-container:hover .cbi-tooltip:not(:empty) { + left: auto; + opacity: 1; + transition: opacity .25s ease-in; +} + +.zonebadge .cbi-tooltip { + padding: 1px; + background: inherit; + margin: -1.6em 0 0 -5px; + border-radius: 2px; + pointer-events: none; + box-shadow: 0 0 3px #444; +} + +.zonebadge .cbi-tooltip > * { + margin: 1px; +} + +.zone-forwards { + display: flex; + flex-wrap: wrap; +} + +.zone-forwards > * { + flex: 1 1 40%; + padding: 1px; +} + +.zone-forwards > span { + flex-basis: 10%; + text-align: center; +} + +.zone-forwards .zone-src, +.zone-forwards .zone-dest { + display: flex; + flex-direction: column; +} + +.btn.active, .btn:active { + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled { + cursor: default; + background-image: none; + opacity: 0.65; + box-shadow: none; +} + +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + box-shadow: none; +} + +.btn.large { + font-size: 15px; + line-height: normal; + padding: 9px 14px 9px; + border-radius: 2px; +} + +.btn.small { + padding: 7px 9px 7px; + font-size: 11px; +} + +button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +.close { + float: right; + color: #000; + font-size: 20px; + font-weight: bold; + line-height: 13.5px; + opacity: 0.25; +} + +.close:hover { + color: #000; + text-decoration: none; + opacity: 0.4; +} + +.alert-message { + position: relative; + padding: 30px; + margin-top: 25px; + margin-bottom: 25px; + color: #404040; + background: #f0e68c; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-width: 1px; + border-style: solid; + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); +} + +.alert-message .close { + margin-top: 1px; + *margin-top: 0; +} + +.alert-message a { + font-weight: bold; + color: #404040; +} + +.alert-message.danger p a, +.alert-message.error p a, +.alert-message.success p a, +.alert-message.info p a { + color: #fff; +} + +.alert-message h5 { + line-height: 18px; +} + +.alert-message p { + margin-bottom: 0; +} + +.alert-message div { + margin-top: 15px; + margin-bottom: 10px; + line-height: 28px; +} + +.label { + padding: 3px 3px 3px 3px; + font-size: 8px; + font-weight: normal; + color: #fff !important; + text-transform: uppercase; + white-space: nowrap; + background-color: #bfbfbf; + border-radius: 2px; + text-shadow: none; +} + +a.label:link, +a.label:visited { + color: #fff; +} + +a.label:hover { + text-decoration: none; +} + +.label.important { + background-color: #c43c35; +} + +.label.warning { + background-color: #f89406; +} + +.label.success { + background-color: #46a546; +} + +.label.notice { + background-color: #62cffc; +} + +/* LuCI specific items */ +.hidden { display: none } + +#memtotal > div, +#memfree > div, +#memcache > div, +#membuff > div, +#conns > div { + border: 1px solid #ccc; + border-radius: 2px 2px 2px 2px; + color: #808080; + display: inline-block; + font-size: 12px; + line-height: 18px; +} + +#xhr_poll_status { + cursor: pointer; +} + +form.inline { display: inline; margin-bottom: 0; } + +header .pull-right { padding-top: 21px; } + +#modemenu li:last-child span.divider { display: none } + +#syslog { width: 100%; } + +.cbi-section-table .tr:hover .td, +.cbi-section-table .tr:hover .th, +.cbi-section-table .tr:hover::before { + background-color: #f5f5f5; +} + +.cbi-section-table .tr.cbi-section-table-descr .th { + font-weight: normal; +} + +.cbi-section-table-titles.named::before, +.cbi-section-table-descr.named::before, +.cbi-section-table-row[data-title]::before { + content: attr(data-title) " "; + display: table-cell; + padding: 10px 10px 9px; + line-height: 18px; + font-weight: bold; + vertical-align: middle; +} + +.cbi-section-table-titles.named::before, +.cbi-section-table-descr.named::before, +.cbi-section-table-row[data-title]::before { + border-top: 1px solid #ddd; +} + +.left { text-align: left !important; } +.right { text-align: right !important; } +.center { text-align: center !important; } +.top { vertical-align: top !important; } +.middle { vertical-align: middle !important; } +.bottom { vertical-align: bottom !important; } + +.cbi-value-field { line-height: 1.5em; } + +.cbi-value-field input[type=checkbox], +.cbi-value-field input[type=radio] { + margin-top: 8px; + margin-right: 6px; +} + +table table td, +.cbi-value-field table td { + border: none; +} + +.table.cbi-section-table input[type="password"], +.table.cbi-section-table input[type="text"], +.table.cbi-section-table textarea, +.table.cbi-section-table select { + width: 100%; +} + +.table.cbi-section-table .td.cbi-section-table-cell { + white-space: nowrap; + text-align: right; +} + +.table.cbi-section-table .td.cbi-section-table-cell select { + width: inherit; +} + +.td.cbi-section-actions { + text-align: right; + vertical-align: middle; +} + +.td.cbi-section-actions > * { + display: flex; +} + +.td.cbi-section-actions > * > *, +.td.cbi-section-actions > * > form > * { + flex: 1 1 4em; + margin: 0 1px; +} + +.td.cbi-section-actions > * > form { + display: inline-flex; + margin: 0; +} + +.table.valign-middle .td { + vertical-align: middle; +} + +.cbi-rowstyle-2, +.tr.table-titles, +.tr.cbi-section-table-titles { + background: #f9f9f9; +} + +.cbi-value-description { + background-image: url(/luci-static/resources/cbi/help.gif); + background-position: .25em .2em; + background-repeat: no-repeat; + margin: 10px 0 10px -5px; + padding: 0 0 0 26px; +} + +.cbi-section-error { + border: 1px solid #f00; + border-radius: 2px; + background-color: #fce6e6; + padding: 5px; + margin-bottom: 18px; +} + +.cbi-section-error ul { margin: 0 0 0 20px; } + +.cbi-section-error ul li { + color: #f00; + font-weight: bold; +} + +.ifacebox { + background-color: #fff; + border: 1px solid #ccc; + margin: 6px 4px; + text-align: center; + white-space: nowrap; + background-image: linear-gradient(#fff, #fff 25%, #f9f9f9); + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + display: inline-flex; + flex-direction: column; + line-height: 1.2em; + min-width: 100px; +} + +.ifacebox .ifacebox-head { + border-bottom: 1px solid #ccc; + padding: 10px; + line-height: 1.2em; + background: #eee; +} + +.ifacebox .ifacebox-head.active { + background: #f0e68c; +} + +.ifacebox .ifacebox-body { + padding: .25em; +} + +.ifacebadge { + display: inline-block; + flex-direction: row; + white-space: nowrap; + background-color: #fff; + border: 1px solid #ccc; + padding: 5px 5px 3px 5px; + background-image: linear-gradient(#fff, #fff 25%, #f9f9f9); + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: default; + line-height: 1.2em; +} + +.ifacebadge img { + width: 16px; + height: 16px; + vertical-align: middle; +} + +.ifacebadge-active { + border-color: #000; + font-weight: bold; +} + +.network-status-table { + display: flex; + flex-wrap: wrap; +} + +.network-status-table .ifacebox { + margin: 10px 10px 15px 2px; + flex-grow: 1; +} + +.network-status-table .ifacebox-body { + display: flex; + flex-direction: column; + height: 100%; + text-align: left; + padding: 8px; +} + +.network-status-table .ifacebox-body > * { + margin: .25em; +} + +.network-status-table .ifacebox-body > span { + flex: 10 10 auto; + height: 100%; +} + +.network-status-table .ifacebox-body > div { + display: flex; + flex-wrap: wrap; + margin: -.125em; +} + +#dsl_status_table .ifacebox-body > span > strong { + display: inline-block; + min-width: 35%; +} + +.ifacebadge.large, +.network-status-table .ifacebox-body .ifacebadge { + display: inline-flex; + flex: 1; + padding: 10px 4px 10px 4px; + min-width: 220px; + margin: 10px 6px 4px 4px; +} + +.ifacebadge > *, +.ifacebadge.large > * { + margin: 0 .125em; +} + +.zonebadge { + padding: 2px; + border-radius: 2px; + display: inline-block; + white-space: nowrap; + color: #666; +} + +.zonebadge > em, +.zonebadge > strong { + margin: 0 2px; + display: inline-block; +} + +.zonebadge input { + width: 6em; +} + +.zonebadge > .ifacebadge { + margin-left: 2px; +} + +.zonebadge-empty { + border: 1px dashed #aaa; + color: #aaa; + font-style: italic; + font-size: smaller; +} + +div.cbi-value var, +.td.cbi-value-field var { + font-style: italic; + color: #215e21; +} + +.uci-change-list { + line-height: 170%; + white-space: pre; +} + +.uci-change-list del, +.uci-change-list ins, +.uci-change-list var, +.uci-change-legend-label del, +.uci-change-legend-label ins, +.uci-change-legend-label var { + text-decoration: none; + font-family: monospace; + font-style: normal; + border: 1px solid #ccc; + background: #eee; + padding: 2px; + display: block; + line-height: 15px; + margin-bottom: 1px; +} + +.uci-change-list ins, +.uci-change-legend-label ins { + border-color: #0f0; + background: #cfc; +} + +.uci-change-list del, +.uci-change-legend-label del { + border-color: #f00; + background: #fcc; +} + +.uci-change-list var, +.uci-change-legend-label var { + border-color: #ccc; + background: #eee; +} + +.uci-change-list var ins, +.uci-change-list var del { + display: inline-block; + border: none; + width: 100%; + padding: 0; +} + +.uci-change-legend { + padding: 5px; +} + +.uci-change-legend-label { + width: 150px; + float: left; +} + +.uci-change-legend-label > ins, +.uci-change-legend-label > del, +.uci-change-legend-label > var { + float: left; + margin-right: 4px; + width: 10px; + height: 10px; + display: block; + position: relative; +} + +.uci-change-legend-label var ins, +.uci-change-legend-label var del { + border: none; + position: absolute; + top: 2px; + left: 2px; + right: 2px; + bottom: 2px; +} + +html body.apply-overlay-active { + height: calc(100vh - 63px); +} + +#applyreboot-section { + line-height: 300%; +} + +.login{ + text-align: center; + background-color: #fff; + border-radius: 20px; + width: 300px; + height: 350px; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%,-50%); +} diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.png new file mode 100755 index 000000000..7ee777910 Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.png differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/html5.js b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/html5.js new file mode 100755 index 000000000..1ec510f2a --- /dev/null +++ b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/html5.js @@ -0,0 +1,3 @@ +// HTML5 Shiv v3 | @jon_neal @afarkas @rem | MIT/GPL2 Licensed +// Uncompressed source: https://github.com/aFarkas/html5shiv +(function(a,b){function f(a){var c,d,e,f;b.documentMode>7?(c=b.createElement("font"),c.setAttribute("data-html5shiv",a.nodeName.toLowerCase())):c=b.createElement("shiv:"+a.nodeName);while(a.firstChild)c.appendChild(a.childNodes[0]);for(d=a.attributes,e=d.length,f=0;f7?e[g][e[g].length-1]=e[g][e[g].length-1].replace(d,'$1font[data-html5shiv="$2"]'):e[g][e[g].length-1]=e[g][e[g].length-1].replace(d,"$1shiv\\:$2"),e[g]=e[g].join("}");return e.join("{")}var c=function(a){return a.innerHTML="",a.childNodes.length===1}(b.createElement("a")),d=function(a,b,c){return b.appendChild(a),(c=(c?c(a):a.currentStyle).display)&&b.removeChild(a)&&c==="block"}(b.createElement("nav"),b.documentElement,a.getComputedStyle),e={elements:"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "),shivDocument:function(a){a=a||b;if(a.documentShived)return;a.documentShived=!0;var f=a.createElement,g=a.createDocumentFragment,h=a.getElementsByTagName("head")[0],i=function(a){f(a)};c||(e.elements.join(" ").replace(/\w+/g,i),a.createElement=function(a){var b=f(a);return b.canHaveChildren&&e.shivDocument(b.document),b},a.createDocumentFragment=function(){return e.shivDocument(g())});if(!d&&h){var j=f("div");j.innerHTML=["x"].join(""),h.insertBefore(j.lastChild,h.firstChild)}return a}};e.shivDocument(b),a.html5=e;if(c||!a.attachEvent)return;a.attachEvent("onbeforeprint",function(){if(a.html5.supportsXElement||!b.namespaces)return;b.namespaces.shiv||b.namespaces.add("shiv");var c=-1,d=new RegExp("^("+a.html5.elements.join("|")+")$","i"),e=b.getElementsByTagName("*"),g=e.length,j,k=i(h(function(a,b){var c=[],d=a.length;while(d)c.unshift(a[--d]);d=b.length;while(d)c.unshift(b[--d]);c.sort(function(a,b){return a.sourceIndex-b.sourceIndex}),d=c.length;while(d)c[--d]=c[d].styleSheet;return c}(b.getElementsByTagName("style"),b.getElementsByTagName("link"))));while(++c ul, .nav { + display: block; + float: left; + margin: 7px 8px 0 8px; + position: relative; + left: 0; +} + +header div > ul a, .nav a { + display: block; + float: left; + padding: 12px 6px 12px 6px; + line-height: 14px; + letter-spacing: 0.2px; +} + +.menu-dropdown, .dropdown-menu { + top: 38px; + min-width: 180px; + max-width: 260px; +} + +@media screen and (max-device-width: 660px) { + #maincontent.container { + width: 98%; + margin: 30px 0 0 6px; + } +} + +@media screen and (max-device-width: 360px) { + #maincontent.container { + width: 96%; + margin: 30px 0 0 6px; + } +} + +@media screen and (max-device-width: 200px) { + #maincontent.container { + width: 94%; + margin: 40px 0 0 2px; + } +} diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/cascade.css b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/cascade.css new file mode 100755 index 000000000..740adc320 --- /dev/null +++ b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/cascade.css @@ -0,0 +1,2027 @@ +/*! + * LuCI Bootstrap Theme + * Copyright 2012 Nut & Bolt + * By David Menting + * Based on Bootstrap v1.4.0 + * + * Copyright 2011 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +/* Reset.less + * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc). + * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ +html { + margin: 0; + padding: 0; +} + +body { + margin: 0; + padding: 5px; +} + +h1, h2, h3, h4, h5, h6, p, pre, a, abbr, acronym, code, del, em, img, ins, q, s, +small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, +form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td, +.table, .tbody, .tfoot, .thead, .tr, .th, .td { + margin: 0; + padding: 0; + border: 0; + font-weight: normal; + font-style: normal; + font-size: 100%; + line-height: 1; + font-family: inherit; +} + +abbr[title], acronym[title] { + border-bottom: 1px dotted; + font-weight: inherit; + cursor: help; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +ol, ul { + list-style: none; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +html { + overflow-y: scroll; + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted; +} + +a:hover, a:active { + outline: 0; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + border: 0; + -ms-interpolation-mode: bicubic; +} + +button, +input, +select, +option, +textarea { + font-size: 100%; + margin: 0; + box-sizing: border-box; + vertical-align: baseline; + *vertical-align: middle; +} + +button, input { + line-height: normal; + *overflow: visible; +} + +button::-moz-focus-inner, input::-moz-focus-inner { + border: 0; + padding: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +button[disabled], +input[type="button"][disabled], +input[type="reset"][disabled], +input[type="submit"][disabled] { + opacity: 0.7; +} + +input[type="search"] { + -webkit-appearance: textfield; + box-sizing: content-box; +} + +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +/* + * Scaffolding + * Basic and global styles for generating a grid system, structural layout, and page templates + * ------------------------------------------------------------------------------------------- */ +body { + background-color: #fff; + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 12px; + font-weight: normal; + line-height: 18px; + color: #404040; + padding-top: 75px; +} + +.container { + width: 100%; + max-width: 940px; + margin-left: auto; + margin-right: auto; + zoom: 1; +} + +.container:before, .container:after { + display: table; + content: ""; + zoom: 1; +} + +.container:after { + clear: both; +} + +a { + color: #215e21; + text-decoration: none; + line-height: inherit; + font-weight: inherit; +} + +a:hover { + color: #000000; + text-decoration: none; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +/* Typography.less + * Headings, body text, lists, code, and more for a versatile and durable typography system + * ---------------------------------------------------------------------------------------- */ +p, +.cbi-map-descr, +.cbi-section-descr, +.table .tr.cbi-section-table-descr .th { + font-size: 12px; + font-weight: normal; + line-height: 18px; + margin-bottom: 9px; +} + +p small { + font-size: 11px; + color: #bfbfbf; +} + +h1, +h2, +h3, legend, +h4, +h5, +h6 { + font-weight: normal; + color: #404040; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + color: #bfbfbf; +} + +h1 { + margin-bottom: 18px; + font-size: 30px; + line-height: 36px; +} + +h1 small { + font-size: 18px; +} + +h2 { + font-size: 24px; + line-height: 58px; + text-transform: uppercase; + font-weight: normal; +} + +h2 small { + font-size: 14px; +} + +h3, legend, +h4, +h5, +h6 { + line-height: 48px; +} + +h3, legend { + font-size: 18px; +} + +h3 small { + font-size: 14px; +} + +h4 { + font-size: 16px; +} + +h4 small { + font-size: 12px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 13px; + color: #bfbfbf; + text-transform: uppercase; +} + +ul, ol { + margin: 0 0 18px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li { + line-height: 18px; + color: #808080; +} + +ul.unstyled { + list-style: none; + margin-left: 0; +} + +dl { + margin-bottom: 18px; +} + +dl dt, dl dd { + line-height: 18px; +} + +dl dt { + font-weight: bold; +} + +dl dd { + margin-left: 9px; +} + +hr { + margin: 20px 0 19px; + border: 0; + border-bottom: 1px solid #eee; +} + +strong { + font-style: inherit; + font-weight: bold; +} + +em { + font-style: italic; + font-weight: inherit; + line-height: inherit; +} + +small { font-size: 0.9em } + +address { + display: block; + line-height: 18px; + margin-bottom: 18px; +} + +code, pre { + padding: 0 3px 2px; + font-family: Monaco, Andale Mono, Courier New, monospace; + font-size: 12px; + border-radius: 2px; +} + +code { + background-color: #fee9cc; + color: rgba(0, 0, 0, 0.75); + padding: 1px 3px; +} + +pre { + background-color: #f5f5f5; + display: block; + padding: 8.5px; + margin: 0 0 18px; + line-height: 18px; + font-size: 12px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 2px; + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +/* Forms.less + * Base styles for various input types, form layouts, and states + * ------------------------------------------------------------- */ +form { + margin-bottom: 18px; +} + +fieldset { + margin-bottom: 9px; + padding-top: 9px; +} + +fieldset legend { + display: block; + font-size: 19.5px; + line-height: 1; + color: #404040; + padding-top: 20px; + *padding: 0 0 5px 0px; + /* IE6-7 */ + + *line-height: 1.5; + /* IE6-7 */ + +} +form .cbi-tab-descr { + line-height: 18px; + margin-bottom: 18px; +} + +form .clearfix, +form .cbi-value { + margin-bottom: 15px; + margin-top: 15px; + zoom: 1; +} + +form .clearfix:before, form .clearfix:after, +form .cbi-value:before, form .cbi-value:after { + display: table; + content: ""; + zoom: 1; +} + +form .clearfix:after, +form .cbi-value:after { + clear: both; +} + +label, +input, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 12px; + font-weight: normal; + line-height: normal; +} + +form .input, +form .cbi-value-field { + margin-left: 120px; +} + +form .cbi-value label.cbi-value-title { + padding-top: 6px; + font-size: 12px; + line-height: 18px; + float: left; + width: 111px; + text-align: left; + color: #404040; +} + +input[type=checkbox], input[type=radio] { + cursor: pointer; +} + +input, +textarea, +select, +.cbi-dropdown, +.uneditable-input { + display: inline-block; + width: 200px; + height: 30px; + padding: 4px; + font-size: 12px; + line-height: 18px; + color: #808080; + border: 1px solid #ccc; + border-radius: 2px; + box-sizing: border-box; + margin: 2px 0; +} + +.cbi-dropdown { + min-width: 210px; + max-width: 400px; + width: auto; +} + +select { + padding: initial; + background: #fff; + box-shadow: inset 0 -1px 3px rgba(0, 0, 0, 0.1); +} + +input[type=checkbox], input[type=radio] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE6-7 */ + + line-height: normal; + border: none; +} + +input[type=file] { + background-color: #fff; + padding: initial; + border: initial; + line-height: initial; + box-shadow: none; + width: auto !important; +} + +input[type=button], input[type=reset], input[type=submit] { + width: auto; + height: auto; +} + +select, input[type=file] { + *height: auto; + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ +} + +select[multiple] { + height: inherit; + background-color: #fff; +} + +textarea { + height: auto; +} + +.td > input[type=text], +.td > input[type=password], +.td > select, +.td > .cbi-dropdown { + width: 100%; +} + +.uneditable-input { + background-color: #fff; + display: block; + border-color: #eee; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} + +::-moz-placeholder { + color: #bfbfbf; +} + +::-webkit-input-placeholder { + color: #bfbfbf; +} + +.btn, .cbi-button, input, textarea { + transition: border linear 0.2s, box-shadow linear 0.2s; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); + padding: 12px 6px; +} + +.btn:hover, .cbi-button:hover, +input:focus, textarea:focus { + outline: 0; + border-color: rgba(82, 168, 236, 0.8) !important; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); + text-decoration: none; +} + +input[type=file]:focus, input[type=checkbox]:focus, select:focus { + box-shadow: none; + outline: 1px dotted #666; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #194119; + border-color: #ccc; + padding: 5px; + pointer-events: none; + cursor: default; +} + +select[readonly], +textarea[readonly] { + pointer-events: auto; + cursor: auto; +} + +.cbi-optionals, +.cbi-section-create { + padding: 0 0 10px 10px; +} + +.cbi-section-create { + margin: 10px 0 0 -10px; + display: inline-flex; + align-items: center; +} + +.cbi-section-create > * { + margin: 3px; + flex: 1 1 auto; +} + +.cbi-section-create > * > input { + width: 100%; +} + +.actions, +.cbi-page-actions { + background: #f5f5f5; + margin-bottom: 20px; + margin-top: 40px; + padding: 15px 20px 15px 20px; + border-radius: 0 0 2px 2px; + text-align: right; +} + +.actions .secondary-action, +.cbi-page-actions .secondary-action{ + float: right; +} + +.actions .secondary-action a, +.cbi-page-actions .secondary-action a { + line-height: 30px; +} + +.actions .secondary-action a:hover, +.cbi-page-actions .secondary-action a:hover { + text-decoration: none; +} + +.cbi-page-actions > form { + display: inline; + margin: 0; +} + +.help-inline, .help-block { + font-size: 12px; + line-height: 18px; + color: #bfbfbf; +} + +.help-inline { + padding-left: 5px; + *position: relative; + /* IE6-7 */ + + *top: -5px; + /* IE6-7 */ + +} + +.help-block { + display: block; + max-width: 600px; +} + +/* + * Tables.less + * Tables for, you guessed it, tabular data + * ---------------------------------------- */ +.tr { display: table-row; } +.table[width="33%"], .th[width="33%"], .td[width="33%"] { width: 33%; } +.table[width="100%"], .th[width="100%"], .td[width="100%"] { width: 100%; } + +.table { + display: table; + width: 100%; + margin: 12px 0 24px 0; + padding: 0; + font-size: 12px; + border-collapse: collapse; + position: relative; +} + +.table .th, .table .td { + display: table-cell; + vertical-align: middle; /* Fixme */ + padding: 6px 6px 6px 2px; + line-height: 18px; + text-align: left; +} + +.table .tr:first-child .th { + padding-top: 9px; + font-weight: normal; + vertical-align: top; +} + +.table .td, .table .th { + border-top: 1px solid #e7e7e7; +} + +.tr.placeholder { + height: calc(3em + 20px); +} + +.tr.placeholder > .td { + position: absolute; + left: 0; + right: 0; + bottom: 0; + text-align: center; + line-height: 3em; +} + +/* Patterns.less + * Repeatable UI elements outside the base styles provided from the scaffolding + * ---------------------------------------------------------------------------- */ +header { + height: 40px; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 10000; + overflow: visible; + color: #BFBFBF; +} + +header a { + color: #c4c4c4; +} + +header h3 a:hover, header .brand:hover, header ul .active > a { + background-color: #333; + background-color: rgba(0, 0, 0, 0.33); + color: #fff; + text-decoration: none; +} + +header h3 { + position: relative; +} + +header h3 a, header .brand { + float: left; + display: block; + padding: 16px 20px 16px; + margin-left: -20px; + color: #fff; + font-size: 24px; + font-weight: 333; + line-height: 1; +} + +header p { + margin: 0; + line-height: 40px; +} + +header .fill { + background-color: #215e21; + background-repeat: repeat-x; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.33), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + padding: 0 5px; +} + +header div > ul, .nav { + display: block; + float: left; + margin: 0 10px 0 20px; + position: relative; + left: 0; +} + +header div > ul > li, .nav > li { + display: block; + float: left; +} + +header div > ul a, .nav a { + display: block; + float: none; + padding: 22px 12px 14px 12px; + line-height: 19px; + letter-spacing: 0.4px; + text-decoration: none; + text-transform: uppercase; +} + +header div > ul a:hover, .nav a:hover { + color: #fff; + text-decoration: none; +} + +header div > ul .active > a, .nav .active > a { + background-color: #222; + background-color: rgba(0, 0, 0, 0.33); +} + +header div > ul.secondary-nav, .nav.secondary-nav { + float: right; + margin-left: 10px; + margin-right: 0; +} + +header div > ul.secondary-nav .menu-dropdown, +.nav.secondary-nav .menu-dropdown, +header div > ul.secondary-nav .dropdown-menu, +.nav.secondary-nav .dropdown-menu { + right: 0; + border: 0; +} + +header div > ul a.menu:hover, +.nav a.menu:hover, +header div > ul li.open .menu, +.nav li.open .menu, +header div > ul .dropdown-toggle:hover, +.nav .dropdown-toggle:hover, +header div > ul .dropdown.open .dropdown-toggle, +.nav .dropdown.open .dropdown-toggle { + background: #444; + background: rgba(0, 0, 0, 0.3); +} + +header div > ul .menu-dropdown, +.nav .menu-dropdown, +header div > ul .dropdown-menu, +.nav .dropdown-menu { + background-color: #003300; +} + +header div > ul .menu-dropdown a.menu, +.nav .menu-dropdown a.menu, +header div > ul .dropdown-menu a.menu, +.nav .dropdown-menu a.menu, +header div > ul .menu-dropdown .dropdown-toggle, +.nav .menu-dropdown .dropdown-toggle, +header div > ul .dropdown-menu .dropdown-toggle, +.nav .dropdown-menu .dropdown-toggle { + color: #fff; +} + +header div > ul .menu-dropdown a.menu.open, +.nav .menu-dropdown a.menu.open, +header div > ul .dropdown-menu a.menu.open, +.nav .dropdown-menu a.menu.open, +header div > ul .menu-dropdown .dropdown-toggle.open, +.nav .menu-dropdown .dropdown-toggle.open, +header div > ul .dropdown-menu .dropdown-toggle.open, +.nav .dropdown-menu .dropdown-toggle.open { + background: #444; + background: rgba(255, 255, 255, 0.05); +} + +header div > ul .menu-dropdown li a, +.nav .menu-dropdown li a, +header div > ul .dropdown-menu li a, +.nav .dropdown-menu li a { + color: #bfbfbf; +} + +header div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +header div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #215e21; + background-repeat: repeat-x; + color: #fff; +} + +header div > ul .menu-dropdown .active a, +.nav .menu-dropdown .active a, +header div > ul .dropdown-menu .active a, +.nav .dropdown-menu .active a { + color: #fff; +} + +header div > ul .menu-dropdown .divider, +.nav .menu-dropdown .divider, +header div > ul .dropdown-menu .divider, +.nav .dropdown-menu .divider { + background-color: #222; + border-color: #444; +} + +header ul .menu-dropdown li a, header ul .dropdown-menu li a { + padding: 6px 12px; +} + +li.menu, .dropdown { + position: relative; +} + +.menu-dropdown, .dropdown-menu { + background-color: #fff; + float: left; + position: absolute; + top: 55px; + left: -9999px; + z-index: 900; + min-width: 200px; + max-width: 300px; + _width: 160px; + margin-left: 0; + margin-right: 0; + padding: 6px 0; + zoom: 1; + border-radius: 0 0 2px 2px; + background-clip: padding-box; +} + +.menu-dropdown li, .dropdown-menu li { + float: none; + display: block; + background-color: transparent; +} + +.menu-dropdown .divider, .dropdown-menu .divider { + height: 1px; + margin: 5px 0; + overflow: hidden; + background-color: #eee; + border-bottom: 1px solid #fff; +} + +header .dropdown-menu a, .dropdown-menu a { + display: block; + padding: 4px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + text-transform: capitalize; + letter-spacing: 0.2px; + color: #808080; + zoom: 1.1; +} + +header .dropdown-menu a:hover, +.dropdown-menu a:hover, +header .dropdown-menu a.hover, +.dropdown-menu a.hover { + background-color: #ddd; + background-repeat: repeat-x; + color: #404040; + text-decoration: none; + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025); +} + +.open .menu, +.dropdown.open .menu, +.open .dropdown-toggle, +.dropdown.open .dropdown-toggle { + color: #fff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} + +.open .menu-dropdown, +.dropdown.open .menu-dropdown, +.open .dropdown-menu, +.dropdown.open .dropdown-menu { + left: 0; +} + +.dropdown:hover ul.dropdown-menu { + left: 0; +} + +.dropdown-menu .dropdown-menu { + position: absolute; + left: 159px; +} + +.dropdown-menu li { + position: relative; +} + +.tabs, .cbi-tabmenu { + margin: 0 0 18px; + padding: 0; + list-style: none; + zoom: 1; +} + +.tabs:before, +.cbi-tabmenu:before, +.tabs:after, +.cbi-tabmenu:after { + display: table; + content: ""; + zoom: 1; +} + +.tabs:after, .cbi-tabmenu:after { + clear: both; +} + +.tabs > li, .cbi-tabmenu > li { + float: left; +} + +.tabs > li > a, .cbi-tabmenu > li > a { + display: block; +} + +.tabs, +.cbi-tabmenu { + border-color: #ddd; + border-style: solid; + border-width: 0 0 1px; +} + +.tabs > li, +.cbi-tabmenu > li { + position: relative; + margin-bottom: -1px; +} + +.cbi-tabmenu.map { + margin: 0; +} + +.cbi-tabmenu.map > li { + font-size: 16.5px; + font-weight: bold; +} + +.cbi-tabcontainer > fieldset.cbi-section[id] > legend { + display: none; +} + +.tabs > li > a, +.cbi-tabmenu > li > a { + padding: 0 15px; + margin-right: 2px; + line-height: 34px; + border: 1px solid transparent; + border-radius: 2px 2px 0 0; +} + +.tabs > li > a:hover, +.cbi-tabmenu > li > a:hover { + text-decoration: none; + background-color: #eee; + border-color: #eee #eee #ddd; +} + +.tabs .active > a, .tabs .active > a:hover, +.cbi-tabmenu .active > a, .cbi-tabmenu .active > a:hover, +.cbi-tab > a:link, .cbi-tab > a:hover { + color: #000000; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} + +.tabs .menu-dropdown, .tabs .dropdown-menu, +.cbi-tabmenu .menu-dropdown, .cbi-tabmenu .dropdown-menu { + top: 35px; + border-width: 1px; + border-radius: 0 2px 2px 2px; +} + +.tabs a.menu:after, .tabs .dropdown-toggle:after, +.cbi-tabmenu a.menu:after, .cbi-tabmenu .dropdown-toggle:after { + border-top-color: #999; + margin-top: 15px; + margin-left: 5px; +} + +.tabs li.open.menu .menu, .tabs .open.dropdown .dropdown-toggle, +.cbi-tabmenu li.open.menu .menu, .cbi-tabmenu .open.dropdown .dropdown-toggle { + border-color: #999; +} + +.tabs li.open a.menu:after, .tabs .dropdown.open .dropdown-toggle:after, +.cbi-tabmenu li.open a.menu:after, .cbi-tabmenu .dropdown.open .dropdown-toggle:after { + border-top-color: #555; +} + +.tab-content > .tab-pane, +.tab-content > div { + display: none; +} + +.tab-content > .active { + display: block; +} + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #f5f5f5; + background-repeat: repeat-x; + border: 1px solid #ddd; + border-radius: 2px; + box-shadow: inset 0 1px 0 #fff; +} + +.breadcrumb li { + display: inline; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #bfbfbf; +} + +.breadcrumb .active a { + color: #404040; +} + +footer { + margin-top: 30px; + padding-top: 20px; + padding-bottom: 20px; + border-top: 1px solid #404040; +} + +.btn.danger, +.alert-message.danger, +.btn.danger:hover, +.alert-message.danger:hover, +.btn.error, +.alert-message.error, +.btn.error:hover, +.alert-message.error:hover, +.btn.success, +.alert-message.success, +.btn.success:hover, +.alert-message.success:hover, +.btn.info, +.alert-message.info, +.btn.info:hover, +.alert-message.info:hover { + color: #fff; +} + +.btn .close, .alert-message .close { + font-family: Arial, sans-serif; + line-height: 18px; +} + +.btn.danger, +.alert-message.danger, +.btn.error, +.alert-message.error { + background: linear-gradient(to bottom, #ee5f5b, #c43c35) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn.success, .alert-message.success { + background: linear-gradient(to bottom, #62c462, #57a957) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn.info, .alert-message.info { + background: linear-gradient(to bottom, #5bc0de, #339bb9) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.alert-message.notice { + background: linear-gradient(to bottom, #efefef, #fefefe) repeat-x; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} + +.btn, +.cbi-button { + cursor: pointer; + display: inline-block; + background: linear-gradient(#fff, #fff 25%, #e6e6e6) no-repeat; + padding: 5px 14px 6px; + color: #333; + font-size: 12px; + line-height: normal; + border: 1px solid #ccc; + border-bottom-color: #bbb; + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:focus, +.cbi-button:focus { + outline: 1px dotted #666; +} + +.cbi-input-invalid, +.cbi-value-error input { + color: #f00; + border-color: #f00; +} + +.cbi-button-positive, +.cbi-button-fieldadd, +.cbi-button-add, +.cbi-button-save { + border-color: #4a4; + color: #4a4; +} + +.cbi-button-neutral, +.cbi-button-download, +.cbi-button-find, +.cbi-button-link, +.cbi-button-up, +.cbi-button-down { + color: #444; +} + +.btn.primary, +.cbi-button-action, +.cbi-button-apply, +.cbi-button-reload, +.cbi-button-edit { + border-color: #4aa44b; + color: #4aa44b; +} + +.cbi-button-negative, +.cbi-section-remove .cbi-button, +.cbi-button-reset, +.cbi-button-remove { + border-color: #c44; + color: #c44; +} + +.cbi-page-actions::after { + display: table; + content: ""; + clear: both; +} + +.cbi-page-actions > :not([method="post"]):not(.cbi-button-apply):not(.cbi-button-save):not(.cbi-button-reset) { + float: left; + margin-right: .4em; +} + +.btn.primary, +.cbi-button-action.important, +.cbi-page-actions .cbi-button-apply, +.cbi-section-actions .cbi-button-edit { + color: #fff; + background: #4aa44b; +} + +.cbi-button-positive.important, +.cbi-page-actions .cbi-button-save { + color: #fff; + background: linear-gradient(to bottom, #4a4, #484) no-repeat; +} + +.cbi-button-negative.important { + color: #fff; + background: linear-gradient(to bottom, #c44, #c00) no-repeat; +} + +.cbi-page-actions .cbi-button-apply + .cbi-button-save { + background: linear-gradient(#fff, #fff 25%, #e6e6e6); + color: #4a4; +} + +.cbi-dropdown { + border: 1px solid #ccc; + border-radius: 2px; + display: inline-flex; + padding: 0; + cursor: pointer; + height: auto; + background: linear-gradient(#fff 0%, #e9e8e6 100%); + position: relative; + color: #404040; +} + +.cbi-dropdown:focus { + outline: 2px solid #4b6e9b; +} + +.cbi-dropdown > ul { + margin: 0 !important; + padding: 0; + list-style: none; + overflow-x: hidden; + overflow-y: auto; + display: flex; + width: 100%; +} + +.cbi-dropdown > ul.preview { + display: none; +} + +.cbi-dropdown > .open, +.cbi-dropdown > .more { + flex-grow: 0; + flex-shrink: 0; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + line-height: 2em; + padding: 0 .25em; +} + +.cbi-dropdown > .more, +.cbi-dropdown > ul > li[placeholder] { + color: #777; + font-weight: bold; + display: none; +} + +.cbi-dropdown > ul > li { + display: none; + padding: .25em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex-shrink: 1; + flex-grow: 1; + align-items: center; + align-self: center; + color: #404040; + min-height: 20px; +} + +.cbi-dropdown > ul > li .hide-open { display: block; display: initial; } +.cbi-dropdown > ul > li .hide-close { display: none; } + +.cbi-dropdown > ul > li[display]:not([display="0"]) { + border-left: 1px solid #ccc; +} + +.cbi-dropdown[empty] > ul { + max-width: 1px; +} + +.cbi-dropdown > ul > li > form { + display: none; + margin: 0; + padding: 0; + pointer-events: none; +} + +.cbi-dropdown > ul > li img { + vertical-align: middle; + margin-right: .25em; +} + +.cbi-dropdown > ul > li > form > input[type="checkbox"] { + margin: 0; +} + +.cbi-dropdown > ul > li input[type="text"] { + height: 20px; +} + +.cbi-dropdown[open] { + position: relative; +} + +.cbi-dropdown[open] > ul.dropdown { + display: block; + background: #f6f6f5; + border: 1px solid #918e8c; + box-shadow: 0 0 4px #918e8c; + position: absolute; + z-index: 1000; + max-width: none; + min-width: 100%; + width: auto; +} + +.cbi-dropdown > ul > li[display], +.cbi-dropdown[open] > ul.preview, +.cbi-dropdown[open] > ul.dropdown > li, +.cbi-dropdown[multiple] > ul > li > label, +.cbi-dropdown[multiple][open] > ul.dropdown > li, +.cbi-dropdown[multiple][more] > .more, +.cbi-dropdown[multiple][empty] > .more { + flex-grow: 1; + display: flex; +} + +.cbi-dropdown[empty] > ul > li, +.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder], +.cbi-dropdown[multiple][open] > ul.dropdown > li > form { + display: block; +} + +.cbi-dropdown[open] > ul.dropdown > li .hide-open { display: none; } +.cbi-dropdown[open] > ul.dropdown > li .hide-close { display: block; display: initial; } + +.cbi-dropdown[open] > ul.dropdown > li { + border-bottom: 1px solid #ccc; +} + +.cbi-dropdown[open] > ul.dropdown > li[selected] { + background: #b0d0f0; +} + +.cbi-dropdown[open] > ul.dropdown > li.focus { + background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%); +} + +.cbi-dropdown[open] > ul.dropdown > li:last-child { + margin-bottom: 0; + border-bottom: none; +} + +.cbi-dropdown[disabled] { + pointer-events: none; + opacity: .6; +} + +input[type="text"] + .cbi-button, +input[type="password"] + .cbi-button, +select + .cbi-button { + border-radius: 2px; + border-color: #ccc; + margin: 2px 0 2px 3px; + padding: 0 12px; + vertical-align: top; + height: 28px; + font-size: 13px; + font-weight: normal; + line-height: 28px; +} + +select + .cbi-button { + #border-left-color: transparent; +} + +.cbi-title-ref { + color: #f39800; +} + +.cbi-title-ref::after { + content: " ➙ "; +} + +.cbi-tooltip-container { + cursor: help; + padding: 5px 3px 5px 3px; +} + +.cbi-tooltip { + position: absolute; + z-index: 1000; + left: -1000px; + opacity: 0; + transition: opacity .25s ease-out; +} + +.cbi-tooltip-container:hover .cbi-tooltip:not(:empty) { + left: auto; + opacity: 1; + transition: opacity .25s ease-in; +} + +.zonebadge .cbi-tooltip { + padding: 1px; + background: inherit; + margin: -1.6em 0 0 -5px; + border-radius: 2px; + pointer-events: none; + box-shadow: 0 0 3px #444; +} + +.zonebadge .cbi-tooltip > * { + margin: 1px; +} + +.zone-forwards { + display: flex; + flex-wrap: wrap; +} + +.zone-forwards > * { + flex: 1 1 40%; + padding: 1px; +} + +.zone-forwards > span { + flex-basis: 10%; + text-align: center; +} + +.zone-forwards .zone-src, +.zone-forwards .zone-dest { + display: flex; + flex-direction: column; +} + +.btn.active, .btn:active { + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled { + cursor: default; + background-image: none; + opacity: 0.65; + box-shadow: none; +} + +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + box-shadow: none; +} + +.btn.large { + font-size: 15px; + line-height: normal; + padding: 9px 14px 9px; + border-radius: 2px; +} + +.btn.small { + padding: 7px 9px 7px; + font-size: 11px; +} + +button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +.close { + float: right; + color: #000; + font-size: 20px; + font-weight: bold; + line-height: 13.5px; + opacity: 0.25; +} + +.close:hover { + color: #000; + text-decoration: none; + opacity: 0.4; +} + +.alert-message { + position: relative; + padding: 30px; + margin-top: 25px; + margin-bottom: 25px; + color: #404040; + background: #f0e68c; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-width: 1px; + border-style: solid; + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25); +} + +.alert-message .close { + margin-top: 1px; + *margin-top: 0; +} + +.alert-message a { + font-weight: bold; + color: #404040; +} + +.alert-message.danger p a, +.alert-message.error p a, +.alert-message.success p a, +.alert-message.info p a { + color: #fff; +} + +.alert-message h5 { + line-height: 18px; +} + +.alert-message p { + margin-bottom: 0; +} + +.alert-message div { + margin-top: 15px; + margin-bottom: 10px; + line-height: 28px; +} + +.label { + padding: 3px 3px 3px 3px; + font-size: 8px; + font-weight: normal; + color: #fff !important; + text-transform: uppercase; + white-space: nowrap; + background-color: #bfbfbf; + border-radius: 2px; + text-shadow: none; +} + +a.label:link, +a.label:visited { + color: #fff; +} + +a.label:hover { + text-decoration: none; +} + +.label.important { + background-color: #c43c35; +} + +.label.warning { + background-color: #f89406; +} + +.label.success { + background-color: #46a546; +} + +.label.notice { + background-color: #62cffc; +} + +/* LuCI specific items */ +.hidden { display: none } + +#memtotal > div, +#memfree > div, +#memcache > div, +#membuff > div, +#conns > div { + border: 1px solid #ccc; + border-radius: 2px 2px 2px 2px; + color: #808080; + display: inline-block; + font-size: 12px; + line-height: 18px; +} + +#xhr_poll_status { + cursor: pointer; +} + +form.inline { display: inline; margin-bottom: 0; } + +header .pull-right { padding-top: 21px; } + +#modemenu li:last-child span.divider { display: none } + +#syslog { width: 100%; } + +.cbi-section-table .tr:hover .td, +.cbi-section-table .tr:hover .th, +.cbi-section-table .tr:hover::before { + background-color: #f5f5f5; +} + +.cbi-section-table .tr.cbi-section-table-descr .th { + font-weight: normal; +} + +.cbi-section-table-titles.named::before, +.cbi-section-table-descr.named::before, +.cbi-section-table-row[data-title]::before { + content: attr(data-title) " "; + display: table-cell; + padding: 10px 10px 9px; + line-height: 18px; + font-weight: bold; + vertical-align: middle; +} + +.cbi-section-table-titles.named::before, +.cbi-section-table-descr.named::before, +.cbi-section-table-row[data-title]::before { + border-top: 1px solid #ddd; +} + +.left { text-align: left !important; } +.right { text-align: right !important; } +.center { text-align: center !important; } +.top { vertical-align: top !important; } +.middle { vertical-align: middle !important; } +.bottom { vertical-align: bottom !important; } + +.cbi-value-field { line-height: 1.5em; } + +.cbi-value-field input[type=checkbox], +.cbi-value-field input[type=radio] { + margin-top: 8px; + margin-right: 6px; +} + +table table td, +.cbi-value-field table td { + border: none; +} + +.table.cbi-section-table input[type="password"], +.table.cbi-section-table input[type="text"], +.table.cbi-section-table textarea, +.table.cbi-section-table select { + width: 100%; +} + +.table.cbi-section-table .td.cbi-section-table-cell { + white-space: nowrap; + text-align: right; +} + +.table.cbi-section-table .td.cbi-section-table-cell select { + width: inherit; +} + +.td.cbi-section-actions { + text-align: right; + vertical-align: middle; +} + +.td.cbi-section-actions > * { + display: flex; +} + +.td.cbi-section-actions > * > *, +.td.cbi-section-actions > * > form > * { + flex: 1 1 4em; + margin: 0 1px; +} + +.td.cbi-section-actions > * > form { + display: inline-flex; + margin: 0; +} + +.table.valign-middle .td { + vertical-align: middle; +} + +.cbi-rowstyle-2, +.tr.table-titles, +.tr.cbi-section-table-titles { + background: #f9f9f9; +} + +.cbi-value-description { + background-image: url(/luci-static/resources/cbi/help.gif); + background-position: .25em .2em; + background-repeat: no-repeat; + margin: 10px 0 10px -5px; + padding: 0 0 0 26px; +} + +.cbi-section-error { + border: 1px solid #f00; + border-radius: 2px; + background-color: #fce6e6; + padding: 5px; + margin-bottom: 18px; +} + +.cbi-section-error ul { margin: 0 0 0 20px; } + +.cbi-section-error ul li { + color: #f00; + font-weight: bold; +} + +.ifacebox { + background-color: #fff; + border: 1px solid #ccc; + margin: 6px 4px; + text-align: center; + white-space: nowrap; + background-image: linear-gradient(#fff, #fff 25%, #f9f9f9); + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + display: inline-flex; + flex-direction: column; + line-height: 1.2em; + min-width: 100px; +} + +.ifacebox .ifacebox-head { + border-bottom: 1px solid #ccc; + padding: 10px; + line-height: 1.2em; + background: #eee; +} + +.ifacebox .ifacebox-head.active { + background: #f0e68c; +} + +.ifacebox .ifacebox-body { + padding: .25em; +} + +.ifacebadge { + display: inline-block; + flex-direction: row; + white-space: nowrap; + background-color: #fff; + border: 1px solid #ccc; + padding: 5px 5px 3px 5px; + background-image: linear-gradient(#fff, #fff 25%, #f9f9f9); + border-radius: 2px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: default; + line-height: 1.2em; +} + +.ifacebadge img { + width: 16px; + height: 16px; + vertical-align: middle; +} + +.ifacebadge-active { + border-color: #000; + font-weight: bold; +} + +.network-status-table { + display: flex; + flex-wrap: wrap; +} + +.network-status-table .ifacebox { + margin: 10px 10px 15px 2px; + flex-grow: 1; +} + +.network-status-table .ifacebox-body { + display: flex; + flex-direction: column; + height: 100%; + text-align: left; + padding: 8px; +} + +.network-status-table .ifacebox-body > * { + margin: .25em; +} + +.network-status-table .ifacebox-body > span { + flex: 10 10 auto; + height: 100%; +} + +.network-status-table .ifacebox-body > div { + display: flex; + flex-wrap: wrap; + margin: -.125em; +} + +#dsl_status_table .ifacebox-body > span > strong { + display: inline-block; + min-width: 35%; +} + +.ifacebadge.large, +.network-status-table .ifacebox-body .ifacebadge { + display: inline-flex; + flex: 1; + padding: 10px 4px 10px 4px; + min-width: 220px; + margin: 10px 6px 4px 4px; +} + +.ifacebadge > *, +.ifacebadge.large > * { + margin: 0 .125em; +} + +.zonebadge { + padding: 2px; + border-radius: 2px; + display: inline-block; + white-space: nowrap; + color: #666; +} + +.zonebadge > em, +.zonebadge > strong { + margin: 0 2px; + display: inline-block; +} + +.zonebadge input { + width: 6em; +} + +.zonebadge > .ifacebadge { + margin-left: 2px; +} + +.zonebadge-empty { + border: 1px dashed #aaa; + color: #aaa; + font-style: italic; + font-size: smaller; +} + +div.cbi-value var, +.td.cbi-value-field var { + font-style: italic; + color: #215e21; +} + +.uci-change-list { + line-height: 170%; + white-space: pre; +} + +.uci-change-list del, +.uci-change-list ins, +.uci-change-list var, +.uci-change-legend-label del, +.uci-change-legend-label ins, +.uci-change-legend-label var { + text-decoration: none; + font-family: monospace; + font-style: normal; + border: 1px solid #ccc; + background: #eee; + padding: 2px; + display: block; + line-height: 15px; + margin-bottom: 1px; +} + +.uci-change-list ins, +.uci-change-legend-label ins { + border-color: #0f0; + background: #cfc; +} + +.uci-change-list del, +.uci-change-legend-label del { + border-color: #f00; + background: #fcc; +} + +.uci-change-list var, +.uci-change-legend-label var { + border-color: #ccc; + background: #eee; +} + +.uci-change-list var ins, +.uci-change-list var del { + display: inline-block; + border: none; + width: 100%; + padding: 0; +} + +.uci-change-legend { + padding: 5px; +} + +.uci-change-legend-label { + width: 150px; + float: left; +} + +.uci-change-legend-label > ins, +.uci-change-legend-label > del, +.uci-change-legend-label > var { + float: left; + margin-right: 4px; + width: 10px; + height: 10px; + display: block; + position: relative; +} + +.uci-change-legend-label var ins, +.uci-change-legend-label var del { + border: none; + position: absolute; + top: 2px; + left: 2px; + right: 2px; + bottom: 2px; +} + +html body.apply-overlay-active { + height: calc(100vh - 63px); +} + +#applyreboot-section { + line-height: 300%; +} + +.login{ + text-align: center; + background-color: #fff; + border-radius: 20px; + width: 300px; + height: 350px; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%,-50%); +} diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/ezenlink.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/ezenlink.png new file mode 100755 index 000000000..070a12b7d Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/ezenlink.png differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/favicon.ico b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/favicon.ico new file mode 100755 index 000000000..dd14062c9 Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/favicon.ico differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/footer.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/footer.png new file mode 100755 index 000000000..c7e2e393a Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/footer.png differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/mobile.css b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/mobile.css new file mode 100755 index 000000000..8c2ab1f25 --- /dev/null +++ b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/mobile.css @@ -0,0 +1,61 @@ +#content-desktop {display: block;} +#content-mobile {display: none;} + +@media screen and (max-width: 600px) { + +#content-desktop {display: none;} +#content-mobile {display: block;} + +} + +header h3 a, header .brand { + float: left; + display: block; + padding: 12px 6px 12px 6px; + margin: 0 0 0 10px; + font-size: 22px; + font-weight: 240; +} + +header div > ul, .nav { + display: block; + float: left; + margin: 7px 8px 0 8px; + position: relative; + left: 0; +} + +header div > ul a, .nav a { + display: block; + float: left; + padding: 12px 6px 12px 6px; + line-height: 14px; + letter-spacing: 0.2px; +} + +.menu-dropdown, .dropdown-menu { + top: 38px; + min-width: 180px; + max-width: 260px; +} + +@media screen and (max-device-width: 660px) { + #maincontent.container { + width: 98%; + margin: 30px 0 0 6px; + } +} + +@media screen and (max-device-width: 360px) { + #maincontent.container { + width: 96%; + margin: 30px 0 0 6px; + } +} + +@media screen and (max-device-width: 200px) { + #maincontent.container { + width: 94%; + margin: 40px 0 0 2px; + } +} diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/omr-logo.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/omr-logo.png new file mode 100755 index 000000000..3d532aec0 Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/omr-logo.png differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/outdoorrouter.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/outdoorrouter.png new file mode 100755 index 000000000..9debc9b21 Binary files /dev/null and b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/outdoorrouter.png differ diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/menu-ezengreen.js b/luci-theme-ezengreen/htdocs/luci-static/resources/menu-ezengreen.js new file mode 100755 index 000000000..5400276b0 --- /dev/null +++ b/luci-theme-ezengreen/htdocs/luci-static/resources/menu-ezengreen.js @@ -0,0 +1,118 @@ +'use strict'; +'require baseclass'; +'require ui'; + +return baseclass.extend({ + __init__: function() { + ui.menu.load().then(L.bind(this.render, this)); + }, + + render: function(tree) { + var node = tree, + url = ''; + + this.renderModeMenu(tree); + + if (L.env.dispatchpath.length >= 3) { + for (var i = 0; i < 3 && node; i++) { + node = node.children[L.env.dispatchpath[i]]; + url = url + (url ? '/' : '') + L.env.dispatchpath[i]; + } + + if (node) + this.renderTabMenu(node, url); + } + + document.addEventListener('poll-start', this.handleBodyMargin); + document.addEventListener('poll-stop', this.handleBodyMargin); + document.addEventListener('uci-new-changes', this.handleBodyMargin); + document.addEventListener('uci-clear-changes', this.handleBodyMargin); + window.addEventListener('resize', this.handleBodyMargin); + + this.handleBodyMargin(); + }, + + renderTabMenu: function(tree, url, level) { + var container = document.querySelector('#tabmenu'), + ul = E('ul', { 'class': 'tabs' }), + children = ui.menu.getChildren(tree), + activeNode = null; + + for (var i = 0; i < children.length; i++) { + var isActive = (L.env.dispatchpath[3 + (level || 0)] == children[i].name), + activeClass = isActive ? ' active' : '', + className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass); + + ul.appendChild(E('li', { 'class': className }, [ + E('a', { 'href': L.url(url, children[i].name) }, [ _(children[i].title) ] )])); + + if (isActive) + activeNode = children[i]; + } + + if (ul.children.length == 0) + return E([]); + + container.appendChild(ul); + container.style.display = ''; + + if (activeNode) + this.renderTabMenu(activeNode, url + '/' + activeNode.name, (level || 0) + 1); + + return ul; + }, + + renderMainMenu: function(tree, url, level) { + var ul = level ? E('ul', { 'class': 'dropdown-menu' }) : document.querySelector('#topmenu'), + children = ui.menu.getChildren(tree); + + if (children.length == 0 || level > 1) + return E([]); + + for (var i = 0; i < children.length; i++) { + var submenu = this.renderMainMenu(children[i], url + '/' + children[i].name, (level || 0) + 1), + subclass = (!level && submenu.firstElementChild) ? 'dropdown' : null, + linkclass = (!level && submenu.firstElementChild) ? 'menu' : null, + linkurl = submenu.firstElementChild ? '#' : L.url(url, children[i].name); + + var li = E('li', { 'class': subclass }, [ + E('a', { 'class': linkclass, 'href': linkurl }, [ _(children[i].title) ]), + submenu + ]); + + ul.appendChild(li); + } + + ul.style.display = ''; + + return ul; + }, + + renderModeMenu: function(tree) { + var ul = document.querySelector('#modemenu'), + children = ui.menu.getChildren(tree); + + for (var i = 0; i < children.length; i++) { + var isActive = (L.env.requestpath.length ? children[i].name == L.env.requestpath[0] : i == 0); + + ul.appendChild(E('li', { 'class': isActive ? 'active' : null }, [ + E('a', { 'href': L.url(children[i].name) }, [ _(children[i].title) ]), + ' ', + E('span', { 'class': 'divider' }, [ '|' ]) + ])); + + if (isActive) + this.renderMainMenu(children[i], children[i].name); + } + + if (ul.children.length > 1) + ul.style.display = ''; + }, + + handleBodyMargin: function(ev) { + var body = document.querySelector('body'), + head = document.querySelector('header'); + + body.style.marginTop = head.offsetHeight + 'px'; + } +}); diff --git a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm new file mode 100755 index 000000000..0fdd0e4d3 --- /dev/null +++ b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm @@ -0,0 +1,19 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Copyright 2012 David Menting + Licensed to the public under the Apache License 2.0. +-%> + +<% local ver = require "luci.version" %> + + + + + + + diff --git a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm new file mode 100755 index 000000000..e5c4c9f97 --- /dev/null +++ b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm @@ -0,0 +1,90 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008-2016 Jo-Philipp Wich + Copyright 2012 David Menting + Licensed to the public under the Apache License 2.0. +-%> + +<% + local sys = require "luci.sys" + local util = require "luci.util" + local http = require "luci.http" + local disp = require "luci.dispatcher" + + local boardinfo = util.ubus("system", "board") + + local node = disp.context.dispatched + + -- send as HTML5 + http.prepare_content("text/html") + + -- Get current and latest OMR version + local current_omr_version = luci.model.uci.cursor():get("openmptcprouter","settings","version") or "" + local latest_omr_version = luci.model.uci.cursor():get("openmptcprouter","latest_versions","omr") or "" + +-%> + + + + + <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - system + + + + + + + + + <% if node and node.css then %> + + <% end -%> + <% if css then %> + + <% end -%> + + + + + "> +
+
+ +
+
+ +
+ <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%> +
+

<%:No password set!%>

+

<%:There is no password set on this router. Please configure a root password to protect the web interface.%>

+ <% if disp.lookup("admin/system/admin") then %> + + <% end %> +
+ <%- end -%> + <%- if current_omr_version ~= "" and latest_omr_version ~= "" and current_omr_version < latest_omr_version then -%> +
+

<%=translatef("你的蚂蚁聚合openmptcprouter of china商业版 版本号 %s 最新 版本号 %s 现在可以升级",current_omr_version,latest_omr_version)%>

+ +
+ <%- end -%> +
+ + +
+ + + + diff --git a/luci-theme-ezengreen/root/etc/uci-defaults/luci-theme-ezengreen b/luci-theme-ezengreen/root/etc/uci-defaults/luci-theme-ezengreen new file mode 100755 index 000000000..e1c8313d2 --- /dev/null +++ b/luci-theme-ezengreen/root/etc/uci-defaults/luci-theme-ezengreen @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ "$(uci -q get luci.themes.ezengreen)" = "" ]; then + uci batch <<-EOF + set luci.themes.ezengreen=/luci-static/ezengreen + set luci.main.mediaurlbase=/luci-static/ezengreen + commit luci + EOF +fi +exit 0 diff --git a/pdnsd-alt/Makefile b/pdnsd-alt/Makefile new file mode 100644 index 000000000..e2c1aacc3 --- /dev/null +++ b/pdnsd-alt/Makefile @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-3.0-only +# +# Copyright (C) 2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=pdnsd +PKG_VERSION:=1.2.9b-par +PKG_RELEASE:=3 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/shadowsocks/pdnsd.git +PKG_SOURCE_DATE:=2012-04-26 +PKG_SOURCE_VERSION:=a8e46ccba7b0fa2230d6c42ab6dcd92926f6c21d +PKG_MIRROR_HASH:=e3e9c56cf91b12d8db73def2c247be2f726a052bed012f7a1e48946375f8e478 + +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/pdnsd-alt + SECTION:=net + CATEGORY:=Network + SUBMENU:=IP Addresses and Names + TITLE:=Proxy DNS Server + DEPENDS:=+libpthread +endef + +define Package/pdnsd-alt/description + pdnsd, is an IPv6 capable proxy DNS server with permanent caching (the cache + contents are written to hard disk on exit) that is designed to cope with + unreachable or down DNS servers (for example in dial-in networking). + + pdnsd can be used with applications that do dns lookups, eg on startup, and + can't be configured to change that behaviour, to prevent the often + minute-long hangs (or even crashes) that result from stalled dns queries. +endef + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include + +CONFIGURE_ARGS += \ + --with-cachedir=/var/pdnsd \ + --with-target=Linux + +define Package/pdnsd-alt/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/pdnsd $(1)/usr/sbin/pdnsd + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/pdnsd-ctl $(1)/usr/sbin/pdnsd-ctl + + #$(INSTALL_DIR) $(1)/etc + #$(INSTALL_CONF) $(PKG_INSTALL_DIR)/etc/pdnsd.conf.sample $(1)/etc/pdnsd.conf + #$(INSTALL_DIR) $(1)/etc/init.d + #$(INSTALL_BIN) ./files/pdnsd.init $(1)/etc/init.d/pdnsd +endef + +$(eval $(call BuildPackage,pdnsd-alt)) diff --git a/pdnsd-alt/files/pdnsd.init b/pdnsd-alt/files/pdnsd.init new file mode 100755 index 000000000..e678d8d6a --- /dev/null +++ b/pdnsd-alt/files/pdnsd.init @@ -0,0 +1,46 @@ +#!/bin/sh /etc/rc.common + +START=65 +NAME=pdnsd +DESC="proxy DNS server" + +DAEMON=/usr/sbin/pdnsd +PID_FILE=/var/run/$NAME.pid +CACHEDIR=/var/pdnsd +CACHE=$CACHEDIR/pdnsd.cache + +USER=nobody +GROUP=nogroup + +start() { + echo -n "Starting $DESC: $NAME" + + gen_cache + + $DAEMON --daemon -p $PID_FILE + echo " ." +} + +stop() { + echo -n "Stopping $DESC: $NAME" + kill `cat $PID_FILE` > /dev/null 2>&1 + rm -rf $PID_FILE + echo " ." +} + +restart() { + echo "Restarting $DESC: $NAME... " + stop + sleep 2 + start +} + +gen_cache() +{ + if ! test -f "$CACHE"; then + mkdir -p `dirname $CACHE` + dd if=/dev/zero of="$CACHE" bs=1 count=4 2> /dev/null + chown -R $USER.$GROUP $CACHEDIR + fi +} + diff --git a/pdnsd-alt/patches/010-no-doc-and-test.patch b/pdnsd-alt/patches/010-no-doc-and-test.patch new file mode 100644 index 000000000..b0a410470 --- /dev/null +++ b/pdnsd-alt/patches/010-no-doc-and-test.patch @@ -0,0 +1,42 @@ +--- a/Makefile.am ++++ b/Makefile.am +@@ -1,5 +1,5 @@ + +-SUBDIRS = src doc contrib ++SUBDIRS = src contrib + + EXTRA_DIST = version ChangeLog.old COPYING.BSD README.par README.par.old PKGBUILD + +--- a/Makefile.in ++++ b/Makefile.in +@@ -196,7 +196,7 @@ threadlib = @threadlib@ + top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ +-SUBDIRS = src doc contrib ++SUBDIRS = src contrib + EXTRA_DIST = version ChangeLog.old COPYING.BSD README.par README.par.old PKGBUILD + all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -15,7 +15,7 @@ EXTRA_DIST = make_rr_types_h.pl rr_types + + ## Try to do this last + +-SUBDIRS = . pdnsd-ctl rc test ++SUBDIRS = . pdnsd-ctl + + $(pdnsd_OBJECTS): rr_types.h + +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -215,7 +215,7 @@ pdnsd_SOURCES = conf-parser.c conff.c co + freebsd_netinet_ip_icmp.h + + EXTRA_DIST = make_rr_types_h.pl rr_types.in +-SUBDIRS = . pdnsd-ctl rc test ++SUBDIRS = . pdnsd-ctl + all: all-recursive + + .SUFFIXES: diff --git a/pdnsd-alt/patches/020-headers.patch b/pdnsd-alt/patches/020-headers.patch new file mode 100644 index 000000000..d5639b51b --- /dev/null +++ b/pdnsd-alt/patches/020-headers.patch @@ -0,0 +1,66 @@ +--- a/src/conff.h ++++ b/src/conff.h +@@ -32,7 +32,7 @@ + #include + #include + #include +-#include ++#include + #include "ipvers.h" + #include "list.h" + +--- a/src/dns.h ++++ b/src/dns.h +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include "rr_types.h" +--- a/src/dns_answer.c ++++ b/src/dns_answer.c +@@ -37,7 +37,7 @@ + #include + #include + #ifdef HAVE_SYS_POLL_H +-#include ++#include + #endif + #include + #include +--- a/src/dns_query.c ++++ b/src/dns_query.c +@@ -23,7 +23,7 @@ + #include + #include + #ifdef HAVE_SYS_POLL_H +-#include ++#include + #endif + #include + #include +--- a/src/icmp.c ++++ b/src/icmp.c +@@ -28,7 +28,7 @@ + + #include + #ifdef HAVE_SYS_POLL_H +-#include ++#include + #endif + #include + #include +--- a/src/netdev.c ++++ b/src/netdev.c +@@ -59,7 +59,7 @@ + #include "ipvers.h" + #include + #include +-#include ++#include + #include + #include + #include diff --git a/simulated-driver/Makefile b/simulated-driver/Makefile new file mode 100644 index 000000000..0c710fe9d --- /dev/null +++ b/simulated-driver/Makefile @@ -0,0 +1,60 @@ +# +# Copyright (c) 2015,2016 The Linux Foundation. All rights reserved. +# Permission to use, copy, modify, and/or distribute this software for +# any purpose with or without fee is hereby granted, provided that the +# above copyright notice and this permission notice appear in all copies. +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=shortcut-fe-simulated-driver +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=https://source.codeaurora.org/quic/qsdk/oss/lklm/shortcut-fe +PKG_SOURCE_PROTO:=git +PKG_SOURCE_DATE:=2021-03-17 +PKG_SOURCE_VERSION:=697977d8d0ccf0ab596e5692d08608a75dd7f33d +PKG_MIRROR_HASH:=659fa82a431e15af797a6c7069faeee02810453ad8b576c51c29f95a1761a045 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/shortcut-fe-drv + SECTION:=kernel + CATEGORY:=Kernel modules + SUBMENU:=Network Support + DEPENDS:=@TARGET_ipq60xx||@TARGET_ipq806x||TARGET_ipq807x +kmod-shortcut-fe + KCONFIG:= \ + CONFIG_NET_CLS_ACT=y \ + CONFIG_XFRM=y + TITLE:=Simulated sfe driver for ECM + FILES:=$(PKG_BUILD_DIR)/simulated-driver/shortcut-fe-drv.ko +endef + +define KernelPackage/shortcut-fe-drv/Description +Simulated sfe driver which act as an adapter to convert message +between a connection manager and the SFE core engine. +endef + +define Build/Compile + $(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ + $(KERNEL_MAKE_FLAGS) \ + $(PKG_MAKE_FLAGS) \ + M="$(PKG_BUILD_DIR)/simulated-driver" \ + EXTRA_CFLAGS="-DSFE_SUPPORT_IPV6" \ + modules +endef + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/shortcut-fe + $(CP) -rf $(PKG_BUILD_DIR)/simulated-driver/sfe_drv.h $(1)/usr/include/shortcut-fe +endef + +$(eval $(call KernelPackage,shortcut-fe-drv)) diff --git a/simulated-driver/patches/200-nss-qdisc-support.patch b/simulated-driver/patches/200-nss-qdisc-support.patch new file mode 100644 index 000000000..638ad8a84 --- /dev/null +++ b/simulated-driver/patches/200-nss-qdisc-support.patch @@ -0,0 +1,11 @@ +--- ./simulated-driver/sfe_drv.c.orig 2020-06-16 12:49:47.680153371 +0800 ++++ ./simulated-driver/sfe_drv.c 2020-06-16 12:50:18.540153371 +0800 +@@ -1167,7 +1167,7 @@ int sfe_drv_recv(struct sk_buff *skb) + * If ingress Qdisc configured, and packet not processed by ingress Qdisc yet + * We can not accelerate this packet. + */ +- if (dev->ingress_queue && !(skb->tc_verd & TC_NCLS)) { ++ if (dev->ingress_queue && !(skb->tc_verd_qca_nss & TC_NCLS)) { + return 0; + } + #endif