eibgrad

ddwrt-add-static-routes-by-domain.sh

Feb 7th, 2017 (edited)
2,217
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 7.70 KB | None | 0 0
  1. #!/bin/sh
  2. export DEBUG= # uncomment/comment to enable/disable debug mode
  3. # ---------------------------------------------------------------------------- #
  4. # ddwrt-add-static-routes-by-domain.sh: v1.0.0, 07 February 2017, by eibgrad
  5. # dd-wrt ref: http://www.dd-wrt.com/phpBB2/viewtopic.php?p=1014263#1014263
  6. # install this script in the dd-wrt startup script
  7. # note: this should work w/ tomato as well, but install in the init script
  8. #
  9. # WARNING: This script WILL LIKELY NOT WORK if the OpenVPN client is active
  10. #          and anything is specified in the policy based routing field. All
  11. #          name resolution (using nslookup) will fail. The only way to resolve
  12. #          the problem is to restart DNSMasq from a telnet/ssh session.
  13. #
  14. #          stopservice dnsmasq; sleep3; startservice dnsmasq
  15. # ---------------------------------------------------------------------------- #
  16.  
  17. SCRIPT_DIR="/tmp"
  18. SCRIPT="$SCRIPT_DIR/ddwrt-add-static-routes-by-domain.sh"
  19. mkdir -p $SCRIPT_DIR
  20.  
  21. cat << "EOF" > $SCRIPT
  22. #!/bin/sh
  23. (
  24. [ ${DEBUG+x} ] && set -x
  25.  
  26. # 0 =   flush archived routes (if any) and start over
  27. # 1 = install archived routes (if any) and continue
  28. # 2 = install archived routes (if any) and exit
  29. OP_MODE="0" # 0|1|2
  30.  
  31. # class B (/16), class C (/24), or (H)ost (/32)
  32. NET_CLASS="C" # B|C|H
  33.  
  34. # specify your domains here, one per line
  35. DOMAINS="
  36. netflix.com
  37. nflxext.com
  38. nflximg.net
  39. nflxvideo.net
  40. "
  41.  
  42. MAX_PASS=0 # max number of passes through domain list (0=infinite)
  43. MAX_PASS_NOCHANGE=0 # max number of consecutive passes w/ no change (0=infinite)
  44. SLEEP=0 # time (in secs) between each pass (0=incremental)
  45.  
  46. # the following only apply to incremental sleep (SLEEP=0)
  47. SLEEP_INCR=10 # percentage increase (note: sleep starts @ 60 secs)
  48. MAX_SLEEP=$((60*60*4)) # max sleep time (in secs) between passes
  49.  
  50. ARCHIVE_DIR="/jffs" # must be persistent (e.g., jffs, usb, mounted share)
  51.  
  52. # ---------------------- DO NOT CHANGE BELOW THIS LINE ----------------------- #
  53.  
  54. WANUP_IP="8.8.8.8" # Google DNS
  55. WAN_GW="$(nvram get wan_gateway)"
  56. ARCHIVE_OUT="$(dirname $0)/$(basename $0 .sh).out"
  57. ARCHIVE_SAV="$ARCHIVE_DIR/${ARCHIVE_OUT##*/}"
  58. _sleep=60
  59.  
  60. # function min( number number )
  61. min() { echo $(( $1 < $2 ? $1 : $2 )); }
  62.  
  63. # function to_upper( string ... )
  64. to_upper() { echo "$@" | awk '{print toupper($0)}'; }
  65.  
  66. # function report_running_time()
  67. report_running_time() {
  68.     [ "$START_TIME" == "" ] && START_TIME=$(date +%s)
  69.  
  70.     # calculate running time
  71.     local diff=$(($(date +%s) - $START_TIME))
  72.  
  73.     # print running time
  74.     printf "info: current running time: %0.2d:%0.2d:%0.2d:%0.2d\n" \
  75.          $((diff/60/60/24)) $((diff/60/60%24)) $((diff/60%60)) $((diff%60))
  76. }
  77.  
  78. # function cleanup_and_exit()
  79. cleanup_and_exit() {
  80.     # sort the archive by domain name
  81.     sort $ARCHIVE_OUT -k 1,1 -o $ARCHIVE_OUT
  82.  
  83.     # save archive to persistent storage
  84.     [ -d $ARCHIVE_DIR ] && cp $ARCHIVE_OUT $ARCHIVE_SAV
  85.  
  86.     # report the number of archived routes
  87.     echo "stat: total archived routes: $(cat $ARCHIVE_SAV | wc -l)"
  88.  
  89.     echo "info: done"
  90.     exit 0
  91. }
  92.  
  93. # wait for WAN to come up
  94. while ! ping -qc1 -w3 $WANUP_IP >/dev/null 2>&1; do sleep 10; done; sleep 3
  95.  
  96. routes_added_total=0
  97.  
  98. # adjust behavior according to operating mode
  99. if [ "$OP_MODE" == "0" ]; then
  100.     # 0: flush archived routes (if any) and start over
  101.     rm -f $ARCHIVE_SAV $ARCHIVE_OUT
  102. else
  103.     # 1|2: install archived routes (if any) ...
  104.     if [ -f $ARCHIVE_SAV ]; then
  105.         while read line; do
  106.             ip="$(echo $line | awk '{print $2}')"
  107.             # avoid dups (from previous runs)
  108.             if ! ip route show | grep -Eq "^$ip "; then
  109.                 # add the route to the routing table
  110.                 if ip route add $ip via $WAN_GW; then
  111.                     routes_added_total=$((routes_added_total + 1))
  112.                 fi
  113.             fi
  114.         done < $ARCHIVE_SAV
  115.  
  116.         # force routing system to recognize our changes
  117.         ip route flush cache
  118.  
  119.         # report the number of routes added from archive
  120.         echo "stat: routes added from archive: $routes_added_total"
  121.  
  122.         # initialize the new archive
  123.         cp $ARCHIVE_SAV $ARCHIVE_OUT
  124.     else
  125.         rm -f $ARCHIVE_OUT
  126.     fi
  127.  
  128.     # 1: and continue | 2: and exit
  129.     [ "$OP_MODE" == "1" ] || { echo "info: done"; exit 0; }
  130. fi
  131.  
  132. # initialize this run
  133. NSLOOKUP="$(dirname $0)/tmp.nslookup.$$"
  134. NET_CLASS="$(to_upper $NET_CLASS)"
  135. pass_count=0
  136. pass_nochange_count=0
  137. START_TIME=$(date +%s)
  138.  
  139. # handle any interrupts by proceeding to cleanup and exit
  140. trap cleanup_and_exit SIGHUP SIGINT SIGTERM
  141.  
  142. # periodically query DNS for our domain names
  143. while :; do
  144.     # initialize this pass
  145.     pass_count=$((pass_count + 1))
  146.     route_added=false
  147.     routes_added_this_pass=0
  148.  
  149.     # iterate over the domains and query DNS for their IPs
  150.     for dom in $DOMAINS; do
  151.         # ignore comments
  152.         echo $dom | grep -Eq '^[[:space:]]*#' && continue
  153.  
  154.         # remove trailing comments and whitespace
  155.         dom="$(echo $dom | grep -Eo '^[^#]*' | awk '{$1=$1}{print}')"
  156.  
  157.         # ignore failed name resolution on current domain
  158.         if ! nslookup $dom > $NSLOOKUP; then
  159.             echo "warning: domain not found, skipping: $dom"
  160.             continue
  161.         fi
  162.  
  163.         # resolve ip address(es) for the current domain
  164.         for ip in $(cat $NSLOOKUP | \
  165.                 awk '/^Name:/,0 {if (/^Addr[^:]*: [0-9]{1,3}\./) print $3}'); do
  166.             if   [ "$NET_CLASS" == "B" ]; then
  167.                 # convert to class B network (/16)
  168.                 ip="$(echo $ip | cut -d . -f1-2).0.0/16"
  169.             elif [ "$NET_CLASS" == "C" ]; then
  170.                 # convert to class C network (/24)
  171.                 ip="$(echo $ip | cut -d . -f1-3).0/24"
  172.             fi
  173.  
  174.             # avoid dups (from previous runs/passes)
  175.             if ! ip route show | grep -Eq "^$ip "; then
  176.                 # add the route to the routing table
  177.                 if ip route add $ip via $WAN_GW; then
  178.                     route_added=true
  179.                     routes_added_this_pass=$((routes_added_this_pass + 1))
  180.  
  181.                     # archive the ip/network address
  182.                     echo "$dom $ip" >> $ARCHIVE_OUT
  183.                 fi
  184.             fi
  185.         done
  186.     done
  187.  
  188.     # force routing system to recognize our changes
  189.     [[ $route_added == true ]] && ip route flush cache
  190.  
  191.     # report the number of routes added this pass
  192.     echo "stat: routes added this pass (#$pass_count): $routes_added_this_pass"
  193.  
  194.     # update the number of consecutive passes w/ no change
  195.     if [ $routes_added_this_pass -eq 0 ]; then
  196.         pass_nochange_count=$((pass_nochange_count + 1))
  197.     else
  198.         pass_nochange_count=0
  199.     fi
  200.  
  201.     # update the running total of currently active routes
  202.     routes_added_total=$((routes_added_total + $routes_added_this_pass))
  203.  
  204.     # report the number of currently active routes
  205.     echo "stat: currently active routes: $routes_added_total"
  206.  
  207.     # report running execution time
  208.     report_running_time
  209.  
  210.     # quit if we've reached any execution limits
  211.     [ $MAX_PASS_NOCHANGE -gt 0 ] && \
  212.         [ $pass_nochange_count -ge $MAX_PASS_NOCHANGE ] && break
  213.     [ $MAX_PASS -gt 0 ] && [ $pass_count -ge $MAX_PASS ] && break
  214.  
  215.     # put it bed for a while
  216.     if [ $SLEEP -gt 0 ]; then
  217.         # fixed sleep
  218.         echo "info: sleeping for $SLEEP seconds"
  219.         sleep $SLEEP
  220.     else
  221.         _sleep=$(min $_sleep $MAX_SLEEP)
  222.         echo "info: sleeping for $_sleep seconds"
  223.         sleep $_sleep
  224.         # incremental sleep (slowly increase over time)
  225.         _sleep=$((_sleep + $((_sleep * $SLEEP_INCR / 100))))
  226.     fi
  227. done
  228.  
  229. cleanup_and_exit
  230.  
  231. ) 2>&1 | logger -t $(basename $0)[$$]
  232. EOF
  233.  
  234. chmod +x $SCRIPT
  235. nohup $SCRIPT >/dev/null 2>&1 &
Add Comment
Please, Sign In to add comment