From 5a6c33f69368fa0df0eb41f85f18ca6c9e14ae7a Mon Sep 17 00:00:00 2001 From: Toastman Date: Sat, 5 May 2012 17:17:08 +0700 Subject: [PATCH] revised QOS/BWLimiter (removed the default limits for unlisted clients) --- release/src/router/httpd/bwm.c | 8 +- release/src/router/httpd/tomato.c | 6 + release/src/router/nvram/defaults.c | 6 + release/src/router/rc/Makefile | 1 + release/src/router/rc/firewall.c | 5 + release/src/router/rc/qoslimit.c | 377 ++++++++++++++++++++++++++++++ release/src/router/rc/rc.h | 5 + release/src/router/rc/services.c | 11 + release/src/router/rc/wan.c | 2 + release/src/router/www/about.asp | 3 +- release/src/router/www/bwm-common.js | 8 + release/src/router/www/qos-qoslimit.asp | 277 ++++++++++++++++++++++ release/src/router/www/status-devices.asp | 11 +- release/src/router/www/tomato.js | 3 +- 14 files changed, 717 insertions(+), 6 deletions(-) create mode 100644 release/src/router/rc/qoslimit.c create mode 100644 release/src/router/www/qos-qoslimit.asp diff --git a/release/src/router/httpd/bwm.c b/release/src/router/httpd/bwm.c index dbd83f0bbc..5ae4029846 100644 --- a/release/src/router/httpd/bwm.c +++ b/release/src/router/httpd/bwm.c @@ -232,7 +232,13 @@ void asp_netdev(int argc, char **argv) // if (sscanf(p + 1, "%lu%*u%*u%*u%*u%*u%*u%*u%lu", &rx, &tx) != 2) continue; - web_printf("%c'%s':{rx:0x%lx,tx:0x%lx}", comma, ifname, rx, tx); + if (!strcmp(ifname, "imq1")) + web_printf("%c'%s':{rx:0x0,tx:0x%lx}", comma, ifname, rx, tx); + else if (!strcmp(ifname, "imq2")) + web_printf("%c'%s':{rx:0x%lx,tx:0x0}", comma, ifname, rx, tx); + else + web_printf("%c'%s':{rx:0x%lx,tx:0x%lx}", comma, ifname, rx, tx); + comma = ','; } diff --git a/release/src/router/httpd/tomato.c b/release/src/router/httpd/tomato.c index 71f0976915..0a522e765a 100644 --- a/release/src/router/httpd/tomato.c +++ b/release/src/router/httpd/tomato.c @@ -1128,6 +1128,12 @@ static const nvset_t nvset_list[] = { { "ne_vbeta", V_NUM }, { "ne_vgamma", V_NUM }, +// qos-bw-limiter + { "qosl_enable", V_01 }, + { "qosl_rules", V_LENGTH(0, 4096) }, + /*qosl_ibw unused - qos_ibw shared*/ + /*qosl_obw unused - qos_obw shared*/ + //NoCatSplash. Victek. #ifdef TCONFIG_NOCAT { "NC_enable", V_01 }, diff --git a/release/src/router/nvram/defaults.c b/release/src/router/nvram/defaults.c index 8b74d62916..0922c7ec91 100644 --- a/release/src/router/nvram/defaults.c +++ b/release/src/router/nvram/defaults.c @@ -532,6 +532,12 @@ const defaults_t defaults[] = { { "ne_vbeta", "3" }, // " { "ne_vgamma", "2" }, // " +// qos-bw-limiter + { "qosl_enable", "0" }, +// { "qosl_obw", "" }, //unused - used qos_obw +// { "qosl_ibw", "" }, //unused - used qos_obw + { "qosl_rules", "" }, + // access restrictions { "rruleN", "0" }, { "rrule0", "0|1320|300|31|||word text\n^begins-with.domain.\n.ends-with.net$\n^www.exact-domain.net$|0|example" }, diff --git a/release/src/router/rc/Makefile b/release/src/router/rc/Makefile index e955804bf2..6a95f19e60 100644 --- a/release/src/router/rc/Makefile +++ b/release/src/router/rc/Makefile @@ -15,6 +15,7 @@ OBJS += firewall.o ppp.o telssh.o wnas.o OBJS += listen.o redial.o led.o qos.o forward.o misc.o mtd.o OBJS += buttons.o restrict.o gpio.o sched.o OBJS += arpbind.o +OBJS += qoslimit.o # heartbeat.o ifeq ($(TCONFIG_USB),y) diff --git a/release/src/router/rc/firewall.c b/release/src/router/rc/firewall.c index ec9e0ff8ba..c8ab39e5cd 100644 --- a/release/src/router/rc/firewall.c +++ b/release/src/router/rc/firewall.c @@ -559,6 +559,8 @@ static void mangle_table(void) if (wanup) { ipt_qos(); + //1 for mangle + ipt_qoslimit(1); p = nvram_safe_get("nf_ttl"); if (strncmp(p, "c:", 2) == 0) { @@ -637,6 +639,9 @@ static void nat_table(void) ":%s - [0:0]\n", chain_wan_prerouting); + //2 for nat + ipt_qoslimit(2); + if (gateway_mode) { strlcpy(lanaddr, nvram_safe_get("lan_ipaddr"), sizeof(lanaddr)); strlcpy(lanmask, nvram_safe_get("lan_netmask"), sizeof(lanmask)); diff --git a/release/src/router/rc/qoslimit.c b/release/src/router/rc/qoslimit.c new file mode 100644 index 0000000000..90c965d65a --- /dev/null +++ b/release/src/router/rc/qoslimit.c @@ -0,0 +1,377 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2008 Jonathan Zarate + Copyright (C) 2011 Deon 'PrinceAMD' Thomas + rate limit & connection limit by conanxu +*/ + +#include "rc.h" + +#include +static const char *qoslimitfn = "/etc/qoslimit"; + +/*int chain +1 = MANGLE +2 = NAT +*/ + +#define IP_ADDRESS 0 +#define MAC_ADDRESS 1 +#define IP_RANGE 2 + +void address_checker (int * address_type, char *ipaddr_old, char *ipaddr) +{ + char * second_part, *last_dot; + int length_to_minus, length_to_dot; + + second_part = strchr(ipaddr_old, '-'); + if (second_part != NULL) { + /* ip range */ + *address_type = IP_RANGE; + if (strchr(second_part+1, '.') != NULL) { + /* long notation */ + strcpy (ipaddr, ipaddr_old); + } + else { + /* short notation */ + last_dot = strrchr(ipaddr_old, '.'); + length_to_minus = second_part - ipaddr_old; + length_to_dot = last_dot- ipaddr_old; + strncpy(ipaddr, ipaddr_old, length_to_minus + 1); + strncpy(ipaddr + length_to_minus + 1, ipaddr, length_to_dot + 1); + strcpy(ipaddr + length_to_minus + length_to_dot + 2, second_part +1); + } + } + else { + /* mac address of ipaddres */ + if (strlen(ipaddr_old) != 17) { + /* IP_ADDRESS */ + *address_type = IP_ADDRESS; + } + else { + /* MAC ADDRESS */ + *address_type = MAC_ADDRESS; + } + strcpy (ipaddr, ipaddr_old); + } +} + +void ipt_qoslimit(int chain) +{ + char *buf; + char *g; + char *p; + char *ibw,*obw;//bandwidth + char seq[4];//mark number + int iSeq = 10; + char *ipaddr_old; + char ipaddr[30];//ip address + char *dlrate,*dlceil;//guaranteed rate & maximum rate for download + char *ulrate,*ulceil;//guaranteed rate & maximum rate for upload + char *priority;//priority + char *lanipaddr; //lan ip address + char *lanmask; //lan netmask + char *tcplimit,*udplimit;//tcp connection limit & udp packets per second + char *laninface; // lan interface + int priority_num; + int i, address_type; + + //qosl is enabled? + if (!nvram_get_int("qosl_enable")) return; + + //read qos1rules from nvram + g = buf = strdup(nvram_safe_get("qosl_rules")); + + ibw = nvram_safe_get("qos_ibw"); // Read from QOS setting - KRP + obw = nvram_safe_get("qos_obw"); // Read from QOS setting - KRP + + lanipaddr = nvram_safe_get("lan_ipaddr"); + lanmask = nvram_safe_get("lan_netmask"); + laninface = nvram_safe_get("lan_ifname"); + + + //MANGLE + if (chain == 1) + { + ipt_write( + "-A PREROUTING -j IMQ -i %s --todev 1\n" + "-A POSTROUTING -j IMQ -o %s --todev 2\n" + ,laninface,laninface); + } + + while (g) { + /* + ipaddr_old")) == NULL) break; + i = vstrsep(p, "<", &ipaddr_old, &dlrate, &dlceil, &ulrate, &ulceil, &priority, &tcplimit, &udplimit); + if (i!=8) continue; + + priority_num = atoi(priority); + if ((priority_num < 0) || (priority_num > 5)) continue; + + if (!strcmp(ipaddr_old,"")) continue; + + address_checker (&address_type, ipaddr_old, ipaddr); + sprintf(seq,"%d",iSeq); + iSeq++; + + if (!strcmp(dlceil,"")) strcpy(dlceil, dlrate); + if (strcmp(dlrate,"") && strcmp(dlceil, "")) { + if(chain == 1) { + switch (address_type) + { + case IP_ADDRESS: + ipt_write( + "-A POSTROUTING ! -s %s/%s -d %s -j MARK --set-mark %s\n" + ,lanipaddr,lanmask,ipaddr,seq); + break; + case MAC_ADDRESS: + break; + case IP_RANGE: + ipt_write( + "-A POSTROUTING ! -s %s/%s -m iprange --dst-range %s -j MARK --set-mark %s\n" + ,lanipaddr,lanmask,ipaddr,seq); + break; + } + } + } + + if (!strcmp(ulceil,"")) strcpy(ulceil, ulrate); + if (strcmp(ulrate,"") && strcmp(ulceil, "")) { + if (chain == 1) { + switch (address_type) + { + case IP_ADDRESS: + ipt_write( + "-A PREROUTING -s %s ! -d %s/%s -j MARK --set-mark %s\n" + ,ipaddr,lanipaddr,lanmask,seq); + break; + case MAC_ADDRESS: + ipt_write( + "-A PREROUTING -m mac --mac-source %s ! -d %s/%s -j MARK --set-mark %s\n" + ,ipaddr,lanipaddr,lanmask,seq); + break; + case IP_RANGE: + ipt_write( + "-A PREROUTING -m iprange --src-range %s ! -d %s/%s -j MARK --set-mark %s\n" + ,ipaddr,lanipaddr,lanmask,seq); + break; + } + } + } + + if(atoi(tcplimit) > 0){ + if (chain == 2) { + switch (address_type) + { + case IP_ADDRESS: + ipt_write( + "-A PREROUTING -s %s -p tcp --syn -m connlimit --connlimit-above %s -j DROP\n" + ,ipaddr,tcplimit); + break; + case MAC_ADDRESS: + ipt_write( + "-A PREROUTING -m mac --mac-source %s -p tcp --syn -m connlimit --connlimit-above %s -j DROP\n" + ,ipaddr,tcplimit); + break; + case IP_RANGE: + ipt_write( + "-A PREROUTING -m iprange --src-range %s -p tcp --syn -m connlimit --connlimit-above %s -j DROP\n" + ,ipaddr,tcplimit); + break; + } + } + } + if(atoi(udplimit) > 0){ + if (chain == 2) { + switch (address_type) + { + case IP_ADDRESS: + ipt_write( + "-A PREROUTING -s %s -p udp -m limit --limit %s/sec -j ACCEPT\n" + ,ipaddr,udplimit); + break; + case MAC_ADDRESS: + ipt_write( + "-A PREROUTING -m mac --mac-source %s -p udp -m limit --limit %s/sec -j ACCEPT\n" + ,ipaddr,udplimit); + break; + case IP_RANGE: + ipt_write( + "-A PREROUTING -m iprange --src-range %s -p udp -m limit --limit %s/sec -j ACCEPT\n" + ,ipaddr,udplimit); + break; + } + } + } + } + free(buf); +} + +// read nvram into files +void start_qoslimit(void) +{ + FILE *tc; + char *buf; + char *g; + char *p; + char *ibw,*obw;//bandwidth + char seq[4];//mark number + int iSeq = 10; + char *ipaddr_old; + char ipaddr[30];//ip address + char *dlrate,*dlceil;//guaranteed rate & maximum rate for download + char *ulrate,*ulceil;//guaranteed rate & maximum rate for upload + char *priority;//priority + char *lanipaddr; //lan ip address + char *lanmask; //lan netmask + char *tcplimit,*udplimit;//tcp connection limit & udp packets per second + int priority_num; + int i, address_type; + int s[6]; + + //qosl is enabled? + if (!nvram_get_int("qosl_enable")) return; + + //read qosl rules from nvram + g = buf = strdup(nvram_safe_get("qosl_rules")); + + ibw = nvram_safe_get("qos_ibw"); // Read from QOS setting - KRP + obw = nvram_safe_get("qos_obw"); // Read from QOS setting - KRP + + lanipaddr = nvram_safe_get("lan_ipaddr"); + lanmask = nvram_safe_get("lan_netmask"); + + if ((tc = fopen(qoslimitfn, "w")) == NULL) return; + + fprintf(tc, + "#!/bin/sh\n" + "ip link set imq1 up\n" + "ip link set imq2 up\n" + "\n" + "tc qdisc del dev imq1 root 2>/dev/null\n" + "tc qdisc del dev imq2 root 2>/dev/null\n" + "tc qdisc del dev br0 root 2>/dev/null\n" //fix me [why should mac get filter here??] + "\n" + "TCAM=\"tc class add dev br0\"\n" //fix me + "TFAM=\"tc filter add dev br0\"\n" //fix me + "TQAM=\"tc qdisc add dev br0\"\n" //fix me + "\n" + "TCA=\"tc class add dev imq2\"\n" + "TFA=\"tc filter add dev imq2\"\n" + "TQA=\"tc qdisc add dev imq2\"\n" + "\n" + "SFQ=\"sfq perturb 10\"\n" + "\n" + "TCAU=\"tc class add dev imq1\"\n" + "TFAU=\"tc filter add dev imq1\"\n" + "TQAU=\"tc qdisc add dev imq1\"\n" + "\n" + "tc qdisc add dev imq2 root handle 1: htb\n" + "tc class add dev imq2 parent 1: classid 1:1 htb rate %skbit\n" + "\n" + "tc qdisc add dev br0 root handle 1: htb\n" + "tc class add dev br0 parent 1: classid 1:1 htb rate %skbit\n" + "\n" + "tc qdisc add dev imq1 root handle 1: htb\n" + "tc class add dev imq1 parent 1: classid 1:1 htb rate %skbit\n" + "\n" + ,ibw,ibw,obw + ); + + while (g) { + /* + ipaddr_old")) == NULL) break; + i = vstrsep(p, "<", &ipaddr_old, &dlrate, &dlceil, &ulrate, &ulceil, &priority, &tcplimit, &udplimit); + if (i!=8) continue; + priority_num = atoi(priority); + if ((priority_num < 0) || (priority_num > 5)) continue; + if (!strcmp(ipaddr_old,"")) continue; + + address_checker(&address_type, ipaddr_old, ipaddr); + sprintf(seq,"%d",iSeq); + iSeq++; + if (!strcmp(dlceil,"")) strcpy(dlceil, dlrate); + if (strcmp(dlrate,"") && strcmp(dlceil, "")) { + if (address_type != MAC_ADDRESS) { + fprintf(tc, + "$TCA parent 1:1 classid 1:%s htb rate %skbit ceil %skbit prio %s\n" + "$TQA parent 1:%s handle %s: $SFQ\n" + "$TFA parent 1:0 prio %s protocol ip handle %s fw flowid 1:%s\n" + "\n" + ,seq,dlrate,dlceil,priority + ,seq,seq + ,priority,seq,seq); + } + else if (address_type == MAC_ADDRESS ) { + sscanf(ipaddr, "%02X:%02X:%02X:%02X:%02X:%02X",&s[0],&s[1],&s[2],&s[3],&s[4],&s[5]); + + fprintf(tc, + "$TCAM parent 1:1 classid 1:%s htb rate %skbit ceil %skbit prio %s\n" + "$TQAM parent 1:%s handle %s: $SFQ\n" + "$TFAM parent 1:0 protocol ip prio %s u32 match u16 0x0800 0xFFFF at -2 match u32 0x%02X%02X%02X%02X 0xFFFFFFFF at -12 match u16 0x%02X%02X 0xFFFF at -14 flowid 1:%s\n" + "\n" + ,seq,dlrate,dlceil,priority + ,seq,seq + ,priority,s[2],s[3],s[4],s[5],s[0],s[1],seq); + } + } + + if (!strcmp(ulceil,"")) strcpy(ulceil, dlrate); + if (strcmp(ulrate,"") && strcmp(ulceil, "")) { + fprintf(tc, + "$TCAU parent 1:1 classid 1:%s htb rate %skbit ceil %skbit prio %s\n" + "$TQAU parent 1:%s handle %s: $SFQ\n" + "$TFAU parent 1:0 prio %s protocol ip handle %s fw flowid 1:%s\n" + "\n" + ,seq,ulrate,ulceil,priority + ,seq,seq + ,priority,seq,seq); + } + } + free(buf); + + fclose(tc); + chmod(qoslimitfn, 0700); + + //fake start + eval((char *)qoslimitfn, "start"); +} + +void stop_qoslimit(void) +{ + FILE *f; + char *s = "/tmp/stop_qoslimittc.sh"; + + if ((f = fopen(s, "w")) == NULL) return; + + fprintf(f, + "#!/bin/sh\n" + "tc qdisc del dev imq2 root\n" + "tc qdisc del dev imq1 root\n" + "tc qdisc del dev br0 root\n" //fix me + "ip link set imq1 down\n" + "ip link set imq2 down\n" //take imq's down - Toastman + + "\n" + ); + + fclose(f); + chmod(s, 0700); + //fake stop + eval((char *)s, "stop"); +} +/* + +PREROUTING (mn) ----> x ----> FORWARD (f) ----> + ----> POSTROUTING (n) + QD | ^ + | | + v | + INPUT (f) OUTPUT (mnf) + + +*/ diff --git a/release/src/router/rc/rc.h b/release/src/router/rc/rc.h index 008206e598..bdf7aab919 100644 --- a/release/src/router/rc/rc.h +++ b/release/src/router/rc/rc.h @@ -475,6 +475,11 @@ static inline void stop_vpn_eas() { } #define write_vpn_resolv(f) (0) #endif +// qoslimit.c +extern void ipt_qoslimit(int chain); +extern void start_qoslimit(void); +extern void stop_qoslimit(void); + // arpbind.c extern void start_arpbind(void); extern void stop_arpbind(void); diff --git a/release/src/router/rc/services.c b/release/src/router/rc/services.c index b258afd4f1..399dad4597 100644 --- a/release/src/router/rc/services.c +++ b/release/src/router/rc/services.c @@ -2239,6 +2239,17 @@ TOP: goto CLEAR; } + if (strcmp(service, "qoslimit") == 0) { + if (action & A_STOP) { + stop_qoslimit(); + } + stop_firewall(); start_firewall(); // always restarted + if (action & A_START) { + start_qoslimit(); + } + goto CLEAR; + } + if (strcmp(service, "upnp") == 0) { if (action & A_STOP) { stop_upnp(); diff --git a/release/src/router/rc/wan.c b/release/src/router/rc/wan.c index 2b1a5c9d4e..3c39abd518 100644 --- a/release/src/router/rc/wan.c +++ b/release/src/router/rc/wan.c @@ -937,6 +937,7 @@ void start_wan_done(char *wan_ifname) start_dnsmasq(); start_firewall(); start_qos(); + start_qoslimit(); start_arpbind(); @@ -1030,6 +1031,7 @@ void stop_wan(void) #endif stop_vpn_eas(); stop_arpbind(); + stop_qoslimit(); stop_qos(); stop_upnp(); //!!TB - moved from stop_services() stop_firewall(); diff --git a/release/src/router/www/about.asp b/release/src/router/www/about.asp index 198e84aa2e..6e4da902db 100644 --- a/release/src/router/www/about.asp +++ b/release/src/router/www/about.asp @@ -146,7 +146,6 @@ Captive Portal Copyright (C) 2011 Ofer Chen & Vicente Soriano
Copyright (C) 2011 MichaƂ Rupental
http://openlinksys.info

