mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
urlfilter: transform into ParentalControl bbf extension
* config file has been renamed from urlfilter to parentalcontrol * along with urlfiltering, shell scripts handle internet_access and bedtime blocking support, which have been added as separate sections for better mapping to the bbf data model extension * uci-default script has been added to handle migration from previous to new format
This commit is contained in:
parent
cc0d1b5910
commit
6f7f14b241
10 changed files with 623 additions and 443 deletions
|
|
@ -5,13 +5,13 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=urlfilter
|
||||
PKG_VERSION:=2.0.1
|
||||
PKG_VERSION:=2.0.2
|
||||
|
||||
LOCAL_DEV:=0
|
||||
ifneq ($(LOCAL_DEV),1)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://dev.iopsys.eu/network/urlfilter.git
|
||||
PKG_SOURCE_VERSION:=08044747036259db23d6581fcbaa51750516749e
|
||||
PKG_SOURCE_VERSION:=e56831c48472c5fa2595f12f02baa4437b6970e4
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=skip
|
||||
endif
|
||||
|
|
@ -26,7 +26,7 @@ define Package/urlfilter
|
|||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=URL filter
|
||||
DEPENDS:=+libuci +libnetfilter-queue +libnfnetlink +iptables-mod-nfqueue +libpthread +libubox +ubus +conntrack
|
||||
DEPENDS:=+libuci +libcurl +libnetfilter-queue +libnfnetlink +iptables-mod-nfqueue +libpthread +libubox +ubus +conntrack
|
||||
endef
|
||||
|
||||
define Package/urlfilter/description
|
||||
|
|
@ -38,11 +38,17 @@ TARGET_CFLAGS += \
|
|||
|
||||
ifeq ($(LOCAL_DEV),1)
|
||||
define Build/Prepare
|
||||
$(CP) -rf ./urlfilter/* $(PKG_BUILD_DIR)/
|
||||
$(CP) -rf ./urlfilter/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
endif
|
||||
|
||||
define Package/urlfilter/install
|
||||
$(INSTALL_DIR) $(1)/lib/parentalcontrol
|
||||
$(INSTALL_DATA) ./files/lib/parentalcontrol/parentalcontrol.sh $(1)/lib/parentalcontrol/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc
|
||||
$(INSTALL_DATA) ./files/etc/firewall.parentalcontrol $(1)/etc/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/urlfilter $(1)/usr/sbin
|
||||
|
||||
|
|
@ -50,15 +56,11 @@ define Package/urlfilter/install
|
|||
$(INSTALL_BIN) ./files/etc/init.d/urlfilter $(1)/etc/init.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_DATA) ./files/etc/config/urlfilter $(1)/etc/config/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/
|
||||
$(INSTALL_DATA) ./files/etc/firewall.urlfilter $(1)/etc/
|
||||
$(INSTALL_DATA) ./files/etc/config/parentalcontrol $(1)/etc/config/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||
$(INSTALL_DATA) ./files/etc/uci-defaults/95-urlfilter_add_firewall_rule $(1)/etc/uci-defaults
|
||||
|
||||
$(BBFDM_INSTALL_MS_DM) ./files/etc/urlfilter/urlfilter.json $(1) $(PKG_NAME)
|
||||
$(INSTALL_DATA) ./files/etc/uci-defaults/95-firewall_parentalcontrol.ucidefaults $(1)/etc/uci-defaults/
|
||||
$(INSTALL_DATA) ./files/etc/uci-defaults/95-migrate_urlfilter.ucidefaults $(1)/etc/uci-defaults/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,urlfilter))
|
||||
|
|
|
|||
41
urlfilter/files/etc/firewall.parentalcontrol
Normal file
41
urlfilter/files/etc/firewall.parentalcontrol
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
. /lib/parentalcontrol/parentalcontrol.sh
|
||||
|
||||
add_iptables_nfqueue_rules() {
|
||||
iptables -w -nL FORWARD|grep -iqE "NFQUEUE"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
# setup netfilter queue 0, use queue bypass so that if no application is
|
||||
# listening to this queue then traffic is unaffected.
|
||||
iptables -w -I FORWARD 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
iptables -w -I FORWARD 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
iptables -w -I INPUT 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
iptables -w -I INPUT 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
# disable acceleration for https packet so that they can be read by urlfilter
|
||||
ebtables --concurrent -A FORWARD -p ip --ip-protocol 6 --ip-destination-port 443 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip --ip-protocol 6 --ip-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip --ip-protocol 17 --ip-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
fi
|
||||
|
||||
ip6tables -w -nL FORWARD|grep -iqE "NFQUEUE"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
#ip6table rules
|
||||
ip6tables -w -I FORWARD 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
ip6tables -w -I FORWARD 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
ip6tables -w -I INPUT 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
ip6tables -w -I INPUT 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
# disable acceleration for https packet so that they can be read by urlfilter
|
||||
ebtables --concurrent -A FORWARD -p ip6 --ip6-protocol 6 --ip6-destination-port 443 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip6 --ip6-protocol 6 --ip6-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip6 --ip6-protocol 17 --ip6-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
add_iptables_nfqueue_rules
|
||||
|
||||
handle_internet_schedule
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
iptables -w -nL FORWARD|grep -iqE "NFQUEUE"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
# setup netfilter queue 0, use queue bypass so that if no application is
|
||||
# listening to this queue then traffic is unaffected.
|
||||
iptables -w -I FORWARD 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
iptables -w -I FORWARD 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
iptables -w -I INPUT 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
iptables -w -I INPUT 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
# disable acceleration for https packet so that they can be read by urlfilter
|
||||
ebtables --concurrent -A FORWARD -p ip --ip-protocol 6 --ip-destination-port 443 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip --ip-protocol 6 --ip-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip --ip-protocol 17 --ip-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
fi
|
||||
|
||||
ip6tables -w -nL FORWARD|grep -iqE "NFQUEUE"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
#ip6table rules
|
||||
ip6tables -w -I FORWARD 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
ip6tables -w -I FORWARD 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
ip6tables -w -I INPUT 1 -p tcp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
ip6tables -w -I INPUT 1 -p udp --match multiport --ports 80,443,53 -j NFQUEUE --queue-num 0 --queue-bypass
|
||||
|
||||
# disable acceleration for https packet so that they can be read by urlfilter
|
||||
ebtables --concurrent -A FORWARD -p ip6 --ip6-protocol 6 --ip6-destination-port 443 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip6 --ip6-protocol 6 --ip6-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
ebtables --concurrent -A FORWARD -p ip6 --ip6-protocol 17 --ip6-source-port 53 -j SKIPLOG 2> /dev/null
|
||||
fi
|
||||
|
|
@ -4,12 +4,11 @@ START=95
|
|||
STOP=10
|
||||
|
||||
USE_PROCD=1
|
||||
NAME=urlfilter
|
||||
PROG=/usr/sbin/urlfilter
|
||||
|
||||
start_service() {
|
||||
|
||||
if [ "$(uci -q get urlfilter.globals.enable)" == "1" ]; then
|
||||
if [ "$(uci -q get parentalcontrol.globals.enable)" == "1" ]; then
|
||||
procd_open_instance urlfilter
|
||||
procd_set_param command ${PROG}
|
||||
procd_set_param respawn
|
||||
|
|
@ -21,6 +20,10 @@ start_service() {
|
|||
sleep 5
|
||||
conntrack -F
|
||||
fi
|
||||
|
||||
. /lib/parentalcontrol/parentalcontrol.sh
|
||||
|
||||
handle_internet_schedule
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -30,5 +33,6 @@ reload_service() {
|
|||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "urlfilter"
|
||||
procd_add_reload_trigger "parentalcontrol"
|
||||
procd_add_reload_trigger "schedules"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -f /etc/firewall.parentalcontrol ]; then
|
||||
uci -q get firewall.parentalcontrol >/dev/null || {
|
||||
uci -q set firewall.parentalcontrol=include
|
||||
uci -q set firewall.parentalcontrol.path="/etc/firewall.parentalcontrol"
|
||||
uci -q set firewall.parentalcontrol.reload=1
|
||||
}
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
# Convert URL filter to parental control format
|
||||
urlfilter_config="/etc/config/urlfilter"
|
||||
parentalcontrol_config="/etc/config/parentalcontrol"
|
||||
schedules_config="/etc/config/schedules"
|
||||
|
||||
# this script only needs to work if urlfilter_config was found
|
||||
if [ ! -s "$urlfilter_config" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# reset parentalcontrol_config
|
||||
# but schedules might have data other than schedules
|
||||
# so append to it
|
||||
rm -f "$parentalcontrol_config"
|
||||
touch "$parentalcontrol_config"
|
||||
|
||||
schedules_enable="$(uci -q get schedules.global.enable)"
|
||||
# if no schedules config, then add it
|
||||
if [ ! -s "$schedules_config" ]; then
|
||||
touch "$schedules_config"
|
||||
schedules_enable=1
|
||||
fi
|
||||
|
||||
# Parse globals
|
||||
uci -q batch <<EOF
|
||||
set parentalcontrol.globals=globals
|
||||
set parentalcontrol.globals.enable="$(uci -q get urlfilter.globals.enable)"
|
||||
set schedules.global=global
|
||||
set schedules.global.enable="$schedules_enable"
|
||||
EOF
|
||||
|
||||
# Function to handle filter sections
|
||||
handle_filter() {
|
||||
local section="$1"
|
||||
local url_list="$2"
|
||||
local profile_name="$3"
|
||||
local access="$4"
|
||||
local profile_name enable start_time duration days filter_profile macaddr_list
|
||||
|
||||
config_get filter_profile "$section" profile
|
||||
|
||||
# if option profile value and profile name match, then
|
||||
if [ "$filter_profile" = "$profile_name" ]; then
|
||||
config_get enable "$section" enable
|
||||
config_get start_time "$section" start_time
|
||||
config_get duration "$section" duration
|
||||
config_get macaddr_list "$section" macaddr
|
||||
config_get days "$section" day
|
||||
|
||||
# Add hosts based on MAC addresses in the filter
|
||||
if [ -n "$macaddr_list" ]; then
|
||||
for macaddr in $macaddr_list; do
|
||||
uci -q add_list parentalcontrol.${profile_name}.host="$macaddr"
|
||||
done
|
||||
fi
|
||||
|
||||
uci -q set parentalcontrol.f_$filter_profile=profile_urlfilter
|
||||
uci -q set parentalcontrol.f_$filter_profile.enable="$enable"
|
||||
uci -q set parentalcontrol.f_$filter_profile.access="$access"
|
||||
uci -q set parentalcontrol.f_$filter_profile.dm_parent="$profile_name"
|
||||
|
||||
# Add URLs one by one as filter_text
|
||||
for url in $url_list; do
|
||||
uci -q add_list parentalcontrol.f_$filter_profile.filter_text="$url"
|
||||
done
|
||||
|
||||
# Add schedule if time restrictions exist
|
||||
if [ -n "$start_time" ] && [ -n "$duration" ] && [ -n "$days" ]; then
|
||||
local schedule_name
|
||||
# declare and assign separately to avoid masking return value
|
||||
schedule_name="$(uci -q add schedules schedule)"
|
||||
|
||||
# if adding schedule was successful, then populate it
|
||||
if [ "$?" -eq 0 ] && [ -n "$schedule_name" ]; then
|
||||
uci -q set schedules.${schedule_name}=schedule
|
||||
uci -q set schedules.${schedule_name}.enable="$enable"
|
||||
uci -q set schedules.${schedule_name}.start="$start_time"
|
||||
uci -q set schedules.${schedule_name}.duration="$duration"
|
||||
|
||||
for day in $days; do
|
||||
uci -q add_list schedules.${schedule_name}.day="$day"
|
||||
done
|
||||
|
||||
# Link schedule to profile_urlfilter
|
||||
uci -q set parentalcontrol.f_$filter_profile.profile_urlfilter_schedule="$schedule_name"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to handle profile sections
|
||||
handle_profile() {
|
||||
local section="$1"
|
||||
local profile_name whitelist_urls blacklist_urls
|
||||
|
||||
config_get profile_name "$section" name
|
||||
|
||||
# if name was not set then continue
|
||||
if [ -z "$profile_name" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
config_get whitelist_urls "$section" whitelist_url
|
||||
config_get blacklist_urls "$section" blacklist_url
|
||||
|
||||
# Create the new profile in parentalcontrol
|
||||
uci -q set parentalcontrol.${profile_name}=profile
|
||||
uci -q set parentalcontrol.${profile_name}.name="$profile_name"
|
||||
|
||||
# Add whitelist/blacklist URLs as filter_text
|
||||
if [ -n "$whitelist_urls" ]; then
|
||||
config_foreach handle_filter filter "$whitelist_urls" "$profile_name" 1 # Whitelist access
|
||||
fi
|
||||
if [ -n "$blacklist_urls" ]; then
|
||||
config_foreach handle_filter filter "$blacklist_urls" "$profile_name" 0 # Blacklist access
|
||||
fi
|
||||
}
|
||||
|
||||
# Load urlfilter UCI config and iterate through profiles and filters
|
||||
config_load "urlfilter"
|
||||
config_foreach handle_profile profile
|
||||
config_foreach handle_filter filter
|
||||
|
||||
# Commit changes
|
||||
uci commit parentalcontrol
|
||||
uci commit schedules
|
||||
|
||||
rm -f "$urlfilter_config"
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
|
||||
if uci -q get firewall.urlfilter >/dev/null; then
|
||||
exit
|
||||
fi
|
||||
|
||||
uci set firewall.urlfilter=include
|
||||
uci set firewall.urlfilter.reload=1
|
||||
uci set firewall.urlfilter.path=/etc/firewall.urlfilter
|
||||
uci commit firewall
|
||||
|
|
@ -1,387 +0,0 @@
|
|||
{
|
||||
"json_plugin_version": 2,
|
||||
"Device.{BBF_VENDOR_PREFIX}URLFilter.": {
|
||||
"type": "object",
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "This object contains the information about URLs to be blocked or allowed to access from specified MAC addresses in given time duration.",
|
||||
"access": false,
|
||||
"array": false,
|
||||
"Enable": {
|
||||
"type": "boolean",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Enable or disable URLFiltering on the CPE.",
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"name": "globals"
|
||||
},
|
||||
"option": {
|
||||
"name": "enable"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"GlobalBlacklist": {
|
||||
"type": "boolean",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Enable or disable access of the URLs specified in <<param|BlacklistURL>> from all connected devices.",
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"name": "globals"
|
||||
},
|
||||
"option": {
|
||||
"name": "global_blacklist"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"BlacklistURL": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Comma separated list of URLs to be blacklisted from all connected devices.",
|
||||
"list": {
|
||||
"datatype": "string"
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"name": "globals"
|
||||
},
|
||||
"list": {
|
||||
"name": "blacklist_url"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ProfileNumberOfEntries": {
|
||||
"type": "unsignedInt",
|
||||
"read": true,
|
||||
"write": false,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"datatype": "unsignedInt",
|
||||
"description": "<<numentries>>",
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"type": "profile"
|
||||
},
|
||||
"option": {
|
||||
"name": "@Count"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Device.{BBF_VENDOR_PREFIX}URLFilter.Profile.{i}.": {
|
||||
"type": "object",
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Table contain details of the blacklist/whitelist profiles.",
|
||||
"uniqueKeys": [
|
||||
"Name"
|
||||
],
|
||||
"access": true,
|
||||
"array": true,
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"type": "profile"
|
||||
},
|
||||
"dmmapfile": "dmmap_urlfilter"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Alias": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": false,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"datatype": "string",
|
||||
"range": [
|
||||
{
|
||||
"max": 64
|
||||
}
|
||||
],
|
||||
"flags": [
|
||||
"Unique",
|
||||
"Linker"
|
||||
],
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "@Name"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Name": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Name of the profile. This should be unique for each entry in the table.",
|
||||
"datatype": "string",
|
||||
"range": [
|
||||
{
|
||||
"max": 64
|
||||
}
|
||||
],
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "name"
|
||||
}
|
||||
]
|
||||
},
|
||||
"WhitelistURL": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Comma separated list of URLs which should be allowed to access.",
|
||||
"list": {
|
||||
"datatype": "string"
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"list": "whitelist_url"
|
||||
}
|
||||
]
|
||||
},
|
||||
"BlacklistURL": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Comma separated list of URLs which should not be allowed to access.",
|
||||
"list": {
|
||||
"datatype": "string"
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"list": "blacklist_url"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"FilterNumberOfEntries": {
|
||||
"type": "unsignedInt",
|
||||
"read": true,
|
||||
"write": false,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"datatype": "unsignedInt",
|
||||
"description": "<<numentries>>",
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"type": "filter"
|
||||
},
|
||||
"option": {
|
||||
"name": "@Count"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Device.{BBF_VENDOR_PREFIX}URLFilter.Filter.{i}.": {
|
||||
"type": "object",
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Table contain MAC addresses on which <<object|Profile>> should be applied along with other information like filtering should be applied on which day, the timing information when the filtering should be done etc.",
|
||||
"access": true,
|
||||
"array": true,
|
||||
"mapping": [
|
||||
{
|
||||
"type": "uci",
|
||||
"uci": {
|
||||
"file": "urlfilter",
|
||||
"section": {
|
||||
"type": "filter"
|
||||
},
|
||||
"dmmapfile": "dmmap_urlfilter"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enable": {
|
||||
"type": "boolean",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Enable or disable this filter instance on the CPE.",
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "enable"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Profile": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"flags": [
|
||||
"Reference"
|
||||
],
|
||||
"description": "Path of the <<object|Profile>> that should be applied.",
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "profile",
|
||||
"linker_obj": "Device.{BBF_VENDOR_PREFIX}URLFilter.Profile.*.Alias"
|
||||
}
|
||||
]
|
||||
},
|
||||
"MACAddress": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Comma separated list of MAC addresses for which the filtering should be done.",
|
||||
"list": {
|
||||
"datatype": "string"
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"list": "macaddr"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Day": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Comma separated list of weekdays. Filtering should be done on the mentioned days only.",
|
||||
"list": {
|
||||
"datatype": "string"
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"list": "day"
|
||||
}
|
||||
]
|
||||
},
|
||||
"StartTime": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "Time when filtering shall start.",
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "start_time"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Duration": {
|
||||
"type": "string",
|
||||
"read": true,
|
||||
"write": true,
|
||||
"protocols": [
|
||||
"cwmp",
|
||||
"usp"
|
||||
],
|
||||
"description": "The duration in seconds to filter the URLs from start time.",
|
||||
"mapping": [
|
||||
{
|
||||
"data": "@Parent",
|
||||
"type": "uci_sec",
|
||||
"key": "duration"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
419
urlfilter/files/lib/parentalcontrol/parentalcontrol.sh
Normal file
419
urlfilter/files/lib/parentalcontrol/parentalcontrol.sh
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
day=""
|
||||
next_days=""
|
||||
prev_days=""
|
||||
schedule_added=""
|
||||
|
||||
ACCESS_RULE=""
|
||||
IP_RULE=""
|
||||
|
||||
ACL_FILE=""
|
||||
parentalcontrol_ipv4_forward=""
|
||||
parentalcontrol_ipv6_forward=""
|
||||
|
||||
# Function to calculate UTC time and relative day
|
||||
get_relative_day() {
|
||||
local hour="$1"
|
||||
local offset="$2"
|
||||
local relative_day="$3"
|
||||
local utc_hour
|
||||
|
||||
# we need to force hours and minutes to be treated as base 10 (decimal)
|
||||
# otherwise shell will treat, for example, 09 as octal
|
||||
# hour=$((10#$hour)) does not work on busybox
|
||||
# so we use another trick
|
||||
hour=$(expr $hour + 0)
|
||||
|
||||
# Extract the sign and the hour part of the offset
|
||||
local sign=${offset:0:1}
|
||||
local offset_hour=${offset:1:2}
|
||||
|
||||
# Adjust hour based on the offset
|
||||
if [ "$sign" = "-" ]; then
|
||||
utc_hour=$((hour + offset_hour))
|
||||
else
|
||||
utc_hour=$((hour - offset_hour))
|
||||
fi
|
||||
|
||||
# Handle overflow/underflow of UTC hours to keep within 0-23 range
|
||||
if [ $utc_hour -lt 0 ]; then
|
||||
if [ "$relative_day" = "today" ]; then
|
||||
relative_day="yesterday"
|
||||
else
|
||||
relative_day="today"
|
||||
fi
|
||||
elif [ $utc_hour -ge 24 ]; then
|
||||
if [ "$relative_day" = "today" ]; then
|
||||
relative_day="tomorrow"
|
||||
else
|
||||
relative_day="tomorrow"
|
||||
fi
|
||||
else
|
||||
if [ "$relative_day" = "tomorrow" ]; then
|
||||
relative_day="tomorrow"
|
||||
else
|
||||
relative_day="today"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$relative_day"
|
||||
}
|
||||
|
||||
get_next_day() {
|
||||
local weekday="$1"
|
||||
case "$weekday" in
|
||||
"Mon"|"Monday") echo "Tuesday"
|
||||
;;
|
||||
"Tue"|"Tuesday") echo "Wednesday"
|
||||
;;
|
||||
"Wed"|"Wednesday") echo "Thursday"
|
||||
;;
|
||||
"Thu"|"Thursday") echo "Friday"
|
||||
;;
|
||||
"Fri"|"Friday") echo "Saturday"
|
||||
;;
|
||||
"Sat"|"Saturday") echo "Sunday"
|
||||
;;
|
||||
"Sun"|"Sunday") echo "Monday"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_previous_day() {
|
||||
local weekday="$1"
|
||||
case "$weekday" in
|
||||
"Mon"|"Monday") echo "Sunday"
|
||||
;;
|
||||
"Tue"|"Tuesday") echo "Monday"
|
||||
;;
|
||||
"Wed"|"Wednesday") echo "Tuesday"
|
||||
;;
|
||||
"Thu"|"Thursday") echo "Wednesday"
|
||||
;;
|
||||
"Fri"|"Friday") echo "Thursday"
|
||||
;;
|
||||
"Sat"|"Saturday") echo "Friday"
|
||||
;;
|
||||
"Sun"|"Sunday") echo "Saturday"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
add_access_rule() {
|
||||
local rule_prefix="$1"
|
||||
local start_time="$2"
|
||||
local stop_time="$3"
|
||||
local weekdays="$4"
|
||||
local target="$5"
|
||||
local rule
|
||||
local start_hm stop_hm
|
||||
|
||||
if [ -z "$target" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -n "$weekdays" ]; then
|
||||
|
||||
start_hm=$(echo "$start_time" | awk -F: '{ print $1,$2 }' | sed 's/ //')
|
||||
stop_hm=$(echo "$stop_time" | awk -F: '{ print $1,$2 }' | sed 's/ //')
|
||||
|
||||
if [ "$start_hm" = "$stop_hm" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
rule_prefix="$rule_prefix -m time --timestart $start_time --timestop $stop_time --weekdays $weekdays"
|
||||
fi
|
||||
|
||||
rule="$rule_prefix -j $target"
|
||||
|
||||
echo "iptables -w -A parentalcontrol_forward ${rule}" >> "$ACL_FILE"
|
||||
echo "ip6tables -w -A parentalcontrol_forward ${rule}" >> "$ACL_FILE"
|
||||
}
|
||||
|
||||
generate_ip_rule() {
|
||||
local utc_start_relative_day="$1"
|
||||
local utc_end_relative_day="$2"
|
||||
local utc_start_time="$3"
|
||||
local utc_stop_time="$4"
|
||||
local target="$5"
|
||||
|
||||
# Handle the cases based on the relation between utc_start_relative_day and utc_end_relative_day
|
||||
if [ "$utc_start_relative_day" = "yesterday" ] && [ "$utc_end_relative_day" = "yesterday" ]; then
|
||||
# Rule for yesterday only
|
||||
add_access_rule "$IP_RULE" "$utc_start_time" "$utc_stop_time" "$prev_days" "$target"
|
||||
|
||||
elif [ "$utc_start_relative_day" = "yesterday" ] && [ "$utc_end_relative_day" = "today" ]; then
|
||||
# Rule for yesterday to today
|
||||
add_access_rule "$IP_RULE" "$utc_start_time" "23:59:59" "$prev_days" "$target"
|
||||
add_access_rule "$IP_RULE" "00:00" "$utc_stop_time" "$day" "$target"
|
||||
|
||||
elif [ "$utc_start_relative_day" = "today" ] && [ "$utc_end_relative_day" = "today" ]; then
|
||||
# Rule for today only
|
||||
add_access_rule "$IP_RULE" "$utc_start_time" "$utc_stop_time" "$day" "$target"
|
||||
|
||||
elif [ "$utc_start_relative_day" = "today" ] && [ "$utc_end_relative_day" = "tomorrow" ]; then
|
||||
# Rule for today to tomorrow
|
||||
add_access_rule "$IP_RULE" "$utc_start_time" "23:59:59" "$day" "$target"
|
||||
add_access_rule "$IP_RULE" "00:00" "$utc_stop_time" "$next_days" "$target"
|
||||
|
||||
elif [ "$utc_start_relative_day" = "tomorrow" ] && [ "$utc_end_relative_day" = "tomorrow" ]; then
|
||||
# Rule for tomorrow only
|
||||
add_access_rule "$IP_RULE" "$utc_start_time" "$utc_stop_time" "$next_days" "$target"
|
||||
else
|
||||
logger -t parental_control "Error: Unhandled case"
|
||||
fi
|
||||
}
|
||||
|
||||
handle_day_list() {
|
||||
local value=$1
|
||||
|
||||
val=$(echo $value | cut -c 1-3)
|
||||
next_day_val=$(get_next_day $val)
|
||||
prev_day_val=$(get_previous_day $val)
|
||||
if [ -z $day ]; then
|
||||
day="$val"
|
||||
next_days="$next_day_val"
|
||||
prev_days="$prev_day_val"
|
||||
else
|
||||
day="$day,$val"
|
||||
next_days="$next_days,$next_day_val"
|
||||
prev_days="$prev_days,$prev_day_val"
|
||||
fi
|
||||
}
|
||||
|
||||
handle_schedule() {
|
||||
local schedule_section="$1"
|
||||
local type="$2"
|
||||
local schedule_ref="$3"
|
||||
local local_start_time local_stop_time duration zone_offset local_start_hh local_stop_hh
|
||||
local is_enabled
|
||||
local target
|
||||
local day_config
|
||||
local relative_day_end="today"
|
||||
|
||||
IP_RULE="$ACCESS_RULE"
|
||||
day=""
|
||||
next_days=""
|
||||
prev_days=""
|
||||
local all_days="Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
|
||||
|
||||
zone_offset=$(date +%z)
|
||||
|
||||
if [ "$type" = "profile_bedtime_schedule" ]; then
|
||||
target="DROP"
|
||||
|
||||
config_get local_start_time "$schedule_section" "start_time" "00:00:00"
|
||||
config_get local_stop_time "$schedule_section" "end_time" "23:59:59"
|
||||
|
||||
local_start_hh=$(echo $local_start_time | awk -F: '{ print $1 }')
|
||||
local_stop_hh=$(echo $local_stop_time | awk -F: '{ print $1 }')
|
||||
|
||||
config_get day_config "$schedule_section" "day" "$all_days"
|
||||
else
|
||||
if [ "$schedule_ref" != "$schedule_section" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
config_get_bool is_enabled "$schedule_section" "enable" 0
|
||||
if [ $is_enabled -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# for access rules to be effective for a schedule, need to add DROP rule
|
||||
# to block the access outside the defined schedule
|
||||
# therefore, set flag
|
||||
if [ "$schedule_added" = "0" ]; then
|
||||
schedule_added="1"
|
||||
fi
|
||||
|
||||
target="ACCEPT"
|
||||
|
||||
config_get local_start_time "$schedule_section" "start_time" "00:00"
|
||||
config_get duration "$schedule_section" "duration"
|
||||
|
||||
local hh=$(echo $local_start_time | awk -F: '{ print $1 }')
|
||||
local mm=$(echo $local_start_time | awk -F: '{ print $2 }')
|
||||
local hh_s=`expr $hh \* 3600`
|
||||
local mm_s=`expr $mm \* 60`
|
||||
local ss=$(( hh_s + mm_s ))
|
||||
local_start_hh=$hh
|
||||
|
||||
if [ -n "$duration" ]; then
|
||||
local stop_ss rem_ss mm
|
||||
stop_ss=$(( ss + duration ))
|
||||
hh=$(( stop_ss / 3600 ))
|
||||
rem_ss=$(( stop_ss % 3600 ))
|
||||
mm=$(( rem_ss / 60 ))
|
||||
ss=$(( rem_ss % 60 ))
|
||||
local_stop_time="$hh:$mm:$ss"
|
||||
local_stop_hh="$hh"
|
||||
else
|
||||
# if duration is not specified, then apply rule to end of the day
|
||||
local_stop_time="23:59:59"
|
||||
local_stop_hh="23"
|
||||
fi
|
||||
|
||||
config_get day_config "$schedule_section" "day" "$all_days"
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for d in $day_config; do
|
||||
handle_day_list $d
|
||||
done
|
||||
|
||||
utc_start_time=$(date -u -d @$(date "+%s" -d "$local_start_time") +%H:%M)
|
||||
utc_start_time="$utc_start_time"
|
||||
utc_stop_time=$(date -u -d @$(date "+%s" -d "$local_stop_time") +%H:%M)
|
||||
utc_stop_time="$utc_stop_time"
|
||||
|
||||
# Determine whether the local end hour crosses midnight
|
||||
if [ "$local_start_hh" -gt "$local_stop_hh" ]; then
|
||||
relative_day_end="tomorrow"
|
||||
fi
|
||||
|
||||
local utc_start_relative_day=$(get_relative_day "$local_start_hh" "$zone_offset" "today")
|
||||
local utc_end_relative_day=$(get_relative_day "$local_stop_hh" "$zone_offset" "$relative_day_end")
|
||||
|
||||
generate_ip_rule "$utc_start_relative_day" "$utc_end_relative_day" "$utc_start_time" "$utc_stop_time" "$target"
|
||||
}
|
||||
|
||||
# Function that parses input for MAC addresses or hostnames
|
||||
parse_macs_or_hostnames() {
|
||||
local input="$1"
|
||||
local lease_file="/tmp/dhcp.leases"
|
||||
|
||||
for item in $input; do
|
||||
case "$item" in
|
||||
??:??:??:??:??:??)
|
||||
# It's a MAC address, print it as is
|
||||
echo "$item"
|
||||
;;
|
||||
*)
|
||||
# Assume it's a hostname and search for its MAC address in the leases file
|
||||
mac=$(awk -v hostname="$item" '$4 == hostname {print $2}' "$lease_file")
|
||||
if [ -n "$mac" ]; then
|
||||
echo "$mac"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
handle_bedtime() {
|
||||
local mac_addresses="$1"
|
||||
local mac
|
||||
|
||||
# if mac addresses are present, then we apply the rule for each mac address
|
||||
# otherwise apply the rule to everybody
|
||||
for mac in $mac_addresses; do
|
||||
ACCESS_RULE="-m mac --mac-source $mac"
|
||||
|
||||
config_foreach handle_schedule profile_bedtime_schedule "profile_bedtime_schedule" ""
|
||||
done
|
||||
}
|
||||
|
||||
handle_internet_access() {
|
||||
local mac_addresses="$1"
|
||||
local mac
|
||||
|
||||
local access_policy
|
||||
config_get access_policy "$profile_section" "internet_access_policy"
|
||||
|
||||
local schedule_ref
|
||||
config_get schedule_ref "$profile_section" "internet_access_schedule"
|
||||
|
||||
for mac in $mac_addresses; do
|
||||
ACCESS_RULE="-m mac --mac-source $mac"
|
||||
|
||||
# As per Data Model, if access policy is deny, then schedule is to be ignored
|
||||
# and no access is to be provided for the device
|
||||
if [ "$access_policy" = "Deny" ]; then
|
||||
add_access_rule "$ACCESS_RULE" "" "" "" "DROP"
|
||||
continue # no need to parse schedule
|
||||
fi
|
||||
|
||||
schedule_added="0"
|
||||
|
||||
# check if schedule is defined for this profile/internet_access instance
|
||||
# and if yes, create rule accordingly
|
||||
if [ -n "$schedule_ref" ]; then
|
||||
config_load "schedules"
|
||||
config_foreach handle_schedule schedule "schedule" "$schedule_ref"
|
||||
fi
|
||||
|
||||
# for access rule to work, need to have default drop rule as last rule
|
||||
if [ "$schedule_added" = "1" ]; then
|
||||
add_access_rule "$ACCESS_RULE" "" "" "" "DROP"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
handle_profile() {
|
||||
local profile_section="$1"
|
||||
local internet_access_enable bedtime_enable hostlist
|
||||
|
||||
config_get hostlist "$profile_section" "host"
|
||||
|
||||
if [ -z "$hostlist" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
ACCESS_RULE=""
|
||||
|
||||
# convert hostnames to mac addresses if needed
|
||||
# and replace newlines with space because it messes up the for loops in
|
||||
# handle_internet_access and handle_bedtime functions
|
||||
local mac_addresses="$(parse_macs_or_hostnames "${hostlist}" | tr '\n' ' ')"
|
||||
|
||||
# default value of Hosts.AccessControl.{i}.Enable is false,
|
||||
# so, if not defined in uci as 1, assume 0
|
||||
config_get_bool internet_access_enable "$profile_section" "internet_access_enable" 0
|
||||
if [ $internet_access_enable -gt 0 ]; then
|
||||
handle_internet_access "${mac_addresses}"
|
||||
# handle_internet_access may have loaded schedules uci
|
||||
# so, reload parentalcontrol
|
||||
config_load "parentalcontrol"
|
||||
fi
|
||||
|
||||
config_get_bool bedtime_enable "$profile_section" "bedtime_enable" 0
|
||||
if [ $bedtime_enable -gt 0 ]; then
|
||||
handle_bedtime "${mac_addresses}"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
handle_internet_schedule() {
|
||||
ACL_FILE="/tmp/parentalcontrol_access_control/access_control.rules"
|
||||
|
||||
rm -f $ACL_FILE
|
||||
|
||||
mkdir -p /tmp/parentalcontrol_access_control/
|
||||
touch $ACL_FILE
|
||||
|
||||
echo "iptables -w -F parentalcontrol_forward" >> $ACL_FILE
|
||||
echo "ip6tables -w -F parentalcontrol_forward" >> $ACL_FILE
|
||||
|
||||
parentalcontrol_ipv4_forward=$(iptables -t filter --list -n | grep parentalcontrol_forward)
|
||||
if [ -z "$parentalcontrol_ipv4_forward" ]; then
|
||||
echo "iptables -w -t filter -N parentalcontrol_forward" >> $ACL_FILE
|
||||
ret=$?
|
||||
[ $ret -eq 0 ] && echo "iptables -w -t filter -I FORWARD -j parentalcontrol_forward" >> $ACL_FILE
|
||||
fi
|
||||
|
||||
parentalcontrol_ipv6_forward=$(ip6tables -t filter --list -n | grep parentalcontrol_forward)
|
||||
if [ -z "$parentalcontrol_ipv6_forward" ]; then
|
||||
echo "ip6tables -w -t filter -N parentalcontrol_forward" >> $ACL_FILE
|
||||
ret=$?
|
||||
[ $ret -eq 0 ] && echo "ip6tables -w -t filter -I FORWARD -j parentalcontrol_forward" >> $ACL_FILE
|
||||
fi
|
||||
|
||||
# Load /etc/config/parentalcontrol UCI file
|
||||
config_load "parentalcontrol"
|
||||
config_foreach handle_profile "profile"
|
||||
|
||||
# apply the rules
|
||||
sh $ACL_FILE
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue