Guest User

Untitled

a guest
Jun 27th, 2024
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 87.66 KB | None | 0 0
  1. #!/bin/sh
  2. ###########################################################
  3. # ______ _ ____ _____ #
  4. # | ____|| | / __ \ / ____| #
  5. # | |__ | | ___ __ __| | | | ___ | (___ #
  6. # | __| | | / _ \\ \/ /| | | | / _ \ \___ \ #
  7. # | | | || __/ > < | |__| || (_) |____) | #
  8. # |_| |_| \___|/_/\_\ \___\_\ \___/|_____/ #
  9. # #
  10. ###########################################################
  11. # FlexQoS maintained by dave14305
  12. # Contributors: @maghuro
  13. # shellcheck disable=SC1090,SC1091,SC2039,SC2154,SC3043
  14. # amtm NoMD5check
  15. version=1.4.3
  16. release=2024-06-18
  17. # Forked from FreshJR_QOS v8.8, written by FreshJR07 https://github.com/FreshJR07/FreshJR_QOS
  18. # License
  19. # FlexQoS is free to use under the GNU General Public License, version 3 (GPL-3.0).
  20. # https://opensource.org/licenses/GPL-3.0
  21.  
  22. # initialize Merlin Addon API helper functions
  23. . /usr/sbin/helper.sh
  24.  
  25. # -x is a flag to show verbose script output for debugging purposes only
  26. if [ "${1}" = "-x" ]; then
  27. shift
  28. set -x
  29. fi
  30.  
  31. # Global variables
  32. readonly SCRIPTNAME_DISPLAY="FlexQoS"
  33. readonly SCRIPTNAME="flexqos"
  34. readonly GIT_URL="https://raw.githubusercontent.com/dave14305/${SCRIPTNAME_DISPLAY}/master"
  35.  
  36. readonly ADDON_DIR="/jffs/addons/${SCRIPTNAME}"
  37. readonly WEBUIPATH="${ADDON_DIR}/${SCRIPTNAME}.asp"
  38. readonly SCRIPTPATH="${ADDON_DIR}/${SCRIPTNAME}.sh"
  39. readonly LOCKFILE="/tmp/addonwebui.lock"
  40. IPv6_enabled="$(nvram get ipv6_service)"
  41.  
  42. # Update version number in custom_settings.txt for reading in WebUI
  43. if [ "$(am_settings_get "${SCRIPTNAME}"_ver)" != "${version}" ]; then
  44. am_settings_set "${SCRIPTNAME}"_ver "${version}"
  45. fi
  46.  
  47. # If Merlin fq_codel patch is active, use original tc binary for passing commands
  48. # Will be obsolete in 386.1 and higher.
  49. if [ -e "/usr/sbin/realtc" ]; then
  50. TC="/usr/sbin/realtc"
  51. else
  52. TC="/usr/sbin/tc"
  53. fi
  54.  
  55. # Detect if script is run from an SSH shell interactively or being invoked via cron or from the WebUI (unattended)
  56. if tty >/dev/null 2>&1; then
  57. mode="interactive"
  58. else
  59. mode="unattended"
  60. fi
  61.  
  62. # marks for iptables rules
  63. # We use the ffff value to avoid conflicts with predefined apps in AppDB so there would be no conflict
  64. # with any user-defined AppDB rules.
  65. Net_mark="09"
  66. Work_mark="06"
  67. Gaming_mark="08"
  68. Others_mark="0a"
  69. Web_mark="18"
  70. Streaming_mark="04"
  71. Downloads_mark="03"
  72. Learn_mark="3f"
  73.  
  74. logmsg() {
  75. if [ "$#" = "0" ]; then
  76. return
  77. fi
  78. logger -t "${SCRIPTNAME_DISPLAY}" "$*"
  79. } # logmsg
  80.  
  81. Red() {
  82. printf -- '\033[1;31m%s\033[0m\n' "${1}"
  83. }
  84.  
  85. Green() {
  86. printf -- '\033[1;32m%s\033[0m\n' "${1}"
  87. }
  88.  
  89. Blue() {
  90. printf -- '\033[1;36m%s\033[0m\n' "${1}"
  91. }
  92.  
  93. Yellow() {
  94. printf -- '\033[1;33m%s\033[0m\n' "${1}"
  95. }
  96.  
  97. get_class_mark() {
  98. case "${1}" in
  99. 0) printf "%s\n" "${Net_mark}" ;;
  100. 1) printf "%s\n" "${Gaming_mark}" ;;
  101. 2) printf "%s\n" "${Streaming_mark}" ;;
  102. 3) printf "%s\n" "${Work_mark}" ;;
  103. 4) printf "%s\n" "${Web_mark}" ;;
  104. 5) printf "%s\n" "${Downloads_mark}" ;;
  105. 6) printf "%s\n" "${Others_mark}" ;;
  106. 7) printf "%s\n" "${Learn_mark}" ;;
  107. *) printf "%s\n" "" ;;
  108. esac
  109. }
  110.  
  111. iptables_static_rules() {
  112. printf "Applying iptables static rules\n"
  113. # Reference for VPN Fix origin: https://www.snbforums.com/threads/36836/page-78#post-412034
  114. # Partially fixed in https://github.com/RMerl/asuswrt-merlin.ng/commit/f7d6478df7b934c9540fa9740ad71d49d84a1756
  115. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  116. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff
  117. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  118. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff
  119. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  120. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff
  121. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  122. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff
  123. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  124. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff
  125. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  126. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff
  127. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  128. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff
  129. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  130. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff
  131. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  132. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff
  133. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  134. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff
  135. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  136. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff
  137. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  138. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff
  139. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  140. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff
  141. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  142. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff
  143. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  144. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff
  145. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  146. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff
  147. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  148. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff
  149. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  150. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff
  151. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  152. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff
  153. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  154. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff
  155. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  156. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff
  157. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  158. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff
  159. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  160. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff
  161. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  162. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff
  163. iptables -t mangle -N "${SCRIPTNAME_DISPLAY}_down" 2>/dev/null
  164. iptables -t mangle -N "${SCRIPTNAME_DISPLAY}_up" 2>/dev/null
  165. iptables -t mangle -A POSTROUTING -o "${lan}" -m mark --mark 0x80000000/0xc0000000 -j "${SCRIPTNAME_DISPLAY}_down"
  166. iptables -t mangle -A POSTROUTING -o "${wan}" -m mark --mark 0x40000000/0xc0000000 -j "${SCRIPTNAME_DISPLAY}_up"
  167. if [ "${IPv6_enabled}" != "disabled" ]; then
  168. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  169. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff
  170. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  171. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x08"${Net_mark}"0fff/0xc03f0fff
  172. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  173. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff
  174. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  175. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x02"${Gaming_mark}"0fff/0xc03f0fff
  176. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  177. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff
  178. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  179. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x18"${Work_mark}"0fff/0xc03f0fff
  180. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  181. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff
  182. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  183. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x04"${Web_mark}"0fff/0xc03f0fff
  184. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  185. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff
  186. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  187. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x01"${Downloads_mark}"0fff/0xc03f0fff
  188. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  189. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff
  190. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  191. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x10"${Downloads_mark}"0fff/0xc03f0fff
  192. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  193. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff
  194. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  195. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x20"${Others_mark}"0fff/0xc03f0fff
  196. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  197. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff
  198. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  199. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x28"${Others_mark}"0fff/0xc03f0fff
  200. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  201. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff
  202. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  203. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2c"${Others_mark}"0fff/0xc03f0fff
  204. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  205. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff
  206. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  207. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x2e"${Others_mark}"0fff/0xc03f0fff
  208. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  209. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff
  210. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  211. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x30"${Learn_mark}"0fff/0xc03f0fff
  212. iptables -t mangle -D OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS & NTP
  213. iptables -t mangle -A OUTPUT -o "${wan}" -p udp -m multiport --dports 53,123 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff
  214. iptables -t mangle -D OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff > /dev/null 2>&1 # Outbound DNS and DoT
  215. iptables -t mangle -A OUTPUT -o "${wan}" -p tcp -m multiport --dports 53,853 -j MARK --set-mark 0x38"${Learn_mark}"0fff/0xc03f0fff
  216. ip6tables -t mangle -N "${SCRIPTNAME_DISPLAY}_down" 2>/dev/null
  217. ip6tables -t mangle -N "${SCRIPTNAME_DISPLAY}_up" 2>/dev/null
  218. ip6tables -t mangle -A POSTROUTING -o "${lan}" -m mark --mark 0x80000000/0xc0000000 -j "${SCRIPTNAME_DISPLAY}_down"
  219. ip6tables -t mangle -A POSTROUTING -o "${wan}" -m mark --mark 0x40000000/0xc0000000 -j "${SCRIPTNAME_DISPLAY}_up"
  220. fi
  221. }
  222.  
  223. get_static_filter() {
  224. local MARK
  225. local FLOWID
  226.  
  227. MARK="${1}"
  228. FLOWID="${2}"
  229.  
  230. printf "filter add dev %s protocol all prio 5 u32 match mark 0x80%sffff 0xc03fffff flowid %s\n" "${tclan}" "${MARK}" "${FLOWID}"
  231. printf "filter add dev %s protocol all prio 5 u32 match mark 0x40%sffff 0xc03fffff flowid %s\n" "${tcwan}" "${MARK}" "${FLOWID}"
  232. } # get_static_filter
  233.  
  234. write_appdb_static_rules() {
  235. # These rules define the flowid (priority level) of the Class destinations selected by users in iptables rules.
  236. # Previous versions of the script were susceptible to the chosen Class being overridden by the users AppDB rules.
  237. # Adding these filters ensures the Class you select in iptables rules is strictly observed.
  238. # prio 5 is used because the first default filter rule (mark 0x80030000 0xc03f0000) is found at prio 6 as of this writing,
  239. # so we want these filters to always take precedence over the built-in filters.
  240. # File is overwritten (>) if it exists and later appended by write_appdb_rules() and write_custom_rates().
  241. {
  242. get_static_filter "${Net_mark}" "${Net_flow}"
  243. get_static_filter "${Work_mark}" "${Work_flow}"
  244. get_static_filter "${Gaming_mark}" "${Gaming_flow}"
  245. get_static_filter "${Others_mark}" "${Others_flow}"
  246. get_static_filter "${Web_mark}" "${Web_flow}"
  247. get_static_filter "${Streaming_mark}" "${Streaming_flow}"
  248. get_static_filter "${Downloads_mark}" "${Downloads_flow}"
  249. get_static_filter "${Learn_mark}" "${Learn_flow}"
  250. } > "/tmp/${SCRIPTNAME}_tcrules"
  251. } # write_appdb_static_rules
  252.  
  253. get_burst() {
  254. local RATE
  255. local DURATION
  256. local BURST
  257. local MIN_BURST
  258.  
  259. RATE="${1}"
  260. DURATION="${2}" # acceptable added latency in microseconds (1ms)
  261.  
  262. # https://github.com/tohojo/sqm-scripts/blob/master/src/functions.sh
  263. # let's assume ATM/AAL5 to be the worst case encapsulation
  264. # and 48 Bytes a reasonable worst case per packet overhead
  265. MIN_BURST=$(( WANMTU + 48 )) # add 48 bytes to MTU for the ovehead
  266. MIN_BURST=$(( MIN_BURST + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic
  267. MIN_BURST=$(( MIN_BURST / 48 ))
  268. MIN_BURST=$(( MIN_BURST * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes
  269.  
  270. BURST=$((DURATION*RATE/8000))
  271.  
  272. # If the calculated burst is less than ASUS' minimum value of 3200, use 3200
  273. # to avoid problems with child and leaf classes outside of FlexQoS scope that use 3200.
  274. # If using fq_codel option, use 1600 as a minimum burst.
  275. if [ "$(am_settings_get "${SCRIPTNAME}"_qdisc)" = "0" ]; then
  276. if [ "${BURST}" -lt 3200 ]; then
  277. BURST=3200
  278. fi
  279. elif [ "${BURST}" -lt "${MIN_BURST}" ]; then
  280. BURST="${MIN_BURST}"
  281. fi
  282.  
  283. printf "%s" "${BURST}"
  284. } # get_burst
  285.  
  286. get_cburst() {
  287. local RATE
  288. local BURST
  289. local MIN_BURST
  290.  
  291. RATE="${1}"
  292.  
  293. # https://github.com/tohojo/sqm-scripts/blob/master/src/functions.sh
  294. # let's assume ATM/AAL5 to be the worst case encapsulation
  295. # and 48 Bytes a reasonable worst case per packet overhead
  296. MIN_BURST=$(( WANMTU + 48 )) # add 48 bytes to MTU for the ovehead
  297. MIN_BURST=$(( MIN_BURST + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic
  298. MIN_BURST=$(( MIN_BURST / 48 ))
  299. MIN_BURST=$(( MIN_BURST * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes
  300.  
  301. BURST=$((RATE*1000/1280000))
  302. BURST=$((BURST*1600))
  303.  
  304. # If the calculated burst is less than ASUS' minimum value of 3200, use 3200
  305. # to avoid problems with child and leaf classes outside of FlexQoS scope that use 3200.
  306. if [ "${BURST}" -lt 3200 ]; then
  307. if [ "$(am_settings_get "${SCRIPTNAME}"_qdisc)" = "0" ]; then
  308. BURST=3200
  309. else
  310. BURST="${MIN_BURST}"
  311. fi
  312. fi
  313.  
  314. printf "%s" "${BURST}"
  315. } # get_cburst
  316.  
  317. get_quantum() {
  318. local RATE
  319. local QUANTUM
  320. local MIN_QUANTUM
  321.  
  322. RATE="${1}"
  323.  
  324. # https://github.com/tohojo/sqm-scripts/blob/master/src/functions.sh
  325. # let's assume ATM/AAL5 to be the worst case encapsulation
  326. # and 48 Bytes a reasonable worst case per packet overhead
  327. MIN_QUANTUM=$(( WANMTU + 48 )) # add 48 bytes to MTU for the ovehead
  328. MIN_QUANTUM=$(( MIN_QUANTUM + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic
  329. MIN_QUANTUM=$(( MIN_QUANTUM / 48 ))
  330. MIN_QUANTUM=$(( MIN_QUANTUM * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes
  331.  
  332. QUANTUM=$((RATE*1000/8/10))
  333.  
  334. # If the calculated quantum is less than the MTU, use MTU+14 as the quantum
  335. if [ "${QUANTUM}" -lt "${MIN_QUANTUM}" ]; then
  336. QUANTUM="${MIN_QUANTUM}"
  337. fi
  338.  
  339. printf "%s" "${QUANTUM}"
  340. } # get_quantum
  341.  
  342. get_overhead() {
  343. local NVRAM_OVERHEAD
  344. local NVRAM_ATM
  345. local OVERHEAD
  346.  
  347. NVRAM_OVERHEAD="$(nvram get qos_overhead)"
  348.  
  349. if [ -n "${NVRAM_OVERHEAD}" ] && [ "${NVRAM_OVERHEAD}" -gt "0" ]; then
  350. OVERHEAD="overhead ${NVRAM_OVERHEAD}"
  351. NVRAM_ATM="$(nvram get qos_atm)"
  352. if [ "${NVRAM_ATM}" = "1" ]; then
  353. OVERHEAD="${OVERHEAD} linklayer atm"
  354. else
  355. OVERHEAD="${OVERHEAD} linklayer ethernet"
  356. fi
  357. fi
  358.  
  359. printf "%s" "${OVERHEAD}"
  360. } # get_overhead
  361.  
  362. get_custom_rate_rule() {
  363. local IFACE
  364. local PRIO
  365. local RATE
  366. local CEIL
  367. local DURATION
  368.  
  369. IFACE="${1}"
  370. PRIO="${2}"
  371. RATE="${3}"
  372. CEIL="${4}"
  373. DURATION=1000 # 1000 microseconds = 1 ms
  374.  
  375. printf "class change dev %s parent 1:1 classid 1:1%s htb %s prio %s rate %sKbit ceil %sKbit burst %sb cburst %sb quantum %s\n" \
  376. "${IFACE}" "${PRIO}" "$(get_overhead)" "${PRIO}" "${RATE}" "${CEIL}" "$(get_burst "${CEIL}" "${DURATION}")" "$(get_cburst "${CEIL}")" "$(get_quantum "${RATE}")"
  377. } # get_custom_rate_rule
  378.  
  379. write_custom_rates() {
  380. local i
  381. if [ "${DownCeil}" -gt "0" ] && [ "${UpCeil}" -gt "0" ]; then
  382. # For all 8 classes (0-7), write the tc commands needed to modify the bandwidth rates and related parameters
  383. # that get assigned in set_tc_variables().
  384. # File is appended (>>) because it is initially created in write_appdb_static_rules().
  385. {
  386. for i in 0 1 2 3 4 5 6 7
  387. do
  388. eval get_custom_rate_rule "${tclan}" "${i}" \$DownRate${i} \$DownCeil${i}
  389. eval get_custom_rate_rule "${tcwan}" "${i}" \$UpRate${i} \$UpCeil${i}
  390. done
  391. } >> "/tmp/${SCRIPTNAME}_tcrules"
  392. fi
  393. } # write_custom_rates
  394.  
  395. set_tc_variables() {
  396. # Read various settings from the router and construct the variables needed to implement the custom rules.
  397. local drp0 drp1 drp2 drp3 drp4 drp5 drp6 drp7
  398. local dcp0 dcp1 dcp2 dcp3 dcp4 dcp5 dcp6 dcp7
  399. local urp0 urp1 urp2 urp3 urp4 urp5 urp6 urp7
  400. local ucp0 ucp1 ucp2 ucp3 ucp4 ucp5 ucp6 ucp7
  401. # shellcheck disable=SC2034
  402. local Cat0DownBandPercent Cat1DownBandPercent Cat2DownBandPercent Cat3DownBandPercent Cat4DownBandPercent Cat5DownBandPercent Cat6DownBandPercent Cat7DownBandPercent
  403. # shellcheck disable=SC2034
  404. local Cat0DownCeilPercent Cat1DownCeilPercent Cat2DownCeilPercent Cat3DownCeilPercent Cat4DownCeilPercent Cat5DownCeilPercent Cat6DownCeilPercent Cat7DownCeilPercent
  405. # shellcheck disable=SC2034
  406. local Cat0UpBandPercent Cat1UpBandPercent Cat2UpBandPercent Cat3UpBandPercent Cat4UpBandPercent Cat5UpBandPercent Cat6UpBandPercent Cat7UpBandPercent
  407. # shellcheck disable=SC2034
  408. local Cat0UpCeilPercent Cat1UpCeilPercent Cat2UpCeilPercent Cat3UpCeilPercent Cat4UpCeilPercent Cat5UpCeilPercent Cat6UpCeilPercent Cat7UpCeilPercent
  409. local flowid
  410. local line
  411. local i
  412.  
  413. tclan="br0"
  414. if [ -f /sys/module/tdts_udb/parameters/qos_wan ]; then
  415. tcwan="$(cat /sys/module/tdts_udb/parameters/qos_wan)"
  416. else
  417. tcwan="$(nvram get wan_ifname)"
  418. fi
  419.  
  420. # Detect the default filter rule for Untracked traffic (Mark 000000) if it exists.
  421. # Newer 384 stock firmware dropped this rule, so Untracked traffic flows into the Work-From-Home priority by default.
  422. # First check for older ASUS default rule (0x80000000 0xc000ffff).
  423. # If not found, get the prio for the Work-From-Home Instant messengers category 00 (0x80000000 0xc03f0000) and subtract 1.
  424. undf_prio="$("${TC}" filter show dev br0 | /bin/grep -i -m1 -B1 "0x80000000 0xc000ffff" | sed -nE 's/.* pref ([0-9]+) .*/\1/p')"
  425. if [ -z "${undf_prio}" ]; then
  426. undf_prio="$("${TC}" filter show dev br0 | /bin/grep -i -m1 -B1 "0x80000000 0xc03f0000" | sed -nE 's/.* pref ([0-9]+) .*/\1/p')"
  427. undf_prio="$((undf_prio-1))"
  428. fi
  429.  
  430. read -r \
  431. drp0 drp1 drp2 drp3 drp4 drp5 drp6 drp7 \
  432. dcp0 dcp1 dcp2 dcp3 dcp4 dcp5 dcp6 dcp7 \
  433. urp0 urp1 urp2 urp3 urp4 urp5 urp6 urp7 \
  434. ucp0 ucp1 ucp2 ucp3 ucp4 ucp5 ucp6 ucp7 \
  435. <<EOF
  436. $(echo "${bwrates}" | sed 's/^<//g;s/[<>]/ /g')
  437. EOF
  438.  
  439. # read priority order of QoS categories as set by user on the QoS page of the GUI
  440. flowid=0
  441. while read -r line;
  442. do
  443. if [ "$(echo "${line}" | cut -c 1)" = '[' ]; then
  444. flowid="$(echo "${line}" | cut -c 2)"
  445. fi
  446. case "${line}" in
  447. '0')
  448. Work_flow="1:1${flowid}"
  449. eval "Cat${flowid}DownBandPercent=${drp3}"
  450. eval "Cat${flowid}DownCeilPercent=${dcp3}"
  451. eval "Cat${flowid}UpBandPercent=${urp3}"
  452. eval "Cat${flowid}UpCeilPercent=${ucp3}"
  453. ;;
  454. '1')
  455. Downloads_flow="1:1${flowid}"
  456. eval "Cat${flowid}DownBandPercent=${drp5}"
  457. eval "Cat${flowid}DownCeilPercent=${dcp5}"
  458. eval "Cat${flowid}UpBandPercent=${urp5}"
  459. eval "Cat${flowid}UpCeilPercent=${ucp5}"
  460. ;;
  461. '4')
  462. # Special handling for category 4 since it is duplicated between Streaming and Learn-From-Home.
  463. # We have to find the priority placement of Learn-From-Home versus Streaming in the QoS GUI to know
  464. # if the first time we encounter a 4 in the file if it is meant to be Streaming or Learn-From-Home.
  465. # The second time we encounter a 4, we know it is meant for the remaining option.
  466. if nvram get bwdpi_app_rulelist | /bin/grep -qE "<4,13(<.*)?<4<"; then
  467. # Learn-From-Home is higher priority than Streaming
  468. if [ -z "${Learn_flow}" ]; then
  469. Learn_flow="1:1${flowid}"
  470. eval "Cat${flowid}DownBandPercent=${drp7}"
  471. eval "Cat${flowid}DownCeilPercent=${dcp7}"
  472. eval "Cat${flowid}UpBandPercent=${urp7}"
  473. eval "Cat${flowid}UpCeilPercent=${ucp7}"
  474. else
  475. Streaming_flow="1:1${flowid}"
  476. eval "Cat${flowid}DownBandPercent=${drp2}"
  477. eval "Cat${flowid}DownCeilPercent=${dcp2}"
  478. eval "Cat${flowid}UpBandPercent=${urp2}"
  479. eval "Cat${flowid}UpCeilPercent=${ucp2}"
  480. fi
  481. else
  482. # Streaming is higher priority than Learn-From-Home
  483. if [ -z "${Streaming_flow}" ]; then
  484. Streaming_flow="1:1${flowid}"
  485. eval "Cat${flowid}DownBandPercent=${drp2}"
  486. eval "Cat${flowid}DownCeilPercent=${dcp2}"
  487. eval "Cat${flowid}UpBandPercent=${urp2}"
  488. eval "Cat${flowid}UpCeilPercent=${ucp2}"
  489. else
  490. Learn_flow="1:1${flowid}"
  491. eval "Cat${flowid}DownBandPercent=${drp7}"
  492. eval "Cat${flowid}DownCeilPercent=${dcp7}"
  493. eval "Cat${flowid}UpBandPercent=${urp7}"
  494. eval "Cat${flowid}UpCeilPercent=${ucp7}"
  495. fi
  496. fi # Check Learn-From-Home and Streaming priority order
  497. ;;
  498. '7')
  499. Others_flow="1:1${flowid}"
  500. eval "Cat${flowid}DownBandPercent=${drp6}"
  501. eval "Cat${flowid}DownCeilPercent=${dcp6}"
  502. eval "Cat${flowid}UpBandPercent=${urp6}"
  503. eval "Cat${flowid}UpCeilPercent=${ucp6}"
  504. ;;
  505. '8')
  506. Gaming_flow="1:1${flowid}"
  507. eval "Cat${flowid}DownBandPercent=${drp1}"
  508. eval "Cat${flowid}DownCeilPercent=${dcp1}"
  509. eval "Cat${flowid}UpBandPercent=${urp1}"
  510. eval "Cat${flowid}UpCeilPercent=${ucp1}"
  511. ;;
  512. '9')
  513. Net_flow="1:1${flowid}"
  514. eval "Cat${flowid}DownBandPercent=${drp0}"
  515. eval "Cat${flowid}DownCeilPercent=${dcp0}"
  516. eval "Cat${flowid}UpBandPercent=${urp0}"
  517. eval "Cat${flowid}UpCeilPercent=${ucp0}"
  518. ;;
  519. '24')
  520. Web_flow="1:1${flowid}"
  521. eval "Cat${flowid}DownBandPercent=${drp4}"
  522. eval "Cat${flowid}DownCeilPercent=${dcp4}"
  523. eval "Cat${flowid}UpBandPercent=${urp4}"
  524. eval "Cat${flowid}UpCeilPercent=${ucp4}"
  525. ;;
  526. 'na')
  527. # This is how the old ASUS default category would appear, but this option will soon be deprecated
  528. # when all supported models are using the new QoS Categories.
  529. Learn_flow="1:1${flowid}"
  530. eval "Cat${flowid}DownBandPercent=${drp7}"
  531. eval "Cat${flowid}DownCeilPercent=${dcp7}"
  532. eval "Cat${flowid}UpBandPercent=${urp7}"
  533. eval "Cat${flowid}UpCeilPercent=${ucp7}"
  534. ;;
  535. esac
  536. done <<EOF
  537. $(sed -E '/^ceil_/d;s/rule=//g;/\{/q' /tmp/bwdpi/qosd.conf | head -n -1)
  538. EOF
  539.  
  540. #calculate up/down rates based on user-provided bandwidth from GUI
  541. #GUI shows in Mb/s; nvram stores in Kb/s
  542. DownCeil="$(printf "%.0f" "$(nvram get qos_ibw)")"
  543. UpCeil="$(printf "%.0f" "$(nvram get qos_obw)")"
  544.  
  545. # Only apply custom rates if Manual Bandwidth mode set in QoS page
  546. if [ "${DownCeil}" -gt "0" ] && [ "${UpCeil}" -gt "0" ]; then
  547. # Automatic bandwidth mode incompatible with custom rates
  548. i=0
  549. while [ "${i}" -lt "8" ]
  550. do
  551. eval "DownRate${i}=\$((DownCeil\*Cat${i}DownBandPercent/100))"
  552. eval "UpRate${i}=\$((UpCeil\*Cat${i}UpBandPercent/100))"
  553. eval "DownCeil${i}=\$((DownCeil\*Cat${i}DownCeilPercent/100))"
  554. eval "UpCeil${i}=\$((UpCeil\*Cat${i}UpCeilPercent/100))"
  555. i="$((i+1))"
  556. done
  557. fi # Auto Bandwidth check
  558. } # set_tc_variables
  559.  
  560. appdb() {
  561. # Search TrendMicro appdb file for matches to user-specified string. Return up to 25 matches
  562. local line cat_decimal
  563. /bin/grep -m 25 -i "${1}" /tmp/bwdpi/bwdpi.app.db | while read -r line; do
  564. echo "${line}" | awk -F "," '{printf " Application: %s\n Mark: %02X%04X\nDefault Class: ", $4, $1, $2}'
  565. cat_decimal=$(echo "${line}" | cut -f 1 -d "," )
  566. case "${cat_decimal}" in
  567. '9'|'18'|'19'|'20')
  568. printf "Net Control Packets"
  569. ;;
  570. '0'|'5'|'6'|'15'|'17')
  571. printf "Work-From-Home"
  572. ;;
  573. '8')
  574. printf "Gaming"
  575. ;;
  576. '7'|'10'|'11'|'21'|'23')
  577. printf "Others"
  578. ;;
  579. '13'|'24')
  580. printf "Web Surfing"
  581. ;;
  582. '4')
  583. printf "Video and Audio Streaming"
  584. ;;
  585. '1'|'3'|'14')
  586. printf "File Transferring"
  587. ;;
  588. *)
  589. printf "Unknown"
  590. ;;
  591. esac
  592. printf "\n\n"
  593. done
  594. } # appdb
  595.  
  596. webconfigpage() {
  597. local urlpage urlproto urldomain urlport
  598.  
  599. # Eye candy function that will construct a URL to display after install or upgrade so a user knows where to
  600. # find the webUI page. In most cases though, they will go to the Adaptive QoS tab and find the FlexQoS sub-tab anyway.
  601. urlpage="$(sed -nE "/${SCRIPTNAME_DISPLAY}/ s/.*url\: \"(user[0-9]+\.asp)\".*/\1/p" /tmp/menuTree.js)"
  602. if [ "$(nvram get http_enable)" = "1" ]; then
  603. urlproto="https"
  604. else
  605. urlproto="http"
  606. fi
  607. if [ -n "$(nvram get lan_domain)" ]; then
  608. urldomain="$(nvram get lan_hostname).$(nvram get lan_domain)"
  609. else
  610. urldomain="$(nvram get lan_ipaddr)"
  611. fi
  612. if [ "$(nvram get ${urlproto}_lanport)" = "80" ] || [ "$(nvram get ${urlproto}_lanport)" = "443" ]; then
  613. urlport=""
  614. else
  615. urlport=":$(nvram get ${urlproto}_lanport)"
  616. fi
  617.  
  618. if echo "${urlpage}" | grep -qE "user[0-9]+\.asp"; then
  619. printf "Advanced configuration available via:\n"
  620. Blue " ${urlproto}://${urldomain}${urlport}/${urlpage}"
  621. fi
  622. } # webconfigpage
  623.  
  624. scriptinfo() {
  625. # Version header used in interactive sessions
  626. [ "${mode}" = "interactive" ] || return
  627. printf "\n"
  628. Green "${SCRIPTNAME_DISPLAY} v${version} released ${release}"
  629. printf "\n"
  630. } # scriptinfo
  631.  
  632. debug() {
  633. local RMODEL ipt_debug appdb_debug
  634. [ -z "$(nvram get odmpid)" ] && RMODEL="$(nvram get productid)" || RMODEL="$(nvram get odmpid)"
  635. Green "[SPOILER=\"${SCRIPTNAME_DISPLAY} Debug\"][CODE]"
  636. scriptinfo
  637. printf "Debug date : %s\n" "$(date +'%Y-%m-%d %H:%M:%S%z')"
  638. printf "Router Model : %s\n" "${RMODEL}"
  639. printf "Firmware Ver : %s_%s\n" "$(nvram get buildno)" "$(nvram get extendno)"
  640. printf "DPI/Sig Ver : %s / %s\n" "$(nvram get bwdpi_dpi_ver)" "$(nvram get bwdpi_sig_ver)"
  641. get_config
  642. set_tc_variables
  643.  
  644. printf "WAN iface : %s\n" "${wan}"
  645. printf "tc WAN iface : %s\n" "${tcwan}"
  646. printf "IPv6 : %s\n" "${IPv6_enabled}"
  647. printf "Undf Prio : %s\n" "${undf_prio}"
  648. printf "Down Band : %s\n" "${DownCeil}"
  649. printf "Up Band : %s\n" "${UpCeil}"
  650. printf "*****************\n"
  651. printf "Net Control : %s\n" "${Net_flow}"
  652. printf "Work-From-Home : %s\n" "${Work_flow}"
  653. printf "Gaming : %s\n" "${Gaming_flow}"
  654. printf "Others : %s\n" "${Others_flow}"
  655. printf "Web Surfing : %s\n" "${Web_flow}"
  656. printf "Streaming : %s\n" "${Streaming_flow}"
  657. printf "File Transfers : %s\n" "${Downloads_flow}"
  658. printf "Learn-From-Home : %s\n" "${Learn_flow}"
  659. printf "*****************\n"
  660. # Only print custom rates if Manual Bandwidth setting is enabled on QoS page
  661. if [ "${DownCeil}" -gt "0" ] && [ "${UpCeil}" -gt "0" ]; then
  662. printf "Downrates : %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n" "${DownRate0}" "${DownRate1}" "${DownRate2}" "${DownRate3}" "${DownRate4}" "${DownRate5}" "${DownRate6}" "${DownRate7}"
  663. printf "Downceils : %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n" "${DownCeil0}" "${DownCeil1}" "${DownCeil2}" "${DownCeil3}" "${DownCeil4}" "${DownCeil5}" "${DownCeil6}" "${DownCeil7}"
  664. printf "Uprates : %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n" "${UpRate0}" "${UpRate1}" "${UpRate2}" "${UpRate3}" "${UpRate4}" "${UpRate5}" "${UpRate6}" "${UpRate7}"
  665. printf "Upceils : %7s, %7s, %7s, %7s, %7s, %7s, %7s, %7s\n" "${UpCeil0}" "${UpCeil1}" "${UpCeil2}" "${UpCeil3}" "${UpCeil4}" "${UpCeil5}" "${UpCeil6}" "${UpCeil7}"
  666. printf "*****************\n"
  667. else
  668. printf "Custom rates disabled with Automatic Bandwidth mode!\n"
  669. printf "*****************\n"
  670. fi
  671. ipt_debug="$(am_settings_get "${SCRIPTNAME}"_iptables)"
  672. printf "iptables settings: %s\n" "${ipt_debug:-Defaults}"
  673. write_iptables_rules
  674. # Remove superfluous commands from the output in order to focus on the parsed details
  675. /bin/sed -E "/^ip[6]?tables -t mangle -[FD] /d; s/ip[6]?tables -t mangle //g; s/[[:space:]]{2,}/ /g" "/tmp/${SCRIPTNAME}_iprules"
  676. printf "*****************\n"
  677. appdb_debug="$(am_settings_get "${SCRIPTNAME}"_appdb)"
  678. printf "appdb rules: %s\n" "${appdb_debug:-Defaults}"
  679. true > "/tmp/${SCRIPTNAME}_tcrules"
  680. write_appdb_rules
  681. write_custom_rates
  682. cat "/tmp/${SCRIPTNAME}_tcrules"
  683. Green "[/CODE][/SPOILER]"
  684. # Since these tmp files aren't being used to apply rules, we delete them to avoid confusion about the last known ruleset
  685. rm "/tmp/${SCRIPTNAME}_iprules" "/tmp/${SCRIPTNAME}_tcrules"
  686. printf "\n"
  687. Yellow "Copy the text from [SPOILER] to [/SPOILER] and paste into a forum post at snbforums.com"
  688. } # debug
  689.  
  690. get_flowid() {
  691. # Map class destination field from webui settings to the established class/flowid based on user priorities
  692. # flowid will be one of 1:10 - 1:17, depending on the user priority sequencing in the QoS GUI
  693. # Input: numeric class destination from iptables rule
  694. local flowid
  695. case "${1}" in
  696. 0) flowid="${Net_flow}" ;;
  697. 1) flowid="${Gaming_flow}" ;;
  698. 2) flowid="${Streaming_flow}" ;;
  699. 3) flowid="${Work_flow}" ;;
  700. 4) flowid="${Web_flow}" ;;
  701. 5) flowid="${Downloads_flow}" ;;
  702. 6) flowid="${Others_flow}" ;;
  703. 7) flowid="${Learn_flow}" ;;
  704. # return empty if destination missing
  705. *) flowid="" ;;
  706. esac
  707. printf "%s\n" "${flowid}"
  708. } # get_flowid
  709.  
  710. Is_Valid_CIDR() {
  711. /bin/grep -qE '^[!]?([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?$'
  712. } # Is_Valid_CIDR
  713.  
  714. Is_Valid_Port() {
  715. /bin/grep -qE '^[!]?([0-9]{1,5})((:[0-9]{1,5})?|(,[0-9]{1,5})*)$'
  716. } # Is_Valid_Port
  717.  
  718. Is_Valid_Mark() {
  719. /bin/grep -qE '^[!]?[A-Fa-f0-9]{2}([A-Fa-f0-9]{4}|[\*]{4})$'
  720. } # Is_Valid_Mark
  721.  
  722. parse_appdb_rule() {
  723. # Process an appdb custom rule into the appropriate tc filter syntax
  724. # Input: $1 = Mark from appdb rule XXYYYY XX=Category(hex) YYYY=ID(hex or ****)
  725. # $2 = Class destination
  726. # Output: stdout is written directly to the /tmp/flexqos_appdb_rules file via redirect in write_appdb_rules(),
  727. # so don't add unnecessary output in this function.
  728. local cat id
  729. local DOWN_mark UP_mark
  730. local flowid
  731. local currmask
  732. local prio currprio
  733. local currhandledown currhandleup
  734. # Only process if Mark is a valid format
  735. if echo "${1}" | Is_Valid_Mark; then
  736. # Extract category and appid from mark
  737. cat="$(echo "${1}" | cut -c 1-2)"
  738. id="$(echo "${1}" | cut -c 3-6)"
  739. # check if wildcard mark
  740. if [ "${id}" = "****" ]; then
  741. # Replace asterisks with zeros and use category mask
  742. # This mark and mask
  743. DOWN_mark="0x80${cat}0000 0xc03f0000"
  744. UP_mark="0x40${cat}0000 0xc03f0000"
  745. elif [ "${1}" = "000000" ]; then
  746. # unidentified traffic needs a special mask
  747. DOWN_mark="0x80${1} 0xc000ffff"
  748. UP_mark="0x40${1} 0xc000ffff"
  749. else
  750. # specific application mark
  751. DOWN_mark="0x80${1} 0xc03fffff"
  752. UP_mark="0x40${1} 0xc03fffff"
  753. fi
  754.  
  755. # get destination class
  756. flowid="$(get_flowid "${2}")"
  757.  
  758. # To override the default tc filters with our custom filter rules, we need to insert our rules
  759. # at a higher priority (lower number) than the built-in filter for each category.
  760. if [ "${1}" = "000000" ]; then
  761. # special mask for unidentified traffic
  762. currmask="0xc000ffff"
  763. else
  764. currmask="0xc03f0000"
  765. fi
  766. # search the tc filter temp file we made in write_appdb_rules() for the existing priority of the
  767. # category we are going to override with a custom appdb filter rule.
  768. # e.g. If we are going to make a rule for appdb mark 1400C5, we need to find the current priority of category 14.
  769. prio="$(/bin/grep -i -m 1 -B1 "0x80${cat}0000 ${currmask}" "/tmp/${SCRIPTNAME}_tmp_tcfilterdown" | sed -nE 's/.* pref ([0-9]+) .*/\1/p')"
  770. currprio="${prio}"
  771.  
  772. # If there is no existing filter for the category, use the undf_prio defined in set_tc_variables().
  773. # This is usually only necessary for Untracked traffic (mark 000000).
  774. # Otherwise, take the current priority and subtract 1 so that our rule will be processed earlier than the default rule.
  775. if [ -z "${prio}" ]; then
  776. prio="${undf_prio}"
  777. else
  778. prio="$((prio-1))"
  779. fi
  780.  
  781. # Build and echo the tc filter commands based on the possible actions required:
  782. # 1. Change an existing filter to point to a new flowid (mostly relevant for wildcard appdb rules).
  783. # 2. Insert a new filter at a higher priority than the existing filter that would otherwise match this mark.
  784. if { [ "${id}" = "****" ] || [ "${1}" = "000000" ]; } && [ -n "${currprio}" ]; then
  785. # change existing rule for wildcard marks and Untracked mark only if current priority already determined.
  786. # Need to get handle of existing filter for proper tc filter change syntax.
  787. currhandledown="$(/bin/grep -i -m 1 -B1 "0x80${cat}0000 ${currmask}" "/tmp/${SCRIPTNAME}_tmp_tcfilterdown" | sed -nE 's/.* fh ([0-9a-f:]+) .*/\1/p')"
  788. currhandleup="$(/bin/grep -i -m 1 -B1 "0x40${cat}0000 ${currmask}" "/tmp/${SCRIPTNAME}_tmp_tcfilterup" | sed -nE 's/.* fh ([0-9a-f:]+) .*/\1/p')"
  789. printf "filter change dev %s prio %s protocol all handle %s u32 flowid %s\n" "${tclan}" "${currprio}" "${currhandledown}" "${flowid}"
  790. printf "filter change dev %s prio %s protocol all handle %s u32 flowid %s\n" "${tcwan}" "${currprio}" "${currhandleup}" "${flowid}"
  791. else
  792. # add new rule for individual app one priority level higher (-1)
  793. printf "filter add dev %s protocol all prio %s u32 match mark %s flowid %s\n" "${tclan}" "${prio}" "${DOWN_mark}" "${flowid}"
  794. printf "filter add dev %s protocol all prio %s u32 match mark %s flowid %s\n" "${tcwan}" "${prio}" "${UP_mark}" "${flowid}"
  795. fi
  796. fi # Is_Valid_Mark
  797. } # parse_appdb_rule
  798.  
  799. create_ipset() {
  800. # To translate IPv4 iptables rules using local IPv4 addresses, create 2 ipsets and 2 iptables rules to track
  801. # corresponding IPv6 addresses for a given IPv4 local address
  802. # Input: $1 = local IP/CIDR (minus optional negation)
  803. # Output: stdout ipset and iptables commands
  804. local LOCALIP IPV6LIFETIME IPV6RASTATE
  805.  
  806. # If IPv6 is disabled, return early
  807. [ "${IPv6_enabled}" = "disabled" ] && return
  808.  
  809. # Strip optional negation if present
  810. LOCALIP="${1}"
  811. IPV6RASTATE="$(nvram get ipv6_autoconf_type)" # 0=Stateless, 1=Stateful
  812. ipset -! create "${LOCALIP}-mac" hash:mac timeout "$(nvram get dhcp_lease)" 2>/dev/null
  813. ipset -! flush "${LOCALIP}-mac" 2>/dev/null
  814.  
  815. case "${IPv6_enabled}" in
  816. dhcp6|other) #Native or Static
  817. if [ "${IPV6RASTATE}" = "1" ]; then
  818. # Stateful, get DHCP Lifetime
  819. IPV6LIFETIME="$(nvram get ipv6_dhcp_lifetime)"
  820. else
  821. # Stateless, use hard-coded value from firmware
  822. IPV6LIFETIME=600
  823. fi
  824. ;;
  825. *)
  826. IPV6LIFETIME=600
  827. ;;
  828. esac
  829.  
  830. ipset -! create "${LOCALIP}" hash:ip family inet6 timeout "${IPV6LIFETIME}" 2>/dev/null
  831. ipset -! flush "${LOCALIP}" 2>/dev/null
  832.  
  833. printf "iptables -t mangle -D PREROUTING -i %s -m conntrack --ctstate NEW -s %s -j SET --add-set %s-mac src --exist 2>/dev/null\n" "${lan}" "${LOCALIP}" "${LOCALIP}"
  834. printf "ip6tables -t mangle -D PREROUTING -i %s -m conntrack --ctstate NEW -m set --match-set %s-mac src -j SET --add-set %s src --exist 2>/dev/null\n" "${lan}" "${LOCALIP}" "${LOCALIP}"
  835. printf "iptables -t mangle -I PREROUTING -i %s -m conntrack --ctstate NEW -s %s -j SET --add-set %s-mac src --exist\n" "${lan}" "${LOCALIP}" "${LOCALIP}"
  836. printf "ip6tables -t mangle -I PREROUTING -i %s -m conntrack --ctstate NEW -m set --match-set %s-mac src -j SET --add-set %s src --exist\n" "${lan}" "${LOCALIP}" "${LOCALIP}"
  837. }
  838.  
  839. parse_iptablerule() {
  840. # Process an iptables custom rule into the appropriate iptables syntax
  841. # Input: $1 = local IP (e.g. 192.168.1.100 !192.168.1.100 192.168.1.100/31 !192.168.1.100/31)
  842. # $2 = remote IP (e.g. 9.9.9.9 !9.9.9.9 9.9.9.0/24 !9.9.9.0/24)
  843. # $3 = protocol (e.g. both, tcp, or udp)
  844. # $4 = local port (e.g. 443 !443 1234:5678 !1234:5678 53,123,853 !53,123,853)
  845. # $5 = remote port (e.g. 443 !443 1234:5678 !1234:5678 53,123,853 !53,123,853)
  846. # $6 = mark (e.g. XXYYYY !XXYYYY XX=Category(hex) YYYY=ID(hex or ****))
  847. # $7 = class destination (e.g. 0-7)
  848. # Output: stdout is written directly to the /tmp/flexqos_iprules file via redirect in write_iptables_rules(),
  849. # so don't add unnecessary output in this function.
  850. local DOWN_Lip UP_Lip CIDR
  851. local DOWN_Lip6 UP_Lip6
  852. local DOWN_Rip UP_Rip
  853. local PROTOS proto
  854. local DOWN_Lport UP_Lport
  855. local DOWN_Rport UP_Rport
  856. local tmpMark DOWN_mark UP_mark
  857. local DOWN_dst UP_dst Dst_mark
  858. # local IP
  859. # Check for acceptable IP format
  860. if echo "${1}" | Is_Valid_CIDR; then
  861. # print ! (if present) and remaining CIDR
  862. DOWN_Lip="$(echo "${1}" | sed -E 's/^([!])?/\1 -d /')"
  863. UP_Lip="$(echo "${1}" | sed -E 's/^([!])?/\1 -s /')"
  864. # Only create ipset if there is no remote IP/CIDR defined, since the IPv6 rule would not work with remote IPv4 CIDR
  865. if ! echo "${2}" | Is_Valid_CIDR; then
  866. # Alternate syntax for IPv6 ipset matching
  867. CIDR="$(echo "${1}" | sed -E 's/^!//')"
  868. create_ipset "${CIDR}" # 2>/dev/null
  869. DOWN_Lip6="$(echo "${1}" | sed -E 's/^([!])?(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)/-m set \1 --match-set \2 dst/')"
  870. UP_Lip6="$(echo "${1}" | sed -E 's/^([!])?(([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?)/-m set \1 --match-set \2 src/')"
  871. fi
  872. else
  873. DOWN_Lip=""
  874. UP_Lip=""
  875. DOWN_Lip6=""
  876. UP_Lip6=""
  877. fi
  878.  
  879. # remote IP
  880. # Check for acceptable IP format
  881. if echo "${2}" | Is_Valid_CIDR; then
  882. # print ! (if present) and remaining CIDR
  883. DOWN_Rip="$(echo "${2}" | sed -E 's/^([!])?/\1 -s /')"
  884. UP_Rip="$(echo "${2}" | sed -E 's/^([!])?/\1 -d /')"
  885. else
  886. DOWN_Rip=""
  887. UP_Rip=""
  888. fi
  889.  
  890. # protocol (required when port specified)
  891. if [ "${3}" = "tcp" ] || [ "${3}" = "udp" ]; then
  892. # print protocol directly
  893. PROTOS="${3}"
  894. elif [ "${#4}" -gt "1" ] || [ "${#5}" -gt "1" ]; then
  895. # proto=both & ports are defined
  896. PROTOS="tcp>udp" # separated by > because IFS will be temporarily set to '>' by calling function. TODO Fix Me
  897. else
  898. # neither proto nor ports defined
  899. PROTOS="all"
  900. fi
  901.  
  902. # local port
  903. if echo "${4}" | Is_Valid_Port; then
  904. # Use multiport to specify any port specification:
  905. # single port, multiple ports, port range
  906. DOWN_Lport="-m multiport $(echo "${4}" | sed -E 's/^([!])?/\1 --dports /')"
  907. UP_Lport="-m multiport $(echo "${4}" | sed -E 's/^([!])?/\1 --sports /')"
  908. else
  909. DOWN_Lport=""
  910. UP_Lport=""
  911. fi
  912.  
  913. # remote port
  914. if echo "${5}" | Is_Valid_Port; then
  915. # Use multiport to specify any port specification:
  916. # single port, multiple ports, port range
  917. DOWN_Rport="-m multiport $(echo "${5}" | sed -E 's/^([!])?/\1 --sports /')"
  918. UP_Rport="-m multiport $(echo "${5}" | sed -E 's/^([!])?/\1 --dports /')"
  919. else
  920. DOWN_Rport=""
  921. UP_Rport=""
  922. fi
  923.  
  924. # mark
  925. if echo "${6}" | Is_Valid_Mark; then
  926. tmpMark="${6}" # Use a tmp variable since we have to manipulate the contents for ! and ****
  927. DOWN_mark="-m mark"
  928. UP_mark="-m mark"
  929. if [ "$(echo "${tmpMark}" | cut -c 1)" = "!" ]; then # first char is !
  930. DOWN_mark="${DOWN_mark} !"
  931. UP_mark="${UP_mark} !"
  932. tmpMark="$(echo "${tmpMark}" | sed -E 's/^!//')" # strip the !
  933. fi
  934. # Extract category and appid from mark
  935. cat="$(echo "${tmpMark}" | cut -c 1-2)"
  936. id="$(echo "${tmpMark}" | cut -c 3-6)"
  937. # check if wildcard mark
  938. if [ "${id}" = "****" ]; then
  939. # replace **** with 0000 and use category mask
  940. DOWN_mark="${DOWN_mark} --mark 0x80${cat}0000/0xc03f0000"
  941. UP_mark="${UP_mark} --mark 0x40${cat}0000/0xc03f0000"
  942. else
  943. DOWN_mark="${DOWN_mark} --mark 0x80${tmpMark}/0xc03fffff"
  944. UP_mark="${UP_mark} --mark 0x40${tmpMark}/0xc03fffff"
  945. fi
  946. else
  947. DOWN_mark=""
  948. UP_mark=""
  949. fi
  950.  
  951. # if all parameters are empty stop processing the rule
  952. if [ -z "${DOWN_Lip}${DOWN_Rip}${DOWN_Lport}${DOWN_Rport}${DOWN_mark}" ]; then
  953. return
  954. fi
  955.  
  956. # destination mark
  957. # numbers come from webui select options for class field
  958. Dst_mark="$(get_class_mark "${7}")"
  959. if [ -z "${Dst_mark}" ]; then
  960. return
  961. fi
  962. DOWN_dst="-j MARK --set-mark 0x80${Dst_mark}ffff/0xc03fffff"
  963. UP_dst="-j MARK --set-mark 0x40${Dst_mark}ffff/0xc03fffff"
  964.  
  965. # This block is redirected to the /tmp/flexqos_iprules file, so no extraneous output, please
  966. # If proto=both we have to create 2 statements, one for tcp and one for udp.
  967. for proto in ${PROTOS}; do
  968. # download ipv4
  969. printf "iptables -t mangle -A %s %s %s -p %s %s %s %s %s\n" "${SCRIPTNAME_DISPLAY}_down" "${DOWN_Lip}" "${DOWN_Rip}" "${proto}" "${DOWN_Lport}" "${DOWN_Rport}" "${DOWN_mark}" "${DOWN_dst}"
  970. # upload ipv4
  971. printf "iptables -t mangle -A %s %s %s -p %s %s %s %s %s\n" "${SCRIPTNAME_DISPLAY}_up" "${UP_Lip}" "${UP_Rip}" "${proto}" "${UP_Lport}" "${UP_Rport}" "${UP_mark}" "${UP_dst}"
  972. # If rule contains no IPv4 remote addresses, and IPv6 is enabled, add a corresponding rule for IPv6
  973. if [ "${IPv6_enabled}" != "disabled" ] && [ -z "${DOWN_Rip}" ]; then
  974. # download ipv6
  975. printf "ip6tables -t mangle -A %s %s -p %s %s %s %s %s\n" "${SCRIPTNAME_DISPLAY}_down" "${DOWN_Lip6}" "${proto}" "${DOWN_Lport}" "${DOWN_Rport}" "${DOWN_mark}" "${DOWN_dst}"
  976. # upload ipv6
  977. printf "ip6tables -t mangle -A %s %s -p %s %s %s %s %s\n" "${SCRIPTNAME_DISPLAY}_up" "${UP_Lip6}" "${proto}" "${UP_Lport}" "${UP_Rport}" "${UP_mark}" "${UP_dst}"
  978. fi
  979. done
  980. } # parse_iptablerule
  981.  
  982. about() {
  983. scriptinfo
  984. cat <<EOF
  985. License
  986. ${SCRIPTNAME_DISPLAY} is free to use under the GNU General Public License, version 3 (GPL-3.0).
  987. https://opensource.org/licenses/GPL-3.0
  988.  
  989. For discussion visit this thread:
  990. https://www.snbforums.com/forums/asuswrt-merlin-addons.60/?prefix_id=8
  991. https://github.com/dave14305/FlexQoS (Source Code)
  992.  
  993. About
  994. Script Changes Unidentified traffic destination away from Work-From-Home into Others
  995. Script Changes HTTPS traffic destination away from Net Control into Web Surfing
  996. Script Changes Guaranteed Bandwidth per QoS category into logical percentages of upload and download.
  997. Script includes misc default rules
  998. (Wifi Calling) - UDP traffic on remote ports 500 & 4500 moved into Work-From-Home
  999. (Facetime) - UDP traffic on local ports 16384 - 16415 moved into Work-From-Home
  1000. (Usenet) - TCP traffic on remote ports 119 & 563 moved into File Transfers
  1001. (Gaming) - Gaming TCP traffic from remote ports 80 & 443 moved into File Transfers.
  1002. (Snapchat) - Moved into Others
  1003. (Speedtest.net) - Moved into File Transfers
  1004. (Google Play) - Moved into File Transfers
  1005. (Apple AppStore)- Moved into File Transfers
  1006. (VPN Fix) - Router VPN Client upload traffic moved into File Transfers instead of whitelisted
  1007. (Gaming Manual) - Unidentified traffic for specified devices, not originating from ports 80/443, moved into Gaming
  1008.  
  1009. Gaming Rule Note
  1010. Gaming traffic originating from ports 80 & 443 is primarily downloads & patches (some lobby/login protocols mixed within)
  1011. Manually configurable rule will take untracked traffic for specified devices, not originating from server ports 80/443, and place it into Gaming
  1012. Use of this gaming rule REQUIRES devices to have a continuous static ip assignment & this range needs to be passed into the script
  1013. EOF
  1014. }
  1015.  
  1016. backup() {
  1017. # Backup existing user rules in /jffs/addons/custom_settings.txt
  1018. # Input: create [force]|restore|remove
  1019. case "${1}" in
  1020. 'create')
  1021. if [ "${2}" != "force" ] && [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1022. grep "# Backup date" "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1023. printf "A backup already exists. Do you want to overwrite this backup? [1=Yes 2=No]: "
  1024. read -r yn
  1025. if [ "${yn}" != "1" ]; then
  1026. Yellow "Backup cancelled."
  1027. return
  1028. fi
  1029. fi
  1030. printf "Running backup...\n"
  1031. {
  1032. printf "#!/bin/sh\n"
  1033. printf "# Backup date: %s\n" "$(date +'%Y-%m-%d %H:%M:%S%z')"
  1034. printf ". /usr/sbin/helper.sh\n"
  1035. [ -n "$(am_settings_get "${SCRIPTNAME}"_iptables)" ] && printf "am_settings_set %s_iptables \"%s\"\n" "${SCRIPTNAME}" "$(am_settings_get "${SCRIPTNAME}"_iptables)"
  1036. [ -n "$(am_settings_get "${SCRIPTNAME}"_iptables_names)" ] && printf "am_settings_set %s_iptables_names \"%s\"\n" "${SCRIPTNAME}" "$(am_settings_get "${SCRIPTNAME}"_iptables_names)"
  1037. [ -n "$(am_settings_get "${SCRIPTNAME}"_appdb)" ] && printf "am_settings_set %s_appdb \"%s\"\n" "${SCRIPTNAME}" "$(am_settings_get "${SCRIPTNAME}"_appdb)"
  1038. [ -n "$(am_settings_get "${SCRIPTNAME}"_bwrates)" ] && printf "am_settings_set %s_bwrates \"%s\"\n" "${SCRIPTNAME}" "$(am_settings_get "${SCRIPTNAME}"_bwrates)"
  1039. [ -n "$(am_settings_get "${SCRIPTNAME}"_qdisc)" ] && printf "am_settings_set %s_qdisc \"%s\"\n" "${SCRIPTNAME}" "$(am_settings_get "${SCRIPTNAME}"_qdisc)"
  1040. } > "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1041. if /bin/grep -q "${SCRIPTNAME}_" "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"; then
  1042. Green "Backup done to ${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1043. else
  1044. rm "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1045. Yellow "Backup cancelled. All settings using default values."
  1046. fi
  1047. ;;
  1048. 'restore')
  1049. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1050. Yellow "$(grep "# Backup date" "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh")"
  1051. printf "Do you want to restore this backup? [1=Yes 2=No]: "
  1052. read -r yn
  1053. if [ "${yn}" = "1" ]; then
  1054. sh "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1055. Green "Backup restored!"
  1056. needrestart=1
  1057. else
  1058. Yellow "Restore cancelled."
  1059. fi
  1060. else
  1061. Red "No backup file exists!"
  1062. fi
  1063. ;;
  1064. 'remove')
  1065. [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ] && rm "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1066. Green "Backup deleted."
  1067. ;;
  1068. esac
  1069. } # backup
  1070.  
  1071. download_file() {
  1072. # Download file from Github once to a temp location. If the same as the destination file, don't replace.
  1073. # Otherwise move it from the temp location to the destination.
  1074. if curl -fsL --retry 3 --connect-timeout 3 "${GIT_URL}/${1}" -o "/tmp/${1}"; then
  1075. if [ "$(md5sum "/tmp/${1}" | awk '{print $1}')" != "$(md5sum "${2}" 2>/dev/null | awk '{print $1}')" ]; then
  1076. mv -f "/tmp/${1}" "${2}"
  1077. logmsg "Updated $(basename "${1}")"
  1078. else
  1079. logmsg "File $(basename "${2}") is already up-to-date"
  1080. rm -f "/tmp/${1}" 2>/dev/null
  1081. fi
  1082. else
  1083. logmsg "Updating $(basename "${1}") failed"
  1084. fi
  1085. } # download_file
  1086.  
  1087. compare_remote_version() {
  1088. # Check version on Github and determine the difference with the installed version
  1089. # Outcomes: Version update, or no update
  1090. local remotever
  1091. # Fetch version of the shell script on Github
  1092. remotever="$(curl -fsN --retry 3 --connect-timeout 3 "${GIT_URL}/$(basename "${SCRIPTPATH}")" | /bin/grep "^version=" | sed -e 's/version=//')"
  1093. if [ "$( echo "${version}" | sed 's/\.//g' )" -lt "$( echo "${remotever}" | sed 's/\.//g' )" ]; then # strip the . from version string for numeric comparison
  1094. # version upgrade
  1095. echo "${remotever}"
  1096. else
  1097. printf "NoUpdate\n"
  1098. fi
  1099. } # compare_remote_version
  1100.  
  1101. update() {
  1102. # Check for, and optionally apply updates.
  1103. # Parameter options: check (do not update), silent (update without prompting)
  1104. local updatestatus yn
  1105. scriptinfo
  1106. printf "Checking for updates\n"
  1107. # Update the webui status thorugh detect_update.js ajax call.
  1108. printf "var verUpdateStatus = \"%s\";\n" "InProgress" > "/www/ext/${SCRIPTNAME}/detect_update.js"
  1109. updatestatus="$(compare_remote_version)"
  1110. # Check to make sure we got back a valid status from compare_remote_version(). If not, indicate Error.
  1111. case "${updatestatus}" in
  1112. 'NoUpdate'|[0-9].[0-9].[0-9]) ;;
  1113. *) updatestatus="Error"
  1114. esac
  1115. printf "var verUpdateStatus = \"%s\";\n" "${updatestatus}" > "/www/ext/${SCRIPTNAME}/detect_update.js"
  1116.  
  1117. if [ "${1}" = "check" ]; then
  1118. # Do not proceed with any updating if check function requested
  1119. return
  1120. fi
  1121. if [ "${mode}" = "interactive" ] && [ -z "${1}" ]; then
  1122. case "${updatestatus}" in
  1123. 'NoUpdate')
  1124. Green " You have the latest version installed"
  1125. printf " Would you like to overwrite your existing installation anyway? [1=Yes 2=No]: "
  1126. ;;
  1127. 'Error')
  1128. Red " Error determining remote version status!"
  1129. PressEnter
  1130. return
  1131. ;;
  1132. *)
  1133. # New Version Number
  1134. Green " ${SCRIPTNAME_DISPLAY} v${updatestatus} is now available!"
  1135. printf " Would you like to update now? [1=Yes 2=No]: "
  1136. ;;
  1137. esac
  1138. read -r yn
  1139. printf "\n"
  1140. if [ "${yn}" != "1" ]; then
  1141. Green " No Changes have been made"
  1142. return 0
  1143. fi
  1144. fi
  1145. printf "Installing: %s...\n\n" "${SCRIPTNAME_DISPLAY}"
  1146. download_file "$(basename "${SCRIPTPATH}")" "${SCRIPTPATH}"
  1147. exec sh "${SCRIPTPATH}" -install "${1}"
  1148. exit
  1149. } # update
  1150.  
  1151. prompt_restart() {
  1152. # Restart QoS so that FlexQoS changes can take effect.
  1153. # Possible values for $needrestart:
  1154. # 0: No restart needed (initialized in main)
  1155. # 1: Restart needed, but prompt user if interactive session
  1156. # 2: Restart needed, do not prompt (force)
  1157. local yn
  1158. if [ "${needrestart}" -gt "0" ]; then
  1159. if [ "${mode}" = "interactive" ]; then
  1160. if [ "${needrestart}" = "1" ]; then
  1161. printf "\nWould you like to restart QoS for modifications to take effect? [1=Yes 2=No]: "
  1162. read -r yn
  1163. if [ "${yn}" = "2" ]; then
  1164. needrestart=0
  1165. return
  1166. fi
  1167. fi
  1168. fi
  1169. printf "Restarting QoS and firewall...\n"
  1170. service "restart_qos;restart_firewall"
  1171. needrestart=0
  1172. fi
  1173. } # prompt_restart
  1174.  
  1175. menu() {
  1176. # Minimal interactive, menu-driven interface for basic maintenance functions.
  1177. local yn
  1178. [ "${mode}" = "interactive" ] || return
  1179. clear
  1180. sed -n '2,10p' "${0}" # display banner
  1181. scriptinfo
  1182. printf " (1) about explain functionality\n"
  1183. printf " (2) update check for updates\n"
  1184. printf " (3) debug traffic control parameters\n"
  1185. printf " (4) restart restart QoS\n"
  1186. printf " (5) backup create settings backup\n"
  1187. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1188. printf " (6) restore restore settings from backup\n"
  1189. printf " (7) delete remove backup\n"
  1190. fi
  1191. printf "\n (9) uninstall uninstall script\n"
  1192. printf " (e) exit\n"
  1193. printf "\nMake a selection: "
  1194. read -r input
  1195. case "${input}" in
  1196. '1')
  1197. about
  1198. ;;
  1199. '2')
  1200. update
  1201. ;;
  1202. '3')
  1203. debug
  1204. ;;
  1205. '4')
  1206. needrestart=1
  1207. prompt_restart
  1208. ;;
  1209. '5')
  1210. backup create
  1211. ;;
  1212. '6')
  1213. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1214. backup restore
  1215. else
  1216. Red "$input is not a valid option!"
  1217. fi
  1218. ;;
  1219. '7')
  1220. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1221. backup remove
  1222. else
  1223. Red "$input is not a valid option!"
  1224. fi
  1225. ;;
  1226. '9')
  1227. scriptinfo
  1228. printf " Do you want to uninstall %s [1=Yes 2=No]: " "${SCRIPTNAME_DISPLAY}"
  1229. read -r yn
  1230. if [ "${yn}" = "1" ]; then
  1231. printf "\n"
  1232. sh "${SCRIPTPATH}" -uninstall
  1233. printf "\n"
  1234. exit
  1235. fi
  1236. printf "\n"
  1237. Yellow "${SCRIPTNAME_DISPLAY} has NOT been uninstalled"
  1238. ;;
  1239. 'e'|'E'|'exit')
  1240. return
  1241. ;;
  1242. *)
  1243. Red "$input is not a valid option!"
  1244. ;;
  1245. esac
  1246. PressEnter
  1247. menu # stay in the menu loop until exit is chosen
  1248. } # menu
  1249.  
  1250. remove_webui() {
  1251. local prev_webui_page
  1252. local FD
  1253. printf "Removing WebUI...\n"
  1254. prev_webui_page="$(sed -nE "s/^\{url\: \"(user[0-9]+\.asp)\"\, tabName\: \"${SCRIPTNAME_DISPLAY}\"\}\,$/\1/p" /tmp/menuTree.js 2>/dev/null)"
  1255. if [ -n "${prev_webui_page}" ]; then
  1256. # Remove page from the UI menu system
  1257. FD=386
  1258. eval exec "${FD}>${LOCKFILE}"
  1259. /usr/bin/flock -x "${FD}"
  1260. umount /www/require/modules/menuTree.js 2>/dev/null
  1261. sed -i "\~tabName: \"${SCRIPTNAME_DISPLAY}\"},~d" /tmp/menuTree.js
  1262. if diff -q /tmp/menuTree.js /www/require/modules/menuTree.js >/dev/null 2>&1; then
  1263. # no more custom pages mounted, so remove the file
  1264. rm /tmp/menuTree.js
  1265. else
  1266. # Still some modifications from another script so remount
  1267. mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
  1268. fi
  1269. /usr/bin/flock -u "${FD}"
  1270. # Remove last mounted asp page
  1271. rm -f "/www/user/${prev_webui_page}" 2>/dev/null
  1272. # Look for previously mounted asp pages that are orphaned now and delete them
  1273. /bin/grep -l "${SCRIPTNAME_DISPLAY} maintained by dave14305" /www/user/user*.asp 2>/dev/null | while read -r oldfile
  1274. do
  1275. rm "${oldfile}"
  1276. done
  1277. fi
  1278. rm -rf "/www/ext/${SCRIPTNAME}" 2>/dev/null # remove js helper scripts
  1279. } # remove_webui
  1280.  
  1281. install_webui() {
  1282. local prev_webui_page
  1283. local FD
  1284. # if this is an install or update...otherwise it's a normal startup/mount
  1285. if [ -z "${1}" ]; then
  1286. printf "Downloading WebUI files...\n"
  1287. download_file "$(basename "${WEBUIPATH}")" "${WEBUIPATH}"
  1288. # cleanup obsolete files from previous versions
  1289. [ -L "/www/ext/${SCRIPTNAME}" ] && rm "/www/ext/${SCRIPTNAME}" 2>/dev/null
  1290. [ -d "${ADDON_DIR}/table" ] && rm -r "${ADDON_DIR}/table"
  1291. [ -f "${ADDON_DIR}/${SCRIPTNAME}_arrays.js" ] && rm "${ADDON_DIR}/${SCRIPTNAME}_arrays.js"
  1292. fi
  1293. FD=386
  1294. eval exec "${FD}>${LOCKFILE}"
  1295. /usr/bin/flock -x "${FD}"
  1296. # Check if the webpage is already mounted in the GUI and reuse that page
  1297. prev_webui_page="$(sed -nE "s/^\{url\: \"(user[0-9]+\.asp)\"\, tabName\: \"${SCRIPTNAME_DISPLAY}\"\}\,$/\1/p" /tmp/menuTree.js 2>/dev/null)"
  1298. if [ -n "${prev_webui_page}" ]; then
  1299. # use the same filename as before
  1300. am_webui_page="${prev_webui_page}"
  1301. else
  1302. # get a new mountpoint
  1303. am_get_webui_page "${WEBUIPATH}"
  1304. fi
  1305. if [ "${am_webui_page}" = "none" ]; then
  1306. logmsg "No API slots available to install web page"
  1307. else
  1308. cp -p "${WEBUIPATH}" "/www/user/${am_webui_page}"
  1309. if [ ! -f /tmp/menuTree.js ]; then
  1310. cp /www/require/modules/menuTree.js /tmp/
  1311. mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
  1312. fi
  1313. if ! /bin/grep -q "{url: \"$am_webui_page\", tabName: \"${SCRIPTNAME_DISPLAY}\"}," /tmp/menuTree.js; then
  1314. umount /www/require/modules/menuTree.js 2>/dev/null
  1315. sed -i "\~{url: \"$am_webui_page\"~d; \~tabName: \"${SCRIPTNAME_DISPLAY}\"},~d" /tmp/menuTree.js
  1316. sed -i "/url: \"QoS_Stats.asp\", tabName:/i {url: \"$am_webui_page\", tabName: \"${SCRIPTNAME_DISPLAY}\"}," /tmp/menuTree.js
  1317. mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
  1318. fi
  1319. fi
  1320. /usr/bin/flock -u "${FD}"
  1321. [ ! -d "/www/ext/${SCRIPTNAME}" ] && mkdir -p "/www/ext/${SCRIPTNAME}"
  1322. }
  1323.  
  1324. Init_UserScript() {
  1325. # Properly setup an empty Merlin user script
  1326. local userscript
  1327. if [ -z "${1}" ]; then
  1328. return
  1329. fi
  1330. userscript="/jffs/scripts/$1"
  1331. if [ ! -f "${userscript}" ]; then
  1332. # If script doesn't exist yet, create with shebang
  1333. printf "#!/bin/sh\n\n" > "${userscript}"
  1334. elif [ -f "${userscript}" ] && ! head -1 "${userscript}" | /bin/grep -qE "^#!/bin/sh"; then
  1335. # Script exists but no shebang, so insert it at line 1
  1336. sed -i '1s~^~#!/bin/sh\n~' "${userscript}"
  1337. elif [ "$(tail -c1 "${userscript}" | wc -l)" = "0" ]; then
  1338. # Script exists with shebang, but no linefeed before EOF; makes appending content unpredictable if missing
  1339. printf "\n" >> "${userscript}"
  1340. fi
  1341. if [ ! -x "${userscript}" ]; then
  1342. # Ensure script is executable by owner
  1343. chmod 755 "${userscript}"
  1344. fi
  1345. } # Init_UserScript
  1346.  
  1347. Auto_ServiceEventEnd() {
  1348. # Borrowed from Adamm00
  1349. # https://github.com/Adamm00/IPSet_ASUS/blob/master/firewall.sh
  1350. local cmdline
  1351. Init_UserScript "service-event-end"
  1352. # Delete existing lines related to this script
  1353. sed -i "\~${SCRIPTNAME_DISPLAY} Addition~d" /jffs/scripts/service-event-end
  1354. # Add line to handle wrs and sig_check events that require reapplying settings
  1355. cmdline="if [ \"\$2\" = \"wrs\" ] || [ \"\$2\" = \"sig_check\" ]; then { sh ${SCRIPTPATH} -start & } ; fi # ${SCRIPTNAME_DISPLAY} Addition"
  1356. echo "${cmdline}" >> /jffs/scripts/service-event-end
  1357. # Add line to handle other events triggered from webui
  1358. cmdline="if echo \"\$2\" | /bin/grep -q \"^${SCRIPTNAME}\"; then { sh ${SCRIPTPATH} \"\${2#${SCRIPTNAME}}\" & } ; fi # ${SCRIPTNAME_DISPLAY} Addition"
  1359. echo "${cmdline}" >> /jffs/scripts/service-event-end
  1360. } # Auto_ServiceEventEnd
  1361.  
  1362. Auto_FirewallStart() {
  1363. # Borrowed from Adamm00
  1364. # https://github.com/Adamm00/IPSet_ASUS/blob/master/firewall.sh
  1365. local cmdline
  1366. Init_UserScript "firewall-start"
  1367. # Delete existing lines related to this script
  1368. sed -i "\~${SCRIPTNAME_DISPLAY} Addition~d" /jffs/scripts/firewall-start
  1369. # Add line to trigger script on firewall startup
  1370. cmdline="sh ${SCRIPTPATH} -start & # ${SCRIPTNAME_DISPLAY} Addition"
  1371. if /bin/grep -vE "^#" /jffs/scripts/firewall-start | /bin/grep -q "Skynet"; then
  1372. # If Skynet also installed, insert this script before Skynet so it doesn't have to wait for Skynet to startup before applying QoS
  1373. # Won't delay Skynet startup since we fork into the background
  1374. sed -i "/Skynet/i ${cmdline}" /jffs/scripts/firewall-start
  1375. else
  1376. # Skynet not installed, so just append
  1377. echo "${cmdline}" >> /jffs/scripts/firewall-start
  1378. fi # is Skynet also installed?
  1379. } # Auto_FirewallStart
  1380.  
  1381. setup_aliases() {
  1382. # shortcuts to launching script
  1383. local cmdline
  1384. if [ -d /opt/bin ]; then
  1385. # Entware is installed, so setup link to /opt/bin
  1386. printf "Adding %s link in Entware /opt/bin...\n" "${SCRIPTNAME}"
  1387. ln -sf "${SCRIPTPATH}" "/opt/bin/${SCRIPTNAME}"
  1388. else
  1389. # Setup shell alias
  1390. printf "Adding %s alias in profile.add...\n" "${SCRIPTNAME}"
  1391. sed -i "/alias ${SCRIPTNAME}/d" /jffs/configs/profile.add 2>/dev/null
  1392. cmdline="alias ${SCRIPTNAME}=\"sh ${SCRIPTPATH}\" # ${SCRIPTNAME_DISPLAY} Addition"
  1393. echo "${cmdline}" >> /jffs/configs/profile.add
  1394. fi
  1395. } # setup_aliases
  1396.  
  1397. Firmware_Check() {
  1398. printf "Checking firmware support...\n"
  1399. if ! nvram get rc_support | grep -q am_addons; then
  1400. Red "${SCRIPTNAME_DISPLAY} requires ASUSWRT-Merlin Addon API support. Installation aborted."
  1401. printf "\nInstall FreshJR_QOS via amtm as an alternative for your firmware version.\n"
  1402. return 1
  1403. fi
  1404. if [ "$(nvram get qos_enable)" != "1" ] || [ "$(nvram get qos_type)" != "1" ]; then
  1405. Red "Adaptive QoS is not enabled. Please enable it in the GUI. Aborting installation."
  1406. return 1
  1407. fi
  1408. if [ "$(nvram get jffs2_scripts)" != "1" ]; then
  1409. Red "\"Enable JFFS custom scripts and configs\" is not enabled. Please enable it in the GUI. Aborting installation."
  1410. return 1
  1411. fi
  1412. } # Firmware_Check
  1413.  
  1414. install() {
  1415. # Install script and download webui file
  1416. # This is also called by the update process once a new script is downloaded by update() function
  1417. if [ "${mode}" = "interactive" ]; then
  1418. clear
  1419. scriptinfo
  1420. printf "Installing %s...\n" "${SCRIPTNAME_DISPLAY}"
  1421. if ! Firmware_Check; then
  1422. PressEnter
  1423. rm -f "${0}" 2>/dev/null
  1424. exit 5
  1425. fi
  1426. fi
  1427. if [ ! -d "${ADDON_DIR}" ]; then
  1428. printf "Creating directories...\n"
  1429. mkdir -p "${ADDON_DIR}"
  1430. chmod 755 "${ADDON_DIR}"
  1431. fi
  1432. if [ ! -f "${SCRIPTPATH}" ]; then
  1433. cp -p "${0}" "${SCRIPTPATH}"
  1434. fi
  1435. if [ ! -x "${SCRIPTPATH}" ]; then
  1436. chmod 755 "${SCRIPTPATH}"
  1437. fi
  1438. install_webui
  1439. generate_bwdpi_arrays force
  1440. printf "Adding %s entries to Merlin user scripts...\n" "${SCRIPTNAME_DISPLAY}"
  1441. Auto_FirewallStart
  1442. Auto_ServiceEventEnd
  1443. setup_aliases
  1444.  
  1445. if [ "${mode}" = "interactive" ]; then
  1446. Green "${SCRIPTNAME_DISPLAY} installation complete!"
  1447. scriptinfo
  1448. webconfigpage
  1449.  
  1450. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ] && ! /bin/grep -qE "^${SCRIPTNAME}_[^(ver )]" /jffs/addons/custom_settings.txt ; then
  1451. Green "Backup found!"
  1452. backup restore
  1453. fi
  1454. [ "$(nvram get qos_enable)" = "1" ] && needrestart=1
  1455. else
  1456. [ "$(nvram get qos_enable)" = "1" ] && needrestart=2
  1457. fi
  1458. # Remove setting if set to default value 1 (enabled)
  1459. sed -i "/^${SCRIPTNAME}_conntrack 1/d" /jffs/addons/custom_settings.txt
  1460. # Remove deprecated 3:30 AM cron job if exists
  1461. sed -i "\~${SCRIPTNAME_DISPLAY}~d" /jffs/scripts/services-start 2>/dev/null
  1462. cru d "${SCRIPTNAME}" 2>/dev/null
  1463. } # install
  1464.  
  1465. uninstall() {
  1466. local yn
  1467. printf "Removing entries from Merlin user scripts...\n"
  1468. sed -i "\~${SCRIPTNAME_DISPLAY}~d" /jffs/scripts/firewall-start 2>/dev/null
  1469. sed -i "\~${SCRIPTNAME_DISPLAY}~d" /jffs/scripts/service-event-end 2>/dev/null
  1470. printf "Removing aliases and shortcuts...\n"
  1471. sed -i "/alias ${SCRIPTNAME}/d" /jffs/configs/profile.add 2>/dev/null
  1472. rm -f "/opt/bin/${SCRIPTNAME}" 2>/dev/null
  1473. printf "Removing delayed cron job...\n"
  1474. cru d "${SCRIPTNAME}_5min" 2>/dev/null
  1475. remove_webui
  1476. printf "Removing %s settings...\n" "${SCRIPTNAME_DISPLAY}"
  1477. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1478. printf "Backup found! Would you like to keep it? [1=Yes 2=No]: "
  1479. read -r yn
  1480. if [ "${yn}" = "2" ]; then
  1481. printf "Deleting Backup...\n"
  1482. rm "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh"
  1483. fi
  1484. else
  1485. printf "Do you want to backup your settings before uninstall? [1=Yes 2=No]: "
  1486. read -r yn
  1487. if [ "${yn}" = "1" ]; then
  1488. printf "Backing up %s settings...\n" "${SCRIPTNAME_DISPLAY}"
  1489. backup create force
  1490. fi
  1491. fi
  1492. sed -i "/^${SCRIPTNAME}_/d" /jffs/addons/custom_settings.txt
  1493. if [ -f "${ADDON_DIR}/restore_${SCRIPTNAME}_settings.sh" ]; then
  1494. printf "Deleting %s folder contents except Backup file...\n" "${SCRIPTNAME_DISPLAY}"
  1495. /usr/bin/find "${ADDON_DIR}" ! -name restore_"${SCRIPTNAME}"_settings.sh ! -exec test -d {} \; -a -exec rm {} +
  1496. else
  1497. printf "Deleting %s directory...\n" "${SCRIPTNAME_DISPLAY}"
  1498. rm -rf "${ADDON_DIR}"
  1499. fi
  1500. Green "${SCRIPTNAME_DISPLAY} has been uninstalled"
  1501. needrestart=1
  1502. } # uninstall
  1503.  
  1504. get_config() {
  1505. local iptables_rules_defined
  1506. local drp0 drp1 drp2 drp3 drp4 drp5 drp6 drp7
  1507. local dcp0 dcp1 dcp2 dcp3 dcp4 dcp5 dcp6 dcp7
  1508. local urp0 urp1 urp2 urp3 urp4 urp5 urp6 urp7
  1509. local ucp0 ucp1 ucp2 ucp3 ucp4 ucp5 ucp6 ucp7
  1510.  
  1511. # Read settings from Addon API config file. If not defined, set default values
  1512. iptables_rules="$(am_settings_get "${SCRIPTNAME}"_iptables)"
  1513. if [ -z "${iptables_rules}" ]; then
  1514. iptables_rules="<>>udp>>500,4500>>3<>>udp>16384:16415>>>3<>>tcp>>119,563>>5<>>tcp>>80,443>08****>5"
  1515. elif [ "${iptables_rules}" = "0" ]; then
  1516. iptables_rules=""
  1517. fi
  1518. appdb_rules="$(am_settings_get "${SCRIPTNAME}"_appdb)"
  1519. if [ -z "${appdb_rules}" ]; then
  1520. appdb_rules="<000000>6<00006B>6<0D0007>5<0D0086>5<0D00A0>5<12003F>4<13****>4<14****>4"
  1521. fi
  1522. bwrates="$(am_settings_get "${SCRIPTNAME}"_bwrates)"
  1523. if [ -z "${bwrates}" ]; then
  1524. # New settings not set
  1525. if [ -z "$(am_settings_get "${SCRIPTNAME}"_bandwidth)" ]; then
  1526. # Old settings not set either, so set the defaults
  1527. bwrates="<5>15>30>20>10>5>10>5<100>100>100>100>100>100>100>100<5>15>10>20>10>5>30>5<100>100>100>100>100>100>100>100"
  1528. else
  1529. # Convert bandwidth to bwrates by reading existing values into the re-sorted order
  1530. read -r \
  1531. drp0 drp1 drp2 drp3 drp4 drp5 drp6 drp7 \
  1532. dcp0 dcp1 dcp2 dcp3 dcp4 dcp5 dcp6 dcp7 \
  1533. urp0 urp1 urp2 urp3 urp4 urp5 urp6 urp7 \
  1534. ucp0 ucp1 ucp2 ucp3 ucp4 ucp5 ucp6 ucp7 \
  1535. <<EOF
  1536. $(am_settings_get "${SCRIPTNAME}"_bandwidth | sed 's/^<//g;s/[<>]/ /g')
  1537. EOF
  1538. am_settings_set "${SCRIPTNAME}"_bwrates "<${drp0}>${drp2}>${drp5}>${drp1}>${drp4}>${drp7}>${drp3}>${drp6}<${dcp0}>${dcp2}>${dcp5}>${dcp1}>${dcp4}>${dcp7}>${dcp3}>${dcp6}<${urp0}>${urp2}>${urp5}>${urp1}>${urp4}>${urp7}>${urp3}>${urp6}<${ucp0}>${ucp2}>${ucp5}>${ucp1}>${ucp4}>${ucp7}>${ucp3}>${ucp6}"
  1539. bwrates="<${drp0}>${drp2}>${drp5}>${drp1}>${drp4}>${drp7}>${drp3}>${drp6}<${dcp0}>${dcp2}>${dcp5}>${dcp1}>${dcp4}>${dcp7}>${dcp3}>${dcp6}<${urp0}>${urp2}>${urp5}>${urp1}>${urp4}>${urp7}>${urp3}>${urp6}<${ucp0}>${ucp2}>${ucp5}>${ucp1}>${ucp4}>${ucp7}>${ucp3}>${ucp6}"
  1540. if [ "${bwrates}" != "<5>15>30>20>10>5>10>5<100>100>100>100>100>100>100>100<5>15>10>20>10>5>30>5<100>100>100>100>100>100>100>100" ]; then
  1541. am_settings_set "${SCRIPTNAME}"_bwrates "<${drp0}>${drp2}>${drp5}>${drp1}>${drp4}>${drp7}>${drp3}>${drp6}<${dcp0}>${dcp2}>${dcp5}>${dcp1}>${dcp4}>${dcp7}>${dcp3}>${dcp6}<${urp0}>${urp2}>${urp5}>${urp1}>${urp4}>${urp7}>${urp3}>${urp6}<${ucp0}>${ucp2}>${ucp5}>${ucp1}>${ucp4}>${ucp7}>${ucp3}>${ucp6}"
  1542. fi
  1543. sed -i "/^${SCRIPTNAME}_bandwidth /d" /jffs/addons/custom_settings.txt
  1544. fi
  1545. fi
  1546. fccontrol="$(am_settings_get "${SCRIPTNAME}"_fccontrol)"
  1547. if [ -z "${fccontrol}" ]; then
  1548. fccontrol="0" # default to Off from GUI
  1549. fi
  1550. # Delete obsolete setting
  1551. if [ -n "$(am_settings_get "${SCRIPTNAME}"_branch)" ]; then
  1552. sed -i "/^${SCRIPTNAME}_branch /d" /jffs/addons/custom_settings.txt
  1553. fi
  1554. } # get_config
  1555.  
  1556. validate_iptables_rules() {
  1557. # Basic check to ensure the number of rules present in the iptables chain matches the number of expected rules
  1558. # Does not verify that the rules present match the rules in the config, since the config hasn't been parsed at this point.
  1559. local iptables_rules_defined iptables_rules_expected iptables_rulespresent
  1560.  
  1561. if [ -z "${iptables_rules}" ]; then
  1562. return 0
  1563. fi
  1564. iptables_rules_defined="$(echo "${iptables_rules}" | sed 's/</\n/g' | /bin/grep -vc "^$")"
  1565. iptables_rules_expected=$((iptables_rules_defined+1)) # 1 download and upload rule per user rule, plus 1 for chain definition
  1566. iptables_rulespresent="$(iptables -t mangle -S ${SCRIPTNAME_DISPLAY}_down | wc -l)" # count rules in chain plus chain itself
  1567. if [ "${iptables_rulespresent}" -lt "${iptables_rules_expected}" ]; then
  1568. return 1
  1569. else
  1570. return 0
  1571. fi
  1572. } # validate_iptables_rules
  1573.  
  1574. write_iptables_rules() {
  1575. # loop through iptables rules and write an iptables command to a temporary file for later execution
  1576. local OLDIFS
  1577. local localip remoteip proto lport rport mark class
  1578. if [ -z "${iptables_rules}" ]; then
  1579. return 0
  1580. fi
  1581. {
  1582. printf "iptables -t mangle -F %s 2>/dev/null\n" "${SCRIPTNAME_DISPLAY}_down"
  1583. printf "iptables -t mangle -F %s 2>/dev/null\n" "${SCRIPTNAME_DISPLAY}_up"
  1584. if [ "${IPv6_enabled}" != "disabled" ]; then
  1585. printf "ip6tables -t mangle -F %s 2>/dev/null\n" "${SCRIPTNAME_DISPLAY}_down"
  1586. printf "ip6tables -t mangle -F %s 2>/dev/null\n" "${SCRIPTNAME_DISPLAY}_up"
  1587. fi
  1588. } > "/tmp/${SCRIPTNAME}_iprules"
  1589. OLDIFS="${IFS}" # Save existing field separator
  1590. IFS=">" # Set custom field separator to match rule format
  1591. # read the rules, 1 per line and break into separate fields
  1592. echo "${iptables_rules}" | sed 's/</\n/g' | while read -r localip remoteip proto lport rport mark class
  1593. do
  1594. # Ensure at least one criteria field is populated
  1595. if [ -n "${localip}${remoteip}${proto}${lport}${rport}${mark}" ]; then
  1596. # Process the rule and the stdout containing the resulting rule gets saved to the temporary script file
  1597. parse_iptablerule "${localip}" "${remoteip}" "${proto}" "${lport}" "${rport}" "${mark}" "${class}" >> "/tmp/${SCRIPTNAME}_iprules" 2>/dev/null
  1598. fi
  1599. done
  1600. IFS="${OLDIFS}" # Restore saved field separator
  1601. } # write_iptables_rules
  1602.  
  1603. write_appdb_rules() {
  1604. # Write the user appdb rules to the existing tcrules file created during write_appdb_static_rules()
  1605. local OLDIFS
  1606. local mark class
  1607. # Save the current filter rules once to avoid repeated calls in parse_appdb_rule() to determine existing prios
  1608. "${TC}" filter show dev "${tclan}" parent 1: > "/tmp/${SCRIPTNAME}_tmp_tcfilterdown"
  1609. "${TC}" filter show dev "${tcwan}" parent 1: > "/tmp/${SCRIPTNAME}_tmp_tcfilterup"
  1610.  
  1611. # loop through appdb rules and write a tc command to a temporary script file
  1612. OLDIFS="${IFS}" # Save existing field separator
  1613. IFS=">" # Set custom field separator to match rule format
  1614.  
  1615. # read the rules, 1 per line and break into separate fields
  1616. echo "${appdb_rules}" | sed 's/</\n/g' | while read -r mark class
  1617. do
  1618. # Ensure the appdb mark is populated
  1619. if [ -n "${mark}" ]; then
  1620. parse_appdb_rule "${mark}" "${class}" >> "/tmp/${SCRIPTNAME}_tcrules" 2>/dev/null
  1621. fi
  1622. done
  1623. IFS="${OLDIFS}" # Restore old field separator
  1624. } # write_appdb_rules
  1625.  
  1626. get_fq_quantum() {
  1627. local BANDWIDTH
  1628. BANDWIDTH="${1}"
  1629.  
  1630. if [ "${BANDWIDTH}" -lt "51200" ]; then
  1631. printf "quantum 300\n"
  1632. fi
  1633. } # get_fq_quantum
  1634.  
  1635. get_fq_target() {
  1636. # Adapted from sqm-scripts adapt_target_to_slow_link() and adapt_interval_to_slow_link().
  1637. # https://github.com/tohojo/sqm-scripts/blob/master/src/functions.sh
  1638. local BANDWIDTH
  1639. local TARGET INTERVAL
  1640. BANDWIDTH="${1}"
  1641.  
  1642. # for ATM the worst case expansion including overhead seems to be 33 cells of 53 bytes each
  1643. # MAX DELAY = 1000 * 1000 * 33 * 53 * 8 / 1000 max delay in microseconds at 1kbps
  1644. TARGET=$(/usr/bin/awk -vBANDWIDTH="${BANDWIDTH}" 'BEGIN { print int( 1000 * 1000 * 33 * 53 * 8 / 1000 / BANDWIDTH ) }')
  1645. if [ "${TARGET}" -gt "5000" ]; then
  1646. # Increase interval by the same amount that target got increased
  1647. INTERVAL=$(( (100 - 5) * 1000 + TARGET ))
  1648. printf "target %sus interval %sus\n" "${TARGET}" "${INTERVAL}"
  1649. fi
  1650. } # get_fq_target
  1651.  
  1652. write_custom_qdisc() {
  1653. local i
  1654. if [ "$(am_settings_get "${SCRIPTNAME}"_qdisc)" != "0" ]; then
  1655. {
  1656. printf "qdisc replace dev %s parent 1:2 handle 102: fq_codel noecn\n" "${tclan}"
  1657. printf "qdisc replace dev %s parent 1:2 handle 102: fq_codel noecn\n" "${tcwan}"
  1658. for i in 0 1 2 3 4 5 6 7
  1659. do
  1660. printf "qdisc replace dev %s parent 1:1%s handle 11%s: fq_codel %s %s\n" "${tclan}" "${i}" "${i}" "$(get_fq_quantum "${DownCeil}")" "$(get_fq_target "${DownCeil}")"
  1661. printf "qdisc replace dev %s parent 1:1%s handle 11%s: fq_codel %s %s noecn\n" "${tcwan}" "${i}" "${i}" "$(get_fq_quantum "${UpCeil}")" "$(get_fq_target "${UpCeil}")"
  1662. done
  1663. } >> "/tmp/${SCRIPTNAME}_tcrules" 2>/dev/null
  1664. fi
  1665. } # write_custom_qdisc
  1666.  
  1667. check_qos_tc() {
  1668. # Check the status of the existing tc class and filter setup by stock Adaptive QoS before custom settings applied.
  1669. # Only br0 interface is checked since we have not yet identified the tcwan interface name yet.
  1670. dlclasscnt="$("${TC}" class show dev br0 parent 1: | /bin/grep -c "parent")" # should be 8
  1671. dlfiltercnt="$("${TC}" filter show dev br0 parent 1: | /bin/grep -cE "flowid 1:1[0-7]")" # should be 39 or 40
  1672. dlqdisccnt="$("${TC}" qdisc show dev br0 | /bin/grep -c " parent 1:1[0-7] ")" # should be 8
  1673. # Check class count, filter count, qdisc count, and tcwan interface name defined with an htb qdisc
  1674. if [ "${dlclasscnt}" -lt "8" ] || [ "${dlfiltercnt}" -lt "39" ] || [ "${dlqdisccnt}" -lt "8" ] || [ -z "$("${TC}" qdisc ls | sed -nE '/dev br[0-9] root/d; s/^qdisc htb 1: dev ([a-z0-9]+) root.*$/\1/p')" ]; then
  1675. return 0
  1676. else
  1677. return 1
  1678. fi
  1679. } # check_qos_tc
  1680.  
  1681. validate_tc_rules() {
  1682. # Check the existing tc filter rules against the user configuration. If any rule missing, force creation of all rules
  1683. # Must run after set_tc_variables() to ensure flowid can be determined
  1684. local OLDIFS filtermissing
  1685. local mark class flowid
  1686. {
  1687. # print a list of existing filters in the format of an appdb rule for easy comparison. Write to tmp file
  1688. "${TC}" filter show dev "${tclan}" parent 1: | sed -nE '/flowid/ { N; s/\n//g; s/.*flowid (1:1[0-7]).*mark 0x[48]0([0-9a-fA-F]{6}).*/<\2>\1/p }'
  1689. "${TC}" filter show dev "${tcwan}" parent 1: | sed -nE '/flowid/ { N; s/\n//g; s/.*flowid (1:1[0-7]).*mark 0x[48]0([0-9a-fA-F]{6}).*/<\2>\1/p }'
  1690. } > "/tmp/${SCRIPTNAME}_checktcrules" 2>/dev/null
  1691. OLDIFS="${IFS}"
  1692. IFS=">"
  1693. filtermissing="0"
  1694. while read -r mark class
  1695. do
  1696. if [ -n "${mark}" ]; then
  1697. flowid="$(get_flowid "${class}")"
  1698. mark="$(echo "${mark}" | sed 's/\*/0/g')"
  1699. if [ "$(/bin/grep -ic "<${mark}>${flowid}" "/tmp/${SCRIPTNAME}_checktcrules")" -lt "2" ]; then
  1700. filtermissing="$((filtermissing+1))"
  1701. break # stop checking after the first missing rule is identified
  1702. fi
  1703. fi
  1704. done <<EOF
  1705. $(echo "${appdb_rules}" | sed 's/</\n/g')
  1706. EOF
  1707. IFS="${OLDIFS}"
  1708. if [ "${filtermissing}" -gt "0" ]; then
  1709. # reapply tc rules
  1710. return 1
  1711. else
  1712. rm "/tmp/${SCRIPTNAME}_checktcrules" 2>/dev/null
  1713. return 0
  1714. fi
  1715. } # validate_tc_rules
  1716.  
  1717. schedule_check_job() {
  1718. # Schedule check for 5 minutes after startup to ensure no qos tc resets
  1719. cru a "${SCRIPTNAME}"_5min "$(/bin/date -D '%s' +'%M %H %d %m %a' -d $(($(/bin/date +%s)+300))) ${SCRIPTPATH} -check"
  1720. } # schedule_check_job
  1721.  
  1722. startup() {
  1723. local sleepdelay
  1724. if [ "$(nvram get qos_enable)" != "1" ] || [ "$(nvram get qos_type)" != "1" ]; then
  1725. logmsg "Adaptive QoS is not enabled. Skipping ${SCRIPTNAME_DISPLAY} startup."
  1726. return 1
  1727. fi # adaptive qos not enabled
  1728.  
  1729. Check_Lock
  1730. install_webui mount
  1731. generate_bwdpi_arrays
  1732. get_config
  1733.  
  1734. case "$(uname -r)" in
  1735. 4.19.*)
  1736. if \
  1737. [ "$(nvram get qos_ibw)" -lt 409600 ] && \
  1738. [ "$(nvram get qos_obw)" -lt 409600 ] && \
  1739. [ "$(nvram get fc_disable)" = "0" ] && \
  1740. [ -n "${iptables_rules}" ] && \
  1741. [ "${fccontrol}" = "2" ]
  1742. then
  1743. logmsg "Auto-disabling flowcache"
  1744. fc disable
  1745. fc flush
  1746. elif \
  1747. [ -n "${iptables_rules}" ] && \
  1748. [ "${fccontrol}" = "1" ]
  1749. then
  1750. logmsg "Disabling flowcache"
  1751. fc disable
  1752. fc flush
  1753. fi
  1754. ;;
  1755. esac
  1756.  
  1757. if ! validate_iptables_rules; then
  1758. write_iptables_rules
  1759. iptables_static_rules 2>&1 | logger -t "${SCRIPTNAME_DISPLAY}"
  1760. if [ -s "/tmp/${SCRIPTNAME}_iprules" ]; then
  1761. logmsg "Applying iptables custom rules"
  1762. . "/tmp/${SCRIPTNAME}_iprules" 2>&1 | logger -t "${SCRIPTNAME_DISPLAY}"
  1763. if [ "$(am_settings_get "${SCRIPTNAME}"_conntrack)" != "0" ]; then
  1764. # Flush conntrack table so that existing connections will be processed by new iptables rules
  1765. logmsg "Flushing conntrack table"
  1766. /usr/sbin/conntrack -F conntrack >/dev/null 2>&1
  1767. fi
  1768. fi
  1769. fi
  1770.  
  1771. cru d "${SCRIPTNAME}"_5min 2>/dev/null
  1772. sleepdelay=0
  1773. while check_qos_tc;
  1774. do
  1775. [ "${sleepdelay}" = "0" ] && logmsg "TC Modification Delayed Start"
  1776. sleep 10s
  1777. if [ "${sleepdelay}" -ge "180" ]; then
  1778. logmsg "QoS state: Classes=${dlclasscnt} | Filters=${dlfiltercnt} | qdiscs=${dlqdisccnt}"
  1779. if [ ! -f "/tmp/${SCRIPTNAME}_restartonce" ]; then
  1780. touch "/tmp/${SCRIPTNAME}_restartonce"
  1781. logmsg "TC Modification Delay reached maximum 180 seconds. Restarting QoS."
  1782. service "restart_qos;restart_firewall"
  1783. else
  1784. logmsg "TC Modification Delay reached maximum 180 seconds again. Canceling startup!"
  1785. rm "/tmp/${SCRIPTNAME}_restartonce" 2>/dev/null
  1786. fi
  1787. return 1
  1788. else
  1789. sleepdelay=$((sleepdelay+10))
  1790. fi
  1791. done
  1792. [ "${sleepdelay}" -gt "0" ] && logmsg "TC Modification delayed for ${sleepdelay} seconds"
  1793. rm "/tmp/${SCRIPTNAME}_restartonce" 2>/dev/null
  1794.  
  1795. set_tc_variables
  1796.  
  1797. # if TC modifcations have not been applied then run modification script
  1798. if ! validate_tc_rules; then
  1799. write_appdb_static_rules
  1800. write_appdb_rules
  1801. write_custom_rates
  1802. write_custom_qdisc
  1803.  
  1804. if [ -s "/tmp/${SCRIPTNAME}_tcrules" ]; then
  1805. logmsg "Applying AppDB rules and TC rates"
  1806. if ! "${TC}" -force -batch "/tmp/${SCRIPTNAME}_tcrules" >"/tmp/${SCRIPTNAME}_tcrules.log" 2>&1; then
  1807. cp -f "/tmp/${SCRIPTNAME}_tcrules" "/tmp/${SCRIPTNAME}_tcrules.err"
  1808. logmsg "ERROR! Check /tmp/${SCRIPTNAME}_tcrules.log"
  1809. else
  1810. rm "/tmp/${SCRIPTNAME}_tmp_tcfilterdown" "/tmp/${SCRIPTNAME}_tmp_tcfilterup" "/tmp/${SCRIPTNAME}_tcrules.log" "/tmp/${SCRIPTNAME}_checktcrules" "/tmp/${SCRIPTNAME}_tcrules.err" 2>/dev/null
  1811. fi
  1812. fi
  1813.  
  1814. schedule_check_job
  1815. else
  1816. logmsg "No TC modifications necessary"
  1817. fi
  1818. } # startup
  1819.  
  1820. show_help() {
  1821. scriptinfo
  1822. Red "You have entered an invalid command"
  1823. cat <<EOF
  1824.  
  1825. Available commands:
  1826.  
  1827. ${SCRIPTNAME} -about explains functionality
  1828. ${SCRIPTNAME} -appdb string search appdb for application marks
  1829. ${SCRIPTNAME} -update checks for updates
  1830. ${SCRIPTNAME} -restart restart QoS and Firewall
  1831. ${SCRIPTNAME} -install install script
  1832. ${SCRIPTNAME} -uninstall uninstall script & delete from disk
  1833. ${SCRIPTNAME} -enable enable script
  1834. ${SCRIPTNAME} -disable disable script but do not delete from disk
  1835. ${SCRIPTNAME} -backup backup user settings
  1836. ${SCRIPTNAME} -debug print debug info
  1837. ${SCRIPTNAME} -menu interactive main menu
  1838.  
  1839. EOF
  1840. webconfigpage
  1841. } # show_help
  1842.  
  1843. generate_bwdpi_arrays() {
  1844. # generate if not exist, plus after wrs restart (signature update)
  1845. # generate if signature rule file is newer than js file
  1846. # generate if js file is smaller than source file (source not present yet during boot)
  1847. # prepend wc variables with zero in case file doesn't exist, to avoid bad number error
  1848. if [ ! -f "/www/user/${SCRIPTNAME}/${SCRIPTNAME}_arrays.js" ] || \
  1849. [ "$(/bin/date -r /jffs/signature/rule.trf +%s)" -gt "$(/bin/date -r "/www/user/${SCRIPTNAME}/${SCRIPTNAME}_arrays.js" +%s)" ] || \
  1850. [ "${1}" = "force" ] || \
  1851. [ "0$(wc -c < "/www/user/${SCRIPTNAME}/${SCRIPTNAME}_arrays.js")" -lt "0$(wc -c 2>/dev/null < /tmp/bwdpi/bwdpi.app.db)" ]; then
  1852. {
  1853. printf "var catdb_mark_array = [ \"000000\""
  1854. awk -F, '{ printf(", \"%02X****\"",$1) }' /tmp/bwdpi/bwdpi.cat.db 2>/dev/null
  1855. awk -F, '{ printf(", \"%02X%04X\"",$1,$2) }' /tmp/bwdpi/bwdpi.app.db 2>/dev/null
  1856. printf ", \"\" ];"
  1857. printf "var catdb_label_array = [ \"Untracked\""
  1858. awk -F, '{ printf(", \"%s (%02X)\"",$2, $1) }' /tmp/bwdpi/bwdpi.cat.db 2>/dev/null
  1859. awk -F, '{ printf(", \"%s\"",$4) }' /tmp/bwdpi/bwdpi.app.db 2>/dev/null
  1860. printf ", \"\" ];"
  1861. } > "/www/user/${SCRIPTNAME}/${SCRIPTNAME}_arrays.js"
  1862. fi
  1863. }
  1864.  
  1865. PressEnter(){
  1866. [ "${mode}" = "interactive" ] || return
  1867. printf "\n"
  1868. while true; do
  1869. printf "Press enter to continue..."
  1870. read -r "key"
  1871. case "${key}" in
  1872. *)
  1873. break
  1874. ;;
  1875. esac
  1876. done
  1877. return 0
  1878. }
  1879.  
  1880. Kill_Lock() {
  1881. if [ -f "/tmp/${SCRIPTNAME}.lock" ] && [ -d "/proc/$(sed -n '1p' "/tmp/${SCRIPTNAME}.lock")" ]; then
  1882. logmsg "[*] Killing Delayed Process (pid=$(sed -n '1p' "/tmp/${SCRIPTNAME}.lock"))"
  1883. logmsg "[*] $(ps | awk -v pid="$(sed -n '1p' "/tmp/${SCRIPTNAME}.lock")" '$1 == pid')"
  1884. kill "$(sed -n '1p' "/tmp/${SCRIPTNAME}.lock")"
  1885. fi
  1886. rm -rf "/tmp/${SCRIPTNAME}.lock"
  1887. } # Kill_Lock
  1888.  
  1889. Check_Lock() {
  1890. if [ -f "/tmp/${SCRIPTNAME}.lock" ] && [ -d "/proc/$(sed -n '1p' "/tmp/${SCRIPTNAME}.lock")" ] && [ "$(sed -n '1p' "/tmp/${SCRIPTNAME}.lock")" != "$$" ]; then
  1891. Kill_Lock
  1892. fi
  1893. printf "%s\n" "$$" > "/tmp/${SCRIPTNAME}.lock"
  1894. lock="true"
  1895. } # Check_Lock
  1896.  
  1897. get_wan_setting() {
  1898. local varname varval
  1899. varname="${1}"
  1900. prefixes="wan0_ wan1_"
  1901.  
  1902. if [ "$(nvram get wans_mode)" = "lb" ] ; then
  1903. for prefix in $prefixes; do
  1904. state="$(nvram get "${prefix}"state_t)"
  1905. sbstate="$(nvram get "${prefix}"sbstate_t)"
  1906. auxstate="$(nvram get "${prefix}"auxstate_t)"
  1907.  
  1908. # is_wan_connect()
  1909. [ "${state}" = "2" ] || continue
  1910. [ "${sbstate}" = "0" ] || continue
  1911. [ "${auxstate}" = "0" ] || [ "${auxstate}" = "2" ] || continue
  1912.  
  1913. # get_wan_ifname()
  1914. proto="$(nvram get "${prefix}"proto)"
  1915. if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then
  1916. varval="$(nvram get "${prefix}"pppoe_"${varname}")"
  1917. else
  1918. varval="$(nvram get "${prefix}""${varname}")"
  1919. fi
  1920. done
  1921. else
  1922. for prefix in $prefixes; do
  1923. primary="$(nvram get "${prefix}"primary)"
  1924. [ "${primary}" = "1" ] && break
  1925. done
  1926.  
  1927. proto="$(nvram get "${prefix}"proto)"
  1928. if [ "${proto}" = "pppoe" ] || [ "${proto}" = "pptp" ] || [ "${proto}" = "l2tp" ] ; then
  1929. varval="$(nvram get "${prefix}"pppoe_"${varname}")"
  1930. else
  1931. varval="$(nvram get "${prefix}""${varname}")"
  1932. fi
  1933. fi
  1934. printf "%s" "${varval}"
  1935. } # get_wan_setting
  1936.  
  1937. arg1="${1#-}"
  1938. if [ -z "${arg1}" ] || [ "${arg1}" = "menu" ] && ! /bin/grep -qE "${SCRIPTPATH} .* # ${SCRIPTNAME_DISPLAY}" /jffs/scripts/firewall-start; then
  1939. arg1="install"
  1940. fi
  1941.  
  1942. wan="$(get_wan_setting 'ifname')"
  1943. WANMTU="$(get_wan_setting 'mtu')"
  1944. lan="$(nvram get lan_ifname)"
  1945. needrestart=0 # initialize variable used in prompt_restart()
  1946.  
  1947. case "${arg1}" in
  1948. 'start'|'check')
  1949. logmsg "$0 (pid=$$) called in ${mode} mode with $# args: $*"
  1950. startup
  1951. ;;
  1952. 'appdb')
  1953. appdb "${2}"
  1954. ;;
  1955. 'install'|'enable')
  1956. install "${2}"
  1957. ;;
  1958. 'uninstall')
  1959. uninstall
  1960. ;;
  1961. 'disable')
  1962. sed -i "/${SCRIPTNAME}/d" /jffs/scripts/firewall-start 2>/dev/null
  1963. sed -i "/${SCRIPTNAME}/d" /jffs/scripts/service-event-end 2>/dev/null
  1964. remove_webui
  1965. needrestart=2
  1966. ;;
  1967. 'backup')
  1968. backup create force
  1969. ;;
  1970. 'debug')
  1971. debug
  1972. ;;
  1973. 'about')
  1974. about
  1975. ;;
  1976. update*) # updatecheck, updatesilent, or plain update
  1977. update "${arg1#update}" # strip 'update' from arg1 to pass to update function
  1978. ;;
  1979. 'menu'|'')
  1980. menu
  1981. ;;
  1982. 'restart')
  1983. needrestart=2
  1984. ;;
  1985. 'flushct')
  1986. sed -i "/^${SCRIPTNAME}_conntrack /d" /jffs/addons/custom_settings.txt
  1987. Green "Enabled conntrack flushing."
  1988. ;;
  1989. 'noflushct')
  1990. am_settings_set "${SCRIPTNAME}_conntrack" "0"
  1991. Yellow "Disabled conntrack flushing."
  1992. ;;
  1993. *)
  1994. show_help
  1995. ;;
  1996. esac
  1997.  
  1998. prompt_restart
  1999. if [ "${lock}" = "true" ]; then rm -rf "/tmp/${SCRIPTNAME}.lock"; fi
  2000.  
Add Comment
Please, Sign In to add comment