You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
7.2 KiB
Bash

#!/bin/sh
. /lib/functions.sh
SCRIPT=$0
# the lock is meant for ebtables, and other scripts are also
# using ebtables. Needs clean up, maybe move to functions.sh, TBD?
LOCKFILE=/tmp/ebtables.lock
LOGFILE=/tmp/log/parental_control.log
PACKAGE=parental_control
# variable to remember if parental control is enabled
parental_control_enabled=0
# uncomment the next line if matching rules should be logged to syslog
# (for debugging), needs watchers extension
#local EBLOG=--log
_log()
{
if [ ${LOGGING} -eq 1 ]; then
local ts=$(date)
echo "$ts $@" >> ${LOGFILE}
fi
}
_exit()
{
local rc=$1
lock -u ${LOCKFILE}
exit ${rc}
}
_cron_restart()
{
/etc/init.d/cron restart > /dev/null
}
_add_cron_script()
{
(crontab -l ; echo "$1") | sort -u | crontab -
}
_rm_cron_script()
{
crontab -l | grep -v "$1" | sort -u | crontab -
}
_rm_and_add_cron_script()
{
(crontab -l | grep -v "$1"; [ -n "$2" ] && echo "$2") | sort -u | crontab -
}
_format_dow_list()
{
local dow=$1
local flist=""
local day
for day in ${dow}
do
if [ ! -z ${flist} ]; then
flist="${flist},"
fi
flist="${flist}${day:0:3}"
done
echo ${flist}
}
_shift_dow_list_by_one_day()
{
local dow=$1
local flist=""
local day
for day in $1
do
if [ ! -z ${flist} ]; then
flist="${flist},"
fi
case $day in
Mon*)
flist="${flist}Tue"
;;
Tue*)
flist="${flist}Wed"
;;
Wed*)
flist="${flist}Thu"
;;
Thu*)
flist="${flist}Fri"
;;
Fri*)
flist="${flist}Sat"
;;
Sat*)
flist="${flist}Sun"
;;
Sun*)
flist="${flist}Mon"
;;
esac
done
echo "$flist"
}
_enable_parental_control()
{
local entry=$1
local enabled starttime stoptime dow
config_get enabled $entry enabled 0
[ "$enabled" -eq 0 ] && return 0
config_get starttime $entry starttime
[ -z "$starttime" ] && return 1
config_get stoptime $entry stoptime
[ -z "$stoptime" ] && return 1
config_get dow $entry daysofweek
[ -z "$dow" ] && return 1
local fdow=$(_format_dow_list "$dow")
# If it shall stop on the same day at 00:00, 24:00 is the transition to the following day, if this is the case,
# the days of the weeks have to be incremented by one
if [ "${stoptime}" == "24:00" ]; then
fdow_stop=$(_shift_dow_list_by_one_day "$dow")
stoptime="0:00"
else
fdow_stop=${fdow}
fi
local stop_cron_entry="$(echo ${stoptime} | awk -F':' '{print $2, $1}') * * ${fdow_stop} ${SCRIPT} check" # ${entry}"
echo "${stop_cron_entry}"
if [[ $starttime != $stoptime ]]
then
local start_cron_entry="$(echo ${starttime} | awk -F':' '{print $2, $1}') * * ${fdow} ${SCRIPT} check" # ${entry}"
echo "${start_cron_entry}"
fi
return 0
}
_create_cron_entries()
{
config_foreach _enable_parental_control entry
}
replace_rules() {
local mac macs="$1"
ebtables -F i-parental-control
ebtables -F o-parental-control
for mac in $macs; do
ebtables -A i-parental-control -s $mac -j DROP $EBLOG
ebtables -A o-parental-control -d $mac -j DROP $EBLOG
done
}
create_chains() {
ebtables -N i-parental-control -P RETURN 2>/dev/null || return 0
ebtables -N o-parental-control -P RETURN 2>/dev/null || return 0
ebtables -A INPUT -i ath+ -j i-parental-control $EBLOG
ebtables -A FORWARD -i ath+ -j i-parental-control $EBLOG
ebtables -A FORWARD -o ath+ -j o-parental-control $EBLOG
ebtables -A OUTPUT -o ath+ -j o-parental-control $EBLOG
}
delete_chains() {
ebtables -D INPUT -i ath+ -j i-parental-control $EBLOG 2>/dev/null
ebtables -D FORWARD -i ath+ -j i-parental-control $EBLOG 2>/dev/null
ebtables -D FORWARD -o ath+ -j o-parental-control $EBLOG 2>/dev/null
ebtables -D OUTPUT -o ath+ -j o-parental-control $EBLOG 2>/dev/null
ebtables -X i-parental-control 2>/dev/null
ebtables -X o-parental-control 2>/dev/null
}
check_cron_status()
{
if [ ${parental_control_enabled} -eq 1 ]; then
_rm_and_add_cron_script "${SCRIPT}" "$(_create_cron_entries)"
else
_rm_cron_script "${SCRIPT}"
fi
_cron_restart
}
handle_global() {
local cfg="$1"
config_get_bool parental_control_enabled "$cfg" enabled 0
config_get_bool LOGGING "$cfg" logging 0
}
handle_entry() {
local cfg="$1"; shift
local curTime="$1"; shift
local weekday="$1"; shift
local blocked_var="$1"; shift
local allowed_var="$1"; shift
local list_var
local entry_enabled starttime stoptime stations dow
config_get_bool entry_enabled "$cfg" enabled 0
# Check if current entry is enabled
[ "$entry_enabled" -eq 0 ] && return 0
# lowercase:
stations="$(config_get "$cfg" stations | tr ABCDEF abcdef)"
config_get dow "$cfg" daysofweek
[ -z "$dow" ] && return 1
config_get starttime "$cfg" starttime
[ -z "$starttime" ] && return 1
config_get stoptime "$cfg" stoptime
[ -z "$stoptime" ] && return 1
# Check if current entry is relevant for today
echo "$dow" | grep "$weekday" > /dev/null || return 0
#remove :, so that we can make easy integer comparison
starttime=${starttime//:}
stoptime=${stoptime//:}
if [ $curTime -ge $starttime ] && [ $curTime -lt $stoptime ]; then
list_var=$allowed_var
else
list_var=$blocked_var
fi
# add or delete rules to the list of stations
local st
for st in $stations; do
! list_contains $list_var $st && append $list_var $st
done
}
# evaluate if a MAC address is allowed at the current time of day
check_and_apply_parental_control_state() {
local curTime=$(date "+%k%M")
local weekday=$(date "+%A")
if [ "$parental_control_enabled" -eq 0 ]; then
delete_chains
else
local blocked_macs allowed_macs st stations
create_chains
# collect which MACs are allowed or blocked by a config entry in separate lists
config_foreach handle_entry entry "$curTime" "$weekday" blocked_macs allowed_macs
# allowed wins
for st in $blocked_macs; do
! list_contains allowed_macs $st && append stations $st
done
replace_rules "$stations"
fi
}
usage()
{
echo ""
echo "$0 cron|check|help"
echo ""
echo " UCI Config File: /etc/config/${PACKAGE}"
echo ""
echo " cron: Create cronjob entries."
echo " check: Check if stations should get access to the network or should be blocked"
echo " help: This description."
echo ""
}
###############################################################################
# MAIN
###############################################################################
config_load "${PACKAGE}"
config_foreach handle_global global
_log ${SCRIPT} $1 $2
lock ${LOCKFILE}
case "$1" in
cron) check_cron_status ;;
check) check_and_apply_parental_control_state;;
help|--help|-h|*) usage ;;
esac
_exit 0