#!/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