From b8b7de294fc1bd2a0ccfe861b076a49249d78f15 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 6 Apr 2022 16:54:29 +0800 Subject: [PATCH 01/26] Revert "Update Makefile" This reverts commit d9354767cfa2ea62b825e42b82e4f10397c644d8. --- netifd/Makefile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/netifd/Makefile b/netifd/Makefile index 2e64a6736..4b5f110da 100644 --- a/netifd/Makefile +++ b/netifd/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git -PKG_SOURCE_DATE:=2021-01-09 -PKG_SOURCE_VERSION:=753c351bc729967a691d99e27693be5aec334028 -PKG_MIRROR_HASH:=e7d95bde520fc660d0a49e28c5bb50fff3071d7f48fe7fc3fc610f38edfc7df1 +PKG_SOURCE_DATE:=2021-07-26 +PKG_SOURCE_VERSION:=440eb0647708274cc8d7d9e7c2bb0cfdfba90023 +PKG_MIRROR_HASH:=eed957036ab608fdc49bdf801fc5b4405fcd2a3a5e5d3343ec39898e156c10e9 PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=GPL-2.0 @@ -25,6 +25,11 @@ define Package/netifd TITLE:=OpenWrt Network Interface Configuration Daemon endef +define Package/netifd/conffiles +/etc/udhcpc.user +/etc/udhcpc.user.d/ +endef + TARGET_CFLAGS += \ -I$(STAGING_DIR)/usr/include/libnl-tiny \ -I$(STAGING_DIR)/usr/include \ @@ -40,6 +45,7 @@ define Package/netifd/install $(INSTALL_DIR) $(1)/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/netifd $(1)/sbin/ $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/etc/udhcpc.user.d/ $(CP) $(PKG_BUILD_DIR)/scripts/* $(1)/lib/netifd/ endef From 411aacefab698a15f0aa21ea582bce62b8bf4c42 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Sat, 23 Apr 2022 14:10:09 +0800 Subject: [PATCH 02/26] Delete 1920-omr-network --- .../files/etc/uci-defaults/1920-omr-network | 415 ------------------ 1 file changed, 415 deletions(-) delete mode 100755 openmptcprouter/files/etc/uci-defaults/1920-omr-network diff --git a/openmptcprouter/files/etc/uci-defaults/1920-omr-network b/openmptcprouter/files/etc/uci-defaults/1920-omr-network deleted file mode 100755 index a0e15b2f5..000000000 --- a/openmptcprouter/files/etc/uci-defaults/1920-omr-network +++ /dev/null @@ -1,415 +0,0 @@ -#!/bin/sh -. /lib/functions.sh - -_setup_macaddr() { - uci -q get "network.$1.macaddr" >/dev/null && return - uci -q set "network.$1.macaddr=$2" -} - -_setup_macvlan() { - uci -q get "network.$1_dev.ifname" >/dev/null && return - - # do not create macvlan for vlan - local _ifname - _ifname=$(uci -q get "network.$1.device") - case "$_ifname" in - eth*.*) return ;; - esac - - uci -q batch <<-EOF - set network.$1_dev=device - set network.$1_dev.name=$1 - set network.$1_dev.type=macvlan - set network.$1_dev.ifname=$_ifname - set network.$1_dev.mode='vepa' - set network.$1.device=$1 - set network.$1.type=macvlan - set network.$1.masterintf=$_ifname - EOF - _macaddr=$(uci -q get "network.$1.macaddr") - _setup_macaddr "$1_dev" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" -} - -#_setup_macvlan_update() { -# uci -q get "network.$1_dev.device" >/dev/null || return -# -# uci -q batch <<-EOF -# set macvlan.$1=macvlan -# set macvlan.$1.device=$_ifname -# commit macvlan -# EOF -#} - -_setup_mptcp_handover_to_on() { - if [ "$(uci -q get network.$1.multipath)" = "handover" ]; then - uci -q set network.$1.multipath=on - fi - if [ "$(uci -q get openmptcprouter.$1.multipath)" = "handover" ]; then - uci -q set openmptcprouter.$1.multipath=on - fi -} - -_setup_multipath_off() { - uci -q get "network.$1.multipath" >/dev/null && return - uci -q set "network.$1.multipath=off" -} - -_setup_wan_interface() { - uci -q batch <<-EOF - set network.$1=interface - set network.$1.device=$2 - set network.$1.proto=static - set network.$1.ip4table=wan - set network.$1.multipath=$3 - set network.$1.defaultroute=0 - set network.${1}_dev=device - set network.${1}_dev.name=$2 - commit network - add_list firewall.@zone[1].network=$1 - commit firewall - EOF - [ -n "$4" ] && uci -q set network.$1.type=$4 -} - -config_load network -#config_foreach _setup_macvlan_update interface -config_foreach _setup_mptcp_handover_to_on interface - -if [ "$(uci -q show network.lan | grep multipath)" != "" ]; then - exit 0 -fi - -lanif="eth0" -if [ "$(grep rockchip /etc/os-release)" != "" ]; then - lanif="eth1" -elif [ -d /sys/class/net/lan0 -o -n "$(ip link | grep ' lan0')" ] && [ -d /sys/class/net/wan -o -n "$(ip link | grep ' wan@')" -o -n "$(ip link | grep ' wan:')" ]; then - lanif="wan" -elif [ -d /sys/class/net/lan1 -o -n "$(ip link | grep ' lan1')" ] && [ -d /sys/class/net/wan -o -n "$(ip link | grep ' wan@')" -o -n "$(ip link | grep ' wan:')" ]; then - lanif="wan" -elif [ -d /sys/class/net/lan ] || [ -n "$(ip link | grep ' lan')" ]; then - lanif="lan" -elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ] && [ "$(cat /etc/board.json | jsonfilter -q -e '@.model.platform' | tr -d '\n')" = "RUTX" ]; then - lanif="eth1" - uci -q batch <<-EOF - set network.@switch_vlan[0]=switch_vlan - set network.@switch_vlan[0].device='switch0' - set network.@switch_vlan[0].vlan=1 - set network.@switch_vlan[0].ports='1t 2t 3t 4t 0t' - set network.@switch_vlan[1]=switch_vlan - set network.@switch_vlan[1].device='switch0' - set network.@switch_vlan[1].vlan=2 - set network.@switch_vlan[1].ports='0 5' - add network switch_vlan - set network.@switch_vlan[2].device='switch0' - set network.@switch_vlan[2].vlan=3 - set network.@switch_vlan[2].ports='0t 1' - add network switch_vlan - set network.@switch_vlan[3].device='switch0' - set network.@switch_vlan[3].vlan=4 - set network.@switch_vlan[3].ports='0t 2' - add network switch_vlan - set network.@switch_vlan[4].device='switch0' - set network.@switch_vlan[4].vlan=5 - set network.@switch_vlan[4].ports='0t 3' - add network switch_vlan - set network.@switch_vlan[5].device='switch0' - set network.@switch_vlan[5].vlan=6 - set network.@switch_vlan[5].ports='0t 4' - EOF -elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ] && [ -d '/sys/class/net/eth1.5' ]; then - lanif="eth1.5" - uci -q batch <<-EOF - set network.@switch_vlan[0]=switch_vlan - set network.@switch_vlan[0].device='switch0' - set network.@switch_vlan[0].vlan=1 - set network.@switch_vlan[0].vid=1 - set network.@switch_vlan[0].ports='3 5t' - add network switch_vlan - set network.@switch_vlan[1].device='switch0' - set network.@switch_vlan[1].vlan=2 - set network.@switch_vlan[1].vid=2 - set network.@switch_vlan[1].ports='2 5t' - add network switch_vlan - set network.@switch_vlan[2].device='switch0' - set network.@switch_vlan[2].vlan=3 - set network.@switch_vlan[2].vid=3 - set network.@switch_vlan[2].ports='1 5t' - add network switch_vlan - set network.@switch_vlan[3].device='switch0' - set network.@switch_vlan[3].vlan=4 - set network.@switch_vlan[3].vid=4 - set network.@switch_vlan[3].ports='0 5t' - add network switch_vlan - set network.@switch_vlan[4].device='switch0' - set network.@switch_vlan[4].vlan=5 - set network.@switch_vlan[4].vid=5 - set network.@switch_vlan[4].ports='4 6t' - EOF -elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ] && [ -d /sys/class/net/eth1 ] && [ "$(grep ipq806x /etc/os-release)" != "" ]; then - lanif="eth0.2" -elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ] && [ -d /sys/class/net/eth1 ]; then - lanif="eth1" -elif [ ! -d /sys/class/net/eth1 ] && [ -d /sys/class/net/eth0 ]; then - lanif="eth0" -fi -uci -q batch <<-EOF -delete network.lan.type -set network.lan=interface -set network.lan.proto=static -set network.lan.ipaddr=192.168.100.1 -set network.lan.netmask=255.255.255.0 -set network.lan.device=${lanif} -set network.lan.ifname=${lanif} -set network.lan.metric=2048 -set network.lan.ipv6=0 -set network.lan.delegate=0 -EOF - -uci -q batch <<-EOF -delete network.none -delete network.wan -delete network.if6rd -reorder network.loopback=0 -reorder network.globals=1 -reorder network.lan=2 -set network.globals.multipath=enable -EOF - -# Set the ip rule for the lan with a pref of 100 -uci -q show network.lan_rule >/dev/null || \ - uci -q batch <<-EOF - set network.lan_rule=rule - set network.lan_rule.lookup=lan - set network.lan_rule.priority=100 - EOF - -if [ "$(uci -q get network.vpn0.proto)" = "none" ]; then - uci -q delete network.vpn0 -fi - -config_load network -config_foreach _setup_multipath_off interface - -# Add the lan as a named routing table -if ! grep -s -q "lan" /etc/iproute2/rt_tables; then - echo "50 lan" >> /etc/iproute2/rt_tables -fi -uci -q set network.lan.ip4table='lan' - -#uci -q set "network.lan.ip6assign=64" - -# Create WAN interfaces -if [ "$(uci -q show network.wan1 | grep multipath)" = "" ] && [ -z "$(uci -q get network.wan1.multipath)" ]; then - if [ "$(grep ipq806x /etc/os-release)" != "" ]; then - _setup_wan_interface wan1 eth1.1 master - _setup_wan_interface wan2 eth1.2 on - _setup_wan_interface wan3 eth1.3 on - _setup_wan_interface wan4 eth1.4 on - elif [ "$(grep rockchip /etc/os-release)" != "" ]; then - _setup_wan_interface wan1 eth0 master macvlan - _setup_wan_interface wan2 eth0 on macvlan - _setup_macvlan wan1 - _setup_macvlan wan2 - elif [ "$(cat /etc/board.json | jsonfilter -q -e '@.model.platform' | tr -d '\n')" = "RUTX" ]; then - _setup_wan_interface wan1 eth0.3 master - _setup_wan_interface wan2 eth0.4 on - _setup_wan_interface wan3 eth0.5 on - _setup_wan_interface wan4 eth0.6 on - elif [ "$(swconfig list 2>&1 | grep switch0)" != "" ]; then - _setup_wan_interface wan1 eth0.1 master - _setup_wan_interface wan2 eth0.2 on - _setup_wan_interface wan3 eth0.3 on - _setup_wan_interface wan4 eth0.4 on - elif [ -d /sys/class/net/wan ] || [ -n "$(ip link | grep ' wan:')" ] || [ -n "$(ip link | grep ' wan@')" ]; then - if [ -d /sys/class/net/lan0 -o -n "$(ip link | grep ' lan0')" ] && [ -d /sys/class/net/lan1 -o -n "$(ip link | grep ' lan1')" ]; then - _setup_wan_interface wan1 lan0 master - _setup_wan_interface wan2 lan1 on - - _macaddr=$(uci -q get "network.lan0.macaddr") - _setup_macaddr "wan1" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - _macaddr=$(uci -q get "network.lan1.macaddr") - _setup_macaddr "wan2" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - if [ -d /sys/class/net/lan2 ] || [ -n "$(ip link | grep ' lan2')" ]; then - _setup_wan_interface wan3 lan2 on - _macaddr=$(uci -q get "network.lan2.macaddr") - _setup_macaddr "wan3" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - if [ -d /sys/class/net/lan3 ] || [ -n "$(ip link | grep ' lan3')" ]; then - _setup_wan_interface wan4 lan3 on - _macaddr=$(uci -q get "network.lan3.macaddr") - _setup_macaddr "wan4" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - fi - fi - elif [ -d /sys/class/net/lan1 -o -n "$(ip link | grep ' lan1')" ] && [ -d /sys/class/net/lan2 -o -n "$(ip link | grep ' lan2')" ]; then - _setup_wan_interface wan1 lan1 master - _setup_wan_interface wan2 lan2 on - - _macaddr=$(uci -q get "network.lan1.macaddr") - _setup_macaddr "wan1" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - _macaddr=$(uci -q get "network.lan2.macaddr") - _setup_macaddr "wan2" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - if [ -d /sys/class/net/lan3 ] || [ -n "$(ip link | grep ' lan3')" ]; then - _setup_wan_interface wan3 lan3 on - _macaddr=$(uci -q get "network.lan3.macaddr") - _setup_macaddr "wan3" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - if [ -d /sys/class/net/lan4 ] || [ -n "$(ip link | grep ' lan4')" ]; then - _setup_wan_interface wan4 lan4 on - _macaddr=$(uci -q get "network.lan4.macaddr") - _setup_macaddr "wan4" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - fi - fi - else - _setup_wan_interface wan1 wan master macvlan - _setup_wan_interface wan2 wan on macvlan - _setup_macvlan wan1 - _setup_macvlan wan2 - fi - elif [ -d /sys/class/net/wan1 ] || [ -n "$(ip link | grep ' wan1')" ]; then - if [ -d /sys/class/net/wan2 ] || [ -n "$(ip link | grep ' wan2')" ]; then - _setup_wan_interface wan1 wan1 master - _setup_wan_interface wan2 wan2 on - - _macaddr=$(uci -q get "network.wan1.macaddr") - _setup_macaddr "wan1" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - _macaddr=$(uci -q get "network.wan2.macaddr") - _setup_macaddr "wan2" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - - if [ -d /sys/class/net/wan3 ] || [ -n "$(ip link | grep ' wan3')" ]; then - _setup_wan_interface wan3 wan3 on - _macaddr=$(uci -q get "network.wan3.macaddr") - _setup_macaddr "wan3" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - if [ -d /sys/class/net/wan4 ] || [ -n "$(ip link | grep ' wan4')" ]; then - _setup_wan_interface wan4 wan4 on - _macaddr=$(uci -q get "network.wan4.macaddr") - _setup_macaddr "wan4" "${_macaddr:-$(dd if=/dev/urandom bs=1024 count=1 2>/dev/null | md5sum | sed -e 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/' -e 's/^\(.\)[13579bdf]/\10/')}" - fi - fi - else - _setup_wan_interface wan1 wan1 master macvlan - _setup_wan_interface wan2 wan1 on macvlan - _setup_macvlan wan1 - _setup_macvlan wan2 - fi - elif [ -d /sys/class/net/eth1 ] || [ -n "$(ip link | grep ' eth1:')" ]; then - if [ -d /sys/class/net/eth2 ] || [ -n "$(ip link | grep ' eth2:')" ]; then - _setup_wan_interface wan1 eth1 master - _setup_wan_interface wan2 eth2 on - if [ -d /sys/class/net/eth3 ] || [ -n "$(ip link | grep ' eth3:')" ]; then - _setup_wan_interface wan3 eth3 on - fi - if [ -d /sys/class/net/eth4 ] || [ -n "$(ip link | grep ' eth4:')" ]; then - _setup_wan_interface wan4 eth4 on - fi - if [ -d /sys/class/net/eth5 ] || [ -n "$(ip link | grep ' eth5:')" ]; then - _setup_wan_interface wan5 eth5 on - fi - if [ -d /sys/class/net/eth6 ] || [ -n "$(ip link | grep ' eth6:')" ]; then - _setup_wan_interface wan6 eth6 on - fi - if [ -d /sys/class/net/eth7 ] || [ -n "$(ip link | grep ' eth7:')" ]; then - _setup_wan_interface wan7 eth7 on - fi - if [ -d /sys/class/net/eth8 ] || [ -n "$(ip link | grep ' eth8:')" ]; then - _setup_wan_interface wan8 eth8 on - fi - else - _setup_wan_interface wan1 eth1 master macvlan - _setup_wan_interface wan2 eth1 on macvlan - _setup_macvlan wan1 - _setup_macvlan wan2 - fi - elif [ -d /sys/class/net/eth0.1 ] && [ -d /sys/class/net/eth0.2 ]; then - _setup_wan_interface wan1 eth0.1 master - _setup_wan_interface wan2 eth0.2 on - else - _setup_wan_interface wan1 eth0 master macvlan - _setup_wan_interface wan2 eth0 on macvlan - _setup_macvlan wan1 - _setup_macvlan wan2 - fi - #uci -q batch <<-EOF - #add network route6 - #set network.@route6[-1].interface='lan' - #set network.@route6[-1].target='::/0' - #EOF -fi - -# Replace omrip to oip in config for old config -sed -i 's/omrip/oip/g' /etc/config/* - -# Fix config from ifname to device for loopback -uci -q delete network.loopback.ifname -uci -q set network.loopback.device='lo' - -local board=$(board_name) -if [ "$board" = "teltonika,rutx" ] && [ -f /sbin/mnf_info ]; then - # Same part for RUTX12 and RUTX11, maybe other RUTX ? - uci -q batch <<-EOF - set network.modem1=interface - set network.modem1.proto='modemmanager' - set network.modem1.apn='' - set network.modem1.auth='none' - set network.modem1.iptype='ipv4v6' - set network.modem1.addlatency='0' - set network.modem1.force_link='1' - set network.modem1.device='/sys/devices/platform/soc/60f8800.usb2/6000000.dwc3/xhci-hcd.1.auto/usb3/3-1' - set network.modem1.peerdns='0' - set network.wan_modem1=interface - set network.wan_modem1.proto='dhcp' - set network.wan_modem1.device='wwan0' - set network.wan_modem1.force_link='1' - set network.wan_modem1.multipath='on' - set network.wan_modem1.addlatency='0' - set network.wan_modem1.hostname='*' - set network.wan_modem1.defaultroute='0' - set network.wan_modem1.peerdns='0' - set network.wan_modem1.ip4table=wan - commit network - add_list firewall.@zone[1].network='wan_modem1' - commit firewall - EOF - if [ "$(mnf_info -n)" = "RUTX1200XXXX" ]; then - uci -q batch <<-EOF - set network.modem2=interface - set network.modem2.proto='modemmanager' - set network.modem2.apn='' - set network.modem2.auth='none' - set network.modem2.iptype='ipv4v6' - set network.modem2.addlatency='0' - set network.modem2.force_link='1' - set network.modem2.device='/sys/devices/platform/soc/8af8800.usb3/8a00000.dwc3/xhci-hcd.0.auto/usb1/1-1/1-1.2' - set network.modem2.peerdns='0' - set network.wan_modem2=interface - set network.wan_modem2.proto='dhcp' - set network.wan_modem2.device='wwan1' - set network.wan_modem2.force_link='1' - set network.wan_modem2.multipath='on' - set network.wan_modem2.addlatency='0' - set network.wan_modem2.hostname='*' - set network.wan_modem2.defaultroute='0' - set network.wan_modem2.peerdns='0' - set network.wan_modem2.ip4table=wan - commit network - add_list firewall.@zone[1].network='wan_modem2' - commit firewall - EOF - fi - uci -q batch <<-EOF - set network.wifi24=interface - set network.wifi24.proto='none' - set network.wifi5=interface - set network.wifi5.proto='none' - commit network - set wireless.radio0.cell_density='0' - set wireless.default_radio0.network='wifi24' - set wireless.radio1.cell_density='0' - set wireless.default_radio1.network='wifi5' - commit wireless - EOF - -fi - - -uci -q commit macvlan -uci -q commit network -rm -f /tmp/luci-indexcache -exit 0 From f1a6d9b60715768ad283f0652f0170b774151cc7 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 27 Apr 2022 15:45:09 +0800 Subject: [PATCH 03/26] add frp --- frp/Makefile | 70 +++++++++++++++++++++++++++++++ frp/files/frpc.config | 23 ++++++++++ frp/files/frpc.init | 84 +++++++++++++++++++++++++++++++++++++ frp/files/frpc.uci-defaults | 19 +++++++++ frp/files/frps.config | 16 +++++++ frp/files/frps.init | 82 ++++++++++++++++++++++++++++++++++++ 6 files changed, 294 insertions(+) create mode 100644 frp/Makefile create mode 100644 frp/files/frpc.config create mode 100644 frp/files/frpc.init create mode 100644 frp/files/frpc.uci-defaults create mode 100644 frp/files/frps.config create mode 100644 frp/files/frps.init diff --git a/frp/Makefile b/frp/Makefile new file mode 100644 index 000000000..0ea29e37c --- /dev/null +++ b/frp/Makefile @@ -0,0 +1,70 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=frp +PKG_VERSION:=0.39.0 +PKG_RELEASE:=$(AUTORELEASE) + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/fatedier/frp/tar.gz/v${PKG_VERSION}? +PKG_HASH:=639ad416587b03751569b0d51c097bcc52727643e0656064843efb5d0b08ba72 + +PKG_MAINTAINER:=Richard Yu +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/fatedier/frp +GO_PKG_BUILD_PKG:=github.com/fatedier/frp/cmd/... + +include $(INCLUDE_DIR)/package.mk +include ../../lang/golang/golang-package.mk + +define Package/frp/install + $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR)) + + $(INSTALL_DIR) $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(2) $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc/frp/$(2).d/ + $(INSTALL_DATA) $(PKG_BUILD_DIR)/conf/$(2)_full.ini $(1)/etc/frp/$(2).d/ + $(INSTALL_DIR) $(1)/etc/config/ + $(INSTALL_CONF) ./files/$(2).config $(1)/etc/config/$(2) + $(INSTALL_DIR) $(1)/etc/init.d/ + $(INSTALL_BIN) ./files/$(2).init $(1)/etc/init.d/$(2) + + if [ -r ./files/$(2).uci-defaults ]; then \ + $(INSTALL_DIR) $(1)/etc/uci-defaults; \ + $(INSTALL_DATA) ./files/$(2).uci-defaults $(1)/etc/uci-defaults/$(2); \ + fi +endef + +define Package/frp/template + define Package/$(1) + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=$(1) - fast reverse proxy $(2) + URL:=https://github.com/fatedier/frp + DEPENDS:=$(GO_ARCH_DEPENDS) + endef + + define Package/$(1)/description + $(1) is a fast reverse proxy $(2) to help you expose a local server behind + a NAT or firewall to the internet. + endef + + define Package/$(1)/conffiles +/etc/config/$(1) + endef + + define Package/$(1)/install + $(call Package/frp/install,$$(1),$(1)) + endef +endef + +$(eval $(call Package/frp/template,frpc,client)) +$(eval $(call Package/frp/template,frps,server)) +$(eval $(call BuildPackage,frpc)) +$(eval $(call BuildPackage,frps)) diff --git a/frp/files/frpc.config b/frp/files/frpc.config new file mode 100644 index 000000000..492e224ff --- /dev/null +++ b/frp/files/frpc.config @@ -0,0 +1,23 @@ +config init + option stdout 1 + option stderr 1 + option user frpc + option group frpc + option respawn 1 +# OS environments pass to frp for config file template, see +# https://github.com/fatedier/frp#configuration-file-template +# list env 'ENV_NAME=value' +# Config files include in temporary config file. +# list conf_inc '/etc/frp/frpc.d/frpc_full.ini' + +config conf 'common' + option server_addr 127.0.0.1 + option server_port 7000 +# List options with name="_" will be directly appended to config file +# list _ '# Key-A=Value-A' + +config conf 'ssh' + option type tcp + option local_ip 127.0.0.1 + option local_port 22 + option remote_port 6000 diff --git a/frp/files/frpc.init b/frp/files/frpc.init new file mode 100644 index 000000000..e7f06edbd --- /dev/null +++ b/frp/files/frpc.init @@ -0,0 +1,84 @@ +#!/bin/sh /etc/rc.common + +START=99 +USE_PROCD=1 + +NAME=frpc +PROG=/usr/bin/$NAME + +_err() { + echo "$*" >&2 + logger -p daemon.err -t "$NAME" "$*" +} + +config_cb() { + [ $# -eq 0 ] && return + + local type="$1" + local name="$2" + if [ "$type" = "conf" ]; then + echo "[$name]" >> "$conf_file" + option_cb() { + local option="$1" + local value="$2" + [ "$option" = "name" ] && \ + sed -i "s/$CONFIG_SECTION/$value/g" "$conf_file" || \ + echo "$option = $value" >> "$conf_file"; + } + list_cb() { + local name="$1" + local value="$2" + [ "$name" = "_" ] && echo "$value" >> "$conf_file" + } + else + [ "$type" = "init" ] && init_cfg="$name" + option_cb() { return 0; } + list_cb() { return 0; } + fi +} + +service_triggers() +{ + procd_add_reload_trigger "$NAME" +} + +start_service() { + local init_cfg=" " + local conf_file="/var/etc/$NAME.ini" + + > "$conf_file" + config_load "$NAME" + + local stdout stderr user group respawn env conf_inc + uci_validate_section "$NAME" init "$init_cfg" \ + 'stdout:bool:1' \ + 'stderr:bool:1' \ + 'user:string' \ + 'group:string' \ + 'respawn:bool:1' \ + 'env:list(string)' \ + 'conf_inc:list(string)' + + local err=$? + [ $err -ne 0 ] && { + _err "uci_validate_section returned $err" + return 1 + } + + [ -n "$conf_inc" ] && config_list_foreach "$init_cfg" conf_inc cat >> "$conf_file" + + procd_open_instance + procd_set_param command "$PROG" -c "$conf_file" + procd_set_param stdout $stdout + procd_set_param stderr $stderr + [ -n "$user" ] && procd_set_param user "$user" + [ -n "$group" ] && procd_set_param group "$group" + [ $respawn -eq 1 ] && procd_set_param respawn + [ -n "$env" ] && config_list_foreach "$init_cfg" env "procd_append_param env" + procd_close_instance +} + +reload_service() { + stop + start +} diff --git a/frp/files/frpc.uci-defaults b/frp/files/frpc.uci-defaults new file mode 100644 index 000000000..4883a2d8c --- /dev/null +++ b/frp/files/frpc.uci-defaults @@ -0,0 +1,19 @@ +#!/bin/sh + +. /lib/functions.sh + +upgrade() { + local section=$1 + local name + [ "$section" != "common" ] || return 0 + config_get name $section name + if [ -z "$name" ]; then + uci_set frpc "$section" name "$section" + uci_commit frpc + fi +} + +config_load frpc +config_foreach upgrade conf + +exit 0 diff --git a/frp/files/frps.config b/frp/files/frps.config new file mode 100644 index 000000000..ae0bffc2f --- /dev/null +++ b/frp/files/frps.config @@ -0,0 +1,16 @@ +config init + option stdout 1 + option stderr 1 + option user frps + option group frps + option respawn 1 +# OS environments pass to frp for config file template, see +# https://github.com/fatedier/frp#configuration-file-template +# list env 'ENV_NAME=value' +# Config files include in temporary config file. +# list conf_inc '/etc/frp/frps.d/frps_full.ini' + +config conf 'common' + option bind_port 7000 +# List options with name="_" will be directly appended to config file +# list _ '# Key-A=Value-A' diff --git a/frp/files/frps.init b/frp/files/frps.init new file mode 100644 index 000000000..b87525cd2 --- /dev/null +++ b/frp/files/frps.init @@ -0,0 +1,82 @@ +#!/bin/sh /etc/rc.common + +START=99 +USE_PROCD=1 + +NAME=frps +PROG=/usr/bin/$NAME + +_err() { + echo "$*" >&2 + logger -p daemon.err -t "$NAME" "$*" +} + +config_cb() { + [ $# -eq 0 ] && return + + local type="$1" + local name="$2" + if [ "$type" = "conf" ]; then + echo "[$name]" >> "$conf_file" + option_cb() { + local option="$1" + local value="$2" + echo "$option = $value" >> "$conf_file" + } + list_cb() { + local name="$1" + local value="$2" + [ "$name" = "_" ] && echo "$value" >> "$conf_file" + } + else + [ "$type" = "init" ] && init_cfg="$name" + option_cb() { return 0; } + list_cb() { return 0; } + fi +} + +service_triggers() +{ + procd_add_reload_trigger "$NAME" +} + +start_service() { + local init_cfg=" " + local conf_file="/var/etc/$NAME.ini" + + > "$conf_file" + config_load "$NAME" + + local stdout stderr user group respawn env conf_inc + uci_validate_section "$NAME" init "$init_cfg" \ + 'stdout:bool:1' \ + 'stderr:bool:1' \ + 'user:string' \ + 'group:string' \ + 'respawn:bool:1' \ + 'env:list(string)' \ + 'conf_inc:list(string)' + + local err=$? + [ $err -ne 0 ] && { + _err "uci_validate_section returned $err" + return 1 + } + + [ -n "$conf_inc" ] && config_list_foreach "$init_cfg" conf_inc cat >> "$conf_file" + + procd_open_instance + procd_set_param command "$PROG" -c "$conf_file" + procd_set_param stdout $stdout + procd_set_param stderr $stderr + [ -n "$user" ] && procd_set_param user "$user" + [ -n "$group" ] && procd_set_param group "$group" + [ $respawn -eq 1 ] && procd_set_param respawn + [ -n "$env" ] && config_list_foreach "$init_cfg" env "procd_append_param env" + procd_close_instance +} + +reload_service() { + stop + start +} From 62c67e0bebd43e1d3e3f82deb79ea00775bfb690 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 27 Apr 2022 15:52:22 +0800 Subject: [PATCH 04/26] add luci proto --- luci-proto-modemmanager/Makefile | 14 ++ .../resources/protocol/modemmanager.js | 139 ++++++++++++++++++ .../rpcd/acl.d/luci-proto-modemmanager.json | 12 ++ 3 files changed, 165 insertions(+) create mode 100644 luci-proto-modemmanager/Makefile create mode 100644 luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js create mode 100644 luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json diff --git a/luci-proto-modemmanager/Makefile b/luci-proto-modemmanager/Makefile new file mode 100644 index 000000000..c2718dd0a --- /dev/null +++ b/luci-proto-modemmanager/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Support for ModemManager +LUCI_DEPENDS:=+modemmanager + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js b/luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js new file mode 100644 index 000000000..501f75964 --- /dev/null +++ b/luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js @@ -0,0 +1,139 @@ +'use strict'; +'require fs'; +'require form'; +'require network'; + +function getModemList() { + return fs.exec_direct('/usr/bin/mmcli', [ '-L' ]).then(function(res) { + var lines = (res || '').split(/\n/), + tasks = []; + + for (var i = 0; i < lines.length; i++) { + var m = lines[i].match(/\/Modem\/(\d+)/); + if (m) + tasks.push(fs.exec_direct('/usr/bin/mmcli', [ '-m', m[1] ])); + } + + return Promise.all(tasks).then(function(res) { + var modems = []; + + for (var i = 0; i < res.length; i++) { + var man = res[i].match(/manufacturer: ([^\n]+)/), + mod = res[i].match(/model: ([^\n]+)/), + dev = res[i].match(/device: ([^\n]+)/); + + if (dev) { + modems.push({ + device: dev[1].trim(), + manufacturer: (man ? man[1].trim() : '') || '?', + model: (mod ? mod[1].trim() : '') || dev[1].trim() + }); + } + } + + return modems; + }); + }); +} + +network.registerPatternVirtual(/^mobiledata-.+$/); +network.registerErrorCode('MM_CONNECT_FAILED', _('Connection attempt failed.')); +network.registerErrorCode('MM_DISCONNECT_IN_PROGRESS', _('Modem disconnection in progress. Please wait.')); +network.registerErrorCode('MM_CONNECT_IN_PROGRESS', _('Modem connection in progress. Please wait. This process will timeout after 2 minutes.')); +network.registerErrorCode('MM_TEARDOWN_IN_PROGRESS', _('Modem bearer teardown in progress.')); +network.registerErrorCode('MM_MODEM_DISABLED', _('Modem is disabled.')); +network.registerErrorCode('DEVICE_NOT_MANAGED', _('Device not managed by ModemManager.')); +network.registerErrorCode('INVALID_BEARER_LIST', _('Invalid bearer list. Possibly too many bearers created. This protocol supports one and only one bearer.')); +network.registerErrorCode('UNKNOWN_METHOD', _('Unknown and unsupported connection method.')); +network.registerErrorCode('DISCONNECT_FAILED', _('Disconnection attempt failed.')); + +return network.registerProtocol('modemmanager', { + getI18n: function() { + return _('ModemManager'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'modemmanager-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'modemmanager'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var dev = this.getL3Device() || this.getDevice(), o; + + o = s.taboption('general', form.ListValue, '_modem_device', _('Modem device')); + o.ucioption = 'device'; + o.rmempty = false; + o.load = function(section_id) { + return getModemList().then(L.bind(function(devices) { + for (var i = 0; i < devices.length; i++) + this.value(devices[i].device, + '%s - %s'.format(devices[i].manufacturer, devices[i].model)); + return form.Value.prototype.load.apply(this, [section_id]); + }, this)); + }; + + o = s.taboption('general', form.Value, 'apn', _('APN')); + o.validate = function(section_id, value) { + if (value == null || value == '') + return true; + + if (!/^[a-zA-Z0-9\-.]*[a-zA-Z0-9]$/.test(value)) + return _('Invalid APN provided'); + + return true; + }; + + o = s.taboption('general', form.Value, 'pincode', _('PIN')); + o.datatype = 'and(uinteger,minlength(4),maxlength(8))'; + + o = s.taboption('general', form.ListValue, 'auth', _('Authentication Type')); + o.value('both', _('PAP/CHAP (both)')); + o.value('pap', 'PAP'); + o.value('chap', 'CHAP'); + o.value('none', _('None')); + o.default = 'none'; + + o = s.taboption('general', form.Value, 'username', _('PAP/CHAP username')); + o.depends('auth', 'pap'); + o.depends('auth', 'chap'); + o.depends('auth', 'both'); + + o = s.taboption('general', form.Value, 'password', _('PAP/CHAP password')); + o.depends('auth', 'pap'); + o.depends('auth', 'chap'); + o.depends('auth', 'both'); + o.password = true; + + o = s.taboption('general', form.ListValue, 'iptype', _('IP Type')); + o.value('ipv4v6', _('IPv4/IPv6 (both - defaults to IPv4)')) + o.value('ipv4', _('IPv4 only')); + o.value('ipv6', _('IPv6 only')); + o.default = 'ipv4v6'; + + o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU')); + o.placeholder = dev ? (dev.getMTU() || '1500') : '1500'; + o.datatype = 'max(9200)'; + + o = s.taboption('general', form.Value, 'signalrate', _('Signal Refresh Rate'), _("In seconds")); + o.datatype = 'uinteger'; + } +}); diff --git a/luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json b/luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json new file mode 100644 index 000000000..716f4c465 --- /dev/null +++ b/luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json @@ -0,0 +1,12 @@ +{ + "luci-proto-modemmanager": { + "description": "Grant access to mmcli", + "read": { + "cgi-io": [ "exec" ], + "file": { + "/usr/bin/mmcli -L": [ "exec" ], + "/usr/bin/mmcli -m [0-9]": [ "exec" ] + } + } + } +} From b6b6a7e6fe4805e2028b205b72c2d39b3ea822ab Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 27 Apr 2022 15:54:52 +0800 Subject: [PATCH 05/26] add bpftools --- bpftools/Makefile | 169 ++++++++++++++++++ ...pc-fix-EDEADLOCK-redefinition-errors.patch | 51 ++++++ 2 files changed, 220 insertions(+) create mode 100644 bpftools/Makefile create mode 100644 bpftools/patches/005-tools-arch-powerpc-fix-EDEADLOCK-redefinition-errors.patch 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 From cc79e03bca9d25f2f03881dc39e9b3f3f9a1f08d Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 27 Apr 2022 16:13:45 +0800 Subject: [PATCH 06/26] fix --- luci-proto-modemmanager/Makefile | 14 -- .../resources/protocol/modemmanager.js | 139 ------------------ .../rpcd/acl.d/luci-proto-modemmanager.json | 12 -- 3 files changed, 165 deletions(-) delete mode 100644 luci-proto-modemmanager/Makefile delete mode 100644 luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js delete mode 100644 luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json diff --git a/luci-proto-modemmanager/Makefile b/luci-proto-modemmanager/Makefile deleted file mode 100644 index c2718dd0a..000000000 --- a/luci-proto-modemmanager/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright (C) 2008-2014 The LuCI Team -# -# This is free software, licensed under the Apache License, Version 2.0 . -# - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=Support for ModemManager -LUCI_DEPENDS:=+modemmanager - -include ../../luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js b/luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js deleted file mode 100644 index 501f75964..000000000 --- a/luci-proto-modemmanager/htdocs/luci-static/resources/protocol/modemmanager.js +++ /dev/null @@ -1,139 +0,0 @@ -'use strict'; -'require fs'; -'require form'; -'require network'; - -function getModemList() { - return fs.exec_direct('/usr/bin/mmcli', [ '-L' ]).then(function(res) { - var lines = (res || '').split(/\n/), - tasks = []; - - for (var i = 0; i < lines.length; i++) { - var m = lines[i].match(/\/Modem\/(\d+)/); - if (m) - tasks.push(fs.exec_direct('/usr/bin/mmcli', [ '-m', m[1] ])); - } - - return Promise.all(tasks).then(function(res) { - var modems = []; - - for (var i = 0; i < res.length; i++) { - var man = res[i].match(/manufacturer: ([^\n]+)/), - mod = res[i].match(/model: ([^\n]+)/), - dev = res[i].match(/device: ([^\n]+)/); - - if (dev) { - modems.push({ - device: dev[1].trim(), - manufacturer: (man ? man[1].trim() : '') || '?', - model: (mod ? mod[1].trim() : '') || dev[1].trim() - }); - } - } - - return modems; - }); - }); -} - -network.registerPatternVirtual(/^mobiledata-.+$/); -network.registerErrorCode('MM_CONNECT_FAILED', _('Connection attempt failed.')); -network.registerErrorCode('MM_DISCONNECT_IN_PROGRESS', _('Modem disconnection in progress. Please wait.')); -network.registerErrorCode('MM_CONNECT_IN_PROGRESS', _('Modem connection in progress. Please wait. This process will timeout after 2 minutes.')); -network.registerErrorCode('MM_TEARDOWN_IN_PROGRESS', _('Modem bearer teardown in progress.')); -network.registerErrorCode('MM_MODEM_DISABLED', _('Modem is disabled.')); -network.registerErrorCode('DEVICE_NOT_MANAGED', _('Device not managed by ModemManager.')); -network.registerErrorCode('INVALID_BEARER_LIST', _('Invalid bearer list. Possibly too many bearers created. This protocol supports one and only one bearer.')); -network.registerErrorCode('UNKNOWN_METHOD', _('Unknown and unsupported connection method.')); -network.registerErrorCode('DISCONNECT_FAILED', _('Disconnection attempt failed.')); - -return network.registerProtocol('modemmanager', { - getI18n: function() { - return _('ModemManager'); - }, - - getIfname: function() { - return this._ubus('l3_device') || 'modemmanager-%s'.format(this.sid); - }, - - getOpkgPackage: function() { - return 'modemmanager'; - }, - - isFloating: function() { - return true; - }, - - isVirtual: function() { - return true; - }, - - getDevices: function() { - return null; - }, - - containsDevice: function(ifname) { - return (network.getIfnameOf(ifname) == this.getIfname()); - }, - - renderFormOptions: function(s) { - var dev = this.getL3Device() || this.getDevice(), o; - - o = s.taboption('general', form.ListValue, '_modem_device', _('Modem device')); - o.ucioption = 'device'; - o.rmempty = false; - o.load = function(section_id) { - return getModemList().then(L.bind(function(devices) { - for (var i = 0; i < devices.length; i++) - this.value(devices[i].device, - '%s - %s'.format(devices[i].manufacturer, devices[i].model)); - return form.Value.prototype.load.apply(this, [section_id]); - }, this)); - }; - - o = s.taboption('general', form.Value, 'apn', _('APN')); - o.validate = function(section_id, value) { - if (value == null || value == '') - return true; - - if (!/^[a-zA-Z0-9\-.]*[a-zA-Z0-9]$/.test(value)) - return _('Invalid APN provided'); - - return true; - }; - - o = s.taboption('general', form.Value, 'pincode', _('PIN')); - o.datatype = 'and(uinteger,minlength(4),maxlength(8))'; - - o = s.taboption('general', form.ListValue, 'auth', _('Authentication Type')); - o.value('both', _('PAP/CHAP (both)')); - o.value('pap', 'PAP'); - o.value('chap', 'CHAP'); - o.value('none', _('None')); - o.default = 'none'; - - o = s.taboption('general', form.Value, 'username', _('PAP/CHAP username')); - o.depends('auth', 'pap'); - o.depends('auth', 'chap'); - o.depends('auth', 'both'); - - o = s.taboption('general', form.Value, 'password', _('PAP/CHAP password')); - o.depends('auth', 'pap'); - o.depends('auth', 'chap'); - o.depends('auth', 'both'); - o.password = true; - - o = s.taboption('general', form.ListValue, 'iptype', _('IP Type')); - o.value('ipv4v6', _('IPv4/IPv6 (both - defaults to IPv4)')) - o.value('ipv4', _('IPv4 only')); - o.value('ipv6', _('IPv6 only')); - o.default = 'ipv4v6'; - - o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU')); - o.placeholder = dev ? (dev.getMTU() || '1500') : '1500'; - o.datatype = 'max(9200)'; - - o = s.taboption('general', form.Value, 'signalrate', _('Signal Refresh Rate'), _("In seconds")); - o.datatype = 'uinteger'; - } -}); diff --git a/luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json b/luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json deleted file mode 100644 index 716f4c465..000000000 --- a/luci-proto-modemmanager/root/usr/share/rpcd/acl.d/luci-proto-modemmanager.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "luci-proto-modemmanager": { - "description": "Grant access to mmcli", - "read": { - "cgi-io": [ "exec" ], - "file": { - "/usr/bin/mmcli -L": [ "exec" ], - "/usr/bin/mmcli -m [0-9]": [ "exec" ] - } - } - } -} From a7f85b4572ab0ea07ea0cae7b2ba3f870ca03d3c Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 27 Apr 2022 16:42:58 +0800 Subject: [PATCH 07/26] Update Makefile --- frp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frp/Makefile b/frp/Makefile index 0ea29e37c..5a662ebdd 100644 --- a/frp/Makefile +++ b/frp/Makefile @@ -20,7 +20,7 @@ GO_PKG:=github.com/fatedier/frp GO_PKG_BUILD_PKG:=github.com/fatedier/frp/cmd/... include $(INCLUDE_DIR)/package.mk -include ../../lang/golang/golang-package.mk +include /golang/golang-package.mk define Package/frp/install $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR)) From d5f24e92ebac8311550facf2d00c29b28232e3ea Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 27 Apr 2022 21:03:39 +0800 Subject: [PATCH 08/26] del frp --- frp/Makefile | 70 ------------------------------- frp/files/frpc.config | 23 ---------- frp/files/frpc.init | 84 ------------------------------------- frp/files/frpc.uci-defaults | 19 --------- frp/files/frps.config | 16 ------- frp/files/frps.init | 82 ------------------------------------ 6 files changed, 294 deletions(-) delete mode 100644 frp/Makefile delete mode 100644 frp/files/frpc.config delete mode 100644 frp/files/frpc.init delete mode 100644 frp/files/frpc.uci-defaults delete mode 100644 frp/files/frps.config delete mode 100644 frp/files/frps.init diff --git a/frp/Makefile b/frp/Makefile deleted file mode 100644 index 5a662ebdd..000000000 --- a/frp/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=frp -PKG_VERSION:=0.39.0 -PKG_RELEASE:=$(AUTORELEASE) - -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:=https://codeload.github.com/fatedier/frp/tar.gz/v${PKG_VERSION}? -PKG_HASH:=639ad416587b03751569b0d51c097bcc52727643e0656064843efb5d0b08ba72 - -PKG_MAINTAINER:=Richard Yu -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/fatedier/frp -GO_PKG_BUILD_PKG:=github.com/fatedier/frp/cmd/... - -include $(INCLUDE_DIR)/package.mk -include /golang/golang-package.mk - -define Package/frp/install - $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR)) - - $(INSTALL_DIR) $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(2) $(1)/usr/bin/ - $(INSTALL_DIR) $(1)/etc/frp/$(2).d/ - $(INSTALL_DATA) $(PKG_BUILD_DIR)/conf/$(2)_full.ini $(1)/etc/frp/$(2).d/ - $(INSTALL_DIR) $(1)/etc/config/ - $(INSTALL_CONF) ./files/$(2).config $(1)/etc/config/$(2) - $(INSTALL_DIR) $(1)/etc/init.d/ - $(INSTALL_BIN) ./files/$(2).init $(1)/etc/init.d/$(2) - - if [ -r ./files/$(2).uci-defaults ]; then \ - $(INSTALL_DIR) $(1)/etc/uci-defaults; \ - $(INSTALL_DATA) ./files/$(2).uci-defaults $(1)/etc/uci-defaults/$(2); \ - fi -endef - -define Package/frp/template - define Package/$(1) - SECTION:=net - CATEGORY:=Network - SUBMENU:=Web Servers/Proxies - TITLE:=$(1) - fast reverse proxy $(2) - URL:=https://github.com/fatedier/frp - DEPENDS:=$(GO_ARCH_DEPENDS) - endef - - define Package/$(1)/description - $(1) is a fast reverse proxy $(2) to help you expose a local server behind - a NAT or firewall to the internet. - endef - - define Package/$(1)/conffiles -/etc/config/$(1) - endef - - define Package/$(1)/install - $(call Package/frp/install,$$(1),$(1)) - endef -endef - -$(eval $(call Package/frp/template,frpc,client)) -$(eval $(call Package/frp/template,frps,server)) -$(eval $(call BuildPackage,frpc)) -$(eval $(call BuildPackage,frps)) diff --git a/frp/files/frpc.config b/frp/files/frpc.config deleted file mode 100644 index 492e224ff..000000000 --- a/frp/files/frpc.config +++ /dev/null @@ -1,23 +0,0 @@ -config init - option stdout 1 - option stderr 1 - option user frpc - option group frpc - option respawn 1 -# OS environments pass to frp for config file template, see -# https://github.com/fatedier/frp#configuration-file-template -# list env 'ENV_NAME=value' -# Config files include in temporary config file. -# list conf_inc '/etc/frp/frpc.d/frpc_full.ini' - -config conf 'common' - option server_addr 127.0.0.1 - option server_port 7000 -# List options with name="_" will be directly appended to config file -# list _ '# Key-A=Value-A' - -config conf 'ssh' - option type tcp - option local_ip 127.0.0.1 - option local_port 22 - option remote_port 6000 diff --git a/frp/files/frpc.init b/frp/files/frpc.init deleted file mode 100644 index e7f06edbd..000000000 --- a/frp/files/frpc.init +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=99 -USE_PROCD=1 - -NAME=frpc -PROG=/usr/bin/$NAME - -_err() { - echo "$*" >&2 - logger -p daemon.err -t "$NAME" "$*" -} - -config_cb() { - [ $# -eq 0 ] && return - - local type="$1" - local name="$2" - if [ "$type" = "conf" ]; then - echo "[$name]" >> "$conf_file" - option_cb() { - local option="$1" - local value="$2" - [ "$option" = "name" ] && \ - sed -i "s/$CONFIG_SECTION/$value/g" "$conf_file" || \ - echo "$option = $value" >> "$conf_file"; - } - list_cb() { - local name="$1" - local value="$2" - [ "$name" = "_" ] && echo "$value" >> "$conf_file" - } - else - [ "$type" = "init" ] && init_cfg="$name" - option_cb() { return 0; } - list_cb() { return 0; } - fi -} - -service_triggers() -{ - procd_add_reload_trigger "$NAME" -} - -start_service() { - local init_cfg=" " - local conf_file="/var/etc/$NAME.ini" - - > "$conf_file" - config_load "$NAME" - - local stdout stderr user group respawn env conf_inc - uci_validate_section "$NAME" init "$init_cfg" \ - 'stdout:bool:1' \ - 'stderr:bool:1' \ - 'user:string' \ - 'group:string' \ - 'respawn:bool:1' \ - 'env:list(string)' \ - 'conf_inc:list(string)' - - local err=$? - [ $err -ne 0 ] && { - _err "uci_validate_section returned $err" - return 1 - } - - [ -n "$conf_inc" ] && config_list_foreach "$init_cfg" conf_inc cat >> "$conf_file" - - procd_open_instance - procd_set_param command "$PROG" -c "$conf_file" - procd_set_param stdout $stdout - procd_set_param stderr $stderr - [ -n "$user" ] && procd_set_param user "$user" - [ -n "$group" ] && procd_set_param group "$group" - [ $respawn -eq 1 ] && procd_set_param respawn - [ -n "$env" ] && config_list_foreach "$init_cfg" env "procd_append_param env" - procd_close_instance -} - -reload_service() { - stop - start -} diff --git a/frp/files/frpc.uci-defaults b/frp/files/frpc.uci-defaults deleted file mode 100644 index 4883a2d8c..000000000 --- a/frp/files/frpc.uci-defaults +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -. /lib/functions.sh - -upgrade() { - local section=$1 - local name - [ "$section" != "common" ] || return 0 - config_get name $section name - if [ -z "$name" ]; then - uci_set frpc "$section" name "$section" - uci_commit frpc - fi -} - -config_load frpc -config_foreach upgrade conf - -exit 0 diff --git a/frp/files/frps.config b/frp/files/frps.config deleted file mode 100644 index ae0bffc2f..000000000 --- a/frp/files/frps.config +++ /dev/null @@ -1,16 +0,0 @@ -config init - option stdout 1 - option stderr 1 - option user frps - option group frps - option respawn 1 -# OS environments pass to frp for config file template, see -# https://github.com/fatedier/frp#configuration-file-template -# list env 'ENV_NAME=value' -# Config files include in temporary config file. -# list conf_inc '/etc/frp/frps.d/frps_full.ini' - -config conf 'common' - option bind_port 7000 -# List options with name="_" will be directly appended to config file -# list _ '# Key-A=Value-A' diff --git a/frp/files/frps.init b/frp/files/frps.init deleted file mode 100644 index b87525cd2..000000000 --- a/frp/files/frps.init +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=99 -USE_PROCD=1 - -NAME=frps -PROG=/usr/bin/$NAME - -_err() { - echo "$*" >&2 - logger -p daemon.err -t "$NAME" "$*" -} - -config_cb() { - [ $# -eq 0 ] && return - - local type="$1" - local name="$2" - if [ "$type" = "conf" ]; then - echo "[$name]" >> "$conf_file" - option_cb() { - local option="$1" - local value="$2" - echo "$option = $value" >> "$conf_file" - } - list_cb() { - local name="$1" - local value="$2" - [ "$name" = "_" ] && echo "$value" >> "$conf_file" - } - else - [ "$type" = "init" ] && init_cfg="$name" - option_cb() { return 0; } - list_cb() { return 0; } - fi -} - -service_triggers() -{ - procd_add_reload_trigger "$NAME" -} - -start_service() { - local init_cfg=" " - local conf_file="/var/etc/$NAME.ini" - - > "$conf_file" - config_load "$NAME" - - local stdout stderr user group respawn env conf_inc - uci_validate_section "$NAME" init "$init_cfg" \ - 'stdout:bool:1' \ - 'stderr:bool:1' \ - 'user:string' \ - 'group:string' \ - 'respawn:bool:1' \ - 'env:list(string)' \ - 'conf_inc:list(string)' - - local err=$? - [ $err -ne 0 ] && { - _err "uci_validate_section returned $err" - return 1 - } - - [ -n "$conf_inc" ] && config_list_foreach "$init_cfg" conf_inc cat >> "$conf_file" - - procd_open_instance - procd_set_param command "$PROG" -c "$conf_file" - procd_set_param stdout $stdout - procd_set_param stderr $stderr - [ -n "$user" ] && procd_set_param user "$user" - [ -n "$group" ] && procd_set_param group "$group" - [ $respawn -eq 1 ] && procd_set_param respawn - [ -n "$env" ] && config_list_foreach "$init_cfg" env "procd_append_param env" - procd_close_instance -} - -reload_service() { - stop - start -} From ace85ed78c5d5e9575809e08b7ee21cdd2390426 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 03:02:11 +0800 Subject: [PATCH 09/26] add theme --- luci-theme-ezengreen/Makefile | 16 + .../htdocs/luci-static/ezengreen/cascade.css | 2027 +++++++++++++++++ .../htdocs/luci-static/ezengreen/ezenlink.png | Bin 0 -> 553 bytes .../htdocs/luci-static/ezengreen/favicon.ico | Bin 0 -> 4286 bytes .../htdocs/luci-static/ezengreen/footer.png | Bin 0 -> 836 bytes .../htdocs/luci-static/ezengreen/mobile.css | 61 + .../luci-static/ezengreen/outdoorrouter.png | Bin 0 -> 1353 bytes .../luasrc/view/themes/ezengreen/footer.htm | 29 + .../luasrc/view/themes/ezengreen/header.htm | 206 ++ .../etc/uci-defaults/30_luci-theme-ezengreen | 7 + luci-theme-lamatel/Makefile | 16 + .../htdocs/luci-static/lamatel/cascade.css | 2022 ++++++++++++++++ .../htdocs/luci-static/lamatel/ezenlink.png | Bin 0 -> 553 bytes .../htdocs/luci-static/lamatel/favicon.ico | Bin 0 -> 762 bytes .../htdocs/luci-static/lamatel/footer.png | Bin 0 -> 2698 bytes .../htdocs/luci-static/lamatel/logo.png | Bin 0 -> 15943 bytes .../htdocs/luci-static/lamatel/mobile.css | 61 + .../luasrc/view/themes/lamatel/footer.htm | 29 + .../luasrc/view/themes/lamatel/header.htm | 206 ++ .../etc/uci-defaults/30_luci-theme-lametal | 7 + 20 files changed, 4687 insertions(+) create mode 100644 luci-theme-ezengreen/Makefile create mode 100755 luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css create mode 100755 luci-theme-ezengreen/htdocs/luci-static/ezengreen/ezenlink.png create mode 100755 luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.ico create mode 100755 luci-theme-ezengreen/htdocs/luci-static/ezengreen/footer.png create mode 100755 luci-theme-ezengreen/htdocs/luci-static/ezengreen/mobile.css create mode 100755 luci-theme-ezengreen/htdocs/luci-static/ezengreen/outdoorrouter.png create mode 100644 luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm create mode 100644 luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm create mode 100755 luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen create mode 100644 luci-theme-lamatel/Makefile create mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/cascade.css create mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/ezenlink.png create mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/favicon.ico create mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/footer.png create mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/logo.png create mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/mobile.css create mode 100644 luci-theme-lamatel/luasrc/view/themes/lamatel/footer.htm create mode 100644 luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm create mode 100755 luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal diff --git a/luci-theme-ezengreen/Makefile b/luci-theme-ezengreen/Makefile new file mode 100644 index 000000000..dc4a25974 --- /dev/null +++ b/luci-theme-ezengreen/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Ezengreen Theme +LUCI_DEPENDS:= + +PKG_LICENSE:=Apache-2.0 + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature 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/ezenlink.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/ezenlink.png new file mode 100755 index 0000000000000000000000000000000000000000..070a12b7da56ad334a98ffb87ca1a382af985ca4 GIT binary patch literal 553 zcmV+^0@nSBP)5Rm*L{Kop!rxswj!voA{raViK6tZ*v8R6tTepaO_o zK%jz<3ScijlMX@!jz*fb7UN%5LM!a|X5Y-td%h{l5<`};@jZaZ<;8JG{Ov%{2>=2f zjE$E=aylzEHXZ{Y&?A5!fj0+a};rI%Z*jv2iL{ zMgq8CqI=*$2EfYY1rNJ&#m0k@fwA!kz*?8~dk$t1{z70E8s|4@}f?f1JGsh-A*IZ+iaOa7=K r8C)FHmOJQUD(bA18eYuZ#s%OHNQeZcR0cH!00000NkvXXu0mjf(L3<` literal 0 HcmV?d00001 diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.ico b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..dd14062c9b9520f0de40f938a7cfa0ecc0edc154 GIT binary patch literal 4286 zcmeHHJ5Iwu5M3%tvJDcVz;u*8f+a4HirPo;4cI_I3Zw{$CRJKGAHg+Mj$mq<$Q=ce zdC!`0R+i(~2|^TJ^jObl=gqveW6TNug23>Zj8AB;4%?Ff3*-B*Qmg#!2eR< z;`K8IBJHZhPFmtq&A*#phCl?=U%1$Tms7_P3xJq0)&)x95L~^=?%Qz7N%1V5ct3Q9IyS=|P{_Q}6eY=TUFv z)zsRt#1<0E#nyMRvgz~JA@iet?(uVey@%NISKq6b>wI2)K7?P->JAQS?mX@lW1f$9 zQ~y@zIqu+}01k-7?z|7?uoe&rsJE|&a)v-au18Vx?>;EajH$xWNFbst{M z>B*mJZR~uGfl6QO2~cyZU+eGN!5;uQkTJK}&#v>}nF1N0daQ?Xx7BXrM_t~%6L5Z= zSGgDPwZ3m{99_O0{7pXPU4b{~sy8$SetsV*Q2n;@JUDpA8NfNILo~GRm_I5oDljVW z*9w#!Yq@-Wx7N(JnB)1wyx5s7>;v$1U08QpTK81i*=cFN&&tAG0rzF`*im^K`T>j! BrMdtB literal 0 HcmV?d00001 diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/footer.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/footer.png new file mode 100755 index 0000000000000000000000000000000000000000..c7e2e393ac0c035c9a41f7e9d095bd11c4099971 GIT binary patch literal 836 zcmV-K1H1f*P)s+)P~w1iKdod zscmgBclR0#Sg?&vEJUVn^1i)(IdXxJpLs9u?q+vpXJ@`|cJpR99AZ)8d^j>!S(>!f zrSoAMz#c#E;xkK=yLpygSn$q=&j5D$d6lKfCG{HsS^(BcOm6|)WNGqe)-~VG74f)y zkS~3I0MMIaw*}zP`EcfZ*qLR)cXI^$BFWO^5kS-Vu*vyWi7Ej5u8NNeH(}K~&(fs3 zl;E8Yw&+fT#tS!*V_p2%Mz#sJ3f1Pj<$Sn!4oWj)o`Ihb!<|S@=R*@fjnnS4G--*= zdx26vOOq!say}f8)XI&kX$g8w=0C~;bpY*W=9@GXBF={aE07a4OOv0@hYo;-%-wZ9 zJlfbKr;8-)L}8^i3S(;pqHc2oJ$9yhnY$myR~|fxcWMw|P(>md)*H@;V}q9woRHIb zU&)U#nF}X{HEv>5Rc_!`#t-nn z1F1gmJfq;vf%Bm~>)qld!tT+|(!_}WjTs)$)L?ncLkvplLYDQU9S>ek%)^+8WeACC zfi$EQRtj0}ObAr3&hZq_gV!T@ebI4SMeX>Hm6cW)E1(s>k@roR-xYsVtcb8pc9MNo zHvVC;fUY@hO$e%oQ$^nOoLOIb@XS!Hpsov+HPF$;t#D~m2>&hmUv}opAQ&?`%c=cj zZVY}P&pzM#1$`9FK(|CcdgmQpZNV$?r2npJA8pDYG#0#FoGjSWST;U$eKg3@#0X{W z&K&2b9q--NDeR7~EzfLYpSI_j*jVQ=KR*f^I;Z}-=**|->`%%a0Q>{Ia7QjydhGlF O0000 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/ezengreen/outdoorrouter.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/outdoorrouter.png new file mode 100755 index 0000000000000000000000000000000000000000..eddd6fafc97aa5e1335be1e9673bd2744df721ca GIT binary patch literal 1353 zcmV-P1-AN$P)jV4QdPygHcHhKUX``hBV)c zf;JJ|IF_7ay|MY5gt59o+qQiHl|A&Q@X=|tGacK5UKG4o8<55BiD<-E(Exuba`6H! zFQ9B^@a}(J6b!v65TjrlR#s4dzw!GmB6{?qU|a;aWd*fKM7IFfT=NaqIRUurxd+>N zxUbt#l?G|}Y+W-zf!w_EFgJ){SpEbNFXkvqMThW}F29)g* z^66cSK}y1yJ@y!!tQkM^)22zR=0=BG@N(B^F5yZY2Aq+Su;li=j7<`<` z$_i>;V=sJgiTxyunFdZ3z01IkvTE6~f_lB-_l(%@O8_w)fb%6_>!69XR!UHlFzzB; zuW*^_>Tkv+E)mizUJLGQD&K3d)LOUrMu}=Rs2M@cJTt0xraSLpB3xH2CH9-(Rn6)E zwh0eSug&8ZN_%mkcU{FnZchcEW89G2b&s<_ZKs0XWk@{3B#arW25|Yg&mCSn zvVn3nZd~44+J*`eMjC|ix@w9$Q1HmH(CDs!Fa0!Mf?sci;^2fgK`IJLnf*~w-GS51 z^*}^_yeOD>QP9&gB|vb=CaE`}^((|&@)0YlLx8*hSDLT}*h_&1CQ8z3Nt^ePD=H4> zpI#J*-6jB=hc7j6UCA+@p`xlgg#JiT1t+!|fVWC#V{TAqgIb&Wovb^dNB7cDQGG|P zewwPPTzXWi``gO*Brlc(e?`k~`)sI$j+9WXE6GdKoJ*k%fTeYpHp+y* zCfo~q;h;!^*!Pu;-L=CNU`gC66*?<#%-E+HAHAQ-k@jqjX%Q$LO-rS#)I1VBwN%EL z*^2_MjuKo?N>k)TkwQ`ul0dBp9e)YbCH^iQr~vQ5YU|a}6j{m6kWF?|zn=;n)@$d|KQUnJJhch;j=m5?MwgigGLI6 z^AD`e8^>L$W9`@)<2;AwE}mC9V#Yi^noiG?k{2rs^RB`2? + Copyright 2008 Jo-Philipp Wich + Copyright 2012 David Menting + Licensed to the public under the Apache License 2.0. +-%> + +<% + local ver = require "luci.version" + local disp = require "luci.dispatcher" + local request = disp.context.path + local category = request[1] + local tree = disp.node() + local categories = disp.node_childs(tree) +%> + + + + + 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 100644 index 000000000..4b5875d75 --- /dev/null +++ b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm @@ -0,0 +1,206 @@ +<%# + 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 request = disp.context.path + local request2 = disp.context.request + + local category = request[1] + local cattree = category and disp.node(category) + + local leaf = request2[#request2] + + local tree = disp.node() + local node = disp.context.dispatched + + local categories = disp.node_childs(tree) + + local c = tree + local i, r + + -- tag all nodes leading to this page + for i, r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end + end + + -- send as HTML5 + http.prepare_content("text/html") + + local function nodeurl(prefix, name, query) + local u = url(prefix, name) + if query then + u = u .. http.build_querystring(query) + end + return pcdata(u) + end + + local function render_tabmenu(prefix, node, level) + if not level then + level = 1 + end + + local childs = disp.node_childs(node) + if #childs > 0 then + if level > 2 then + write('
    ') + end + + local selected_node + local selected_name + local i, v + + for i, v in ipairs(childs) do + local nnode = node.nodes[v] + if nnode._menu_selected then + selected_node = nnode + selected_name = v + end + + if level > 2 then + write('
  • %s
  • ' %{ + v, (nnode._menu_selected or (node.leaf and v == leaf)) and 'active' or '', + nodeurl(prefix, v, nnode.query), + striptags(translate(nnode.title)) + }) + end + end + + if level > 2 then + write('
') + end + + if selected_node then + render_tabmenu(prefix .. "/" .. selected_name, selected_node, level + 1) + end + end + end + + local function render_submenu(prefix, node) + local childs = disp.node_childs(node) + if #childs > 0 then + write('') + end + end + + local function render_topmenu() + local childs = disp.node_childs(cattree) + if #childs > 0 then + write('') + end + end + + local function render_changes() + -- calculate the number of unsaved changes + if tree.nodes[category] and tree.nodes[category].ucidata then + local ucichanges = 0 + + local i, j + for i, j in pairs(require("luci.model.uci").cursor():changes()) do + ucichanges = ucichanges + #j + end + + if ucichanges > 0 then + write('%s: %d' %{ + url(category, 'uci/changes'), + http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")), + translate('Unsaved Changes'), + ucichanges + }) + end + end + end +-%> + + + + + <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI + + + + + <% if node and node.css then %> + + <% end -%> + <% if css then %> + + <% end -%> + + + + + +
+
+
+ <%=boardinfo.hostname or "?"%> + <% render_topmenu() %> +
+ +
+
+
+
+ +
+ <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%> +
+

<%:No password set!%>

+

<%:You are using the default router password. Please custom your router password to protect the web interface and enable SSH.%>

+ +
+ <%- end -%> + + + + <% if category then render_tabmenu(category, cattree) end %> diff --git a/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen b/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen new file mode 100755 index 000000000..ad238fc36 --- /dev/null +++ b/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen @@ -0,0 +1,7 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.Ezengreen=/luci-static/ezengreen + set luci.main.mediaurlbase=/luci-static/ezengreen + commit luci +EOF +exit 0 diff --git a/luci-theme-lamatel/Makefile b/luci-theme-lamatel/Makefile new file mode 100644 index 000000000..530c15e06 --- /dev/null +++ b/luci-theme-lamatel/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=Lamatel Theme +LUCI_DEPENDS:= + +PKG_LICENSE:=Apache-2.0 + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/cascade.css b/luci-theme-lamatel/htdocs/luci-static/lamatel/cascade.css new file mode 100755 index 000000000..26bc66806 --- /dev/null +++ b/luci-theme-lamatel/htdocs/luci-static/lamatel/cascade.css @@ -0,0 +1,2022 @@ +/*! + * 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: #f6943e; + 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: #3f3f45; +} + +header h3 a:hover, header .brand:hover, header ul .active > a { + background-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: #3f3f45; + font-size: 24px; + font-weight: 440; + line-height: 1; +} + +header p { + margin: 0; + line-height: 40px; +} + +header .fill { + background-color: #e5e5e6; + background-repeat: repeat-x; + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.05); + 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 { + text-decoration: none; +} + +header div > ul .active > a, .nav .active > a { + background-color: #fff; +} + +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: #fff; +} + +header div > ul .menu-dropdown, +.nav .menu-dropdown, +header div > ul .dropdown-menu, +.nav .dropdown-menu { + background-color: #bebec0; +} + +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: #3f3f45; +} + +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: #e5e5e6; + background-repeat: repeat-x; + color: #3f3f45; +} + +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), inset 0 1px rgba(0, 0, 0, 0); +} + +.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: #f6943e; + color: #f6943e; +} + +.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: #f6943e; +} + +.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 #f6943e; +} + +.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: #f6943e; +} + +.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: #f6943e; +} + +.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-lamatel/htdocs/luci-static/lamatel/ezenlink.png b/luci-theme-lamatel/htdocs/luci-static/lamatel/ezenlink.png new file mode 100755 index 0000000000000000000000000000000000000000..070a12b7da56ad334a98ffb87ca1a382af985ca4 GIT binary patch literal 553 zcmV+^0@nSBP)5Rm*L{Kop!rxswj!voA{raViK6tZ*v8R6tTepaO_o zK%jz<3ScijlMX@!jz*fb7UN%5LM!a|X5Y-td%h{l5<`};@jZaZ<;8JG{Ov%{2>=2f zjE$E=aylzEHXZ{Y&?A5!fj0+a};rI%Z*jv2iL{ zMgq8CqI=*$2EfYY1rNJ&#m0k@fwA!kz*?8~dk$t1{z70E8s|4@}f?f1JGsh-A*IZ+iaOa7=K r8C)FHmOJQUD(bA18eYuZ#s%OHNQeZcR0cH!00000NkvXXu0mjf(L3<` literal 0 HcmV?d00001 diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/favicon.ico b/luci-theme-lamatel/htdocs/luci-static/lamatel/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..674d8e5d07076e5561c1dcd1cddd8d0bd59941bb GIT binary patch literal 762 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 Ef*7h5cmMzZ literal 0 HcmV?d00001 diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/logo.png b/luci-theme-lamatel/htdocs/luci-static/lamatel/logo.png new file mode 100755 index 0000000000000000000000000000000000000000..2b7dd1c511d4c240a5245adca08486001309338a GIT binary patch literal 15943 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 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-lamatel/luasrc/view/themes/lamatel/footer.htm b/luci-theme-lamatel/luasrc/view/themes/lamatel/footer.htm new file mode 100644 index 000000000..eb0994f74 --- /dev/null +++ b/luci-theme-lamatel/luasrc/view/themes/lamatel/footer.htm @@ -0,0 +1,29 @@ +<%# + 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" + local disp = require "luci.dispatcher" + local request = disp.context.path + local category = request[1] + local tree = disp.node() + local categories = disp.node_childs(tree) +%> + +
+ + + diff --git a/luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm b/luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm new file mode 100644 index 000000000..cf042bb8c --- /dev/null +++ b/luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm @@ -0,0 +1,206 @@ +<%# + 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 request = disp.context.path + local request2 = disp.context.request + + local category = request[1] + local cattree = category and disp.node(category) + + local leaf = request2[#request2] + + local tree = disp.node() + local node = disp.context.dispatched + + local categories = disp.node_childs(tree) + + local c = tree + local i, r + + -- tag all nodes leading to this page + for i, r in ipairs(request) do + if c.nodes and c.nodes[r] then + c = c.nodes[r] + c._menu_selected = true + end + end + + -- send as HTML5 + http.prepare_content("text/html") + + local function nodeurl(prefix, name, query) + local u = url(prefix, name) + if query then + u = u .. http.build_querystring(query) + end + return pcdata(u) + end + + local function render_tabmenu(prefix, node, level) + if not level then + level = 1 + end + + local childs = disp.node_childs(node) + if #childs > 0 then + if level > 2 then + write('
    ') + end + + local selected_node + local selected_name + local i, v + + for i, v in ipairs(childs) do + local nnode = node.nodes[v] + if nnode._menu_selected then + selected_node = nnode + selected_name = v + end + + if level > 2 then + write('
  • %s
  • ' %{ + v, (nnode._menu_selected or (node.leaf and v == leaf)) and 'active' or '', + nodeurl(prefix, v, nnode.query), + striptags(translate(nnode.title)) + }) + end + end + + if level > 2 then + write('
') + end + + if selected_node then + render_tabmenu(prefix .. "/" .. selected_name, selected_node, level + 1) + end + end + end + + local function render_submenu(prefix, node) + local childs = disp.node_childs(node) + if #childs > 0 then + write('') + end + end + + local function render_topmenu() + local childs = disp.node_childs(cattree) + if #childs > 0 then + write('') + end + end + + local function render_changes() + -- calculate the number of unsaved changes + if tree.nodes[category] and tree.nodes[category].ucidata then + local ucichanges = 0 + + local i, j + for i, j in pairs(require("luci.model.uci").cursor():changes()) do + ucichanges = ucichanges + #j + end + + if ucichanges > 0 then + write('%s: %d' %{ + url(category, 'uci/changes'), + http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")), + translate('Unsaved Changes'), + ucichanges + }) + end + end + end +-%> + + + + + <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI + + + + + <% if node and node.css then %> + + <% end -%> + <% if css then %> + + <% end -%> + + + + + +
+
+
+ Outdoor Router + <% render_topmenu() %> +
+ +
+
+
+
+ +
+ <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%> +
+

<%:No password set!%>

+

<%:You are using the default router password. Please custom your router password to protect the web interface and enable SSH.%>

+ +
+ <%- end -%> + + + + <% if category then render_tabmenu(category, cattree) end %> diff --git a/luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal b/luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal new file mode 100755 index 000000000..3c64379bd --- /dev/null +++ b/luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal @@ -0,0 +1,7 @@ +#!/bin/sh +uci batch <<-EOF + set luci.themes.lamtel=/luci-static/lamatel + set luci.main.mediaurlbase=/luci-static/lamatel + commit luci +EOF +exit 0 From 5439846e5a57a4034e1213facabed69217e920d4 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 03:26:59 +0800 Subject: [PATCH 10/26] fix --- luci-theme-ezengreen/Makefile | 2 +- luci-theme-lamatel/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/luci-theme-ezengreen/Makefile b/luci-theme-ezengreen/Makefile index dc4a25974..9930ce2c4 100644 --- a/luci-theme-ezengreen/Makefile +++ b/luci-theme-ezengreen/Makefile @@ -11,6 +11,6 @@ LUCI_DEPENDS:= PKG_LICENSE:=Apache-2.0 -include ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature diff --git a/luci-theme-lamatel/Makefile b/luci-theme-lamatel/Makefile index 530c15e06..988e850c7 100644 --- a/luci-theme-lamatel/Makefile +++ b/luci-theme-lamatel/Makefile @@ -11,6 +11,6 @@ LUCI_DEPENDS:= PKG_LICENSE:=Apache-2.0 -include ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature From ee5ed3827aa469344fa8b1612f4be78bc2e51859 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 14:08:52 +0800 Subject: [PATCH 11/26] Update 30_luci-theme-ezengreen --- .../root/etc/uci-defaults/30_luci-theme-ezengreen | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen b/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen index ad238fc36..3b96c4239 100755 --- a/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen +++ b/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen @@ -1,7 +1,12 @@ #!/bin/sh -uci batch <<-EOF - set luci.themes.Ezengreen=/luci-static/ezengreen - set luci.main.mediaurlbase=/luci-static/ezengreen - commit luci -EOF + +if [ "$PKG_UPGRADE" != 1 ]; then + uci get luci.themes.ezengreen >/dev/null 2>&1 || \ + uci batch <<-EOF + set luci.themes.ezengreen=/luci-static/ezengreen + set luci.main.mediaurlbase=/luci-static/ezengreen + commit luci + EOF +fi + exit 0 From f6819bdfa9f33fa73be48db0482a592ce1bd147d Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 14:27:36 +0800 Subject: [PATCH 12/26] Update header.htm --- .../luasrc/view/themes/ezengreen/header.htm | 142 +----------------- 1 file changed, 4 insertions(+), 138 deletions(-) diff --git a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm index 4b5875d75..e4a3d9cfd 100644 --- a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm +++ b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm @@ -4,153 +4,19 @@ 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 ver = require "luci.version" - local boardinfo = util.ubus("system", "board") + local boardinfo = util.ubus("system", "board") or { } - local request = disp.context.path - local request2 = disp.context.request - - local category = request[1] - local cattree = category and disp.node(category) - - local leaf = request2[#request2] - - local tree = disp.node() local node = disp.context.dispatched + local path = table.concat(disp.context.path, "-") - local categories = disp.node_childs(tree) - - local c = tree - local i, r - - -- tag all nodes leading to this page - for i, r in ipairs(request) do - if c.nodes and c.nodes[r] then - c = c.nodes[r] - c._menu_selected = true - end - end - - -- send as HTML5 - http.prepare_content("text/html") - - local function nodeurl(prefix, name, query) - local u = url(prefix, name) - if query then - u = u .. http.build_querystring(query) - end - return pcdata(u) - end - - local function render_tabmenu(prefix, node, level) - if not level then - level = 1 - end - - local childs = disp.node_childs(node) - if #childs > 0 then - if level > 2 then - write('
    ') - end - - local selected_node - local selected_name - local i, v - - for i, v in ipairs(childs) do - local nnode = node.nodes[v] - if nnode._menu_selected then - selected_node = nnode - selected_name = v - end - - if level > 2 then - write('
  • %s
  • ' %{ - v, (nnode._menu_selected or (node.leaf and v == leaf)) and 'active' or '', - nodeurl(prefix, v, nnode.query), - striptags(translate(nnode.title)) - }) - end - end - - if level > 2 then - write('
') - end - - if selected_node then - render_tabmenu(prefix .. "/" .. selected_name, selected_node, level + 1) - end - end - end - - local function render_submenu(prefix, node) - local childs = disp.node_childs(node) - if #childs > 0 then - write('') - end - end - - local function render_topmenu() - local childs = disp.node_childs(cattree) - if #childs > 0 then - write('') - end - end - - local function render_changes() - -- calculate the number of unsaved changes - if tree.nodes[category] and tree.nodes[category].ucidata then - local ucichanges = 0 - - local i, j - for i, j in pairs(require("luci.model.uci").cursor():changes()) do - ucichanges = ucichanges + #j - end - - if ucichanges > 0 then - write('%s: %d' %{ - url(category, 'uci/changes'), - http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")), - translate('Unsaved Changes'), - ucichanges - }) - end - end - end + http.prepare_content("text/html; charset=UTF-8") -%> From 02df59a6f7a9e2e312d243c13a79ad174499c89a Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 22:10:16 +0800 Subject: [PATCH 13/26] fix ezengreen --- luci-theme-ezengreen/Makefile | 6 +- .../cascade.css | 0 .../luci-static/openmptcprouter/favicon.png | Bin 0 -> 8175 bytes .../luci-static/openmptcprouter/html5.js | 3 + .../{ezengreen => openmptcprouter}/mobile.css | 0 .../openmptcprouter/omr-logo-apple.png | Bin 0 -> 8175 bytes .../resources/menu-openmptcprouter.js | 118 ++++++++++ .../openmptcprouter/images}/cascade.css | 45 ++-- .../openmptcprouter/images}/ezenlink.png | Bin .../openmptcprouter/images}/favicon.ico | Bin .../openmptcprouter/images}/footer.png | Bin .../openmptcprouter/images}/mobile.css | 0 .../openmptcprouter/images/omr-logo.png | Bin 0 -> 19149 bytes .../openmptcprouter/images}/outdoorrouter.png | Bin .../luasrc/view/themes/ezengreen/footer.htm | 29 --- .../luasrc/view/themes/ezengreen/header.htm | 72 ------ .../view/themes/openmptcprouter/footer.htm | 19 ++ .../view/themes/openmptcprouter/header.htm | 90 ++++++++ ...i-theme-ezengreen => luci-theme-ezengreen} | 4 +- luci-theme-lamatel/Makefile | 16 -- .../htdocs/luci-static/lamatel/ezenlink.png | Bin 553 -> 0 bytes .../htdocs/luci-static/lamatel/favicon.ico | Bin 762 -> 0 bytes .../htdocs/luci-static/lamatel/footer.png | Bin 2698 -> 0 bytes .../htdocs/luci-static/lamatel/logo.png | Bin 15943 -> 0 bytes .../luasrc/view/themes/lamatel/footer.htm | 29 --- .../luasrc/view/themes/lamatel/header.htm | 206 ------------------ .../etc/uci-defaults/30_luci-theme-lametal | 7 - 27 files changed, 259 insertions(+), 385 deletions(-) mode change 100644 => 100755 luci-theme-ezengreen/Makefile rename luci-theme-ezengreen/htdocs/luci-static/{ezengreen => openmptcprouter}/cascade.css (100%) create mode 100755 luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/favicon.png create mode 100755 luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/html5.js rename luci-theme-ezengreen/htdocs/luci-static/{ezengreen => openmptcprouter}/mobile.css (100%) create mode 100755 luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/omr-logo-apple.png create mode 100755 luci-theme-ezengreen/htdocs/luci-static/resources/menu-openmptcprouter.js rename {luci-theme-lamatel/htdocs/luci-static/lamatel => luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images}/cascade.css (98%) rename luci-theme-ezengreen/htdocs/luci-static/{ezengreen => resources/openmptcprouter/images}/ezenlink.png (100%) rename luci-theme-ezengreen/htdocs/luci-static/{ezengreen => resources/openmptcprouter/images}/favicon.ico (100%) rename luci-theme-ezengreen/htdocs/luci-static/{ezengreen => resources/openmptcprouter/images}/footer.png (100%) rename {luci-theme-lamatel/htdocs/luci-static/lamatel => luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images}/mobile.css (100%) create mode 100755 luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/omr-logo.png rename luci-theme-ezengreen/htdocs/luci-static/{ezengreen => resources/openmptcprouter/images}/outdoorrouter.png (100%) delete mode 100644 luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm delete mode 100644 luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm create mode 100755 luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/footer.htm create mode 100755 luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm rename luci-theme-ezengreen/root/etc/uci-defaults/{30_luci-theme-ezengreen => luci-theme-ezengreen} (65%) delete mode 100644 luci-theme-lamatel/Makefile delete mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/ezenlink.png delete mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/favicon.ico delete mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/footer.png delete mode 100755 luci-theme-lamatel/htdocs/luci-static/lamatel/logo.png delete mode 100644 luci-theme-lamatel/luasrc/view/themes/lamatel/footer.htm delete mode 100644 luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm delete mode 100755 luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal diff --git a/luci-theme-ezengreen/Makefile b/luci-theme-ezengreen/Makefile old mode 100644 new mode 100755 index 9930ce2c4..ee17e224f --- a/luci-theme-ezengreen/Makefile +++ b/luci-theme-ezengreen/Makefile @@ -1,16 +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 +LUCI_TITLE:=ezengreen Theme (default) LUCI_DEPENDS:= -PKG_LICENSE:=Apache-2.0 - +#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/cascade.css b/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/cascade.css similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css rename to luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/cascade.css diff --git a/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/favicon.png b/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/favicon.png new file mode 100755 index 0000000000000000000000000000000000000000..7ee7779108d5a958e17f305962fef3f5715fbafd GIT binary patch literal 8175 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.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"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 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-lamatel/htdocs/luci-static/lamatel/cascade.css b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/cascade.css similarity index 98% rename from luci-theme-lamatel/htdocs/luci-static/lamatel/cascade.css rename to luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/cascade.css index 26bc66806..740adc320 100755 --- a/luci-theme-lamatel/htdocs/luci-static/lamatel/cascade.css +++ b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/cascade.css @@ -192,7 +192,7 @@ body { } a { - color: #f6943e; + color: #215e21; text-decoration: none; line-height: inherit; font-weight: inherit; @@ -745,11 +745,13 @@ header { } header a { - color: #3f3f45; + color: #c4c4c4; } header h3 a:hover, header .brand:hover, header ul .active > a { - background-color: #fff; + background-color: #333; + background-color: rgba(0, 0, 0, 0.33); + color: #fff; text-decoration: none; } @@ -762,9 +764,9 @@ header h3 a, header .brand { display: block; padding: 16px 20px 16px; margin-left: -20px; - color: #3f3f45; + color: #fff; font-size: 24px; - font-weight: 440; + font-weight: 333; line-height: 1; } @@ -774,9 +776,9 @@ header p { } header .fill { - background-color: #e5e5e6; + background-color: #215e21; background-repeat: repeat-x; - box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.33), inset 0 -1px 0 rgba(0, 0, 0, 0.1); padding: 0 5px; } @@ -804,11 +806,13 @@ header div > ul a, .nav a { } header div > ul a:hover, .nav a:hover { + color: #fff; text-decoration: none; } header div > ul .active > a, .nav .active > a { - background-color: #fff; + background-color: #222; + background-color: rgba(0, 0, 0, 0.33); } header div > ul.secondary-nav, .nav.secondary-nav { @@ -833,14 +837,15 @@ header div > ul .dropdown-toggle:hover, .nav .dropdown-toggle:hover, header div > ul .dropdown.open .dropdown-toggle, .nav .dropdown.open .dropdown-toggle { - background: #fff; + 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: #bebec0; + background-color: #003300; } header div > ul .menu-dropdown a.menu, @@ -870,16 +875,16 @@ 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: #3f3f45; + 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: #e5e5e6; + background-color: #215e21; background-repeat: repeat-x; - color: #3f3f45; + color: #fff; } header div > ul .menu-dropdown .active a, @@ -957,7 +962,7 @@ header .dropdown-menu a.hover, background-repeat: repeat-x; color: #404040; text-decoration: none; - box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0), inset 0 1px rgba(0, 0, 0, 0); + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.025), inset 0 -1px rgba(0, 0, 0, 0.025); } .open .menu, @@ -1227,8 +1232,8 @@ footer { .cbi-button-apply, .cbi-button-reload, .cbi-button-edit { - border-color: #f6943e; - color: #f6943e; + border-color: #4aa44b; + color: #4aa44b; } .cbi-button-negative, @@ -1255,7 +1260,7 @@ footer { .cbi-page-actions .cbi-button-apply, .cbi-section-actions .cbi-button-edit { color: #fff; - background: #f6943e; + background: #4aa44b; } .cbi-button-positive.important, @@ -1287,7 +1292,7 @@ footer { } .cbi-dropdown:focus { - outline: 2px solid #f6943e; + outline: 2px solid #4b6e9b; } .cbi-dropdown > ul { @@ -1630,7 +1635,7 @@ a.label:hover { } .label.success { - background-color: #f6943e; + background-color: #46a546; } .label.notice { @@ -1920,7 +1925,7 @@ table table td, div.cbi-value var, .td.cbi-value-field var { font-style: italic; - color: #f6943e; + color: #215e21; } .uci-change-list { diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/ezenlink.png b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/ezenlink.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/ezengreen/ezenlink.png rename to luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/ezenlink.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.ico b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/favicon.ico similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.ico rename to luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/favicon.ico diff --git a/luci-theme-ezengreen/htdocs/luci-static/ezengreen/footer.png b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/footer.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/ezengreen/footer.png rename to luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/footer.png diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/mobile.css b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/mobile.css similarity index 100% rename from luci-theme-lamatel/htdocs/luci-static/lamatel/mobile.css rename to luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/mobile.css diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/omr-logo.png b/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/omr-logo.png new file mode 100755 index 0000000000000000000000000000000000000000..3d532aec038b0c7bf504b1583606b1139a43a037 GIT binary patch literal 19149 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

bVaUL}!q88y{QQ?r(PMb$$ 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 - Copyright 2008 Jo-Philipp Wich - Copyright 2012 David Menting - Licensed to the public under the Apache License 2.0. --%> - -<% - local ver = require "luci.version" - local disp = require "luci.dispatcher" - local request = disp.context.path - local category = request[1] - local tree = disp.node() - local categories = disp.node_childs(tree) -%> -

-
- - - diff --git a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm deleted file mode 100644 index e4a3d9cfd..000000000 --- a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm +++ /dev/null @@ -1,72 +0,0 @@ -<%# - 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 ver = require "luci.version" - - local boardinfo = util.ubus("system", "board") or { } - - local node = disp.context.dispatched - local path = table.concat(disp.context.path, "-") - - http.prepare_content("text/html; charset=UTF-8") --%> - - - - - <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI - - - - - <% if node and node.css then %> - - <% end -%> - <% if css then %> - - <% end -%> - - - - - -
-
-
- <%=boardinfo.hostname or "?"%> - <% render_topmenu() %> -
- -
-
-
-
- -
- <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%> -
-

<%:No password set!%>

-

<%:You are using the default router password. Please custom your router password to protect the web interface and enable SSH.%>

- -
- <%- end -%> - - - - <% if category then render_tabmenu(category, cattree) end %> diff --git a/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/footer.htm b/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/footer.htm new file mode 100755 index 000000000..0fdd0e4d3 --- /dev/null +++ b/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/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/openmptcprouter/header.htm b/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm new file mode 100755 index 000000000..932764c24 --- /dev/null +++ b/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/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 -%> + + + + + "> +
+
+
+ openmptcprouter businessOpenMPTCProuter + +
+
+
+
+ +
+ <%- 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/30_luci-theme-ezengreen b/luci-theme-ezengreen/root/etc/uci-defaults/luci-theme-ezengreen similarity index 65% rename from luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen rename to luci-theme-ezengreen/root/etc/uci-defaults/luci-theme-ezengreen index 3b96c4239..e1c8313d2 100755 --- a/luci-theme-ezengreen/root/etc/uci-defaults/30_luci-theme-ezengreen +++ b/luci-theme-ezengreen/root/etc/uci-defaults/luci-theme-ezengreen @@ -1,12 +1,10 @@ #!/bin/sh -if [ "$PKG_UPGRADE" != 1 ]; then - uci get luci.themes.ezengreen >/dev/null 2>&1 || \ +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/luci-theme-lamatel/Makefile b/luci-theme-lamatel/Makefile deleted file mode 100644 index 988e850c7..000000000 --- a/luci-theme-lamatel/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (C) 2008-2014 The LuCI Team -# -# This is free software, licensed under the Apache License, Version 2.0 . -# - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=Lamatel Theme -LUCI_DEPENDS:= - -PKG_LICENSE:=Apache-2.0 - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/ezenlink.png b/luci-theme-lamatel/htdocs/luci-static/lamatel/ezenlink.png deleted file mode 100755 index 070a12b7da56ad334a98ffb87ca1a382af985ca4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 553 zcmV+^0@nSBP)5Rm*L{Kop!rxswj!voA{raViK6tZ*v8R6tTepaO_o zK%jz<3ScijlMX@!jz*fb7UN%5LM!a|X5Y-td%h{l5<`};@jZaZ<;8JG{Ov%{2>=2f zjE$E=aylzEHXZ{Y&?A5!fj0+a};rI%Z*jv2iL{ zMgq8CqI=*$2EfYY1rNJ&#m0k@fwA!kz*?8~dk$t1{z70E8s|4@}f?f1JGsh-A*IZ+iaOa7=K r8C)FHmOJQUD(bA18eYuZ#s%OHNQeZcR0cH!00000NkvXXu0mjf(L3<` diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/favicon.ico b/luci-theme-lamatel/htdocs/luci-static/lamatel/favicon.ico deleted file mode 100755 index 674d8e5d07076e5561c1dcd1cddd8d0bd59941bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 762 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 Ef*7h5cmMzZ diff --git a/luci-theme-lamatel/htdocs/luci-static/lamatel/logo.png b/luci-theme-lamatel/htdocs/luci-static/lamatel/logo.png deleted file mode 100755 index 2b7dd1c511d4c240a5245adca08486001309338a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15943 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 - Copyright 2008 Jo-Philipp Wich - Copyright 2012 David Menting - Licensed to the public under the Apache License 2.0. --%> - -<% - local ver = require "luci.version" - local disp = require "luci.dispatcher" - local request = disp.context.path - local category = request[1] - local tree = disp.node() - local categories = disp.node_childs(tree) -%> - -
- - - diff --git a/luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm b/luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm deleted file mode 100644 index cf042bb8c..000000000 --- a/luci-theme-lamatel/luasrc/view/themes/lamatel/header.htm +++ /dev/null @@ -1,206 +0,0 @@ -<%# - 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 request = disp.context.path - local request2 = disp.context.request - - local category = request[1] - local cattree = category and disp.node(category) - - local leaf = request2[#request2] - - local tree = disp.node() - local node = disp.context.dispatched - - local categories = disp.node_childs(tree) - - local c = tree - local i, r - - -- tag all nodes leading to this page - for i, r in ipairs(request) do - if c.nodes and c.nodes[r] then - c = c.nodes[r] - c._menu_selected = true - end - end - - -- send as HTML5 - http.prepare_content("text/html") - - local function nodeurl(prefix, name, query) - local u = url(prefix, name) - if query then - u = u .. http.build_querystring(query) - end - return pcdata(u) - end - - local function render_tabmenu(prefix, node, level) - if not level then - level = 1 - end - - local childs = disp.node_childs(node) - if #childs > 0 then - if level > 2 then - write('
    ') - end - - local selected_node - local selected_name - local i, v - - for i, v in ipairs(childs) do - local nnode = node.nodes[v] - if nnode._menu_selected then - selected_node = nnode - selected_name = v - end - - if level > 2 then - write('
  • %s
  • ' %{ - v, (nnode._menu_selected or (node.leaf and v == leaf)) and 'active' or '', - nodeurl(prefix, v, nnode.query), - striptags(translate(nnode.title)) - }) - end - end - - if level > 2 then - write('
') - end - - if selected_node then - render_tabmenu(prefix .. "/" .. selected_name, selected_node, level + 1) - end - end - end - - local function render_submenu(prefix, node) - local childs = disp.node_childs(node) - if #childs > 0 then - write('') - end - end - - local function render_topmenu() - local childs = disp.node_childs(cattree) - if #childs > 0 then - write('') - end - end - - local function render_changes() - -- calculate the number of unsaved changes - if tree.nodes[category] and tree.nodes[category].ucidata then - local ucichanges = 0 - - local i, j - for i, j in pairs(require("luci.model.uci").cursor():changes()) do - ucichanges = ucichanges + #j - end - - if ucichanges > 0 then - write('%s: %d' %{ - url(category, 'uci/changes'), - http.urlencode(http.formvalue('redir') or table.concat(disp.context.request, "/")), - translate('Unsaved Changes'), - ucichanges - }) - end - end - end --%> - - - - - <%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI - - - - - <% if node and node.css then %> - - <% end -%> - <% if css then %> - - <% end -%> - - - - - -
-
-
- Outdoor Router - <% render_topmenu() %> -
- -
-
-
-
- -
- <%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%> -
-

<%:No password set!%>

-

<%:You are using the default router password. Please custom your router password to protect the web interface and enable SSH.%>

- -
- <%- end -%> - - - - <% if category then render_tabmenu(category, cattree) end %> diff --git a/luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal b/luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal deleted file mode 100755 index 3c64379bd..000000000 --- a/luci-theme-lamatel/root/etc/uci-defaults/30_luci-theme-lametal +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -uci batch <<-EOF - set luci.themes.lamtel=/luci-static/lamatel - set luci.main.mediaurlbase=/luci-static/lamatel - commit luci -EOF -exit 0 From 6e4bf6d2df96e01c3a8b545a47d4e5de07aa9a58 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 22:30:47 +0800 Subject: [PATCH 14/26] fix --- r8152/Makefile | 55 ++++++++++++++ .../100-add-LED-configuration-from-OF.patch | 74 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 r8152/Makefile create mode 100644 r8152/patches/100-add-LED-configuration-from-OF.patch diff --git a/r8152/Makefile b/r8152/Makefile new file mode 100644 index 000000000..9e199e273 --- /dev/null +++ b/r8152/Makefile @@ -0,0 +1,55 @@ +# +# Download realtek r8152 linux driver from official site: +# [https://www.realtek.com/en/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-usb-3-0-software] +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=r8152 +PKG_VERSION:=2.15.20211119 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/wget/realtek-r8152-linux/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=b7926db3b4ca71d453ac1cf875d7a8ab409ece108edc6913e8bc1c0c3b99179d + +PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/realtek-$(PKG_NAME)-linux-$(PKG_VERSION) + +PKG_BUILD_PARALLEL:=1 + +PKG_MAINTAINER:=Tianling Shen + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/usb-net-rtl8152-vendor + TITLE:=Kernel module for USB-to-Ethernet Realtek convertors + SUBMENU:=USB Support + VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)-$(BOARD)-$(PKG_RELEASE) + DEPENDS:=+kmod-usb-net + CONFLICTS:=kmod-usb-net-rtl8152 + FILES:= $(PKG_BUILD_DIR)/r8152.ko + AUTOLOAD:=$(call AutoProbe,r8152) +endef + +define KernelPackage/usb-net-rtl8152-vendor/description + Kernel module for Realtek RTL8152/RTL8153 Based USB Ethernet Adapters +endef + +R8152_MAKEOPTS= -C $(PKG_BUILD_DIR) \ + PATH="$(TARGET_PATH)" \ + ARCH="$(LINUX_KARCH)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + TARGET="$(HAL_TARGET)" \ + TOOLPREFIX="$(KERNEL_CROSS)" \ + TOOLPATH="$(KERNEL_CROSS)" \ + KERNELPATH="$(LINUX_DIR)" \ + KERNELDIR="$(LINUX_DIR)" \ + LDOPTS=" " \ + DOMULTI=1 + +define Build/Compile + +$(MAKE) $(PKG_JOBS) $(R8152_MAKEOPTS) modules +endef + +$(eval $(call KernelPackage,usb-net-rtl8152-vendor)) diff --git a/r8152/patches/100-add-LED-configuration-from-OF.patch b/r8152/patches/100-add-LED-configuration-from-OF.patch new file mode 100644 index 000000000..38d885d72 --- /dev/null +++ b/r8152/patches/100-add-LED-configuration-from-OF.patch @@ -0,0 +1,74 @@ +From 82985725e071f2a5735052f18e109a32aeac3a0b Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sun, 26 Jul 2020 02:38:31 +0200 +Subject: [PATCH] add LED configuration from OF + +This adds the ability to configure the LED configuration register using +OF. This way, the correct value for board specific LED configuration can +be determined. + +Signed-off-by: David Bauer +--- + r8152.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +--- a/r8152.c ++++ b/r8152.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -9804,6 +9805,22 @@ static void rtl_tally_reset(struct r8152 + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); + } + ++static int r8152_led_configuration(struct r8152 *tp) ++{ ++ u32 led_data; ++ int ret; ++ ++ ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data", ++ &led_data); ++ ++ if (ret) ++ return ret; ++ ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data); ++ ++ return 0; ++} ++ + static void r8152b_init(struct r8152 *tp) + { + u32 ocp_data; +@@ -9865,6 +9882,8 @@ static void r8152b_init(struct r8152 *tp + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); ++ ++ r8152_led_configuration(tp); + } + + static void r8153_init(struct r8152 *tp) +@@ -10008,6 +10027,8 @@ static void r8153_init(struct r8152 *tp) + tp->coalesce = COALESCE_SLOW; + break; + } ++ ++ r8152_led_configuration(tp); + } + + static void r8153b_init(struct r8152 *tp) +@@ -10098,6 +10119,8 @@ static void r8153b_init(struct r8152 *tp + rtl_tally_reset(tp); + + tp->coalesce = 15000; /* 15 us */ ++ ++ r8152_led_configuration(tp); + } + + static void r8153c_init(struct r8152 *tp) From d2b275ab2100632655ba6d58dfc3ce6af980979c Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 23:12:43 +0800 Subject: [PATCH 15/26] fix --- .../favicon.png => ezengreen/1omr-logo-apple.png} | Bin .../{openmptcprouter => ezengreen}/cascade.css | 0 .../omr-logo-apple.png => ezengreen/favicon.png} | Bin .../{openmptcprouter => ezengreen}/html5.js | 0 .../{openmptcprouter => ezengreen}/mobile.css | 0 .../images/cascade.css | 0 .../images/ezenlink.png | Bin .../images/favicon.ico | Bin .../images/footer.png | Bin .../images/mobile.css | 0 .../images/omr-logo.png | Bin .../images/outdoorrouter.png | Bin .../{menu-openmptcprouter.js => menu-ezengreen.js} | 0 .../luasrc/view/themes/openmptcprouter/header.htm | 4 ++-- 14 files changed, 2 insertions(+), 2 deletions(-) rename luci-theme-ezengreen/htdocs/luci-static/{openmptcprouter/favicon.png => ezengreen/1omr-logo-apple.png} (100%) rename luci-theme-ezengreen/htdocs/luci-static/{openmptcprouter => ezengreen}/cascade.css (100%) rename luci-theme-ezengreen/htdocs/luci-static/{openmptcprouter/omr-logo-apple.png => ezengreen/favicon.png} (100%) rename luci-theme-ezengreen/htdocs/luci-static/{openmptcprouter => ezengreen}/html5.js (100%) rename luci-theme-ezengreen/htdocs/luci-static/{openmptcprouter => ezengreen}/mobile.css (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/cascade.css (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/ezenlink.png (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/favicon.ico (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/footer.png (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/mobile.css (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/omr-logo.png (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{openmptcprouter => ezengreen}/images/outdoorrouter.png (100%) rename luci-theme-ezengreen/htdocs/luci-static/resources/{menu-openmptcprouter.js => menu-ezengreen.js} (100%) diff --git a/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/favicon.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/1omr-logo-apple.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/favicon.png rename to luci-theme-ezengreen/htdocs/luci-static/ezengreen/1omr-logo-apple.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/cascade.css b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/cascade.css rename to luci-theme-ezengreen/htdocs/luci-static/ezengreen/cascade.css diff --git a/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/omr-logo-apple.png b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/omr-logo-apple.png rename to luci-theme-ezengreen/htdocs/luci-static/ezengreen/favicon.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/html5.js b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/html5.js similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/html5.js rename to luci-theme-ezengreen/htdocs/luci-static/ezengreen/html5.js diff --git a/luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/mobile.css b/luci-theme-ezengreen/htdocs/luci-static/ezengreen/mobile.css similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/openmptcprouter/mobile.css rename to luci-theme-ezengreen/htdocs/luci-static/ezengreen/mobile.css diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/cascade.css b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/cascade.css similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/cascade.css rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/cascade.css diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/ezenlink.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/ezenlink.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/ezenlink.png rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/ezenlink.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/favicon.ico b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/favicon.ico similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/favicon.ico rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/favicon.ico diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/footer.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/footer.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/footer.png rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/footer.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/mobile.css b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/mobile.css similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/mobile.css rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/mobile.css diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/omr-logo.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/omr-logo.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/omr-logo.png rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/omr-logo.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/outdoorrouter.png b/luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/outdoorrouter.png similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/openmptcprouter/images/outdoorrouter.png rename to luci-theme-ezengreen/htdocs/luci-static/resources/ezengreen/images/outdoorrouter.png diff --git a/luci-theme-ezengreen/htdocs/luci-static/resources/menu-openmptcprouter.js b/luci-theme-ezengreen/htdocs/luci-static/resources/menu-ezengreen.js similarity index 100% rename from luci-theme-ezengreen/htdocs/luci-static/resources/menu-openmptcprouter.js rename to luci-theme-ezengreen/htdocs/luci-static/resources/menu-ezengreen.js diff --git a/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm b/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm index 932764c24..1dff61219 100755 --- a/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm +++ b/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm @@ -35,7 +35,7 @@ - + <% if node and node.css then %> <% end -%> @@ -50,7 +50,7 @@
From 079ffbbf319729b7d7a0d26a795cd8f65b4bebfb Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 23:23:56 +0800 Subject: [PATCH 16/26] Update outdoorrouter.png --- .../ezengreen/images/outdoorrouter.png | Bin 1353 -> 3815 bytes 1 file changed, 0 insertions(+), 0 deletions(-) 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 index eddd6fafc97aa5e1335be1e9673bd2744df721ca..9debc9b21e55fbe23e27430ae0af39124f204143 100755 GIT binary patch literal 3815 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 GOZW$!hAhAU delta 1326 zcmV+}1=0HF9mxuiEPoIH00j^M_k!yp000F0Nkl>NS5FA}yjxQh~vHb$L z7g!Dy8@~XYC?PQSg2OL39FQn6et~hUz}yRLzu>rpgy75zbTw43ODr>sgb_yeRHjV z4QdPygHcHhKUX``hBV)cf;JJ|IF_7ay|MY5gt59o+qQiHl|A&Q@X=|tGacK5UKG4o z8<55BiD<-E(Exuba`6H!FQ9B^@a}(J6b!v65TjrlR#s4dzw!GmB6{?qU|a;aWd*fK zM7IFfT=NaqIe!7T?70WqdbqFKT4E*v zgz*HDYyl2Du!&7@0n9vo=S2ZWK=&=ltWZ#)J%>b8$Ix}PGwl|6PulczN*|LIqz2Wza*zZdK zF&%*OC4XS+poz6sN>Gz9?jl^TaGC1rZ^k7q5z;GO3+`+x-)phdTDSN{iE1{e89~iF zGpcr`JMUp4Tvse5_M6~U&FTQQ2@g%L&EpqJdvT$6UBy9ePX(Z3+>qOKkF!B-r-I&P zNIb(Nj2YB#@MNtoPyyGjl)Tt9Ny}E&(ZD9*-+vbL=Pxvx_sRfp4-s|mc(@xy9ds2+ zX}Jo6O+eK+W$!>W25|Yg&mCSnvVn3nZd~44+J*`eMjC|ix@w9$Q1HmH(CDs!Fa0!M zf?sci;^2fgK`IJLnf*~w-GS51^*}^_yeOD>QP9&gB|vb=CaE`}^((|&@)0YlLx8*h zSAUwY2G~o11|~|~1NBg=|9Nvwz<^V7|1ERYppc<(uOhGM)jCVC>>2prK{9D5($W|S;@|jO?Fe{&;|<|AT>|yd1B&DD~nQr3LspsP_`tGRd`U!BNAXzUXdi& zD^HirQ?sZMX^sSz#Fx@MNv}Jb@?`@xiyD#MHOP80u@z1JSx!@TS{;@R)GTl0NqSS_ zPw9+lD{s#jP_;uWX*|!|ZQC%zdw-~zj*)Xv!dhKw+X7UahT0-odq8RISvgUaN;;`2 zA!X;e{evKTv_2@?g?%y#v$=9*ZROdtd3MCi)Avn>zn=;n)@$d|KQUnJJhch;j=m5?MwgigGLI6^AD`e8^>L$W9`@)<2;AwE}mC9VkgEtKAKL? klad!J4D+tR^6w|2{~(+n+w$k-?EnA(07*qoM6N<$f``jt<8 From be247ee0a9de8d76a11428c935cf0a7de21a623f Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Tue, 24 May 2022 23:48:22 +0800 Subject: [PATCH 17/26] fix --- .../luasrc/view/themes/{openmptcprouter => ezengreen}/footer.htm | 0 .../luasrc/view/themes/{openmptcprouter => ezengreen}/header.htm | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename luci-theme-ezengreen/luasrc/view/themes/{openmptcprouter => ezengreen}/footer.htm (100%) rename luci-theme-ezengreen/luasrc/view/themes/{openmptcprouter => ezengreen}/header.htm (100%) diff --git a/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/footer.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm similarity index 100% rename from luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/footer.htm rename to luci-theme-ezengreen/luasrc/view/themes/ezengreen/footer.htm diff --git a/luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm similarity index 100% rename from luci-theme-ezengreen/luasrc/view/themes/openmptcprouter/header.htm rename to luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm From b1ba99574e5210cca262061ae928a8eb99cc8dae Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Wed, 25 May 2022 00:48:45 +0800 Subject: [PATCH 18/26] Update header.htm --- luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm index 1dff61219..e5c4c9f97 100755 --- a/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm +++ b/luci-theme-ezengreen/luasrc/view/themes/ezengreen/header.htm @@ -50,7 +50,7 @@
From be190289ee326598afbbf57be23fa84f41451571 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 10:49:43 +0800 Subject: [PATCH 19/26] fix shoprtcut --- fast-classifier/Makefile | 59 ++++-- fast-classifier/src/Makefile | 0 fast-classifier/src/fast-classifier.c | 38 +++- fast-classifier/src/fast-classifier.h | 0 fast-classifier/src/nl_classifier_test.c | 0 fast-classifier/src/sfe.h | 114 ---------- fast-classifier/src/sfe_backport.h | 195 ----------------- fast-classifier/src/sfe_cm.h | 259 ----------------------- fast-classifier/src/userspace_example.c | 0 shortcut-fe/Makefile | 37 ++-- shortcut-fe/files/etc/init.d/shortcut-fe | 49 +++++ shortcut-fe/src/Kconfig | 3 +- shortcut-fe/src/Makefile | 1 + shortcut-fe/src/sfe.h | 0 shortcut-fe/src/sfe_backport.h | 2 +- shortcut-fe/src/sfe_cm.c | 160 +++++++++----- shortcut-fe/src/sfe_cm.h | 3 +- shortcut-fe/src/sfe_ipv4.c | 39 ++-- shortcut-fe/src/sfe_ipv6.c | 41 ++-- 19 files changed, 298 insertions(+), 702 deletions(-) mode change 100755 => 100644 fast-classifier/Makefile mode change 100755 => 100644 fast-classifier/src/Makefile mode change 100755 => 100644 fast-classifier/src/fast-classifier.c mode change 100755 => 100644 fast-classifier/src/fast-classifier.h mode change 100755 => 100644 fast-classifier/src/nl_classifier_test.c delete mode 100755 fast-classifier/src/sfe.h delete mode 100755 fast-classifier/src/sfe_backport.h delete mode 100755 fast-classifier/src/sfe_cm.h mode change 100755 => 100644 fast-classifier/src/userspace_example.c mode change 100755 => 100644 shortcut-fe/Makefile create mode 100755 shortcut-fe/files/etc/init.d/shortcut-fe mode change 100755 => 100644 shortcut-fe/src/Kconfig mode change 100755 => 100644 shortcut-fe/src/Makefile mode change 100755 => 100644 shortcut-fe/src/sfe.h mode change 100755 => 100644 shortcut-fe/src/sfe_backport.h mode change 100755 => 100644 shortcut-fe/src/sfe_cm.c mode change 100755 => 100644 shortcut-fe/src/sfe_cm.h mode change 100755 => 100644 shortcut-fe/src/sfe_ipv4.c mode change 100755 => 100644 shortcut-fe/src/sfe_ipv6.c diff --git a/fast-classifier/Makefile b/fast-classifier/Makefile old mode 100755 new mode 100644 index 29d024e7b..757d60e52 --- a/fast-classifier/Makefile +++ b/fast-classifier/Makefile @@ -1,43 +1,60 @@ +# +# Copyright (c) 2013-2018 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:=fast-classifier -PKG_RELEASE:=1 -PKG_CONFIG_DEPENDS := CONFIG_IPV6 +PKG_RELEASE:=3 include $(INCLUDE_DIR)/package.mk -define KernelPackage/$(PKG_NAME)/Default +define KernelPackage/fast-classifier/Default SECTION:=kernel CATEGORY:=Kernel modules SUBMENU:=Network Support DEPENDS:=+kmod-ipt-conntrack +kmod-shortcut-fe TITLE:=Kernel driver for FAST Classifier FILES:=$(PKG_BUILD_DIR)/fast-classifier.ko - KCONFIG:=CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y CONFIG_NF_CONNTRACK_MARK=y - PROVIDES:=$(PKG_NAME) + KCONFIG:= \ + CONFIG_NF_CONNTRACK_EVENTS=y \ + CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y \ + CONFIG_NF_CONNTRACK_MARK=y \ + CONFIG_XFRM=y + CONFLICTS:=kmod-shortcut-fe-drv kmod-shortcut-fe-cm endef -define KernelPackage/$(PKG_NAME) - $(call KernelPackage/$(PKG_NAME)/Default) +define KernelPackage/fast-classifier + $(call KernelPackage/fast-classifier/Default) endef -define KernelPackage/$(PKG_NAME)-noload - $(call KernelPackage/$(PKG_NAME)/Default) +define KernelPackage/fast-classifier-noload + $(call KernelPackage/fast-classifier/Default) endef -define KernelPackage/$(PKG_NAME)/Default/description +define KernelPackage/fast-classifier/Default/description FAST Classifier talks to SFE to make decisions about offloading connections endef -define KernelPackage/$(PKG_NAME)/description -$(call KernelPackage/$(PKG_NAME)/Default/description) +define KernelPackage/fast-classifier/description +$(call KernelPackage/fast-classifier/Default/description) endef -define KernelPackage/$(PKG_NAME)-noload/description -$(call KernelPackage/$(PKG_NAME)/Default/description) +define KernelPackage/fast-classifier-noload/description +$(call KernelPackage/fast-classifier/Default/description) -This package does not load $(PKG_NAME) at boot by default +This package does not load fast-classifier at boot by default endef define Package/fast-classifier-example @@ -50,15 +67,16 @@ Example user space program that communicates with fast classifier kernel module endef -SFE_MAKE_OPTS:=SFE_SUPPORT_IPV6=$(if $(CONFIG_IPV6),y,n) +HAVE_ECM:=$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-standard) define Build/Compile/kmod - +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" $(SFE_MAKE_OPTS) \ + +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ $(KERNEL_MAKE_FLAGS) \ $(PKG_MAKE_FLAGS) \ M="$(PKG_BUILD_DIR)" \ CONFIG_FAST_CLASSIFIER=m \ - EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + EXTRA_CFLAGS+="-DSFE_SUPPORT_IPV6" \ + $(if $(HAVE_ECM),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM" CONFIG_SFE_ECM=y,) \ modules endef @@ -81,12 +99,11 @@ define Build/InstallDev $(CP) $(PKG_BUILD_DIR)/fast-classifier.h $(1)/usr/include/ endef - define Package/fast-classifier-example/install $(INSTALL_DIR) $(1)/sbin $(CP) $(PKG_BUILD_DIR)/userspace_fast_classifier $(1)/sbin/ endef -$(eval $(call KernelPackage,$(PKG_NAME))) -$(eval $(call KernelPackage,$(PKG_NAME)-noload)) +$(eval $(call KernelPackage,fast-classifier)) +#$(eval $(call KernelPackage,fast-classifier-noload)) #$(eval $(call BuildPackage,fast-classifier-example)) diff --git a/fast-classifier/src/Makefile b/fast-classifier/src/Makefile old mode 100755 new mode 100644 diff --git a/fast-classifier/src/fast-classifier.c b/fast-classifier/src/fast-classifier.c old mode 100755 new mode 100644 index 7ca5d973b..746a0d6f9 --- a/fast-classifier/src/fast-classifier.c +++ b/fast-classifier/src/fast-classifier.c @@ -36,9 +36,9 @@ #include #include -#include "sfe_backport.h" -#include "sfe.h" -#include "sfe_cm.h" +#include +#include +#include #include "fast-classifier.h" typedef enum fast_classifier_exception { @@ -451,6 +451,10 @@ static u32 fc_conn_hash(sfe_ip_addr_t *saddr, sfe_ip_addr_t *daddr, */ static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, struct nf_conn *ct) { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + struct net *net=NULL ; + struct nf_tcp_net *tn=NULL; + #endif switch (p_sic->protocol) { case IPPROTO_TCP: p_sic->src_td_window_scale = ct->proto.tcp.seen[0].td_scale; @@ -461,8 +465,14 @@ static int fast_classifier_update_protocol(struct sfe_connection_create *p_sic, p_sic->dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; p_sic->dest_td_end = ct->proto.tcp.seen[1].td_end; p_sic->dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; - - if (nf_ct_tcp_no_window_check +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + net = nf_ct_net(ct); + tn = nf_tcp_pernet(net); + if ((tn&&tn->tcp_no_window_check) +#else + if (nf_ct_tcp_no_window_check +#endif + || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL) || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) { p_sic->flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; @@ -1744,8 +1754,11 @@ static int __init fast_classifier_init(void) { struct fast_classifier *sc = &__sc; int result = -1; +#ifdef CONFIG_SFE_ECM + int (*fast_recv)(struct sk_buff *skb); +#endif - printk(KERN_ALERT "fast-classifier (PBR safe v2.1.4a): starting up\n"); + printk(KERN_ALERT "fast-classifier: starting up\n"); DEBUG_INFO("SFE CM init\n"); hash_init(fc_conn_ht); @@ -1810,6 +1823,7 @@ static int __init fast_classifier_init(void) goto exit3; } +#ifdef CONFIG_NF_CONNTRACK_EVENTS /* * Register a notifier hook to get fast notifications of expired connections. */ @@ -1817,12 +1831,14 @@ static int __init fast_classifier_init(void) result = nf_conntrack_register_chain_notifier(&init_net, &fast_classifier_conntrack_notifier); #else result = nf_conntrack_register_notifier(&init_net, &fast_classifier_conntrack_notifier); +#endif if (result < 0) { DEBUG_ERROR("can't register nf notifier hook: %d\n", result); goto exit4; } #endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) result = genl_register_family(&fast_classifier_gnl_family); if (result) { @@ -1865,7 +1881,16 @@ static int __init fast_classifier_init(void) /* * Hook the receive path in the network stack. */ +#ifdef CONFIG_SFE_ECM + rcu_read_lock(); + fast_recv = rcu_dereference(athrs_fast_nat_recv); + rcu_read_unlock(); + if (!fast_recv) { + BUG_ON(athrs_fast_nat_recv); + } +#else BUG_ON(athrs_fast_nat_recv); +#endif RCU_INIT_POINTER(athrs_fast_nat_recv, fast_classifier_recv); /* @@ -1974,3 +1999,4 @@ module_exit(fast_classifier_exit) MODULE_DESCRIPTION("Shortcut Forwarding Engine - Connection Manager"); MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/fast-classifier/src/fast-classifier.h b/fast-classifier/src/fast-classifier.h old mode 100755 new mode 100644 diff --git a/fast-classifier/src/nl_classifier_test.c b/fast-classifier/src/nl_classifier_test.c old mode 100755 new mode 100644 diff --git a/fast-classifier/src/sfe.h b/fast-classifier/src/sfe.h deleted file mode 100755 index 279e7b3dc..000000000 --- a/fast-classifier/src/sfe.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * sfe.h - * Shortcut forwarding engine. - * - * Copyright (c) 2013-2017 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. - */ - - -/* - * The following are debug macros used throughout the SFE. - * - * The DEBUG_LEVEL enables the followings based on its value, - * when dynamic debug option is disabled. - * - * 0 = OFF - * 1 = ASSERTS / ERRORS - * 2 = 1 + WARN - * 3 = 2 + INFO - * 4 = 3 + TRACE - */ -#define DEBUG_LEVEL 2 - -#if (DEBUG_LEVEL < 1) -#define DEBUG_ASSERT(s, ...) -#define DEBUG_ERROR(s, ...) -#else -#define DEBUG_ASSERT(c, s, ...) if (!(c)) { pr_emerg("ASSERT: %s:%d:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__); BUG(); } -#define DEBUG_ERROR(s, ...) pr_err("%s:%d:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif - -#if defined(CONFIG_DYNAMIC_DEBUG) -/* - * Compile messages for dynamic enable/disable - */ -#define DEBUG_WARN(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define DEBUG_INFO(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define DEBUG_TRACE(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#else - -/* - * Statically compile messages at different levels - */ -#if (DEBUG_LEVEL < 2) -#define DEBUG_WARN(s, ...) -#else -#define DEBUG_WARN(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif - -#if (DEBUG_LEVEL < 3) -#define DEBUG_INFO(s, ...) -#else -#define DEBUG_INFO(s, ...) pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif - -#if (DEBUG_LEVEL < 4) -#define DEBUG_TRACE(s, ...) -#else -#define DEBUG_TRACE(s, ...) pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__) -#endif -#endif - -#ifdef CONFIG_NF_FLOW_COOKIE -typedef int (*flow_cookie_set_func_t)(u32 protocol, __be32 src_ip, __be16 src_port, - __be32 dst_ip, __be16 dst_port, u16 flow_cookie); -/* - * sfe_register_flow_cookie_cb - * register a function in SFE to let SFE use this function to configure flow cookie for a flow - * - * Hardware driver which support flow cookie should register a callback function in SFE. Then SFE - * can use this function to configure flow cookie for a flow. - * return: 0, success; !=0, fail - */ -int sfe_register_flow_cookie_cb(flow_cookie_set_func_t cb); - -/* - * sfe_unregister_flow_cookie_cb - * unregister function which is used to configure flow cookie for a flow - * - * return: 0, success; !=0, fail - */ -int sfe_unregister_flow_cookie_cb(flow_cookie_set_func_t cb); - -typedef int (*sfe_ipv6_flow_cookie_set_func_t)(u32 protocol, __be32 src_ip[4], __be16 src_port, - __be32 dst_ip[4], __be16 dst_port, u16 flow_cookie); - -/* - * sfe_ipv6_register_flow_cookie_cb - * register a function in SFE to let SFE use this function to configure flow cookie for a flow - * - * Hardware driver which support flow cookie should register a callback function in SFE. Then SFE - * can use this function to configure flow cookie for a flow. - * return: 0, success; !=0, fail - */ -int sfe_ipv6_register_flow_cookie_cb(sfe_ipv6_flow_cookie_set_func_t cb); - -/* - * sfe_ipv6_unregister_flow_cookie_cb - * unregister function which is used to configure flow cookie for a flow - * - * return: 0, success; !=0, fail - */ -int sfe_ipv6_unregister_flow_cookie_cb(sfe_ipv6_flow_cookie_set_func_t cb); - -#endif /*CONFIG_NF_FLOW_COOKIE*/ diff --git a/fast-classifier/src/sfe_backport.h b/fast-classifier/src/sfe_backport.h deleted file mode 100755 index 2f8c8ca3c..000000000 --- a/fast-classifier/src/sfe_backport.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * sfe_backport.h - * Shortcut forwarding engine compatible header file. - * - * Copyright (c) 2014-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 - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#include -#else -enum udp_conntrack { - UDP_CT_UNREPLIED, - UDP_CT_REPLIED, - UDP_CT_MAX -}; - -static inline unsigned int * -nf_ct_timeout_lookup(struct net *net, struct nf_conn *ct, - struct nf_conntrack_l4proto *l4proto) -{ -#ifdef CONFIG_NF_CONNTRACK_TIMEOUT - struct nf_conn_timeout *timeout_ext; - unsigned int *timeouts; - - timeout_ext = nf_ct_timeout_find(ct); - if (timeout_ext) - timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); - else - timeouts = l4proto->get_timeouts(net); - - return timeouts; -#else - return l4proto->get_timeouts(net); -#endif /*CONFIG_NF_CONNTRACK_TIMEOUT*/ -} -#endif /*KERNEL_VERSION(3, 7, 0)*/ -#endif /*KERNEL_VERSION(3, 4, 0)*/ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) -#define sfe_define_post_routing_hook(FN_NAME, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ -static unsigned int FN_NAME(void *priv, \ - struct sk_buff *SKB, \ - const struct nf_hook_state *state) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -#define sfe_define_post_routing_hook(FN_NAME, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ -static unsigned int FN_NAME(const struct nf_hook_ops *OPS, \ - struct sk_buff *SKB, \ - const struct net_device *UNUSED, \ - const struct net_device *OUT, \ - int (*OKFN)(struct sk_buff *)) -#else -#define sfe_define_post_routing_hook(FN_NAME, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ -static unsigned int FN_NAME(unsigned int HOOKNUM, \ - struct sk_buff *SKB, \ - const struct net_device *UNUSED, \ - const struct net_device *OUT, \ - int (*OKFN)(struct sk_buff *)) -#endif - -#define sfe_cm_ipv4_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ - sfe_define_post_routing_hook(__sfe_cm_ipv4_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) -#define sfe_cm_ipv6_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ - sfe_define_post_routing_hook(__sfe_cm_ipv6_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) -#define fast_classifier_ipv4_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ - sfe_define_post_routing_hook(__fast_classifier_ipv4_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) -#define fast_classifier_ipv6_post_routing_hook(HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) \ - sfe_define_post_routing_hook(__fast_classifier_ipv6_post_routing_hook, HOOKNUM, OPS, SKB, UNUSED, OUT, OKFN) - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) -#define SFE_IPV4_NF_POST_ROUTING_HOOK(fn) \ - { \ - .hook = fn, \ - .pf = NFPROTO_IPV4, \ - .hooknum = NF_INET_POST_ROUTING, \ - .priority = NF_IP_PRI_NAT_SRC + 1, \ - } -#else -#define SFE_IPV4_NF_POST_ROUTING_HOOK(fn) \ - { \ - .hook = fn, \ - .owner = THIS_MODULE, \ - .pf = NFPROTO_IPV4, \ - .hooknum = NF_INET_POST_ROUTING, \ - .priority = NF_IP_PRI_NAT_SRC + 1, \ - } -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) -#define SFE_IPV6_NF_POST_ROUTING_HOOK(fn) \ - { \ - .hook = fn, \ - .pf = NFPROTO_IPV6, \ - .hooknum = NF_INET_POST_ROUTING, \ - .priority = NF_IP_PRI_NAT_SRC + 1, \ - } -#else -#define SFE_IPV6_NF_POST_ROUTING_HOOK(fn) \ - { \ - .hook = fn, \ - .owner = THIS_MODULE, \ - .pf = NFPROTO_IPV6, \ - .hooknum = NF_INET_POST_ROUTING, \ - .priority = NF_IP6_PRI_NAT_SRC + 1, \ - } -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) -#define SFE_NF_CT_DEFAULT_ZONE (&nf_ct_zone_dflt) -#else -#define SFE_NF_CT_DEFAULT_ZONE NF_CT_DEFAULT_ZONE -#endif - -/* - * sfe_dev_get_master - * get master of bridge port, and hold it - */ -static inline struct net_device *sfe_dev_get_master(struct net_device *dev) -{ - struct net_device *master; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) - rcu_read_lock(); - master = netdev_master_upper_dev_get_rcu(dev); - if (master) - dev_hold(master); - - rcu_read_unlock(); -#else - master = dev->master; - if (master) - dev_hold(master); -#endif - return master; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -#define SFE_DEV_EVENT_PTR(PTR) netdev_notifier_info_to_dev(PTR) -#else -#define SFE_DEV_EVENT_PTR(PTR) (struct net_device *)(PTR) -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -#define SFE_NF_CONN_ACCT(NM) struct nf_conn_acct *NM -#else -#define SFE_NF_CONN_ACCT(NM) struct nf_conn_counter *NM -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -#define SFE_ACCT_COUNTER(NM) ((NM)->counter) -#else -#define SFE_ACCT_COUNTER(NM) (NM) -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) -#define sfe_hash_for_each_possible(name, obj, node, member, key) \ - hash_for_each_possible(name, obj, member, key) -#else -#define sfe_hash_for_each_possible(name, obj, node, member, key) \ - hash_for_each_possible(name, obj, node, member, key) -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) -#define sfe_hash_for_each(name, bkt, node, obj, member) \ - hash_for_each(name, bkt, obj, member) -#else -#define sfe_hash_for_each(name, bkt, node, obj, member) \ - hash_for_each(name, bkt, node, obj, member) -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) -#define sfe_dst_get_neighbour(dst, daddr) dst_neigh_lookup(dst, daddr) -#else -static inline struct neighbour * -sfe_dst_get_neighbour(struct dst_entry *dst, void *daddr) -{ - struct neighbour *neigh = dst_get_neighbour_noref(dst); - - if (neigh) - neigh_hold(neigh); - - return neigh; -} -#endif diff --git a/fast-classifier/src/sfe_cm.h b/fast-classifier/src/sfe_cm.h deleted file mode 100755 index 23cbde859..000000000 --- a/fast-classifier/src/sfe_cm.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * sfe_cm.h - * Shortcut forwarding engine. - * - * Copyright (c) 2013-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. - */ - -/* - * connection flags. - */ -#define SFE_CREATE_FLAG_NO_SEQ_CHECK BIT(0) - /* Indicates that we should not check sequence numbers */ -#define SFE_CREATE_FLAG_REMARK_PRIORITY BIT(1) - /* Indicates that we should remark priority of skb */ -#define SFE_CREATE_FLAG_REMARK_DSCP BIT(2) - /* Indicates that we should remark DSCP of packet */ - -/* - * IPv6 address structure - */ -struct sfe_ipv6_addr { - __be32 addr[4]; -}; - -typedef union { - __be32 ip; - struct sfe_ipv6_addr ip6[1]; -} sfe_ip_addr_t; - -/* - * connection creation structure. - */ -struct sfe_connection_create { - int protocol; - struct net_device *src_dev; - struct net_device *dest_dev; - u32 flags; - u32 src_mtu; - u32 dest_mtu; - sfe_ip_addr_t src_ip; - sfe_ip_addr_t src_ip_xlate; - sfe_ip_addr_t dest_ip; - sfe_ip_addr_t dest_ip_xlate; - __be16 src_port; - __be16 src_port_xlate; - __be16 dest_port; - __be16 dest_port_xlate; - u8 src_mac[ETH_ALEN]; - u8 src_mac_xlate[ETH_ALEN]; - u8 dest_mac[ETH_ALEN]; - u8 dest_mac_xlate[ETH_ALEN]; - u8 src_td_window_scale; - u32 src_td_max_window; - u32 src_td_end; - u32 src_td_max_end; - u8 dest_td_window_scale; - u32 dest_td_max_window; - u32 dest_td_end; - u32 dest_td_max_end; - u32 mark; -#ifdef CONFIG_XFRM - u32 original_accel; - u32 reply_accel; -#endif - u32 src_priority; - u32 dest_priority; - u32 src_dscp; - u32 dest_dscp; -}; - -/* - * connection destruction structure. - */ -struct sfe_connection_destroy { - int protocol; - sfe_ip_addr_t src_ip; - sfe_ip_addr_t dest_ip; - __be16 src_port; - __be16 dest_port; -}; - -typedef enum sfe_sync_reason { - SFE_SYNC_REASON_STATS, /* Sync is to synchronize stats */ - SFE_SYNC_REASON_FLUSH, /* Sync is to flush a entry */ - SFE_SYNC_REASON_DESTROY /* Sync is to destroy a entry(requested by connection manager) */ -} sfe_sync_reason_t; - -/* - * Structure used to sync connection stats/state back within the system. - * - * NOTE: The addresses here are NON-NAT addresses, i.e. the true endpoint addressing. - * 'src' is the creator of the connection. - */ -struct sfe_connection_sync { - struct net_device *src_dev; - struct net_device *dest_dev; - int is_v6; /* Is it for ipv6? */ - int protocol; /* IP protocol number (IPPROTO_...) */ - sfe_ip_addr_t src_ip; /* Non-NAT source address, i.e. the creator of the connection */ - sfe_ip_addr_t src_ip_xlate; /* NATed source address */ - __be16 src_port; /* Non-NAT source port */ - __be16 src_port_xlate; /* NATed source port */ - sfe_ip_addr_t dest_ip; /* Non-NAT destination address, i.e. to whom the connection was created */ - sfe_ip_addr_t dest_ip_xlate; /* NATed destination address */ - __be16 dest_port; /* Non-NAT destination port */ - __be16 dest_port_xlate; /* NATed destination port */ - u32 src_td_max_window; - u32 src_td_end; - u32 src_td_max_end; - u64 src_packet_count; - u64 src_byte_count; - u32 src_new_packet_count; - u32 src_new_byte_count; - u32 dest_td_max_window; - u32 dest_td_end; - u32 dest_td_max_end; - u64 dest_packet_count; - u64 dest_byte_count; - u32 dest_new_packet_count; - u32 dest_new_byte_count; - u32 reason; /* reason for stats sync message, i.e. destroy, flush, period sync */ - u64 delta_jiffies; /* Time to be added to the current timeout to keep the connection alive */ -}; - -/* - * connection mark structure - */ -struct sfe_connection_mark { - int protocol; - sfe_ip_addr_t src_ip; - sfe_ip_addr_t dest_ip; - __be16 src_port; - __be16 dest_port; - u32 mark; -}; - -/* - * Expose the hook for the receive processing. - */ -extern int (*athrs_fast_nat_recv)(struct sk_buff *skb); - -/* - * Expose what should be a static flag in the TCP connection tracker. - */ -extern int nf_ct_tcp_no_window_check; - -/* - * This callback will be called in a timer - * at 100 times per second to sync stats back to - * Linux connection track. - * - * A RCU lock is taken to prevent this callback - * from unregistering. - */ -typedef void (*sfe_sync_rule_callback_t)(struct sfe_connection_sync *); - -/* - * IPv4 APIs used by connection manager - */ -int sfe_ipv4_recv(struct net_device *dev, struct sk_buff *skb); -int sfe_ipv4_create_rule(struct sfe_connection_create *sic); -void sfe_ipv4_destroy_rule(struct sfe_connection_destroy *sid); -void sfe_ipv4_destroy_all_rules_for_dev(struct net_device *dev); -void sfe_ipv4_register_sync_rule_callback(sfe_sync_rule_callback_t callback); -void sfe_ipv4_update_rule(struct sfe_connection_create *sic); -void sfe_ipv4_mark_rule(struct sfe_connection_mark *mark); - -#ifdef SFE_SUPPORT_IPV6 -/* - * IPv6 APIs used by connection manager - */ -int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb); -int sfe_ipv6_create_rule(struct sfe_connection_create *sic); -void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid); -void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev); -void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t callback); -void sfe_ipv6_update_rule(struct sfe_connection_create *sic); -void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark); -#else -static inline int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb) -{ - return 0; -} - -static inline int sfe_ipv6_create_rule(struct sfe_connection_create *sic) -{ - return 0; -} - -static inline void sfe_ipv6_destroy_rule(struct sfe_connection_destroy *sid) -{ - return; -} - -static inline void sfe_ipv6_destroy_all_rules_for_dev(struct net_device *dev) -{ - return; -} - -static inline void sfe_ipv6_register_sync_rule_callback(sfe_sync_rule_callback_t callback) -{ - return; -} - -static inline void sfe_ipv6_update_rule(struct sfe_connection_create *sic) -{ - return; -} - -static inline void sfe_ipv6_mark_rule(struct sfe_connection_mark *mark) -{ - return; -} -#endif - -/* - * sfe_ipv6_addr_equal() - * compare ipv6 address - * - * return: 1, equal; 0, no equal - */ -static inline int sfe_ipv6_addr_equal(struct sfe_ipv6_addr *a, - struct sfe_ipv6_addr *b) -{ - return a->addr[0] == b->addr[0] && - a->addr[1] == b->addr[1] && - a->addr[2] == b->addr[2] && - a->addr[3] == b->addr[3]; -} - -/* - * sfe_ipv4_addr_equal() - * compare ipv4 address - * - * return: 1, equal; 0, no equal - */ -#define sfe_ipv4_addr_equal(a, b) ((u32)(a) == (u32)(b)) - -/* - * sfe_addr_equal() - * compare ipv4 or ipv6 address - * - * return: 1, equal; 0, no equal - */ -static inline int sfe_addr_equal(sfe_ip_addr_t *a, - sfe_ip_addr_t *b, int is_v4) -{ - return is_v4 ? sfe_ipv4_addr_equal(a->ip, b->ip) : sfe_ipv6_addr_equal(a->ip6, b->ip6); -} diff --git a/fast-classifier/src/userspace_example.c b/fast-classifier/src/userspace_example.c old mode 100755 new mode 100644 diff --git a/shortcut-fe/Makefile b/shortcut-fe/Makefile old mode 100755 new mode 100644 index 54711c46a..2baa86cbe --- a/shortcut-fe/Makefile +++ b/shortcut-fe/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2014 The Linux Foundation. All rights reserved. +# Copyright (c) 2013-2018, 2020 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. @@ -11,12 +11,12 @@ # 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 -PKG_RELEASE:=2 -PKG_CONFIG_DEPENDS := CONFIG_IPV6 +PKG_RELEASE:=5 include $(INCLUDE_DIR)/package.mk @@ -24,13 +24,17 @@ define KernelPackage/shortcut-fe SECTION:=kernel CATEGORY:=Kernel modules SUBMENU:=Network Support - DEPENDS:= + DEPENDS:=@IPV6 +kmod-nf-conntrack TITLE:=Kernel driver for SFE - FILES:=$(PKG_BUILD_DIR)/shortcut-fe.ko $(if $(CONFIG_IPV6),$(PKG_BUILD_DIR)/shortcut-fe-ipv6.ko,) - KCONFIG:=CONFIG_NF_CONNTRACK_EVENTS=y \ + FILES:= \ + $(PKG_BUILD_DIR)/shortcut-fe.ko \ + $(PKG_BUILD_DIR)/shortcut-fe-ipv6.ko + KCONFIG:= \ + CONFIG_NF_CONNTRACK_EVENTS=y \ CONFIG_NF_CONNTRACK_TIMEOUT=y \ CONFIG_SHORTCUT_FE=y \ CONFIG_XFRM=y + PROVIDES:=$(PKG_NAME) AUTOLOAD:=$(call AutoLoad,09,shortcut-fe shortcut-fe-ipv6) endef @@ -39,10 +43,14 @@ Shortcut is an in-Linux-kernel IP packet forwarding engine. endef define KernelPackage/shortcut-fe/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/etc/init.d/shortcut-fe $(1)/etc/init.d $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) ./files/usr/bin/sfe_dump $(1)/usr/bin endef +HAVE_ECM:=$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-premium-noload)$(CONFIG_PACKAGE_kmod-qca-nss-ecm-standard) + define KernelPackage/shortcut-fe-cm SECTION:=kernel CATEGORY:=Kernel modules @@ -50,7 +58,11 @@ define KernelPackage/shortcut-fe-cm DEPENDS:=+kmod-ipt-conntrack +kmod-shortcut-fe TITLE:=Kernel driver for SFE FILES:=$(PKG_BUILD_DIR)/shortcut-fe-cm.ko - KCONFIG:=CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y + KCONFIG:= \ + CONFIG_NF_CONNTRACK_CHAIN_EVENTS=y \ + CONFIG_NF_CONNTRACK_EVENTS=y \ + CONFIG_XFRM=y + CONFLICTS:=kmod-shortcut-fe-drv endef define KernelPackage/shortcut-fe-cm/Description @@ -58,20 +70,21 @@ Simple connection manager for the Shortcut forwarding engine. endef define Build/Compile - +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ + $(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ $(KERNEL_MAKE_FLAGS) \ $(PKG_MAKE_FLAGS) \ M="$(PKG_BUILD_DIR)" \ - modules \ - $(if $(CONFIG_IPV6),EXTRA_CFLAGS="-DSFE_SUPPORT_IPV6" SFE_SUPPORT_IPV6=y,) + EXTRA_CFLAGS+="-DSFE_SUPPORT_IPV6" SFE_SUPPORT_IPV6=y \ + $(if $(HAVE_ECM),EXTRA_CFLAGS+="-DCONFIG_SFE_ECM" CONFIG_SFE_ECM=y,) \ + modules endef -#ifneq ($(CONFIG_PACKAGE_kmod-shortcut-fe)$(CONFIG_PACKAGE_kmod-shortcut-fe-cm),) +ifneq ($(CONFIG_PACKAGE_kmod-shortcut-fe)$(CONFIG_PACKAGE_kmod-shortcut-fe-cm),) define Build/InstallDev $(INSTALL_DIR) $(1)/usr/include/shortcut-fe $(CP) -rf $(PKG_BUILD_DIR)/sfe.h $(1)/usr/include/shortcut-fe endef -#endif +endif $(eval $(call KernelPackage,shortcut-fe)) $(eval $(call KernelPackage,shortcut-fe-cm)) diff --git a/shortcut-fe/files/etc/init.d/shortcut-fe b/shortcut-fe/files/etc/init.d/shortcut-fe new file mode 100755 index 000000000..786e52df0 --- /dev/null +++ b/shortcut-fe/files/etc/init.d/shortcut-fe @@ -0,0 +1,49 @@ +#!/bin/sh /etc/rc.common +# +# Copyright (c) 2014-2015 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. +# + +#SFE connection manager has a lower priority, it should be started after other connection manager +#to detect the existence of connection manager with higher priority +START=99 + +have_cm() { + [ -d "/sys/kernel/debug/ecm" ] && echo 1 && return + + echo 0 +} + +#load shortcut-fe and connection manager +load_sfe() { + local kernel_version=$(uname -r) + + [ -d "/sys/module/shortcut_fe" ] || insmod /lib/modules/$kernel_version/shortcut-fe.ko + [ -d "/sys/module/shortcut_fe_ipv6" ] || insmod /lib/modules/$kernel_version/shortcut-fe-ipv6.ko + + [ -e "/lib/modules/$kernel_version/shortcut-fe-cm.ko" ] && { + [ -d /sys/module/shortcut_fe_cm ] || insmod /lib/modules/$kernel_version/shortcut-fe-cm.ko + } + [ -e "/lib/modules/$kernel_version/fast-classifier.ko" ] && { + [ -d /sys/module/fast_classifier ] || insmod /lib/modules/$kernel_version/fast-classifier.ko + } +} + +start() { + [ "$(have_cm)" = "0" ] && load_sfe +} + +stop() { + [ -d "/sys/module/shortcut_fe_drv" ] && rmmod shortcut_fe_drv + [ -d "/sys/module/shortcut_fe_cm" ] && rmmod shortcut_fe_cm + [ -d "/sys/module/fast_classifier" ] && rmmod fast_classifier +} diff --git a/shortcut-fe/src/Kconfig b/shortcut-fe/src/Kconfig old mode 100755 new mode 100644 index f45e56b47..487f1e065 --- a/shortcut-fe/src/Kconfig +++ b/shortcut-fe/src/Kconfig @@ -5,8 +5,7 @@ config SHORTCUT_FE tristate "Shortcut Forwarding Engine" depends on NF_CONNTRACK - default n - help + ---help--- Shortcut is a fast in-kernel packet forwarding engine. To compile this code as a module, choose M here: the module will be diff --git a/shortcut-fe/src/Makefile b/shortcut-fe/src/Makefile old mode 100755 new mode 100644 index 3b1ceaa44..991a20ec6 --- a/shortcut-fe/src/Makefile +++ b/shortcut-fe/src/Makefile @@ -21,3 +21,4 @@ endif shortcut-fe-cm-objs := \ sfe_cm.o +ccflags-y += -Werror -Wall diff --git a/shortcut-fe/src/sfe.h b/shortcut-fe/src/sfe.h old mode 100755 new mode 100644 diff --git a/shortcut-fe/src/sfe_backport.h b/shortcut-fe/src/sfe_backport.h old mode 100755 new mode 100644 index 2f8c8ca3c..d2d60c73c --- a/shortcut-fe/src/sfe_backport.h +++ b/shortcut-fe/src/sfe_backport.h @@ -180,7 +180,7 @@ static inline struct net_device *sfe_dev_get_master(struct net_device *dev) #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) -#define sfe_dst_get_neighbour(dst, daddr) dst_neigh_lookup(dst, daddr) +#define sfe_dst_get_neighbour(dst, daddr) dst_neigh_lookup(dst, addr) #else static inline struct neighbour * sfe_dst_get_neighbour(struct dst_entry *dst, void *daddr) diff --git a/shortcut-fe/src/sfe_cm.c b/shortcut-fe/src/sfe_cm.c old mode 100755 new mode 100644 index 18f3475e5..68304b388 --- a/shortcut-fe/src/sfe_cm.c +++ b/shortcut-fe/src/sfe_cm.c @@ -2,7 +2,7 @@ * sfe-cm.c * Shortcut forwarding engine connection manager. * - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018, 2020 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. @@ -199,7 +199,7 @@ int sfe_cm_recv(struct sk_buff *skb) * structure, obtain the hardware address. This means this function also * works if the neighbours are routers too. */ -static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, int is_v4) +static bool sfe_cm_find_dev_and_mac_addr(struct sk_buff *skb, sfe_ip_addr_t *addr, struct net_device **dev, u8 *mac_addr, int is_v4) { struct neighbour *neigh; struct rtable *rt; @@ -207,6 +207,15 @@ static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device struct dst_entry *dst; struct net_device *mac_dev; + /* + * If we have skb provided, use it as the original code is unable + * to lookup routes that are policy routed. + */ + if (unlikely(skb)) { + dst = skb_dst(skb); + goto skip_dst_lookup; + } + /* * Look up the rtable entry for the IP address then get the hardware * address from its neighbour structure. This means this work when the @@ -220,11 +229,11 @@ static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device dst = (struct dst_entry *)rt; } else { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) - rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, NULL, 0); -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)) rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, 0); -#endif /*KERNEL_VERSION(4, 17, 0)*/ +#else + rt6 = rt6_lookup(&init_net, (struct in6_addr *)addr->ip6, 0, 0, NULL, 0); +#endif if (!rt6) { goto ret_fail; } @@ -232,18 +241,21 @@ static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device dst = (struct dst_entry *)rt6; } +skip_dst_lookup: rcu_read_lock(); neigh = sfe_dst_get_neighbour(dst, addr); if (unlikely(!neigh)) { rcu_read_unlock(); - dst_release(dst); + if (likely(!skb)) + dst_release(dst); goto ret_fail; } if (unlikely(!(neigh->nud_state & NUD_VALID))) { rcu_read_unlock(); neigh_release(neigh); - dst_release(dst); + if (likely(!skb)) + dst_release(dst); goto ret_fail; } @@ -251,7 +263,8 @@ static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device if (!mac_dev) { rcu_read_unlock(); neigh_release(neigh); - dst_release(dst); + if (likely(!skb)) + dst_release(dst); goto ret_fail; } @@ -261,7 +274,8 @@ static bool sfe_cm_find_dev_and_mac_addr(sfe_ip_addr_t *addr, struct net_device *dev = mac_dev; rcu_read_unlock(); neigh_release(neigh); - dst_release(dst); + if (likely(!skb)) + dst_release(dst); return true; @@ -295,7 +309,13 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) struct net_device *dest_br_dev = NULL; struct nf_conntrack_tuple orig_tuple; struct nf_conntrack_tuple reply_tuple; + struct sk_buff *tmp_skb = NULL; SFE_NF_CONN_ACCT(acct); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + struct net *net=NULL; + struct nf_tcp_net *tn=NULL; + #endif /* * Don't process broadcast or multicast packets. @@ -352,16 +372,18 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) return NF_ACCEPT; } -#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) /* * Don't process untracked connections. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) if (unlikely(nf_ct_is_untracked(ct))) { +#else + if (unlikely(ctinfo == IP_CT_UNTRACKED)) { +#endif sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_CT_NO_TRACK); DEBUG_TRACE("untracked connection\n"); return NF_ACCEPT; } -#endif /*KERNEL_VERSION(4, 12, 0)*/ /* * Unconfirmed connection may be dropped by Linux at the final step, @@ -479,8 +501,13 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) sic.dest_td_max_window = ct->proto.tcp.seen[1].td_maxwin; sic.dest_td_end = ct->proto.tcp.seen[1].td_end; sic.dest_td_max_end = ct->proto.tcp.seen[1].td_maxend; - - if (nf_ct_tcp_no_window_check +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + net = nf_ct_net(ct); + tn = nf_tcp_pernet(net); + if ((tn&&tn->tcp_no_window_check) +#else + if (nf_ct_tcp_no_window_check +#endif || (ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_BE_LIBERAL) || (ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_BE_LIBERAL)) { sic.flags |= SFE_CREATE_FLAG_NO_SEQ_CHECK; @@ -510,6 +537,21 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) return NF_ACCEPT; } spin_unlock_bh(&ct->lock); + + /* + * Somehow, SFE is not playing nice with IPSec traffic. + * Do not accelerate for now. + */ + if (ntohs(sic.dest_port) == 4500 || ntohs(sic.dest_port) == 500) { + if (likely(is_v4)) + DEBUG_TRACE("IPsec bypass: %pI4:%d(%pI4:%d) to %pI4:%d(%pI4:%d)\n", + &sic.src_ip.ip, ntohs(sic.src_port), &sic.src_ip_xlate.ip, ntohs(sic.src_port_xlate), + &sic.dest_ip.ip, ntohs(sic.dest_port), &sic.dest_ip_xlate.ip, ntohs(sic.dest_port_xlate)); + else + DEBUG_TRACE("IPsec bypass: %pI6:%d to %pI6:%d\n", + &sic.src_ip.ip6, ntohs(sic.src_port), &sic.dest_ip.ip6, ntohs(sic.dest_port)); + return NF_ACCEPT; + } break; case IPPROTO_UDP: @@ -533,10 +575,10 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) * For packets de-capsulated from xfrm, we still can accelerate it * on the direction we just received the packet. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) - if (unlikely(skb_ext_exist(skb, SKB_EXT_SEC_PATH))) { -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) if (unlikely(skb->sp)) { +#else + if (unlikely(secpath_exists(skb))) { #endif if (sic.protocol == IPPROTO_TCP && !(sic.flags & SFE_CREATE_FLAG_NO_SEQ_CHECK)) { @@ -564,25 +606,27 @@ static unsigned int sfe_cm_post_routing(struct sk_buff *skb, int is_v4) * Get the net device and MAC addresses that correspond to the various source and * destination host addresses. */ - if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip, &src_dev_tmp, sic.src_mac, is_v4)) { + if (!sfe_cm_find_dev_and_mac_addr(NULL, &sic.src_ip, &src_dev_tmp, sic.src_mac, is_v4)) { sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_DEV); return NF_ACCEPT; } src_dev = src_dev_tmp; - if (!sfe_cm_find_dev_and_mac_addr(&sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) { + if (!sfe_cm_find_dev_and_mac_addr(NULL, &sic.src_ip_xlate, &dev, sic.src_mac_xlate, is_v4)) { sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_SRC_XLATE_DEV); goto done1; } dev_put(dev); - - if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip, &dev, sic.dest_mac, is_v4)) { + /* Somehow, for IPv6, we need this workaround as well */ + if (unlikely(!is_v4)) + tmp_skb = skb; + if (!sfe_cm_find_dev_and_mac_addr(tmp_skb, &sic.dest_ip, &dev, sic.dest_mac, is_v4)) { sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_DEV); goto done1; } dev_put(dev); - if (!sfe_cm_find_dev_and_mac_addr(&sic.dest_ip_xlate, &dest_dev_tmp, sic.dest_mac_xlate, is_v4)) { + if (!sfe_cm_find_dev_and_mac_addr(skb, &sic.dest_ip_xlate, &dest_dev_tmp, sic.dest_mac_xlate, is_v4)) { sfe_cm_incr_exceptions(SFE_CM_EXCEPTION_NO_DEST_XLATE_DEV); goto done1; } @@ -688,14 +732,11 @@ static int sfe_cm_conntrack_event(unsigned int events, struct nf_ct_event *item) } #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) - /* - * If this is an untracked connection then we can't have any state either. - */ if (unlikely(nf_ct_is_untracked(ct))) { DEBUG_TRACE("ignoring untracked conn\n"); return NOTIFY_DONE; } -#endif /*KERNEL_VERSION(4, 12, 0)*/ +#endif /* * We're only interested in destroy events. @@ -825,18 +866,17 @@ static void sfe_cm_sync_rule(struct sfe_connection_sync *sis) ct = nf_ct_tuplehash_to_ctrack(h); #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); -#endif /*KERNEL_VERSION(4, 9, 0)*/ - +#endif /* * Only update if this is not a fixed timeout */ if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { spin_lock_bh(&ct->lock); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) - ct->timeout += sis->delta_jiffies; -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) ct->timeout.expires += sis->delta_jiffies; -#endif /*KERNEL_VERSION(4, 9, 0)*/ +#else + ct->timeout += sis->delta_jiffies; +#endif spin_unlock_bh(&ct->lock); } @@ -891,26 +931,26 @@ static void sfe_cm_sync_rule(struct sfe_connection_sync *sis) if (reply_pkts != 0) { unsigned int *timeouts; - + struct nf_conntrack_l4proto *l4proto __maybe_unused; set_bit(IPS_SEEN_REPLY_BIT, &ct->status); set_bit(IPS_ASSURED_BIT, &ct->status); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) - timeouts = nf_ct_timeout_lookup(ct); -#else - struct nf_conntrack_l4proto *l4proto; - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) l4proto = __nf_ct_l4proto_find((sis->is_v6 ? AF_INET6 : AF_INET), IPPROTO_UDP); timeouts = nf_ct_timeout_lookup(&init_net, ct, l4proto); -#endif /*KERNEL_VERSION(4, 19, 0)*/ + spin_lock_bh(&ct->lock); + ct->timeout.expires = jiffies + timeouts[UDP_CT_REPLIED]; + spin_unlock_bh(&ct->lock); +#else + timeouts = nf_ct_timeout_lookup(ct); + if (!timeouts) { + timeouts = nf_udp_pernet(nf_ct_net(ct))->timeouts; + } spin_lock_bh(&ct->lock); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) ct->timeout = jiffies + timeouts[UDP_CT_REPLIED]; -#else - ct->timeout.expires = jiffies + timeouts[UDP_CT_REPLIED]; -#endif /*KERNEL_VERSION(4, 9, 0)*/ spin_unlock_bh(&ct->lock); +#endif } } break; @@ -1001,6 +1041,9 @@ static int __init sfe_cm_init(void) { struct sfe_cm *sc = &__sc; int result = -1; +#ifdef CONFIG_SFE_ECM + int (*fast_recv)(struct sk_buff *skb); +#endif DEBUG_INFO("SFE CM init\n"); @@ -1036,7 +1079,11 @@ static int __init sfe_cm_init(void) /* * Register our netfilter hooks. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + result = nf_register_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else result = nf_register_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif if (result < 0) { DEBUG_ERROR("can't register nf post routing hook: %d\n", result); goto exit3; @@ -1049,22 +1096,30 @@ static int __init sfe_cm_init(void) */ #ifdef CONFIG_NF_CONNTRACK_EVENTS #ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS - (void)nf_conntrack_register_chain_notifier(&init_net, &sfe_cm_conntrack_notifier); + result = nf_conntrack_register_chain_notifier(&init_net, &sfe_cm_conntrack_notifier); #else result = nf_conntrack_register_notifier(&init_net, &sfe_cm_conntrack_notifier); +#endif if (result < 0) { DEBUG_ERROR("can't register nf notifier hook: %d\n", result); goto exit4; } #endif -#endif - spin_lock_init(&sc->lock); /* * Hook the receive path in the network stack. */ +#ifdef CONFIG_SFE_ECM + rcu_read_lock(); + fast_recv = rcu_dereference(athrs_fast_nat_recv); + rcu_read_unlock(); + if (!fast_recv) { + BUG_ON(athrs_fast_nat_recv); + } +#else BUG_ON(athrs_fast_nat_recv); +#endif RCU_INIT_POINTER(athrs_fast_nat_recv, sfe_cm_recv); /* @@ -1075,10 +1130,15 @@ static int __init sfe_cm_init(void) return 0; #ifdef CONFIG_NF_CONNTRACK_EVENTS -#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS exit4: +#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); #endif + +#endif #endif exit3: unregister_inet6addr_notifier(&sc->inet6_notifier); @@ -1129,8 +1189,12 @@ static void __exit sfe_cm_exit(void) nf_conntrack_unregister_notifier(&init_net, &sfe_cm_conntrack_notifier); #endif #endif - nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)) + nf_unregister_hooks(sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#else + nf_unregister_net_hooks(&init_net, sfe_cm_ops_post_routing, ARRAY_SIZE(sfe_cm_ops_post_routing)); +#endif unregister_inet6addr_notifier(&sc->inet6_notifier); unregister_inetaddr_notifier(&sc->inet_notifier); unregister_netdevice_notifier(&sc->dev_notifier); diff --git a/shortcut-fe/src/sfe_cm.h b/shortcut-fe/src/sfe_cm.h old mode 100755 new mode 100644 index 23cbde859..124c86f47 --- a/shortcut-fe/src/sfe_cm.h +++ b/shortcut-fe/src/sfe_cm.h @@ -152,8 +152,9 @@ extern int (*athrs_fast_nat_recv)(struct sk_buff *skb); /* * Expose what should be a static flag in the TCP connection tracker. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) extern int nf_ct_tcp_no_window_check; - +#endif /* * This callback will be called in a timer * at 100 times per second to sync stats back to diff --git a/shortcut-fe/src/sfe_ipv4.c b/shortcut-fe/src/sfe_ipv4.c old mode 100755 new mode 100644 index 531456c05..cdcdd66dd --- a/shortcut-fe/src/sfe_ipv4.c +++ b/shortcut-fe/src/sfe_ipv4.c @@ -2,7 +2,7 @@ * sfe_ipv4.c * Shortcut forwarding engine - IPv4 edition. * - * Copyright (c) 2013-2016, 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 2019-2020 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. @@ -1311,14 +1311,13 @@ static int sfe_ipv4_recv_udp(struct sfe_ipv4 *si, struct sk_buff *skb, struct ne * change the cloned skb's data section. */ if (unlikely(skb_cloned(skb))) { - DEBUG_TRACE("%p: skb is a cloned skb\n", skb); + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) { DEBUG_WARN("Failed to unshare the cloned skb\n"); si->exception_events[SFE_IPV4_EXCEPTION_EVENT_CLONED_SKB_UNSHARE_ERROR]++; si->packets_not_forwarded++; spin_unlock_bh(&si->lock); - return 0; } @@ -1891,14 +1890,13 @@ static int sfe_ipv4_recv_tcp(struct sfe_ipv4 *si, struct sk_buff *skb, struct ne * change the cloned skb's data section. */ if (unlikely(skb_cloned(skb))) { - DEBUG_TRACE("%p: skb is a cloned skb\n", skb); + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) { DEBUG_WARN("Failed to unshare the cloned skb\n"); si->exception_events[SFE_IPV4_EXCEPTION_EVENT_CLONED_SKB_UNSHARE_ERROR]++; si->packets_not_forwarded++; spin_unlock_bh(&si->lock); - return 0; } @@ -2512,7 +2510,7 @@ int sfe_ipv4_create_rule(struct sfe_connection_create *sic) spin_unlock_bh(&si->lock); DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n" - " s: %s:%pM:%pI4:%u, d: %s:%pM:%pI4:%u\n", + " s: %s:%pxM:%pI4:%u, d: %s:%pxM:%pI4:%u\n", sic->mark, sic->protocol, sic->src_dev->name, sic->src_mac, &sic->src_ip.ip, ntohs(sic->src_port), sic->dest_dev->name, sic->dest_mac, &sic->dest_ip.ip, ntohs(sic->dest_port)); @@ -2728,8 +2726,8 @@ int sfe_ipv4_create_rule(struct sfe_connection_create *sic) * We have everything we need! */ DEBUG_INFO("new connection - mark: %08x, p: %d\n" - " s: %s:%pM(%pM):%pI4(%pI4):%u(%u)\n" - " d: %s:%pM(%pM):%pI4(%pI4):%u(%u)\n", + " s: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n" + " d: %s:%pxM(%pxM):%pI4(%pI4):%u(%u)\n", sic->mark, sic->protocol, sic->src_dev->name, sic->src_mac, sic->src_mac_xlate, &sic->src_ip.ip, &sic->src_ip_xlate.ip, ntohs(sic->src_port), ntohs(sic->src_port_xlate), @@ -2858,17 +2856,17 @@ another_round: /* * sfe_ipv4_periodic_sync() */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) -static void sfe_ipv4_periodic_sync(struct timer_list *arg) -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) static void sfe_ipv4_periodic_sync(unsigned long arg) -#endif /*KERNEL_VERSION(4, 15, 0)*/ -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) - struct sfe_ipv4 *si = (struct sfe_ipv4 *)arg->cust_data; #else +static void sfe_ipv4_periodic_sync(struct timer_list *tl) +#endif +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) struct sfe_ipv4 *si = (struct sfe_ipv4 *)arg; -#endif /*KERNEL_VERSION(4, 15, 0)*/ +#else + struct sfe_ipv4 *si = from_timer(si, tl, timer); +#endif u64 now_jiffies; int quota; sfe_sync_rule_callback_t sync_rule_callback; @@ -3547,12 +3545,11 @@ static int __init sfe_ipv4_init(void) /* * Create a timer to handle periodic statistics. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) - timer_setup(&si->timer, sfe_ipv4_periodic_sync, 0); - si->timer.cust_data = (unsigned long)si; -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) setup_timer(&si->timer, sfe_ipv4_periodic_sync, (unsigned long)si); -#endif /*KERNEL_VERSION(4, 15, 0)*/ +#else + timer_setup(&si->timer, sfe_ipv4_periodic_sync, 0); +#endif mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); spin_lock_init(&si->lock); diff --git a/shortcut-fe/src/sfe_ipv6.c b/shortcut-fe/src/sfe_ipv6.c old mode 100755 new mode 100644 index 3c5ef1263..ae3306693 --- a/shortcut-fe/src/sfe_ipv6.c +++ b/shortcut-fe/src/sfe_ipv6.c @@ -2,7 +2,7 @@ * sfe_ipv6.c * Shortcut forwarding engine - IPv6 support. * - * Copyright (c) 2015-2016, 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, 2019-2020 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. @@ -1369,14 +1369,13 @@ static int sfe_ipv6_recv_udp(struct sfe_ipv6 *si, struct sk_buff *skb, struct ne * change the cloned skb's data section. */ if (unlikely(skb_cloned(skb))) { - DEBUG_TRACE("%p: skb is a cloned skb\n", skb); + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) { DEBUG_WARN("Failed to unshare the cloned skb\n"); si->exception_events[SFE_IPV6_EXCEPTION_EVENT_CLONED_SKB_UNSHARE_ERROR]++; si->packets_not_forwarded++; spin_unlock_bh(&si->lock); - return 0; } @@ -1929,14 +1928,13 @@ static int sfe_ipv6_recv_tcp(struct sfe_ipv6 *si, struct sk_buff *skb, struct ne * change the cloned skb's data section. */ if (unlikely(skb_cloned(skb))) { - DEBUG_TRACE("%p: skb is a cloned skb\n", skb); + DEBUG_TRACE("%px: skb is a cloned skb\n", skb); skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) { DEBUG_WARN("Failed to unshare the cloned skb\n"); si->exception_events[SFE_IPV6_EXCEPTION_EVENT_CLONED_SKB_UNSHARE_ERROR]++; si->packets_not_forwarded++; spin_unlock_bh(&si->lock); - return 0; } @@ -2328,7 +2326,7 @@ int sfe_ipv6_recv(struct net_device *dev, struct sk_buff *skb) si->packets_not_forwarded++; spin_unlock_bh(&si->lock); - DEBUG_TRACE("payload_len: %u, exceeds len: %u\n", payload_len, (len - sizeof(struct sfe_ipv6_ip_hdr))); + DEBUG_TRACE("payload_len: %u, exceeds len: %u\n", payload_len, (len - (unsigned int)sizeof(struct sfe_ipv6_ip_hdr))); return 0; } @@ -2526,7 +2524,7 @@ int sfe_ipv6_create_rule(struct sfe_connection_create *sic) spin_unlock_bh(&si->lock); DEBUG_TRACE("connection already exists - mark: %08x, p: %d\n" - " s: %s:%pM:%pI6:%u, d: %s:%pM:%pI6:%u\n", + " s: %s:%pxM:%pI6:%u, d: %s:%pxM:%pI6:%u\n", sic->mark, sic->protocol, sic->src_dev->name, sic->src_mac, sic->src_ip.ip6, ntohs(sic->src_port), sic->dest_dev->name, sic->dest_mac, sic->dest_ip.ip6, ntohs(sic->dest_port)); @@ -2742,8 +2740,8 @@ int sfe_ipv6_create_rule(struct sfe_connection_create *sic) * We have everything we need! */ DEBUG_INFO("new connection - mark: %08x, p: %d\n" - " s: %s:%pM(%pM):%pI6(%pI6):%u(%u)\n" - " d: %s:%pM(%pM):%pI6(%pI6):%u(%u)\n", + " s: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n" + " d: %s:%pxM(%pxM):%pI6(%pI6):%u(%u)\n", sic->mark, sic->protocol, sic->src_dev->name, sic->src_mac, sic->src_mac_xlate, sic->src_ip.ip6, sic->src_ip_xlate.ip6, ntohs(sic->src_port), ntohs(sic->src_port_xlate), @@ -2866,17 +2864,17 @@ another_round: /* * sfe_ipv6_periodic_sync() */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) -static void sfe_ipv6_periodic_sync(struct timer_list *arg) -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) static void sfe_ipv6_periodic_sync(unsigned long arg) -#endif /*KERNEL_VERSION(4, 15, 0)*/ -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) - struct sfe_ipv6 *si = (struct sfe_ipv6 *)arg->cust_data; #else +static void sfe_ipv6_periodic_sync(struct timer_list *tl) +#endif +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) struct sfe_ipv6 *si = (struct sfe_ipv6 *)arg; -#endif /*KERNEL_VERSION(4, 15, 0)*/ +#else + struct sfe_ipv6 *si = from_timer(si, tl, timer); +#endif u64 now_jiffies; int quota; sfe_sync_rule_callback_t sync_rule_callback; @@ -3555,12 +3553,11 @@ static int __init sfe_ipv6_init(void) /* * Create a timer to handle periodic statistics. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) - timer_setup(&si->timer, sfe_ipv6_periodic_sync, 0); - si->timer.cust_data = (unsigned long)si; -#else +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) setup_timer(&si->timer, sfe_ipv6_periodic_sync, (unsigned long)si); -#endif /*KERNEL_VERSION(4, 15, 0)*/ +#else + timer_setup(&si->timer, sfe_ipv6_periodic_sync, 0); +#endif mod_timer(&si->timer, jiffies + ((HZ + 99) / 100)); spin_lock_init(&si->lock); From 06a4f10a4d251fe76ec81a1d04b4974e49d323d3 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 10:55:40 +0800 Subject: [PATCH 20/26] add simulated --- simulated-driver/Makefile | 60 +++++++++++++++++++ .../patches/200-nss-qdisc-support.patch | 11 ++++ 2 files changed, 71 insertions(+) create mode 100644 simulated-driver/Makefile create mode 100644 simulated-driver/patches/200-nss-qdisc-support.patch 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 From 1020d095bc955234b0d92dacd8b56be9388ddf3d Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 11:23:58 +0800 Subject: [PATCH 21/26] fix --- luci-app-cpufreq/Makefile | 19 + .../luasrc/controller/cpufreq.lua | 9 + luci-app-cpufreq/luasrc/model/cbi/cpufreq.lua | 60 ++ luci-app-cpufreq/po/zh-cn/cpufreq.po | 57 ++ luci-app-cpufreq/root/etc/config/cpufreq | 8 + luci-app-cpufreq/root/etc/init.d/cpufreq | 30 + .../root/etc/uci-defaults/luci-cpufreq | 11 + luci-app-diskman/Makefile | 53 ++ .../luasrc/controller/diskman.lua | 155 ++++ .../luasrc/model/cbi/diskman/btrfs.lua | 210 +++++ .../luasrc/model/cbi/diskman/disks.lua | 327 ++++++++ .../luasrc/model/cbi/diskman/partition.lua | 366 +++++++++ luci-app-diskman/luasrc/model/diskman.lua | 738 ++++++++++++++++++ .../view/diskman/cbi/disabled_button.htm | 7 + .../luasrc/view/diskman/cbi/format_button.htm | 7 + .../luasrc/view/diskman/cbi/inlinebutton.htm | 7 + .../luasrc/view/diskman/cbi/xnullsection.htm | 37 + .../luasrc/view/diskman/cbi/xsimpleform.htm | 88 +++ .../luasrc/view/diskman/disk_info.htm | 108 +++ .../luasrc/view/diskman/partition_info.htm | 129 +++ .../luasrc/view/diskman/smart_detail.htm | 79 ++ luci-app-diskman/po/zh-cn/diskman.po | 239 ++++++ luci-app-netdata/Makefile | 18 + .../luasrc/controller/netdata.lua | 6 + .../luasrc/view/netdata/netdata.htm | 9 + luci-app-netdata/po/zh-cn/netdata.po | 5 + luci-app-turboacc/Makefile | 72 ++ .../luasrc/controller/turboacc.lua | 39 + .../luasrc/model/cbi/turboacc.lua | 67 ++ .../luasrc/view/turboacc/turboacc_status.htm | 25 + luci-app-turboacc/po/zh-cn/turboacc.po | 99 +++ luci-app-turboacc/root/etc/config/turboacc | 10 + luci-app-turboacc/root/etc/init.d/turboacc | 364 +++++++++ .../root/etc/uci-defaults/luci-turboacc | 10 + .../root/usr/share/dnscache/dnscache-while.sh | 38 + luci-app-zerotier/Makefile | 4 +- .../luasrc/controller/zerotier.lua | 7 +- .../luasrc/model/cbi/zerotier/info.lua | 4 +- .../luasrc/model/cbi/zerotier/settings.lua | 4 +- luci-app-zerotier/po/zh-cn/zerotier.po | 8 - luci-app-zerotier/root/etc/init.d/zerotier | 2 +- .../root/etc/uci-defaults/40_luci-zerotier | 3 +- luci-app-zerotier/root/etc/zerotier.stop | 2 +- .../share/rpcd/acl.d/luci-app-zerotier.json | 11 - 44 files changed, 3520 insertions(+), 31 deletions(-) create mode 100644 luci-app-cpufreq/Makefile create mode 100644 luci-app-cpufreq/luasrc/controller/cpufreq.lua create mode 100644 luci-app-cpufreq/luasrc/model/cbi/cpufreq.lua create mode 100644 luci-app-cpufreq/po/zh-cn/cpufreq.po create mode 100644 luci-app-cpufreq/root/etc/config/cpufreq create mode 100755 luci-app-cpufreq/root/etc/init.d/cpufreq create mode 100755 luci-app-cpufreq/root/etc/uci-defaults/luci-cpufreq create mode 100644 luci-app-diskman/Makefile create mode 100644 luci-app-diskman/luasrc/controller/diskman.lua create mode 100644 luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua create mode 100644 luci-app-diskman/luasrc/model/cbi/diskman/disks.lua create mode 100644 luci-app-diskman/luasrc/model/cbi/diskman/partition.lua create mode 100644 luci-app-diskman/luasrc/model/diskman.lua create mode 100644 luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/disk_info.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/partition_info.htm create mode 100644 luci-app-diskman/luasrc/view/diskman/smart_detail.htm create mode 100644 luci-app-diskman/po/zh-cn/diskman.po create mode 100644 luci-app-netdata/Makefile create mode 100644 luci-app-netdata/luasrc/controller/netdata.lua create mode 100644 luci-app-netdata/luasrc/view/netdata/netdata.htm create mode 100644 luci-app-netdata/po/zh-cn/netdata.po create mode 100644 luci-app-turboacc/Makefile create mode 100644 luci-app-turboacc/luasrc/controller/turboacc.lua create mode 100644 luci-app-turboacc/luasrc/model/cbi/turboacc.lua create mode 100644 luci-app-turboacc/luasrc/view/turboacc/turboacc_status.htm create mode 100644 luci-app-turboacc/po/zh-cn/turboacc.po create mode 100644 luci-app-turboacc/root/etc/config/turboacc create mode 100755 luci-app-turboacc/root/etc/init.d/turboacc create mode 100755 luci-app-turboacc/root/etc/uci-defaults/luci-turboacc create mode 100755 luci-app-turboacc/root/usr/share/dnscache/dnscache-while.sh delete mode 100644 luci-app-zerotier/root/usr/share/rpcd/acl.d/luci-app-zerotier.json diff --git a/luci-app-cpufreq/Makefile b/luci-app-cpufreq/Makefile new file mode 100644 index 000000000..a5945f704 --- /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 ../../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..8d258c4f6 --- /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 ../../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..e4ec8fcbc --- /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 ../../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..e174d8e03 --- /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_ipq806x||TARGET_ipq807x) + +config PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE + bool "Include Shortcut-FE" + default y if !(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 ../../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..4946b5f37 100644 --- a/luci-app-zerotier/Makefile +++ b/luci-app-zerotier/Makefile @@ -9,9 +9,11 @@ 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 -include $(TOPDIR)/feeds/luci/luci.mk +include ../../luci.mk # call BuildPackage - OpenWrt buildroot signature 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" ] - } - } -} From a7c56dd7f6757c4e8e0a449722dbcb9029106015 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 11:26:38 +0800 Subject: [PATCH 22/26] Update Makefile --- luci-app-turboacc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/luci-app-turboacc/Makefile b/luci-app-turboacc/Makefile index e174d8e03..2eadbdb9c 100644 --- a/luci-app-turboacc/Makefile +++ b/luci-app-turboacc/Makefile @@ -38,11 +38,11 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_OFFLOADING 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_ipq806x||TARGET_ipq807x) + default y if (TARGET_ipq60xxx||TARGET_ipq806x||TARGET_ipq807x) config PACKAGE_$(PKG_NAME)_INCLUDE_SHORTCUT_FE bool "Include Shortcut-FE" - default y if !(TARGET_ipq806x||TARGET_ipq807x||TARGET_ramips) + default y if !(TARGET_ipq60xxx||TARGET_ipq806x||TARGET_ipq807x||TARGET_ramips) config PACKAGE_$(PKG_NAME)_INCLUDE_BBR_CCA bool "Include BBR CCA" From d4ceecb05b747a39bdd965444ebfb8649c77a528 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 11:39:39 +0800 Subject: [PATCH 23/26] fix --- luci-app-cpufreq/Makefile | 2 +- luci-app-diskman/Makefile | 2 +- luci-app-netdata/Makefile | 2 +- luci-app-turboacc/Makefile | 6 +++--- luci-app-zerotier/Makefile | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/luci-app-cpufreq/Makefile b/luci-app-cpufreq/Makefile index a5945f704..676cbf2d3 100644 --- a/luci-app-cpufreq/Makefile +++ b/luci-app-cpufreq/Makefile @@ -14,6 +14,6 @@ PKG_NAME:=luci-app-cpufreq PKG_VERSION:=1 PKG_RELEASE:=7 -include ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-diskman/Makefile b/luci-app-diskman/Makefile index 8d258c4f6..0fc535f4b 100644 --- a/luci-app-diskman/Makefile +++ b/luci-app-diskman/Makefile @@ -48,6 +48,6 @@ define Package/$(PKG_NAME)/postinst rm -fr /tmp/luci-indexcache /tmp/luci-modulecache endef -include ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-netdata/Makefile b/luci-app-netdata/Makefile index e4ec8fcbc..de3b86671 100644 --- a/luci-app-netdata/Makefile +++ b/luci-app-netdata/Makefile @@ -13,6 +13,6 @@ PKG_NAME:=luci-app-netdata PKG_VERSION:=1.0 PKG_RELEASE:=3 -include ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-turboacc/Makefile b/luci-app-turboacc/Makefile index 2eadbdb9c..9d70f1631 100644 --- a/luci-app-turboacc/Makefile +++ b/luci-app-turboacc/Makefile @@ -38,11 +38,11 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_OFFLOADING 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) + 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) + default y if !(TARGET_ipq60xxx|TARGET_ipq806x||TARGET_ipq807x||TARGET_ramips) config PACKAGE_$(PKG_NAME)_INCLUDE_BBR_CCA bool "Include BBR CCA" @@ -67,6 +67,6 @@ define Package/$(PKG_NAME)/postrm 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 ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-zerotier/Makefile b/luci-app-zerotier/Makefile index 4946b5f37..11c26ca4f 100644 --- a/luci-app-zerotier/Makefile +++ b/luci-app-zerotier/Makefile @@ -14,6 +14,6 @@ PKG_NAME:=luci-app-zerotier PKG_VERSION:=1.0 PKG_RELEASE:=20 -include ../../luci.mk +include $(TOPDIR)/feeds/luci/luci.mk # call BuildPackage - OpenWrt buildroot signature From a8fff120894e0d8cf1f9b5220e5ae250e4e29fe2 Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 11:44:13 +0800 Subject: [PATCH 24/26] fix --- dnsforwarder/Makefile | 61 + dnsforwarder/files/etc/config/dnsforwarder | 79 + dnsforwarder/files/etc/dnsforwarder/gfw.txt | 5605 +++++++++++++++++ dnsforwarder/files/etc/init.d/dnsforwarder | 260 + .../files/usr/share/dnsforwarder/gfwlist.sh | 313 + dnsproxy/Makefile | 59 + dnsproxy/files/dnsproxy.config | 41 + dnsproxy/files/dnsproxy.init | 115 + dnsproxy/test.sh | 3 + pdnsd-alt/Makefile | 57 + pdnsd-alt/files/pdnsd.init | 46 + pdnsd-alt/patches/010-no-doc-and-test.patch | 42 + pdnsd-alt/patches/020-headers.patch | 66 + 13 files changed, 6747 insertions(+) create mode 100644 dnsforwarder/Makefile create mode 100644 dnsforwarder/files/etc/config/dnsforwarder create mode 100644 dnsforwarder/files/etc/dnsforwarder/gfw.txt create mode 100755 dnsforwarder/files/etc/init.d/dnsforwarder create mode 100755 dnsforwarder/files/usr/share/dnsforwarder/gfwlist.sh create mode 100644 dnsproxy/Makefile create mode 100644 dnsproxy/files/dnsproxy.config create mode 100644 dnsproxy/files/dnsproxy.init create mode 100644 dnsproxy/test.sh create mode 100644 pdnsd-alt/Makefile create mode 100755 pdnsd-alt/files/pdnsd.init create mode 100644 pdnsd-alt/patches/010-no-doc-and-test.patch create mode 100644 pdnsd-alt/patches/020-headers.patch 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..7760f739d --- /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 ../../lang/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/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 From 53df01db58908fbd33b96001cc74dbc38c1a17cb Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 11:45:51 +0800 Subject: [PATCH 25/26] Update Makefile --- dnsproxy/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnsproxy/Makefile b/dnsproxy/Makefile index 7760f739d..9da19835b 100644 --- a/dnsproxy/Makefile +++ b/dnsproxy/Makefile @@ -24,7 +24,7 @@ GO_PKG:=github.com/AdguardTeam/dnsproxy GO_PKG_LDFLAGS_X:=main.VersionString=v$(PKG_VERSION) include $(INCLUDE_DIR)/package.mk -include ../../lang/golang/golang-package.mk +include $(TOPDIR)/feeds/openmptcprouter/golang/golang-package.mk define Package/dnsproxy SECTION:=net From 1c779c2acf86b2f7727d8d0ebcc95f71bb9fd9fd Mon Sep 17 00:00:00 2001 From: suyuan168 <175338101@qq.com> Date: Thu, 9 Jun 2022 11:49:34 +0800 Subject: [PATCH 26/26] Update Makefile --- luci-app-turboacc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/luci-app-turboacc/Makefile b/luci-app-turboacc/Makefile index 9d70f1631..eb707831a 100644 --- a/luci-app-turboacc/Makefile +++ b/luci-app-turboacc/Makefile @@ -38,11 +38,11 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_OFFLOADING 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) + 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) + default y if !(TARGET_ipq60xxx||TARGET_ipq806x||TARGET_ipq807x||TARGET_ramips) config PACKAGE_$(PKG_NAME)_INCLUDE_BBR_CCA bool "Include BBR CCA"