mirror of
https://github.com/sirpdboy/sirpdboy-package.git
synced 2025-01-08 11:57:57 +08:00
upset
This commit is contained in:
parent
03dc00df0d
commit
184a6339f9
@ -1,88 +1,75 @@
|
||||
# Copyright (C) 2020 Lienol
|
||||
#
|
||||
# Copyright (C) 2015-2016 OpenWrt.org
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE.txt for more information.
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=AdGuardHome
|
||||
PKG_VERSION:=0.104.0
|
||||
PKG_VERSION:=release
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
|
||||
PKG_SOURCE_URL:=https://github.com/AdguardTeam/AdGuardHome
|
||||
PKG_MIRROR_HASH:=852861f83c3788a3913cb953b2eb0e2a94c27e2e158feae8c7485480c1481257
|
||||
ifeq ($(ARCH),i386)
|
||||
PKG_ARCH:=386
|
||||
endif
|
||||
ifeq ($(ARCH),x86_64)
|
||||
PKG_ARCH:=amd64
|
||||
endif
|
||||
ifeq ($(ARCH),mipsel)
|
||||
PKG_ARCH:=mipsle
|
||||
endif
|
||||
ifeq ($(ARCH),mips)
|
||||
PKG_ARCH:=mips
|
||||
endif
|
||||
ifeq ($(ARCH),arm)
|
||||
PKG_ARCH:=arm
|
||||
endif
|
||||
ifeq ($(ARCH),arm64)
|
||||
PKG_ARCH:=arm64
|
||||
endif
|
||||
ifeq ($(ARCH),aarch64)
|
||||
PKG_ARCH:=arm64
|
||||
endif
|
||||
|
||||
PKG_LICENSE:=GPL-3.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE.txt
|
||||
PKG_MAINTAINER:=Dobroslaw Kijowski <dobo90@gmail.com>
|
||||
|
||||
PKG_BUILD_DEPENDS:=golang/host node/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_USE_MIPS16:=0
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_ADGUARDHOME_COMPRESS_GOPROXY \
|
||||
CONFIG_ADGUARDHOME_COMPRESS_UPX
|
||||
|
||||
GO_PKG:=github.com/AdguardTeam/AdGuardHome
|
||||
GO_PKG_EXCLUDES:=dhcpd/standalone
|
||||
GO_PKG_LDFLAGS:=-s -w
|
||||
GO_PKG_LDFLAGS_X:=main.version=$(PKG_VERSION) main.channel=release
|
||||
PKG_FILE:=$(PKG_NAME)_$(PKG_VERSION)_linux_$(PKG_ARCH).tar.gz
|
||||
PKG_URL:=https://static.adguard.com/adguardhome/$(PKG_VERSION)/$(PKG_NAME)_linux_$(PKG_ARCH).tar.gz
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)/$(PKG_VERSION)
|
||||
PKG_HASH:=skip
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
|
||||
|
||||
define Package/AdGuardHome
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Network-wide ads and trackers blocking DNS server
|
||||
URL:=https://github.com/AdguardTeam/AdGuardHome
|
||||
DEPENDS:=$(GO_ARCH_DEPENDS) +ca-bundle
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Network-wide ads & trackers blocking DNS server
|
||||
URL:=https://github.com/AdguardTeam/AdGuardHome
|
||||
endef
|
||||
|
||||
define Package/AdGuardHome/description
|
||||
Free and open source, powerful network-wide ads and trackers blocking DNS server.
|
||||
define Package/$(PKG_NAME)/description
|
||||
Network-wide ads & trackers blocking DNS server
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
config ADGUARDHOME_COMPRESS_GOPROXY
|
||||
bool "Compiling with GOPROXY proxy"
|
||||
default n
|
||||
|
||||
config ADGUARDHOME_COMPRESS_UPX
|
||||
bool "Compress executable files with UPX"
|
||||
default n
|
||||
define Build/Prepare
|
||||
if [ ! -f $(DL_DIR)/$(PKG_FILE) ] ; then \
|
||||
curl -f --connect-timeout 20 --retry 5 --location --insecure $(PKG_URL) -o $(DL_DIR)/$(PKG_FILE); \
|
||||
fi
|
||||
rm -r $(PKG_BUILD_DIR)
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
tar -zxvf $(DL_DIR)/$(PKG_FILE) -C $(PKG_BUILD_DIR) --strip-components 1
|
||||
endef
|
||||
|
||||
ifeq ($(CONFIG_ADGUARDHOME_COMPRESS_GOPROXY),y)
|
||||
export GO111MODULE=on
|
||||
export GOPROXY=https://goproxy.io
|
||||
endif
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
( \
|
||||
cd $(PKG_BUILD_DIR) ; \
|
||||
npm --prefix client ci ; \
|
||||
npm --prefix client run build-prod ; \
|
||||
GOOS=$$$$(go env GOOS) GOARCH=$$$$(go env GOARCH) GO111MODULE=off go get -v github.com/gobuffalo/packr/... ; \
|
||||
"$$$$(go env GOPATH)/bin/packr" -v -z -i $(PKG_BUILD_DIR)/home ; \
|
||||
$(call GoPackage/Build/Compile) ; \
|
||||
)
|
||||
ifeq ($(CONFIG_ADGUARDHOME_COMPRESS_UPX),y)
|
||||
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/AdGuardHome
|
||||
endif
|
||||
endef
|
||||
|
||||
define Package/AdGuardHome/install
|
||||
$(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin/AdGuardHome
|
||||
$(INSTALL_BIN) $(GO_PKG_BUILD_BIN_DIR)/AdGuardHome $(1)/usr/bin/AdGuardHome/AdGuardHome
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin/AdGuardHome/$(PKG_NAME)
|
||||
$(INSTALL_DIR) $(1)/etc
|
||||
$(CP) -r ./files/etc $(1)/etc
|
||||
$(CP) -r ./files/etc/config $(1)/etc/config
|
||||
endef
|
||||
|
||||
$(eval $(call GoBinPackage,AdGuardHome))
|
||||
$(eval $(call BuildPackage,AdGuardHome))
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
@ -21,7 +21,7 @@ dns:
|
||||
blocking_mode: default
|
||||
blocking_ipv4: ""
|
||||
blocking_ipv6: ""
|
||||
blocked_response_ttl: 10
|
||||
blocked_response_ttl: 60
|
||||
parental_block_host: family-block.dns.adguard.com
|
||||
safebrowsing_block_host: standard-block.dns.adguard.com
|
||||
ratelimit: 0
|
||||
@ -29,18 +29,19 @@ dns:
|
||||
refuse_any: true
|
||||
upstream_dns:
|
||||
- tls://1dot1dot1dot1.cloudflare-dns.com
|
||||
- tls://dns.google
|
||||
- https://cloudflare-dns.com/dns-query
|
||||
- https://1.0.0.1/dns-query
|
||||
- https://dns.adgk.net:4433/dns-query
|
||||
- https://esdns.kbsml.com/dns-query
|
||||
- tcp://8.8.8.8
|
||||
- tcp://8.8.4.4
|
||||
- 117.50.11.11
|
||||
- 117.50.22.22
|
||||
- 223.5.5.5
|
||||
- 223.6.6.6
|
||||
- 119.29.29.29
|
||||
- 208.67.222.222
|
||||
- 114.114.114.114
|
||||
- 180.76.76.76
|
||||
upstream_dns_file: ""
|
||||
bootstrap_dns:
|
||||
- 119.29.29.29
|
||||
- 223.5.5.5
|
||||
@ -48,18 +49,23 @@ dns:
|
||||
- 8.8.8.8
|
||||
- 2620:fe::10
|
||||
- 2620:fe::fe:10
|
||||
all_servers: true
|
||||
all_servers: false
|
||||
fastest_addr: false
|
||||
allowed_clients: []
|
||||
disallowed_clients: []
|
||||
blocked_hosts: []
|
||||
cache_size: 4194304
|
||||
blocked_hosts:
|
||||
- version.bind
|
||||
- id.server
|
||||
- hostname.bind
|
||||
cache_size: 1194304
|
||||
cache_ttl_min: 60
|
||||
cache_ttl_max: 86400
|
||||
bogus_nxdomain: []
|
||||
aaaa_disabled: true
|
||||
enable_dnssec: true
|
||||
edns_client_subnet: true
|
||||
max_goroutines: 50
|
||||
ipset: []
|
||||
filtering_enabled: true
|
||||
filters_update_interval: 24
|
||||
parental_enabled: false
|
||||
@ -77,6 +83,7 @@ tls:
|
||||
force_https: false
|
||||
port_https: 443
|
||||
port_dns_over_tls: 853
|
||||
port_dns_over_quic: 784
|
||||
allow_unencrypted_doh: false
|
||||
strict_sni_check: false
|
||||
certificate_chain: ""
|
||||
@ -202,7 +209,6 @@ filters:
|
||||
id: 139789184
|
||||
whitelist_filters: []
|
||||
user_rules:
|
||||
- '@@||taobao.com^$important'
|
||||
- '@@||jd.com^important'
|
||||
- '@@||flyme.cn^$important'
|
||||
- '@@||meizu.com^$important'
|
||||
@ -217,12 +223,19 @@ user_rules:
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: ""
|
||||
gateway_ip: ""
|
||||
subnet_mask: ""
|
||||
range_start: ""
|
||||
range_end: ""
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
dhcpv4:
|
||||
gateway_ip: ""
|
||||
subnet_mask: ""
|
||||
range_start: ""
|
||||
range_end: ""
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
options: []
|
||||
dhcpv6:
|
||||
range_start: ""
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
clients: []
|
||||
log_compress: false
|
||||
log_localtime: false
|
||||
@ -231,4 +244,4 @@ log_max_size: 100
|
||||
log_max_age: 3
|
||||
log_file: ""
|
||||
verbose: false
|
||||
schema_version: 6
|
||||
schema_version: 7
|
||||
|
14
AdGuardHome/files/etc/config/AdGuardHome
Normal file
14
AdGuardHome/files/etc/config/AdGuardHome
Normal file
@ -0,0 +1,14 @@
|
||||
config AdGuardHome 'AdGuardHome'
|
||||
option enabled '0'
|
||||
option httpport '3000'
|
||||
option redirect 'none'
|
||||
option configpath '/etc/AdGuardHome.yaml'
|
||||
option workdir '/usr/bin/AdGuardHome'
|
||||
option logfile '/tmp/AdGuardHome.log'
|
||||
option verbose '0'
|
||||
option binpath '/usr/bin/AdGuardHome/AdGuardHome'
|
||||
option upxflag ''
|
||||
option redirect 'dnsmasq-upstream'
|
||||
option waitonboot '0'
|
||||
option ucitracktest '1'
|
||||
|
@ -84,7 +84,7 @@ sed -i '/log-facility/d' /etc/dnsmasq.conf
|
||||
echo "log-facility=/dev/null" >> /etc/dnsmasq.conf
|
||||
|
||||
sed -i 's/cbi.submit\"] = true/cbi.submit\"] = \"1\"/g' /usr/lib/lua/luci/dispatcher.lua
|
||||
/etc/modules-boot.d && ln -s ../modules.d/18-phy-broadcom
|
||||
#/etc/modules-boot.d && ln -s ../modules.d/18-phy-broadcom
|
||||
echo 'hsts=0' > /root/.wgetrc
|
||||
|
||||
rm -rf /tmp/luci-modulecache/
|
||||
|
@ -1,52 +0,0 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=https-dns-proxy
|
||||
PKG_VERSION:=2020-04-09
|
||||
PKG_RELEASE=3
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/aarond10/https_dns_proxy
|
||||
PKG_SOURCE_DATE:=2020-04-09
|
||||
PKG_SOURCE_VERSION:=40647ce94c62a47e9d53efae8018fb3142e277b9
|
||||
PKG_MIRROR_HASH:=4a8052b8bd482a17b769bcd4ee2620368f8c91955c5e976088be8d2ab002dde6
|
||||
PKG_MAINTAINER:=Stan Grishin <stangri@melmac.net>
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
CMAKE_OPTIONS += -DCLANG_TIDY_EXE=
|
||||
|
||||
define Package/https-dns-proxy
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=DNS Over HTTPS Proxy
|
||||
DEPENDS:=+libcares +libcurl +libev +ca-bundle
|
||||
CONFLICTS:=https_dns_proxy
|
||||
endef
|
||||
|
||||
define Package/https-dns-proxy/description
|
||||
https_dns_proxy is a light-weight DNS<-->HTTPS, non-caching translation proxy for the RFC 8484 DNS-over-HTTPS standard. It receives regular (UDP) DNS requests and issues them via DoH.
|
||||
Please see https://github.com/openwrt/packages/blob/master/net/https-dns-proxy/files/README.md for further information.
|
||||
endef
|
||||
|
||||
define Package/https-dns-proxy/conffiles
|
||||
/etc/config/https-dns-proxy
|
||||
endef
|
||||
|
||||
define Package/https-dns-proxy/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d ${1}/etc/config
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/https_dns_proxy $(1)/usr/sbin/https-dns-proxy
|
||||
$(INSTALL_BIN) ./files/https-dns-proxy.init $(1)/etc/init.d/https-dns-proxy
|
||||
$(INSTALL_CONF) ./files/https-dns-proxy.config $(1)/etc/config/https-dns-proxy
|
||||
endef
|
||||
|
||||
define Package/https-dns-proxy/postinst
|
||||
#!/bin/sh
|
||||
/etc/init.d/https-dns-proxy disable
|
||||
/etc/init.d/https-dns-proxy stop
|
||||
exit 0
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,https-dns-proxy))
|
@ -1,94 +0,0 @@
|
||||
# DNS Over HTTPS Proxy (https-dns-proxy)
|
||||
|
||||
A lean RFC8484-compatible (no JSON API support) DNS-over-HTTPS (DoH) proxy service which supports DoH servers ran by AdGuard, CleanBrowsing, Cloudflare, Google, ODVR (nic.cz) and Quad9. Based on [@aarond10](https://github.com/aarond10)'s [https-dns-proxy](https://github.com/aarond10/https_dns_proxy).
|
||||
|
||||
## Features
|
||||
|
||||
- [RFC8484](https://tools.ietf.org/html/rfc8484)-compatible DoH Proxy.
|
||||
- Compact size.
|
||||
- Web UI (```luci-app-https-dns-proxy```) available.
|
||||
- (By default) automatically updates DNSMASQ settings to use DoH proxy when it's started and reverts to old DNSMASQ resolvers when DoH proxy is stopped.
|
||||
|
||||
## Screenshots (luci-app-https-dns-proxy)
|
||||
|
||||
![screenshot](https://cdn.jsdelivr.net/gh/stangri/openwrt_packages@master/screenshots/https-dns-proxy/screenshot01.png "https-dns-proxy screenshot")
|
||||
|
||||
## Requirements
|
||||
|
||||
This proxy requires the following packages to be installed on your router: ```libc```, ```libcares```, ```libcurl```, ```libev```, ```ca-bundle```. They will be automatically installed when you're installing ```https-dns-proxy```.
|
||||
|
||||
## Unmet Dependencies
|
||||
|
||||
If you are running a development (trunk/snapshot) build of OpenWrt/LEDE Project on your router and your build is outdated (meaning that packages of the same revision/commit hash are no longer available and when you try to satisfy the [requirements](#requirements) you get errors), please flash either current LEDE release image or current development/snapshot image.
|
||||
|
||||
## How To Install
|
||||
|
||||
Install ```https-dns-proxy``` and ```luci-app-https-dns-proxy``` packages from Web UI or run the following in the command line:
|
||||
|
||||
```sh
|
||||
opkg update; opkg install https-dns-proxy luci-app-https-dns-proxy;
|
||||
```
|
||||
|
||||
## Default Settings
|
||||
|
||||
Default configuration has service enabled and starts the service with Google and Cloudflare DoH servers. In most configurations, you will keep the default ```DNSMASQ``` service installed to handle requests from devices in your local network and point ```DNSMASQ``` to use ```https-dns-proxy``` for name resolution.
|
||||
|
||||
By default, the service will intelligently override existing ```DNSMASQ``` servers settings on start to use the DoH servers and restores original ```DNSMASQ``` servers on stop. See the [Configuration Settings](#configuration-settings) section below for more information and how to disable this behavior.
|
||||
|
||||
## Configuration Settings
|
||||
|
||||
Configuration contains the (named) "main" config section where you can configure which ```DNSMASQ``` settings the service will automatically affect and the typed (unnamed) https-dns-proxy instance settings. The original config file is included below:
|
||||
|
||||
```text
|
||||
config main 'config'
|
||||
option update_dnsmasq_config '*'
|
||||
|
||||
config https-dns-proxy
|
||||
option bootstrap_dns '8.8.8.8,8.8.4.4'
|
||||
option resolver_url 'https://dns.google/dns-query'
|
||||
option listen_addr '127.0.0.1'
|
||||
option listen_port '5053'
|
||||
option user 'nobody'
|
||||
option group 'nogroup'
|
||||
|
||||
config https-dns-proxy
|
||||
option bootstrap_dns '1.1.1.1,1.0.0.1'
|
||||
option resolver_url 'https://cloudflare-dns.com/dns-query'
|
||||
option listen_addr '127.0.0.1'
|
||||
option listen_port '5054'
|
||||
option user 'nobody'
|
||||
option group 'nogroup'
|
||||
```
|
||||
|
||||
The ```update_dnsmasq_config``` option can be set to dash (set to ```'-'``` to not change ```DNSMASQ``` server settings on start/stop), can be set to ```'*'``` to affect all ```DNSMASQ``` instance server settings or have a space-separated list of ```DNSMASQ``` instances to affect (like ```'0 4 5'```). If this option is omitted, the default setting is ```'*'```.
|
||||
|
||||
Starting with ```https-dns-proxy``` version ```2019-12-03-3``` and higher, when the service is set to update the DNSMASQ servers setting on start/stop, it does not override entries which contain either ```#``` or ```/```, so the entries like listed below will be kept in use:
|
||||
|
||||
```test
|
||||
list server '/onion/127.0.0.1#65453'
|
||||
list server '/openwrt.org/8.8.8.8'
|
||||
list server '/pool.ntp.org/8.8.8.8'
|
||||
list server '127.0.0.1#15353'
|
||||
list server '127.0.0.1#55353'
|
||||
list server '127.0.0.1#65353'
|
||||
```
|
||||
|
||||
The https-dns-proxy instance settings are:
|
||||
|
||||
|Parameter|Type|Default|Description|
|
||||
| --- | --- | --- | --- |
|
||||
|bootstrap_dns|IP Address||The non-encrypted DNS servers to be used to resolve the DoH server name on start.|
|
||||
|listen_addr|IP Address|127.0.0.1|The local IP address to listen to requests.|
|
||||
|listen_port|port|5053 and up|If this setting is omitted, the service will start the first https-dns-proxy instance on port 5053, second on 5054 and so on.|
|
||||
|logfile|Full filepath||Full filepath to the file to log the instance events to.|
|
||||
|resolver_url|URL||The https URL to the RFC8484-compatible resolver.|
|
||||
|proxy_server|URL||Local proxy server to use when accessing resolvers.|
|
||||
|user|String|nobody|Local user to run instance under.|
|
||||
|group|String|nogroup|Local group to run instance under.|
|
||||
|use_http1|Boolean|0|If set to 1, use HTTP/1 on installations with broken/outdated ```curl``` package. Included for posterity reasons, you will most likely not ever need it on OpenWrt.|
|
||||
|verbosity|Integer|0|logging verbosity level. fatal = 0, error = 1, warning = 2, info = 3, debug = 4|
|
||||
|use_ipv6_resolvers_only|Boolean|0|If set to 1, Forces IPv6 DNS resolvers instead of IPv4|
|
||||
|
||||
## Thanks
|
||||
|
||||
This OpenWrt package wouldn't have been possible without [@aarond10](https://github.com/aarond10)'s [https-dns-proxy](https://github.com/aarond10/https_dns_proxy) and his active participation in the OpenWrt package itself. Special thanks to [@jow-](https://github.com/jow-) for general package/luci guidance.
|
@ -1,2 +0,0 @@
|
||||
config main 'config'
|
||||
option update_dnsmasq_config ''
|
@ -1,184 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright 2019 Stan Grishin (stangri@melmac.net)
|
||||
# shellcheck disable=SC2039
|
||||
|
||||
export START=80
|
||||
export USE_PROCD=1
|
||||
|
||||
dnsmasqConfig=''
|
||||
|
||||
PROG=/usr/sbin/https-dns-proxy
|
||||
|
||||
xappend() { param="$param $1"; }
|
||||
|
||||
append_bool() {
|
||||
local section="$1"
|
||||
local option="$2"
|
||||
local value="$3"
|
||||
local default="$4"
|
||||
local _loctmp
|
||||
[ -z "$default" ] && default="0"
|
||||
config_get_bool _loctmp "$section" "$option" "$default"
|
||||
[ "$_loctmp" != "0" ] && xappend "$value"
|
||||
}
|
||||
|
||||
append_parm() {
|
||||
local section="$1"
|
||||
local option="$2"
|
||||
local switch="$3"
|
||||
local default="$4"
|
||||
local _loctmp
|
||||
config_get _loctmp "$section" "$option" "$default"
|
||||
[ -z "$_loctmp" ] && return 0
|
||||
xappend "$switch $_loctmp"
|
||||
}
|
||||
|
||||
start_instance() {
|
||||
local cfg="$1" param listen_addr listen_port i
|
||||
|
||||
append_parm "$cfg" 'listen_addr' '-a' '127.0.0.1'
|
||||
append_parm "$cfg" 'listen_port' '-p' "$p"
|
||||
append_parm "$cfg" 'bootstrap_dns' '-b'
|
||||
append_parm "$cfg" 'resolver_url' '-r'
|
||||
append_parm "$cfg" 'user' '-u' 'nobody'
|
||||
append_parm "$cfg" 'group' '-g' 'nogroup'
|
||||
append_parm "$cfg" 'proxy_server' '-t'
|
||||
append_parm "$cfg" 'logfile' '-l'
|
||||
append_bool "$cfg" 'use_http1' '-x'
|
||||
config_get_bool ipv6_resolvers_only "$cfg" 'use_ipv6_resolvers_only' '0'
|
||||
config_get verbosity "$cfg" 'verbosity' "0"
|
||||
|
||||
# shellcheck disable=SC2086,SC2154
|
||||
for i in $(seq 1 $verbosity); do
|
||||
xappend "-v"
|
||||
done
|
||||
# shellcheck disable=SC2154
|
||||
if [ "$ipv6_resolvers_only" = 0 ]; then
|
||||
xappend "-4"
|
||||
fi
|
||||
|
||||
procd_open_instance
|
||||
# shellcheck disable=SC2086
|
||||
procd_set_param command ${PROG} ${param}
|
||||
procd_set_param stderr 1
|
||||
procd_set_param stdout 1
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
|
||||
config_get listen_addr "$cfg" 'listen_addr' '127.0.0.1'
|
||||
config_get listen_port "$cfg" 'listen_port' "$p"
|
||||
|
||||
if [ "$dnsmasqConfig" = "*" ]; then
|
||||
config_load 'dhcp'
|
||||
config_foreach dnsmasq_add_doh_server 'dnsmasq' "${listen_addr}" "${listen_port}"
|
||||
elif [ -n "$dnsmasqConfig" ]; then
|
||||
for i in $dnsmasqConfig; do
|
||||
dnsmasq_add_doh_server "@dnsmasq[${i}]" "${listen_addr}" "${listen_port}"
|
||||
done
|
||||
fi
|
||||
p="$((p+1))"
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger 'https-dns-proxy'
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local p=5053
|
||||
config_load 'https-dns-proxy'
|
||||
#config_get dnsmasqConfig 'config' 'update_dnsmasq_config' '*'
|
||||
dhcp_backup 'create'
|
||||
config_load 'https-dns-proxy'
|
||||
config_foreach start_instance 'https-dns-proxy'
|
||||
if [ -n "$(uci -q changes dhcp)" ]; then
|
||||
uci -q commit dhcp
|
||||
[ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
config_load 'https-dns-proxy'
|
||||
#config_get dnsmasqConfig 'config' 'update_dnsmasq_config' '*'
|
||||
dhcp_backup 'restore'
|
||||
if [ -n "$(uci -q changes dhcp)" ]; then
|
||||
uci -q commit dhcp
|
||||
[ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger 'https-dns-proxy'
|
||||
}
|
||||
|
||||
dnsmasq_add_doh_server() {
|
||||
local cfg="$1" address="$2" port="$3"
|
||||
case $address in
|
||||
0.0.0.0|::ffff:0.0.0.0) address='127.0.0.1';;
|
||||
::) address='::1';;
|
||||
esac
|
||||
uci -q del_list "dhcp.${cfg}.server=${address}#${port}"
|
||||
uci -q add_list "dhcp.${cfg}.server=${address}#${port}"
|
||||
}
|
||||
|
||||
dnsmasq_create_server_backup() {
|
||||
local cfg="$1"
|
||||
local i
|
||||
uci -q get "dhcp.${cfg}" >/dev/null || return 0
|
||||
if ! uci -q get "dhcp.${cfg}.doh_backup_noresolv" >/dev/null; then
|
||||
if [ -z "$(uci -q get "dhcp.${cfg}.noresolv")" ]; then
|
||||
uci -q set "dhcp.${cfg}.noresolv=1"
|
||||
uci -q set "dhcp.${cfg}.doh_backup_noresolv=-1"
|
||||
elif [ "$(uci -q get "dhcp.${cfg}.noresolv")" != "1" ]; then
|
||||
uci -q set "dhcp.${cfg}.noresolv=1"
|
||||
uci -q set "dhcp.${cfg}.doh_backup_noresolv=0"
|
||||
fi
|
||||
fi
|
||||
if ! uci -q get "dhcp.${cfg}.doh_backup_server" >/dev/null; then
|
||||
for i in $(uci -q get "dhcp.${cfg}.server"); do
|
||||
uci -q add_list "dhcp.${cfg}.doh_backup_server=$i"
|
||||
if [ "$i" = "${i//127.0.0.1}" ] && [ "$i" = "$(echo "$i" | tr -d /)" ]; then
|
||||
uci -q del_list "dhcp.${cfg}.server=$i"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
dnsmasq_restore_server_backup() {
|
||||
local cfg="$1"
|
||||
local i
|
||||
uci -q get "dhcp.${cfg}" >/dev/null || return 0
|
||||
if uci -q get "dhcp.${cfg}.doh_backup_noresolv" >/dev/null; then
|
||||
if [ "$(uci -q get "dhcp.${cfg}.doh_backup_noresolv")" = "0" ]; then
|
||||
uci -q set "dhcp.${cfg}.noresolv=0"
|
||||
else
|
||||
uci -q del "dhcp.${cfg}.noresolv"
|
||||
fi
|
||||
uci -q del "dhcp.${cfg}.doh_backup_noresolv"
|
||||
fi
|
||||
if uci -q get "dhcp.${cfg}.doh_backup_server" >/dev/null; then
|
||||
uci -q del "dhcp.${cfg}.server"
|
||||
for i in $(uci -q get "dhcp.${cfg}.doh_backup_server"); do
|
||||
uci -q add_list "dhcp.${cfg}.server=$i"
|
||||
done
|
||||
uci -q del "dhcp.${cfg}.doh_backup_server"
|
||||
fi
|
||||
}
|
||||
|
||||
dhcp_backup() {
|
||||
local i
|
||||
config_load 'dhcp'
|
||||
case "$1" in
|
||||
create)
|
||||
if [ "$dnsmasqConfig" = "*" ]; then
|
||||
config_foreach dnsmasq_create_server_backup 'dnsmasq'
|
||||
elif [ -n "$dnsmasqConfig" ]; then
|
||||
for i in $dnsmasqConfig; do
|
||||
dnsmasq_create_server_backup "@dnsmasq[${i}]"
|
||||
done
|
||||
fi
|
||||
;;
|
||||
restore)
|
||||
config_foreach dnsmasq_restore_server_backup 'dnsmasq'
|
||||
;;
|
||||
esac
|
||||
}
|
@ -17,7 +17,7 @@ define Package/luci-app-adguardhome
|
||||
TITLE:=LuCI app for adguardhome
|
||||
PKG_MAINTAINER:=<https://github.com/rufengsuixing/luci-app-adguardhome>
|
||||
PKGARCH:=all
|
||||
DEPENDS:=+AdGuardHome +!wget&&!curl:wget
|
||||
DEPENDS:=+!wget&&!curl:wget
|
||||
endef
|
||||
|
||||
define Package/luci-app-adguardhome/description
|
||||
|
@ -1,12 +1,13 @@
|
||||
require("luci.sys")
|
||||
require("luci.util")
|
||||
require("io")
|
||||
local m,s,o,o1
|
||||
local fs=require"nixio.fs"
|
||||
local uci=require"luci.model.uci".cursor()
|
||||
local configpath=uci:get("AdGuardHome","AdGuardHome","configpath") or "/etc/AdGuardHome.yaml"
|
||||
local binpath=uci:get("AdGuardHome","AdGuardHome","binpath") or "/usr/bin/AdGuardHome/AdGuardHome"
|
||||
httpport=uci:get("AdGuardHome","AdGuardHome","httpport") or "3000"
|
||||
local m, s, o, o1
|
||||
local fs = require "nixio.fs"
|
||||
local uci = require"luci.model.uci".cursor()
|
||||
local configpath = uci:get("AdGuardHome", "AdGuardHome", "configpath") or "/etc/config/AdGuardHome.yaml"
|
||||
local binpath = uci:get("AdGuardHome", "AdGuardHome", "binpath") or "/usr/bin/AdGuardHome/AdGuardHome"
|
||||
httpport = uci:get("AdGuardHome", "AdGuardHome", "httpport") or "3000"
|
||||
|
||||
m = Map("AdGuardHome", "AdGuard Home")
|
||||
m.description = translate("Free and open source, powerful network-wide ads & trackers blocking DNS server.")
|
||||
m:section(SimpleSection).template = "AdGuardHome/AdGuardHome_status"
|
||||
@ -102,8 +103,8 @@ o.rmempty = true
|
||||
|
||||
---- config path
|
||||
o = s:option(Value, "configpath", translate("Config Path"), translate("AdGuardHome config path"))
|
||||
o.default = "/etc/AdGuardHome.yaml"
|
||||
o.datatype = "string"
|
||||
o.default = "/etc/config/AdGuardHome.yaml"
|
||||
o.datatype = "string"
|
||||
o.optional = false
|
||||
o.rmempty = false
|
||||
o.validate = function(self, value)
|
||||
|
@ -21,7 +21,7 @@ dns:
|
||||
blocking_mode: default
|
||||
blocking_ipv4: ""
|
||||
blocking_ipv6: ""
|
||||
blocked_response_ttl: 10
|
||||
blocked_response_ttl: 60
|
||||
parental_block_host: family-block.dns.adguard.com
|
||||
safebrowsing_block_host: standard-block.dns.adguard.com
|
||||
ratelimit: 0
|
||||
@ -29,18 +29,19 @@ dns:
|
||||
refuse_any: true
|
||||
upstream_dns:
|
||||
- tls://1dot1dot1dot1.cloudflare-dns.com
|
||||
- tls://dns.google
|
||||
- https://cloudflare-dns.com/dns-query
|
||||
- https://1.0.0.1/dns-query
|
||||
- https://dns.adgk.net:4433/dns-query
|
||||
- https://esdns.kbsml.com/dns-query
|
||||
- tcp://8.8.8.8
|
||||
- tcp://8.8.4.4
|
||||
- 117.50.11.11
|
||||
- 117.50.22.22
|
||||
- 223.5.5.5
|
||||
- 223.6.6.6
|
||||
- 119.29.29.29
|
||||
- 208.67.222.222
|
||||
- 114.114.114.114
|
||||
- 180.76.76.76
|
||||
upstream_dns_file: ""
|
||||
bootstrap_dns:
|
||||
- 119.29.29.29
|
||||
- 223.5.5.5
|
||||
@ -48,18 +49,23 @@ dns:
|
||||
- 8.8.8.8
|
||||
- 2620:fe::10
|
||||
- 2620:fe::fe:10
|
||||
all_servers: true
|
||||
all_servers: false
|
||||
fastest_addr: false
|
||||
allowed_clients: []
|
||||
disallowed_clients: []
|
||||
blocked_hosts: []
|
||||
cache_size: 4194304
|
||||
blocked_hosts:
|
||||
- version.bind
|
||||
- id.server
|
||||
- hostname.bind
|
||||
cache_size: 1194304
|
||||
cache_ttl_min: 60
|
||||
cache_ttl_max: 86400
|
||||
bogus_nxdomain: []
|
||||
aaaa_disabled: true
|
||||
enable_dnssec: true
|
||||
edns_client_subnet: true
|
||||
max_goroutines: 50
|
||||
ipset: []
|
||||
filtering_enabled: true
|
||||
filters_update_interval: 24
|
||||
parental_enabled: false
|
||||
@ -77,6 +83,7 @@ tls:
|
||||
force_https: false
|
||||
port_https: 443
|
||||
port_dns_over_tls: 853
|
||||
port_dns_over_quic: 784
|
||||
allow_unencrypted_doh: false
|
||||
strict_sni_check: false
|
||||
certificate_chain: ""
|
||||
@ -202,7 +209,6 @@ filters:
|
||||
id: 139789184
|
||||
whitelist_filters: []
|
||||
user_rules:
|
||||
- '@@||taobao.com^$important'
|
||||
- '@@||jd.com^important'
|
||||
- '@@||flyme.cn^$important'
|
||||
- '@@||meizu.com^$important'
|
||||
@ -217,12 +223,19 @@ user_rules:
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: ""
|
||||
gateway_ip: ""
|
||||
subnet_mask: ""
|
||||
range_start: ""
|
||||
range_end: ""
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
dhcpv4:
|
||||
gateway_ip: ""
|
||||
subnet_mask: ""
|
||||
range_start: ""
|
||||
range_end: ""
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
options: []
|
||||
dhcpv6:
|
||||
range_start: ""
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
clients: []
|
||||
log_compress: false
|
||||
log_localtime: false
|
||||
@ -231,4 +244,4 @@ log_max_size: 100
|
||||
log_max_age: 3
|
||||
log_file: ""
|
||||
verbose: false
|
||||
schema_version: 6
|
||||
schema_version: 7
|
||||
|
@ -1,7 +1,6 @@
|
||||
config AdGuardHome 'AdGuardHome'
|
||||
option enabled '0'
|
||||
option httpport '3000'
|
||||
option redirect 'none'
|
||||
option configpath '/etc/AdGuardHome.yaml'
|
||||
option workdir '/usr/bin/AdGuardHome'
|
||||
option logfile '/tmp/AdGuardHome.log'
|
||||
@ -9,3 +8,8 @@ config AdGuardHome 'AdGuardHome'
|
||||
option binpath '/usr/bin/AdGuardHome/AdGuardHome'
|
||||
option upxflag ''
|
||||
option redirect 'dnsmasq-upstream'
|
||||
option waitonboot '0'
|
||||
option ucitracktest '1'
|
||||
list old_redirect 'dnsmasq-upstream'
|
||||
list old_port '5333'
|
||||
list old_enabled '0'
|
||||
|
@ -1,5 +1,3 @@
|
||||
#提交就可以直接用的配置模板文件
|
||||
#a template config can be use with a apply
|
||||
bind_host: 0.0.0.0
|
||||
bind_port: 3000
|
||||
users:
|
||||
@ -14,27 +12,62 @@ dns:
|
||||
bind_host: 0.0.0.0
|
||||
port: 5553
|
||||
statistics_interval: 1
|
||||
protection_enabled: true
|
||||
filtering_enabled: true
|
||||
filters_update_interval: 24
|
||||
blocking_mode: nxdomain
|
||||
blocked_response_ttl: 10
|
||||
querylog_enabled: false
|
||||
querylog_enabled: true
|
||||
querylog_file_enabled: true
|
||||
querylog_interval: 1
|
||||
querylog_size_memory: 1000
|
||||
anonymize_client_ip: false
|
||||
protection_enabled: true
|
||||
blocking_mode: default
|
||||
blocking_ipv4: ""
|
||||
blocking_ipv6: ""
|
||||
blocked_response_ttl: 60
|
||||
parental_block_host: family-block.dns.adguard.com
|
||||
safebrowsing_block_host: standard-block.dns.adguard.com
|
||||
ratelimit: 0
|
||||
ratelimit_whitelist: []
|
||||
refuse_any: false
|
||||
refuse_any: true
|
||||
upstream_dns:
|
||||
- tls://1dot1dot1dot1.cloudflare-dns.com
|
||||
- https://1.0.0.1/dns-query
|
||||
- https://dns.adgk.net:4433/dns-query
|
||||
- https://esdns.kbsml.com/dns-query
|
||||
- tcp://8.8.8.8
|
||||
- tcp://8.8.4.4
|
||||
- 117.50.11.11
|
||||
- 117.50.22.22
|
||||
- 223.5.5.5
|
||||
- 223.6.6.6
|
||||
- 208.67.222.222
|
||||
- 114.114.114.114
|
||||
- 180.76.76.76
|
||||
upstream_dns_file: ""
|
||||
bootstrap_dns:
|
||||
#bootstrap_dns
|
||||
- 119.29.29.29
|
||||
- 223.5.5.5
|
||||
- 114.114.114.114
|
||||
- 8.8.8.8
|
||||
- 2620:fe::10
|
||||
- 2620:fe::fe:10
|
||||
all_servers: false
|
||||
fastest_addr: false
|
||||
allowed_clients: []
|
||||
disallowed_clients: []
|
||||
blocked_hosts: []
|
||||
parental_block_host: ""
|
||||
safebrowsing_block_host: ""
|
||||
blocked_services: []
|
||||
cache_size: 4194304
|
||||
parental_sensitivity: 13
|
||||
blocked_hosts:
|
||||
- version.bind
|
||||
- id.server
|
||||
- hostname.bind
|
||||
cache_size: 1194304
|
||||
cache_ttl_min: 60
|
||||
cache_ttl_max: 86400
|
||||
bogus_nxdomain: []
|
||||
aaaa_disabled: true
|
||||
enable_dnssec: true
|
||||
edns_client_subnet: true
|
||||
max_goroutines: 50
|
||||
ipset: []
|
||||
filtering_enabled: true
|
||||
filters_update_interval: 24
|
||||
parental_enabled: false
|
||||
safesearch_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
@ -43,77 +76,172 @@ dns:
|
||||
parental_cache_size: 1048576
|
||||
cache_time: 30
|
||||
rewrites: []
|
||||
upstream_dns:
|
||||
#upstream_dns
|
||||
blocked_services: []
|
||||
tls:
|
||||
enabled: false
|
||||
server_name: ""
|
||||
force_https: false
|
||||
port_https: 443
|
||||
port_dns_over_tls: 853
|
||||
port_dns_over_quic: 784
|
||||
allow_unencrypted_doh: false
|
||||
strict_sni_check: false
|
||||
certificate_chain: ""
|
||||
private_key: ""
|
||||
certificate_path: ""
|
||||
private_key_path: ""
|
||||
filters:
|
||||
- enabled: true
|
||||
url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
|
||||
name: AdGuard Simplified Domain Names filter
|
||||
id: 1
|
||||
- enabled: true
|
||||
url: https://adaway.org/hosts.txt
|
||||
name: AdAway
|
||||
id: 2
|
||||
- enabled: false
|
||||
url: https://hosts-file.net/ad_servers.txt
|
||||
name: hpHosts - Ad and Tracking servers only
|
||||
id: 3
|
||||
name: Adaway HOST
|
||||
id: 139789111
|
||||
- enabled: true
|
||||
url: https://raw.githubusercontent.com/neodevpro/neodevhost/master/adblocker
|
||||
name: NEO DEV HOST
|
||||
id: 139789112
|
||||
- enabled: true
|
||||
url: https://banbendalao.coding.net/p/adgk/d/ADgk/git/raw/master/ADgk.txt
|
||||
name: adgk手机去广告规则
|
||||
id: 139789121
|
||||
- enabled: true
|
||||
url: https://cdn.jsdelivr.net/gh/privacy-protection-tools/anti-AD@master/anti-ad-easylist.txt
|
||||
name: anti-AD命中率最高列表
|
||||
id: 139789122
|
||||
- enabled: true
|
||||
url: https://gitee.com/halflife/list/raw/master/ad.txt
|
||||
name: halflife合并乘风
|
||||
id: 139789131
|
||||
- enabled: true
|
||||
url: https://easylist.to/easylist/easyprivacy.txt
|
||||
name: EasyPrivacy隐私相关
|
||||
id: 139789132
|
||||
- enabled: true
|
||||
url: https://www.i-dont-care-about-cookies.eu/abp/
|
||||
name: I don't care about cookies隐私相关
|
||||
id: 139789133
|
||||
- enabled: true
|
||||
url: https://gitee.com/cjx82630/cjxlist/raw/master/cjx-ublock.txt
|
||||
name: CJX's uBlock list隐私相关
|
||||
id: 139789141
|
||||
- enabled: false
|
||||
url: https://gitee.com/xinggsf/Adblock-Rule/raw/master/rule.txt
|
||||
name: 乘风 广告过滤规则
|
||||
id: 139789142
|
||||
- enabled: false
|
||||
url: https://gitee.com/xinggsf/Adblock-Rule/raw/master/mv.txt
|
||||
name: 乘风 视频广告过滤规则
|
||||
id: 139789143
|
||||
- enabled: false
|
||||
url: https://raw.githubusercontent.com/Goooler/1024_hosts/master/hosts
|
||||
name: 1024host
|
||||
id: 139789151
|
||||
- enabled: false
|
||||
url: https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext
|
||||
name: Peter Lowe’s Ad and tracking server list
|
||||
id: 139789152
|
||||
- enabled: false
|
||||
url: https://easylist.to/easylist/fanboy-social.txt
|
||||
name: Fanboy's Social Blocking List
|
||||
id: 139789153
|
||||
- enabled: false
|
||||
url: https://easylist.to/easylist/fanboy-annoyance.txt
|
||||
name: Fanboy's Annoyance List
|
||||
id: 139789154
|
||||
- enabled: false
|
||||
url: https://secure.fanboy.co.nz/fanboy-cookiemonster.txt
|
||||
name: EasyList Cookie List
|
||||
id: 139789155
|
||||
- enabled: false
|
||||
url: https://fanboy.co.nz/fanboy-antifacebook.txt
|
||||
name: Anti-Facebook List
|
||||
id: 139789161
|
||||
- enabled: false
|
||||
url: https://filters.adtidy.org/extension/ublock/filters/14.txt
|
||||
name: AdGuard Annoyances filter
|
||||
id: 139789162
|
||||
- enabled: false
|
||||
url: https://www.malwaredomainlist.com/hostslist/hosts.txt
|
||||
name: MalwareDomainList.com Hosts List
|
||||
id: 4
|
||||
id: 139789163
|
||||
- enabled: false
|
||||
url: https://raw.githubusercontent.com/vokins/yhosts/master/data/tvbox.txt
|
||||
name: tvbox
|
||||
id: 1575018007
|
||||
- enabled: true
|
||||
url: https://hosts.nfz.moe/full/hosts
|
||||
name: neoHosts full
|
||||
id: 1575618240
|
||||
url: https://www.fanboy.co.nz/enhancedstats.txt
|
||||
name: Fanboy's Enhanced Tracking List
|
||||
id: 139789164
|
||||
- enabled: false
|
||||
url: https://hosts.nfz.moe/basic/hosts
|
||||
name: neoHosts basic
|
||||
id: 1575618241
|
||||
url: https://filters.adtidy.org/extension/ublock/filters/3.txt
|
||||
name: AdGuard Tracking Protection filter
|
||||
id: 139789165
|
||||
- enabled: false
|
||||
url: http://sbc.io/hosts/hosts
|
||||
name: StevenBlack host basic
|
||||
id: 1575618242
|
||||
url: https://easylist.to/easylist/easylist.txt
|
||||
name: EasyList
|
||||
id: 139789171
|
||||
- enabled: false
|
||||
url: http://sbc.io/hosts/alternates/fakenews-gambling-porn-social/hosts
|
||||
name: StevenBlack host+fakenews + gambling + porn + social
|
||||
id: 1575618243
|
||||
url: https://filters.adtidy.org/extension/ublock/filters/11.txt
|
||||
name: AdGuard Mobile Ads filter
|
||||
id: 139789172
|
||||
- enabled: false
|
||||
url: https://cdn.jsdelivr.net/gh/privacy-protection-tools/anti-AD/anti-ad-easylist.txt
|
||||
name: anti-AD(Adblock+neohosts+yhosts+cjxlist+adhlist)
|
||||
id: 1577113202
|
||||
url: https://filters.adtidy.org/extension/ublock/filters/2_without_easylist.txt
|
||||
name: AdGuard Base filter
|
||||
id: 139789173
|
||||
- enabled: false
|
||||
url: https://easylist-downloads.adblockplus.org/antiadblockfilters.txt
|
||||
name: Adblock Warning Removal List
|
||||
id: 139789174
|
||||
- enabled: false
|
||||
url: https://fanboy.co.nz/fanboy-problematic-sites.txt
|
||||
name: Fanboy's problematic-sites
|
||||
id: 139789175
|
||||
- enabled: false
|
||||
url: http://sub.adtchrome.com/adt-chinalist-easylist.txt
|
||||
name: ChinaList+EasyList(修正)
|
||||
id: 139789181
|
||||
- enabled: false
|
||||
url: https://raw.githubusercontent.com/adbyby/xwhyc-rules/master/lazy.txt
|
||||
name: Adbyby Lazy Rule
|
||||
id: 139789182
|
||||
- enabled: false
|
||||
url: https://raw.githubusercontent.com/VeleSila/yhosts/master/hosts.txt
|
||||
name: hosts
|
||||
id: 139789183
|
||||
- enabled: false
|
||||
url: https://gitlab.com/xuhaiyang1234/AAK-Cont/raw/master/FINAL_BUILD/aak-cont-list-notubo.txt
|
||||
name: aak-cont-list-notubo
|
||||
id: 139789184
|
||||
whitelist_filters: []
|
||||
user_rules:
|
||||
- '@@||jd.com^important'
|
||||
- '@@||flyme.cn^$important'
|
||||
- '@@||meizu.com^$important'
|
||||
- '@@||wl.jd.com^$important'
|
||||
- '@@||taobao.com^$important'
|
||||
- '@@||flydigi.com^'
|
||||
- '@@||pv.sohu.com^$important'
|
||||
- /googleads.$~script,domain=~googleads.github.io
|
||||
- /pagead/lvz?
|
||||
- '||google.com/pagead/'
|
||||
- '||static.doubleclick.net^$domain=youtube.com'
|
||||
- '||youtube.com/get_midroll_'
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: ""
|
||||
gateway_ip: ""
|
||||
subnet_mask: ""
|
||||
range_start: ""
|
||||
range_end: ""
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
dhcpv4:
|
||||
gateway_ip: ""
|
||||
subnet_mask: ""
|
||||
range_start: ""
|
||||
range_end: ""
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
options: []
|
||||
dhcpv6:
|
||||
range_start: ""
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
clients: []
|
||||
log_compress: false
|
||||
log_localtime: false
|
||||
log_max_backups: 0
|
||||
log_max_size: 100
|
||||
log_max_age: 3
|
||||
log_file: ""
|
||||
verbose: false
|
||||
schema_version: 5
|
||||
schema_version: 7
|
||||
|
@ -1,18 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 OpenWrt.org
|
||||
# Á÷Á¿Í³¼Æ
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI support for Wrtbwmon-pd
|
||||
PKG_NAME:=luci-app-wrtbwmon-pd
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=7
|
||||
LUCI_DEPENDS:=+wrtbwmon
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
@ -1,575 +0,0 @@
|
||||
var wrt = {
|
||||
// variables for auto-update, interval is in seconds
|
||||
scheduleTimeout: undefined,
|
||||
updateTimeout: undefined,
|
||||
isScheduled: true,
|
||||
interval: 5,
|
||||
// option on whether to show per host sub-totals
|
||||
perHostTotals: false,
|
||||
// variables for sorting
|
||||
sortData: {
|
||||
column: 7,
|
||||
elId: 'thTotal',
|
||||
dir: 'desc',
|
||||
cache: {}
|
||||
}
|
||||
};
|
||||
|
||||
(function () {
|
||||
var oldDate, oldValues = [];
|
||||
|
||||
// find base path
|
||||
var re = /(.*?admin\/status\/[^/]+)/;
|
||||
var basePath = window.location.pathname.match(re)[1];
|
||||
|
||||
//----------------------
|
||||
// HELPER FUNCTIONS
|
||||
//----------------------
|
||||
|
||||
/**
|
||||
* Human readable text for size
|
||||
* @param size
|
||||
* @returns {string}
|
||||
*/
|
||||
function getSize(size) {
|
||||
var prefix = [' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z'];
|
||||
var precision, base = 1000, pos = 0;
|
||||
while (size > base) {
|
||||
size /= base;
|
||||
pos++;
|
||||
}
|
||||
if (pos > 2) precision = 1000; else precision = 1;
|
||||
return (Math.round(size * precision) / precision) + ' ' + prefix[pos] + 'B';
|
||||
}
|
||||
|
||||
/**
|
||||
* Human readable text for date
|
||||
* @param date
|
||||
* @returns {string}
|
||||
*/
|
||||
function dateToString(date) {
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string representation of the date received from BE
|
||||
* @param value
|
||||
* @returns {*}
|
||||
*/
|
||||
function getDateString(value) {
|
||||
var tmp = value.split('_'),
|
||||
str = tmp[0].split('-').reverse().join('-') + 'T' + tmp[1];
|
||||
return dateToString(new Date(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `tr` element with content
|
||||
* @param content
|
||||
* @returns {string}
|
||||
*/
|
||||
function createTR(content) {
|
||||
var res = '<tr';
|
||||
res += ' class="tr">';
|
||||
res += content;
|
||||
res += '</tr>';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `th` element with content and options
|
||||
* @param content
|
||||
* @param opts
|
||||
* @returns {string}
|
||||
*/
|
||||
function createTH(content, opts) {
|
||||
opts = opts || {};
|
||||
var res = '<th';
|
||||
if (opts.left) {
|
||||
res += ' align="left"';
|
||||
}
|
||||
if (opts.right) {
|
||||
res += ' align="right"';
|
||||
}
|
||||
if (opts.center) {
|
||||
res += ' align="center"';
|
||||
}
|
||||
if (opts.title) {
|
||||
res += ' title="' + opts.title + '"';
|
||||
}
|
||||
if (opts.id) {
|
||||
res += ' id="' + opts.id + '"';
|
||||
}
|
||||
res += ' class="th">';
|
||||
res += content;
|
||||
res += '</th>';
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `td` element with content and options
|
||||
* @param content
|
||||
* @param opts
|
||||
* @returns {string}
|
||||
*/
|
||||
function createTD(content, opts) {
|
||||
opts = opts || {};
|
||||
var res = '<td';
|
||||
if (opts.right) {
|
||||
res += ' align="right"';
|
||||
}
|
||||
if (opts.center) {
|
||||
res += ' align="center"';
|
||||
}
|
||||
if (opts.title) {
|
||||
res += ' title="' + opts.title + '"';
|
||||
}
|
||||
res += ' class="td">';
|
||||
res += content;
|
||||
res += '</td>';
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if obj is instance of Array
|
||||
* @param obj
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isArray(obj) {
|
||||
return obj instanceof Array;
|
||||
}
|
||||
|
||||
//----------------------
|
||||
// END HELPER FUNCTIONS
|
||||
//----------------------
|
||||
|
||||
/**
|
||||
* Handle the error that happened during the call to the BE
|
||||
*/
|
||||
function handleError() {
|
||||
// TODO handle errors
|
||||
// var message = 'Something went wrong...';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the new `values` that were received from the BE
|
||||
* @param values
|
||||
* @returns {string}
|
||||
*/
|
||||
function handleValues(values) {
|
||||
if (!isArray(values)) return '';
|
||||
|
||||
// find data and totals
|
||||
var res = parseValues(values);
|
||||
var data = res[0];
|
||||
var totals = res[1];
|
||||
|
||||
// aggregate (sub-total) by hostname (or MAC address) after the global totals are computed, before sort and display
|
||||
aggregateHostTotals(data);
|
||||
|
||||
// store them in cache for quicker re-rendering
|
||||
wrt.sortData.cache.data = data;
|
||||
wrt.sortData.cache.totals = totals;
|
||||
|
||||
renderTableData(data, totals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the table body
|
||||
* @param data
|
||||
* @param totals
|
||||
*/
|
||||
function renderTableData(data, totals) {
|
||||
// sort data
|
||||
data.sort(sortingFunction);
|
||||
|
||||
// display data
|
||||
document.getElementById('tableBody').innerHTML = getDisplayData(data, totals);
|
||||
|
||||
// set sorting arrows
|
||||
var el = document.getElementById(wrt.sortData.elId);
|
||||
if (el) {
|
||||
el.innerHTML = el.innerHTML + (wrt.sortData.dir === 'desc' ? '▼' : '▲');
|
||||
}
|
||||
|
||||
// register table events
|
||||
registerTableEventHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the values and returns a data array, where each element in the data array is an array with two elements,
|
||||
* and a totals array, that holds aggregated values for each column.
|
||||
* The first element of each row in the data array, is the HTML output of the row as a `tr` element
|
||||
* and the second is the actual data:
|
||||
* [ result, data ]
|
||||
* @param values The `values` array
|
||||
* @returns {Array}
|
||||
*/
|
||||
function parseValues(values) {
|
||||
var data = [], totals = [0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var d = parseValueRow(values[i]);
|
||||
if (d[1]) {
|
||||
data.push(d);
|
||||
// get totals
|
||||
for (var j = 0; j < totals.length; j++) {
|
||||
totals[j] += d[1][3 + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [data, totals];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse each row in the `values` array and return an array with two elements.
|
||||
* The first element is the HTML output of the row as a `tr` element and the second is the actual data
|
||||
* [ result, data ]
|
||||
* @param data A row from the `values` array
|
||||
* @returns {[ string, [] ]}
|
||||
*/
|
||||
function parseValueRow(data) {
|
||||
// check if data is array
|
||||
if (!isArray(data)) return [''];
|
||||
|
||||
// find old data
|
||||
var oldData;
|
||||
for (var i = 0; i < oldValues.length; i++) {
|
||||
var cur = oldValues[i];
|
||||
// compare mac addresses and ip addresses
|
||||
if (oldValues[i][1] === data[1] && oldValues[i][2] === data[2]) {
|
||||
oldData = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// find download and upload speeds
|
||||
var dlSpeed = 0, upSpeed = 0;
|
||||
if (oldData) {
|
||||
var now = new Date(),
|
||||
seconds = (now - oldDate) / 1000;
|
||||
dlSpeed = (data[3] - oldData[3]) / seconds;
|
||||
upSpeed = (data[4] - oldData[4]) / seconds;
|
||||
}
|
||||
|
||||
// create rowData
|
||||
var rowData = [];
|
||||
for (var j = 0; j < data.length; j++) {
|
||||
rowData.push(data[j]);
|
||||
if (j === 2) {
|
||||
rowData.push(dlSpeed, upSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
// create displayData
|
||||
var displayData = [
|
||||
createTD(data[0] + '<br />' + data[2], {title: data[1]}),
|
||||
createTD(getSize(dlSpeed) + '/s', {right: true}),
|
||||
createTD(getSize(upSpeed) + '/s', {right: true}),
|
||||
createTD(getSize(data[3]), {right: true}),
|
||||
createTD(getSize(data[4]), {right: true}),
|
||||
createTD(getSize(data[5]), {right: true}),
|
||||
createTD(getDateString(data[6]), {center: true}),
|
||||
createTD(getDateString(data[7]), {center: true})
|
||||
];
|
||||
|
||||
// display row data
|
||||
var result = '';
|
||||
for (var k = 0; k < displayData.length; k++) {
|
||||
result += displayData[k];
|
||||
}
|
||||
result = createTR(result);
|
||||
return [result, rowData];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the HTML output based on the `data` and `totals` inputs
|
||||
* @param data
|
||||
* @param totals
|
||||
* @returns {string} HTML output
|
||||
*/
|
||||
function getDisplayData(data, totals) {
|
||||
var result =
|
||||
createTH('目标主机', {id: 'thClient'}) +
|
||||
createTH('下行速率', {id: 'thDownload', right: true}) +
|
||||
createTH('上行速率', {id: 'thUpload', right: true}) +
|
||||
createTH('总下载量', {id: 'thTotalDown', right: true}) +
|
||||
createTH('总上传量', {id: 'thTotalUp', right: true}) +
|
||||
createTH('累计流量', {id: 'thTotal', right: true}) +
|
||||
createTH('首次可见', {id: 'thFirstSeen'}) +
|
||||
createTH('最后可见', {id: 'thLastSeen'});
|
||||
result = createTR(result);
|
||||
for (var k = 0; k < data.length; k++) {
|
||||
result += data[k][0];
|
||||
}
|
||||
var totalsRow = createTH('总计');
|
||||
for (var m = 0; m < totals.length; m++) {
|
||||
var t = totals[m];
|
||||
totalsRow += createTD(getSize(t) + (m < 2 ? '/s' : ''), {right: true});
|
||||
}
|
||||
result += createTR(totalsRow);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates per host sub-totals and adds them in the data input
|
||||
* @param data The data input
|
||||
*/
|
||||
function aggregateHostTotals(data) {
|
||||
if (!wrt.perHostTotals) return;
|
||||
|
||||
var curHost = 0, insertAt = 1;
|
||||
while (curHost < data.length && insertAt < data.length) {
|
||||
// grab the current hostname/mac, and walk the data looking for rows with the same host/mac
|
||||
var hostName = data[curHost][1][0].toLowerCase();
|
||||
for (var k = curHost + 1; k < data.length; k++) {
|
||||
if (data[k][1][0].toLowerCase() === hostName) {
|
||||
// this is another row for the same host, group it with any other rows for this host
|
||||
data.splice(insertAt, 0, data.splice(k, 1)[0]);
|
||||
insertAt++;
|
||||
}
|
||||
}
|
||||
|
||||
// if we found more than one row for the host, add a subtotal row
|
||||
if (insertAt > curHost + 1) {
|
||||
var hostTotals = [data[curHost][1][0], '', '', 0, 0, 0, 0, 0];
|
||||
for (var i = curHost; i < insertAt && i < data.length; i++) {
|
||||
for (var j = 3; j < hostTotals.length; j++) {
|
||||
hostTotals[j] += data[i][1][j];
|
||||
}
|
||||
}
|
||||
var hostTotalRow = createTH(data[curHost][1][0] + '<br/> (同名主机合并)', {title: data[curHost][1][1], left: true});
|
||||
for (var m = 3; m < hostTotals.length; m++) {
|
||||
var t = hostTotals[m];
|
||||
hostTotalRow += createTD(getSize(t) + (m < 5 ? '/s' : ''), {right: true});
|
||||
}
|
||||
//__时间占位符__
|
||||
hostTotalRow += createTD("-", {center: true});
|
||||
hostTotalRow += createTD("-", {center: true});
|
||||
|
||||
hostTotalRow = createTR(hostTotalRow);
|
||||
data.splice(insertAt, 0, [hostTotalRow, hostTotals]);
|
||||
}
|
||||
curHost = insertAt;
|
||||
insertAt = curHost + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorting function used to sort the `data`. Uses the global sort settings
|
||||
* @param x first item to compare
|
||||
* @param y second item to compare
|
||||
* @returns {number} 1 for desc, -1 for asc, 0 for equal
|
||||
*/
|
||||
function sortingFunction(x, y) {
|
||||
// get data from global variable
|
||||
var sortColumn = wrt.sortData.column, sortDirection = wrt.sortData.dir;
|
||||
var a = x[1][sortColumn];
|
||||
var b = y[1][sortColumn];
|
||||
if (a === b) {
|
||||
return 0;
|
||||
} else if (sortDirection === 'desc') {
|
||||
return a < b ? 1 : -1;
|
||||
} else {
|
||||
return a > b ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the relevant global sort variables and re-renders the table to apply the new sorting
|
||||
* @param elId
|
||||
* @param column
|
||||
*/
|
||||
function setSortColumn(elId, column) {
|
||||
if (column === wrt.sortData.column) {
|
||||
// same column clicked, switch direction
|
||||
wrt.sortData.dir = wrt.sortData.dir === 'desc' ? 'asc' : 'desc';
|
||||
} else {
|
||||
// change sort column
|
||||
wrt.sortData.column = column;
|
||||
// reset sort direction
|
||||
wrt.sortData.dir = 'desc';
|
||||
}
|
||||
wrt.sortData.elId = elId;
|
||||
|
||||
// render table data from cache
|
||||
renderTableData(wrt.sortData.cache.data, wrt.sortData.cache.totals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the table events handlers for sorting when clicking the column headers
|
||||
*/
|
||||
function registerTableEventHandlers() {
|
||||
// note these ordinals are into the data array, not the table output
|
||||
document.getElementById('thClient').addEventListener('click', function () {
|
||||
setSortColumn(this.id, 0); // hostname
|
||||
});
|
||||
document.getElementById('thDownload').addEventListener('click', function () {
|
||||
setSortColumn(this.id, 3); // dl speed
|
||||
});
|
||||
document.getElementById('thUpload').addEventListener('click', function () {
|
||||
setSortColumn(this.id, 4); // ul speed
|
||||
});
|
||||
document.getElementById('thTotalDown').addEventListener('click', function () {
|
||||
setSortColumn(this.id, 5); // total down
|
||||
});
|
||||
document.getElementById('thTotalUp').addEventListener('click', function () {
|
||||
setSortColumn(this.id, 6); // total up
|
||||
});
|
||||
document.getElementById('thTotal').addEventListener('click', function () {
|
||||
setSortColumn(this.id, 7); // total
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches and handles the updated `values` from the BE
|
||||
* @param once If set to true, it re-schedules itself for execution based on selected interval
|
||||
*/
|
||||
function receiveData(once) {
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = function () {
|
||||
// noinspection EqualityComparisonWithCoercionJS
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
var re = /(var values = new Array[^;]*;)/,
|
||||
match = ajax.responseText.match(re);
|
||||
if (!match) {
|
||||
handleError();
|
||||
} else {
|
||||
// evaluate values
|
||||
eval(match[1]);
|
||||
//noinspection JSUnresolvedVariable
|
||||
var v = values;
|
||||
if (!v) {
|
||||
handleError();
|
||||
} else {
|
||||
handleValues(v);
|
||||
// set old values
|
||||
oldValues = v;
|
||||
// set old date
|
||||
oldDate = new Date();
|
||||
document.getElementById('updated').innerHTML = '数据更新时间 ' + dateToString(oldDate);
|
||||
}
|
||||
}
|
||||
var int = wrt.interval;
|
||||
if (!once && int > 0) reschedule(int);
|
||||
}
|
||||
};
|
||||
ajax.open('GET', basePath + '/usage_data', true);
|
||||
ajax.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers DOM event listeners for user interaction
|
||||
*/
|
||||
function addEventListeners() {
|
||||
document.getElementById('intervalSelect').addEventListener('change', function () {
|
||||
var int = wrt.interval = this.value;
|
||||
if (int > 0) {
|
||||
// it is not scheduled, schedule it
|
||||
if (!wrt.isScheduled) {
|
||||
reschedule(int);
|
||||
}
|
||||
} else {
|
||||
// stop the scheduling
|
||||
stopSchedule();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('resetDatabase').addEventListener('click', function () {
|
||||
if (confirm('本操作将删除并重置数据库文件,是否继续?')) {
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = function () {
|
||||
// noinspection EqualityComparisonWithCoercionJS
|
||||
if (this.readyState == 4 && this.status == 204) {
|
||||
location.reload();
|
||||
}
|
||||
};
|
||||
ajax.open('GET', basePath + '/usage_reset', true);
|
||||
ajax.send();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('perHostTotals').addEventListener('change', function () {
|
||||
wrt.perHostTotals = !wrt.perHostTotals;
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------
|
||||
// AUTO-UPDATE
|
||||
//----------------------
|
||||
|
||||
/**
|
||||
* Stop auto-update schedule
|
||||
*/
|
||||
function stopSchedule() {
|
||||
window.clearTimeout(wrt.scheduleTimeout);
|
||||
window.clearTimeout(wrt.updateTimeout);
|
||||
setUpdateMessage('');
|
||||
wrt.isScheduled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start auto-update schedule
|
||||
* @param seconds
|
||||
*/
|
||||
function reschedule(seconds) {
|
||||
wrt.isScheduled = true;
|
||||
seconds = seconds || 60;
|
||||
updateSeconds(seconds);
|
||||
wrt.scheduleTimeout = window.setTimeout(receiveData, seconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the `#updating` element
|
||||
* @param msg
|
||||
*/
|
||||
function setUpdateMessage(msg) {
|
||||
document.getElementById('updating').innerHTML = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the 'Updating in X seconds' message
|
||||
* @param start
|
||||
*/
|
||||
function updateSeconds(start) {
|
||||
setUpdateMessage('下次将于 <b>' + start + '</b> 秒后更新。');
|
||||
if (start > 0) {
|
||||
wrt.updateTimeout = window.setTimeout(function () {
|
||||
updateSeconds(start - 1);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------
|
||||
// END AUTO-UPDATE
|
||||
//----------------------
|
||||
|
||||
/**
|
||||
* Check for dependency, and if all is well, run callback
|
||||
* @param cb Callback function
|
||||
*/
|
||||
function checkForDependency(cb) {
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.onreadystatechange = function () {
|
||||
// noinspection EqualityComparisonWithCoercionJS
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
// noinspection EqualityComparisonWithCoercionJS
|
||||
if (ajax.responseText == "1") {
|
||||
cb();
|
||||
} else {
|
||||
alert("wrtbwmon 未安装!");
|
||||
}
|
||||
}
|
||||
};
|
||||
ajax.open('GET', basePath + '/check_dependency', true);
|
||||
ajax.send();
|
||||
}
|
||||
|
||||
checkForDependency(function () {
|
||||
// register events
|
||||
addEventListeners();
|
||||
// Main entry point
|
||||
receiveData();
|
||||
});
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
module("luci.controller.wrtbwmon", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "status", "usage"}, alias("admin", "status", "usage", "details"), _("Usage"), 60)
|
||||
entry({"admin", "status", "usage", "details"}, template("wrtbwmon"), _("Details"), 10).leaf=true
|
||||
entry({"admin", "status", "usage", "config"}, cbi("wrtbwmon/config"), _("Configuration"), 20).leaf=true
|
||||
entry({"admin", "status", "usage", "custom"}, form("wrtbwmon/custom"), _("User file"), 30).leaf=true
|
||||
entry({"admin", "status", "usage", "check_dependency"}, call("check_dependency")).dependent=true
|
||||
entry({"admin", "status", "usage", "usage_data"}, call("usage_data")).dependent=true
|
||||
entry({"admin", "status", "usage", "usage_reset"}, call("usage_reset")).dependent=true
|
||||
end
|
||||
|
||||
function usage_database_path()
|
||||
local cursor = luci.model.uci.cursor()
|
||||
if cursor:get("wrtbwmon", "general", "persist") == "1" then
|
||||
return "/etc/config/usage.db"
|
||||
else
|
||||
return "/tmp/usage.db"
|
||||
end
|
||||
end
|
||||
|
||||
function check_dependency()
|
||||
local ret = "0"
|
||||
local status, ipkg = pcall(require, "luci.model.ipkg")
|
||||
if not status or ipkg.installed('wrtbwmon') then
|
||||
ret = "1"
|
||||
end
|
||||
luci.http.prepare_content("text/plain")
|
||||
luci.http.write(ret)
|
||||
end
|
||||
|
||||
function usage_data()
|
||||
local db = usage_database_path()
|
||||
local publish_cmd = "wrtbwmon publish " .. db .. " /tmp/usage.htm /etc/wrtbwmon.user"
|
||||
local cmd = "wrtbwmon update " .. db .. " && " .. publish_cmd .. " && cat /tmp/usage.htm"
|
||||
luci.http.prepare_content("text/html")
|
||||
luci.http.write(luci.sys.exec(cmd))
|
||||
end
|
||||
|
||||
function usage_reset()
|
||||
local db = usage_database_path()
|
||||
local ret = luci.sys.call("wrtbwmon update " .. db .. " && rm " .. db)
|
||||
luci.http.status(204)
|
||||
end
|
@ -1,18 +0,0 @@
|
||||
local m = Map("wrtbwmon", translate("Details"))
|
||||
|
||||
local s = m:section(NamedSection, "general", "wrtbwmon", translate("General settings"))
|
||||
|
||||
local o = s:option(Flag, "persist", translate("Persist database"),
|
||||
translate("Check this to persist the database file"))
|
||||
o.rmempty = false
|
||||
|
||||
function o.write(self, section, value)
|
||||
if value == '1' then
|
||||
luci.sys.call("mv /tmp/usage.db /etc/config/usage.db")
|
||||
elseif value == '0' then
|
||||
luci.sys.call("mv /etc/config/usage.db /tmp/usage.db")
|
||||
end
|
||||
return Flag.write(self, section ,value)
|
||||
end
|
||||
|
||||
return m
|
@ -1,23 +0,0 @@
|
||||
local USER_FILE_PATH = "/etc/config/wrtbwmon.user"
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
local f = SimpleForm("wrtbwmon",
|
||||
translate("Usage - Custom User File"),
|
||||
translate("This file is used to match users with MAC addresses and it must have the following format: 00:aa:bb:cc:ee:ff,username"))
|
||||
|
||||
local o = f:field(Value, "_custom")
|
||||
|
||||
o.template = "cbi/tvalue"
|
||||
o.rows = 20
|
||||
|
||||
function o.cfgvalue(self, section)
|
||||
return fs.readfile(USER_FILE_PATH)
|
||||
end
|
||||
|
||||
function o.write(self, section, value)
|
||||
value = value:gsub("\r\n?", "\n")
|
||||
fs.writefile(USER_FILE_PATH, value)
|
||||
end
|
||||
|
||||
return f
|
@ -1,63 +0,0 @@
|
||||
<%+header%>
|
||||
<h2><%=translate("Usage")%></h2>
|
||||
<p style="position:relative;">
|
||||
<button id="resetDatabase" class="cbi-button" style="position:absolute;right:0;bottom:0;"><%=translate("Reset Database")%></button>
|
||||
</p>
|
||||
<p>
|
||||
<small><span id="updated"></span> <span id="updating"></span></small>
|
||||
<span style="float:right;text-align:right;margin-top:10px;">
|
||||
<label>
|
||||
<small><%=translate("Auto Refresh Interval")%></small>
|
||||
<select id="intervalSelect" style="font-size:11px;">
|
||||
<option value="-1"><%=translate("Disabled")%></option>
|
||||
<option value="1">1 <%=translate("Second")%></option>
|
||||
<option value="2">2 <%=translate("Seconds")%></option>
|
||||
<option value="3">3 <%=translate("Seconds")%></option>
|
||||
<option value="4">4 <%=translate("Seconds")%></option>
|
||||
<option value="5" selected="selected">5 <%=translate("Seconds")%></option>
|
||||
<option value="10">10 <%=translate("Seconds")%></option>
|
||||
<option value="20">20 <%=translate("Seconds")%></option>
|
||||
<option value="30">30 <%=translate("Seconds")%></option>
|
||||
<option value="40">40 <%=translate("Seconds")%></option>
|
||||
<option value="50">50 <%=translate("Seconds")%></option>
|
||||
<option value="60">60 <%=translate("Seconds")%></option>
|
||||
<option value="120">2 <%=translate("Minutes")%></option>
|
||||
<option value="180">3 <%=translate("Minutes")%></option>
|
||||
<option value="240">4 <%=translate("Minutes")%></option>
|
||||
<option value="360">5 <%=translate("Minutes")%></option>
|
||||
</select>
|
||||
</label>
|
||||
<br/>
|
||||
<label>
|
||||
<small><%=translate("Per-host Totals")%></small>
|
||||
<input id="perHostTotals" type="checkbox" style="vertical-align:middle;"/>
|
||||
</label>
|
||||
<!--label>
|
||||
<small>仅显示同名主机聚合数据</small>
|
||||
<input id="showPerHostTotalsOnly" type="checkbox" style="vertical-align:middle;"/>
|
||||
</label-->
|
||||
</span>
|
||||
</p>
|
||||
<style>
|
||||
fieldset.cbi-section {
|
||||
margin-top: 80px;
|
||||
}
|
||||
table.table {
|
||||
font-family: apple color emoji,segoe ui emoji,noto color emoji,android emoji,emojisymbols,emojione mozilla,twemoji mozilla,segoe ui symbol;
|
||||
}
|
||||
table.table tr.tr {
|
||||
transition: all .3s;
|
||||
}
|
||||
table.table tr.tr:hover {
|
||||
background: rgba(0,0,0,0.05);
|
||||
}
|
||||
</style>
|
||||
|
||||
<fieldset class="cbi-section">
|
||||
<table class="table">
|
||||
<tbody id="tableBody"><tr><td><%=translate("Loading...")%></td></tr></tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<!--suppress HtmlUnknownTarget -->
|
||||
<script src="/luci-static/wrtbwmon.js"></script>
|
||||
<%+footer%>
|
@ -1,56 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Usage"
|
||||
msgstr "流量统计"
|
||||
|
||||
msgid "Details"
|
||||
msgstr "详细信息"
|
||||
|
||||
msgid "Configuration"
|
||||
msgstr "配置"
|
||||
|
||||
msgid "User file"
|
||||
msgstr "自定义"
|
||||
|
||||
msgid "Usage - Configuration"
|
||||
msgstr "详细设置"
|
||||
|
||||
msgid "General settings"
|
||||
msgstr "通用设置"
|
||||
|
||||
msgid "Persist database"
|
||||
msgstr "写入数据库到硬盘"
|
||||
|
||||
msgid "Check this to persist the database file"
|
||||
msgstr "把统计数据写入 /etc/config 中避免重启或者升级后丢失"
|
||||
|
||||
msgid "Usage - Custom User File"
|
||||
msgstr "本配置可根据 MAC 地址自定义主机备注名"
|
||||
|
||||
msgid "This file is used to match users with MAC addresses and it must have the following format: 00:aa:bb:cc:ee:ff,username"
|
||||
msgstr "每一行格式必须按照此格式配置: 00:aa:bb:cc:ee:ff,username"
|
||||
|
||||
msgid "Reset Database"
|
||||
msgstr "重置数据库"
|
||||
|
||||
msgid "Auto Refresh Interval"
|
||||
msgstr "自动刷新间隔"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "禁用"
|
||||
|
||||
msgid "Second"
|
||||
msgstr "秒"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "秒"
|
||||
|
||||
msgid "Minutes"
|
||||
msgstr "分钟"
|
||||
|
||||
msgid "Per-host Totals"
|
||||
msgstr "将同名主机合并"
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr "加载中..."
|
@ -1,4 +0,0 @@
|
||||
|
||||
config wrtbwmon 'general'
|
||||
option persist '0'
|
||||
|
@ -1,22 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
#
|
||||
# start/stop wrtbwmon bandwidth monitor
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: wrtbwmon
|
||||
# Required-Start: $network $local_fs $remote_fs
|
||||
# Required-Stop: $local_fs $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: iptables-based bandwidth monitor
|
||||
### END INIT INFO
|
||||
|
||||
START=91
|
||||
|
||||
start(){
|
||||
/usr/sbin/wrtbwmon setup /tmp/usage.db
|
||||
}
|
||||
|
||||
stop(){
|
||||
/usr/sbin/wrtbwmon remove
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete firewall.wrtbwmon
|
||||
set firewall.wrtbwmon=include
|
||||
set firewall.wrtbwmon.type=script
|
||||
set firewall.wrtbwmon.path='/etc/wrtbwmon.include'
|
||||
set firewall.wrtbwmon.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
/etc/init.d/wrtbwmon enable
|
||||
/etc/init.d/wrtbwmon start
|
||||
exit 0
|
@ -1 +0,0 @@
|
||||
/etc/init.d/wrtbwmon restart >/dev/null 2>&1
|
@ -1,157 +0,0 @@
|
||||
#!/usr/bin/awk
|
||||
|
||||
function inInterfaces(host){
|
||||
return(interfaces ~ "(^| )"host"($| )")
|
||||
}
|
||||
|
||||
function newRule(arp_ip,
|
||||
ipt_cmd){
|
||||
# checking for existing rules shouldn't be necessary if newRule is
|
||||
# always called after db is read, arp table is read, and existing
|
||||
# iptables rules are read.
|
||||
ipt_cmd="iptables -t mangle -j RETURN -s " arp_ip
|
||||
system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD")
|
||||
ipt_cmd="iptables -t mangle -j RETURN -d " arp_ip
|
||||
system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD")
|
||||
}
|
||||
|
||||
function total(i){
|
||||
return(bw[i "/in"] + bw[i "/out"])
|
||||
}
|
||||
|
||||
function date( cmd, d){
|
||||
cmd="date +%d-%m-%Y_%H:%M:%S"
|
||||
cmd | getline d
|
||||
close(cmd)
|
||||
#!@todo could start a process with "while true; do date ...; done"
|
||||
return(d)
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
od=""
|
||||
fid=1
|
||||
debug=0
|
||||
rrd=0
|
||||
}
|
||||
|
||||
/^#/ { # get DB filename
|
||||
FS=","
|
||||
dbFile=FILENAME
|
||||
next
|
||||
}
|
||||
|
||||
# data from database; first file
|
||||
FNR==NR { #!@todo this doesn't help if the DB file is empty.
|
||||
if($2 == "NA")
|
||||
#!@todo could get interface IP here
|
||||
n=$1
|
||||
else
|
||||
n=$2
|
||||
|
||||
hosts[n] = "" # add this host/interface to hosts
|
||||
mac[n] = $1
|
||||
ip[n] = $2
|
||||
inter[n] = $3
|
||||
bw[n "/in"] = $4
|
||||
bw[n "/out"] = $5
|
||||
firstDate[n] = $7
|
||||
lastDate[n] = $8
|
||||
next
|
||||
}
|
||||
|
||||
# not triggered on the first file
|
||||
FNR==1 {
|
||||
FS=" "
|
||||
fid++ #!@todo use fid for all files; may be problematic for empty files
|
||||
next
|
||||
}
|
||||
|
||||
# arp: ip hw flags hw_addr mask device
|
||||
fid==2 {
|
||||
#!@todo regex match IPs and MACs for sanity
|
||||
arp_ip = $1
|
||||
arp_flags = $3
|
||||
arp_mac = $4
|
||||
arp_dev = $6
|
||||
if(arp_flags != "0x0" && !(arp_ip in ip)){
|
||||
if(debug)
|
||||
print "new host:", arp_ip, arp_flags > "/dev/stderr"
|
||||
hosts[arp_ip] = ""
|
||||
mac[arp_ip] = arp_mac
|
||||
ip[arp_ip] = arp_ip
|
||||
inter[arp_ip] = arp_dev
|
||||
bw[arp_ip "/in"] = bw[arp_ip "/out"] = 0
|
||||
firstDate[arp_ip] = lastDate[arp_ip] = date()
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
#!@todo could use mangle chain totals or tailing "unnact" rules to
|
||||
# account for data for new hosts from their first presence on the
|
||||
# network to rule creation. The "unnact" rules would have to be
|
||||
# maintained at the end of the list, and new rules would be inserted
|
||||
# at the top.
|
||||
|
||||
# skip line
|
||||
# read the chain name and deal with the data accordingly
|
||||
fid==3 && $1 == "Chain"{
|
||||
rrd=$2 ~ /RRDIPT_.*/
|
||||
next
|
||||
}
|
||||
|
||||
fid==3 && rrd && (NF < 9 || $1=="pkts"){ next }
|
||||
|
||||
fid==3 && rrd { # iptables input
|
||||
if($6 != "*"){
|
||||
m=$6
|
||||
n=m "/out"
|
||||
} else if($7 != "*"){
|
||||
m=$7
|
||||
n=m "/in"
|
||||
} else if($8 != "0.0.0.0/0"){
|
||||
m=$8
|
||||
n=m "/out"
|
||||
} else { # $9 != "0.0.0.0/0"
|
||||
m=$9
|
||||
n=m "/in"
|
||||
}
|
||||
|
||||
# remove host from array; any hosts left in array at END get new
|
||||
# iptables rules
|
||||
|
||||
#!@todo this deletes a host if any rule exists; if only one
|
||||
# directional rule is removed, this will not remedy the situation
|
||||
delete hosts[m]
|
||||
|
||||
if($2 > 0){ # counted some bytes
|
||||
if(mode == "diff" || mode == "noUpdate")
|
||||
print n, $2
|
||||
if(mode!="noUpdate"){
|
||||
if(inInterfaces(m)){ # if label is an interface
|
||||
if(!(m in mac)){ # if label was not in db (also not in
|
||||
# arp table, but interfaces won't be
|
||||
# there anyway)
|
||||
firstDate[m] = date()
|
||||
mac[m] = inter[m] = m
|
||||
ip[m] = "NA"
|
||||
bw[m "/in"]=bw[m "/out"]= 0
|
||||
}
|
||||
}
|
||||
bw[n]+=$2
|
||||
lastDate[m] = date()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
if(mode=="noUpdate") exit
|
||||
close(dbFile)
|
||||
system("rm -f " dbFile)
|
||||
print "#mac,ip,iface,in,out,total,first_date,last_date" > dbFile
|
||||
OFS=","
|
||||
for(i in mac)
|
||||
print mac[i], ip[i], inter[i], bw[i "/in"], bw[i "/out"], total(i), firstDate[i], lastDate[i] > dbFile
|
||||
close(dbFile)
|
||||
# for hosts without rules
|
||||
for(host in hosts) if(!inInterfaces(host)) newRule(host)
|
||||
}
|
@ -1,301 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# wrtbwmon: traffic logging tool for routers
|
||||
#
|
||||
# Peter Bailey (peter.eldridge.bailey+wrtbwmon AT gmail.com)
|
||||
#
|
||||
# Based on work by:
|
||||
# Emmanuel Brucy (e.brucy AT qut.edu.au)
|
||||
# Fredrik Erlandsson (erlis AT linux.nu)
|
||||
# twist - http://wiki.openwrt.org/RrdTrafficWatch
|
||||
|
||||
trap "rm -f /tmp/*_$$.tmp; kill $$" INT
|
||||
binDir=/usr/sbin
|
||||
dataDir=/usr/share/wrtbwmon
|
||||
lockDir=/tmp/wrtbwmon.lock
|
||||
pidFile=$lockDir/pid
|
||||
networkFuncs=/lib/functions/network.sh
|
||||
uci=`which uci 2>/dev/null`
|
||||
nslookup=`which nslookup 2>/dev/null`
|
||||
nvram=`which nvram 2>/dev/null`
|
||||
|
||||
chains='INPUT OUTPUT FORWARD'
|
||||
DEBUG=
|
||||
interfaces='eth0 tun0' # in addition to detected WAN
|
||||
DB=$2
|
||||
mode=
|
||||
|
||||
# DNS server for reverse lookups provided in "DNS".
|
||||
# don't perform reverse DNS lookups by default
|
||||
DO_RDNS=${DNS-}
|
||||
|
||||
header="#mac,ip,iface,in,out,total,first_date,last_date"
|
||||
|
||||
createDbIfMissing()
|
||||
{
|
||||
[ ! -f "$DB" ] && echo $header > "$DB"
|
||||
}
|
||||
|
||||
checkDbArg()
|
||||
{
|
||||
[ -z "$DB" ] && echo "ERROR: Missing argument 2 (database file)" && exit 1
|
||||
}
|
||||
|
||||
checkDB()
|
||||
{
|
||||
[ ! -f "$DB" ] && echo "ERROR: $DB does not exist" && exit 1
|
||||
[ ! -w "$DB" ] && echo "ERROR: $DB is not writable" && exit 1
|
||||
}
|
||||
|
||||
checkWAN()
|
||||
{
|
||||
[ -z "$wan" ] && echo "Warning: failed to detect WAN interface."
|
||||
}
|
||||
|
||||
lookup()
|
||||
{
|
||||
MAC=$1
|
||||
IP=$2
|
||||
userDB=$3
|
||||
for USERSFILE in $userDB /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do
|
||||
[ -e "$USERSFILE" ] || continue
|
||||
case $USERSFILE in
|
||||
/tmp/dhcp.leases )
|
||||
USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ')
|
||||
;;
|
||||
/etc/hosts )
|
||||
USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ')
|
||||
;;
|
||||
* )
|
||||
USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,)
|
||||
;;
|
||||
esac
|
||||
[ "$USER" = "*" ] && USER=
|
||||
[ -n "$USER" ] && break
|
||||
done
|
||||
if [ -n "$DO_RDNS" -a -z "$USER" -a "$IP" != "NA" -a -n "$nslookup" ]; then
|
||||
USER=`$nslookup $IP $DNS | awk '!/server can/{if($4){print $4; exit}}' | sed -re 's/[.]$//'`
|
||||
fi
|
||||
[ -z "$USER" ] && USER=${MAC}
|
||||
echo $USER
|
||||
}
|
||||
|
||||
detectIF()
|
||||
{
|
||||
if [ -f "$networkFuncs" ]; then
|
||||
IF=`. $networkFuncs; network_get_device netdev $1; echo $netdev`
|
||||
[ -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
|
||||
if [ -n "$uci" -a -x "$uci" ]; then
|
||||
IF=`$uci get network.${1}.ifname 2>/dev/null`
|
||||
[ $? -eq 0 -a -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
|
||||
if [ -n "$nvram" -a -x "$nvram" ]; then
|
||||
IF=`$nvram get ${1}_ifname 2>/dev/null`
|
||||
[ $? -eq 0 -a -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
}
|
||||
|
||||
detectLAN()
|
||||
{
|
||||
[ -e /sys/class/net/br-lan ] && echo br-lan && return
|
||||
lan=$(detectIF lan)
|
||||
[ -n "$lan" ] && echo $lan && return
|
||||
}
|
||||
|
||||
detectWAN()
|
||||
{
|
||||
[ -n "$WAN_IF" ] && echo $WAN_IF && return
|
||||
wan=$(detectIF wan)
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/')
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
[ -f "$networkFuncs" ] && wan=$(. $networkFuncs; network_find_wan wan; echo $wan)
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
}
|
||||
|
||||
lock()
|
||||
{
|
||||
attempts=0
|
||||
while [ $attempts -lt 10 ]; do
|
||||
mkdir $lockDir 2>/dev/null && break
|
||||
attempts=$((attempts+1))
|
||||
pid=`cat $pidFile 2>/dev/null`
|
||||
if [ -n "$pid" ]; then
|
||||
if [ -d "/proc/$pid" ]; then
|
||||
[ -n "$DEBUG" ] && echo "WARNING: Lockfile detected but process $(cat $pidFile) does not exist !"
|
||||
rm -rf $lockDir
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
mkdir $lockDir 2>/dev/null
|
||||
echo $$ > $pidFile
|
||||
[ -n "$DEBUG" ] && echo $$ "got lock after $attempts attempts"
|
||||
trap '' INT
|
||||
}
|
||||
|
||||
unlock()
|
||||
{
|
||||
rm -rf $lockDir
|
||||
[ -n "$DEBUG" ] && echo $$ "released lock"
|
||||
trap "rm -f /tmp/*_$$.tmp; kill $$" INT
|
||||
}
|
||||
|
||||
# chain
|
||||
newChain()
|
||||
{
|
||||
chain=$1
|
||||
# Create the RRDIPT_$chain chain (it doesn't matter if it already exists).
|
||||
iptables -t mangle -N RRDIPT_$chain 2> /dev/null
|
||||
|
||||
# Add the RRDIPT_$chain CHAIN to the $chain chain if not present
|
||||
iptables -t mangle -C $chain -j RRDIPT_$chain 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
[ -n "$DEBUG" ] && echo "DEBUG: iptables chain misplaced, recreating it..."
|
||||
iptables -t mangle -I $chain -j RRDIPT_$chain
|
||||
fi
|
||||
}
|
||||
|
||||
# chain tun
|
||||
newRuleIF()
|
||||
{
|
||||
chain=$1
|
||||
IF=$2
|
||||
|
||||
#!@todo test
|
||||
if [ "$chain" = "OUTPUT" ]; then
|
||||
cmd="iptables -t mangle -o $IF -j RETURN"
|
||||
eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain"
|
||||
elif [ "$chain" = "INPUT" ]; then
|
||||
cmd="iptables -t mangle -i $IF -j RETURN"
|
||||
eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain"
|
||||
fi
|
||||
}
|
||||
|
||||
update()
|
||||
{
|
||||
#!@todo could let readDB.awk handle this; that would place header
|
||||
#!info in fewer places
|
||||
createDbIfMissing
|
||||
|
||||
checkDB
|
||||
checkWAN
|
||||
|
||||
> /tmp/iptables_$$.tmp
|
||||
lock
|
||||
# only zero our own chains
|
||||
for chain in $chains; do
|
||||
iptables -nvxL RRDIPT_$chain -t mangle -Z >> /tmp/iptables_$$.tmp
|
||||
done
|
||||
# the iptables and readDB commands have to be separate. Otherwise,
|
||||
# they will fight over iptables locks
|
||||
awk -v mode="$mode" -v interfaces=\""$interfaces"\" -f $binDir/readDB.awk \
|
||||
$DB \
|
||||
/proc/net/arp \
|
||||
/tmp/iptables_$$.tmp
|
||||
unlock
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
case $1 in
|
||||
"dump" )
|
||||
checkDbArg
|
||||
lock
|
||||
tr ',' '\t' < "$DB"
|
||||
unlock
|
||||
;;
|
||||
|
||||
"update" )
|
||||
checkDbArg
|
||||
wan=$(detectWAN)
|
||||
interfaces="$interfaces $wan"
|
||||
update
|
||||
rm -f /tmp/*_$$.tmp
|
||||
exit
|
||||
;;
|
||||
|
||||
"publish" )
|
||||
checkDbArg
|
||||
[ -z "$3" ] && echo "ERROR: Missing argument 3 (output html file)" && exit 1
|
||||
|
||||
# sort DB
|
||||
lock
|
||||
|
||||
# busybox sort truncates numbers to 32 bits
|
||||
grep -v '^#' $DB | awk -F, '{OFS=","; a=sprintf("%f",$4/1e6); $4=""; print a,$0}' | tr -s ',' | sort -rn | awk -F, '{OFS=",";$1=sprintf("%f",$1*1e6);print}' > /tmp/sorted_$$.tmp
|
||||
|
||||
# create HTML page
|
||||
rm -f $3.tmp
|
||||
cp $dataDir/usage.htm1 $3.tmp
|
||||
|
||||
#!@todo fix publishing
|
||||
while IFS=, read PEAKUSAGE_IN MAC IP IFACE PEAKUSAGE_OUT TOTAL FIRSTSEEN LASTSEEN
|
||||
do
|
||||
echo "
|
||||
new Array(\"$(lookup $MAC $IP $4)\",\"$MAC\",\"$IP\",
|
||||
$PEAKUSAGE_IN,$PEAKUSAGE_OUT,$TOTAL,\"$FIRSTSEEN\",\"$LASTSEEN\")," >> $3.tmp
|
||||
done < /tmp/sorted_$$.tmp
|
||||
echo "0);" >> $3.tmp
|
||||
|
||||
sed "s/(date)/`date`/" < $dataDir/usage.htm2 >> $3.tmp
|
||||
mv $3.tmp $3
|
||||
|
||||
unlock
|
||||
|
||||
#Free some memory
|
||||
rm -f /tmp/*_$$.tmp
|
||||
;;
|
||||
|
||||
"setup" )
|
||||
checkDbArg
|
||||
[ -w "$DB" ] && echo "Warning: using existing $DB"
|
||||
createDbIfMissing
|
||||
|
||||
for chain in $chains; do
|
||||
newChain $chain
|
||||
done
|
||||
|
||||
#lan=$(detectLAN)
|
||||
wan=$(detectWAN)
|
||||
checkWAN
|
||||
interfaces="$interfaces $wan"
|
||||
|
||||
# track local data
|
||||
for chain in INPUT OUTPUT; do
|
||||
for interface in $interfaces; do
|
||||
[ -n "$interface" ] && [ -e "/sys/class/net/$interface" ] && newRuleIF $chain $interface
|
||||
done
|
||||
done
|
||||
|
||||
# this will add rules for hosts in arp table
|
||||
update
|
||||
|
||||
rm -f /tmp/*_$$.tmp
|
||||
;;
|
||||
|
||||
"remove" )
|
||||
iptables-save | grep -v RRDIPT | iptables-restore
|
||||
rm -rf "$lockDir"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo \
|
||||
"Usage: $0 {setup|update|publish|remove} [options...]
|
||||
Options:
|
||||
$0 setup database_file
|
||||
$0 update database_file
|
||||
$0 publish database_file path_of_html_report [user_file]
|
||||
Examples:
|
||||
$0 setup /tmp/usage.db
|
||||
$0 update /tmp/usage.db
|
||||
$0 publish /tmp/usage.db /www/user/usage.htm /jffs/users.txt
|
||||
$0 remove
|
||||
Note: [user_file] is an optional file to match users with MAC addresses.
|
||||
Its format is \"00:MA:CA:DD:RE:SS,username\", with one entry per line."
|
||||
;;
|
||||
esac
|
@ -1,23 +0,0 @@
|
||||
<html><head><title>Traffic</title>
|
||||
<script type="text/javascript">
|
||||
function getSize(size) {
|
||||
var prefix=new Array("","k","M","G","T","P","E","Z"); var base=1000;
|
||||
var pos=0;
|
||||
while (size>base) {
|
||||
size/=base; pos++;
|
||||
}
|
||||
if (pos > 2) precision=1000; else precision = 1;
|
||||
return (Math.round(size*precision)/precision)+' '+prefix[pos];}
|
||||
</script></head>
|
||||
<body><h1>Total Usage:</h1>
|
||||
<table border="1">
|
||||
<tr bgcolor=silver>
|
||||
<th>User</th>
|
||||
<th>Download</th>
|
||||
<th>Upload</th>
|
||||
<th>Total</th>
|
||||
<th>First seen</th>
|
||||
<th>Last seen</th>
|
||||
</tr>
|
||||
<script type="text/javascript">
|
||||
var values = new Array(
|
@ -1,14 +0,0 @@
|
||||
var totalIn = 0;
|
||||
var totalOut = 0;
|
||||
for (i=0; i < values.length-1; i++) {
|
||||
totalIn += values[i][3];
|
||||
totalOut += values[i][4];
|
||||
document.write("<tr><td><div title=\"" + values[i][1] + " (" + values[i][2] + ")" + "\">" + values[i][0] + "</div></td>");
|
||||
for (j=3; j < 6; j++)
|
||||
document.write("<td>" + getSize(values[i][j]) + "</td>");
|
||||
document.write("<td>" + values[i][6] + "</td><td>" + values[i][7] + "</td></tr>");
|
||||
}
|
||||
document.write("<tr><td>TOTAL</td><td>" + getSize(totalIn) + "</td><td>" + getSize(totalOut) + "</td><td>" + getSize(totalIn + totalOut) + "</td><td></td><td></td></tr>");
|
||||
</script></table>
|
||||
<br /><small>This page was generated on (date)</small>
|
||||
</body></html>
|
@ -1,15 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 OpenWrt.org
|
||||
# 流量统计
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=wrtbwmon
|
||||
PKG_VERSION:=v0.3
|
||||
PKG_RELEASE:=1
|
||||
LUCI_TITLE:=Wrtbwmon
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
@ -1,22 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
#
|
||||
# start/stop wrtbwmon bandwidth monitor
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: wrtbwmon
|
||||
# Required-Start: $network $local_fs $remote_fs
|
||||
# Required-Stop: $local_fs $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: iptables-based bandwidth monitor
|
||||
### END INIT INFO
|
||||
|
||||
START=91
|
||||
|
||||
start(){
|
||||
/usr/sbin/wrtbwmon setup /tmp/usage.db
|
||||
}
|
||||
|
||||
stop(){
|
||||
/usr/sbin/wrtbwmon remove
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
#!/usr/bin/awk
|
||||
|
||||
function inInterfaces(host){
|
||||
return(interfaces ~ "(^| )"host"($| )")
|
||||
}
|
||||
|
||||
function newRule(arp_ip,
|
||||
ipt_cmd){
|
||||
# checking for existing rules shouldn't be necessary if newRule is
|
||||
# always called after db is read, arp table is read, and existing
|
||||
# iptables rules are read.
|
||||
ipt_cmd="iptables -t mangle -j RETURN -s " arp_ip
|
||||
system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD")
|
||||
ipt_cmd="iptables -t mangle -j RETURN -d " arp_ip
|
||||
system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD")
|
||||
}
|
||||
|
||||
function total(i){
|
||||
return(bw[i "/in"] + bw[i "/out"])
|
||||
}
|
||||
|
||||
function date( cmd, d){
|
||||
cmd="date +%d-%m-%Y_%H:%M:%S"
|
||||
cmd | getline d
|
||||
close(cmd)
|
||||
#!@todo could start a process with "while true; do date ...; done"
|
||||
return(d)
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
od=""
|
||||
fid=1
|
||||
debug=0
|
||||
rrd=0
|
||||
}
|
||||
|
||||
/^#/ { # get DB filename
|
||||
FS=","
|
||||
dbFile=FILENAME
|
||||
next
|
||||
}
|
||||
|
||||
# data from database; first file
|
||||
FNR==NR { #!@todo this doesn't help if the DB file is empty.
|
||||
if($2 == "NA")
|
||||
#!@todo could get interface IP here
|
||||
n=$1
|
||||
else
|
||||
n=$2
|
||||
|
||||
hosts[n] = "" # add this host/interface to hosts
|
||||
mac[n] = $1
|
||||
ip[n] = $2
|
||||
inter[n] = $3
|
||||
bw[n "/in"] = $4
|
||||
bw[n "/out"] = $5
|
||||
firstDate[n] = $7
|
||||
lastDate[n] = $8
|
||||
next
|
||||
}
|
||||
|
||||
# not triggered on the first file
|
||||
FNR==1 {
|
||||
FS=" "
|
||||
fid++ #!@todo use fid for all files; may be problematic for empty files
|
||||
next
|
||||
}
|
||||
|
||||
# arp: ip hw flags hw_addr mask device
|
||||
fid==2 {
|
||||
#!@todo regex match IPs and MACs for sanity
|
||||
arp_ip = $1
|
||||
arp_flags = $3
|
||||
arp_mac = $4
|
||||
arp_dev = $6
|
||||
if(arp_flags != "0x0" && !(arp_ip in ip)){
|
||||
if(debug)
|
||||
print "new host:", arp_ip, arp_flags > "/dev/stderr"
|
||||
hosts[arp_ip] = ""
|
||||
mac[arp_ip] = arp_mac
|
||||
ip[arp_ip] = arp_ip
|
||||
inter[arp_ip] = arp_dev
|
||||
bw[arp_ip "/in"] = bw[arp_ip "/out"] = 0
|
||||
firstDate[arp_ip] = lastDate[arp_ip] = date()
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
#!@todo could use mangle chain totals or tailing "unnact" rules to
|
||||
# account for data for new hosts from their first presence on the
|
||||
# network to rule creation. The "unnact" rules would have to be
|
||||
# maintained at the end of the list, and new rules would be inserted
|
||||
# at the top.
|
||||
|
||||
# skip line
|
||||
# read the chain name and deal with the data accordingly
|
||||
fid==3 && $1 == "Chain"{
|
||||
rrd=$2 ~ /RRDIPT_.*/
|
||||
next
|
||||
}
|
||||
|
||||
fid==3 && rrd && (NF < 9 || $1=="pkts"){ next }
|
||||
|
||||
fid==3 && rrd { # iptables input
|
||||
if($6 != "*"){
|
||||
m=$6
|
||||
n=m "/out"
|
||||
} else if($7 != "*"){
|
||||
m=$7
|
||||
n=m "/in"
|
||||
} else if($8 != "0.0.0.0/0"){
|
||||
m=$8
|
||||
n=m "/out"
|
||||
} else { # $9 != "0.0.0.0/0"
|
||||
m=$9
|
||||
n=m "/in"
|
||||
}
|
||||
|
||||
# remove host from array; any hosts left in array at END get new
|
||||
# iptables rules
|
||||
|
||||
#!@todo this deletes a host if any rule exists; if only one
|
||||
# directional rule is removed, this will not remedy the situation
|
||||
delete hosts[m]
|
||||
|
||||
if($2 > 0){ # counted some bytes
|
||||
if(mode == "diff" || mode == "noUpdate")
|
||||
print n, $2
|
||||
if(mode!="noUpdate"){
|
||||
if(inInterfaces(m)){ # if label is an interface
|
||||
if(!(m in mac)){ # if label was not in db (also not in
|
||||
# arp table, but interfaces won't be
|
||||
# there anyway)
|
||||
firstDate[m] = date()
|
||||
mac[m] = inter[m] = m
|
||||
ip[m] = "NA"
|
||||
bw[m "/in"]=bw[m "/out"]= 0
|
||||
}
|
||||
}
|
||||
bw[n]+=$2
|
||||
lastDate[m] = date()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
if(mode=="noUpdate") exit
|
||||
close(dbFile)
|
||||
system("rm -f " dbFile)
|
||||
print "#mac,ip,iface,in,out,total,first_date,last_date" > dbFile
|
||||
OFS=","
|
||||
for(i in mac)
|
||||
print mac[i], ip[i], inter[i], bw[i "/in"], bw[i "/out"], total(i), firstDate[i], lastDate[i] > dbFile
|
||||
close(dbFile)
|
||||
# for hosts without rules
|
||||
for(host in hosts) if(!inInterfaces(host)) newRule(host)
|
||||
}
|
@ -1,313 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# wrtbwmon: traffic logging tool for routers
|
||||
#
|
||||
# Peter Bailey (peter.eldridge.bailey+wrtbwmon AT gmail.com)
|
||||
#
|
||||
# Based on work by:
|
||||
# Emmanuel Brucy (e.brucy AT qut.edu.au)
|
||||
# Fredrik Erlandsson (erlis AT linux.nu)
|
||||
# twist - http://wiki.openwrt.org/RrdTrafficWatch
|
||||
|
||||
trap "rm -f /tmp/*_$$.tmp; kill $$" INT
|
||||
binDir=/usr/sbin
|
||||
dataDir=/usr/share/wrtbwmon
|
||||
lockDir=/tmp/wrtbwmon.lock
|
||||
pidFile=$lockDir/pid
|
||||
networkFuncs=/lib/functions/network.sh
|
||||
uci=`which uci 2>/dev/null`
|
||||
nslookup=`which nslookup 2>/dev/null`
|
||||
nvram=`which nvram 2>/dev/null`
|
||||
|
||||
chains='INPUT OUTPUT FORWARD'
|
||||
DEBUG=
|
||||
interfaces='eth0 tun0' # in addition to detected WAN
|
||||
DB=$2
|
||||
mode=
|
||||
|
||||
# DNS server for reverse lookups provided in "DNS".
|
||||
# don't perform reverse DNS lookups by default
|
||||
DO_RDNS=${DNS-}
|
||||
|
||||
header="#mac,ip,iface,in,out,total,first_date,last_date"
|
||||
|
||||
createDbIfMissing()
|
||||
{
|
||||
[ ! -f "$DB" ] && echo $header > "$DB"
|
||||
}
|
||||
|
||||
checkDbArg()
|
||||
{
|
||||
[ -z "$DB" ] && echo "ERROR: Missing argument 2 (database file)" && exit 1
|
||||
}
|
||||
|
||||
checkDB()
|
||||
{
|
||||
[ ! -f "$DB" ] && echo "ERROR: $DB does not exist" && exit 1
|
||||
[ ! -w "$DB" ] && echo "ERROR: $DB is not writable" && exit 1
|
||||
}
|
||||
|
||||
checkWAN()
|
||||
{
|
||||
[ -z "$wan" ] && echo "Warning: failed to detect WAN interface."
|
||||
}
|
||||
|
||||
checkIptIfMissing()
|
||||
{
|
||||
iptables-save | grep 'RRDIPT_INPUT' >/dev/null 2>&1; CHK1=$?
|
||||
iptables-save | grep 'RRDIPT_OUTPUT' >/dev/null 2>&1; CHK2=$?
|
||||
iptables-save | grep 'RRDIPT_FORWARD' >/dev/null 2>&1; CHK3=$?
|
||||
if [ "$CHK1" != "0" ] || [ "$CHK2" != "0" ] || [ "$CHK3" != "0" ]
|
||||
then
|
||||
/etc/init.d/wrtbwmon restart
|
||||
fi
|
||||
}
|
||||
|
||||
lookup()
|
||||
{
|
||||
MAC=$1
|
||||
IP=$2
|
||||
userDB=$3
|
||||
for USERSFILE in $userDB /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do
|
||||
[ -e "$USERSFILE" ] || continue
|
||||
case $USERSFILE in
|
||||
/tmp/dhcp.leases )
|
||||
USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ')
|
||||
;;
|
||||
/etc/hosts )
|
||||
USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ')
|
||||
;;
|
||||
* )
|
||||
USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,)
|
||||
;;
|
||||
esac
|
||||
[ "$USER" = "*" ] && USER=
|
||||
[ -n "$USER" ] && break
|
||||
done
|
||||
if [ -n "$DO_RDNS" -a -z "$USER" -a "$IP" != "NA" -a -n "$nslookup" ]; then
|
||||
USER=`$nslookup $IP $DNS | awk '!/server can/{if($4){print $4; exit}}' | sed -re 's/[.]$//'`
|
||||
fi
|
||||
[ -z "$USER" ] && USER=${MAC}
|
||||
echo $USER
|
||||
}
|
||||
|
||||
detectIF()
|
||||
{
|
||||
if [ -f "$networkFuncs" ]; then
|
||||
IF=`. $networkFuncs; network_get_device netdev $1; echo $netdev`
|
||||
[ -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
|
||||
if [ -n "$uci" -a -x "$uci" ]; then
|
||||
IF=`$uci get network.${1}.ifname 2>/dev/null`
|
||||
[ $? -eq 0 -a -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
|
||||
if [ -n "$nvram" -a -x "$nvram" ]; then
|
||||
IF=`$nvram get ${1}_ifname 2>/dev/null`
|
||||
[ $? -eq 0 -a -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
}
|
||||
|
||||
detectLAN()
|
||||
{
|
||||
[ -e /sys/class/net/br-lan ] && echo br-lan && return
|
||||
lan=$(detectIF lan)
|
||||
[ -n "$lan" ] && echo $lan && return
|
||||
}
|
||||
|
||||
detectWAN()
|
||||
{
|
||||
[ -n "$WAN_IF" ] && echo $WAN_IF && return
|
||||
wan=$(detectIF wan)
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/')
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
[ -f "$networkFuncs" ] && wan=$(. $networkFuncs; network_find_wan wan; echo $wan)
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
}
|
||||
|
||||
lock()
|
||||
{
|
||||
attempts=0
|
||||
while [ $attempts -lt 10 ]; do
|
||||
mkdir $lockDir 2>/dev/null && break
|
||||
attempts=$((attempts+1))
|
||||
pid=`cat $pidFile 2>/dev/null`
|
||||
if [ -n "$pid" ]; then
|
||||
if [ -d "/proc/$pid" ]; then
|
||||
[ -n "$DEBUG" ] && echo "WARNING: Lockfile detected but process $(cat $pidFile) does not exist !"
|
||||
rm -rf $lockDir
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
mkdir $lockDir 2>/dev/null
|
||||
echo $$ > $pidFile
|
||||
[ -n "$DEBUG" ] && echo $$ "got lock after $attempts attempts"
|
||||
trap '' INT
|
||||
}
|
||||
|
||||
unlock()
|
||||
{
|
||||
rm -rf $lockDir
|
||||
[ -n "$DEBUG" ] && echo $$ "released lock"
|
||||
trap "rm -f /tmp/*_$$.tmp; kill $$" INT
|
||||
}
|
||||
|
||||
# chain
|
||||
newChain()
|
||||
{
|
||||
chain=$1
|
||||
# Create the RRDIPT_$chain chain (it doesn't matter if it already exists).
|
||||
iptables -t mangle -N RRDIPT_$chain 2> /dev/null
|
||||
|
||||
# Add the RRDIPT_$chain CHAIN to the $chain chain if not present
|
||||
iptables -t mangle -C $chain -j RRDIPT_$chain 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
[ -n "$DEBUG" ] && echo "DEBUG: iptables chain misplaced, recreating it..."
|
||||
iptables -t mangle -I $chain -j RRDIPT_$chain
|
||||
fi
|
||||
}
|
||||
|
||||
# chain tun
|
||||
newRuleIF()
|
||||
{
|
||||
chain=$1
|
||||
IF=$2
|
||||
|
||||
#!@todo test
|
||||
if [ "$chain" = "OUTPUT" ]; then
|
||||
cmd="iptables -t mangle -o $IF -j RETURN"
|
||||
eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain"
|
||||
elif [ "$chain" = "INPUT" ]; then
|
||||
cmd="iptables -t mangle -i $IF -j RETURN"
|
||||
eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain"
|
||||
fi
|
||||
}
|
||||
|
||||
update()
|
||||
{
|
||||
#!@todo could let readDB.awk handle this; that would place header
|
||||
#!info in fewer places
|
||||
createDbIfMissing
|
||||
checkIptIfMissing
|
||||
|
||||
checkDB
|
||||
checkWAN
|
||||
|
||||
> /tmp/iptables_$$.tmp
|
||||
lock
|
||||
# only zero our own chains
|
||||
for chain in $chains; do
|
||||
iptables -nvxL RRDIPT_$chain -t mangle -Z >> /tmp/iptables_$$.tmp
|
||||
done
|
||||
# the iptables and readDB commands have to be separate. Otherwise,
|
||||
# they will fight over iptables locks
|
||||
awk -v mode="$mode" -v interfaces=\""$interfaces"\" -f $binDir/readDB.awk \
|
||||
$DB \
|
||||
/proc/net/arp \
|
||||
/tmp/iptables_$$.tmp
|
||||
unlock
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
case $1 in
|
||||
"dump" )
|
||||
checkDbArg
|
||||
lock
|
||||
tr ',' '\t' < "$DB"
|
||||
unlock
|
||||
;;
|
||||
|
||||
"update" )
|
||||
checkDbArg
|
||||
wan=$(detectWAN)
|
||||
interfaces="$interfaces $wan"
|
||||
update
|
||||
rm -f /tmp/*_$$.tmp
|
||||
exit
|
||||
;;
|
||||
|
||||
"publish" )
|
||||
checkDbArg
|
||||
[ -z "$3" ] && echo "ERROR: Missing argument 3 (output html file)" && exit 1
|
||||
|
||||
# sort DB
|
||||
lock
|
||||
|
||||
# busybox sort truncates numbers to 32 bits
|
||||
grep -v '^#' $DB | awk -F, '{OFS=","; a=sprintf("%f",$4/1e6); $4=""; print a,$0}' | tr -s ',' | sort -rn | awk -F, '{OFS=",";$1=sprintf("%f",$1*1e6);print}' > /tmp/sorted_$$.tmp
|
||||
|
||||
# create HTML page
|
||||
rm -f $3.tmp
|
||||
cp $dataDir/usage.htm1 $3.tmp
|
||||
|
||||
#!@todo fix publishing
|
||||
while IFS=, read PEAKUSAGE_IN MAC IP IFACE PEAKUSAGE_OUT TOTAL FIRSTSEEN LASTSEEN
|
||||
do
|
||||
echo "
|
||||
new Array(\"$(lookup $MAC $IP $4)\",\"$MAC\",\"$IP\",
|
||||
$PEAKUSAGE_IN,$PEAKUSAGE_OUT,$TOTAL,\"$FIRSTSEEN\",\"$LASTSEEN\")," >> $3.tmp
|
||||
done < /tmp/sorted_$$.tmp
|
||||
echo "0);" >> $3.tmp
|
||||
|
||||
sed "s/(date)/`date`/" < $dataDir/usage.htm2 >> $3.tmp
|
||||
mv $3.tmp $3
|
||||
|
||||
unlock
|
||||
|
||||
#Free some memory
|
||||
rm -f /tmp/*_$$.tmp
|
||||
;;
|
||||
|
||||
"setup" )
|
||||
checkDbArg
|
||||
[ -w "$DB" ] && echo "Warning: using existing $DB"
|
||||
createDbIfMissing
|
||||
|
||||
for chain in $chains; do
|
||||
newChain $chain
|
||||
done
|
||||
|
||||
#lan=$(detectLAN)
|
||||
wan=$(detectWAN)
|
||||
checkWAN
|
||||
interfaces="$interfaces $wan"
|
||||
|
||||
# track local data
|
||||
for chain in INPUT OUTPUT; do
|
||||
for interface in $interfaces; do
|
||||
[ -n "$interface" ] && [ -e "/sys/class/net/$interface" ] && newRuleIF $chain $interface
|
||||
done
|
||||
done
|
||||
|
||||
# this will add rules for hosts in arp table
|
||||
update
|
||||
|
||||
rm -f /tmp/*_$$.tmp
|
||||
;;
|
||||
|
||||
"remove" )
|
||||
iptables-save | grep -v RRDIPT | iptables-restore
|
||||
rm -rf "$lockDir"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo \
|
||||
"Usage: $0 {setup|update|publish|remove} [options...]
|
||||
Options:
|
||||
$0 setup database_file
|
||||
$0 update database_file
|
||||
$0 publish database_file path_of_html_report [user_file]
|
||||
Examples:
|
||||
$0 setup /tmp/usage.db
|
||||
$0 update /tmp/usage.db
|
||||
$0 publish /tmp/usage.db /www/user/usage.htm /jffs/users.txt
|
||||
$0 remove
|
||||
Note: [user_file] is an optional file to match users with MAC addresses.
|
||||
Its format is \"00:MA:CA:DD:RE:SS,username\", with one entry per line."
|
||||
;;
|
||||
esac
|
@ -1,23 +0,0 @@
|
||||
<html><head><title>Traffic</title>
|
||||
<script type="text/javascript">
|
||||
function getSize(size) {
|
||||
var prefix=new Array("","k","M","G","T","P","E","Z"); var base=1000;
|
||||
var pos=0;
|
||||
while (size>base) {
|
||||
size/=base; pos++;
|
||||
}
|
||||
if (pos > 2) precision=1000; else precision = 1;
|
||||
return (Math.round(size*precision)/precision)+' '+prefix[pos];}
|
||||
</script></head>
|
||||
<body><h1>Total Usage:</h1>
|
||||
<table border="1">
|
||||
<tr bgcolor=silver>
|
||||
<th>User</th>
|
||||
<th>Download</th>
|
||||
<th>Upload</th>
|
||||
<th>Total</th>
|
||||
<th>First seen</th>
|
||||
<th>Last seen</th>
|
||||
</tr>
|
||||
<script type="text/javascript">
|
||||
var values = new Array(
|
@ -1,14 +0,0 @@
|
||||
var totalIn = 0;
|
||||
var totalOut = 0;
|
||||
for (i=0; i < values.length-1; i++) {
|
||||
totalIn += values[i][3];
|
||||
totalOut += values[i][4];
|
||||
document.write("<tr><td><div title=\"" + values[i][1] + " (" + values[i][2] + ")" + "\">" + values[i][0] + "</div></td>");
|
||||
for (j=3; j < 6; j++)
|
||||
document.write("<td>" + getSize(values[i][j]) + "</td>");
|
||||
document.write("<td>" + values[i][6] + "</td><td>" + values[i][7] + "</td></tr>");
|
||||
}
|
||||
document.write("<tr><td>TOTAL</td><td>" + getSize(totalIn) + "</td><td>" + getSize(totalOut) + "</td><td>" + getSize(totalIn + totalOut) + "</td><td></td><td></td></tr>");
|
||||
</script></table>
|
||||
<br /><small>This page was generated on (date)</small>
|
||||
</body></html>
|
Loading…
Reference in New Issue
Block a user