#!/bin/sh ##FreshJR_QOS version=8.8 release=03/07/2019 #Copyright (C) 2017-2019 FreshJR - All Rights Reserved #Tested with ASUS AC-68U, FW384.9, using Adaptive QOS with Manual Bandwidth Settings # Script Changes Unidentified traffic destination away from "Defaults" into "Others" # Script Changes HTTPS traffic destination away from "Net Control" into "Web Surfing" # Script Changes Guaranteed Bandwidth per QOS category into logical percentages of upload and download. # Script Repurposes "Defaults" to contain "Game Downloads" # "Game Downloads" moved into 6th position # "Lowest Defined" moved into 7th position #Script includes misc hardcoded rules # (Wifi Calling) - UDP traffic on remote ports 500 & 4500 moved into VOIP # (Facetime) - UDP traffic on local ports 16384 - 16415 moved into VOIP # (Usenet) - TCP traffic on remote ports 119 & 563 moved into Downloads # (Gaming) - Gaming TCP traffic from remote ports 80 & 443 moved into Game Downloads. # (Snapchat) - Moved into Others # (Speedtest.net) - Moved into Downloads # (Google Play) - Moved into Downloads # (Apple AppStore)- Moved into Downloads # (Advertisement) - Moved into Downloads # (VPN Fix) - Router VPN Client upload traffic moved into Downloads instead of whitelisted # (VPN Fix) - Router VPN Client download traffic moved into Downloads instead of showing up in Uploads # (Gaming Manual) - Unidentified traffic for specified devices, not originating from ports 80/443, moved into "Gaming" # # Gaming traffic originating from ports 80 & 443 is primarily downloads & patches (some lobby/login protocols mixed within) # Manually configurable rule will take untracked traffic, not originating from 80/443, for specified devices and place it into Gaming # Use of this gaming rule REQUIRES devices to have a continuous static ip assignment && this range needs to be defined in the script # # Custom rules can be created within the WebUI OR by running the -rules command: # (custom rules): /jffs/scripts/FreshJR_QOS -rules # # Default bandwidth allocation per category can be adjusted via WebUI OR -rates command: # (custom rates): /jffs/scripts/FreshJR_QOS -rates # ##For discussion visit this thread: ## https://www.snbforums.com/threads/release-freshjr-adaptive-qos-improvements-custom-rules-and-inner-workings.36836/ ## https://github.com/FreshJR07/FreshJR_QOS (Source Code + Backup Link) # ##License ## FreshJR_QOS is free to use under the GNU General Public License, version 3 (GPL-3.0). ## https://opensource.org/licenses/GPL-3.0 #################### MODIFY BELOW WITH CAUTION ##################### #################### MODIFY BELOW WITH CAUTION ##################### # ### IF YOU MANUALLY ADD RULES TO AREA BELOW THEN KEEP IN MIND THAT YOUR CHANGES WILL TAKE EFFECT BUT WILL NOT BE REFLECTED UNDER THE TRACKED CONNECTIONS SECTION OF THE WEBUI. ### FOR HARDCODED CHANGES TO BE REFLECTED IN TRACKED CONNECTIONS SECTION OF THE WEBUI THEN YOU ALSO HAVE TO MODIFY THE CORRESPONDING JAVASCRIPT CODE IN /jffs/scripts/FreshJR_QoS_Stats.asp ### INSTEAD OF HARDCODED CHANGES (legacy method) YOU CAN USE THE SCRIPTS -RULES COMMAND OR ENTER THE WEBUI PAGE FOR CREATING RULES AND THOSE CHANGES WILL BE REFLECTED IN THE TRACKED CONNECTIONS TABLE. # #################### MODIFY BELOW WITH CAUTION ##################### #################### MODIFY BELOW WITH CAUTION ##################### iptable_down_rules() { echo "Applying - Iptable Down Rules" ##DOWNLOAD (INCOMMING TRAFFIC) CUSTOM RULES START HERE -- legacy method iptables -D POSTROUTING -t mangle -o br0 -p udp -m multiport --sports 500,4500 -j MARK --set-mark ${VOIP_mark_down} &> /dev/null #Wifi Calling - (All incoming traffic from WAN source ports 500 & 4500 --> VOIP ) iptables -A POSTROUTING -t mangle -o br0 -p udp -m multiport --sports 500,4500 -j MARK --set-mark ${VOIP_mark_down} iptables -D POSTROUTING -t mangle -o br0 -p udp --dport 16384:16415 -j MARK --set-mark ${VOIP_mark_down} &> /dev/null #Facetime - (All incoming traffic to LAN destination ports 16384-16415 --> VOIP ) iptables -A POSTROUTING -t mangle -o br0 -p udp --dport 16384:16415 -j MARK --set-mark ${VOIP_mark_down} iptables -D POSTROUTING -t mangle -o br0 -p tcp -m multiport --sports 119,563 -j MARK --set-mark ${Downloads_mark_down} &> /dev/null #Usenet - (All incoming traffic from WAN source ports 119 & 563 --> Downloads ) iptables -A POSTROUTING -t mangle -o br0 -p tcp -m multiport --sports 119,563 -j MARK --set-mark ${Downloads_mark_down} iptables -D POSTROUTING -t mangle -o br0 -m mark --mark 0x40000000/0xc0000000 -j MARK --set-xmark 0x80000000/0xC0000000 &> /dev/null #VPN Fix - (Fixes download traffic showing up in upload section when router is acting as a VPN Client) iptables -A POSTROUTING -t mangle -o br0 -m mark --mark 0x40000000/0xc0000000 -j MARK --set-xmark 0x80000000/0xC0000000 iptables -D POSTROUTING -t mangle -o br0 -m mark --mark 0x80080000/0xc03f0000 -p tcp -m multiport --sports 80,443 -j MARK --set-mark ${Default_mark_down} &> /dev/null #Gaming - (Incoming "Gaming" traffic from WAN source ports 80 & 443 --> Defaults//GameDownloads) iptables -A POSTROUTING -t mangle -o br0 -m mark --mark 0x80080000/0xc03f0000 -p tcp -m multiport --sports 80,443 -j MARK --set-mark ${Default_mark_down} ##DOWNLOAD (INCOMMING TRAFFIC) CUSTOM RULES END HERE -- legacy method if [ "$( echo $gameCIDR | tr -cd '.' | wc -c )" -eq "3" ] ; then iptables -D POSTROUTING -t mangle -o br0 -d $gameCIDR -m mark --mark 0x80000000/0x8000ffff -p tcp -m multiport ! --sports 80,443 -j MARK --set-mark ${Gaming_mark_down} &> /dev/null #Gaming - (Incoming "Unidentified" TCP traffic, for devices specified, not from WAN source ports 80 & 443 --> Gaming) iptables -A POSTROUTING -t mangle -o br0 -d $gameCIDR -m mark --mark 0x80000000/0x8000ffff -p tcp -m multiport ! --sports 80,433 -j MARK --set-mark ${Gaming_mark_down} iptables -D POSTROUTING -t mangle -o br0 -d $gameCIDR -m mark --mark 0x80000000/0x8000ffff -p udp -m multiport ! --sports 80,443 -j MARK --set-mark ${Gaming_mark_down} &> /dev/null #Gaming - (Incoming "Unidentified" UDP traffic, for devices specified, not from WAN source ports 80 & 443 --> Gaming) iptables -A POSTROUTING -t mangle -o br0 -d $gameCIDR -m mark --mark 0x80000000/0x8000ffff -p udp -m multiport ! --sports 80,443 -j MARK --set-mark ${Gaming_mark_down} fi if ! [ -z "$ip1_down" ] ; then #Script Interactively Defined Rule 1 if [ "$(echo ${ip1_down} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o br0 ${ip1_down//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip1_down//both/tcp} iptables -D POSTROUTING -t mangle -o br0 ${ip1_down//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip1_down//both/udp} else iptables -D POSTROUTING -t mangle -o br0 ${ip1_down} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip1_down} fi fi if ! [ -z "$ip2_down" ] ; then #Script Interactively Defined Rule 2 if [ "$(echo ${ip2_down} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o br0 ${ip2_down//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip2_down//both/tcp} iptables -D POSTROUTING -t mangle -o br0 ${ip2_down//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip2_down//both/udp} else iptables -D POSTROUTING -t mangle -o br0 ${ip2_down} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip2_down} fi fi if ! [ -z "$ip3_down" ] ; then #Script Interactively Defined Rule 3 if [ "$(echo ${ip3_down} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o br0 ${ip3_down//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip3_down//both/tcp} iptables -D POSTROUTING -t mangle -o br0 ${ip3_down//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip3_down//both/udp} else iptables -D POSTROUTING -t mangle -o br0 ${ip3_down} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip3_down} fi fi if ! [ -z "$ip4_down" ] ; then #Script Interactively Defined Rule 4 if [ "$(echo ${ip4_down} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o br0 ${ip4_down//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip4_down//both/tcp} iptables -D POSTROUTING -t mangle -o br0 ${ip4_down//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip4_down//both/udp} else iptables -D POSTROUTING -t mangle -o br0 ${ip4_down} &> /dev/null iptables -A POSTROUTING -t mangle -o br0 ${ip4_down} fi fi } iptable_up_rules(){ #wan="ppp0" ## WAN interface over-ride for upload traffic if automatic detection is not working properly echo "Applying - Iptable Up Rules ($wan)" ##UPLOAD (OUTGOING TRAFFIC) CUSTOM RULES START HERE -- legacy method iptables -D POSTROUTING -t mangle -o $wan -p udp -m multiport --dports 500,4500 -j MARK --set-mark ${VOIP_mark_up} &> /dev/null #Wifi Calling - (All outgoing traffic to WAN destination ports 500 & 4500 --> VOIP ) iptables -A POSTROUTING -t mangle -o $wan -p udp -m multiport --dports 500,4500 -j MARK --set-mark ${VOIP_mark_up} iptables -D POSTROUTING -t mangle -o $wan -p udp --sport 16384:16415 -j MARK --set-mark ${VOIP_mark_up} &> /dev/null #Facetime - (All outgoing traffic from LAN source ports 16384-16415 --> VOIP ) iptables -A POSTROUTING -t mangle -o $wan -p udp --sport 16384:16415 -j MARK --set-mark ${VOIP_mark_up} iptables -D POSTROUTING -t mangle -o $wan -p tcp -m multiport --dports 119,563 -j MARK --set-mark ${Downloads_mark_up} &> /dev/null #Usenet - (All outgoing traffic to WAN destination ports 119 & 563 --> Downloads ) iptables -A POSTROUTING -t mangle -o $wan -p tcp -m multiport --dports 119,563 -j MARK --set-mark ${Downloads_mark_up} iptables -D OUTPUT -t mangle -o $wan -p udp -m multiport ! --dports 53,123 -j MARK --set-mark ${Downloads_mark_up} &> /dev/null #VPN Fix - (Fixes upload traffic not detected when the router is acting as a VPN Client) iptables -A OUTPUT -t mangle -o $wan -p udp -m multiport ! --dports 53,123 -j MARK --set-mark ${Downloads_mark_up} iptables -D OUTPUT -t mangle -o $wan -p tcp -m multiport ! --dports 53,123 -j MARK --set-mark ${Downloads_mark_up} &> /dev/null #VPN Fix - (Fixes upload traffic not detected when the router is acting as a VPN Client) iptables -A OUTPUT -t mangle -o $wan -p tcp -m multiport ! --dports 53,123 -j MARK --set-mark ${Downloads_mark_up} iptables -D POSTROUTING -t mangle -o $wan -m mark --mark 0x40080000/0xc03f0000 -p tcp -m multiport --sports 80,443 -j MARK --set-mark ${Default_mark_up} &> /dev/null #Gaming - (Outgoing "Gaming" traffic to WAN destinations ports 80 & 443 --> Defaults//GameDownloads) iptables -A POSTROUTING -t mangle -o $wan -m mark --mark 0x40080000/0xc03f0000 -p tcp -m multiport --sports 80,443 -j MARK --set-mark ${Default_mark_up} ##UPLOAD (OUTGOING TRAFFIC) CUSTOM RULES END HERE -- legacy method if [ "$( echo $gameCIDR | tr -cd '.' | wc -c )" -eq "3" ] ; then iptables -D POSTROUTING -t mangle -o $wan -s $gameCIDR -m mark --mark 0x40000000/0x4000ffff -p tcp -m multiport ! --dports 80,443 -j MARK --set-mark ${Gaming_mark_up} &> /dev/null #Gaming - (Outgoing "Unidentified" TCP traffic, for devices specified, not to WAN destination ports 80 & 443 --> Gaming) iptables -A POSTROUTING -t mangle -o $wan -s $gameCIDR -m mark --mark 0x40000000/0x4000ffff -p tcp -m multiport ! --dports 80,443 -j MARK --set-mark ${Gaming_mark_up} iptables -D POSTROUTING -t mangle -o $wan -s $gameCIDR -m mark --mark 0x40000000/0x4000ffff -p udp -m multiport ! --dports 80,443 -j MARK --set-mark ${Gaming_mark_up} &> /dev/null #Gaming - (Outgoing "Unidentified" UDP traffic, for devices specified, not to WAN destination ports 80 & 443 --> Gaming) iptables -A POSTROUTING -t mangle -o $wan -s $gameCIDR -m mark --mark 0x40000000/0x4000ffff -p udp -m multiport ! --dports 80,443 -j MARK --set-mark ${Gaming_mark_up} fi if ! [ -z "$ip1_up" ] ; then #Script Interactively Defined Rule 1 if [ "$(echo ${ip1_up} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o $wan ${ip1_up//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip1_up//both/tcp} iptables -D POSTROUTING -t mangle -o $wan ${ip1_up//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip1_up//both/udp} else iptables -D POSTROUTING -t mangle -o $wan ${ip1_up} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip1_up} fi fi if ! [ -z "$ip2_up" ] ; then #Script Interactively Defined Rule 2 if [ "$(echo ${ip2_up} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o $wan ${ip2_up//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip2_up//both/tcp} iptables -D POSTROUTING -t mangle -o $wan ${ip2_up//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip2_up//both/udp} else iptables -D POSTROUTING -t mangle -o $wan ${ip2_up} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip2_up} fi fi if ! [ -z "$ip3_up" ] ; then #Script Interactively Defined Rule 3 if [ "$(echo ${ip3_up} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o $wan ${ip3_up//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip3_up//both/tcp} iptables -D POSTROUTING -t mangle -o $wan ${ip3_up//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip3_up//both/udp} else iptables -D POSTROUTING -t mangle -o $wan ${ip3_up} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip3_up} fi fi if ! [ -z "$ip4_up" ] ; then #Script Interactively Defined Rule 4 if [ "$(echo ${ip4_up} | grep -c "both")" -ge "1" ] ; then iptables -D POSTROUTING -t mangle -o $wan ${ip4_up//both/tcp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip4_up//both/tcp} iptables -D POSTROUTING -t mangle -o $wan ${ip4_up//both/udp} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip4_up//both/udp} else iptables -D POSTROUTING -t mangle -o $wan ${ip4_up} &> /dev/null iptables -A POSTROUTING -t mangle -o $wan ${ip4_up} fi fi } tc_redirection_down_rules() { echo "Applying TC Down Rules" ${tc} filter del dev br0 parent 1: prio $1 #remove original unidentified traffic rule ${tc} filter del dev br0 parent 1: prio 22 &> /dev/null #remove original HTTPS rule ${tc} filter del dev br0 parent 1: prio 23 &> /dev/null #remove original HTTPS rule ! [ -z "$tc4_down" ] && ${tc} filter add dev br0 protocol all ${tc4_down} #Script Interactively Defined Rule 4 ! [ -z "$tc3_down" ] && ${tc} filter add dev br0 protocol all ${tc3_down} #Script Interactively Defined Rule 3 ! [ -z "$tc2_down" ] && ${tc} filter add dev br0 protocol all ${tc2_down} #Script Interactively Defined Rule 2 ! [ -z "$tc1_down" ] && ${tc} filter add dev br0 protocol all ${tc1_down} #Script Interactively Defined Rule 1 ${tc} filter add dev br0 protocol all prio 20 u32 match mark 0x8012003F 0xc03fffff flowid ${Web} # HTTP rule with different destination ${tc} filter add dev br0 protocol all prio 22 u32 match mark 0x80130000 0xc03f0000 flowid ${Web} #recreate HTTPS rule with different destination ${tc} filter add dev br0 protocol all prio 23 u32 match mark 0x80140000 0xc03f0000 flowid ${Web} #recreate HTTPS rule with different destination ##DOWNLOAD APP_DB TRAFFIC REDIRECTION RULES START HERE -- legacy method ${tc} filter add dev br0 protocol all prio 2 u32 match mark 0x8000006B 0xc03fffff flowid ${Others} #Snapchat ${tc} filter add dev br0 protocol all prio 15 u32 match mark 0x800D0007 0xc03fffff flowid ${Downloads} #Speedtest.net ${tc} filter add dev br0 protocol all prio 15 u32 match mark 0x800D0086 0xc03fffff flowid ${Downloads} #Google Play ${tc} filter add dev br0 protocol all prio 15 u32 match mark 0x800D00A0 0xc03fffff flowid ${Downloads} #Apple AppStore ${tc} filter add dev br0 protocol all prio 50 u32 match mark 0x801A0000 0xc03f0000 flowid ${Downloads} #Advertisement ##DOWNLOAD APP_DB TRAFFIC REDIRECTION RULES END HERE -- legacy method ${tc} filter add dev br0 protocol all prio $1 u32 match mark 0x80000000 0x8000ffff flowid ${Others} #recreate unidentified traffic rule with different destination - Routes Unidentified Traffic into webUI adjustable "Others" traffic container instead of "Defaults" ${tc} filter add dev br0 protocol all prio 10 u32 match mark 0x803f0001 0xc03fffff flowid ${Defaults} #Used for iptables Default_mark_down functionality } tc_redirection_up_rules() { echo "Applying TC Up Rules" ${tc} filter del dev eth0 parent 1: prio $1 #remove original unidentified traffic rule ${tc} filter del dev eth0 parent 1: prio 22 &> /dev/null #remove original HTTPS rule ${tc} filter del dev eth0 parent 1: prio 23 &> /dev/null #remove original HTTPS rule ! [ -z "$tc4_up" ] && ${tc} filter add dev eth0 protocol all ${tc4_up} #Script Interactively Defined Rule 4 ! [ -z "$tc3_up" ] && ${tc} filter add dev eth0 protocol all ${tc3_up} #Script Interactively Defined Rule 3 ! [ -z "$tc2_up" ] && ${tc} filter add dev eth0 protocol all ${tc2_up} #Script Interactively Defined Rule 2 ! [ -z "$tc1_up" ] && ${tc} filter add dev eth0 protocol all ${tc1_up} #Script Interactively Defined Rule 1 ${tc} filter add dev eth0 protocol all prio 20 u32 match mark 0x4012003F 0xc03fffff flowid ${Web} # HTTP rule with different destination ${tc} filter add dev eth0 protocol all prio 22 u32 match mark 0x40130000 0xc03f0000 flowid ${Web} #recreate HTTPS rule with different destination ${tc} filter add dev eth0 protocol all prio 23 u32 match mark 0x40140000 0xc03f0000 flowid ${Web} #recreate HTTPS rule with different destination ##UPLOAD APP_DB TRAFFIC REDIRECTION RULES START HERE -- legacy method ${tc} filter add dev eth0 protocol all prio 2 u32 match mark 0x4000006B 0xc03fffff flowid ${Others} #Snapchat ${tc} filter add dev eth0 protocol all prio 15 u32 match mark 0x400D0007 0xc03fffff flowid ${Downloads} #Speedtest.net ${tc} filter add dev eth0 protocol all prio 15 u32 match mark 0x400D0086 0xc03fffff flowid ${Downloads} #Google Play ${tc} filter add dev eth0 protocol all prio 15 u32 match mark 0x400D00A0 0xc03fffff flowid ${Downloads} #Apple AppStore ${tc} filter add dev eth0 protocol all prio 50 u32 match mark 0x401A0000 0xc03f0000 flowid ${Downloads} #Advertisement ##UPLOAD APP_DB TRAFFIC REDIRECTION RULES END HERE -- legacy method ${tc} filter add dev eth0 protocol all prio $1 u32 match mark 0x40000000 0x4000ffff flowid ${Others} #recreate unidentified traffic rule with different destination - Routes Unidentified Traffic into webUI adjustable "Others" traffic container, instead of "Default" traffic container ${tc} filter add dev eth0 protocol all prio 10 u32 match mark 0x403f0001 0xc03fffff flowid ${Defaults} #Used for iptables Default_mark_up functionality } custom_rates() { echo "Modifying TC Class Rates" ${tc} class change dev br0 parent 1:1 classid 1:10 htb ${PARMS}prio 0 rate ${DownRate0}Kbit ceil ${DownCeil0}Kbit burst ${DownBurst0} cburst ${DownCburst0} ${tc} class change dev br0 parent 1:1 classid 1:11 htb ${PARMS}prio 1 rate ${DownRate1}Kbit ceil ${DownCeil1}Kbit burst ${DownBurst1} cburst ${DownCburst1} ${tc} class change dev br0 parent 1:1 classid 1:12 htb ${PARMS}prio 2 rate ${DownRate2}Kbit ceil ${DownCeil2}Kbit burst ${DownBurst2} cburst ${DownCburst2} ${tc} class change dev br0 parent 1:1 classid 1:13 htb ${PARMS}prio 3 rate ${DownRate3}Kbit ceil ${DownCeil3}Kbit burst ${DownBurst3} cburst ${DownCburst3} ${tc} class change dev br0 parent 1:1 classid 1:14 htb ${PARMS}prio 4 rate ${DownRate4}Kbit ceil ${DownCeil4}Kbit burst ${DownBurst4} cburst ${DownCburst4} ${tc} class change dev br0 parent 1:1 classid 1:15 htb ${PARMS}prio 5 rate ${DownRate5}Kbit ceil ${DownCeil5}Kbit burst ${DownBurst5} cburst ${DownCburst5} ${tc} class change dev br0 parent 1:1 classid 1:16 htb ${PARMS}prio 7 rate ${DownRate6}Kbit ceil ${DownCeil6}Kbit burst ${DownBurst6} cburst ${DownCburst6} ${tc} class change dev br0 parent 1:1 classid 1:17 htb ${PARMS}prio 6 rate ${DownRate7}Kbit ceil ${DownCeil7}Kbit burst ${DownBurst7} cburst ${DownCburst7} ${tc} class change dev eth0 parent 1:1 classid 1:10 htb ${PARMS}prio 0 rate ${UpRate0}Kbit ceil ${UpCeil0}Kbit burst ${UpBurst0} cburst ${UpCburst0} ${tc} class change dev eth0 parent 1:1 classid 1:11 htb ${PARMS}prio 1 rate ${UpRate1}Kbit ceil ${UpCeil1}Kbit burst ${UpBurst1} cburst ${UpCburst1} ${tc} class change dev eth0 parent 1:1 classid 1:12 htb ${PARMS}prio 2 rate ${UpRate2}Kbit ceil ${UpCeil2}Kbit burst ${UpBurst2} cburst ${UpCburst2} ${tc} class change dev eth0 parent 1:1 classid 1:13 htb ${PARMS}prio 3 rate ${UpRate3}Kbit ceil ${UpCeil3}Kbit burst ${UpBurst3} cburst ${UpCburst3} ${tc} class change dev eth0 parent 1:1 classid 1:14 htb ${PARMS}prio 4 rate ${UpRate4}Kbit ceil ${UpCeil4}Kbit burst ${UpBurst4} cburst ${UpCburst4} ${tc} class change dev eth0 parent 1:1 classid 1:15 htb ${PARMS}prio 5 rate ${UpRate5}Kbit ceil ${UpCeil5}Kbit burst ${UpBurst5} cburst ${UpCburst5} ${tc} class change dev eth0 parent 1:1 classid 1:16 htb ${PARMS}prio 7 rate ${UpRate6}Kbit ceil ${UpCeil6}Kbit burst ${UpBurst6} cburst ${UpCburst6} ${tc} class change dev eth0 parent 1:1 classid 1:17 htb ${PARMS}prio 6 rate ${UpRate7}Kbit ceil ${UpCeil7}Kbit burst ${UpBurst7} cburst ${UpCburst7} } #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### #################### DO NOT MODIFY BELOW ##################### webpath='/jffs/scripts/www_FreshJR_QoS_Stats.asp' #path of FreshJR_QoS_Stats.asp #marks for iptable rules Net_mark_down="0x80090001" VOIP_mark_down="0x80060001" # Marks for iptables variant of download rules Gaming_mark_down="0x80080001" # Note these marks are same as filter match/mask combo but have a 1 at the end. That trailing 1 prevents them from being caught by unidentified mask Others_mark_down="0x800a0001" Web_mark_down="0x800d0001" Streaming_mark_down="0x80040001" Downloads_mark_down="0x80030001" Default_mark_down="0x803f0001" Net_mark_up="0x40090001" VOIP_mark_up="0x40060001" # Marks for iptables variant of upload rules Gaming_mark_up="0x40080001" # Note these marks are same as filter match/mask combo but have a 1 at the end. That trailing 1 prevents them from being caught by unidentified mask Others_mark_up="0x400a0001" Web_mark_up="0x400d0001" Streaming_mark_up="0x40040001" Downloads_mark_up="0x40030001" Default_mark_up="0x403f0001" set_tc_variables(){ if [ -e "/usr/sbin/realtc" ] ; then tc="realtc" else tc="tc" fi #read order of QOS categories Defaults="1:17" Net="1:10" flowid=0 while read -r line; # reads users order of QOS categories do #logger -s "${line} ${flowid}" case ${line} in '0') VOIP="1:1${flowid}" eval "Cat${flowid}DownBandPercent=${drp1}" eval "Cat${flowid}UpBandPercent=${urp1}" eval "Cat${flowid}DownCeilPercent=${dcp1}" eval "Cat${flowid}UpCeilPercent=${ucp1}" ;; '1') Downloads="1:1${flowid}" eval "Cat${flowid}DownBandPercent=${drp7}" eval "Cat${flowid}UpBandPercent=${urp7}" eval "Cat${flowid}DownCeilPercent=${dcp7}" eval "Cat${flowid}UpCeilPercent=${ucp7}" ;; '4') Streaming="1:1${flowid}" eval "Cat${flowid}DownBandPercent=${drp5}" eval "Cat${flowid}UpBandPercent=${urp5}" eval "Cat${flowid}DownCeilPercent=${dcp5}" eval "Cat${flowid}UpCeilPercent=${ucp5}" ;; '7') Others="1:1${flowid}" eval "Cat${flowid}DownBandPercent=${drp3}" eval "Cat${flowid}UpBandPercent=${urp3}" eval "Cat${flowid}DownCeilPercent=${dcp3}" eval "Cat${flowid}UpCeilPercent=${ucp3}" ;; '8') Gaming="1:1${flowid}" eval "Cat${flowid}DownBandPercent=${drp2}" eval "Cat${flowid}UpBandPercent=${urp2}" eval "Cat${flowid}DownCeilPercent=${dcp2}" eval "Cat${flowid}UpCeilPercent=${ucp2}" ;; '9') #net control flowid=0 ;; '13') Web="1:1${flowid}" eval "Cat${flowid}DownBandPercent=${drp4}" eval "Cat${flowid}UpBandPercent=${urp4}" eval "Cat${flowid}DownCeilPercent=${dcp4}" eval "Cat${flowid}UpCeilPercent=${ucp4}" ;; esac firstchar="${line%%[0-9]*}" if [ "${firstchar}" == "[" ] ; then flowid=$((flowid + 1)) #logger -s "flowid = ${flowid} ===========" fi done </;/g' | tr -cd ';' | wc -c) -ne 20 ] ; then $(nvram set fb_comment=";;;;;;>;;;;;;>;;;;;;") fi if [ $(nvram get fb_email_dbg | sed 's/>/;/g' | tr -cd ';' | wc -c) -ne 48 ] ; then $(nvram set fb_email_dbg=";;;;;;>;>;>;>;>>>5;20;15;10;10;30;5;5>100;100;100;100;100;100;100;100>5;20;15;30;10;10;5;5>100;100;100;100;100;100;100;100") fi read \ e1 e2 e3 e4 e5 e6 e7 \ f1 f2 f3 f4 f5 f6 f7 \ g1 g2 g3 g4 g5 g6 g7 \ </;/g' ) EOF read \ h1 h2 h3 h4 h5 h6 h7 \ r1 d1 \ r2 d2 \ r3 d3 \ r4 d4 \ gameCIDR \ ruleFLAG \ drp0 drp1 drp2 drp3 drp4 drp5 drp6 drp7 \ dcp0 dcp1 dcp2 dcp3 dcp4 dcp5 dcp6 dcp7 \ urp0 urp1 urp2 urp3 urp4 urp5 urp6 urp7 \ ucp0 ucp1 ucp2 ucp3 ucp4 ucp5 ucp6 ucp7 \ </;/g' ) EOF IFS=$OLDIFS #Verify each read nvram rate is between 5-100 (disabled unless needed in future) # [ "${drp0//[^0-9]}" -ge "5" ] && [ "${drp0//[^0-9]}" -le "100" ] && drp0="5" # [ "${drp1//[^0-9]}" -ge "5" ] && [ "${drp1//[^0-9]}" -le "100" ] && drp1="20" # [ "${drp2//[^0-9]}" -ge "5" ] && [ "${drp2//[^0-9]}" -le "100" ] && drp2="15" # [ "${drp3//[^0-9]}" -ge "5" ] && [ "${drp3//[^0-9]}" -le "100" ] && drp3="10" # [ "${drp4//[^0-9]}" -ge "5" ] && [ "${drp4//[^0-9]}" -le "100" ] && drp4="10" # [ "${drp5//[^0-9]}" -ge "5" ] && [ "${drp5//[^0-9]}" -le "100" ] && drp5="30" # [ "${drp6//[^0-9]}" -ge "5" ] && [ "${drp6//[^0-9]}" -le "100" ] && drp6="5" # [ "${drp7//[^0-9]}" -ge "5" ] && [ "${drp7//[^0-9]}" -le "100" ] && drp7="5" # [ "${dcp0//[^0-9]}" -ge "5" ] && [ "${dcp0//[^0-9]}" -le "100" ] && dcp0="100" # [ "${dcp1//[^0-9]}" -ge "5" ] && [ "${dcp1//[^0-9]}" -le "100" ] && dcp1="100" # [ "${dcp2//[^0-9]}" -ge "5" ] && [ "${dcp2//[^0-9]}" -le "100" ] && dcp2="100" # [ "${dcp3//[^0-9]}" -ge "5" ] && [ "${dcp3//[^0-9]}" -le "100" ] && dcp3="100" # [ "${dcp4//[^0-9]}" -ge "5" ] && [ "${dcp4//[^0-9]}" -le "100" ] && dcp4="100" # [ "${dcp5//[^0-9]}" -ge "5" ] && [ "${dcp5//[^0-9]}" -le "100" ] && dcp5="100" # [ "${dcp6//[^0-9]}" -ge "5" ] && [ "${dcp6//[^0-9]}" -le "100" ] && dcp6="100" # [ "${dcp7//[^0-9]}" -ge "5" ] && [ "${dcp7//[^0-9]}" -le "100" ] && dcp7="100" # [ "${urp0//[^0-9]}" -ge "5" ] && [ "${urp0//[^0-9]}" -le "100" ] && urp0="5" # [ "${urp1//[^0-9]}" -ge "5" ] && [ "${urp1//[^0-9]}" -le "100" ] && urp1="20" # [ "${urp2//[^0-9]}" -ge "5" ] && [ "${urp2//[^0-9]}" -le "100" ] && urp2="15" # [ "${urp3//[^0-9]}" -ge "5" ] && [ "${urp3//[^0-9]}" -le "100" ] && urp3="30" # [ "${urp4//[^0-9]}" -ge "5" ] && [ "${urp4//[^0-9]}" -le "100" ] && urp4="10" # [ "${urp5//[^0-9]}" -ge "5" ] && [ "${urp5//[^0-9]}" -le "100" ] && urp5="10" # [ "${urp6//[^0-9]}" -ge "5" ] && [ "${urp6//[^0-9]}" -le "100" ] && urp6="5" # [ "${urp7//[^0-9]}" -ge "5" ] && [ "${urp7//[^0-9]}" -le "100" ] && urp7="5" # [ "${ucp0//[^0-9]}" -ge "5" ] && [ "${ucp0//[^0-9]}" -le "100" ] && ucp0="100" # [ "${ucp1//[^0-9]}" -ge "5" ] && [ "${ucp1//[^0-9]}" -le "100" ] && ucp1="100" # [ "${ucp2//[^0-9]}" -ge "5" ] && [ "${ucp2//[^0-9]}" -le "100" ] && ucp2="100" # [ "${ucp3//[^0-9]}" -ge "5" ] && [ "${ucp3//[^0-9]}" -le "100" ] && ucp3="100" # [ "${ucp4//[^0-9]}" -ge "5" ] && [ "${ucp4//[^0-9]}" -le "100" ] && ucp4="100" # [ "${ucp5//[^0-9]}" -ge "5" ] && [ "${ucp5//[^0-9]}" -le "100" ] && ucp5="100" # [ "${ucp6//[^0-9]}" -ge "5" ] && [ "${ucp6//[^0-9]}" -le "100" ] && ucp6="100" # [ "${ucp7//[^0-9]}" -ge "5" ] && [ "${ucp7//[^0-9]}" -le "100" ] && ucp7="100" #takes protocol saved in nvram and makes it lower case e3=$(echo ${e3} | tr '[A-Z]' '[a-z]') f3=$(echo ${f3} | tr '[A-Z]' '[a-z]') g3=$(echo ${g3} | tr '[A-Z]' '[a-z]') h3=$(echo ${h3} | tr '[A-Z]' '[a-z]') } ## helper function to save nvram variables in csv format save_nvram(){ $(nvram set fb_comment="${e1};${e2};${e3};${e4};${e5};${e6};${e7}>${f1};${f2};${f3};${f4};${f5};${f6};${f7}>${g1};${g2};${g3};${g4};${g5};${g6};${g7}") $(nvram set fb_email_dbg="${h1};${h2};${h3};${h4};${h5};${h6};${h7}>${r1};${d1}>${r2};${d2}>${r3};${d3}>${r4};${d4}>${gameCIDR}>${ruleFLAG}>${drp0};${drp1};${drp2};${drp3};${drp4};${drp5};${drp6};${drp7}>${dcp0};${dcp1};${dcp2};${dcp3};${dcp4};${dcp5};${dcp6};${dcp7}>${urp0};${urp1};${urp2};${urp3};${urp4};${urp5};${urp6};${urp7}>${ucp0};${ucp1};${ucp2};${ucp3};${ucp4};${ucp5};${ucp6};${ucp7}") $(nvram commit) } ## helper function for interactive menu mode dst_2_name() { case "$1" in 0) echo "Net Control" ;; 1) echo "Gaming" ;; 2) echo "Streaming" ;; 3) echo "VoIP" ;; 4) echo "Web Surfing" ;; 5) echo "Downloads" ;; 6) echo "Others" ;; 7) echo "Game Downloads" ;; *) echo "" ;; esac } ## helper function for interactive menu mode mark_2_name() { return #function disabled since grep is kinda slow [ -z "$1" ] && return cat="$( echo ${1} | head -c2 )" id="$( echo ${1} | tail -c -5 )" cat="$(printf "%d" 0x${cat})" id="$(printf "%d" 0x${id})" cat /tmp/bwdpi/bwdpi.app.db | grep "^${cat},${id}" | head -n1 | cut -d',' -f4 } ## INTERACTIVE mode - rate main page (overview) rates(){ echo -en "\033c\e[3J" #clear screen echo -en '\033[?7l' #disable line wrap printf '\e[8;30;120t' #set height/width of terminal echo -e "\033[1;32mFreshJR QOS v${version}\033[0m" echo "QoS Rates: -------Download------- --------Upload--------" echo " Minimum Maximum Minimum Maximum" echo " Reserved Reserved Allowed Allowed" echo " Bandwidth Bandwidth Bandwidth Bandwidth" echo " (%) (%) (%) (%) " echo " ----------------------- -----------------------" format="%-15s %-13s %-18s %-13s %-4s\n" printf "${format}" "Net Control" "${drp0}" "${dcp0}" "${urp0}" "${ucp0}" printf "${format}" "VoIP" "${drp1}" "${dcp1}" "${urp1}" "${ucp1}" printf "${format}" "Gaming" "${drp2}" "${dcp2}" "${urp2}" "${ucp2}" printf "${format}" "Others" "${drp3}" "${dcp3}" "${urp3}" "${ucp3}" printf "${format}" "Web Surfing" "${drp4}" "${dcp4}" "${urp4}" "${ucp4}" printf "${format}" "Streaming" "${drp5}" "${dcp5}" "${urp5}" "${ucp5}" printf "${format}" "Game Downloads" "${drp6}" "${dcp6}" "${urp6}" "${ucp6}" printf "${format}" "File Downloads" "${drp7}" "${dcp7}" "${urp7}" "${ucp7}" echo "" echo "Available actions:" echo "" echo "1) Minimum Reserved Bandwidth -- Download" echo "2) Minimum Reserved Bandwidth -- Upload" echo "" echo "3) Maximum Allowed Bandwidth -- Download" echo "4) Maximum Allowed Bandwidth -- Upload" echo "" echo "r) Reset Values to Defaults" echo "s) Save & Exit" echo "e) Exit" echo -en '\033[?7h' #enable line wrap echo "" echo -n "What would you like to do (Enter 1-10): " read input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" case $input in 1) echo "Minimum Reserved Bandwidth" read -p " Net Control : " in0 read -p " Voip : " in1 read -p " Gaming : " in2 read -p " Others : " in3 read -p " Web Surfing : " in4 read -p " Streaming : " in5 read -p " Game Downloads : " in6 read -p " File Downloads : " in7 [ "${in0//[^0-9]}" -ge "5" ] && [ "${in0//[^0-9]}" -le "100" ] && drp0="${in0//[^0-9]}" [ "${in1//[^0-9]}" -ge "5" ] && [ "${in1//[^0-9]}" -le "100" ] && drp1="${in1//[^0-9]}" [ "${in2//[^0-9]}" -ge "5" ] && [ "${in2//[^0-9]}" -le "100" ] && drp2="${in2//[^0-9]}" [ "${in3//[^0-9]}" -ge "5" ] && [ "${in3//[^0-9]}" -le "100" ] && drp3="${in3//[^0-9]}" [ "${in4//[^0-9]}" -ge "5" ] && [ "${in4//[^0-9]}" -le "100" ] && drp4="${in4//[^0-9]}" [ "${in5//[^0-9]}" -ge "5" ] && [ "${in5//[^0-9]}" -le "100" ] && drp5="${in5//[^0-9]}" [ "${in6//[^0-9]}" -ge "5" ] && [ "${in6//[^0-9]}" -le "100" ] && drp6="${in6//[^0-9]}" [ "${in7//[^0-9]}" -ge "5" ] && [ "${in7//[^0-9]}" -le "100" ] && drp7="${in7//[^0-9]}" rates ;; 2) echo "Minimum Reserved Bandwidth" read -p " Net Control : " in0 read -p " Voip : " in1 read -p " Gaming : " in2 read -p " Others : " in3 read -p " Web Surfing : " in4 read -p " Streaming : " in5 read -p " Game Downloads : " in6 read -p " File Downloads : " in7 [ "${in0//[^0-9]}" -ge "5" ] && [ "${in0//[^0-9]}" -le "100" ] && urp0="${in0//[^0-9]}" [ "${in1//[^0-9]}" -ge "5" ] && [ "${in1//[^0-9]}" -le "100" ] && urp1="${in1//[^0-9]}" [ "${in2//[^0-9]}" -ge "5" ] && [ "${in2//[^0-9]}" -le "100" ] && urp2="${in2//[^0-9]}" [ "${in3//[^0-9]}" -ge "5" ] && [ "${in3//[^0-9]}" -le "100" ] && urp3="${in3//[^0-9]}" [ "${in4//[^0-9]}" -ge "5" ] && [ "${in4//[^0-9]}" -le "100" ] && urp4="${in4//[^0-9]}" [ "${in5//[^0-9]}" -ge "5" ] && [ "${in5//[^0-9]}" -le "100" ] && urp5="${in5//[^0-9]}" [ "${in6//[^0-9]}" -ge "5" ] && [ "${in6//[^0-9]}" -le "100" ] && urp6="${in6//[^0-9]}" [ "${in7//[^0-9]}" -ge "5" ] && [ "${in7//[^0-9]}" -le "100" ] && urp7="${in7//[^0-9]}" rates ;; 3) echo "Minimum Reserved Bandwidth" read -p " Net Control : " in0 read -p " Voip : " in1 read -p " Gaming : " in2 read -p " Others : " in3 read -p " Web Surfing : " in4 read -p " Streaming : " in5 read -p " Game Downloads : " in6 read -p " File Downloads : " in7 [ "${in0//[^0-9]}" -ge "5" ] && [ "${in0//[^0-9]}" -le "100" ] && dcp0="${in0//[^0-9]}" [ "${in1//[^0-9]}" -ge "5" ] && [ "${in1//[^0-9]}" -le "100" ] && dcp1="${in1//[^0-9]}" [ "${in2//[^0-9]}" -ge "5" ] && [ "${in2//[^0-9]}" -le "100" ] && dcp2="${in2//[^0-9]}" [ "${in3//[^0-9]}" -ge "5" ] && [ "${in3//[^0-9]}" -le "100" ] && dcp3="${in3//[^0-9]}" [ "${in4//[^0-9]}" -ge "5" ] && [ "${in4//[^0-9]}" -le "100" ] && dcp4="${in4//[^0-9]}" [ "${in5//[^0-9]}" -ge "5" ] && [ "${in5//[^0-9]}" -le "100" ] && dcp5="${in5//[^0-9]}" [ "${in6//[^0-9]}" -ge "5" ] && [ "${in6//[^0-9]}" -le "100" ] && dcp6="${in6//[^0-9]}" [ "${in7//[^0-9]}" -ge "5" ] && [ "${in7//[^0-9]}" -le "100" ] && dcp7="${in7//[^0-9]}" rates ;; 4) echo "Minimum Reserved Bandwidth" read -p " Net Control : " in0 read -p " Voip : " in1 read -p " Gaming : " in2 read -p " Others : " in3 read -p " Web Surfing : " in4 read -p " Streaming : " in5 read -p " Game Downloads : " in6 read -p " File Downloads : " in7 [ "${in0//[^0-9]}" -ge "5" ] && [ "${in0//[^0-9]}" -le "100" ] && ucp0="${in0//[^0-9]}" [ "${in1//[^0-9]}" -ge "5" ] && [ "${in1//[^0-9]}" -le "100" ] && ucp1="${in1//[^0-9]}" [ "${in2//[^0-9]}" -ge "5" ] && [ "${in2//[^0-9]}" -le "100" ] && ucp2="${in2//[^0-9]}" [ "${in3//[^0-9]}" -ge "5" ] && [ "${in3//[^0-9]}" -le "100" ] && ucp3="${in3//[^0-9]}" [ "${in4//[^0-9]}" -ge "5" ] && [ "${in4//[^0-9]}" -le "100" ] && ucp4="${in4//[^0-9]}" [ "${in5//[^0-9]}" -ge "5" ] && [ "${in5//[^0-9]}" -le "100" ] && ucp5="${in5//[^0-9]}" [ "${in6//[^0-9]}" -ge "5" ] && [ "${in6//[^0-9]}" -le "100" ] && ucp6="${in6//[^0-9]}" [ "${in7//[^0-9]}" -ge "5" ] && [ "${in7//[^0-9]}" -le "100" ] && ucp7="${in7//[^0-9]}" rates ;; 'r'|'R') drp0="5" drp1="20" drp2="15" drp3="10" drp4="10" drp5="30" drp6="5" drp7="5" dcp0="100" dcp1="100" dcp2="100" dcp3="100" dcp4="100" dcp5="100" dcp6="100" dcp7="100" urp0="5" urp1="20" urp2="15" urp3="30" urp4="10" urp5="10" urp6="5" urp7="5" ucp0="100" ucp1="100" ucp2="100" ucp3="100" ucp4="100" ucp5="100" ucp6="100" ucp7="100" rates ;; 's'|'S') save_nvram echo " Saving Changes" [ "$(nvram get qos_enable)" == "1" ] && prompt_restart return 1 ;; 'e'|'E') echo -e "\033[1;31;7m No Changes have been saved \033[0m" echo "" return 0 ;; *) rates ;; esac } ## INTERACTIVE mode - rule main page (overview) rules(){ echo -en "\033c\e[3J" #clear screen echo -en '\033[?7l' #disable line wrap printf '\e[8;30;120t' #set height/width of terminal echo -e "\033[1;32mFreshJR QOS v${version}\033[0m" echo "Custom QoS Rules:" echo " Local IP Remote IP Proto Local Port Remote Port Mark Dst" printf '1) Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$e1" "$e2" "$e3" "$e4" "$e5" "$e6" "$([ -z $e7 ] || echo "--> $(dst_2_name $e7)")" printf '2) Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$f1" "$f2" "$f3" "$f4" "$f5" "$f6" "$([ -z $f7 ] || echo "--> $(dst_2_name $f7)")" printf '3) Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$g1" "$g2" "$g3" "$g4" "$g5" "$g6" "$([ -z $g7 ] || echo "--> $(dst_2_name $g7)")" printf '4) Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$h1" "$h2" "$h3" "$h4" "$h5" "$h6" "$([ -z $h7 ] || echo "--> $(dst_2_name $h7)")" printf '5) Gameip %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "${gameCIDR}" "" "$([ -z $gameCIDR ] || echo "both")" "" "$([ -z $gameCIDR ] || echo "!80:443")" "$([ -z $gameCIDR ] || echo "000000")" "--> Gaming" printf '6) Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r1)" "$r1" "$([ -z $d1 ] || echo "--> $(dst_2_name $d1)")" printf '7) Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r2)" "$r2" "$([ -z $d2 ] || echo "--> $(dst_2_name $d2)")" printf '8) Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r3)" "$r3" "$([ -z $d3 ] || echo "--> $(dst_2_name $d3)")" printf '9) Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r4)" "$r4" "$([ -z $d4 ] || echo "--> $(dst_2_name $d4)")" echo "" echo "s) Save & Exit" echo "e) Exit" echo -en '\033[?7h' #enable line wrap echo "" echo -n "Select Rule to Modify (Enter 1-9): " read input case $input in '1') iprule e1 e2 e3 e4 e5 e6 e7 "Rule 1";; '2') iprule f1 f2 f3 f4 f5 f6 f7 "Rule 2";; '3') iprule g1 g2 g3 g4 g5 g6 g7 "Rule 3";; '4') iprule h1 h2 h3 h4 h5 h6 h7 "Rule 4";; '5') gamerule ;; '6') apprule r1 d1 "Appdb 1" ;; '7') apprule r2 d2 "Appdb 2" ;; '8') apprule r3 d3 "Appdb 3" ;; '9') apprule r4 d4 "Appdb 4" ;; 's'|'S') echo "" echo "Saving Changes" save_nvram [ "$(nvram get qos_enable)" == "1" ] && prompt_restart return 1 ;; 'e'|'E') echo "" echo -e "\033[1;31;7m No Changes have been saved \033[0m" echo "" return 0 ;; *) rules ;; esac } ## INTERACTIVE mode - modify iptable rule iprule() { echo -en "\033c\e[3J" echo -en '\033[?7l' #disable line wrap echo -e "\033[1;32mFreshJR QOS v${version} \033[0m" echo "Modifying ${8}" echo -n "1) Name " && sed -nE 's/var rulename'${8//[^0-9]/}'="(.*?)";/\1/p' "${webpath}" echo -n "2) Local IP " && eval "echo \${$1}" echo -n "3) Remote IP " && eval "echo \${$2}" echo -n "4) Local Port " && [ -z $(eval "echo \${$4}") ] && echo || eval "echo \${$3} \${$4}" #if ${4} is blank then leave field blank else populate echo -n "5) Remote Port " && [ -z $(eval "echo \${$5}") ] && echo || eval "echo \${$3} \${$5}" #if ${5} is blank then leave field blank else populate echo -n "6) Protocol " && eval "echo \${$3}" echo -n "7) QoS Mark " && eval "echo \${$6}" echo -n "8) Destination " && eval "dst_2_name \${$7}" echo "" echo "r) Reset / Disable" echo "e) Go Back" echo "" in_progress=1 while [ ${in_progress} -eq 1 ] ; do echo -n "Select Parameter to Modify (Enter 1-8): " read input echo -en "\033[1A\r\033[0K" #clear user input prompt case $input in 1) #name echo -ne "\033[1;32m" echo " WebUI Rule Name" echo "" echo -ne "\033[0m" echo -n " Name(Rule${8//[^0-9]/})=" #read user input read input if [ -z $input ] ; then input="${8// /}" fi echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #make changes to WebUI.asp page echo "$( cat "${webpath}" | sed -E 's/var rulename'"${8//[^0-9]/}"'="(.*?)";/var rulename'"${8//[^0-9]/}"'="'"${input}"'";/')" > "${webpath}" #update table entry echo -en "\033[3;0f\033[0K" #move to line 3 pos 0 \ erase to end echo -n "1) Name " && sed -nE 's/var rulename'${8//[^0-9]/}'="(.*?)";/\1/p' "${webpath}" ;; 2) #local ip #show valid syntax echo -ne "\033[1;32m" echo " Local IP Syntax: 192.168.X.XXX or !192.168.X.XXX" echo " 192.168.X.XXX/CIDR or !192.168.X.XXX/CIDR" echo "" echo -ne "\033[0m" echo -n " Local IP=" #read user input read input eval "$1=\$input" #clear syntax+input echo -en "\033[1A\r\033[0K" #up one line \ beginning line \ erase to end echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[4;0f\033[0K" #move to line 4 pos 0 \ erase to end echo -n "2) Local IP " && eval "echo \${$1}" ;; 3) #remote ip #show valid syntax echo -ne "\033[1;32m" echo " Remote IP Syntax: 75.75.75.75 or !75.75.75.75 " echo " 75.75.75.75/CIDR or !75.75.75.75/CIDR" echo "" echo -ne "\033[0m" echo -n " Remote IP=" #read user input read input eval "$2=\$input" #clear syntax+input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[5;0f\033[0K" #move to line 5 pos 0 \ erase to end echo -n "3) Remote IP " && eval "echo \${$2}" ;; 4) #local port #show valid syntax echo -ne "\033[1;32m" echo " Local Port Syntax: XXX or !XXX" echo " XXXX:YYYY or !XXXX:YYYY" echo " XXX,YYY,ZZZ or !XXX,YYY,ZZZ" echo "" echo -ne "\033[0m" echo -n " Local Port=" #read user input read input eval "$4=\$input" if [ -z $input ] ; then #if port entry blank --> do not continue #clear syntax + input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #if both ports are blank then reset protocol variable [ -z $(eval "echo \${$5}") ] && eval "$3='both'" else #else port was defined --> ask for protocol definition #show additional valid syntax echo -ne "\033[1;32m" echo "" echo " Protocol Syntax: tcp" echo " udp" echo " both" echo "" echo -ne "\033[0m" echo -n " Protocol=" #read user input read user input input=$(echo ${input} | tr '[A-Z]' '[a-z]') if [ "${input}" = "udp" ] || [ "${input}" = "both" ] ; then eval "$3=\$input" else eval "$3='tcp'" fi #clear syntax+input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" fi #update table entry echo -en "\033[8;0f\033[0K" #move to line 8 pos 0 \ erase to end echo -en "\033[7;0f\033[0K" #move to line 7 pos 0 \ erase to end echo -en "\033[6;0f\033[0K" #move to line 6 pos 0 \ erase to end echo -n "4) Local Port " && [ -z $(eval "echo \${$4}") ] && echo || eval "echo \${$3} \${$4}" #if ${4} is blank then leave field blank else populate echo -n "5) Remote Port " && [ -z $(eval "echo \${$5}") ] && echo || eval "echo \${$3} \${$5}" #if ${5} is blank then leave field blank else populate echo -n "6) Protocol " && eval "echo \${$3}" ;; 5) #remote port #show valid syntax echo -ne "\033[1;32m" echo " Remote Port Syntax: XXX or !XXX" echo " XXXX:YYYY or !XXXX:YYYY" echo " XXX,YYY,ZZZ or !XXX,YYY,ZZZ" echo "" echo -ne "\033[0m" echo -n " Remote Port=" #read user input read input eval "$5=\$input" if [ -z $input ] ; then #if port entry blank --> do not continue #clear syntax + input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #if both ports are blank then also clear protocol variable [ -z $(eval "echo \${$4}") ] && eval "$3='both'" else #else port was defined --> ask for protocol definition #show additional valid syntax echo -ne "\033[1;32m" echo "" echo " Protocol Syntax: tcp" echo " udp" echo " both" echo "" echo -ne "\033[0m" echo -n " Protocol=" #read user input read input input=$(echo ${input} | tr '[A-Z]' '[a-z]') if [ "${input}" = "udp" ] || [ "${input}" = "both" ] ; then eval "$3=\$input" else eval "$3='tcp'" fi #clear syntax+input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" fi #update table entry echo -en "\033[8;0f\033[0K" #move to line 8 pos 0 \ erase to end echo -en "\033[7;0f\033[0K" #move to line 7 pos 0 \ erase to end echo -en "\033[6;0f\033[0K" #move to line 6 pos 0 \ erase to end echo -n "4) Local Port " && [ -z $(eval "echo \${$4}") ] && echo || eval "echo \${$3} \${$4}" #if ${4} is blank then leave field blank else populate echo -n "5) Remote Port " && [ -z $(eval "echo \${$5}") ] && echo || eval "echo \${$3} \${$5}" #if ${5} is blank then leave field blank else populate echo -n "6) Protocol " && eval "echo \${$3}" ;; 6) #protocol #show valid syntax echo -ne "\033[1;32m" echo " Protocol Syntax: tcp" echo " udp" echo " both" echo "" echo -ne "\033[0m" echo -n " Protocol=" #read user input read input input=$(echo ${input} | tr '[A-Z]' '[a-z]') if [ "${input}" = "udp" ] || [ "${input}" = "tcp" ] ; then eval "$3=\$input" else eval "$3='both'" fi #clear sytnax + input echo -en "\033[1A\r\033[0K" #up one line \ beginning line \ erase to end echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[8;0f\033[0K" #move to line 8 pos 0 \ erase to end echo -en "\033[7;0f\033[0K" #move to line 7 pos 0 \ erase to end echo -en "\033[6;0f\033[0K" #move to line 6 pos 0 \ erase to end echo -n "4) Local Port " && [ -z $(eval "echo \${$4}") ] && echo || eval "echo \${$3} \${$4}" #if ${4} is blank then leave field blank else populate echo -n "5) Remote Port " && [ -z $(eval "echo \${$5}") ] && echo || eval "echo \${$3} \${$5}" #if ${5} is blank then leave field blank else populate echo -n "6) Protocol " && eval "echo \${$3}" ;; 7) #qos mark #show valid syntax echo -ne "\033[1;32m" echo " QoS Mark Syntax (hex): XXYYYY" echo " Note: YYYY can be **** wildcard" echo "" echo -ne "\033[0m" echo -n " QoS Mark=" #read user input read input input=${input//!/} eval "$6=\$input" #clear sytnax + input echo -en "\033[1A\r\033[0K" #up one line \ beginning line \ erase to end echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[9;0f\033[0K" #move to line 9 pos 0 \ erase to end echo -n "7) QoS Mark " && eval "echo \${$6}" ;; 8) #packetdestination #show valid syntax echo -ne "\033[1;32m" echo " Destination Syntax: 0-7" echo "" echo " Reference: " echo " 0) Net Control" echo " 1) VoIP" echo " 2) Gaming" echo " 3) Others" echo " 4) Web Surfing" echo " 5) Streaming" echo " 6) Game Downloads" echo " 7) Downloads" echo "" echo -ne "\033[0m" echo -n " Destination=" #read user input read input case $input in 0) eval "$7='0'" ;; #net 1) eval "$7='3'" ;; #voip 2) eval "$7='1'" ;; #game 3) eval "$7='6'" ;; #other 4) eval "$7='4'" ;; #web 5) eval "$7='2'" ;; #video 6) eval "$7='7'" ;; #game download 7) eval "$7='5'" ;; #downloads *) eval "$7='0'" ;; #invalid input -> net esac #clear syntax + input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[10;0f\033[0K" #move to line 10 pos 0 \ erase to end echo -n "8) Destination " && eval "dst_2_name \${$7}" #if all params empty leave blank else populate ;; 'r'|'R') #reset eval "$1=''" eval "$2=''" eval "$3=''" eval "$4=''" eval "$5=''" eval "$6=''" eval "$7=''" echo "$( cat "${webpath}" | sed -E 's/var rulename'"${8//[^0-9]/}"'="(.*?)";/var rulename'"${8//[^0-9]/}"'="Rule'"${8//[^0-9]/}"'";/')" > "${webpath}" in_progress=0 ;; 'e'|'E') in_progress=0 ;; esac echo -en "\033[15;0f" #set cursor to user prompt original position done rules #go back to rules page after modifying individual rule } ## INTERACTIVE mode - modify gameip range gamerule() { echo -en "\033c\e[3J" echo -en '\033[?7l' #disable line wrap echo -e "\033[1;32mFreshJR QOS v${version} \033[0m" echo "Modifying Gaming Device IP Range " echo -ne "\033[1;32m" echo "" echo " Gaming Device IP Syntax: 192.168.X.XXX " echo " 192.168.X.XXX/CIDR" echo "" echo -ne "\033[0m" echo -ne " Gaming Device IP=" read input if [ "$( echo $input | tr -cd '.' | wc -c )" -eq "3" ] ; then gameCIDR=${input} else gameCIDR='' fi rules } ## INTERACTIVE mode - modify appdb TC rule apprule() { echo -en "\033c\e[3J" echo -en '\033[?7l' #disable line wrap echo -e "\033[1;32mFreshJR QOS v${version} \033[0m" echo "Modifying ${3}" echo -n "1) QoS Mark " && eval "echo \${$1}" echo -n "2) Destination " && eval "dst_2_name \${$2}" echo "" echo "r) Reset / Disable" echo "e) Go Back" echo "" in_progress=1 while [ ${in_progress} -eq 1 ] ; do echo -n "Select Parameter to Modify (Enter 1-2): " read input echo -en "\033[1A\r\033[0K" #clear user input prompt case $input in 1) #QoS MARK #show valid syntax echo -ne "\033[1;32m" echo " QoS Mark Syntax: XXYYYY" echo "" echo -ne "\033[0m" echo -n " QoS Mark=" #read user input read input eval "$1=\$input" #clear syntax + input echo -en "\033[1A\r\033[0K" #up one line \ beginning line \ erase to end echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[3;0f\033[0K" #move to line 3 pos 0 \ erase to end echo -n "1) QoS Mark " && eval "echo \${$1}" if [ -z $(eval "echo \${$2}") ] ; then echo -en "\033[9;0f" #show valid syntax echo -ne "\033[1;32m" echo " Destination Syntax: 0-7" echo "" echo " Reference: " echo " 0) Net Control" echo " 1) VoIP" echo " 2) Gaming" echo " 3) Others" echo " 4) Web Surfing" echo " 5) Streaming" echo " 6) Game Downloads" echo " 7) Downloads" echo "" echo -ne "\033[0m" echo -n " Destination=" #read user input read input case $input in 0) eval "$2='0'" ;; #net 1) eval "$2='3'" ;; #voip 2) eval "$2='1'" ;; #game 3) eval "$2='6'" ;; #other 4) eval "$2='4'" ;; #web 5) eval "$2='2'" ;; #video 6) eval "$2='7'" ;; #game download 7) eval "$2='5'" ;; #downloads *) eval "$2=''" ;; #invalid input -> disable esac #clear syntax + input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[4;0f\033[0K" #move to line 4 pos 0 \ erase to end echo -n "2) Destination " && eval "dst_2_name \${$2}" fi ;; 2) #packet destination #show valid syntax echo -ne "\033[1;32m" echo " Destination Syntax: 0-7" echo "" echo " Reference: " echo " 0) Net Control" echo " 1) VoIP" echo " 2) Gaming" echo " 3) Others" echo " 4) Web Surfing" echo " 5) Streaming" echo " 6) Game Downloads" echo " 7) Downloads" echo "" echo -ne "\033[0m" echo -n " Destination=" #read user input read input case $input in 0) eval "$2='0'" ;; #net 1) eval "$2='3'" ;; #voip 2) eval "$2='1'" ;; #game 3) eval "$2='6'" ;; #other 4) eval "$2='4'" ;; #web 5) eval "$2='2'" ;; #video 6) eval "$2='7'" ;; #game download 7) eval "$2='5'" ;; #downloads *) eval "$2=''" ;; #invalid input -> disable esac #clear syntax + input echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" echo -en "\033[1A\r\033[0K" #update table entry echo -en "\033[4;0f\033[0K" #move to line 4 pos 0 \ erase to end echo -n "2) Destination " && eval "dst_2_name \${$2}" ;; 'r'|'R') #reset eval "$1=''" eval "$2=''" #apprule $1 $2 "${3}" in_progress=0 ;; 'e'|'E') in_progress=0 ;; esac echo -en "\033[9;0f" #set cursor to user prompt original position done rules #go back to rules page after modifying individual rule } ## helper function - parse parameters into tc syntax parse_tcrule() { ##requires global variables previously set by set_tc_variables ##----------input----------- ##$1 = mark ##$2 = dst ##----------output----------- ##byref sets $3 ##byref sets $4 cat="$( echo ${1} | head -c2 )" id="$( echo ${1} | tail -c -5 )" #filter field if [ "$( echo ${1} | wc -c )" -eq "7" ] ; then if [ "${id}" == "****" ] ; then DOWN_mark="0x80${1//!/} 0xc03ff0000" UP_mark="0x40${1//!/} 0xc03ff0000" else DOWN_mark="0x80${1//!/} 0xc03fffff" UP_mark="0x40${1//!/} 0xc03fffff" fi else ##return early if mark is less than 6 digits return fi #destination field case "$2" in 0) flowid=${Net};; 1) flowid=${Gaming};; 2) flowid=${Streaming};; 3) flowid=${VOIP};; 4) flowid=${Web};; 5) flowid=${Downloads};; 6) flowid=${Others};; 7) flowid=${Defaults};; ##return early if destination missing *) return ;; esac #prio field prio="$(tc filter show dev br0 | grep ${cat}0000 -B1 | tail -2 | cut -d " " -f7 | head -1)" if [ -z "${prio}" ] ; then prio="${undf_prio}" else prio="$(expr ${prio} - 1)" fi down_rule="prio $prio u32 match mark $DOWN_mark flowid $flowid" up_rule="prio $prio u32 match mark $UP_mark flowid $flowid" eval "$3=\$down_rule" eval "$4=\$up_rule" } ## helper function - parse parameters into iptable syntax parse_iptablerule() { ##----------input----------- #$1=local IP accepted XXX.XXX.XXX.XXX or !XXX.XXX.XXX.XXX #$2=remote IP accepted XXX.XXX.XXX.XXX or !XXX.XXX.XXX.XXX #$3=protocol accepted tcp or udp #$4=local port accepted XXXXX or XXXXX:YYYYY or XXX,YYY,ZZZ or !XXXXX or !XXXXX:YYYYY or !XXX,YYY,ZZZ #$5=remote port accepted XXXXX or XXXXX:YYYYY or XXX,YYY,ZZZ or !XXXXX or !XXXXX:YYYYY or !XXX,YYY,ZZZ #$6=mark accepted XXYYYY (setting YYYY to **** will filter entire "XX" parent category) #$7=qos destination accepted 0-7 ##----------output----------- ##byref sets $8 ##byref sets $9 #local IP if [ "$( echo ${1} | wc -c )" -gt "1" ] ; then DOWN_Lip="${1//[^!]*/} -d ${1//!/}" UP_Lip="${1//[^!]*/} -s ${1//!/}" else DOWN_Lip="" UP_Lip="" fi #remote IP if [ "$( echo ${2} | wc -c )" -gt "1" ] ; then DOWN_Rip="${2//[^!]*/} -s ${2//!/}" UP_Rip="${2//[^!]*/} -d ${2//!/}" else DOWN_Rip="" UP_Rip="" fi #protocol (required for port rules) if [ "${3}" = 'tcp' ] || [ "${3}" = 'udp' ] ; then #if tcp/udp PROTO="-p ${3}" else if [ "$( echo ${4} | wc -c )" -gt "1" ] || [ "$( echo ${5} | wc -c )" -gt "1" ] ; then #if both & port rules defined PROTO="-p both" #"BOTH" gets replaced with tcp & udp during later prior to rule execution else #if both & port rules not defined PROTO="" fi fi #local port if [ "$( echo ${4} | wc -c )" -gt "1" ] ; then if [ "$( echo ${4} | tr -cd ',' | wc -c )" -ge "1" ] ; then #multiport XXX,YYY,ZZZ DOWN_Lport="-m multiport ${4//[^!]*/} --dports ${4//!/}" UP_Lport="-m multiport ${4//[^!]*/} --sports ${4//!/}" else #single port XXX or port range XXX:YYY DOWN_Lport="${4//[^!]*/} --dport ${4//!/}" UP_Lport="${4//[^!]*/} --sport ${4//!/}" fi else DOWN_Lport="" UP_Lport="" fi #remote port if [ "$( echo ${5} | wc -c )" -gt "1" ] ; then if [ "$( echo ${5} | tr -cd ',' | wc -c )" -ge "1" ] ; then #multiport XXX,YYY,ZZZ DOWN_Rport="-m multiport ${5//[^!]*/} --sports ${5//!/}" UP_Rport="-m multiport ${5//[^!]*/} --dports ${5//!/}" else #single port XXX or port range XXX:YYY DOWN_Rport="${5//[^!]*/} --sport ${5//!/}" UP_Rport="${5//[^!]*/} --dport ${5//!/}" fi else DOWN_Rport="" UP_Rport="" fi #match mark if [ "$( echo ${6} | wc -c )" -eq "7" ] ; then if [ "$( echo ${6} | tail -c -5 )" == "****" ] ; then DOWN_mark="-m mark --mark 0x80${6//!/}/0xc03f0000" UP_mark="-m mark --mark 0x40${6//!/}/0xc03f0000" else DOWN_mark="-m mark --mark 0x80${6//!/}/0xc03fffff" UP_mark="-m mark --mark 0x40${6//!/}/0xc03fffff" fi else DOWN_mark="" UP_mark="" fi ##if parameters are empty return early if [ -z "${DOWN_Lip}${DOWN_Rip}${DOWN_Lport}${DOWN_Rport}${DOWN_mark}" ] ; then return fi #destination mark case "$7" in 0) DOWN_dst="-j MARK --set-mark ${Net_mark_down}" UP_dst="-j MARK --set-mark ${Net_mark_up}" ;; 1) DOWN_dst="-j MARK --set-mark ${Gaming_mark_down}" UP_dst="-j MARK --set-mark ${Gaming_mark_up}" ;; 2) DOWN_dst="-j MARK --set-mark ${Streaming_mark_down}" UP_dst="-j MARK --set-mark ${Streaming_mark_up}" ;; 3) DOWN_dst="-j MARK --set-mark ${VOIP_mark_down}" UP_dst="-j MARK --set-mark ${VOIP_mark_up}" ;; 4) DOWN_dst="-j MARK --set-mark ${Web_mark_down}" UP_dst="-j MARK --set-mark ${Web_mark_up}" ;; 5) DOWN_dst="-j MARK --set-mark ${Downloads_mark_down}" UP_dst="-j MARK --set-mark ${Downloads_mark_up}" ;; 6) DOWN_dst="-j MARK --set-mark ${Others_mark_down}" UP_dst="-j MARK --set-mark ${Others_mark_up}" ;; 7) DOWN_dst="-j MARK --set-mark ${Default_mark_down}" UP_dst="-j MARK --set-mark ${Default_mark_up}" ;; *) ##if destinations is empty return early return ;; esac down_rule="$(echo "${DOWN_Lip} ${DOWN_Rip} ${PROTO} ${DOWN_Lport} ${DOWN_Rport} ${DOWN_mark} ${DOWN_dst}" | sed 's/ */ /g')" up_rule="$(echo "${UP_Lip} ${UP_Rip} ${PROTO} ${UP_Lport} ${UP_Rport} ${UP_mark} ${UP_dst}" | sed 's/ */ /g')" eval "$8=\$down_rule" eval "$9=\$up_rule" } about(){ echo -en "\033c\e[3J" #clear screen echo -en '\033[?7l' #disable line wrap printf '\e[8;41;160t' #set height/width of terminal echo "FreshJR_QOS v${version} released ${release}" echo "" echo 'License' echo ' FreshJR_QOS is free to use under the GNU General Public License, version 3 (GPL-3.0).' echo ' https://opensource.org/licenses/GPL-3.0' echo "" echo 'For discussion visit this thread:' echo ' https://www.snbforums.com/threads/release-freshjr-adaptive-qos-improvements-custom-rules-and-inner-workings.36836/' echo " https://github.com/FreshJR07/FreshJR_QOS (Source Code)" echo "" echo -e "\033[1;32mFreshJR QOS v${version} \033[0m" echo "About" echo ' Script Changes Unidentified traffic destination away from "Defaults" into "Others"' echo ' Script Changes HTTPS traffic destination away from "Net Control" into "Web Surfing" ' echo ' Script Changes Guaranteed Bandwidth per QOS category into logical percentages of upload and download.' echo "" echo ' Script Repurposes "Defaults" to contain "Game Downloads" ' echo ' "Game Downloads" container moved into 6th position' echo ' "Lowest Defined" container moved into 7th position' echo "" echo ' Script includes misc hardcoded rules ' echo ' (Wifi Calling) - UDP traffic on remote ports 500 & 4500 moved into VOIP' echo ' (Facetime) - UDP traffic on local ports 16384 - 16415 moved into VOIP ' echo ' (Usenet) - TCP traffic on remote ports 119 & 563 moved into Downloads ' echo ' (Gaming) - Gaming TCP traffic from remote ports 80 & 443 moved into Game Downloads.' echo ' (Snapchat) - Moved into Others' echo ' (Speedtest.net) - Moved into Downloads' echo ' (Google Play) - Moved into Downloads' echo ' (Apple AppStore)- Moved into Downloads' echo ' (Advertisement) - Moved into Downloads' echo ' (VPN Fix) - Router VPN Client upload traffic moved into Downloads instead of whitelisted' echo ' (VPN Fix) - Router VPN Client download traffic moved into Downloads instead of showing up in Uploads' echo ' (Gaming Manual) - Unidentified traffic for specified devices, not originating from ports 80/443, moved into "Gaming"' echo "" echo 'Gaming Rule Note' echo ' Gaming traffic originating from ports 80 & 443 is primarily downloads & patches (some lobby/login protocols mixed within)' echo ' Manually configurable rule will take untracked traffic for specified devices, not originating from server ports 80/443, and place it into Gaming' echo ' Use of this gaming rule REQUIRES devices to have a continous static ip assignment && this range needs to be passed into the script' echo "" echo "How to Use Advanced Functionality" echo ' Interactive terminal mode can be accessed by running the -menu command:' echo ' (interactive mode) : /jffs/scripts/FreshJR_QOS -menu' echo ' Custom rules can be created via the WebUI OR directly accessed by running the -rules command:' echo ' (custom rules) : /jffs/scripts/FreshJR_QOS -rules' echo ' Bandwidth allocation per category can be adjusted via the WebUI OR directly accessed by running the -rates command:' echo ' (custom rates) : /jffs/scripts/FreshJR_QOS -rates' echo "" echo 'Development' echo ' Tested with ASUS AC-68U, FW384.9, using Adaptive QOS with Manual Bandwidth Settings' echo ' Copyright (C) 2017-2019 FreshJR - All Rights Reserved ' echo -en '\033[?7h' #enable line wrap } update(){ echo -en "\033c\e[3J" #clear screen echo -en '\033[?7l' #disable line wrap printf '\e[8;30;120t' #set height/width of terminal echo -e "\033[1;32mFreshJR QOS v${version} \033[0m" echo "Checking for updates" echo "" url="https://raw.githubusercontent.com/FreshJR07/FreshJR_QOS/master/FreshJR_QOS.sh" remotever=$(curl -fsN --retry 3 ${url} | grep "^version=" | sed -e s/version=//) if [ "$version" != "$remotever" ]; then echo " FreshJR QOS v${remotever} is now available!" echo "" echo -n " Would you like to update now? [1=Yes 2=No] : " read yn echo "" if ! [ "${yn}" == "1" ] ; then echo -e "\033[1;31;7m No Changes have been made \033[0m" echo "" return 0 fi else echo " You have the latest version installed" echo -n " Would you like to overwrite your existing installation anyway? [1=Yes 2=No] : " read yn echo "" if ! [ "${yn}" == "1" ] ; then echo -e "\033[1;31;7m No Changes have been made \033[0m" echo "" return 0 fi fi echo -e "Installing: FreshJR_QOS_v${remotever}" echo "" echo "Curl Output:" curl "https://raw.githubusercontent.com/FreshJR07/FreshJR_QOS/master/FreshJR_QOS.sh" -o /jffs/scripts/FreshJR_QOS --create-dirs && curl "https://raw.githubusercontent.com/FreshJR07/FreshJR_QOS/master/FreshJR_QoS_Stats.asp" -o "${webpath}" && sh /jffs/scripts/FreshJR_QOS -install exit } prompt_restart(){ echo "" echo -en " Would you like to \033[1;32m[Restart QoS]\033[0m for modifications to take effect? [1=Yes 2=No] : " read yn if [ "${yn}" == "1" ] ; then if grep -q -x '/jffs/scripts/FreshJR_QOS -start $1 & ' /jffs/scripts/firewall-start ; then #RMerlin install service "restart_qos;restart_firewall" else #Stock Install service "restart_qos;restart_firewall" cru a FreshJR_QOS_run_once "* * * * * /jffs/scripts/FreshJR_QOS -mount &" #cron task so keeps running after terminal is closed fi echo "" else echo "" if grep -q -x '/jffs/scripts/FreshJR_QOS -start $1 & ' /jffs/scripts/firewall-start ; then #RMerlin install echo -e "\033[1;31;7m Remember: [ Restart QOS ] for modifications to take effect \033[0m" echo "" else #Stock install echo -e "\033[1;31;7m Remember: [ Restart Router ] for modifications to take effect \033[0m" echo "" fi fi } menu(){ read_nvram echo -en "\033c\e[3J" #clear screen echo -en '\033[?7l' #disable line wrap printf '\e[8;30;120t' #set height/width of terminal echo -e "\033[1;32mFreshJR QOS v${version} released ${release} \033[0m" echo " (1) about explain functionality" echo " (2) update check for updates " echo "" echo " (3) QoS rules QoS rules (user defined)" echo " (4) QoS rates QoS rates (bandwidth allocation per category)" echo "" echo " (5) debug traffic control parameters" echo " (6) debug2 parsed nvram parameters" echo "" echo " (u) uninstall uninstall script" echo "" echo " (e) exit" echo "" echo " Current Setup:" echo " Local IP Remote IP Proto Local Port Remote Port Mark Dst" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$e1" "$e2" "$e3" "$e4" "$e5" "$e6" "$([ -z $e7 ] || echo "--> $(dst_2_name $e7)")" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$f1" "$f2" "$f3" "$f4" "$f5" "$f6" "$([ -z $f7 ] || echo "--> $(dst_2_name $f7)")" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$g1" "$g2" "$g3" "$g4" "$g5" "$g6" "$([ -z $g7 ] || echo "--> $(dst_2_name $g7)")" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$h1" "$h2" "$h3" "$h4" "$h5" "$h6" "$([ -z $h7 ] || echo "--> $(dst_2_name $h7)")" printf ' Gameip %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "${gameCIDR}" "" "$([ -z $gameCIDR ] || echo "both")" "" "$([ -z $gameCIDR ] || echo "!80:443")" "$([ -z $gameCIDR ] || echo "000000")" "--> Gaming" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r1)" "$r1" "$([ -z $d1 ] || echo "--> $(dst_2_name $d1)")" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r2)" "$r2" "$([ -z $d2 ] || echo "--> $(dst_2_name $d2)")" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r3)" "$r3" "$([ -z $d3 ] || echo "--> $(dst_2_name $d3)")" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r4)" "$r4" "$([ -z $d4 ] || echo "--> $(dst_2_name $d4)")" echo "" echo -en '\033[?7h' #enable line wrap echo -n "Make a selection: " read input case $input in '1') about read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; '2') update read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; '3') rules read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; '4') rates read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; '5') debug echo "" read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; '6') debug2 echo "" read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; 'u'|'U') clear echo -e "\033[1;32mFreshJR QOS v${version} released ${release} \033[0m" echo "" echo -en " Confirm you want to \033[1;32m[uninstall]\033[0m FreshJR_QOS [1=Yes 2=No] : " read yn if [ "${yn}" == "1" ] ; then echo "" sh /jffs/scripts/FreshJR_QOS -uninstall echo "" exit fi echo "" echo -e "\033[1;31;7m FreshJR QOS has NOT been uninstalled \033[0m" echo "" read -n 1 -s -r -p "(Press any key to return)" echo -en "\033c" #clear screen ;; 'e'|'E') echo -en "\033[1A\r\033[0K" return ;; esac menu } ##alternative install for (non-RMerlin) firmware stock_install(){ if [ "$(nvram get script_usbmount)" != "/jffs/scripts/script_usbmount" ] ; then echo "" echo -e "\033[1;32m Creating environment to trigger scripts post USB Mount \033[0m" nvram set script_usbmount="/jffs/scripts/script_usbmount" nvram commit fi if [ -f /jffs/scripts/script_usbmount ] ; then #check if script_usbmount exists if grep -q "#!/bin/sh" /jffs/scripts/script_usbmount ; then #check if script_usbmount header is correct : #if header is correct, do nothing else #if header is incorrect, fix header echo " Detected improper header in script_usbmount, fixing header" sed -i "1i #!/bin/sh" /jffs/scripts/script_usbmount chmod 0755 /jffs/scripts/script_usbmount fi sed -i '/FreshJR_QOS/d' /jffs/scripts/script_usbmount echo '/jffs/scripts/FreshJR_QOS mount &' >> /jffs/scripts/script_usbmount else #if script_usbmount did not exist then set it up entirely echo " Creating script_usbmount in /jffs/scripts/" echo " Placing FreshJR_QOS into script_usbmount" echo "#!/bin/sh" > /jffs/scripts/script_usbmount echo '/jffs/scripts/FreshJR_QOS mount &' >> /jffs/scripts/script_usbmount chmod 0755 /jffs/scripts/script_usbmount fi echo -e "\033[1;32mFreshJR QOS v${version} has been installed \033[0m" echo -e "\033[1;32m make sure a USB storage device is plugged in and \033[0m" echo -e "\033[1;31;7m [ reboot router ] to finalize installation\033[0m" echo "" } #Main program here, will execute different things depending on arguments arg1="$(echo "$1" | tr -d "-")" case "$arg1" in 'start'|'check'|'mount') ##RAN ON FIREWALL-START OR CRON TASK, (RAN ONLY POST USB MOUNT IF USING STOCK ASUS FIRMWARE) cru a FreshJR_QOS "30 3 * * * /jffs/scripts/FreshJR_QOS -check" #makes sure daily check if active cru d FreshJR_QOS_run_once #(used for stock firmware to trigger script and have it run after terminal is closed when making changes) if [ "$(nvram get qos_enable)" == "1" ] ; then for pid in $(pidof FreshJR_QOS); do if [ $pid != $$ ]; then if ! [ "$(ps -w | grep "${pid}.*\(install\|menu\|rules\|rates\)" | grep -v "grep")" ] ; then #kill all previous instances of FreshJR_QOS (-install, -menu, -rules, -rates instances are whitelisted) kill $pid logger -t "adaptive QOS" -s "Delayed Start Canceled" fi fi done ##check if should mount QoS_stats page if [ "$(uname -o)" == "ASUSWRT-Merlin" ] ; then buildno="$(nvram get buildno)"; #Example "User12 v17.2 Beta4" if [ "$(echo ${buildno} | tr -cd '.' | wc -c)" -ne 0 ] ; then #if has decimal CV="$(echo ${buildno} | cut -d "." -f 1 | grep -o '[0-9]\+' | tail -1)" #get first number before decimal --> 17 MV="$(echo ${buildno} | cut -d "." -f 2 | grep -o '[0-9]\+' | head -1)" #get first number after decimal --> 2 else CV="$(echo ${buildno} | grep -o '[0-9]\+' | head -1)" #get first number --> 17 MV="0" fi if [ "${CV}" -ge "382" ] ; then if ! [ "${webpath}" -ef "/www/QoS_Stats.asp" ] ; then mount -o bind "${webpath}" /www/QoS_Stats.asp fi #elif [ "${CV}" = "384" ] && [ ${MV} -ge "9" ] ; then fi fi read_nvram #needs to be set before parse_iptablerule or custom rates if [ "$arg1" == "start" ] ; then ##iptables rules will only be reapplied on firewall "start" due to receiving interface name wan="${2}" if [ -z "$wan" ] ; then wan="eth0" fi parse_iptablerule "${e1}" "${e2}" "${e3}" "${e4}" "${e5}" "${e6}" "${e7}" ip1_down ip1_up ##last two arguments are variables that get set "ByRef" parse_iptablerule "${f1}" "${f2}" "${f3}" "${f4}" "${f5}" "${f6}" "${f7}" ip2_down ip2_up parse_iptablerule "${g1}" "${g2}" "${g3}" "${g4}" "${g5}" "${g6}" "${g7}" ip3_down ip3_up parse_iptablerule "${h1}" "${h2}" "${h3}" "${h4}" "${h5}" "${h6}" "${h7}" ip4_down ip4_up iptable_down_rules 2>&1 | logger -t "adaptive QOS" iptable_up_rules 2>&1 | logger -t "adaptive QOS" logger -t "adaptive QOS" -s -- "TC Modification Delayed Start (5min)" sleep 300s fi if [ "$arg1" == "mount" ] ; then logger -t "adaptive QOS" -s -- "--Post USB Mount-- Delayed Start (10min)" sleep 600s fi current_undf_rule="$(tc filter show dev br0 | grep -v "/" | grep "000ffff" -B1)" undf_flowid=$(echo $current_undf_rule | grep -o "flowid.*" | cut -d" " -f2 | head -1) undf_prio=$(echo $current_undf_rule | grep -o "pref.*" | cut -d" " -f2 | head -1) #if TC modifcations have no been applied then run modification script #eg (if rule setting unidentified traffic to 1:17 exists) --> run modification script if [ "${undf_flowid}" == "1:17" ] ; then if [ "$arg1" == "check" ] ; then logger -t "adaptive QOS" -s "Scheduled Persistence Check -> Reapplying Changes" fi #this section is only used stock ASUS firmware. It will will evaluate on (-mount && -check) parameters only on STOCK firmware if [ "$(nvram get script_usbmount)" == "/jffs/scripts/script_usbmount" ] && [ "$arg1" != "start" ] ; then wan="$(iptables -vL -t mangle | grep -m 1 "BWDPI_FILTER" | tr -s ' ' | cut -d ' ' -f 7)" #try to detect upload interface automatically if [ -z "$wan" ] ; then wan="eth0" fi parse_iptablerule "${e1}" "${e2}" "${e3}" "${e4}" "${e5}" "${e6}" "${e7}" ip1_down ip1_up ##last two arguments are variables that get set "ByRef" parse_iptablerule "${f1}" "${f2}" "${f3}" "${f4}" "${f5}" "${f6}" "${f7}" ip2_down ip2_up parse_iptablerule "${g1}" "${g2}" "${g3}" "${g4}" "${g5}" "${g6}" "${g7}" ip3_down ip3_up parse_iptablerule "${h1}" "${h2}" "${h3}" "${h4}" "${h5}" "${h6}" "${h7}" ip4_down ip4_up iptable_down_rules 2>&1 | logger -t "adaptive QOS" iptable_up_rules 2>&1 | logger -t "adaptive QOS" fi set_tc_variables #needs to be set before parse_tcrule ##last two arguments are variables that get set "ByRef" parse_tcrule "${r1}" "${d1}" tc1_down tc1_up parse_tcrule "${r2}" "${d2}" tc2_down tc2_up parse_tcrule "${r3}" "${d3}" tc3_down tc3_up parse_tcrule "${r4}" "${d4}" tc4_down tc4_up tc_redirection_down_rules "$undf_prio" 2>&1 | logger -t "adaptive QOS" #forwards terminal output & errors to logger tc_redirection_up_rules "$undf_prio" 2>&1 | logger -t "adaptive QOS" #forwards terminal output & errors to logger if [ "$ClassesPresent" -lt "8" ] ; then logger -t "adaptive QOS" -s "Adaptive QOS not fully done setting up prior to modification script" logger -t "adaptive QOS" -s "(Skipping class modification, delay trigger time period needs increase)" else if [ "$DownCeil" -gt "500" ] && [ "$UpCeil" -gt "500" ] ; then custom_rates 2>&1 | logger -t "adaptive QOS" #forwards terminal output & errors to logger fi fi else if [ "$arg1" == "check" ] ; then logger -t "adaptive QOS" -s "Scheduled Persistence Check -> No modifications necessary" else logger -t "adaptive QOS" -s "No modifications necessary" fi fi fi ;; 'install'|'enable') ## INSTALLS AND TURNS ON SCRIPT printf '\e[8;30;120t' #set height/width of terminal clear chmod 0755 /jffs/scripts/FreshJR_QOS if grep -qs "FreshJR_QOS" /jffs/scripts/init-start ; then sed -i '/FreshJR_QOS/d' /jffs/scripts/init-start 2>/dev/null fi if [ "/jffs/scripts/FreshJR_QOS_fakeTC" -ef "/bin/tc" ] || [ "/jffs/scripts/FreshJR_QOS_fakeTC" -ef "/usr/sbin/tc" ] ; then ##uninstall previous version FreshJR_QOS_fakeTC if not already uninstalled echo "Old version of FreshJR_QOS_fast(fakeTC) has been Detected" if [ -e "/bin/tc" ] ; then umount /bin/tc &> /dev/null #suppresses error if present mount -o bind /usr/sbin/faketc /bin/tc elif [ -e "/usr/sbin/tc" ] ; then umount /usr/sbin/tc &> /dev/null #suppresses error if present mount -o bind /usr/sbin/faketc /usr/sbin/tc fi rm -f /jffs/scripts/FreshJR_QOS_fakeTC nvram unset qos_downrates nvram unset qos_uprates nvram commit if [ "/usr/sbin/faketc" -ef "/usr/sbin/tc" ] || [ "/usr/sbin/faketc" -ef "/bin/tc" ] ; then echo "Old version of FreshJR_QOS_fast(fakeTC) has been Successfully Uninstalled" else echo "FreshJR_QOS_fast(fakeTC) Uninstall Process has been Initiated " echo -e "\033[1;31;7m Please [ reboot router ] to finish the uninstall process \033[0m" echo -e "\033[1;31;7m Rerun this install procedure after system reboot \033[0m" exit 0 fi fi if [ "$(uname -o)" != "ASUSWRT-Merlin" ] ; then ##GIVE USER CHOICE TO RUN STOCK INSTALL IF Non-RMerlin FIRMWARE detected echo -e "\033[1;31m Non-RMerlin Firmware Detected \033[0m" echo -e -n "\033[1;31m Is this installation for (Stock / Default / Unmodified) Asus firmware? [1=Yes 2=No] : \033[0m" # Display prompt in red read yn echo "" case $yn in '1') sed -i '/FreshJR_QOS/d' /jffs/scripts/firewall-start 2>/dev/null stock_install; exit 0 ;; '2') sed -i '/FreshJR_QOS/d' /jffs/scripts/script_usbmount 2>/dev/null echo -e "\033[1;32m Installing RMerlin version of the script \033[0m" # Display prompt in red echo "" break ;; *) echo "Invalid Option" echo "ABORTING INSTALLATION " exit 0 ;; esac fi if [ -f /jffs/scripts/firewall-start ] ; then #check if firewall-start exists if grep -q "#!/bin/sh" /jffs/scripts/firewall-start ; then #check if firewall-start header is correct : #if header is correct, do nothing else #if header is incorrect, fix header echo "Detected improper header in firewall-start, fixing header" sed -i "1i #!/bin/sh" /jffs/scripts/firewall-start chmod 0755 /jffs/scripts/firewall-start fi if grep -q -x '/jffs/scripts/FreshJR_QOS -start $1 & ' /jffs/scripts/firewall-start ; then #check if FreshJR_QOS is present as item in firewall start : #if FreshJR_QOS is present do nothing else #if not, appened it to the last line (also delete any previously formated entry) echo "Placing FreshJR_QOS entry into firewall-start" sed -i '/FreshJR_QOS/d' /jffs/scripts/firewall-start echo '/jffs/scripts/FreshJR_QOS -start $1 & ' >> /jffs/scripts/firewall-start fi else #if firewall-start does not exist then set it up entirely echo "Firewall-start not detected, creating firewall-start" echo "Placing FreshJR_QOS entry into firewall-start" echo "#!/bin/sh" > /jffs/scripts/firewall-start echo '/jffs/scripts/FreshJR_QOS -start $1 & ' >> /jffs/scripts/firewall-start chmod 0755 /jffs/scripts/firewall-start fi cru a FreshJR_QOS "30 3 * * * /jffs/scripts/FreshJR_QOS -check" if [ "$(uname -o)" == "ASUSWRT-Merlin" ] ; then #Mounts webpage on RMerlin v382+ buildno="$(nvram get buildno)"; #Example "User12 v17.2 Beta4" if [ "$(echo ${buildno} | tr -cd '.' | wc -c)" -ne 0 ] ; then #if has decimal CV="$(echo ${buildno} | cut -d "." -f 1 | grep -o '[0-9]\+' | tail -1)" #get first number before decimal --> 17 MV="$(echo ${buildno} | cut -d "." -f 2 | grep -o '[0-9]\+' | head -1)" #get first number after decimal --> 2 else CV="$(echo ${buildno} | grep -o '[0-9]\+' | head -1)" #get first number --> 17 MV="0" fi if [ "${CV}" -ge "382" ] ; then if ! [ "${webpath}" -ef "/www/QoS_Stats.asp" ] ; then mount -o bind "${webpath}" /www/QoS_Stats.asp fi #elif [ "${CV}" = "384" ] && [ ${MV} -ge "9" ] ; then fi fi #shortcut to launching FreshJR_QOS (/usr/bin was readonly) alias freshjr="sh /jffs/scripts/FreshJR_QOS -menu" alias freshjrqos="sh /jffs/scripts/FreshJR_QOS -menu" alias freshjr_qos="sh /jffs/scripts/FreshJR_QOS -menu" alias FreshJR_QOS="sh /jffs/scripts/FreshJR_QOS -menu" sed -i '/fresh/d' /jffs/configs/profile.add 2>/dev/null echo 'alias freshjr="sh /jffs/scripts/FreshJR_QOS -menu"' >> /jffs/configs/profile.add echo 'alias freshjrqos="sh /jffs/scripts/FreshJR_QOS -menu"' >> /jffs/configs/profile.add echo 'alias freshjr_qos="sh /jffs/scripts/FreshJR_QOS -menu"' >> /jffs/configs/profile.add echo 'alias FreshJR_QOS="sh /jffs/scripts/FreshJR_QOS -menu"' >> /jffs/configs/profile.add echo -e "\033[1;32mFreshJR QOS v${version} has been installed \033[0m" echo "" echo -n " Advanced configuration available via: " if [ "$(uname -o)" == "ASUSWRT-Merlin" ] ; then if [ -e "/jffs/scripts/amtm" ] ; then echo -e "\033[1;32m[ WebUI ]\033[0m or \033[1;32m[ /jffs/scripts/FreshJR_QOS -menu ]\033[0m or \033[1;32m[ amtm ]\033[0m " else echo -e "\033[1;32m[ WebUI ]\033[0m or \033[1;32m[ /jffs/scripts/FreshJR_QOS -menu ]\033[0m " fi else echo -e "\033[1;32m[ /jffs/scripts/FreshJR_QOS -menu ]\033[0m " fi [ "$(nvram get qos_enable)" == "1" ] && prompt_restart ;; 'uninstall') ## UNINSTALLS SCRIPT AND DELETES FILES sed -i '/FreshJR_QOS/d' /jffs/scripts/firewall-start 2>/dev/null #remove FreshJR_QOS from firewall start sed -i '/FreshJR_QOS/d' /jffs/scripts/script_usbmount 2>/dev/null #remove FreshJR_QOS from script_usbmount - only used on stock ASUS firmware installs sed -i '/freshjr/d' /jffs/configs/profile.add 2>/dev/null #remove aliases used to launch interactive mode sed -i '/FreshJR/d' /jffs/configs/profile.add 2>/dev/null cru d FreshJR_QOS rm -f /jffs/scripts/FreshJR_QOS umount /www/QoS_Stats.asp &> /dev/null #suppresses error if present mount -o bind /www/QoS_Stats.asp /www/QoS_Stats.asp umount /www/QoS_Stats.asp &> /dev/null rm -f "${webpath}" if [ "$(nvram get script_usbmount)" == "/jffs/scripts/script_usbmount" ] ; then #only used on stock ASUS firmware installs nvram unset script_usbmount fi nvram set fb_comment="" nvram set fb_email_dbg="" nvram commit echo -e "\033[1;32m FreshJR QOS has been uninstalled \033[0m" ;; 'disable') ## TURNS OFF SCRIPT BUT KEEP FILES sed -i '/FreshJR_QOS/d' /jffs/scripts/firewall-start 2>/dev/null sed -i '/FreshJR_QOS/d' /jffs/scripts/script_usbmount 2>/dev/null cru d FreshJR_QOS umount /www/QoS_Stats.asp &> /dev/null #suppresses error if present mount -o bind /www/QoS_Stats.asp /www/QoS_Stats.asp umount /www/QoS_Stats.asp &> /dev/null ;; 'debug') debug ;; 'debug2') debug2 ;; 'debug3') debug3 ;; 'appdb') appdb "$2" ;; 'gameip') read_nvram gameip "$2" ;; 'rules') read_nvram rules ;; 'rates') read_nvram rates ;; 'about') about ;; 'update') update ;; 'menu') menu ;; 'isinstalled') if grep -q -x '/jffs/scripts/FreshJR_QOS -start $1 & ' /jffs/scripts/firewall-start ; then exit 0 #script IS installed else exit 1 #script in NOT installed fi ;; 'isuptodate') url="https://raw.githubusercontent.com/FreshJR07/FreshJR_QOS/master/FreshJR_QOS.sh" remotever=$(curl -fsN --retry 3 ${url} | grep "^version=" | sed -e s/version=//) if [ "$version" == "$remotever" ]; then exit 0 #script IS current else exit 1 #script is NOT up to date fi ;; *) read_nvram echo -en "\033c\e[3J" #clear screen echo -en '\033[?7l' #disable line wrap # printf '\e[8;30;120t' #set height/width of terminal echo -e "\033[1;32mFreshJR QOS v${version} \033[0m" echo -e "\033[1;32mreleased ${release} \033[0m" echo "" echo "You have inputted an UNRECOGNIZED COMMAND" echo "" echo " Available commands:" echo "" echo " FreshJR_QOS -about explains functionality" echo " FreshJR_QOS -update checks for updates " echo "" echo " FreshJR_QOS -install install script" echo " FreshJR_QOS -uninstall uninstall script && delete from disk " echo "" echo " FreshJR_QOS -enable enable script " echo " FreshJR_QOS -disable disable script but do not delete from disk" echo "" echo " FreshJR_QOS -debug print traffic control parameters" echo " FreshJR_QOS -debug2 print parsed nvram parameters" echo "" echo ' FreshJR_QOS -appdb "App Name" looks up mark for specifed application' echo "" echo " FreshJR_QOS -rules create/modify custom rules" echo " FreshJR_QOS -rates modify bandwidth allocations" echo "" echo ' FreshJR_QOS -menu interactive main menu' echo "" echo " Current Setup:" echo " Local IP Remote IP Proto Local Port Remote Port Mark Dst" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$e1" "$e2" "$e3" "$e4" "$e5" "$e6" "$([ -z $e7 ] || echo "--> $(dst_2_name $e7)")" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$f1" "$f2" "$f3" "$f4" "$f5" "$f6" "$([ -z $f7 ] || echo "--> $(dst_2_name $f7)")" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$g1" "$g2" "$g3" "$g4" "$g5" "$g6" "$([ -z $g7 ] || echo "--> $(dst_2_name $g7)")" printf ' Rule %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "$h1" "$h2" "$h3" "$h4" "$h5" "$h6" "$([ -z $h7 ] || echo "--> $(dst_2_name $h7)")" printf ' Gameip %-19s %-19s %-6s %-14s %-14s %-7s %-10s\n' "${gameCIDR}" "" "$([ -z $gameCIDR ] || echo "both")" "" "$([ -z $gameCIDR ] || echo "!80:443")" "$([ -z $gameCIDR ] || echo "000000")" "--> Gaming" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r1)" "$r1" "$([ -z $d1 ] || echo "--> $(dst_2_name $d1)")" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r2)" "$r2" "$([ -z $d2 ] || echo "--> $(dst_2_name $d2)")" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r3)" "$r3" "$([ -z $d3 ] || echo "--> $(dst_2_name $d3)")" printf ' Appdb %-44s %-7s %-10s\n' "$(mark_2_name $r4)" "$r4" "$([ -z $d4 ] || echo "--> $(dst_2_name $d4)")" echo "" echo -en '\033[?7h' #enable line wrap ;; esac