- "JYAvenard" Features:
@@ -159,7 +158,6 @@ Copyright (C) 2010-2011 Jean-Yves Avenard
jean-yves@avenard.org

- "Teaman" Features:
- QOS-detailed & ctrate improved filters
- Per-IP bandwidth monitoring of LAN clients [cstats v2]
@@ -188,6 +186,7 @@ Copyright (C) 2012 Tiomo
- 250 entry limit in Static DHCP & Wireless Filter
- 500 entry limit in Access Restriction rules
- Up to 80 QOS rules
+- IMQ based QOS/Bandwidth Limiter
- Configurable QOS class names
- Comprehensive QOS rule examples set by default
- GPT support for HDD by Yaniv Hamo
diff --git a/release/src/router/www/bwm-common.js b/release/src/router/www/bwm-common.js index a4595e7420..a9ba0cb4f9 100644 --- a/release/src/router/www/bwm-common.js +++ b/release/src/router/www/bwm-common.js @@ -233,6 +233,14 @@ REMOVE-END */ t = 'WL (' + i + ')'; } + if (i == 'imq1') { + t = 'Lim. OUT (' + i + ')'; + } + + if (i == 'imq2') { + t = 'Lim. IN (' + i + ')'; + } + else if ((nvram.wan_proto == 'pptp') || (nvram.wan_proto == 'pppoe') || (nvram.wan_proto == 'l2tp') || (nvram.wan_proto == 'ppp3g')) { if (nvram.wan_iface == i) t = 'WAN (' + i + ')'; else if (nvram.wan_ifname == i && ((nvram.wan_proto != 'pppoe') && (nvram.wan_proto != 'ppp3g'))) t = 'MAN (' + i + ')'; diff --git a/release/src/router/www/qos-qoslimit.asp b/release/src/router/www/qos-qoslimit.asp new file mode 100644 index 0000000000..cea186fd00 --- /dev/null +++ b/release/src/router/www/qos-qoslimit.asp @@ -0,0 +1,277 @@ + + + + + + +[<% ident(); %>] QoS - Bandwidth Limiter + + + + + + + + + + + + +
+ + + + + +
+
<% ident(); %>
+ + + + + + + + + + +
+ +
Bandwidth Limiter - QOS
+
+ +
+
+
+ + + +
+
+ + + diff --git a/release/src/router/www/status-devices.asp b/release/src/router/www/status-devices.asp index a0cce85c87..a7b84c8e40 100644 --- a/release/src/router/www/status-devices.asp +++ b/release/src/router/www/status-devices.asp @@ -151,6 +151,13 @@ function addWF(n) location.href = 'basic-wfilter.asp'; } +function addqoslimit(n) +{ + var e = list[n]; + cookie.set('addqoslimit', [e.ip, e.name.split(',')[0]].join(','), 1); + location.href = 'qos-qoslimit.asp'; +} + var ref = new TomatoRefresh('update.cgi', 'exec=devlist', 0, 'status_devices_refresh'); ref.refresh = function(text) @@ -284,7 +291,8 @@ dg.populate = function() if (e.mac.match(/^(..):(..):(..)/)) { b += '
' + '[oui] ' + - '[static]'; + '[static]' + + '[qoslimit]'; if (e.rssi != '') { b += ' [wfilter]'; @@ -377,4 +385,3 @@ createFieldTable('', f); - diff --git a/release/src/router/www/tomato.js b/release/src/router/www/tomato.js index 9ea4b63d87..5a6836ef41 100644 --- a/release/src/router/www/tomato.js +++ b/release/src/router/www/tomato.js @@ -2402,7 +2402,8 @@ REMOVE-END */ ['Classification', 'classify.asp'], ['View Graphs', 'graphs.asp'], ['View Details', 'detailed.asp'], - ['Transfer Rates', 'ctrate.asp'] ] ], + ['Transfer Rates', 'ctrate.asp'], + ['B/W Limiter', 'qoslimit.asp'] ] ], ['Access Restriction', 'restrict.asp'], /* NOCAT-BEGIN */ -- 2.11.4.GIT