MartineauPASTEBIN

IPCamsBlock.sh

Sep 16th, 2017
1,381
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/bin/sh
  2. VER="v1.12"
  3. #======================================================================================== © 2016-2018 Martineau, v1.12
  4. #
  5. # Block unsolicited outbound traffic from the I/P cameras, except for NTP and optional WAN NVR, but still allow viewing via the VPN Servers (and/or WAN Port forwards)
  6. # (Default is via secure VPN servers only viewing)
  7. #
  8. #          IPCamsBlock     [help|-h] | [init [blockntp] [logdrop] [logntp]] | [status] | [del] | [ntplogscan | [logscan ['ip_address']] ]
  9. #                          [ wanip='ip_address[,...]' [ usewanip ] ] [mac] [ mail='mailserver[:port]]
  10. #
  11. #          IPCamsBlock     init
  12. #                          Create the blocking rules (usually called from /jffs/scripts/firewall-start)
  13. #                          (Assumes /jffs/configs/IPGroups exists with valid 'CAMERAS' entry - Uppercase text!)
  14. #                                    e.g. CAMERAS  10.88.8.10, 10.88.8.15-10.88.8.20, 10.88.8.50:10.88.8.55  #Comment
  15. #          IPCamsBlock     init blockntp
  16. #                          Create blocking rules but NTP is also blocked (assumes cameras etc. use LAN NTP server)
  17. #          IPCamsBlock
  18. #                          Show status of the rules in name form e.g. CAM-L-F1812 (unless 'mac' directive was used during 'init')
  19. #          IPCamsBlock     status
  20. #                          Show status of the rules in I/P form e.g. 10.88.8.10 (unless 'mac' directive was used during 'init')
  21. #          IPCamsBlock     del
  22. #                          Delete the blocking rules (NOTE: If CAMERAS list has changed since rules were created,
  23. #                                 then it won't delete non-matching I/Ps!)
  24. #          IPCamsBlock     init logdrop
  25. #                          All DROPs will be logged to Syslog for analysis as to where the cameras are trying to connect to
  26. #          IPCamsBlock     init logntp
  27. #                          All NTP access requests will be logged to Syslog for analysis and displayed as part of status reuest
  28. #          IPCamsBlock     ntplogscan
  29. #                          Scan Syslog for any NTP logged entries - even if 'logntp' is not currently enabled.
  30. #          IPCamsBlock     init wan
  31. #                          Access to cameras will be via VPN and WAN Port Forwards
  32. #          IPCamsBlock     init wanaccept
  33. #                          Access to cameras will be via VPN and WAN Port Forwards and an inbound WAN 'logaccept' rule to Syslog will be created
  34. #          IPCamsBlock     init wanip=123.123.123.123
  35. #                          Access to cameras will be via VPN but LAN devices can access 123.123.123.123 via the WAN (i.e. external NVR site).
  36. #          IPCamsBlock     init wanip=1.2.3.4,9.8.7.6 usewanip
  37. #                          Access to cameras will be via VPN but the specific Cameras can access both 1.2.3.4 and 9.8.7.6 via the WAN
  38. #          IPCamsBlock     init mac
  39. #                          Use the current Camera MAC address rather than the Camera IP (Static DHCP recommended!)
  40. #          IPCamsBlock     init mail=smtp.gmail.com:587
  41. #                          Cameras can send emails to smtp.gmail.com:587
  42. #          IPCamsBlock     logscan
  43. #                          Scan Syslog for any blocking entries for ALL IP Cameras. (NOTE: 'init logdrop' must have been used.)
  44. #          IPCamsBlock     logscan 10.88.8.10
  45. #                          Scan Syslog for any blocking entries for IP Camera 10.88.8.10. (NOTE: 'init logdrop' must have been used.)
  46. #
  47. #
  48. # /jffs/scripts/firewall-start
  49. #      /jffs/scripts/IPCamsBlock.sh init
  50.  
  51. # [URL="https://www.snbforums.com/threads/help-please-need-assistance-stopping-outbound-connections.38086/page-2#post-314785"]IPCamsBlock.sh[/URL]
  52. # [URL="https://www.snbforums.com/threads/help-please-need-assistance-stopping-outbound-connections.38086/page-3#post-314828"]Mini WinSCP tutorial for IPCamsBlock[/URL]
  53.  
  54. #*************************************FUNCTIONS***************************************************************
  55. Say(){
  56.    echo -e $$ $@ | logger -st "($(basename $0))"
  57. }
  58. SayT(){
  59.    echo -e $$ $@ | logger -t "($(basename $0))"
  60. }
  61. # Print between line beginning with'#==' to first blank line inclusive
  62. ShowHelp() {
  63.     awk '/^#==/{f=1} f{print; if (!NF) exit}' $0
  64. }
  65. ANSIColours() {
  66.  
  67.     cRESET="\e[0m";cBLA="\e[30m";cRED="\e[31m";cGRE="\e[32m";cYEL="\e[33m";cBLU="\e[34m";cMAG="\e[35m";cCYA="\e[36m";cGRA="\e[37m"
  68.     cBGRA="\e[90m";cBRED="\e[91m";cBGRE="\e[92m";cBYEL="\e[93m";cBBLU="\e[94m";cBMAG="\e[95m";cBCYA="\e[96m";cBWHT="\e[97m"
  69.     aBOLD="\e[1m";aDIM="\e[2m";aUNDER="\e[4m";aBLINK="\e[5m";aREVERSE="\e[7m"
  70.     cRED_="\e[41m";cGRE_="\e[42m"
  71.  
  72. }
  73. # Function Parse(String delimiter(s) variable_names)
  74. Parse() {
  75.     #
  76.     #   Parse       "Word1,Word2|Word3" ",|" VAR1 VAR2 REST
  77.     #               (Effectivley executes VAR1="Word1";VAR2="Word2";REST="Word3")
  78.  
  79.     local string IFS
  80.  
  81.     TEXT="$1"
  82.     IFS="$2"
  83.     shift 2
  84.     read -r -- "$@" <<EOF
  85. $TEXT
  86. EOF
  87. }
  88. Check_Router_Mode() {
  89.     local OK=1                              # Assume not Router mode
  90.     case "$(nvram get sw_mode)" in
  91.         0) SW_MODE="Unconfigured";;
  92.         1) SW_MODE="Router";OK=0;;
  93.         2) SW_MODE="Repeater";;
  94.         3) SW_MODE="AP";;
  95.         4) SW_MODE="Hotspot";;
  96.         *) SW_MODE="Unknown nvram sw_mode value="$(nvram get sw_mode);;
  97.     esac
  98.     echo $SW_MODE
  99.     return $OK
  100. }
  101. Is_IPv4 () {
  102.         grep -oE '^([0-9]{1,3}\.){3}[0-9]{1,3}$'                    # IPv4 format
  103. }
  104. Firewall(){
  105.  
  106.     $IPT $@ 2>/dev/null
  107.     local RC=$?
  108.     if [ "$RC" -gt 0 ];then             # Report error for "-I" insert actions
  109.         local FIREWALL_ERROR=$RC
  110.         if [ "$1" == "-I" ] || [ "$1" == "-A" ];then
  111.             echo -e "\n\a'"$IPT $@"'"
  112.             $IPT $@
  113.             return 1
  114.         fi
  115.     fi
  116.     return 0
  117. }
  118. ExpandIPRange() {
  119.  
  120.     # '192.168.1.30 192.168.1.50-192.168.1.54' -> '192.168.1.30 192.168.1.50 192.168.1.51 192.168.1.52 192.168.1.53 192.168.1.54'
  121.  
  122.     local IP_LIST=
  123.     local START_RANGE=
  124.     local END_RANGE=
  125.     local NUM=
  126.     local MAX=
  127.  
  128.     local LANIPADDR=`nvram get lan_ipaddr`
  129.     local LAN_PREFIX=${LANIPADDR%.*}                    # 1.2.3.99 -> 1.2.3
  130.  
  131.     for THIS in $@
  132.         do
  133.  
  134.             if [ -n "$(echo "$THIS" | grep -E "^#")" ];then
  135.                 break               # Ignore comment  v1.07
  136.             fi
  137.  
  138.             if [ -n "$(echo $THIS | grep -o "-")" ];then            # v1.11
  139.                 Parse $THIS "-" START_RANGE END_RANGE               # 1.2.3.90-1.2.3.99 -> 1.2.3.90 1.2.3.99
  140.                 local START_PREFIX=${START_RANGE%.*}                # 1.2.3.90 -> 1.2.3
  141.                 local END_PREFIX=${END_RANGE%.*}                    # 1.2.3.99 -> 1.2.3
  142.  
  143.                 if [ "$START_PREFIX" != "$END_PREFIX" ];then        # Restrict range of devices to 254
  144.                     Say "***ERROR*** invalid IP range" $THIS
  145.                     echo -e"\a"
  146.                     exit 99
  147.                 fi
  148.  
  149.                 NUM=${START_RANGE##*.}                              # Extract 4th octet 1.2.3.90 -> 90
  150.                 MAX=${END_RANGE##*.}                                # Extract 4th octet 1.2.3.99 -> 99
  151.                 while [ $NUM -le $MAX ]
  152.                     do
  153.                         IP_LIST=$IP_LIST" "$START_PREFIX"."$NUM
  154.                         NUM=$(($NUM+1))
  155.                     done
  156.             else
  157.                 local THIS_PREFIX=${THIS%.*}
  158.                 if [ "$THIS_PREFIX" != "$LAN_PREFIX" ];then
  159.                     Say "***ERROR '"$THIS"' is not on this LAN '"$LAN_PREFIX".0/24'"
  160.                     echo ""
  161.                     return 1
  162.                 else
  163.                     IP_LIST=$IP_LIST" "$THIS                            # Add to list
  164.                 fi
  165.             fi
  166.  
  167.             shift 1
  168.         done
  169.  
  170.     echo $IP_LIST
  171. }
  172. Convert_TO_IP() {
  173.  
  174.     # Perform a lookup if a hostname (or I/P address) is supplied and is not known to PING
  175.     # NOTE: etc/host.dnsmasq is in format
  176.     #
  177.     #       I/P address    hostname
  178.     #
  179.  
  180.     local USEPATH="/jffs/configs"
  181.  
  182.     if [ -n "$1" ];then                                     # v1.11
  183.  
  184.         if [ -z $2 ];then                                   # Name to IP Address
  185.            local IP_NAME=$(echo $1 | tr '[a-z]' '[A-Z]')
  186.  
  187.            local IP_RANGE=$(ping -c1 -t1 -w1 $IP_NAME 2>&1 | tr -d '():' | awk '/^PING/{print $3}')
  188.  
  189.            # 127.0.53.53 for ANDROID? https://github.com/laravel/valet/issues/115
  190.            if [ -n "$(echo $IP_RANGE | grep -E "^127")" ];then
  191.               local IP_RANGE=
  192.            fi
  193.  
  194.            if [ -z "$IP_RANGE" ];then       # Not PINGable so lookup static
  195.  
  196.               IP_RANGE=$(grep -i "$IP_NAME" /etc/hosts.dnsmasq  | awk '{print $1}')
  197.               #logger -s -t "($(basename $0))" $$ "Lookup '$IP_NAME' in DNSMASQ returned:>$IP_RANGE<"
  198.  
  199.               # If entry not matched in /etc /hosts.dnsmasq see if it exists in our IPGroups lookup file
  200.               #
  201.               #       KEY     I/P address[ {,|-} I/P address]
  202.               #
  203.               if [ -z "$IP_RANGE" ] && [ -f $USEPATH/IPGroups ];then
  204.                  #IP_RANGE=$(grep -i "^$IP_NAME" $USEPATH/IPGroups | awk '{print $2}')
  205.                  IP_RANGE=$(grep -i "^$IP_NAME" $USEPATH/IPGroups | awk '{$1=""; print $0}')
  206.                  #logger -s -t "($(basename $0))" $$ "Lookup '$IP_NAME' in '$USEPATH/IPGroups' returned:>$IP_RANGE<"
  207.               fi
  208.            fi
  209.         else                                                # IP Address to name
  210.             IP_RANGE=$(nslookup $1 | grep "Address" | grep -v localhost | cut -d" " -f4)
  211.         fi
  212.     else
  213.        local IP_RANGE=                                  # Return a default WiFi Client????
  214.        #IP_NAME="Nexus-7"
  215.        #IP_RANGE=`grep -i $IP_NAME /etc/hosts.dnsmasq  | awk '{print $1}'`
  216.        #logger -s -t "($(basename $0))" $$ "DEFAULT '$IP_NAME' lookup returned:>$IP_RANGE<"
  217.     fi
  218.  
  219.     echo $IP_RANGE
  220. }
  221. Hostname_from_IP() {
  222.  
  223.     local HOSTNAMES=
  224.  
  225.     local ITEMS=$@
  226.  
  227.     local STRIP_DOMAIN=0
  228.     if [ -n "$(echo $@ | grep -oE "NODOMAIN")" ];then
  229.         STRIP_DOMAIN=1
  230.         ITEMS=$(echo "$@" | sed 's/NODOMAIN//')
  231.     fi
  232.  
  233.     for IP in $ITEMS
  234.         do
  235.             local HOSTNAME=$(Convert_TO_IP "$IP" "Reverse")
  236.             if [ -n "$HOSTNAME" ];then                  # v1.10
  237.                 if [ $STRIP_DOMAIN -eq 1 ];then
  238.                     local HOSTNAME=${HOSTNAME%%.*}          # Strip domain e.g. 'CAM-W-JPT3815W.Martineau.lan' -> 'CAM-W-JPT3815W'
  239.                 fi
  240.             else
  241.                 local HOSTNAME="N/A"                        # v1.10
  242.             fi
  243.             if [ -z "$HOSTNAMES" ];then
  244.                 local HOSTNAMES=$HOSTNAME                   # v1.10 Eliminate spurious leading space
  245.             else
  246.                 local HOSTNAMES=$HOSTNAMES" "$HOSTNAME
  247.             fi
  248.         done
  249.  
  250.     echo $HOSTNAMES
  251. }
  252. Get_WAN_IF_Name() {
  253.  
  254.     local IF_NAME=$(nvram get wan0_ifname)              # DHCP/Static ?
  255.  
  256.     # Usually this is probably valid for both eth0/ppp0e ?
  257.     if [ "$(nvram get wan0_gw_ifname)" != "$IF_NAME" ];then
  258.         local IF_NAME=$(nvram get wan0_gw_ifname)
  259.     fi
  260.  
  261.     if [ -n "$(nvram get wan0_pppoe_ifname)" ];then
  262.         local IF_NAME="$(nvram get wan0_pppoe_ifname)"      # PPPoE
  263.     fi
  264.  
  265.     echo $IF_NAME
  266.  
  267. }
  268. Chain_exists() {
  269.  
  270.     # Args: {chain_name} [table_name]
  271.  
  272.     local CHAIN="$1"
  273.     shift
  274.  
  275.     [ $# -eq 1 ] && local TABLE="-t $1"
  276.  
  277.     iptables $TABLE -n -L $CHAIN >/dev/null 2>&1
  278.     local RC=$?
  279.     if [ $RC -ne 0 ];then
  280.         echo "N"
  281.         return 1
  282.     else
  283.         echo "Y"
  284.         return 0
  285.     fi
  286. }
  287. Check_SkynetStatus() {
  288.         if [ "$(nvram get wan0_proto)" = "pppoe" ] || [ "$(nvram get wan0_proto)" = "pptp" ] || [ "$(nvram get wan0_proto)" = "l2tp" ]; then
  289.             local iface="ppp0"
  290.         else
  291.             local iface="$(nvram get wan0_ifname)"
  292.         fi
  293.         local skynetloc="$(grep -ow "skynetloc=.* # Skynet" /jffs/scripts/firewall-start 2>/dev/null | grep -vE "^#" | awk '{print $1}' | cut -c 11-)"
  294.         local skynetipset="${skynetloc}/skynet.ipset"
  295.         { [ -f "$skynetipset" ] && ipset -L -n Skynet-Whitelist >/dev/null 2>&1 && iptables -t raw -C PREROUTING -i "$iface" -m set ! --match-set Skynet-Whitelist src -m set --match-set Skynet-Master src -j DROP >/dev/null 2>&1; } ||
  296.         { [ -f "$skynetipset" ] && ipset -L -n Skynet-Whitelist >/dev/null 2>&1 && iptables -t raw -C PREROUTING -i br0 -m set ! --match-set Skynet-Whitelist dst -m set --match-set Skynet-Master dst -j DROP >/dev/null 2>&1 && iptables -t raw -C OUTPUT -m set ! --match-set Skynet-Whitelist dst -m set --match-set Skynet-Master dst -j DROP >/dev/null 2>&1; }
  297. }
  298.  
  299. #======================================Main==================================================================================
  300. Main(){}
  301.  
  302. ANSIColours
  303.  
  304. MYROUTER=$(nvram get computer_name)
  305. FIRMWARE=$(echo $(nvram get buildno) | awk 'BEGIN { FS = "." } {printf("%03d%02d",$1,$2)}')
  306.  
  307. WAN_IF=$(Get_WAN_IF_Name)
  308.  
  309. # Can only run in Router Mode;
  310. if [ "$(Check_Router_Mode)" != "Router" ];then
  311.     echo -e $cBRED"\a\n\n\n\n\t\t\t\t** "$(Check_Router_Mode)" mode is not supported **\t\t\t\t\t\n\n\n"$cRESET
  312.     exit 999
  313. fi
  314.  
  315. # Need assistance!???
  316. if [ "$1" == "help" ] || [ "$1" == "-h" ]; then
  317.     echo -e $cBWHT
  318.     ShowHelp
  319.     echo -e $cRESET
  320.     exit 0
  321. fi
  322.  
  323. echo -e $cBWHT
  324.  
  325. Say $VER "I/P Cameras Firewall blocking...." $@
  326.  
  327. VPNONLY=1                   # Only allow remote viewing via a secure VPN connection
  328. if [ "$(echo $@ | grep -cw "wanaccept")" -eq 1 ];then
  329.     VPNONLY=0
  330. fi
  331.  
  332. IPT="/usr/sbin/iptables"
  333.  
  334. # Check for group names, and expand as necessary
  335. #   e.g. '192.168.1.30,192.168.1.50-192.168.1.54' -> '192.168.1.30 192.168.1.50 192.168.1.51 192.168.1.52 192.168.1.53 192.168.1.54'
  336. if [ -f "/jffs/configs/IPGroups" ];then         # '/jffs/configs/IPGroups' two columns
  337.                                                 # ID xxx.xxx.xxx.xxx[[,xxx.xxx.xxx.xxx][-xxx.xxx.xxx.xxx]
  338.     #CAMERAS=$(grep -iwE "^CAMERAS" /jffs/configs/IPGroups | awk '{print $2}')          # Assume .csv format
  339.     CAMERAS=$(grep -iwE "^CAMERAS" /jffs/configs/IPGroups | awk '{$1=""; print $0}')    # All columns except 1st to allow '#comments' and
  340.     #                                                                                   #     spaces and ',' between IPs v1.07
  341. else
  342.     #CAMERAS="10.88.8.120,10.88.8.122-10.88.8.123,10.88.8.124:10.88.8.125"      # Silly example to illustrate how multiple ranges can be specified!
  343.     CAMERAS=
  344. fi
  345.  
  346. # Expand the list of camera I/Ps as necessary
  347. #   e.g. '192.168.1.30,192.168.1.50-192.168.1.54' -> '192.168.1.30 192.168.1.50 192.168.1.51 192.168.1.52 192.168.1.53 192.168.1.54'
  348. CAMERAS=`echo $CAMERAS | tr ',' ' '`                                # CSVs ?
  349. CAMERAS=`echo $CAMERAS | tr ':' '-'`                                # Alternative range spec xxx.xxx.xxx.xxx:xxx.xxx.xxx.xxx
  350.  
  351.  
  352. # Expand any ranges
  353. if [ -n  "$(echo $CAMERAS | grep -o "-")" ];then                    # xxx-yyy range ?
  354.     CAMERAS="$(ExpandIPRange "$CAMERAS")"
  355. fi
  356.  
  357. if [ -z "$CAMERAS" ];then
  358.     echo -e $cBRED
  359.     Say "***ERROR No Cameras defined - see /jffs/configs/IPGroups"
  360.     echo -e "\a"$cRESET
  361.     exit 1
  362. fi
  363.  
  364. CAMERA_CNT=$(echo $CAMERAS | wc -w)
  365.  
  366. RULECNT=$(($CAMERA_CNT+1))
  367. CAMERAS=$(echo $CAMERAS | tr " " "\n" | sort -r | tr "\n" " ")          # Cosmetic; add rules in reverse order
  368. JUMP="DROP"
  369.  
  370. if [ "$(echo "$@" | grep -cw "logdrop")" -gt 0  ];then
  371.     # Unfortunately the creator of Skynet deems it acceptable to silently cripple intrinsic iptables diagnostic functionality - go figure!?... :-(
  372.     # Check to see if the standard 'logdrop' chain is still functional :-(
  373.     if [ -z "$(iptables -nL logdrop | grep -E "^LOG")" ];then
  374.         if Check_SkynetStatus; then
  375.             echo -en $cBRED"\a\t"
  376.             Say "***ERROR Intrinsic 'iptables -t filter logdrop' chain functionality has been purposely CRIPPLED by ACTIVE SKynet...WTF?!!!"
  377.             if [ "$(echo "$@" | grep -cw "fixskynet")" -gt 0 ];then
  378.                 echo -en $cBRED
  379.                 iptables -I logdrop -m state --state NEW -j LOG --log-prefix "DROP " --log-tcp-sequence --log-tcp-options --log-ip-options -m comment --comment "FUBAR'd by SKynet"
  380.                 echo -en $cBGRE"\t"
  381.                 Say ".....has now been repaired."
  382.                 iptables --line -nvL logdrop
  383.                 echo -en $cRESET
  384.             else
  385.                 iptables --line -nvL logdrop
  386.                 echo -e $cRESET
  387.                 exit 999
  388.             fi
  389.         else
  390.             echo -en $cBRED"\a\t"
  391.             Say "***ERROR Intrinsic 'iptables -t filter logdrop' chain functionality has been purposely probably been CRIPPLED by a (temporarily) DISABLED SKynet...WTF?!!!"
  392.             iptables --line -nvL logdrop
  393.             echo -e $cRESET
  394.             exit 999
  395.         fi
  396.     fi
  397.     JUMP="logdrop"
  398. fi
  399.  
  400. TRACK_NTP=0
  401. if [ "$(echo "$@" | grep -cw "logntp")" -gt 0  ];then
  402.     TRACK_NTP=1
  403. fi
  404.  
  405. NTP_SCAN=0
  406. if [ "$(echo "$@" | grep -cw "ntplogscan")" -gt 0 ];then
  407.     NTP_SCAN=1
  408. fi
  409.  
  410. LOG_SCAN=0                                              # v1.09
  411. if [ "$1" == "logscan" ];then
  412.     LOG_SCAN=1
  413.     if [ -n "$2" ];then
  414.         CAMERAS=$2                                          # Scan the log for a specific IP Camera
  415.         # Convert to IP if required
  416.         if [ -z "$(echo "$CAMERAS" | Is_IPv4)" ];then
  417.             CAMERAS=$(Convert_TO_IP "$2")
  418.         fi
  419.  
  420.     fi
  421. fi
  422.  
  423. WAN_IP=                                                 # Web IP address(es)
  424. if [ -n "$(echo "$@" | grep "wanip=")" ];then
  425.     WAN_IP="$(echo "$@" | grep -oE "wanip=.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" | cut -d'=' -f2)"
  426. fi
  427.  
  428. USEWANIP=0                                              # Web IP address(es) is for any device
  429. if [ "$(echo "$@" | grep -cw "usewanip")" -gt 0 ] && [ -n "$WAN_IP" ];then
  430.     USEWANIP=1                                          # Web IP address(es) is only for CAMERA devices
  431. fi
  432. USEMAC=0                                                # Use MAC rather than IP address
  433. if [ "$(echo "$@" | grep -cw "mac")" -gt 0 ];then
  434.     USEMAC=1
  435. fi
  436.  
  437. MAIL=                                                   # Allow sending email to server e.g. mail=smtp.gmail.com:587
  438. if [ -n "$(echo "$@" | grep "mail=")" ];then
  439.     MAIL="$(echo "$@" | sed -n "s/^.*mail=//p" | awk '{print $1}')"
  440. fi
  441.  
  442. # When logdrop (rather than DROP target) was used:
  443. #       Amcrest I/P camera (10.88.8.125) goes to http://54.84.228.44/ for Firmware Check/List/Update?
  444. #       Tenvis  I/P camera (10.88.8.120  goes to http://91.198.22.70/ to  Identify my WAN I/P?
  445.  
  446. echo -en $cBRED
  447.  
  448. if [ $FIRMWARE -ge 38201 ];then     # v01.04 v382.+ seems to use more chains, so to keep the FORWARD CHAIN easier to read create chain MyIPCAMs
  449.     CHAIN="MyIPCAMs"
  450. else
  451.     CHAIN="FORWARD"
  452. fi
  453.  
  454. # Allow MAC comments v1.07
  455. IPCOMMENT=
  456. modprobe xt_comment 2>/dev/null
  457. RC=$?
  458. if [ $RC -eq 0 ];then
  459.     IPCOMMENT="-m comment --comment "
  460. fi
  461.  
  462. # Create or Delete rules for the specified cameras
  463. if [ "$1" == "init" ] || [ "$1" == "del" ];then             # Called from firewall-start/nat-start ?
  464.     # Firewall modification
  465.     if [ "$1" == "init" ];then          # Create rules (but delete them if they already exist to prevent duplicates)
  466.         ACTIONS="-D -I"
  467.     else
  468.         ACTIONS="-D"                    # Delete rules (obviously CAMERAS variable must be the same list as when the rules were created!)
  469.         #                               # but efficiently zap ALL rules if they are in a separate chain :-;
  470.         if [ $FIRMWARE -ge 38201 ];then                     # v1.10
  471.             iptables -F $CHAIN  2> /dev/null
  472.             Firewall -D FORWARD -i br0 -j $CHAIN
  473.             iptables -X $CHAIN  2> /dev/null
  474.             ACTIONS=
  475.         fi
  476.     fi
  477.  
  478.     FWRULENO=
  479.  
  480.  
  481.     for ACTION in $ACTIONS
  482.         do
  483.             if [ "$ACTION" == "-I" ];then
  484.                 if [ $FIRMWARE -ge 38201 ];then
  485.                     iptables -F $CHAIN  2> /dev/null
  486.                     Firewall -D FORWARD -i br0 -j $CHAIN
  487.                     iptables -X $CHAIN  2> /dev/null
  488.                     iptables -N $CHAIN
  489.  
  490.                     if [ "$(Chain_exists "other2wan")" == "Y" ];then        # v1.12 Allow for multiple Dual-WAN 'other2wan' references
  491.                         Firewall -I FORWARD "$(iptables -nvL FORWARD --line | grep -E -m 1 "other2wan" | awk '{print $1}')" -i br0 -j $CHAIN
  492.                     else
  493.                         Firewall -I FORWARD "$(iptables -nvL FORWARD --line | grep -E "ACCEPT     all.*state RELATED,ESTABLISHED" | awk '{print $1+1}')" -i br0 -j $CHAIN
  494.                     fi
  495.  
  496.                 else
  497.                     FWRULENO=$(iptables -nvL FORWARD --line | grep -E "ACCEPT     all.*state RELATED,ESTABLISHED" | awk '{print $1}')
  498.                     FWRULENO=$(($FWRULENO+1))
  499.                 fi
  500.             fi
  501.             for CAMERA in $CAMERAS
  502.                 do
  503.                     MATCH_MAC=
  504.                     MATCH_IP="-s "$CAMERA
  505.                     if [ $USEMAC -eq 1 ];then
  506.                         MATCH_IP=
  507.                         #MACADDR=$(arp -a | grep "$CAMERA" | awk '{print $4}')
  508.                         MACADDR=$(ip neigh | grep "$CAMERA" | awk '{print $5}')
  509.                         if [ -z "$MACADDR" ];then
  510.                             # Camera not online? so see if static DHCP exists
  511.                             if [ $FIRMWARE -gt 38201 ];then
  512.                                 MACADDR=$(grep $CAMERA /etc/dnsmasq.conf | grep -oE "([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}")
  513.                             else
  514.                                 MACADDR=$(grep $CAMERA /etc/ethers | awk '{print $1}')
  515.                             fi
  516.                         fi
  517.                         if [ -n "$MACADDR" ];then
  518.                             MATCH_MAC="-m mac --mac-source "$MACADDR
  519.                             if [ -n "$IPCOMMENT" ];then
  520.                                 COMMENT=$IPCOMMENT" "$CAMERA            # v1.07
  521.                             fi
  522.                         fi
  523.                     fi
  524.                     if [ "$VPNONLY" == "1" ];then                   # VPN only access
  525.                         #Firewall $ACTION FORWARD -s $CAMERA -i br0 ! -o tun2+ -j DROP              # v01.00
  526.                         Firewall $ACTION $CHAIN $FWRULENO $MATCH_IP $MATCH_MAC -i br0 ! -o tun2+ -j $JUMP $COMMENT      # v01.01
  527.                         # Should the device have access to the WAN IP address(es)?
  528.                         if [ $USEWANIP -eq 1 ];then
  529.                             WAN_IP_LIST=$(echo $WAN_IP | tr ',' ' ')            # CSVs ?
  530.                             for IP in $WAN_IP_LIST                              # Allow multiple addresses v1.10
  531.                                 do
  532.                                     Firewall $ACTION $CHAIN $FWRULENO $MATCH_IP $MATCH_MAC -d $IP -i br0 -o $WAN_IF -j ACCEPT  $COMMENT
  533.                                 done
  534.                         fi
  535.                         # v01.02 The following rule is belt'n' braces to explicity ensure UPnP (if still ENABLED on router) can't start a new inbound connection
  536.                         # but if using Port Forwarding it will actually Block remote viewing!
  537.                         if [ "$(nvram get wan_upnp_enable)" == "1" ];then
  538.                             Firewall $ACTION $CHAIN $FWRULENO -d $CAMERA $MATCH_MAC -i $WAN_IF -m state --state NEW -j $JUMP  $COMMENT
  539.                             DUMMY=
  540.                         fi
  541.                     else                                            # WAN Port Forward and VPN access
  542.                         # The following debug rule can be used to track successful Port Forward requests
  543.                         if [ "$1" == "del" ];then
  544.                             Firewall $ACTION $CHAIN $FWRULENO -i $WAN_IF -d $CAMERA $MATCH_MAC -j logaccept
  545.                         else
  546.                             if [ "$(echo $@ | grep -cw "wanaccept")" -eq 1 ];then
  547.                                 Firewall $ACTION $CHAIN $FWRULENO -i $WAN_IF -d $CAMERA $MATCH_MAC -j logaccept
  548.                             fi
  549.                             # Should the device have access to the WAN IP address(es)?
  550.                             if [ $USEWANIP -eq 1 ];then
  551.                                 WAN_IP_LIST=$(echo $WAN_IP | tr ',' ' ')            # CSVs ?
  552.                                 for IP in $WAN_IP_LIST                              # Allow multiple addresses v1.10
  553.                                     do
  554.                                         Firewall $ACTION $CHAIN $FWRULENO $MATCH_IP $MATCH_MAC -d $IP -i br0 -o $WAN_IF -j ACCEPT  $COMMENT
  555.                                     done
  556.                             fi
  557.                         fi
  558.                         #     IN=eth0 OUT=br0 SRC=213.205.198.14 DST=10.88.8.120 LEN=60 TOS=0x00 PREC=0x00 TTL=51 ID=31481 DF PROTO=TCP SPT=57053 DPT=81
  559.  
  560.                         # Allow outbound WAN IP camera traffic that was initiated inbound via a Port Forward request, but don't allow the IP camera to initiate a new outbound WAN session
  561.                         Firewall $ACTION $CHAIN $FWRULENO $MATCH_IP $MATCH_MAC -i br0 -o $WAN_IF -m state --state NEW -j $JUMP  $COMMENT
  562.                         # Allow outbound VPN camera traffic via either of the VPN servers
  563.                         Firewall $ACTION $CHAIN $FWRULENO $MATCH_IP $MATCH_MAC -i br0 -o tun2+ -j ACCEPT  $COMMENT
  564.  
  565.                     fi
  566.                 done
  567.             if [ $FIRMWARE -ge 38201 ] && [ "$1" == "del" ];then
  568.                     Firewall $ACTION FORWARD -i br0 -j $CHAIN
  569.                     Firewall -F $CHAIN  2> /dev/null
  570.                     Firewall -X $CHAIN  2> /dev/null
  571.             fi
  572.         done
  573.  
  574.     # All cameras need to allow NTP (port 123) outbound? - Might be prudent to use router as internal NTPD?
  575.     # NOTE: Allow NTP for ALL LAN devices (e.g. IoT devices?) rather than for the individual cameras!!! - reduces number of rules!
  576.     for ACTION in $ACTIONS              # Create rules (but delete them if they already exist to prevent duplicates) or simply Delete if requested!
  577.         do
  578.             if [ "$2" == "blockntp" ];then
  579.                 if [ "$ACTION" == "-I" ] && [ "$1" != "init" ];then                         # Don't allow NTP if 'init blockntp' requested
  580.                     Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -p udp -m udp --dport 123 -j ACCEPT
  581.                 fi
  582.             else
  583.                 # Track who is referencing the external NTP server the most
  584.                 if [ "$TRACK_NTP" -eq 0 ];then
  585.                     Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -p udp -m udp --dport 123 -j ACCEPT
  586.                 else
  587.                     Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -p udp -m udp --dport 123 -j logaccept
  588.                 fi
  589.             fi
  590.             # Allow Global access to remote WEB IP address(es) unless 'usewanip' was specified
  591.             if [ -n "$WAN_IP" ] && [ $USEWANIP -eq 0 ];then
  592.                 WAN_IP_LIST=$(echo $WAN_IP | tr ',' ' ')            # CSVs ?
  593.                 for IP in $WAN_IP_LIST                              # Allow multiple addresses v1.10
  594.                     do
  595.                         Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -d $IP -j ACCEPT
  596.                     done
  597.             fi
  598.  
  599.             # Allow Global access to Email server               # v1.08
  600.             if [ -n "$MAIL" ];then
  601.                 Parse $MAIL ":" SMTP SMTP_PORT
  602.                 if [ -n "$SMTP_PORT" ];then
  603.                     MATCH_SMTP_PORT="--dport "$SMTP_PORT
  604.                     Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -d $SMTP -p tcp $MATCH_SMTP_PORT -j ACCEPT -m comment --comment $SMTP
  605.                     Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -d $SMTP -p udp $MATCH_SMTP_PORT -j ACCEPT -m comment --comment $SMTP
  606.                 else
  607.                     Firewall $ACTION $CHAIN $FWRULENO -i br0 -o $WAN_IF -d $SMTP -j ACCEPT -m comment --comment $SMTP
  608.                 fi
  609.  
  610.             fi
  611.         done
  612. fi
  613.  
  614. echo -e $cBYEL
  615.  
  616. # Display rules by I/P address or by name i.e. resolve the I/Ps
  617. if [ "$1" == "status" ];then
  618.     REGEXP="|"$(echo "$CAMERAS"                        | sed s'/.$//' | tr " " "|" )        # v1.02 include the inbound (UPnP) rules
  619.     if [ "$(Chain_exists "$CHAIN")" == "Y" ];then
  620.         $IPT -nvL FORWARD --line -t filter | grep -E "$CHAIN|Chain FORWARD|^num";echo -e
  621.         #$IPT -nvL $CHAIN --line -t filter | grep -E "$CHAIN|pkts bytes|!tun2+|udp dpt:123"$REGEXP      # Display I/P Addresses
  622.         $IPT -nvL $CHAIN --line -t filter                                                               # Display I/P Addresses
  623.     fi
  624. else
  625.     # Convert the list of I/Ps back into hostnames
  626.     REGEXP="|"$(echo "$(Hostname_from_IP "$CAMERAS"))" | sed s'/.$//' | tr " " "|" )        # v1.02 include the inbound (UPnP) rules
  627.     if [ "$(Chain_exists "$CHAIN")" == "Y" ];then
  628.         $IPT -nvL FORWARD --line -t filter | grep -E "$CHAIN|Chain FORWARD|^num";echo -e
  629.         $IPT -vL  $CHAIN --line -t filter | grep -E "$CHAIN|pkts bytes|!tun2+|udp dpt:ntp"$REGEXP       # Resolve I/P address in Hostnames
  630.     fi
  631. fi
  632.  
  633. echo -e $cBWHT
  634. if [ "$1" != "del" ];then
  635.     if [ "$1" == "init" ];then
  636.         Say "I/P Cameras Firewall blocking request completed."
  637.     else
  638.         # if the NTP rule is using 'logaccept' then report on the NTP request stats - Echo Dots and Synology NAS are frequent requesters
  639.         iptables -C $CHAIN -i br0 -o $WAN_IF -p udp -m udp --dport 123 -j logaccept 2> /dev/null
  640.         if [ $? -eq 0 ]  || [ "$NTP_SCAN" -eq 1 ];then
  641.             TXT=" "
  642.             if [ "$NTP_SCAN" -eq 1 ];then
  643.                 TXT=" (Previous/Archived) "
  644.             fi
  645.             echo -e $cBMAG"\nNTP requestor"$TXT"statistics:\n"
  646.             LINE=
  647.             for ITEM in $(cat $SYSLOG | grep  "DPT=123" | grep -v "BLOCKED - INBOUND" | grep -oE ' SRC=[0-9,\.]* '  | cut -c 6- | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 | uniq -c)
  648.                 do
  649.                     if [ -z "$LINE" ];then
  650.                         LINE="$(printf "%-3s" "$ITEM")"
  651.                     else
  652.                         LINE="$(echo -e ${LINE}"\t"$ITEM)"
  653.                     fi
  654.                     if [ "$(echo "$LINE" | wc -w)" -eq 2 ];then
  655.                         echo -e "\t${LINE}\t("$(Hostname_from_IP "$ITEM")")"
  656.                         LINE=
  657.                     fi
  658.                 done
  659.             echo -e $cRESET
  660.         fi
  661.         # Allow scanning of Syslog for the blocked packets from either a specific IP Camera or any          # v1.09
  662.  
  663.         LINE=
  664.         CNT=0
  665.         if [ "$LOG_SCAN" -eq 1 ];then
  666.        
  667.             if [ -z "$(ps | grep -v grep | grep -m 1 syslog-ng)" ];then             # v1.12
  668.                 SYSLOG="/tmp/syslog.log"
  669.             else
  670.                 SYSLOG="/opt/var/log/messages"
  671.             fi
  672.  
  673.             if [ $(echo "$CAMERAS" | wc -w) -eq 1 ];then        # Specific IP Camera ?
  674.                 TXT="IP Camera "$CAMERAS
  675.                 CAMERAS_GREP=$CAMERAS
  676.                 # Check if the IP camera is valid
  677.                 if [ -z "$(iptables -nvL $CHAIN | grep -w "$CAMERAS")" ];then
  678.                     echo -e $cBRED"\a\t***ERROR '"$(Hostname_from_IP "$CAMERAS" "NODOMAIN")"' ("$CAMERAS") does not exist in Chain '"$CHAIN"' for 'logscan' request\n"$cRESET
  679.                     exit 999
  680.                 else
  681.                     # Check if logdrop is in effect for the target?
  682.                     if [ -z "$(iptables -nvL $CHAIN | grep -E "logdrop.*$CAMERAS")" ];then
  683.  
  684.                         echo -e $cRED"\a\t**Warning IP Camera '"$(Hostname_from_IP "$CAMERAS" "NODOMAIN")"' ("$CAMERAS") does not have 'logdrop' enabled for 'logscan' request\n"$cRESET
  685.                         #exit 999
  686.                     fi
  687.                 fi
  688.             else
  689.                 TXT="ALL IP Cameras"
  690.                 CAMERAS_GREP=$(echo $CAMERAS | sed 's/ /|/g')
  691.             fi
  692.  
  693.             echo -en $cBCYA
  694.             Say "BLOCKED traffic for "$TXT
  695.             TOTAL=0
  696.  
  697.             for ITEM in $(grep -E "$CAMERAS_GREP" $SYSLOG | grep "DROP" | grep -v "$(basename $0)" | sed 's/SEQ=.*$//;s/LEN=.*DF//')
  698.                 do
  699.                     if [ -z "$LINE" ];then
  700.                         LINE="$(printf "%-3s" "$ITEM")"
  701.                     else
  702.                         case $CNT in                    # Cosmetic tabular column formatting
  703.                             9)          LINE=$(echo ${LINE}"\\t")$(printf "%-20s" "$ITEM");;
  704.                             10|11|13)   LINE=$(echo ${LINE}"\\t")$(printf "%-10s" "$ITEM");;
  705.                             *)          LINE=$(echo ${LINE}" "$ITEM);;
  706.                         esac
  707.                     fi
  708.                     CNT=$((CNT+1))
  709.                     if [ $CNT -eq 14 ];then
  710.                         echo -e $cBBLU"\t"$LINE
  711.                         LINE=
  712.                         CNT=0
  713.                         TOTAL=$((TOTAL+1))
  714.                     fi
  715.                 done
  716.         echo -e $cBCYA
  717.         Say "For "$TXT" - BLOCKED traffic Syslog rule count="$TOTAL
  718.         echo -e $cRESET
  719.         fi
  720.  
  721.         Say "I/P Cameras Firewall blocking" $1 "request completed."
  722.     fi
  723. else
  724.     Say "I/P Cameras Firewall unblocking complete."
  725. fi
  726.  
  727. echo -e $cRESET
  728.  
  729. exit 0
RAW Paste Data