#! /bin/sh # ----------- ENVIRONMENT VARIABLES ----------- # CAN BE SOURCED INTO UTILS USING AEGIS ------- # USING: eval "$(aegis _env)" ----------------- if [ "$1" = '_env' ]; then /usr/bin/awk '$0==": ENV EOF"{exit} $0==": ENV STOP"{e=0} e{print} $0==": ENV START"{e=1}' $0; exit; fi # --------------------------------------------- : ENV START # --------------------------------------------- { ! command -v iptables && export PATH=/bin:/sbin:/usr/bin:/usr/sbin ! command -v iprange && [ -e /root/.profile ] && source /root/.profile SC_VERS="1.7.1" SC_NAME="aegis" SC_ABR="aegis" #RT_MOD="$(cat /module_name)" # Orbi=RBR50 R7800=R7800 R9000=R9000 IPR_BIN="$(/usr/bin/which iprange)" IPT_COM='iptables' IPT_BIN="/usr/sbin/$IPT_COM" IPS_BIN="/usr/sbin/ipset" #IPTBL_SRC="${SC_ABR}_src" IPTBL_WAN_SRC="${SC_ABR}_wan_src" IPTBL_TUN_SRC="${SC_ABR}_vpn_src" #IPTBL_DST="${SC_ABR}_dst" IPTBL_WAN_DST="${SC_ABR}_wan_dst" IPTBL_TUN_DST="${SC_ABR}_vpn_dst" IPSET_ALL_BL_NAME="${SC_ABR}_all_bl" IPSET_WAN_BL_NAME="${SC_ABR}_wan_bl" IPSET_TUN_BL_NAME="${SC_ABR}_vpn_bl" IPSET_ALL_WL_NAME="${SC_ABR}_all_wl" IPSET_WAN_WL_NAME="${SC_ABR}_wan_wl" IPSET_TUN_WL_NAME="${SC_ABR}_vpn_wl" IPSET_TMP="${SC_ABR}_tmp" ROOT_DIR="/opt/bolemo" PETC_DIR="$ROOT_DIR/etc/.${SC_ABR}" ALL_BL_FILE="$PETC_DIR/all.bl.dir" WAN_BL_FILE="$PETC_DIR/wan.bl.dir" TUN_BL_FILE="$PETC_DIR/tun.bl.dir" ALL_WL_FILE="$PETC_DIR/all.bp.dir" WAN_WL_FILE="$PETC_DIR/wan.bp.dir" TUN_WL_FILE="$PETC_DIR/tun.bp.dir" INFO_FILE="/tmp/${SC_ABR}_status" LOG_FILE="/var/log/log-$SC_ABR" SHIELD_LOCK="/tmp/${SC_ABR}_lock" CONF_DIR="$ROOT_DIR/etc/config" /sbin/ifconfig ppp0 && WAN_IF='ppp0' || WAN_IF="$(/bin/nvram get wan_ifname)" # VPN tunnel detection if /sbin/ifconfig wg0; then # WireGuard TUN_IF='wg0' else TUN_IF="$(/bin/ps -w|/bin/grep -F -- '/usr/sbin/openvpn --dev'|/bin/grep -vE 'grep|server_tap|server_tun')" [ "$TUN_IF" ] && TUN_IF=${TUN_IF##* --dev } && TUN_IF=${TUN_IF%% *} # Open VPN client or no tunneling fi } >/dev/null 2>&1 DEBUG=false STDERR=/dev/null # INFO FROM (2 bits) INFO_FROM_MASK=3 INFO_FROM_FWS=1 # _ x INFO_FROM_PM=2 # x _ INFO_FROM_SC=3 # x x # INFO DIRECTIVES (18 bits) INFO_DIR_SHIFT=2 INFO_DIR_MASK=524287 INFO_DIR__SAME=1 # _ _ x SAME => KEEP INFO_DIR__KEEP=2 # _ x _ KEEP (was loaded but no file) INFO_DIR__LOAD=4 # x _ _ INFO_DIR__SWAP=5 # x _ x RELOAD INFO_DIR__DEST=6 # x x _ => was there, was destroyed INFO_DIR__MISS=0 # _ _ _ => was not there, was not loaded INFO_DIR__DIFF=7 # x x x used for status INFO_DIR__MASK=7 # x x x INFO_DIR_ALL=0 INFO_DIR_WAN=6 INFO_DIR_TUN=12 INFO_DIR_BL=0 INFO_DIR_WL=3 # INFO IPTABLES (2 bits) INFO_IPT_SHIFT=20 INFO_IPT_MASK=3 INFO_IPT_KEEP=1 # . x INFO_IPT_RUN=2 # x . INFO_IPT_PBM=0 # _ _ # INFO LOGD (2 bits) and _logd_start return code INFO_LOGD_SHIFT=22 INFO_LOGD_MASK=3 INFO_LOGD_STARTED=0 # _ _ INFO_LOGD_STOPPED=1 # _ x INFO_LOGD_KEEP_ON=2 # x _ INFO_LOGD_KEEP_OFF=3 # x x # INFO STRUCTURE (24 bits) # L L I I D6 D6 D6 D5 D5 D5 D4 D4 D4 D3 D3 D3 D2 D2 D2 D1 D1 D1 F F # SHIELD DNA (8 bits) #DNA_SHIFT= DNA_MASK=511 DNA_LOG=1 DNA_ABL=2 DNA_AWL=4 DNA_WBW=8 DNA_WBL=16 DNA_WWL=32 DNA_TBW=64 DNA_TBL=128 DNA_TWL=256 # --------------- ENV FUNCTIONS --------------- sc_conf() { [ -z "$2" ] && _OPT= || _OPT=".$2" ;/sbin/uci -qc $CONF_DIR $1 $SC_ABR$_OPT; return $?; } get_ipt() { _IPT="$($IPT_BIN -w -S|/bin/grep -F "$SC_ABR")" if $DEBUG; then debug 'get_ipt'; echo "$_IPT"|/usr/bin/awk '{print " "$0}'; fi } >>"$STDERR" 2>&1 inet_for_if() { _IP="$(/usr/sbin/ip -4 addr show $1|/usr/bin/awk 'NR==2 {print $2;exit}')" case $_IP in */32) echo $_IP ;; */*) echo $_IP|$IPR_BIN - ;; *) echo "$_IP/32" ;; esac } # --------------------------------------------- : ENV STOP # --------------------------------------------- # ------------------- DEBUG ------------------- debug() { touch $STDERR; echo "$(/bin/date +%s) $SC_ABR: $*" >>"$STDERR"; } export DEBUG STDERR="$(sc_conf get debug)" if [ "$STDERR" ]; then DEBUG=true debug "$SC_NAME $SC_VERS launched [$0 $*] ["$(/bin/cat /module_name /hardware_version /firmware_version)"]" sc_conf show | /usr/bin/awk '{print " - "$0}' >>"$STDERR" else DEBUG=false STDERR=/dev/null fi _exit() { $DEBUG && debug "exiting with code: $1"; exit $1; } _warn() { $DEBUG && debug "warning: $1"; >&2 echo -e "\033[31m! $1\033[0m"; [ "$2" ] && _exit $2; } # -------------- LOGD FUNCTIONS --------------- # Aegis logging daemon # --------------------------------------------- LOGD_NAME=${SC_ABR}-logd LOGD_PID="/var/run/${LOGD_NAME}.pid" LOGD_TMP="/tmp/$LOGD_NAME" _logd_logmsg() { $DEBUG && debug "_logd_logmsg" if test -e /var/log/log-message; then echo '/var/log/log-message'; return 0 elif test -e /var/log/log_message; then echo '/var/log/log_message'; return 0 else _warn "No log-message or log_message found!"; return 1 fi } _logd_start() { $DEBUG && debug "_logd_start" if [ -e $LOGD_PID ] && /bin/kill -0 $(cat $LOGD_PID); then # logd is already running if _logd_logmsg >/dev/null; then return $INFO_LOGD_KEEP_ON else _logd_stop; return $INFO_LOGD_STOPPED; fi fi if ! sc_conf get log.len >/dev/null; then sc_conf set log.len=5000; sc_conf commit; fi; local LOG_MSG=$(_logd_logmsg); [ $? -ne 0 ] && return $INFO_LOGD_KEEP_OFF cat >"$LOGD_TMP" <>$STDERR\ndebug \"log daemon starting with PID: \$PID\"") /bin/rm -f $LOGD_TMP 2>/dev/null trapf() { $($DEBUG && echo "debug \"trap signal: \$1\";") [ -e $LOGD_PID ] && /bin/rm -f $LOGD_PID; [ -e $LOGD_TMP ] && /bin/rm -f $LOGD_TMP; $($DEBUG && echo 'debug "log daemon exiting";') exit; } 2>>$STDERR trap "trapf TERM" TERM; trap "trapf INT" INT; trap "trapf QUIT" QUIT; trap "trapf EXIT" EXIT touch $LOG_FILE inode() { set -- \$(/bin/ls -i $LOG_MSG); echo \$1; } lc() { set -- \$(/usr/bin/wc -l \$1); echo \$1; } while :; do local INODE=\$(inode) $($DEBUG && echo "debug \"working with log-message inode: \$INODE\"") local NUMLINES=\$(uci -qc $CONF_DIR get $SC_ABR.log.len) if [ -s $LOG_FILE ]; then $($DEBUG && echo "debug 'log-aegis exists and is not empty'") local FIRST_MSG_LINE="\$(/usr/bin/awk '/\[$SC_ABR\]/{print; exit}' $LOG_MSG)" # first line in rotated message log if [ "\$FIRST_MSG_LINE" ]; then local FIRST_EXT_TS="\$(/usr/bin/awk -F':' 'NR==1{print \$1; exit}' $LOG_FILE)" # first timestamp in our log if [ 0\${FIRST_MSG_LINE%%:*} -gt 0\$FIRST_EXT_TS ]; then :>$LOGD_TMP /usr/bin/awk '\$0=="'"\$FIRST_MSG_LINE"'"{exit} {print}' $LOG_FILE >>$LOGD_TMP if [ 0\$NUMLINES -lt 0\$(lc $LOGD_TMP) ] then /usr/bin/tail -n \$NUMLINES $LOGD_TMP >$LOG_FILE else /bin/cat $LOGD_TMP >$LOG_FILE fi $($DEBUG && echo "debug \"log-message 1st aegis record is more recent than log-aegis 1st record: kept older records from log-aegis up to \$NUMLINES\"") else :>$LOG_FILE $($DEBUG && echo "; debug 'log-message 1st aegis record is older than log-aegis 1st record: emptying log-aegis'") fi elif [ 0\$NUMLINES -lt 0\$(lc $LOG_FILE) ] then /usr/bin/tail -n \$NUMLINES $LOG_FILE >$LOGD_TMP; cat $LOGD_TMP >$LOG_FILE $($DEBUG && echo "debug \"no aegis log record in log-message; kept only \$NUMLINES records\"") fi else :>$LOG_FILE $($DEBUG && echo "; debug 'aegis-log was empty or inexistant, making sure file exists'") fi /bin/rm -f $LOGD_TMP # using LOG_FILE to LOGD_TMP to LOG_FILE allow to keep same inode for LOG_FILE # now LOG_FILE ends just before LOG_MSG starts and is no longer than NUMLINES local C=1 D=1 FC=false while /usr/bin/awk -F: '/\[$SC_ABR\]/{st=index(\$0," ");if (\$1==pts) {c++} else {c=0;pts=\$1}; printf("%s:%.3d:%s\n",\$1,c,substr(\$0,st)); fflush()}'; do sleep 2 & wait \$! [ "\$INODE" != "\$(inode)" ] && break if [ \$C -eq 10 ]; then # check every 20 seconds if [ -e $LOGD_PID ]; then [ "\$(/bin/cat $LOGD_PID)" != "\$PID" ] && { $($DEBUG && echo "debug \"$LOGD_PID (\$(/bin/cat $LOGD_PID)) is different than PID (\$PID): killing daemon\";") /bin/kill \$PID; } else $($DEBUG && echo "debug \"$LOGD_PID is missing: killing daemon\";") /bin/kill \$PID; fi if ! $IPT_BIN -w -S 2>/dev/null |/bin/grep -qF -- "-j LOG --log-prefix \"[$SC_ABR] "; then $($DEBUG && echo "debug \"checking iptables logging rules returned: \$?\"") if [ -e "$SHIELD_LOCK" ]; then $($DEBUG && echo "debug 'shield is locked, waiting for next check'" || echo ":") elif \$FC; then $($DEBUG && echo "debug 'shield is unlocked, this is second check: killing daemon';") /bin/kill \$PID; $($DEBUG && echo "else debug 'shield is unlocked but waiting for second check';") fi FC=true; C=5 else FC=false; C=1; fi else C=\$((C+1)); fi if [ \$D -eq 300 ]; then $($DEBUG && echo "debug '10 minutes in the loop; breaking it.';") break else D=\$((D+1)); fi done <$LOG_MSG >>$LOG_FILE done 2>>"$STDERR" EOF cd /tmp; /bin/sh $LOGD_NAME & echo $! >$LOGD_PID return $INFO_LOGD_STARTED } _logd_stop() { $DEBUG && debug "_logd_stop"; [ -e $LOGD_PID ] && /bin/kill $(cat $LOGD_PID) && return $INFO_LOGD_STOPPED || return $INFO_LOGD_KEEP_OFF; } 2>/dev/null _logd_status() { $DEBUG && debug "_logd_status"; [ -e $LOGD_PID ] && /bin/kill -0 $(cat $LOGD_PID); return $?; } # ------------- CIPSET FUNCTIONS -------------- # Copy ipset in /tmp to work on it # --------------------------------------------- _cipset_trap() { $DEBUG && debug "_cipset_trap"; _cipset_end; exit; } _cipset_init() { _CIPSET_DIR=$(/bin/mktemp -d "/tmp/${SC_ABR}_XXXXXX"); trap "_cipset_trap" TERM INT; $DEBUG && debug "_cipset_init (dir: $_CIPSET_DIR)"; } 2>>"$STDERR" _cipset_end() { if [ -d "$_CIPSET_DIR" ]; then /bin/rm -rf $_CIPSET_DIR; fi; trap - TERM INT; $DEBUG && debug "_cipset_end"; } 2>>"$STDERR" _cipset_copy_set() { $DEBUG && debug "_cipset_copy_set $*" return $({ { $IPS_BIN -q -L "$1" 3>&1; echo $? >&3; }|/usr/bin/awk 'NR==1,/Members:/ {next};NF' >"$_CIPSET_DIR/$1"; } 3>&1) } 2>>"$STDERR" _cipset_diff_set_file() { $DEBUG && debug "_cipset_diff_set_file $*" $IPR_BIN --quiet "$_CIPSET_DIR/$1" --diff "$2" return $? } 2>>"$STDERR" _cipset_swap_set_file() { $DEBUG && debug "_cipset_swap_set_file $*" /bin/cp -f $2 "$_CIPSET_DIR/$1" /usr/bin/awk '{l[c++]=$0} END {print "create '$IPSET_TMP' hash:net family inet maxelem "c; while(d>"$STDERR" _cipset_create_set_file() { $DEBUG && debug "_cipset_create_set_file $*" /bin/cp -f $2 "$_CIPSET_DIR/$1" /usr/bin/awk '{l[c++]=$0} END {print "create '$1' hash:net family inet maxelem "c; while(d>"$STDERR" _cipset_inet_in_bl() { $DEBUG && debug "_cipset_inet_in_bl $*" [ -s "$_CIPSET_DIR/$IPSET_ALL_BL_NAME" ] && [ -z "$(echo "$1" | $IPR_BIN "$_CIPSET_DIR/$IPSET_ALL_BL_NAME" --common - )" ] && return 1 [ -s "$_CIPSET_DIR/$2" ] && [ -z "$(echo "$1" | $IPR_BIN "$_CIPSET_DIR/$2" --common - )" ] && return 1 return 0 } 2>>"$STDERR" _cipset_count_set() { $DEBUG && debug "_cipset_count_set $*" $IPR_BIN "$_CIPSET_DIR/$1" -C|/usr/bin/cut -d, -f2 } 2>>"$STDERR" # ------- NON ENV SCRIPT WIDE FUNCTIONS ------- clean_ipset() { for SET in $($IPS_BIN -q -L -n|/bin/grep -F "$SC_ABR"); do $IPS_BIN -q -X "$SET"; done; } express_ipt_dna() { $DEBUG && debug "express_ipt_dna $*" # $1: status file, if not: we already have vars [ "$1" ] && read _NFO _DNA _WAN _WINET _TUN _TINET <"$1" [ "$_WAN" ] && _WIF=true || _WIF=false [ "$_TUN" ] && _TIF=true || _TIF=false [ $((_DNA&DNA_LOG)) -ne 0 ] && _LOG=true || _LOG=false [ $((_DNA&DNA_ABL)) -ne 0 ] && _ABL=true || _ABL=false [ $((_DNA&DNA_AWL)) -ne 0 ] && _AWL=true || _AWL=false [ $((_DNA&DNA_WBW)) -ne 0 ] && _WBW=true || _WBW=false [ $((_DNA&DNA_WBL)) -ne 0 ] && _WBL=true || _WBL=false [ $((_DNA&DNA_WWL)) -ne 0 ] && _WWL=true || _WWL=false [ $((_DNA&DNA_TBW)) -ne 0 ] && _TBW=true || _TBW=false [ $((_DNA&DNA_TBL)) -ne 0 ] && _TBL=true || _TBL=false [ $((_DNA&DNA_TWL)) -ne 0 ] && _TWL=true || _TWL=false $_TIF && echo "-N $IPTBL_TUN_DST" $_TIF && echo "-N $IPTBL_TUN_SRC" $_WIF && echo "-N $IPTBL_WAN_DST" $_WIF && echo "-N $IPTBL_WAN_SRC" # IFO $_WIF && echo "-A INPUT -i $_WAN -m comment --comment \"jump to $SC_ABR WAN src chain\" -j $IPTBL_WAN_SRC" $_TIF && echo "-A INPUT -i $_TUN -m comment --comment \"jump to $SC_ABR VPN src chain\" -j $IPTBL_TUN_SRC" $_WIF && echo "-A FORWARD -i $_WAN -m comment --comment \"jump to $SC_ABR WAN src chain\" -j $IPTBL_WAN_SRC" $_WIF && echo "-A FORWARD -o $_WAN -m comment --comment \"jump to $SC_ABR WAN dst chain\" -j $IPTBL_WAN_DST" $_TIF && echo "-A FORWARD -i $_TUN -m comment --comment \"jump to $SC_ABR VPN src chain\" -j $IPTBL_TUN_SRC" $_TIF && echo "-A FORWARD -o $_TUN -m comment --comment \"jump to $SC_ABR VPN dst chain\" -j $IPTBL_TUN_DST" $_WIF && echo "-A OUTPUT -o $_WAN -m comment --comment \"jump to $SC_ABR WAN dst chain\" -j $IPTBL_WAN_DST" $_TIF && echo "-A OUTPUT -o $_TUN -m comment --comment \"jump to $SC_ABR VPN dst chain\" -j $IPTBL_TUN_DST" if $_TIF; then # TUN DST $_TBW && echo "-A $IPTBL_TUN_DST -d $_TINET -m comment --comment \"$SC_ABR inet bypass\" -j RETURN" if $_ABL; then $_TBL && echo "-A $IPTBL_TUN_DST -m set ! --match-set $IPSET_ALL_BL_NAME dst -m set ! --match-set $IPSET_TUN_BL_NAME dst -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" \ || echo "-A $IPTBL_TUN_DST -m set ! --match-set $IPSET_ALL_BL_NAME dst -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" else $_TBL && echo "-A $IPTBL_TUN_DST -m set ! --match-set $IPSET_TUN_BL_NAME dst -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" fi $_AWL && echo "-A $IPTBL_TUN_DST -m set --match-set $IPSET_ALL_WL_NAME dst -m comment --comment \"in $SC_ABR whitelist\" -j RETURN" $_TWL && echo "-A $IPTBL_TUN_DST -m set --match-set $IPSET_TUN_WL_NAME dst -m comment --comment \"in $SC_ABR VPN whitelist\" -j RETURN" $_LOG && echo "-A $IPTBL_TUN_DST -j LOG --log-prefix \"[$SC_ABR] IF=VPN DIR=OUT \"" echo "-A $IPTBL_TUN_DST -m comment --comment \"$SC_ABR reject outgoing\" -j REJECT --reject-with icmp-admin-prohibited" # TUN SRC $_TBW && echo "-A $IPTBL_TUN_SRC -s $_TINET -m comment --comment \"$SC_ABR inet bypass\" -j RETURN" if $_ABL; then $_TBL && echo "-A $IPTBL_TUN_SRC -m set ! --match-set $IPSET_ALL_BL_NAME src -m set ! --match-set $IPSET_TUN_BL_NAME src -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" \ || echo "-A $IPTBL_TUN_SRC -m set ! --match-set $IPSET_ALL_BL_NAME src -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" else $_TBL && echo "-A $IPTBL_TUN_SRC -m set ! --match-set $IPSET_TUN_BL_NAME src -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" fi $_AWL && echo "-A $IPTBL_TUN_SRC -m set --match-set $IPSET_ALL_WL_NAME src -m comment --comment \"in $SC_ABR whitelist\" -j RETURN" $_TWL && echo "-A $IPTBL_TUN_SRC -m set --match-set $IPSET_TUN_WL_NAME src -m comment --comment \"in $SC_ABR VPN whitelist\" -j RETURN" $_LOG && echo "-A $IPTBL_TUN_SRC -j LOG --log-prefix \"[$SC_ABR] IF=VPN DIR=IN \"" echo "-A $IPTBL_TUN_SRC -m comment --comment \"$SC_ABR drop incoming\" -j DROP" fi if $_WIF; then # WAN DST $_WBW && echo "-A $IPTBL_WAN_DST -d $_WINET -m comment --comment \"$SC_ABR inet bypass\" -j RETURN" if $_ABL; then $_WBL && echo "-A $IPTBL_WAN_DST -m set ! --match-set $IPSET_ALL_BL_NAME dst -m set ! --match-set $IPSET_WAN_BL_NAME dst -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" \ || echo "-A $IPTBL_WAN_DST -m set ! --match-set $IPSET_ALL_BL_NAME dst -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" else $_WBL && echo "-A $IPTBL_WAN_DST -m set ! --match-set $IPSET_WAN_BL_NAME dst -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" fi $_AWL && echo "-A $IPTBL_WAN_DST -m set --match-set $IPSET_ALL_WL_NAME dst -m comment --comment \"in $SC_ABR whitelist\" -j RETURN" $_WWL && echo "-A $IPTBL_WAN_DST -m set --match-set $IPSET_WAN_WL_NAME dst -m comment --comment \"in $SC_ABR WAN whitelist\" -j RETURN" $_LOG && echo "-A $IPTBL_WAN_DST -j LOG --log-prefix \"[$SC_ABR] IF=WAN DIR=OUT \"" echo "-A $IPTBL_WAN_DST -m comment --comment \"$SC_ABR reject outgoing\" -j REJECT --reject-with icmp-admin-prohibited" # WAN SRC $_WBW && echo "-A $IPTBL_WAN_SRC -s $_WINET -m comment --comment \"$SC_ABR inet bypass\" -j RETURN" if $_ABL; then $_WBL && echo "-A $IPTBL_WAN_SRC -m set ! --match-set $IPSET_ALL_BL_NAME src -m set ! --match-set $IPSET_WAN_BL_NAME src -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" \ || echo "-A $IPTBL_WAN_SRC -m set ! --match-set $IPSET_ALL_BL_NAME src -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" else $_WBL && echo "-A $IPTBL_WAN_SRC -m set ! --match-set $IPSET_WAN_BL_NAME src -m comment --comment \"not in $SC_ABR blocklists\" -j RETURN" fi $_AWL && echo "-A $IPTBL_WAN_SRC -m set --match-set $IPSET_ALL_WL_NAME src -m comment --comment \"in $SC_ABR whitelist\" -j RETURN" $_WWL && echo "-A $IPTBL_WAN_SRC -m set --match-set $IPSET_WAN_WL_NAME src -m comment --comment \"in $SC_ABR WAN whitelist\" -j RETURN" $_LOG && echo "-A $IPTBL_WAN_SRC -j LOG --log-prefix \"[$SC_ABR] IF=WAN DIR=IN \"" echo "-A $IPTBL_WAN_SRC -m comment --comment \"$SC_ABR drop incoming\" -j DROP" fi } ############################################### # # ENGINE-START # ############################################### process_directive() { # $1: IPSET / $2: FILE _NFO=0 if _cipset_copy_set $1; then # an ipset is already loaded if [ -r "$2" ]; then if $_RELOAD_WTD; then _RELOAD=true elif _cipset_diff_set_file $1 $2 # checking if ipset and file are identical then _RELOAD=false; _NFO=$INFO_DIR__SAME else _RELOAD=true fi elif $_RELOAD_WTD; then _NFO=$INFO_DIR__DEST; return 1 # no file, we want to destroy the loaded ipset else _RELOAD=false; _NFO=$INFO_DIR__KEEP # no file, we want to keep the loaded ipset fi if $_RELOAD; then # reload is asked for; so need to swap ipset _cipset_swap_set_file $1 $2 _NFO=$INFO_DIR__SWAP # else keeping existing ipset fi elif [ -r "$2" ]; then # file exists, so creating ipset from it _cipset_create_set_file $1 $2 _NFO=$INFO_DIR__LOAD else _NFO=$INFO_DIR__MISS; return 1 # no file fi return 0 } shield_uprear() { $DEBUG && debug "|---> shield_uprear $*" NFO_FROM=$1 [ "$2" ] && _RELOAD_WTD=true || _RELOAD_WTD=false NFO_DIR=0 NFO_IPT=0 _DNA=0 sc_conf get wan >/dev/null && _WAN=$WAN_IF sc_conf get tun >/dev/null && _TUN=$TUN_IF _cipset_init # creating ipset ALL blocklist if needed process_directive $IPSET_ALL_BL_NAME $ALL_BL_FILE && _DNA=$((_DNA+DNA_ABL)) NFO_DIR=$((NFO_DIR+(_NFO<<(INFO_DIR_ALL+INFO_DIR_BL)))) # creating ipset ALL whitelist if needed process_directive $IPSET_ALL_WL_NAME $ALL_WL_FILE && _DNA=$((_DNA+DNA_AWL)) NFO_DIR=$((NFO_DIR+(_NFO<<(INFO_DIR_ALL+INFO_DIR_WL)))) if [ "$_WAN" ]; then # creating ipset WAN blocklist if needed process_directive $IPSET_WAN_BL_NAME $WAN_BL_FILE && _DNA=$((_DNA+DNA_WBL)) NFO_DIR=$((NFO_DIR+(_NFO<<(INFO_DIR_WAN+INFO_DIR_BL)))) # creating ipset WAN whitelist if needed process_directive $IPSET_WAN_WL_NAME $WAN_WL_FILE && _DNA=$((_DNA+DNA_WWL)) NFO_DIR=$((NFO_DIR+(_NFO<<(INFO_DIR_WAN+INFO_DIR_WL)))) if ! sc_conf get wan.no_bypass >/dev/null; then _WINET=$(inet_for_if $_WAN) _cipset_inet_in_bl $_WINET $IPSET_WAN_BL_NAME && _DNA=$((_DNA+DNA_WBW)) fi fi if [ "$_TUN" ]; then # creating ipset TUN blocklist if needed process_directive $IPSET_TUN_BL_NAME $TUN_BL_FILE && _DNA=$((_DNA+DNA_TBL)) NFO_DIR=$((NFO_DIR+(_NFO<<(INFO_DIR_TUN+INFO_DIR_BL)))) # creating ipset TUN whitelist if needed process_directive $IPSET_TUN_WL_NAME $TUN_WL_FILE && _DNA=$((_DNA+DNA_TWL)) NFO_DIR=$((NFO_DIR+(_NFO<<(INFO_DIR_TUN+INFO_DIR_WL)))) if ! sc_conf get tun.no_bypass >/dev/null; then _TINET=$(inet_for_if $_TUN) _cipset_inet_in_bl $_TINET $IPSET_TUN_BL_NAME && _DNA=$((_DNA+DNA_TBW)) fi fi sc_conf get log.enabled >/dev/null && _DNA=$((_DNA+DNA_LOG)) _cipset_end # do we have any blocking ipset? [ -z "$($IPS_BIN -L -n|/bin/grep "${SC_ABR}.*_bl")" ] && clean_ipset && _warn 'No blocking ipset, aborting!' 1 WIPTF=/tmp/aegis_wipt express_ipt_dna >$WIPTF # creating the lock file to advertise that shield IS BEING (re)-built get_ipt; AIPTF=$SHIELD_LOCK; echo "$_IPT" >$AIPTF if /usr/bin/diff -q $WIPTF $AIPTF >/dev/null; then NFO_IPT=$((NFO_IPT+INFO_IPT_KEEP)); else /usr/bin/awk '$1=="-A"{sub(/-A/,"-D"); system("'$IPT_BIN' -w "$0)}' $AIPTF /usr/bin/awk '$1=="-N"{sub(/-N/,"-X"); system("'$IPT_BIN' -w "$0)}' $AIPTF /usr/bin/awk '$1=="-N"{system("'$IPT_BIN' -w "$0)}' $WIPTF /usr/bin/awk '$1=="-A"{a[i++]="-I"substr($0,3); next} {system("'$IPT_BIN' -w "$0)} END {while(i--){system("'$IPT_BIN' -w "a[i])}}' $WIPTF get_ipt; echo "$_IPT" >$AIPTF /usr/bin/diff -q $WIPTF $AIPTF >/dev/null && NFO_IPT=$((NFO_IPT+INFO_IPT_RUN)) fi #Removing any trace of unused ipsets and if any (used ones won't be deleted) clean_ipset #Log daemon if [ $((_DNA&DNA_LOG)) -ne 0 ]; then _logd_start; else _logd_stop; fi NFO_LOGD=$? /bin/rm -f "$SHIELD_LOCK" # removing the lock file /bin/rm -f "$WIPTF" echo -n "$((NFO_FROM+(NFO_DIR<"$INFO_FILE" $DEBUG && debug "<---| shield_uprear [$INFO_FILE -> $(/bin/cat $INFO_FILE)]" } 2>>"$STDERR" ############################################### # # CALLED FROM FIREWALL-START & POST-MOUNT # ############################################### #we are called from firewall_start.sh if [ "$1" = "_fws" ]; then sc_conf get up >/dev/null && shield_uprear "$INFO_FROM_FWS"; _exit 0; fi #when called from post-mount.sh _pm() { $DEBUG && debug "_pm $*" if sc_conf get up >/dev/null; then [ -d "$ROOT_DIR" ] || /bin/ln -sfn /tmp/mnt/$2/bolemo $ROOT_DIR sc_init; shield_init; shield_uprear "$INFO_FROM_PM" fi _exit 0 } ############################################### # # ADDITIONNAL GLOBALS NEEDED WHEN NOT CALLED FROM FIREWALL-START # ############################################### # --------------------------------------------- : ENV START # --------------------------------------------- SC_NICEPATH="$ROOT_DIR/scripts/$SC_NAME" SC_PATH="$(cd "$ROOT_DIR/scripts/">/dev/null 2>&1; pwd -P)" SRC_LIST="$ROOT_DIR/etc/$SC_NAME.sources" SRC_BL_CACHE="$PETC_DIR/all.src.bl.cache" CUST_ALL_BL_FILE="$ROOT_DIR/etc/${SC_NAME}*.blacklist" CUST_WAN_BL_FILE="$ROOT_DIR/etc/${SC_NAME}*.wan-blacklist" CUST_TUN_BL_FILE="$ROOT_DIR/etc/${SC_NAME}*.vpn-blacklist" CUST_ALL_WL_FILE="$ROOT_DIR/etc/${SC_NAME}*.whitelist" CUST_WAN_WL_FILE="$ROOT_DIR/etc/${SC_NAME}*.wan-whitelist" CUST_TUN_WL_FILE="$ROOT_DIR/etc/${SC_NAME}*.vpn-whitelist" TMP_HTML="/tmp/$SC_NAME-html.tmp" WWW_PATH="$ROOT_DIR/www" FWS_DIR="/opt/scripts" FWS_FILE="$FWS_DIR/firewall-start.sh" # Check if script is installed on USB if [ -z "${SC_PATH##/tmp/mnt/*}" ]; then EXT_DRIVE=true PM_DIR="${SC_PATH%${SC_PATH#/tmp/mnt/*/}}autorun/scripts" PM_FILE="$PM_DIR/post-mount.sh" else EXT_DRIVE=false fi # --------------------------------------------- : ENV STOP # --------------------------------------------- ############################################### # # DEALING WITH EXTERNAL SCRIPTS/CONFS # check, set, clean # ############################################### # SCRIPT: firewall-start.sh ################### check_firewall_start() { $DEBUG && debug "check_firewall_start" [ -x "$FWS_FILE" ] || return 1 [ "$(/bin/sed 's/[[:space:]]\+/ /g' "$FWS_FILE"|/bin/grep -c -- "\[ -x $SC_NICEPATH \] && $SC_NICEPATH _fws")" = 1 ] || return 1 return 0 } set_firewall_start() { $DEBUG && debug "set_firewall_start" [ -d "$FWS_DIR" ] || /bin/mkdir -p "$FWS_DIR" [ -e "$FWS_FILE" ] && /bin/sed -i "/$SC_NAME/d" "$FWS_FILE" echo -e "# Bolemo $SC_NAME\n[ -x $SC_NICEPATH ] && $SC_NICEPATH _fws" >> "$FWS_FILE" [ -x "$FWS_FILE" ] || /bin/chmod +x "$FWS_FILE" } clean_firewall_start() { $DEBUG && debug "clean_firewall_start" if [ -e "$FWS_FILE" ]; then if [ "$(/bin/grep -Fv "$SC_NAME" "$FWS_FILE"|/bin/sed '/^[[:space:]]*$/d')" ]; then /bin/sed -i "/$SC_NAME/d" "$FWS_FILE" [ $VERBOSE ] && echo "- 'firewall-start.sh' has some other rules; removed only our rules." else /bin/rm -f "$FWS_FILE" 2>/dev/null [ $VERBOSE ] && echo "- 'firewall-start.sh' had no other rules; removed it." fi fi } # SCRIPT: post-mount.sh ######################## check_postmount() { $DEBUG && debug "check_postmount" [ -x "$PM_FILE" ] || return 1 [ "$(/bin/sed 's/[[:space:]]\+/ /g' "$PM_FILE"|/bin/grep -cF -- "[ -x $SC_NICEPATH ] && $SC_NICEPATH _pm \$1")" = 1 ] || return 1 return 0 } set_postmount() { $DEBUG && debug "set_postmount" $EXT_DRIVE || return 1 [ -d "$PM_DIR" ] || /bin/mkdir -p "$PM_DIR" [ -e "$PM_FILE" ] && /bin/sed -i "/$SC_NAME/d" "$PM_FILE" echo -e "# Bolemo $SC_NAME\n[ -x $SC_NICEPATH ] && $SC_NICEPATH _pm \$1" >> "$PM_FILE" [ -x "$PM_FILE" ] || /bin/chmod +x "$PM_FILE" } clean_postmount() { $DEBUG && debug "clean_postmount" if $EXT_DRIVE && [ -e "$PM_FILE" ]; then if [ "$(/bin/grep -Fv "$SC_NAME" "$PM_FILE"|/bin/sed '/^[[:space:]]*$/d')" ]; then /bin/sed -i "/$SC_NAME/d" "$PM_FILE" [ $VERBOSE ] && echo "- 'post-mount.sh' has some other code; removed only our code." else /bin/rm -f "$PM_FILE" 2>/dev/null [ $VERBOSE ] && echo "- 'post-mount.sh' had no other code; removed it." fi fi } # SYMLINK: /usr/bin/SELF ###################### check_path() { $DEBUG && debug "check_path" command -v "$SC_NAME"; return $? } >/dev/null set_path() { $DEBUG && debug "set_path" [ -e "/usr/bin/$SC_NAME" ] || /bin/ln -s "$SC_NICEPATH" "/usr/bin/$SC_NAME" } clean_path() { $DEBUG && debug "clean_path" if [ -e "/usr/bin/$SC_NAME" ]; then /bin/rm -f "/usr/bin/$SC_NAME" 2>/dev/null [ $VERBOSE ] && echo "- '/usr/bin' symlink was removed." fi } # CONFIG: .../bolemo/etc/config/aegis ######### check_conf() { $DEBUG && debug "check_conf" [ -d "$ROOT_DIR/etc/config" ] && sc_conf get && sc_conf get wan && sc_conf get tun && sc_conf get log return $? } >/dev/null set_conf() { $DEBUG && debug "set_conf" [ -d "$ROOT_DIR/etc/config" ] || /bin/mkdir -p "$ROOT_DIR/etc/config" 2>/dev/null uci -qc $ROOT_DIR/etc/config import $SC_ABR << EOF package $SC_ABR config net-iface 'wan' config net-iface 'tun' config log 'log' EOF sc_conf commit } clean_conf() { $DEBUG && debug "clean_conf" /bin/rm -f "$ROOT_DIR/etc/config/$SC_ABR" 2>/dev/null [ $VERBOSE ] && echo "- '$SC_NAME' configuration file was removed." } ############################################### # # FUNCTIONS DEPENDING ON BOLEMO GIT REPO # ############################################### # --------------------------------------------- : ENV START # --------------------------------------------- BOLEMO_GIT_REPO='https://raw.githubusercontent.com/bolemo' SC_BASE_REPO="$BOLEMO_GIT_REPO/$SC_NAME" SC_MAIN_REPO="$SC_BASE_REPO/master" REPO="$SC_MAIN_REPO" # can be overriden to change repo last_avail_version() { $DEBUG && debug "last_avail_version" VERSION_URL="$REPO/version" /usr/bin/wget -qO- --no-check-certificate "$VERSION_URL" } # --------------------------------------------- : ENV STOP # --------------------------------------------- _dlinfo() { # to know how many people are downloading this script TITLE="$1" IP="$(/usr/bin/curl --interface $WAN_IF 'ifconfig.me/ip')" REF1="$(cat /module_name)"; $EXT_DRIVE && REF2=ext || REF2=int /usr/bin/curl -H 'Content-Type: application/json' -H "Authorization: Bearer 1a3mmidk3rg2j1xv6t82ak65up1yht5dambypyh1ze7xhbw7941r" -X POST "https://aegis.goatcounter.com/api/v0/count" \ --data '{"no_sessions": true, "hits": [{"path": "/upgrade/'$TITLE'", "title": "'$TITLE'", "ip": "'$IP'", "ref": "'$REF1/$REF2'"}]}' } >/dev/null 2>&1 _download() { # $1=URL, $2=DEST, $3=OPTS echo -ne "\033[35m" if ! /usr/bin/wget -qO "$2" $3 --show-progress --no-check-certificate "$1"; then echo -ne "\033[0m" /bin/rm -f "$2" _warn "Wget error code $?! Could not download $1" 1 fi echo -ne "\033[0m" } do_upgrade() { $DEBUG && debug "do_upgrade" _dlinfo "$UPGRADE_VER" & echo "- Downloading:" DL_PATH="/tmp/$SC_NAME.dl" _download "$UPGRADE_URL" "$DL_PATH" "--no-cache" strip_sh_file "$DL_PATH" /bin/mv "$DL_PATH" "$SC_NICEPATH" /bin/chmod +x "$SC_NICEPATH" echo -e "\033[0m- Script installed to $SC_NICEPATH" check_web && install_web _exit 0 } _upgrade() { $DEBUG && debug "_upgrade" UPGRADE_URL="$REPO/$SC_NAME"; UPGRADE_VER="$(last_avail_version)" do_upgrade } upgrade() { $DEBUG && debug "upgrade" echo -e "\033[1;36mUpgrading:\033[0m" echo "- version installed: $SC_VERS" echo -ne "- checking latest available version...\r" SC_LAST_VERS="$(last_avail_version)" if [ "$SC_LAST_VERS" ]; then if [ "$SC_VERS" = "$SC_LAST_VERS" ]; then echo "- you have already the latest version: $SC_VERS " _ASK="? do you want to reapply it (y/n)?" else VERS_ARRAY="$(echo -e "$SC_VERS\n$SC_LAST_VERS")"; SORT_ARRAY="$(echo "$VERS_ARRAY"|/usr/bin/awk -F. '{o=$0;if(!gsub(/b/,".0")){$0=$0".999"};a[sprintf("%d%03d%03d%03d\n",$1,$2,$3,$4)]=o;} END {for(i in a){printf("%d:%s\n",i,a[i])|"/usr/bin/sort -n|/usr/bin/cut -d: -f2"}}')" if [ "$VERS_ARRAY" = "$SORT_ARRAY" ]; then echo "- new version available: $SC_LAST_VERS " _ASK="? do you want to upgrade from $SC_VERS to $SC_LAST_VERS (y/n)?" else echo -e "\033[35m- this version is higher than than the one available: $SC_LAST_VERS!\033[0m " _ASK="? do you want to downgrade from $SC_VERS to $SC_LAST_VERS anyway (y/n)?" fi fi else _warn "Could not check what is the latest version online!" 1; fi UPGRADE_URL="$REPO/$SC_NAME" UPGRADE_VER="$SC_LAST_VERS" echo -n "$_ASK " case "$(i=0;while [ $i -lt 2 ];do i=$((i+1));read -p '' YN /dev/null [ $VERBOSE ] && echo -e "- default list was downloaded." fi } ############################################### # # WEB COMPANION RELATED FUNCTIONS # ############################################### WEB_NAME='Web Companion' check_web() { $DEBUG && debug "check_web" [ -L "/www/bolemo" ] || return 1 [ -e "/www/bolemo/aegis.htm" ] || return 1 [ -x "/www/bolemo/cgi-bin/aegis_web.cgi" ] || return 1 return 0 } install_web() { $DEBUG && debug "install_web" [ -d "$WWW_PATH" ] || /bin/mkdir "$WWW_PATH" 2>/dev/null [ -d "$WWW_PATH/cgi-bin" ] || mkdir "$WWW_PATH/cgi-bin" [ -z "$UPGRADE_URL" ] && UPGRADE_URL="$REPO/$SC_NAME" echo "- downloading $WEB_NAME:" DL_PATH="/tmp/$SC_NAME.dl" _download "${UPGRADE_URL}.htm" "$DL_PATH" "--no-cache" /bin/mv "$DL_PATH" "$WWW_PATH/$SC_NAME.htm" echo -e "\033[0m- $WEB_NAME htm file installed to $WWW_PATH/$SC_NAME.htm" _download "${UPGRADE_URL}_web.cgi" "$DL_PATH" "$_PROG" strip_sh_file "$DL_PATH" /bin/mv "$DL_PATH" "$WWW_PATH/cgi-bin/${SC_NAME}_web.cgi" /bin/chmod +x "$WWW_PATH/cgi-bin/${SC_NAME}_web.cgi" eval "$WWW_PATH/cgi-bin/${SC_NAME}_web.cgi postinstall" # Let the script run its own install needs echo -e "\033[0m- $WEB_NAME cgi file installed to $WWW_PATH/cgi-bin/${SC_NAME}_web.cgi" if ! check_web; then /bin/rm -f "/www/bolemo" 2>/dev/null /bin/ln -sfn "$WWW_PATH" '/www/bolemo' 2>/dev/null echo "- $WEB_NAME paths were repaired." fi _exit 0 } clean_web() { $DEBUG && debug "clean_web" /bin/rm -f "$WWW_PATH/$SC_NAME.htm" eval "$WWW_PATH/cgi-bin/${SC_NAME}_web.cgi uninstall" /bin/rm -f "$WWW_PATH/cgi-bin/${SC_NAME}_web.cgi" [ $VERBOSE ] && echo "- $WEB_NAME was removed." } 2>/dev/null ############################################### # # UTILITY FUNCTIONS # ############################################### strip_sh_file() { /bin/sed -i 's/^[[:space:]]*// ; 1!{/^#/d;s/#[^"\}'\'']*$//;} ; s/[[:space:]]*$// ; /^$/d ; s/ *\([^"'\'']*\)$/ \1/ ; s/^\(\([^"'\'' ]\+ \)*\) \+/\1/' "$1"; } # --------------------------------------------- : ENV START # --------------------------------------------- is_ipv4() { /usr/sbin/ip route get $1; return $?; } >/dev/null 2>>"$STDERR" ip_in_if_inet() { $DEBUG && debug "ip_in_if_inet $*" [ -z "$2" ] && return 1 _INET="$(/bin/mktemp /tmp/$SC_ABR.inet.tmp-XXXXXX)" inet_for_if $2 >"$_INET" [ "$(echo "$1" | $IPR_BIN --common "$_INET" -)" ] && _RET=0 || _RET=1 /bin/rm -rf "$_INET" return $_RET } # --------------------------------------------- : ENV STOP # --------------------------------------------- ############################################### # # INIT FUNCTIONS # script init & shield init # ############################################### sc_init() { $DEBUG && debug "sc_init" check_path || set_path [ -d "$ROOT_DIR/etc" ] || /bin/mkdir -p "$ROOT_DIR/etc" [ -d "$PETC_DIR" ] || /bin/mkdir -p "$PETC_DIR" check_conf || set_conf [ -d "$WWW_PATH" ] || /bin/mkdir -p "$WWW_PATH" [ -d '/www/bolemo' ] || /bin/ln -sfn "$WWW_PATH" '/www/bolemo' } 2>/dev/null shield_init() { $DEBUG && debug "shield_init" [ $VERBOSE ] && echo -e "\033[1;36mInitializing...\033[0m" [ -e "$SHIELD_LOCK" ] && /bin/rm -f "$SHIELD_LOCK" $IPS_BIN -q -X $IPSET_TMP if check_conf; then [ $VERBOSE ] && echo "- configuration file is set." else _warn "Problem with the configuration system!" 1; fi if check_firewall_start; then [ $VERBOSE ] && echo "- firewall-start.sh is in place and ok." else set_firewall_start if check_firewall_start; then [ $VERBOSE ] && echo "- firewall-start.sh was edited and is now ok." else _warn "Problem with $FWS_FILE!" 1; fi fi if $EXT_DRIVE; then [ $VERBOSE ] && echo "- $SC_NAME is installed on external drive." if check_postmount; then [ $VERBOSE ] && echo "- post-mount.sh is in place and ok." else set_postmount if check_postmount; then [ $VERBOSE ] && echo "- post-mount.sh was edited and is now ok." else _warn "Problem with $PM_FILE!" 1; fi fi else [ $VERBOSE ] && echo "- $SC_NAME is installed on internal drive." fi } ############################################### # # FUNCTIONS FOR SCRIPT CMD ARGUMENTS # ############################################### print_log() { $DEBUG && debug "print_log $*" _UPT=$(/usr/bin/cut -d. -f1 /proc/uptime) _logd_status || echo -e "\033[35mLogging is disabled!\033[0m" echo -e "\033[1;36mLog:\033[0m" case "$1" in '') _TAIL=100; _LSCI=0 ;; 0) _TAIL=100; _LSCI="${_UPT}000" ;; *) _TAIL=$1 _LSCI=0 ;; esac _LSC=/tmp/aegis_lsc; echo "$_LSCI">"$_LSC"; trap "/bin/rm -f '$_LSC' >/dev/null 2>&1; exit" INT TERM _BT=$(( $(/bin/date +%s) - _UPT )) _RSIZE=$(wc -l <$LOG_FILE) $DEBUG && debug "UPT:$_UPT BT:$_BT TAIL:$_TAIL LSCI:$_LSCI LSC(I):$(/bin/cat "$_LSC") RSIZE:$_RSIZE" [ -d /tmp/netscan ] || mkdir /tmp/netscan; touch /tmp/netscan/attach_device # TEMP FIX UNTIL WE CAN CALL devscan directly if [ "$(cat /module_name)" = "RBR50" ] ; then _NSDEVCMD='BEGIN{RS=\"-----device:[[:digit:]]+-----\";FS=\"\\n\"}NR==1{next}$2==\""ip"\"{print $8;exit}' else _NSDEVCMD='$1==\""ip"\"{print $3;exit}' fi while :; do while /usr/bin/awk -F: ' function namefromip(ip){ nm="";cmd="/usr/bin/awk '"'$_NSDEVCMD'"' /tmp/netscan/attach_device";cmd|getline nm;close(cmd); if (!nm) {cmd="/usr/bin/awk '"'"'$1==\""ip"\"{print $NF;exit}'"'"' /tmp/dhcpd_hostlist /tmp/hosts";cmd|getline nm;close(cmd)} if (nm) {nm=nm"("ip")"} else {nm=ip} return nm} function protoname(proto){return (proto~/^[0-9]+$/)?"[protocol "proto"]":proto} function getval(n){i=index(l[c]," "n"=");if(i==0)return;str=substr(l[c],i+length(n)+2);i=index(str," ");str=substr(str,0,i-1);return str} function floored(a){return (a<0)?0:a} $1$2>0'$(/bin/cat "$_LSC")'{ts[++b]=$1;l[b]=$0} END {c=floored(b-'$_TAIL');while (c++"'$_LSC'"}'; do [ 0$_LSCI -eq 0 ] && break 2; _ASIZE=$(wc -l <$LOG_FILE); if [ 0$_ASIZE -ge 0$_RSIZE ]; then _RSIZE=$_ASIZE; else _RSIZE=$_ASIZE; break; fi sleep 1 done <$LOG_FILE; done /bin/rm -f $_LSC >/dev/null 2>&1 } shield_up() { $DEBUG && debug "shield_up" sc_conf set up=1; sc_conf commit shield_init [ $VERBOSE ] && echo -e "\033[1;36mUprearing $SC_NAME shield...\033[0m" if [ "$1" ]; then [ -r "$ALL_BL_FILE" ] || _warn "$ALL_BL_FILE not readable!" 1 [ $VERBOSE ] && echo "- directives will be (re)loaded into $SC_NAME shield." _FORCE_NS_RELOAD=1 fi sc_conf get log.enabled >/dev/null && [ $VERBOSE ] && echo "- enabling logging." if [ "$2" ]; then [ $VERBOSE ] && echo -e "- restarting firewall with $SC_NAME shield.\033[0m" /usr/sbin/net-wall restart > /dev/null else shield_uprear "$INFO_FROM_SC" $_FORCE_NS_RELOAD fi [ $VERBOSE ] && echo "- Done." } shield_down() { $DEBUG && debug "shield_down" [ $VERBOSE ] && echo -e "\033[1;36mWithdrawing shield...\033[0m" sc_conf delete up; sc_conf commit /bin/rm -f "$INFO_FILE" /usr/sbin/net-wall restart > /dev/null; [ $VERBOSE ] && echo "- built-in firewall restarted." _logd_stop; [ $VERBOSE ] && echo "- made sure the log daemon is off." clean_ipset && [ $VERBOSE ] && echo "- cleaned ipsets." [ $VERBOSE ] && echo "- shield is down." } clean() { $DEBUG && debug "clean $RM_CONF|$RM_SYMLINK|$RM_WEB" [ $VERBOSE ] && echo -e "\033[1;36mUnsetting...\033[0m" clean_firewall_start clean_postmount if check_conf; then [ $RM_CONF ] && clean_conf || { sc_conf delete up; sc_conf commit; }; fi [ $RM_SYMLINK ] && check_path && clean_path [ $RM_WEB ] && check_web && clean_web /bin/rm -f "$INFO_FILE" /usr/sbin/net-wall restart > /dev/null; [ $VERBOSE ] && echo "- built-in firewall restarted." _logd_stop && [ $VERBOSE ] && echo "- made sure the log daemon is off." [ $RM_LOG ] && /bin/rm -f $LOG_FILE 2>/dev/null && [ $VERBOSE ] && echo "- removed log file." clean_ipset && [ $VERBOSE ] && echo "- cleaned ipsets." [ -e "$PETC_DIR" ] && /bin/rm -rf "$PETC_DIR" && [ $VERBOSE ] && echo "- removed directives cache." [ -e "$SHIELD_LOCK" ] && /bin/rm -f "$SHIELD_LOCK" && [ $VERBOSE ] && echo "- removed temporary files." echo "- done." } update_iplist() { $DEBUG && debug "update_iplist $*" [ $VERBOSE ] && echo -e "\033[1;36mGenerating directives file from sources and custom lists...\033[0m" [ -s "$SRC_LIST" ] || get_def_srclst # change to -e when ready to deal with empty sources file TMP_DIR="$(/bin/mktemp -d /tmp/${SC_ABR}-tmp-XXXXXX)" trap "/bin/rm -rf "$TMP_DIR" >/dev/null 2>&1; exit" INT TERM EXIT if [ "$1" ]; then # $1 set means using cache [ $VERBOSE ] && echo "- using cached sources global blocking directives (offline)." if [ -e "$SRC_BL_CACHE" ]; then /bin/cp -f "$SRC_BL_CACHE" "$TMP_DIR/src.bl" else _warn "blocklist sources cache is empty!" 1; fi elif [ -s "$SRC_LIST" ]; then :>"$TMP_DIR/src.bl" # Process each source url [ $VERBOSE ] && echo "- downloading global blocking lists defined in $SRC_LIST" [ $VERBOSE ] && WGET_OPTS='-qO- --show-progress --no-check-certificate' || WGET_OPTS='-qO- --no-check-certificate' _NBOK=0; _TOT=0; /bin/grep -v "^[[:space:]*\#]" "$SRC_LIST" | \ { while read -r URL; do _TOT=$((_TOT+1)) [ $VERBOSE ] && echo -e "$_TOT) $URL\033[35m" /usr/bin/wget $WGET_OPTS "$URL" >>"$TMP_DIR/src.bl"; _EC=$? [ $VERBOSE ] && echo -e "\033[0m" [ $_EC -eq 0 ] && _NBOK=$((_NBOK+1)) || _warn "Wget error code $_EC! Could not download $URL" done if [ $_NBOK -eq 0 ]; then _warn "Could not get any list! Exiting!" 1; fi [ $_NBOK -eq $_TOT ] || _warn "Downloaded only $_NBOK / $_TOT list(s)!" } [ $VERBOSE ] && echo "- creating offline cache for global blocking directives from sources..." $IPR_BIN "$TMP_DIR/src.bl" >"$SRC_BL_CACHE" else [ $VERBOSE ] && echo "- sources file $SRC_LIST is empty or does not exists." :>"$TMP_DIR/src.bl" fi # processing common custom blacklist if any if [ -r $CUST_ALL_BL_FILE ]; then [ $VERBOSE ] && echo "- adding global blocking directives from custom blocklist(s)..." _IPR2=$CUST_ALL_BL_FILE else _IPR2=; fi $IPR_BIN "$TMP_DIR/src.bl" $_IPR2 >"$TMP_DIR/all.bl" || :>"$TMP_DIR/all.bl" if [ -s "$TMP_DIR/all.bl" ]; then [ $VERBOSE ] && echo "- generating global blocking directives..." $IPR_BIN --ipset-reduce 20 "$TMP_DIR/all.bl" >"$ALL_BL_FILE" else [ $VERBOSE ] && echo "- no global blocking directives!" /bin/rm -f "$ALL_BL_FILE" 2>/dev/null fi # processing custom common whitelists if any :>"$TMP_DIR/all.wl" $IPR_BIN $CUST_ALL_WL_FILE >"$TMP_DIR/all.raw.wl" 2>/dev/null $IPR_BIN --common "$TMP_DIR/all.bl" "$TMP_DIR/all.raw.wl" >>"$TMP_DIR/all.wl" if [ -s "$TMP_DIR/all.wl" ]; then [ $VERBOSE ] && echo "- generating global bypassing directives from custom whitelist(s)..." $IPR_BIN --ipset-reduce 20 "$TMP_DIR/all.wl" >"$ALL_WL_FILE" else /bin/rm -f "$ALL_WL_FILE" 2>/dev/null fi # --------- WAN SPECIFIC LISTS --------- # processing custom WAN blocklists if any $IPR_BIN $CUST_WAN_BL_FILE --except "$TMP_DIR/all.bl" >"$TMP_DIR/wan.bl" 2>/dev/null || :>"$TMP_DIR/wan.bl" if [ -s "$TMP_DIR/wan.bl" ]; then [ $VERBOSE ] && echo "- generating WAN specific blocking directives from custom blocklist(s)..." $IPR_BIN --ipset-reduce 20 "$TMP_DIR/wan.bl" >"$WAN_BL_FILE" else /bin/rm -f "$WAN_BL_FILE" 2>/dev/null fi # processing custom WAN whitelists if any :>"$TMP_DIR/wan.wl" $IPR_BIN $CUST_WAN_WL_FILE >"$TMP_DIR/wan.raw.wl" 2>/dev/null $IPR_BIN --common "$TMP_DIR/wan.bl" "$TMP_DIR/wan.raw.wl" >>"$TMP_DIR/wan.wl" $IPR_BIN --common "$TMP_DIR/all.bl" "$TMP_DIR/wan.raw.wl" >>"$TMP_DIR/wan.wl" $IPR_BIN --common "$TMP_DIR/wan.bl" "$TMP_DIR/all.wl" >>"$TMP_DIR/wan.wl" if [ -s "$TMP_DIR/wan.wl" ]; then [ $VERBOSE ] && echo "- generating WAN specific bypassing directives from custom whitelist(s)..." $IPR_BIN --ipset-reduce 20 "$TMP_DIR/wan.wl" >"$WAN_WL_FILE" else /bin/rm -f "$WAN_WL_FILE" 2>/dev/null fi # --------- VPN SPECIFIC LISTS --------- # processing custom VPN blocklists if any $IPR_BIN $CUST_TUN_BL_FILE --except "$TMP_DIR/all.bl" >"$TMP_DIR/tun.bl" 2>/dev/null || :>"$TMP_DIR/tun.bl" if [ -s "$TMP_DIR/tun.bl" ]; then [ $VERBOSE ] && echo "- generating VPN specific blocking directives from custom blocklist(s)..." $IPR_BIN --ipset-reduce 20 "$TMP_DIR/tun.bl" >"$TUN_BL_FILE" else /bin/rm -f "$TUN_BL_FILE" 2>/dev/null fi # processing custom TUN whitelists if any :>"$TMP_DIR/tun.wl" $IPR_BIN $CUST_TUN_WL_FILE >"$TMP_DIR/tun.raw.wl" 2>/dev/null $IPR_BIN --common "$TMP_DIR/tun.bl" "$TMP_DIR/tun.raw.wl" >>"$TMP_DIR/tun.wl" $IPR_BIN --common "$TMP_DIR/all.bl" "$TMP_DIR/tun.raw.wl" >>"$TMP_DIR/tun.wl" $IPR_BIN --common "$TMP_DIR/tun.bl" "$TMP_DIR/all.wl" >>"$TMP_DIR/tun.wl" if [ -s "$TMP_DIR/tun.wl" ]; then [ $VERBOSE ] && echo "- generating VPN specific bypassing directives from custom whitelist(s)..." $IPR_BIN --ipset-reduce 20 "$TMP_DIR/tun.wl" >"$TUN_WL_FILE" else /bin/rm -f "$TUN_WL_FILE" 2>/dev/null fi /bin/rm -rf "$TMP_DIR" 2>/dev/null trap - INT TERM EXIT } info() { $DEBUG && debug "info" echo -e "\033[1;36mInfo:\033[0m" if [ -r "$SRC_LIST" ] && [ -d $(dirname "$ALL_BL_FILE") ] then echo -n "- $SC_NAME version $SC_VERS is installed "; $EXT_DRIVE && echo 'on external drive.' || echo 'on internal drive.' else echo -e "\033[31m! something is wrong with installation!\033[0m" fi echo -ne "- checking latest available version...\r" SC_LAST_VERS="$(last_avail_version)"; if [ "$SC_LAST_VERS" ]; then echo "- latest available version: $SC_LAST_VERS " else echo -e "\033[31m! could not check what is the latest version online!\033[0m" fi if check_path then echo "- $SC_NAME is in PATH." else echo "- $SC_NAME is not in PATH (you need to use $NICE_PATH)." fi # check iprange binary [ "$IPR_BIN" ] && echo "- iprange is installed: $($IPR_BIN --version | /usr/bin/head -n 1)" || echo -e "\033[31m! iprange is not installed!\033[0m" # check web compagnon check_web && echo "- $WEB_NAME is installed." || echo "- $WEB_NAME is not installed." } test_ip() { # $1: IP to test, ($2: IF) echo -e "\033[1;36mTesting IP $1:\033[0m" if /usr/bin/traceroute -q1 -m1 -w1 -i $WAN_IF $1 38 2>&1 >/dev/null | /bin/grep -qF 'sendto: Operation not permitted' then echo "- IP address $1 is blocked by the router for WAN interface." else echo "- IP address $1 is not blocked by the router for WAN interface." fi if [ "$TUN_IF" ]; then if /usr/bin/traceroute -q1 -m1 -w1 -i $TUN_IF $1 38 2>&1 >/dev/null | /bin/grep -qF 'sendto: Operation not permitted' then echo "- IP address $1 is blocked by the router for VPN tunnel." else echo "- IP address $1 is not blocked by the router for VPN tunnel." fi fi $IPS_BIN -L -n|/bin/grep -F -- "$SC_ABR"|while read _SET; do case "$_SET" in "$IPSET_ALL_BL_NAME") $IPS_BIN -q test $IPSET_ALL_BL_NAME $1 && echo "- IP address $1 is in $SC_NAME global block directives." ;; "$IPSET_ALL_WL_NAME") $IPS_BIN -q test $IPSET_ALL_WL_NAME $1 && echo "- IP address $1 is in $SC_NAME global bypass directives." ;; "$IPSET_WAN_BL_NAME") $IPS_BIN -q test $IPSET_WAN_BL_NAME $1 && echo "- IP address $1 is in $SC_NAME WAN specific block directives." ;; "$IPSET_WAN_WL_NAME") $IPS_BIN -q test $IPSET_WAN_WL_NAME $1 && echo "- IP address $1 is in $SC_NAME WAN specific bypass directives." ;; "$IPSET_TUN_BL_NAME") $IPS_BIN -q test $IPSET_TUN_BL_NAME $1 && echo "- IP address $1 is in $SC_NAME VPN specific block directives." ;; "$IPSET_TUN_WL_NAME") $IPS_BIN -q test $IPSET_TUN_WL_NAME $1 && echo "- IP address $1 is in $SC_NAME VPN specific bypass directives." ;; esac; done ip_in_if_inet $1 $WAN_IF && echo "- IP address $1 is in the WAN network range ($(inet_for_if $WAN_IF))." ip_in_if_inet $1 $TUN_IF && echo "- IP address $1 is in the VPN network range ($(inet_for_if $TUN_IF))." _exit 0 } #---------------------------- _STATUS ---------------------------- # --------------------------------------------- : ENV START # --------------------------------------------- # STATUS VARS CK_PMND=1 CK_PM=3 CK_FWS=4 CK_UNSET=1 CK_SETOK=5 CK_SET=7 CK_SND=8 # SHIELD NOT DOWN CK_NFO=16 CK_UPF=32 # INFO FILE & UP FLAG CK_UPOK=56 # SHIELD UP OK CK_DOK=63 # PROBLEMS (WE MUST USE CK_DPB MASK) CK_DDNA=64 CK_DWIF=128 CK_DWINET=256 CK_DTIF=512 CK_DTINET=1024 CK_DIPT=2048 CK_OIPT=4096 CK_DPB=8191 CK_LOGD=8192 CK_DLOGD=16384 CK_LOG=24576 CK_BLNS=32768 ST_UNSET=1 # . . _ . . x ST_SETPB=8 # . . x . . _ ST_DOWN=2 # . _ . . x . ST_UPPB=16 # . x . . _ . ST_LOGD=4 # _ . . x . . ST_LGDPB=32 # x . . _ . . ST_PB=56 # --------------------------------------------- : ENV EOF # --------------------------------------------- netset_exists() { test -s "$ALL_BL_FILE" && return 0 sc_conf get wan >/dev/null && [ "$WAN_IF" ] && test -s "$WAN_BL_FILE" && return 0 sc_conf get tun >/dev/null && [ "$TUN_IF" ] && test -s "$TUN_BL_FILE" && return 0 return 1 } directive_status() { # $1: IPSET / $2: FILE _NFO=0 _CNT=0 if _cipset_copy_set $1; then _RET=0 # ipset is loaded _CNT=$(_cipset_count_set $1) if [ -r "$2" ]; then if _cipset_diff_set_file $1 $2 then _NFO=$INFO_DIR__SAME # loaded == file else _NFO=$INFO_DIR__DIFF # loaded != file fi else _NFO=$INFO_DIR__KEEP # loaded but no file fi elif [ -r "$2" ]; then _RET=1; _NFO=$INFO_DIR__LOAD # file exists, but not loaded else _RET=1; _NFO=$INFO_DIR__DEST # no file, not loaded fi return $_RET } _status() { $DEBUG && debug "|---> _status" _CK=0 # CHECK SET ENVIRONMENT check_firewall_start && _CK=$((_CK+CK_FWS)) # check firewall-start.sh script if $EXT_DRIVE; then check_postmount && _CK=$((_CK+CK_PM)) # check post-mount.sh script if script on external drive else _CK=$((_CK+CK_PMND)) # post-mount.sh not needed fi # CHECK IF ANY TRACES OF OUR SHIELD IS PRESENT IN THE FIREWALL get_ipt; _IPS="$($IPS_BIN -L -n|/bin/grep -F "$SC_ABR")" [ -z "$_IPT$_IPS" ] || _CK=$((_CK+CK_SND)) # shield not down [ -r "$INFO_FILE" ] && _CK=$((_CK+CK_NFO)) # info file exists sc_conf get up >/dev/null && _CK=$((_CK+CK_UPF)) # shield up flag is on _WAN=$WAN_IF _TUN=$TUN_IF # CHECKING IF WE HAVE BLOCKING DIRECTIVES FILE ONLY IF SHIELD IS AT LEAST NOT DOWN [ $_CK -ge $CK_SND ] && netset_exists && _CK=$((_CK+CK_BLNS)) # CHECKING DIRECTIVES, IPTABLES... ONLY IF SHIELD IS NOT DOWN if [ $((_CK&CK_SND)) -ne 0 ]; then # CHECK DIRECTIVES _DIR=0 _DNA=0 _ABLC=0 _AWLC=0 _WBLC=0 _WWLC=0 _TBLC=0 _TWLC=0 _cipset_init # ALL blocklist directive_status $IPSET_ALL_BL_NAME $ALL_BL_FILE && _DNA=$((_DNA+DNA_ABL)) _DIR=$((_DIR+(_NFO<<(INFO_DIR_ALL+INFO_DIR_BL)))) _ABLC=$_CNT # ALL whitelist directive_status $IPSET_ALL_WL_NAME $ALL_WL_FILE && _DNA=$((_DNA+DNA_AWL)) _DIR=$((_DIR+(_NFO<<(INFO_DIR_ALL+INFO_DIR_WL)))) _AWLC=$_CNT if [ "$_WAN" ]; then # WAN blocklist directive_status $IPSET_WAN_BL_NAME $WAN_BL_FILE && _DNA=$((_DNA+DNA_WBL)) _DIR=$((_DIR+(_NFO<<(INFO_DIR_WAN+INFO_DIR_BL)))) _WBLC=$_CNT # WAN whitelist directive_status $IPSET_WAN_WL_NAME $WAN_WL_FILE && _DNA=$((_DNA+DNA_WWL)) _DIR=$((_DIR+(_NFO<<(INFO_DIR_WAN+INFO_DIR_WL)))) _WWLC=$_CNT if ! sc_conf get wan.no_bypass >/dev/null; then _WINET=$(inet_for_if $_WAN) [ $((_DNA&(DNA_ABL+DNA_WBL))) -ne 0 ] && _cipset_inet_in_bl $_WINET $IPSET_WAN_BL_NAME && _DNA=$((_DNA+DNA_WBW)) fi fi if [ "$_TUN" ]; then # TUN blocklist directive_status $IPSET_TUN_BL_NAME $TUN_BL_FILE && _DNA=$((_DNA+DNA_TBL)) _DIR=$((_DIR+(_NFO<<(INFO_DIR_TUN+INFO_DIR_BL)))) _TBLC=$_CNT # TUN whitelist directive_status $IPSET_TUN_WL_NAME $TUN_WL_FILE && _DNA=$((_DNA+DNA_TWL)) _DIR=$((_DIR+(_NFO<<(INFO_DIR_TUN+INFO_DIR_WL)))) _TWLC=$_CNT if ! sc_conf get tun.no_bypass >/dev/null; then _TINET=$(inet_for_if $_TUN) [ $((_DNA&(DNA_ABL+DNA_TBL))) -ne 0 ] && _cipset_inet_in_bl $_TINET $IPSET_TUN_BL_NAME && _DNA=$((_DNA+DNA_TBW)) fi fi sc_conf get log.enabled >/dev/null && _DNA=$((_DNA+DNA_LOG)) _cipset_end _logd_status && _CK=$((_CK+CK_LOGD)) if [ $((_CK&CK_NFO)) -ne 0 ]; then # we have info file read _ONFO _ODNA _OWAN _OWINET _OTUN _OTINET <"$INFO_FILE" [ $_ODNA -ne $_DNA ] && _CK=$((_CK+CK_DDNA)) [ "$_OWAN" != "$_WAN" ] && _CK=$((_CK+CK_DWIF)) [ $((_DNA+DNA_WBW)) -ne 0 ] && [ "$_OWINET" != "$_WINET" ] && _CK=$((_CK+CK_DWINET)) [ "$_OTUN" != "$_TUN" ] && _CK=$((_CK+CK_DTIF)) [ $((_DNA+DNA_TBW)) -ne 0 ] && [ "$_OTINET" != "$_TINET" ] && _CK=$((_CK+CK_DTINET)) if [ $((_ONFO&INFO_IPT_MASK)) -eq $INFO_IPT_PBM ]; then _CK=$((_CK+CK_OIPT)) else AIPTF=/tmp/aegis_aipt OIPTF=/tmp/aegis_oipt express_ipt_dna "$INFO_FILE" >$OIPTF echo "$_IPT" >$AIPTF ! /usr/bin/diff -q $OIPTF $AIPTF >/dev/null && _CK=$((_CK+CK_DIPT)) /bin/rm -rf $OIPTF; /bin/rm -rf $AIPTF fi if [ $((_ODNA&DNA_LOG)) -ne 0 ]; then [ $((_CK&CK_LOGD)) -eq 0 ] && _CK=$((_CK+CK_DLOGD)) else [ $((_CK&CK_LOGD)) -ne 0 ] && _CK=$((_CK+CK_DLOGD)) fi fi fi [ "$_ONFO" ] || _ONFO=0; [ "$_ODNA" ] || _ODNA=0 $DEBUG && debug "<---| _status [$_CK $_DNA $_DIR $_ABLC $_AWLC $_WBLC $_WWLC $_TBLC $_TWLC '$_WAN' '$_TUN' '$_WINET' '$_TINET' $_ONFO $_ODNA '$_OWAN' '$_OWINET' '$_OTUN' '$_OTINET']" } 2>>"$STDERR" status_term() { $DEBUG && debug "status_term" _status _OFROM=$((_ONFO&INFO_FROM_MASK)) _ODIR=$(((_ONFO>>INFO_DIR_SHIFT)&INFO_DIR_MASK)) _OIPT=$(((_ONFO>>INFO_IPT_SHIFT)&INFO_IPT_MASK)) _OLOGD=$(((_ONFO>>INFO_LOGD_SHIFT)&INFO_LOGD_MASK)) _RETVAL=0 if [ $((_CK&CK_SET)) -le $CK_UNSET ]; then _RETVAL=$ST_UNSET elif [ $((_CK&CK_SET)) -lt $CK_SETOK ]; then _RETVAL=$ST_SETPB fi [ $((_CK&CK_SND)) -eq 0 ] && _RETVAL=$((_RETVAL+ST_DOWN)) if [ $_CK -le $CK_SET ]; then : # Ok elif [ $((_CK&CK_DPB)) -lt $CK_UPOK ]; then _RETVAL=$((_RETVAL+ST_UPPB)) elif [ $((_CK&CK_DPB)) -gt $CK_DOK ]; then _RETVAL=$((_RETVAL+ST_UPPB)) fi if [ $((_CK&CK_DPB)) -ge $CK_SND ]; then # creating up status info string _STRBLC="global: $_ABLC" _STRWLC="global: $_AWLC" if [ "$_OWAN" ]; then _UPSTR="WAN interface ($_OWAN)" _STRBLC="$_STRBLC, WAN only: $_WBLC" _STRWLC="$_STRWLC, WAN only: $_WWLC"; fi if [ "$_OTUN" ]; then [ "$_UPSTR" ] && _UPSTR="$_UPSTR and VPN tunnel ($_OTUN)" || _UPSTR="VPN tunnel ($_OTUN)" _STRBLC="$_STRBLC, VPN only: $_TBLC" _STRWLC="$_STRWLC, VPN only: $_TWLC" fi _UPSTR=" for: $_UPSTR.\n- blocking a total of $((_ABLC+_WBLC+_TBLC)) IP addresses ($_STRBLC).\n- bypassing $((_AWLC+_WWLC+_TWLC)) IP addresses ($_STRWLC)" fi if [ $((_CK&CK_LOG)) -ge $CK_DLOGD ]; then _RETVAL=$((_RETVAL+ST_LGDPB)) elif [ $((_CK&CK_LOG)) -ge $CK_LOGD ]; then _RETVAL=$((_RETVAL+ST_LOGD)) fi if [ $((_RETVAL&ST_PB)) -ne 0 ]; then # we have errors ---------------------- echo -e '\033[1;31mProblems:' [ $((_CK&CK_FWS)) -eq 0 ] && echo "- set: firewall-start.sh is not set for $SC_NAME!" [ $((_CK&CK_PM)) -eq $CK_PMND ] && echo "- set: post-mount.sh is not set for $SC_NAME!" if [ $((_CK&CK_SND)) -ne 0 ]; then [ $((_CK&CK_NFO)) -eq 0 ] && echo "- status file is missing!" [ $((_CK&CK_UPF)) -eq 0 ] && echo "- shield should be down, but is not!" else [ $((_CK&CK_NFO)) -ne 0 ] && echo "- shield is down, but status file exists!" [ $((_CK&CK_UPF)) -ne 0 ] && echo "- shield was upreared, but is not up!" fi [ $((_CK&CK_BLNS)) -eq 0 ] && echo "- directives: there are no blocking directives!" if [ $((_CK&CK_DDNA)) -ne 0 ]; then _parse_dir() { case "$(($1&INFO_DIR__MASK))" in "$INFO_DIR__DIFF") echo "- directives: $2 changed since $SC_NAME was upreared!";; # loaded != file "$INFO_DIR__KEEP") echo "- directives: $2 is missing (but loaded in ipset)!";; # loaded but no file "$INFO_DIR__LOAD") echo "- directives: $2 was created after $SC_NAME was upreared!";; # file exists, but not loaded esac; } _parse_dir $((_DIR>>(INFO_DIR_ALL+INFO_DIR_BL))) 'global block list' _parse_dir $((_DIR>>(INFO_DIR_WAN+INFO_DIR_BL))) 'WAN specific block list' _parse_dir $((_DIR>>(INFO_DIR_TUN+INFO_DIR_BL))) 'VPN specific block list' _parse_dir $((_DIR>>(INFO_DIR_ALL+INFO_DIR_WL))) 'global bypass list' _parse_dir $((_DIR>>(INFO_DIR_WAN+INFO_DIR_WL))) 'WAN specific bypass list' _parse_dir $((_DIR>>(INFO_DIR_TUN+INFO_DIR_WL))) 'VPN specific bypass list' fi [ $((_CK&CK_DWIF)) -ne 0 ] && echo "- WAN: interface changed from '$_OWAN' to '$WAN_IF' since $SC_NAME was upreared!" [ $((_CK&CK_DWINET)) -ne 0 ] && echo "- WAN: interface subnet range changed from $_OWINET to $_WINET since $SC_NAME was upreared!" [ $((_CK&CK_DTIF)) -ne 0 ] && echo "- VPN: tunnel changed from '$_OTUN' to '$TUN_IF' since $SC_NAME was upreared!" [ $((_CK&CK_DTINET)) -ne 0 ] && echo "- VPN: tunnel subnet range changed from $_OTINET to $_TINET since $SC_NAME was upreared!" [ $((_CK&CK_OIPT)) -ne 0 ] && echo "- iptables: $SC_NAME rules were UNSUCCESSFULLY (re)set during last uprear!" [ $((_CK&CK_DIPT)) -ne 0 ] && echo "- iptables: current $SC_NAME rules were modified since last uprear!" if [ $((_CK&CK_LOG)) -eq $CK_LOG ]; then echo "- logd: the log daemon is running but was not started from the shield!" elif [ $((_CK&CK_DLOGD)) -ne 0 ]; then echo "- logd: log daemon was started but is not running!" fi echo -ne '\033[0m' fi if [ -z "$VERBOSE" ]; then # basic status ---------------------- echo -e '\033[1;36mStatus:\033[0m' if [ $((_RETVAL&ST_UNSET)) -ne 0 ]; then echo "- shield is unset." elif [ $((_RETVAL&ST_DOWN)) -ne 0 ]; then echo -e "- shield is \033[1;35mdown\033[0m." else echo -e "- shield is \033[1;32mup\033[0m$_UPSTR." fi case $((_CK&CK_LOG)) in 0) echo -e "- logging is \033[1;35mdisabled\033[0m.";; $CK_LOGD) echo -e "- logging is \033[1;32menabled\033[0m.";; *) echo -e "! logging is \033[1;31mdefective\033[0m!";; esac _exit $_RETVAL fi echo -e '\033[1;36mSetting status:\033[0m' [ $((_CK&CK_FWS)) -ne 0 ] && echo "- firewall-start.sh is set for $SC_NAME." case $((_CK&CK_PM)) in $CK_PM) echo "- post-mount.sh is set for $SC_NAME." ;; $CK_PMND) echo "- ignoring post-mount.sh ($SC_NAME is on internal memory)." ;; esac echo -e '\033[1;36mShield status:\033[0m' if [ $((_RETVAL&ST_UNSET)) -ne 0 ]; then echo "- shield is unset." elif [ $((_RETVAL&ST_DOWN)) -ne 0 ]; then echo -e "- shield is \033[1;35mdown\033[0m." else echo -e "- shield is \033[1;32mup\033[0m$_UPSTR." fi case $((_CK&CK_LOG)) in 0) echo -e "- logging is \033[1;35mdisabled\033[0m.";; $CK_LOGD) echo -e "- logging is \033[1;32menabled\033[0m.";; *) echo -e "! logging is \033[1;31mdefective\033[0m!";; esac echo -e '\033[1;36mDirectives generation times:\033[0m' _gentimeforlist() { [ -e "$1" ] && echo "- $2: $(/bin/date +'%Y-%m-%d %X' -r "$1")"; } echo "- actual router time: $(/bin/date +'%Y-%m-%d %X')" [ -r "$SRC_BL_CACHE" ] && echo "- sources cache list latest update: $(/bin/date +'%Y-%m-%d %X' -r "$SRC_BL_CACHE")" _gentimeforlist "$ALL_BL_FILE" "global block list" _gentimeforlist "$WAN_BL_FILE" "WAN specific block list" _gentimeforlist "$TUN_BL_FILE" "VPN specific block list" _gentimeforlist "$ALL_WL_FILE" "global bypass list" _gentimeforlist "$WAN_WL_FILE" "WAN specific bypass list" _gentimeforlist "$TUN_WL_FILE" "VPN specific bypass list" if [ -r "$INFO_FILE" ]; then echo -e '\033[1;36mUprear information:\033[0m' case "$_OFROM" in $INFO_FROM_SC) FROM="$SC_NAME script" ;; $INFO_FROM_PM) FROM="post-mount.sh" ;; $INFO_FROM_FWS) FROM="firewall-start.sh" ;; esac echo "- shield was upreared from: $FROM @ $(/bin/date +'%Y-%m-%d %X' -r $INFO_FILE)" _parse_odir() { case "$(($1&INFO_DIR__MASK))" in "$INFO_DIR__SAME") echo "- ipset: latest $2 was already loaded and conform with directives.";; "$INFO_DIR__KEEP") echo "! ipset: loaded $2 was kept since no directives file could be found for it!";; "$INFO_DIR__LOAD") echo "- ipset: $2 was loaded from file directives.";; "$INFO_DIR__SWAP") echo "- ipset: $2 was reloaded from directives.";; "$INFO_DIR__DEST") echo "- ipset: $2 was unloaded.";; "$INFO_DIR__MISS") :;; esac; } _parse_odir $((_ODIR>>(INFO_DIR_ALL+INFO_DIR_BL))) 'global block list' _parse_odir $((_ODIR>>(INFO_DIR_WAN+INFO_DIR_BL))) 'WAN specific block list' _parse_odir $((_ODIR>>(INFO_DIR_TUN+INFO_DIR_BL))) 'VPN specific block list' _parse_odir $((_ODIR>>(INFO_DIR_ALL+INFO_DIR_WL))) 'global bypass list' _parse_odir $((_ODIR>>(INFO_DIR_WAN+INFO_DIR_WL))) 'WAN specific bypass list' _parse_odir $((_ODIR>>(INFO_DIR_TUN+INFO_DIR_WL))) 'VPN specific bypass list' if [ $((_OIPT&INFO_IPT_KEEP)) -ne 0 ]; then echo -n "- iptables: rules were already set with:" elif [ $((_OIPT&INFO_IPT_RUN)) -ne 0 ]; then echo -n "- iptables: rules were (re)set with:" else echo -n "- iptables: rules were UNSUCCESSFULLY (re)set with:" fi # _ODNA _AND='' [ $((_ODNA&DNA_ABL)) -ne 0 ] && echo -n " global block" && _AND=',' [ $((_ODNA&DNA_AWL)) -ne 0 ] && echo -n "$_AND global bypass" && _AND=',' [ $((_ODNA&DNA_WBW)) -ne 0 ] && echo -n "$_AND WAN network bypass" && _AND=',' [ $((_ODNA&DNA_WBL)) -ne 0 ] && echo -n "$_AND WAN block" && _AND=',' [ $((_ODNA&DNA_WWL)) -ne 0 ] && echo -n "$_AND WAN bypass" && _AND=',' [ $((_ODNA&DNA_TBW)) -ne 0 ] && echo -n "$_AND VPN network bypass" && _AND=',' [ $((_ODNA&DNA_TBL)) -ne 0 ] && echo -n "$_AND VPN block" && _AND=',' [ $((_ODNA&DNA_TWL)) -ne 0 ] && echo -n "$_AND VPN bypass" [ $((_ODNA&DNA_LOG)) -ne 0 ] && echo -n "$_AND logging" echo '.' # _OLOGD case "$_OLOGD" in $INFO_LOGD_KEEP_OFF) echo '- log daemon: was already off.';; $INFO_LOGD_KEEP_ON) echo '- log daemon: was already on.';; $INFO_LOGD_STOPPED) echo '- log daemon: was turned off.';; $INFO_LOGD_STARTED) echo '- log daemon: was turned on.';; esac fi [ 0$VERBOSE -lt 2 ] && _exit $_RETVAL echo -e "\033[1;36miptables $SC_NAME rules:\033[0m" [ -z "$_IPT" ] && echo "- no $SC_NAME rules are set." || echo "$_IPT"|/bin/sed 's/^/- iptables /' echo -e "\033[1;36mipset $SC_NAME sets:\033[0m" [ -z "$_IPS" ] && _IPS="$($IPS_BIN -L -n|/bin/grep -F -- "$SC_ABR")" if [ "$_IPS" ]; then echo "$_IPS"|while read _SET; do case "$_SET" in "$IPSET_ALL_BL_NAME") _NAME='general block directives' ;; "$IPSET_ALL_WL_NAME") _NAME='general bypass directives' ;; "$IPSET_WAN_BL_NAME") _NAME='WAN specific block directives' ;; "$IPSET_WAN_WL_NAME") _NAME='WAN specific bypass directives' ;; "$IPSET_TUN_BL_NAME") _NAME='VPN specific block directives' ;; "$IPSET_TUN_WL_NAME") _NAME='VPN specific bypass directives' ;; *) _NAME="'$_SET'" ;; esac echo -e "\033[1;34m- $_NAME:\033[0m" $IPS_BIN -L -t $_SET|/bin/sed 's/^/ /' done; else echo "- no $SC_NAME ipsets are set." fi _exit $_RETVAL } status_raw() { $DEBUG && debug "status_raw" _status; echo "$_CK $_DNA $_DIR $_ABLC $_AWLC $_WBLC $_WWLC $_TBLC $_TWLC '$_WAN' '$_TUN' '$_WINET' '$_TINET' '$_ONFO' '$_ODNA' '$_OWAN' '$_OWINET' '$_OTUN' '$_OTINET'"; _exit 0 # set -- $(_status); _CK=$1 _DNA=$2 _DIR=$3 _ABLC=$4 _AWLC=$5 _WBLC=$6 _WWLC=$7 _TBLC=$8 _TWLC=$9 _WAN=${10} _TUN=${11} _WINET=${12} _TINET=${13} _ONFO=${14} _ODNA=${15} _OWAN=${16} _OWINET=${17} _OTUN=${18} _OTINET=${19} } #---------------------------- END _STATUS ---------------------------- print_help() { $DEBUG && debug "print_help" echo -e "\033[1;36m$SC_NAME $SC_VERS\033[0m"' '"Usage: \033[1m$SC_NAME \033[35mCOMMAND \033[36m[OPTION(S)]\033[0m"' '"\033[7mCOMMANDS (only one) and their specific options:\033[0m"' '"\033[1;35mup\033[0m - (re)starts $SC_NAME shield protection"' '" \033[1;36m-net-wall\033[0m + by restarting the internal firewall"' '" \033[1;36m-refresh\033[0m + with updated shield directives"' '" \033[1;36m-log-enable\033[0m + with logging enabled"' '" \033[1;36m-log-disable\033[0m + with logging disabled"' '" \033[1;36m-wan-no-bypass\033[0m + without WAN network range bypass"' '" \033[1;36m-vpn-no-bypass\033[0m + without VPN network range bypass"' '" \033[1;35mdown\033[0m - stops $SC_NAME shield protection"' '" \033[1;35mrefresh\033[0m - updates shield directives from sources and custom lists\033[0m"' '" \033[1;36m-custom-only\033[0m + will refresh directives only from custom lists (using offline cache for sources)"' '" \033[1;35mlog -enable\033[0m - enables logging"' '" \033[1;35mlog -disable\033[0m - disables logging"' '" \033[1;35mlog -show\033[0m - displays the log report"' '" \033[1;36m-lines=\033[0mN + will display N last lines (N being the number of lines to show)"' '" \033[1;35mlog -live\033[0m - displays the log report live (CTRL-C to exit)"' '" \033[1;35mlog -get-history\033[0m - show the history size for the log file $LOG_FILE"' '" \033[1;35mlog -set-history=\033[0mN - sets the history size to N records for the log file $LOG_FILE"' '" \033[1;35munset\033[0m - stops and unsets $SC_NAME shield"' '" \033[1;36m-rm-config\033[0m + and removes $SC_NAME configuration file"' '" \033[1;36m-rm-symlink\033[0m + and removes the symlink /usr/bin/$SC_NAME"' '" \033[1;36m-rm-web\033[0m + and removes $WEB_NAME"' '" \033[1;36m-rm-log\033[0m + and removes log file"' '" \033[1;35mhelp\033[0m - displays help (this)"' '" \033[1;35minfo\033[0m - displays info on this script"' '" \033[1;35mstatus\033[0m - displays status"' '" \033[1;35mupgrade\033[0m - downloads and installs latest version"' '" \033[1;35mweb -install\033[0m - downloads and installs $WEB_NAME"' '" \033[1;35mweb -remove\033[0m - removes $WEB_NAME"' '" \033[1;35mtest -ip=\033[0mIP - test if IP is blocked or not by $SC_NAME"' '"\033[7mGENERAL OPTIONS (none, one or more, can be used with any command):\033[0m"' '" \033[1;36m-v\033[0m + verbose mode (level 1)"' '" \033[1;36m-vv\033[0m + verbose mode (level 2)"' '" \033[1;36m-q\033[0m + quiet mode (no output)" } ############################################### # # MAIN ROUTINE # ############################################### if [ $# -eq 0 ]; then _warn "No parameter!"; print_help; _exit 1; fi [ "$1" = "_pm" ] && [ "$2" ] && _pm # Called from post-mount.sh, go to right processing... ARGS=" $* " $DEBUG && debug "main routing with args: $ARGS" PARAM="$(echo "$ARGS" | /bin/sed 's/-[[:alpha:]=]*[[:space:]]*[[:digit:].]*//g')" case $(echo "$PARAM"|/usr/bin/wc -w) in 0) _warn "No parameter!"; print_help; _exit 1 ;; 1) PARAM="$(echo "$PARAM"|/bin/sed 's/ //g')" ;; *) _warn "Too many parameters!"; print_help; _exit 1 ;; esac # Verbosity case $ARGS in *' -q '*) unset VERBOSE ;; *' -v '*) VERBOSE=1 ;; *' -vv '*) VERBOSE=2 ;; *) VERBOSE= ;; esac _refresh_args() { [ -z "${ARGS##* -custom-only *}" ] && RF_OFFLN=1 || RF_OFFLN= } _shield_args() { [ -z "${ARGS##* -log-enable *}" ] && sc_conf set log.enabled=1 [ -z "${ARGS##* -log-disable *}" ] && sc_conf delete log.enabled [ -z "${ARGS##* -wan-no-bypass *}" ] && sc_conf set wan.no_bypass=1 || sc_conf delete wan.no_bypass [ -z "${ARGS##* -vpn-no-bypass *}" ] && sc_conf set tun.no_bypass=1 || sc_conf delete tun.no_bypass [ -z "${ARGS##* -net-wall *}" ] && ST_FW=1 || ST_FW= [ -z "${ARGS##* -refresh *}" ] && ST_US=1 || ST_US= sc_conf commit } _log_args() { case $ARGS in *' -enable '*) sc_conf set log.enabled=1; sc_conf commit; sc_conf get up >/dev/null && { shield_up; status_term; } ;; *' -disable '*) sc_conf delete log.enabled; sc_conf commit; sc_conf get up >/dev/null && { shield_up; status_term; } ;; *' -show '*) [ -z "${ARGS##* -lines=[0-9]*}" ] && _PL=$(echo "$ARGS"|/bin/sed 's/.* -lines=\([[:digit:]]\+\) .*/\1/') || _PL=''; print_log $_PL ;; *' -live '*) print_log 0 ;; *' -get-history '*) sc_conf get log.len ;; *' -set-history='[0-9]*) sc_conf set log.len=$(echo "$ARGS"|/bin/sed 's/.* -set-history=\([[:digit:]]\+\) .*/\1/'); sc_conf commit ;; esac; } _clean_args() { [ -z "${ARGS##* -rm-config *}" ] && RM_CONF=1 || RM_CONF= [ -z "${ARGS##* -rm-symlink *}" ] && RM_SYMLINK=1 || RM_SYMLINK= [ -z "${ARGS##* -rm-web *}" ] && RM_WEB=1 || RM_WEB= [ -z "${ARGS##* -rm-log *}" ] && RM_LOG=1 || RM_LOG= } _repo_args() { [ -z "${ARGS##* -repo=[^ ]* }" ] && REPO="$SC_BASE_REPO/$(echo "$ARGS"|/bin/sed 's/.* -repo=\([^ ]\+\) .*/\1/')" } [ -z ${VERBOSE+x} ] && exec >/dev/null sc_init [ $VERBOSE ] && echo -e "\033[7;31m$SC_NAME $SC_VERS - Verbose mode [level $VERBOSE]\033[0m" case "$PARAM" in 'up') _shield_args; netset_exists || { ST_US=1; [ $VERBOSE ] && echo "- no directives were found! Refresh will be made."; } [ $ST_US ] && update_iplist; shield_up "$ST_US" "$ST_FW"; status_term ;; 'down') shield_down; status_term ;; 'unset') _clean_args; clean; status_term ;; 'refresh') _refresh_args; update_iplist $RF_OFFLN; sc_conf get up >/dev/null && { shield_up 1; status_term; } ;; 'status') status_term ;; 'help') print_help ;; 'info') info ;; 'test') [ -z "${ARGS##* -ip=*}" ] && _IP=$(echo "$ARGS"|/bin/sed 's/.* -ip=\([[:digit:].]\+\) .*/\1/') && is_ipv4 $_IP && test_ip $_IP || _warn "Invalid IP" 1 ;; 'log') _log_args ;; 'upgrade') _repo_args; upgrade ;; 'web') [ -z "${ARGS##* -install *}" ] && install_web; [ -z "${ARGS##* -remove *}" ] && clean_web ;; # calls for outside helpers (html) '_status') status_raw ;; '_up') _shield_args; VERBOSE=1; netset_exists || { ST_US=1; echo "- no directives were found! Refresh will be made."; } [ $ST_US ] && update_iplist; shield_up "$ST_US" 1 ;; '_refresh') _refresh_args; _shield_args; VERBOSE=1; update_iplist $RF_OFFLN; shield_up 1 ;; '_down') VERBOSE=1; shield_down ;; '_unset') VERBOSE=1; clean ;; '_upgrade') _repo_args; _upgrade ;; *) _warn "Unknown Parameter $2!"; print_help; _exit 1 ;; esac _exit 0