Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- # version: 1.1.0, 26-apr-2022, by eibgrad
- # href: https://tinyurl.com/335ee4hb
- SCRIPTS_DIR='/tmp'
- SCRIPT="$SCRIPTS_DIR/ddwrt-dns-monitor.sh"
- mkdir -p $SCRIPTS_DIR
- # ------------------------------ BEGIN OPTIONS ------------------------------- #
- # how often (in secs) to update display (min 3, max 30)
- INTERVAL=6
- # uncomment/comment to enable/disable logging of Do53 connections over WAN
- #LOGGING=
- # ------------------------------- END OPTIONS -------------------------------- #
- # ---------------------- DO NOT CHANGE BELOW THIS LINE ----------------------- #
- cat << 'EOF' > $SCRIPT
- #!/bin/sh
- BNAME="$(basename $0 .sh)"
- # display color attributes
- RED='\033[0;31m'
- YELLOW='\033[0;33m'
- GREEN='\033[0;32m'
- # display monochrome attributes
- NORMAL='\033[0m'
- BOLD='\033[1m'
- ITALIC='\033[3m'
- UNDERLINE='\033[4m'
- # display command menu attributes (color and monochrome)
- CMENU='\033[7;36m' # reverse + cyan
- MMENU='\033[7m' # reverse only
- # display reset attribute
- RS='\033[0m'
- # display update interval boundaries
- MIN_INTERVAL=3
- MAX_INTERVAL=30
- # work files
- HEAD="/tmp/tmp.$$.$BNAME.head"
- BODY="/tmp/tmp.$$.$BNAME.body"
- DATA="/tmp/tmp.$$.$BNAME.data"
- LOG="/tmp/tmp.$$.$BNAME.log"; > $LOG
- # function min_str( str1 str2 )
- min_str() { [ "$1" ] && echo "$1" || echo "$2"; }
- # function max_val( val1 val2 )
- max_val() { echo $(($1 < $2 ? $2 : $1)); }
- # function min_val( val1 val2 )
- min_val() { echo $(($1 > $2 ? $2 : $1)); }
- # function format_header()
- format_header() {
- local ip dns spbr dpbr sw_vpn_printed
- # publish wan/lan ip information
- printf "WAN/LAN IP: $wan_ip_4disp/$(nvram get lan_ipaddr)\n\n"
- # publish wan dns information
- printf " WAN DNS: $(echo $(awk '/^nameserver /{print $2}' \
- /tmp/resolv.conf) | sed -r 's/ /, /g')\n"
- # publish dhcp dns information
- if grep -Eq '^no-resolv( |$)' /tmp/dnsmasq.conf; then
- printf "DHCP DNS: $(echo $(awk -F'[= ]' '/^server=/{print $2}' \
- /tmp/dnsmasq.conf) | sed -r 's/ /, /g')\n"
- else
- printf "DHCP DNS: $(echo $(awk '/^nameserver /{print $2}' \
- /tmp/resolv.dnsmasq) | sed -r 's/ /, /g')\n"
- fi
- # publish dnscrypt dns information
- [ "$doc_ip" ] && printf " DoC DNS: $doc_ip:$doc_port\n"
- # publish openvpn information
- if [ "$(nvram get openvpncl_enable)" == "1" ]; then
- ip="$(ifconfig tun1 2>/dev/null | \
- awk '/inet addr/{split ($2,A,":"); print A[2]}')"
- case $(nvram get openvpncl_spbr) in
- '0') spbr='All via VPN';;
- '1') spbr='Selected via VPN';;
- '2') spbr='Selected via WAN';;
- *) if [ "$(nvram get openvpncl_route)" ]; then
- spbr='Selected via VPN'
- else
- spbr='All via VPN'
- fi;;
- esac
- printf "\nOpenVPN IP/SPBR: $(min_str $ip 0.0.0.0)/$spbr\n"
- fi
- local i=0; local tunnels=$(nvram get oet_tunnels)
- # publish wireguard information
- while [ $((++i)) -le $tunnels ]; do
- [ "$(nvram get oet${i}_en)" == "1" ] || continue
- ip="$(nvram get oet${i}_ipaddr)"
- dns="$(nvram get oet${i}_dns)"
- case $(nvram get oet${i}_spbr) in
- '0') spbr='All via VPN';;
- '1') spbr='Selected via VPN';;
- '2') spbr='Selected via WAN';;
- esac
- case $(nvram get oet${i}_dpbr) in
- '0') dpbr='All via VPN';;
- '1') dpbr='Selected via VPN';;
- '2') dpbr='Selected via WAN';;
- esac
- printf "\nWireGuard #${i} IP/DNS/SPBR/DPBR: $ip/$dns/$spbr/$dpbr"
- sw_vpn_printed=
- done
- [ ${sw_vpn_printed+x} ] && printf '\n'
- printf "\nActive DNS (Do53/DoC/DoT) UDP/TCP Connections\n"
- printf " ${sev_lvl_2}Do53 (plaintext) routed over the WAN${RS}\n"
- printf " ${sev_lvl_1}DoC/DoT (ciphertext) routed over the WAN${RS}\n"
- printf " ${sev_lvl_0}DoC/DoT/Do53 NOT routed over the WAN "
- printf "(loopback, local, or VPN)${RS}\n"
- echo ' '
- }
- # function format_body()
- format_body() {
- _print_with_dupe_count() {
- local dupe_count=0
- local prev_line="$(head -n1 $DATA)"
- # print line w/ duplicate line-count indicator
- __print_line() {
- if [ $dupe_count -gt 1 ]; then
- printf '%-95s %s\n' "$prev_line" "($dupe_count)"
- else
- echo "$prev_line"
- fi
- }
- # find and print unique lines while counting duplicates
- while read line; do
- if [ "$line" == "$prev_line" ]; then
- let dupe_count++
- else
- __print_line; prev_line="$line"; dupe_count=1
- fi
- done < $DATA
- [ "$prev_line" ] && __print_line
- }
- # publish DoC/Do53 over udp (replied and sorted)
- grep -E "^ipv4 .* (udp .* dport=$doc_port .* src=$doc_ip |udp .* dport=53 )" \
- /proc/net/nf_conntrack | \
- awk '$0 !~ /UNREPLIED/{printf "%s %-19s %-19s %-11s %-19s %s\n",
- $3, $6, $7, $9, $12, $13}' | \
- sort > $DATA
- # remove duplicates; optionally include dupe count
- [ ${sw_dupes+x} ] && _print_with_dupe_count || uniq $DATA
- # publish DoC/DoT/Do53 over tcp (replied and sorted)
- grep -E "^ipv4 .* (tcp .* dport=$doc_port .* src=$doc_ip |tcp .* dport=(53|853)) " \
- /proc/net/nf_conntrack | \
- awk '/ASSURED/{printf "%s %-19s %-19s %-11s %-19s %s\n",
- $3, $7, $8, $10, $13, $14}' | \
- sort > $DATA
- # remove duplicates; optionally include dupe count
- [ ${sw_dupes+x} ] && _print_with_dupe_count || uniq $DATA
- }
- # function pause_display()
- pause_display() {
- read -sp "$(echo -e ${menu}"\nPress [Enter] key to continue..."${RS})" \
- < "$(tty 0>&2)"
- }
- # function exit_0()
- exit_0() {
- # publish name of log file
- [ -s $LOG ] && echo -e "\nlog file: $LOG" || rm -f $LOG
- # cleanup work files
- rm -f $HEAD $BODY $DATA
- # publish information on restarting
- echo -e "\nRun $0 to restart."
- exit 0
- }
- # trap on unexpected exit (e.g., crtl-c)
- trap 'exit_0' SIGHUP SIGINT SIGTERM
- # enable header
- sw_head=
- # set initial update interval
- interval=$(max_val $MIN_INTERVAL $(min_val $INTERVAL $MAX_INTERVAL))
- # set initial logging state
- [ "$LOGGING" ] && sw_log=
- # begin display loop
- while :; do
- # establish wan ip for analysis and display
- wan_ip="$(nvram get wan_ipaddr)"
- [ "$wan_ip" == '0.0.0.0' ] && wan_ip="$(nvram get lan_gateway)"
- wan_ip_4disp="$([ ${sw_wanip+x} ] && echo 'x.x.x.x' || echo $wan_ip)"
- # establish dnscrypt ip and port
- if [ "$(nvram get dns_crypt)" == '1' ]; then
- doc_ip_port="$(grep -m1 ^$(nvram get dns_crypt_resolver), \
- /etc/dnscrypt/dnscrypt-resolvers.csv | \
- sed 's/\".*\"//g' | cut -d, -f11 | \
- grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}(:[0-9]{1,5}|)')"
- doc_ip="$(echo $doc_ip_port | cut -d: -f1)"
- if [ "$doc_ip" ]; then
- doc_port="$(min_str $(echo $doc_ip_port | cut -sd: -f2) 443)"
- else
- doc_port=''
- fi
- else
- doc_ip=''; doc_port=''
- fi
- # set display attributes (color (default) or monochrome)
- if [ ! ${sw_mono+x} ]; then
- sev_lvl_2="$RED"
- sev_lvl_1="$YELLOW"
- sev_lvl_0="$GREEN"
- menu="$CMENU"
- else
- sev_lvl_2="$BOLD"
- sev_lvl_1="$UNDERLINE"
- sev_lvl_0="$NORMAL"
- menu="$MMENU"
- fi
- # format command menu
- [ ${sw_head+x} ] && _head='hide' || _head='show'
- [ ${sw_scroll+x} ] && _scroll='disable' || _scroll='enable'
- [ ${sw_wanip+x} ] && _wanip='show' || _wanip='hide'
- [ ${sw_dupes+x} ] && _dupes='hide' || _dupes='show'
- [ ${sw_mono+x} ] && _mono='disable' || _mono='enable'
- [ ${sw_log+x} ] && _log='disable' || _log='enable'
- # format header
- [ ${sw_head+x} ] && format_header > $HEAD
- # format body
- format_body > $BODY
- # clear display
- clear
- # start of "more-able" output
- {
- # display command menu
- if [ ! ${sw_next+x} ]; then
- printf "${menu}%s | %s | %s | %s | %s | %s%s${RS}\n" \
- "[n]ext menu" \
- "$_head [h]eader" \
- "[+/-] interval ($interval)" \
- "$_scroll [s]croll" \
- "[p]ause" \
- "[e]xit" \
- ''
- else
- printf "${menu}%s | %s | %s | %s | %s%s${RS}\n" \
- "[n]ext menu" \
- "$_wanip wan [i]p" \
- "$_dupes [d]upes" \
- "$_mono [m]ono" \
- "$_log [l]og" \
- ''
- fi
- # display header
- [ ${sw_head+x} ] && cat $HEAD
- # display column headings
- printf '%43s' 'v-------------- sender ---------------v'
- printf '%52s\n' 'v------------- recipient -------------v'
- # display body/data (include severity level 0|1|2)
- while read line; do
- # hide wan/public ip when requested
- if [ ${sw_wanip+x} ]; then
- line_4disp="$(echo "$line" | \
- sed -r "s/(src|dst)=$wan_ip($)/\1=$wan_ip_4disp/g; \
- s/(src|dst)=$wan_ip( +)/\1=$wan_ip_4disp /g")"
- else
- line_4disp="$line"
- fi
- if echo $line | grep 'dport=53 ' | \
- grep -Eq "(src|dst)=$wan_ip( |$)"; then
- # Do53 connection routed over WAN
- printf "${sev_lvl_2}$line_4disp${RS}\n"
- # log the connection (optional)
- if [ ${sw_log+x} ]; then
- # remove dupe count (if present)
- line="$(echo "$line" | sed 's/\s*([0-9]*)$//')"
- # ignore duplicates
- grep -qxF "$line" $LOG || echo "$line" >> $LOG
- fi
- elif echo $line | grep -E "dport=($doc_port|853) " | \
- grep -Eq "(src|dst)=$wan_ip( |$)"; then
- # DoC/DoT connection routed over WAN
- printf "${sev_lvl_1}$line_4disp${RS}\n"
- else
- # Do53/DoC/DoT connection NOT routed over WAN
- printf "${sev_lvl_0}$line_4disp${RS}\n"
- fi
- done < $BODY
- [ -s $BODY ] || echo '<no-data>'
- # end of "more-able" output
- } 2>&1 | $([ ${sw_scroll+x} ] && echo 'tee' || echo 'more')
- # update display at regular interval (capture any user input)
- key_press=''; read -rsn1 -t $interval key_press < "$(tty 0>&2)"
- # handle key-press (optional)
- if [ $key_press ]; then
- case $key_press in
- # common/shared menu option(s)
- 'n') [ ${sw_next+x} ] && unset sw_next || sw_next=;;
- # primary menu options
- 'h') [ ${sw_head+x} ] && unset sw_head || sw_head=;;
- '+') interval=$(min_val $((interval+3)) $MAX_INTERVAL);;
- '-') interval=$(max_val $((interval-3)) $MIN_INTERVAL);;
- 'p') pause_display;;
- 'e') exit_0;;
- # secondary menu options
- 'i') [ ${sw_wanip+x} ] && unset sw_wanip || sw_wanip=;;
- 'd') [ ${sw_dupes+x} ] && unset sw_dupes || sw_dupes=;;
- 'm') [ ${sw_mono+x} ] && unset sw_mono || sw_mono=;;
- 's') [ ${sw_scroll+x} ] && unset sw_scroll || sw_scroll=;;
- 'l') [ ${sw_log+x} ] && unset sw_log || sw_log=;;
- esac
- fi
- done # end of 'while :; do'
- EOF
- [ ${LOGGING+x} ] && sed -ri 's/\$LOGGING/LOGGING/g' $SCRIPT
- sed -i "s:\$INTERVAL:$INTERVAL:g" $SCRIPT
- chmod +x $SCRIPT
- # begin execution
- $SCRIPT
Add Comment
Please, Sign In to add comment