int add_iQosRules(char *pcWANIF) { FILE *fn; #ifdef RTCONFIG_IPV6 FILE *fn_ipv6; #endif char *buf; char *g; char *p; char *desc, *addr, *port, *prio, *transferred, *proto; int class_num; int down_class_num=6; // for download class_num = 0x6 / 0x106 int proto_num; int i, inuse; char q_inuse[32]; // for inuse char dport[192], saddr[192], conn[256], end[256]; int method; int gum; int sticky_enable; const char *chain; int v4v6_ok; if (pcWANIF == NULL || !nvram_match("qos_enable", "1")) return -1; if ((fn = fopen(mangle_fn, "w")) == NULL) return -2; #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && (fn_ipv6 = fopen(mangle_fn_ipv6, "w")) == NULL) return -3; #endif inuse = sticky_enable = 0; if (nvram_match("qos_sticky", "0")) sticky_enable = 1; del_iQosRules(); // flush all rules in mangle table fprintf(stderr, "[qos] iptables START\n"); fprintf(fn, "*mangle\n" ":PREROUTING ACCEPT [0:0]\n" ":OUTPUT ACCEPT [0:0]\n" ":QOSO - [0:0]\n" "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n" "-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n" ); #ifdef RTCONFIG_IPV6 if (ipv6_enabled()) fprintf(fn_ipv6, "*mangle\n" ":PREROUTING ACCEPT [0:0]\n" ":OUTPUT ACCEPT [0:0]\n" ":QOSO - [0:0]\n" "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n" "-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n" ); #endif g = buf = strdup(nvram_safe_get("qos_rulelist")); while (g) { /* ASUSWRT qos_rulelist : desc>addr>port>proto>transferred>prio addr : source ip or mac port : dest port proto : tcp, udp, tcp/udp, any , (icmp, igmp) transferred : min:max prio : 0-4, 0 is the highest */ if ((p = strsep(&g, "<")) == NULL) break; if((vstrsep(p, ">", &desc, &addr, &port, &proto, &transferred, &prio)) != 6) continue; class_num = atoi(prio); if ((class_num < 0) || (class_num > 4)) continue; i = 1 << class_num; ++class_num; //if (method == 1) class_num |= 0x200; if ((inuse & i) == 0) { inuse |= i; fprintf(stderr, "[qos] iptable creates, inuse=%d\n", inuse); } v4v6_ok = IPT_V4; #ifdef RTCONFIG_IPV6 if (ipv6_enabled()) v4v6_ok |= IPT_V6; #endif /* Beginning of the Rule */ /* if transferred != NULL, class_num must bt 0x1~0x6, not 0x101~0x106 0x1~0x6 : keep tracing this connection. 0x101~0x106 : connection will be considered as marked connection, won't detect again. */ #if 0 if(strcmp(transferred, "") != 0 ) method = 1; else method = atoi(nvram_safe_get("qos_method")); // strict rule ordering gum = (method == 0) ? 0x100 : 0; #else method = 1; gum = 0; #endif class_num |= gum; down_class_num |= gum; // for download chain = "QOSO"; // chain name sprintf(end , " -j CONNMARK --set-return 0x%x/0xFF\n", class_num); // CONNMARK string /*************************************************/ /* addr */ /* src mac or src ip */ /*************************************************/ char tmp[20]; char *tmp_addr, *q_ip, *q_mac; sprintf(tmp, "%s", addr); tmp_addr = tmp; q_ip = strsep(&tmp_addr, ":"); q_mac = tmp_addr; if(strcmp(addr, "") == 0 ) sprintf(saddr, "%s", addr); // src addr else{ if (q_mac == NULL){ sprintf(saddr, "-s %s", addr); // src addr v4v6_ok &= ipt_addr_compact(addr, v4v6_ok, (v4v6_ok==IPT_V4)); if (!v4v6_ok) continue; } else{ sprintf(saddr, "-m mac --mac-source %s", addr); // src mac } } //fprintf(stderr, "[qos] tmp=%s, ip=%s, mac=%s, addr=%s\n", tmp, q_ip, q_mac, addr ); // tmp test /*************************************************/ /* port */ /* single port or multi-ports */ /*************************************************/ char *tmp_port, *q_port, *q_leave; sprintf(tmp, "%s", port); tmp_port = tmp; q_port = strsep(&tmp_port, ","); q_leave = tmp_port; if(strcmp(port, "") == 0 ){ sprintf(dport, ""); } else{ if(q_leave != NULL) sprintf(dport, "-m multiport --dport %s", port); // multi port else sprintf(dport, "--dport %s", port); // single port } //fprintf(stderr, "[qos] tmp=%s, q_port=%s, q_leave=%s, port=%s\n", tmp, q_port, q_leave, port ); // tmp test /*************************************************/ /* transferred */ /* --connbytes min:max */ /* --connbytes-dir (original/reply/both) */ /* --connbytes-mode (packets/bytes/avgpkt) */ /*************************************************/ char *tmp_trans, *q_min, *q_max; long min, max ; sprintf(tmp, "%s", transferred); tmp_trans = tmp; q_min = strsep(&tmp_trans, "~"); q_max = tmp_trans; if (strcmp(transferred,"") == 0){ sprintf(conn, ""); } else{ sprintf(tmp, "%s", q_min); min = atol(tmp); if(strcmp(q_max,"") == 0) // q_max == NULL sprintf(conn, "-m connbytes --connbytes %ld:%s --connbytes-dir both --connbytes-mode bytes", min*1024, q_max); else{// q_max != NULL sprintf(tmp, "%s", q_max); max = atol(tmp); sprintf(conn, "-m connbytes --connbytes %ld:%ld --connbytes-dir both --connbytes-mode bytes", min*1024, max*1024-1); } } //fprintf(stderr, "[qos] tmp=%s, transferred=%s, min=%ld, max=%ld, q_max=%s, conn=%s\n", tmp, transferred, min*1024, max*1024-1, q_max, conn ); // tmp test /*************************************************/ /* proto */ /* tcp, udp, tcp/udp, any, (icmp, igmp) */ /*************************************************/ if(strcmp(proto, "tcp") == 0 ) { if (v4v6_ok & IPT_V4) fprintf(fn, "-A %s -p %s %s %s %s %s", chain, "tcp", dport, saddr, conn, end); #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && (v4v6_ok & IPT_V6)) fprintf(fn_ipv6, "-A %s -p %s %s %s %s %s", chain, "tcp", dport, saddr, conn, end); #endif } else if(strcmp(proto, "udp") == 0 ) { if (v4v6_ok & IPT_V4) fprintf(fn, "-A %s -p %s %s %s %s %s", chain, "udp", dport, saddr, conn, end); #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && (v4v6_ok & IPT_V6)) fprintf(fn_ipv6, "-A %s -p %s %s %s %s %s", chain, "udp", dport, saddr, conn, end); #endif } //else if(strcmp(proto, "icmp") == 0 || strcmp(proto, "igmp") == 0 ) else if(strcmp(proto, "any") == 0) { if (v4v6_ok & IPT_V4) fprintf(fn, "-A %s %s %s %s", chain, saddr, conn, end); #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && (v4v6_ok & IPT_V6)) fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr, conn, end); #endif } else if(strcmp(proto, "tcp/udp") == 0 ){ if (v4v6_ok & IPT_V4) { fprintf(fn, "-A %s -p %s %s %s %s %s", chain, "tcp", dport, saddr, conn, end); fprintf(fn, "-A %s -p %s %s %s %s %s", chain, "udp", dport, saddr, conn, end); } #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && (v4v6_ok & IPT_V6)) { fprintf(fn_ipv6, "-A %s -p %s %s %s %s %s", chain, "tcp", dport, saddr, conn, end); fprintf(fn_ipv6, "-A %s -p %s %s %s %s %s", chain, "udp", dport, saddr, conn, end); } #endif } else fprintf(stderr, "[qos] proto doesn't exist!!\n"); //fprintf(stderr,"[qos] -A %s -p %s %s %s %s %s", chain, "tcp", port, saddr, conn, end); //tmp test } free(buf); /* lan_addr for iptables use (LAN download) */ char *a, *b, *c, *d; char lan_addr[20]; g = buf = strdup(nvram_safe_get("lan_ipaddr")); if((vstrsep(g, ".", &a, &b, &c, &d)) != 4){ fprintf(stderr,"[qos] lan_ipaddr doesn't exist!!\n"); } else{ //fprintf(stderr,"[qos] lan_ipaddr exist!!\n"); sprintf(lan_addr, "%s.%s.%s.0/24", a, b, c); fprintf(stderr,"[qos] lan_addr=%s\n", lan_addr); } free(buf); //fprintf(stderr, "[qos] down_class_num=%x\n", down_class_num); /* The default class */ i = nvram_get_int("qos_default"); if ((i < 0) || (i > 4)) i = 3; // "lowest" class_num = i + 1; #ifndef RTCONFIG_RALINK // TODO: it is only for the case, eth0 as wan, vlanx as lan fprintf(fn, "-A QOSO -d %s -j CONNMARK --set-return 0x%x/0xFF\n" // for download (LAN or wireless) "-A POSTROUTING -o br0 -j QOSO\n" // for download, interface br0 "-A QOSO -j CONNMARK --set-return 0x%x\n" "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n", lan_addr, down_class_num, class_num, pcWANIF, pcWANIF); #else fprintf(fn, "-A QOSO -j CONNMARK --set-return 0x%x\n" "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n", class_num, pcWANIF, pcWANIF); #endif #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && *wan6face) { fprintf(fn_ipv6, "-A QOSO -d %s -j CONNMARK --set-return 0x%x/0xFF\n" // for download (LAN or wireless) "-A POSTROUTING -o br0 -j QOSO\n" // for download, interface br0 "-A QOSO -j CONNMARK --set-return 0x%x\n" "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n", lan_addr, down_class_num, class_num, wan6face, wan6face); } #endif inuse |= (1 << i) | 1; // default and highest are always built sprintf(q_inuse, "%d", inuse); nvram_set("qos_inuse", q_inuse); fprintf(stderr, "[qos] qos_inuse=%d\n", inuse); /* Ingress rules */ g = buf = strdup(nvram_safe_get("qos_irates")); for (i = 0; i < 10; ++i) { if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue; if ((inuse & (1 << i)) == 0) continue; if (atoi(p) > 0) { fprintf(fn, "-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", pcWANIF); #ifdef RTCONFIG_IPV6 if (ipv6_enabled() && *wan6face) fprintf(fn_ipv6, "-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face); #endif break; } } free(buf); fprintf(fn, "COMMIT\n"); fclose(fn); chmod(mangle_fn, 0700); eval("iptables-restore", "/tmp/mangle_rules"); #ifdef RTCONFIG_IPV6 if (ipv6_enabled()) { fprintf(fn_ipv6, "COMMIT\n"); fclose(fn_ipv6); chmod(mangle_fn_ipv6, 0700); eval("ip6tables-restore", "/tmp/mangle_rules_ipv6"); } #endif fprintf(stderr, "[qos] iptables DONE!\n"); }
// in mangle table void ipt_qos(void) { char *buf; char *g; char *p; char *addr_type, *addr; char *proto; char *port_type, *port; char *class_prio; char *ipp2p, *layer7; char *bcount; char *dscp; char *desc; int class_num; int proto_num; int v4v6_ok; int i; char sport[192]; char saddr[256]; char end[256]; char s[32]; char app[128]; int inuse; const char *chain; unsigned long min; unsigned long max; unsigned long prev_max; int gum; const char *qface; int sizegroup; int class_flag; int rule_num; if (!nvram_get_int("qos_enable")) return; inuse = 0; gum = 0x100; sizegroup = 0; prev_max = 0; rule_num = 0; ip46t_write( ":QOSO - [0:0]\n" "-A QOSO -j CONNMARK --restore-mark --mask 0xff\n" "-A QOSO -m connmark ! --mark 0/0x0f00 -j RETURN\n"); g = buf = strdup(nvram_safe_get("qos_orules")); while (g) { /* addr_type<addr<proto<port_type<port<ipp2p<L7<bcount<dscp<class_prio<desc addr_type: 0 = any 1 = dest ip 2 = src ip 3 = src mac addr: ip/mac if addr_type == 1-3 proto: 0-65535 = protocol -1 = tcp or udp -2 = any protocol port_type: if proto == -1,tcp,udp: d = dest s = src x = both a = any port: port # if proto == -1,tcp,udp bcount: min:max blank = none dscp: empty - any numeric (0:63) - dscp value afXX, csX, be, ef - dscp class class_prio: 0-10 // was 0-8 - Changed from 8 in pkt_sched.h - Toastman -1 = disabled */ if ((p = strsep(&g, ">")) == NULL) break; i = vstrsep(p, "<", &addr_type, &addr, &proto, &port_type, &port, &ipp2p, &layer7, &bcount, &dscp, &class_prio, &desc); rule_num++; if (i == 10) { // fixup < v1.28.XX55 desc = class_prio; class_prio = dscp; dscp = ""; } else if (i == 9) { // fixup < v0.08 // !!! temp desc = class_prio; class_prio = bcount; bcount = ""; dscp = ""; } else if (i != 11) continue; class_num = atoi(class_prio); if ((class_num < 0) || (class_num > 9)) continue; i = 1 << class_num; ++class_num; if ((inuse & i) == 0) { inuse |= i; } v4v6_ok = IPT_V4; #ifdef TCONFIG_IPV6 if (ipv6_enabled()) v4v6_ok |= IPT_V6; #endif class_flag = gum; saddr[0] = '\0'; end[0] = '\0'; // mac or ip address if ((*addr_type == '1') || (*addr_type == '2')) { // match ip v4v6_ok &= ipt_addr(saddr, sizeof(saddr), addr, (*addr_type == '1') ? "dst" : "src", v4v6_ok, (v4v6_ok==IPT_V4), "QoS", desc); if (!v4v6_ok) continue; } else if (*addr_type == '3') { // match mac sprintf(saddr, "-m mac --mac-source %s", addr); // (-m mac modified, returns !match in OUTPUT) } // IPP2P/Layer7 if (ipt_ipp2p(ipp2p, app)) v4v6_ok &= ~IPT_V6; else ipt_layer7(layer7, app); if (app[0]) { v4v6_ok &= ~IPT_V6; // temp: l7 not working either! class_flag = 0x100; // IPP2P and L7 rules may need more than one packet before matching // so port-based rules that come after them in the list can't be sticky // or else these rules might never match. gum = 0; strcat(saddr, app); } // dscp if (ipt_dscp(dscp, s)) { #ifndef LINUX26 v4v6_ok &= ~IPT_V6; // dscp ipv6 match is not present in K2.4 #endif strcat(saddr, s); } // -m connbytes --connbytes x:y --connbytes-dir both --connbytes-mode bytes if (*bcount) { min = strtoul(bcount, &p, 10); if (*p != 0) { strcat(saddr, " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes "); ++p; if (*p == 0) { sprintf(saddr + strlen(saddr), "%lu:", min * 1024); } else { max = strtoul(p, NULL, 10); sprintf(saddr + strlen(saddr), "%lu:%lu", min * 1024, (max * 1024) - 1); if (gum) { if (!sizegroup) { // Create table of connbytes sizes, pass appropriate connections there // and only continue processing them if mark was wiped ip46t_write( ":QOSSIZE - [0:0]\n" "-I QOSO 3 -m connmark ! --mark 0/0xff000 -j QOSSIZE\n" "-I QOSO 4 -m connmark ! --mark 0/0xff000 -j RETURN\n"); } if (max != prev_max && sizegroup<255) { class_flag = ++sizegroup << 12; prev_max = max; ip46t_flagged_write(v4v6_ok, "-A QOSSIZE -m connmark --mark 0x%x/0xff000" " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j CONNMARK --set-return 0x00000/0xFF\n", (sizegroup << 12), (max * 1024)); #ifdef BCMARM ip46t_flagged_write(v4v6_ok, "-A QOSSIZE -m connmark --mark 0x%x/0xff000" " -m connbytes --connbytes-mode bytes --connbytes-dir both --connbytes %lu: -j RETURN\n", (sizegroup << 12), (max * 1024)); #endif } else { class_flag = sizegroup << 12; } } } } else { bcount = ""; } } chain = "QOSO"; class_num |= class_flag; class_num |= rule_num << 20; sprintf(end + strlen(end), " -j CONNMARK --set-return 0x%x/0xFF\n", class_num); // protocol & ports proto_num = atoi(proto); if (proto_num > -2) { if ((proto_num == 6) || (proto_num == 17) || (proto_num == -1)) { if (*port_type != 'a') { if ((*port_type == 'x') || (strchr(port, ','))) { // dst-or-src port matches, and anything with multiple lists "," use multiport sprintf(sport, "-m multiport --%sports %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port); } else { // single or simple x:y range, use built-in tcp/udp match sprintf(sport, "--%sport %s", (*port_type == 's') ? "s" : ((*port_type == 'd') ? "d" : ""), port); } } else { sport[0] = 0; } if (proto_num != 6) { ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "udp", sport, saddr, end); #ifdef BCMARM ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s -j RETURN\n", chain, "udp", sport, saddr); #endif } if (proto_num != 17) { ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s %s", chain, "tcp", sport, saddr, end); #ifdef BCMARM ip46t_flagged_write(v4v6_ok, "-A %s -p %s %s %s -j RETURN\n", chain, "tcp", sport, saddr); #endif } } else { ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s %s", chain, proto_num, saddr, end); #ifdef BCMARM ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s -j RETURN\n", chain, proto_num, saddr); #endif } } else { // any protocol ip46t_flagged_write(v4v6_ok, "-A %s %s %s", chain, saddr, end); #ifdef BCMARM ip46t_flagged_write(v4v6_ok, "-A %s %s -j RETURN\n", chain, saddr); #endif } } free(buf); qface = wanfaces.iface[0].name; i = nvram_get_int("qos_default"); if ((i < 0) || (i > 9)) i = 3; // "low" class_num = i + 1; class_num |= 0xFF00000; // use rule_num=255 for default ip46t_write("-A QOSO -j CONNMARK --set-return 0x%x\n", class_num); #ifdef BCMARM ip46t_write("-A QOSO -j RETURN\n"); #endif ipt_write( "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n" "-A FORWARD -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n" "-A OUTPUT -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n", qface, qface, qface, qface); #ifdef TCONFIG_IPV6 if (*wan6face) { ip6t_write( "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n" "-A FORWARD -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n" "-A OUTPUT -o %s -m connmark ! --mark 0 -j CONNMARK --save-mark\n", wan6face, wan6face, wan6face, wan6face); } #endif inuse |= (1 << i) | 1; // default and highest are always built sprintf(s, "%d", inuse); nvram_set("qos_inuse", s); g = buf = strdup(nvram_safe_get("qos_irates")); for (i = 0; i < 10; ++i) { if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue; if ((inuse & (1 << i)) == 0) continue; unsigned int rate; unsigned int ceil; // check if we've got a percentage definition in the form of "rate-ceiling" // and that rate > 1 if ((sscanf(p, "%u-%u", &rate, &ceil) == 2) && (rate >= 1)) { ipt_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", qface); #ifdef BCMARM ipt_write("-A PREROUTING -i %s -j RETURN\n", qface); #endif #ifdef TCONFIG_IPV6 if (*wan6face) { ip6t_write("-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0xff\n", wan6face); #ifdef BCMARM ip6t_write("-A PREROUTING -i %s -j RETURN\n", wan6face); #endif } #endif break; } } free(buf); }
static int add_qos_rules(char *pcWANIF) { FILE *fn; #ifdef RTCONFIG_IPV6 FILE *fn_ipv6 = NULL; #endif char *buf; char *g; char *p; char *desc, *addr, *port, *prio, *transferred, *proto; int class_num; int down_class_num=6; // for download class_num = 0x6 / 0x106 int i, inuse; char q_inuse[32]; // for inuse char dport[192], saddr_1[192], saddr_2[192], proto_1[8], proto_2[8],conn[256], end[256], end2[256]; int method; int gum; int sticky_enable; const char *chain; int v4v6_ok; if((fn = fopen(mangle_fn, "w")) == NULL) return -2; inuse = sticky_enable = 0; if(get_model()==MODEL_RTAC56U || get_model()==MODEL_RTAC56S || get_model()==MODEL_RTAC68U || get_model()==MODEL_DSLAC68U || get_model()==MODEL_RTAC87U || get_model()==MODEL_RTAC3200 || get_model()==MODEL_RTAC88U || get_model()==MODEL_RTAC3100 || get_model()==MODEL_RTAC5300) manual_return = 1; if(nvram_match("qos_sticky", "0")) sticky_enable = 1; del_iQosRules(); // flush all rules in mangle table #ifdef CLS_ACT eval("ip", "link", "set", "imq0", "up"); #endif fprintf(stderr, "[qos] iptables START\n"); fprintf(fn, "*mangle\n" ":PREROUTING ACCEPT [0:0]\n" ":OUTPUT ACCEPT [0:0]\n" ":QOSO - [0:0]\n" "-A QOSO -j CONNMARK --restore-mark --mask 0x7\n" "-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n" ); #ifdef RTCONFIG_IPV6 if (fn_ipv6 && ipv6_enabled()) fprintf(fn_ipv6, "*mangle\n" ":PREROUTING ACCEPT [0:0]\n" ":OUTPUT ACCEPT [0:0]\n" ":QOSO - [0:0]\n" "-A QOSO -j CONNMARK --restore-mark --mask 0x7\n" "-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n" ); #endif g = buf = strdup(nvram_safe_get("qos_rulelist")); while (g) { /* ASUSWRT qos_rulelist : desc>addr>port>proto>transferred>prio addr : (source) IP or MAC or IP-range port : dest port proto : tcp, udp, tcp/udp, any , (icmp, igmp) transferred : min:max prio : 0-4, 0 is the highest */ if ((p = strsep(&g, "<")) == NULL) break; if((vstrsep(p, ">", &desc, &addr, &port, &proto, &transferred, &prio)) != 6) continue; class_num = atoi(prio); if ((class_num < 0) || (class_num > 4)) continue; i = 1 << class_num; ++class_num; //if (method == 1) class_num |= 0x200; if ((inuse & i) == 0) { inuse |= i; fprintf(stderr, "[qos] iptable creates, inuse=%d\n", inuse); } v4v6_ok = IPT_V4; #ifdef RTCONFIG_IPV6 if (fn_ipv6 && ipv6_enabled()) v4v6_ok |= IPT_V6; #endif /* Beginning of the Rule */ /* if transferred != NULL, class_num must bt 0x1~0x6, not 0x101~0x106 0x1~0x6 : keep tracing this connection. 0x101~0x106 : connection will be considered as marked connection, won't detect again. */ #if 0 if(strcmp(transferred, "") != 0 ) method = 1; else method = nvram_get_int("qos_method"); // strict rule ordering gum = (method == 0) ? 0x100 : 0; #else method = 1; gum = 0; #endif class_num |= gum; down_class_num |= gum; // for download chain = "QOSO"; // chain name sprintf(end , " -j CONNMARK --set-return 0x%x/0x7\n", class_num); // CONNMARK string sprintf(end2, " -j RETURN\n"); /*************************************************/ /* addr */ /* src mac or src ip or IP range */ /*************************************************/ char tmp[20], addr_t[40]; char *tmp_addr, *q_ip, *q_mac; memset(saddr_1, 0, sizeof(saddr_1)); memset(saddr_2, 0, sizeof(saddr_2)); memset(tmp, 0, sizeof(tmp)); sprintf(tmp, "%s", addr); tmp_addr = tmp; q_ip = strsep(&tmp_addr, ":"); q_mac = tmp_addr; memset(addr_t, 0, sizeof(addr_t)); sprintf(addr_t, "%s", addr); // step1: check contain '-' or not, if yes, IP-range, ex. 192.168.1.10-192.168.1.100 // step2: check addr is NULL // step3: check IP or MAC // step4: check IP contain '*' or not, if yes, IP-range // step5: check DUT's LAN IP shouldn't inside IP-range // step1: check contain '-' or not, if yes, IP-range if(strchr(addr_t, '-') == NULL){ // step2: check addr is NULL if(!strcmp(addr_t, "")){ sprintf(saddr_1, "%s", addr_t); // NULL } else{ // step2 // step3: check IP or MAC if (q_mac == NULL){ // step4: check IP contain '*' or not, if yes, IP-range if(strchr(q_ip, '*') != NULL){ char *rule; char Mask[40]; struct in_addr range_A, range_B, range_C; memset(Mask, 0, sizeof(Mask)); rule = strdup(addr_t); FindMask(rule, "*", "0", Mask); // find submask and replace "*" to "0" memset(addr_t, 0, sizeof(addr_t)); sprintf(addr_t, "%s", rule); // copy rule to addr_t for v4v6_ok unsigned int ip = inet_addr(rule); // covert rule's IP into binary form unsigned int nm = inet_addr(Mask); // covert submask into binary form unsigned int gw = inet_addr(nvram_safe_get("lan_ipaddr")); // covert DUT's LAN IP into binary form unsigned int gw_t = htonl(gw); range_A.s_addr = ntohl(gw_t - 1); range_B.s_addr = ntohl(gw_t + 1); range_C.s_addr = ip | ~nm; //fprintf(stderr, "[addr] addr_t=%s, rule/Mask=%s/%s, ip/nm/gw=%x/%x/%x\n", addr_t, rule, Mask, ip, nm, gw); // tmp test // step5: check DUT's LAN IP shouldn't inside IP-range // DUT's LAN IP inside IP-range if( (ip & nm) == (gw & nm)){ //fprintf(stderr, "[addr] %x/%x/%x/%x/%s matched\n", ip_t, nm_t, gw_t, range_B.s_addr, inet_ntoa(range_B)); // tmp test char range_B_addr[40]; sprintf(range_B_addr, "%s", inet_ntoa(range_B)); sprintf(saddr_1, "-m iprange --src-range %s-%s", rule, inet_ntoa(range_A)); // IP-range sprintf(saddr_2, "-m iprange --src-range %s-%s", range_B_addr, inet_ntoa(range_C)); // IP-range } else{ sprintf(saddr_1, "-m iprange --src-range %s-%s", rule, inet_ntoa(range_C)); // IP-range } free(rule); } else{ // step4 sprintf(saddr_1, "-s %s", addr_t); // IP } v4v6_ok &= ipt_addr_compact(addr_t, v4v6_ok, (v4v6_ok==IPT_V4)); if (!v4v6_ok) continue; } else{ // step3 sprintf(saddr_1, "-m mac --mac-source %s", addr_t); // MAC } } } else{ // step1 sprintf(saddr_1, "-m iprange --src-range %s", addr_t); // IP-range } //fprintf(stderr, "[qos] tmp=%s, ip=%s, mac=%s, addr=%s, addr_t=%s, saddr_1=%s, saddr_2=%s\n", tmp, q_ip, q_mac, addr, addr_t, saddr_1, saddr_2); // tmp test /*************************************************/ /* port */ /* single port or multi-ports */ /*************************************************/ char *tmp_port, *q_port, *q_leave; sprintf(tmp, "%s", port); tmp_port = tmp; q_port = strsep(&tmp_port, ","); q_leave = tmp_port; if(strcmp(port, "") == 0 ){ sprintf(dport, "%s", ""); } else{ if(q_leave != NULL) sprintf(dport, "-m multiport --dport %s", port); // multi port else sprintf(dport, "--dport %s", port); // single port } //fprintf(stderr, "[qos] tmp=%s, q_port=%s, q_leave=%s, port=%s\n", tmp, q_port, q_leave, port ); // tmp test /*************************************************/ /* transferred */ /* --connbytes min:max */ /* --connbytes-dir (original/reply/both) */ /* --connbytes-mode (packets/bytes/avgpkt) */ /*************************************************/ char *tmp_trans, *q_min, *q_max; long min, max ; sprintf(tmp, "%s", transferred); tmp_trans = tmp; q_min = strsep(&tmp_trans, "~"); q_max = tmp_trans; if (strcmp(transferred,"") == 0){ sprintf(conn, "%s", ""); } else{ sprintf(tmp, "%s", q_min); min = atol(tmp); if(strcmp(q_max,"") == 0) // q_max == NULL sprintf(conn, "-m connbytes --connbytes %ld:%s --connbytes-dir both --connbytes-mode bytes", min*1024, q_max); else{// q_max != NULL sprintf(tmp, "%s", q_max); max = atol(tmp); sprintf(conn, "-m connbytes --connbytes %ld:%ld --connbytes-dir both --connbytes-mode bytes", min*1024, max*1024-1); } } //fprintf(stderr, "[qos] tmp=%s, transferred=%s, min=%ld, max=%ld, q_max=%s, conn=%s\n", tmp, transferred, min*1024, max*1024-1, q_max, conn); // tmp test /*************************************************/ /* proto */ /* tcp, udp, tcp/udp, any, (icmp, igmp) */ /*************************************************/ memset(proto_1, 0, sizeof(proto_1)); memset(proto_2, 0, sizeof(proto_2)); if(!strcmp(proto, "tcp")) { sprintf(proto_1, "-p tcp"); sprintf(proto_2, "NO"); } else if(!strcmp(proto, "udp")) { sprintf(proto_1, "-p udp"); sprintf(proto_2, "NO"); } else if(!strcmp(proto, "any")) { sprintf(proto_1, "%s", ""); sprintf(proto_2, "NO"); } else if(!strcmp(proto, "tcp/udp")) { sprintf(proto_1, "-p tcp"); sprintf(proto_2, "-p udp"); } else{ sprintf(proto_1, "NO"); sprintf(proto_2, "NO"); } //fprintf(stderr, "[qos] proto_1=%s, proto_2=%s, proto=%s\n", proto_1, proto_2, proto); // tmp test /*******************************************************************/ /* */ /* build final rule for check proto_1, proto_2, saddr_1, saddr_2 */ /* */ /*******************************************************************/ // step1. check proto != "NO" // step2. if proto = any, no proto / dport // step3. check saddr for ip-range; saddr_1 could be empty, dport only if (v4v6_ok & IPT_V4){ // step1. check proto != "NO" if(strcmp(proto_1, "NO")){ // step2. if proto = any, no proto / dport if(strcmp(proto_1, "")){ // step3. check saddr for ip-range;saddr_1 could be empty, dport only fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end2); } } else{ fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end2); } } } // step1. check proto != "NO" if(strcmp(proto_2, "NO")){ // step2. if proto = any, no proto / dport if(strcmp(proto_2, "")){ // step3. check saddr for ip-range;saddr_1 could be empty, dport only fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end2); } } else{ fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end); if(manual_return) fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end2); } } } } #ifdef RTCONFIG_IPV6 if (fn_ipv6 && ipv6_enabled() && (v4v6_ok & IPT_V6)){ // step1. check proto != "NO" if(strcmp(proto_1, "NO")){ // step2. if proto = any, no proto / dport if(strcmp(proto_1, "")){ // step3. check saddr for ip-range;saddr_1 could be empty, dport only fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end2); } } else{ fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end2); } } } // step1. check proto != "NO" if(strcmp(proto_2, "NO")){ // step2. if proto = any, no proto / dport if(strcmp(proto_2, "")){ // step3. check saddr for ip-range;saddr_1 could be empty, dport only fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end2); } } else{ fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end2); if(strcmp(saddr_2, "")){ fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end); if(manual_return) fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end2); } } } } #endif } free(buf); /* lan_addr for iptables use (LAN download) */ char *a, *b, *c, *d; char lan_addr[20]; g = buf = strdup(nvram_safe_get("lan_ipaddr")); if((vstrsep(g, ".", &a, &b, &c, &d)) != 4){ fprintf(stderr,"[qos] lan_ipaddr doesn't exist!!\n"); } else{ sprintf(lan_addr, "%s.%s.%s.0/24", a, b, c); fprintf(stderr,"[qos] lan_addr=%s\n", lan_addr); } free(buf); //fprintf(stderr, "[qos] down_class_num=%x\n", down_class_num); /* The default class */ i = nvram_get_int("qos_default"); if ((i < 0) || (i > 4)) i = 3; // "lowest" class_num = i + 1; #ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan if(strncmp(pcWANIF, "ppp", 3)==0){ // ppp related interface doesn't need physdev // do nothing } else{ /* for WLAN to LAN bridge packet */ // ebtables : identify bridge packet add_EbtablesRules(); // for multicast fprintf(fn, "-A QOSO -d 224.0.0.0/4 -j CONNMARK --set-return 0x%x/0x7\n", down_class_num); if(manual_return) fprintf(fn , "-A QOSO -d 224.0.0.0/4 -j RETURN\n"); // for download (LAN or wireless) fprintf(fn, "-A QOSO -d %s -j CONNMARK --set-return 0x%x/0x7\n", lan_addr, down_class_num); if(manual_return) fprintf(fn , "-A QOSO -d %s -j RETURN\n", lan_addr); /* Requires bridge netfilter, but slows down and breaks EMF/IGS IGMP IPTV Snooping // for WLAN to LAN bridge issue fprintf(fn, "-A POSTROUTING -d %s -m physdev --physdev-is-in -j CONNMARK --set-return 0x6/0x7\n", lan_addr); */ // for download, interface br0 fprintf(fn, "-A POSTROUTING -o br0 -j QOSO\n"); } #endif fprintf(fn, "-A QOSO -j CONNMARK --set-return 0x%x/0x7\n" "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n", class_num, pcWANIF, pcWANIF); if(manual_return) fprintf(fn , "-A QOSO -j RETURN\n"); #ifdef RTCONFIG_IPV6 if (fn_ipv6 && ipv6_enabled() && *wan6face) { #ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan if(strncmp(wan6face, "ppp", 3)==0){ // ppp related interface doesn't need physdev // do nothing } else{ /* for WLAN to LAN bridge packet */ // ebtables : identify bridge packet add_EbtablesRules(); // for multicast fprintf(fn_ipv6, "-A QOSO -d 224.0.0.0/4 -j CONNMARK --set-return 0x%x/0x7\n", down_class_num); if(manual_return) fprintf(fn_ipv6, "-A QOSO -d 224.0.0.0/4 -j RETURN\n"); // for download (LAN or wireless) fprintf(fn_ipv6, "-A QOSO -d %s -j CONNMARK --set-return 0x%x/0x7\n", lan_addr, down_class_num); if(manual_return) fprintf(fn_ipv6, "-A QOSO -d %s -j RETURN\n", lan_addr); /* Requires bridge netfilter, but slows down and breaks EMF/IGS IGMP IPTV Snooping // for WLAN to LAN bridge issue fprintf(fn_ipv6, "-A POSTROUTING -d %s -m physdev --physdev-is-in -j CONNMARK --set-return 0x6/0x7\n", lan_addr); */ // for download, interface br0 fprintf(fn_ipv6, "-A POSTROUTING -o br0 -j QOSO\n"); } #endif fprintf(fn_ipv6, "-A QOSO -j CONNMARK --set-return 0x%x/0x7\n" "-A FORWARD -o %s -j QOSO\n" "-A OUTPUT -o %s -j QOSO\n", class_num, wan6face, wan6face); if(manual_return) fprintf(fn_ipv6, "-A QOSO -j RETURN\n"); } #endif inuse |= (1 << i) | 1; // default and highest are always built sprintf(q_inuse, "%d", inuse); nvram_set("qos_inuse", q_inuse); fprintf(stderr, "[qos] qos_inuse=%d\n", inuse); /* Ingress rules */ g = buf = strdup(nvram_safe_get("qos_irates")); for (i = 0; i < 10; ++i) { if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue; if ((inuse & (1 << i)) == 0) continue; if (atoi(p) > 0) { fprintf(fn, "-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0x7\n", pcWANIF); #ifdef CLS_ACT fprintf(fn, "-A PREROUTING -i %s -j IMQ --todev 0\n", pcWANIF); #endif #ifdef RTCONFIG_IPV6 if (fn_ipv6 && ipv6_enabled() && *wan6face) { fprintf(fn_ipv6, "-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0x7\n", wan6face); #ifdef CLS_ACT fprintf(fn_ipv6, "-A PREROUTING -i %s -j IMQ --todev 0\n", wan6face); #endif } #endif break; } } free(buf); fprintf(fn, "COMMIT\n"); fclose(fn); chmod(mangle_fn, 0700); eval("iptables-restore", (char*)mangle_fn); #ifdef RTCONFIG_IPV6 if (fn_ipv6 && ipv6_enabled()) { fprintf(fn_ipv6, "COMMIT\n"); fclose(fn_ipv6); chmod(mangle_fn_ipv6, 0700); // eval("ip6tables-restore", (char*)mangle_fn_ipv6); } #endif fprintf(stderr, "[qos] iptables DONE!\n"); return 0; }
int ej_ipv6_pinhole_array(int eid, webs_t wp, int argc, char_t **argv) { FILE *fp; char *ipt_argv[] = {"ip6tables", "-nxL", "UPNP", NULL}; char line[256], tmp[256]; char target[16], proto[16]; char src[45]; char dst[45]; char *sport, *dport, *ptr, *val; int ret = 0; ret += websWrite(wp, "var pinholes = "); if (!(ipv6_enabled() && is_routing_enabled())) { ret += websWrite(wp, "[];\n"); return ret; } _eval(ipt_argv, ">/tmp/pinhole.log", 10, NULL); fp = fopen("/tmp/pinhole.log", "r"); if (fp == NULL) { ret += websWrite(wp, "[];\n"); return ret; } ret += websWrite(wp, "["); while (fgets(line, sizeof(line), fp) != NULL) { tmp[0] = '\0'; if (sscanf(line, "%15s%*[ \t]" // target "%15s%*[ \t]" // prot "%44[^/]/%*d%*[ \t]" // source "%44[^/]/%*d%*[ \t]" // destination "%255[^\n]", // options target, proto, src, dst, tmp) < 5) continue; if (strcmp(target, "ACCEPT")) continue; /* uppercase proto */ for (ptr = proto; *ptr; ptr++) *ptr = toupper(*ptr); /* parse source */ if (strcmp(src, "::") == 0) strcpy(src, "ALL"); /* parse destination */ if (strcmp(dst, "::") == 0) strcpy(dst, "ALL"); /* parse options */ sport = dport = ""; ptr = tmp; while ((val = strsep(&ptr, " ")) != NULL) { if (strncmp(val, "dpt:", 4) == 0) dport = val + 4; if (strncmp(val, "spt:", 4) == 0) sport = val + 4; else if (strncmp(val, "dpts:", 5) == 0) dport = val + 5; else if (strncmp(val, "spts:", 5) == 0) sport = val + 5; } ret += websWrite(wp, "[\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"],\n", src, sport, dst, dport, proto); } ret += websWrite(wp, "[]];\n"); fclose(fp); unlink("/tmp/pinhole.log"); return ret; }
ej_lan_ipv6_network_array(int eid, webs_t wp, int argc, char_t **argv) { FILE *fp; char buf[64+32+8192+1]; char *hostname, *macaddr, ipaddrs[8192+1]; char ipv6_dns_str[1024]; char *wan_type, *wan_dns, *p; int service, i, ret = 0; ret += websWrite(wp, "var ipv6cfgarray = ["); if (!(ipv6_enabled() && is_routing_enabled())) { ret += websWrite(wp, "[]];\n"); ret += websWrite(wp, "var ipv6clientarray = ["); ret += websWrite(wp, "[]];\n"); return ret; } service = get_ipv6_service(); switch (service) { case IPV6_NATIVE_DHCP: wan_type = "Native with DHCP-PD"; break; case IPV6_6TO4: wan_type = "Tunnel 6to4"; break; case IPV6_6IN4: wan_type = "Tunnel 6in4"; break; case IPV6_6RD: wan_type = "Tunnel 6rd"; break; case IPV6_MANUAL: wan_type = "Static"; break; default: wan_type = "Disabled"; break; } ret += websWrite(wp, "[\"IPv6 Connection Type\",\"%s\"],", wan_type); ret += websWrite(wp, "[\"WAN IPv6 Address\",\"%s\"],", getifaddr((char *) get_wan6face(), AF_INET6, GIF_PREFIXLEN) ? : nvram_safe_get("ipv6_rtr_addr")); ret += websWrite(wp, "[\"WAN IPv6 Gateway\",\"%s\"],", ipv6_gateway_address() ? : ""); ret += websWrite(wp, "[\"LAN IPv6 Address\",\"%s/%d\"],", nvram_safe_get("ipv6_rtr_addr"), nvram_get_int("ipv6_prefix_length")); ret += websWrite(wp, "[\"LAN IPv6 Link-Local Address\",\"%s\"],", getifaddr(nvram_safe_get("lan_ifname"), AF_INET6, GIF_LINKLOCAL | GIF_PREFIXLEN) ? : ""); if (service == IPV6_NATIVE_DHCP) { ret += websWrite(wp, "[\"DHCP-PD\",\"%s\"],", nvram_get_int("ipv6_dhcp_pd") ? "Enabled" : "Disabled"); } ret += websWrite(wp, "[\"LAN IPv6 Prefix\",\"%s/%d\"],", nvram_safe_get("ipv6_prefix"), nvram_get_int("ipv6_prefix_length")); if (service == IPV6_NATIVE_DHCP && nvram_get_int("ipv6_dnsenable")) { wan_dns = nvram_safe_get("ipv6_get_dns"); } else { char nvname[sizeof("ipv6_dnsXXX")]; char *next = ipv6_dns_str; ipv6_dns_str[0] = '\0'; for (i = 1; i <= 3; i++) { snprintf(nvname, sizeof(nvname), "ipv6_dns%d", i); wan_dns = nvram_safe_get(nvname); if (*wan_dns) next += sprintf(next, *ipv6_dns_str ? " %s" : "%s", wan_dns); } wan_dns = ipv6_dns_str; } ret += websWrite(wp, "[\"DNS Address\",\"%s\"],", wan_dns); ret += websWrite(wp, "[]];\n"); ret += websWrite(wp, "var ipv6clientarray = ["); /* Refresh lease file to get actual expire time */ killall("dnsmasq", SIGUSR2); usleep(100 * 1000); get_ipv6_client_info(); get_ipv6_client_list(); if ((fp = fopen(IPV6_CLIENT_LIST, "r")) == NULL) { _dprintf("can't open %s: %s", IPV6_CLIENT_LIST, strerror(errno)); return ret; } while (fgets(buf, sizeof(buf), fp) != NULL) { char *ptr = buf; ptr = strsep(&ptr, "\n"); hostname = strsep(&ptr, " "); macaddr = strsep(&ptr, " "); if (!macaddr || *macaddr == '\0' || !ptr || *ptr == '\0') continue; if (strlen(hostname) > 32) sprintf(hostname + 29, "..."); ipaddrs[0] = '\0'; p = ipaddrs; while (ptr && *ptr) { char *next = strsep(&ptr, ",\n"); if (next && *next) p += snprintf(p, sizeof(ipaddrs) + ipaddrs - p, "%s%s", *ipaddrs ? ", " : "", next); } ret += websWrite(wp, "[\"%s\", \"%s\", \"%s\"],", hostname, macaddr, ipaddrs); } fclose(fp); ret += websWrite(wp, "[]];\n"); return ret; }
int rcheck_main(int argc, char *argv[]) { char buf[256]; char *p; int sched_begin; int sched_end; int sched_dow; time_t now; struct tm *tms; int now_dow; int now_mins; int n; int nrule; char comp; int insch; unsigned long long activated; int count; int radio; int r; #ifdef TCONFIG_IPV6 int r6; #endif #ifdef LINUX26 int ipt_active; #endif if (!nvram_contains_word("log_events", "acre")) { setlogmask(LOG_MASK(LOG_EMERG)); // can't set to 0 } simple_lock("restrictions"); now = time(0); if (now < Y2K) { if (!nvram_match("rrules_timewarn", "1")) { nvram_set("rrules_timewarn", "1"); syslog(LOG_INFO, "Time not yet set. Only \"all day, everyday\" restrictions will be activated."); } now_mins = now_dow = 0; } else { tms = localtime(&now); now_dow = 1 << tms->tm_wday; now_mins = (tms->tm_hour * 60) + tms->tm_min; } #ifdef LINUX26 ipt_active = 0; #endif activated = strtoull(nvram_safe_get("rrules_activated"), NULL, 16); count = 0; radio = foreach_wif(0, NULL, radio_on) ? -1 : -2; for (nrule = 0; nrule < MAX_NRULES; ++nrule) { sprintf(buf, "rrule%d", nrule); if ((p = nvram_get(buf)) == NULL) continue; if (sscanf(p, "%d|%d|%d|%d|%c", &n, &sched_begin, &sched_end, &sched_dow, &comp) != 5) continue; if (n == 0) continue; ++count; if (now < Y2K) { if ((sched_begin >= 0) || (sched_end >= 0) || (sched_dow != 0x7F)) continue; insch = 1; } else { insch = in_sched(now_mins, now_dow, sched_begin, sched_end, sched_dow); } #ifdef LINUX26 if ((insch) && (comp != '~')) ++ipt_active; #endif n = 1 << nrule; if ((insch) == ((activated & n) != 0)) { continue; } syslog(LOG_INFO, "%sctivating rule %d", insch ? "A" : "Dea", nrule); if (comp == '~') { if ((radio != 0) && (radio != -2)) radio = !insch; } else { sprintf(buf, "r%s%02d", (comp != '|') ? "dev" : "res", nrule); r = eval("iptables", "-D", "restrict", "-j", buf); if (insch) { // ignore error above (if any) r = eval("iptables", "-A", "restrict", "-j", buf); } #ifdef TCONFIG_IPV6 r6 = eval("ip6tables", "-D", "restrict", "-j", buf); if (ipv6_enabled()) { if (insch) { // ignore error above (if any) r6 = eval("ip6tables", "-A", "restrict", "-j", buf); } r |= r6; } #endif if (r != 0) { syslog(LOG_ERR, "Iptables: %sactivating chain \"%s\" failed. Retrying in 15 minutes.", insch ? "" : "de", buf); continue; } } if (insch) activated |= n; else activated &= ~n; } sprintf(buf, "%llx", activated); nvram_set("rrules_activated", buf); if (count > 0) { if ((argc != 2) || (strcmp(argv[1], "--cron") != 0)) { eval("cru", "a", "rcheck", "*/15 * * * * rcheck --cron"); } } else { unsched_restrictions(); } if (radio >= 0) { nvram_set("rrules_radio", radio ? "0" : "1"); #if 1 // changed for dual radio support _dprintf("%s: radio = %d\n", __FUNCTION__, radio); eval("radio", radio ? "on" : "off"); #else if (get_radio() != radio) { _dprintf("%s: radio = %d\n", __FUNCTION__, radio); eval("radio", radio ? "on" : "off"); } else { _dprintf("%s: no radio change = %d\n", __FUNCTION__, radio); } #endif } #ifdef LINUX26 allow_fastnat("restrictions", (ipt_active == 0)); try_enabling_fastnat(); #endif simple_unlock("restrictions"); return 0; }