Esempio n. 1
0
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");
}
Esempio n. 2
0
// 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);
}
Esempio n. 3
0
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;
}
Esempio n. 4
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;

}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}