--- a/src/dns_block.c	2018-12-04 10:25:50.158766982 +0800
+++ b/src/dns_block.c	2018-12-05 09:27:40.966246409 +0800
@@ -19,6 +19,45 @@
 #define LEASE_KEY_NUM		7
 #define LEASE_KEY_MAX_LEN	16

+#define PCTL_CMD_DEL_U		1
+#define PCTL_CMD_SET_U		2
+#define PCTL_GAME			0
+#define PCTL_VIDEO			1
+#define PCTL_SOCIAL			2
+#define PCTL_TYPE_NUM		3
+#define PCTL_KEY_NUM		32
+#define PCTL_HASH_NUM		64
+
+/*
+ * ctl bit means
+ *bit 0: game
+ *bit 1: video
+ *bit 2: social
+ *bit 3: function enable
+ */
+typedef struct pctl_dev {
+	struct pctl_dev *next;
+	char mac[6];
+	unsigned char ctl;
+}PDEV;
+
+typedef struct pctl_key {
+	u8 key_num[3];
+	char keywords[PCTL_TYPE_NUM][PCTL_KEY_NUM][16];
+}PKEY;
+
+PKEY si_pctl_key = {
+	.key_num = {4,16,5},
+	.keywords = {
+		{"steam","game*qq","blizzard","dota"},
+		{"xigua","douyin","youku","iqiyi","bilibili","tudou","acfun","douyu","huya","panda","miaopai","kuaishou","qqlive","v*qq","video*baidu","mgtv"},
+		{"wx.qq","weixin","weibo","momo","zhihu"}
+		}
+};
+
+PDEV pctl_devs[PCTL_HASH_NUM];
+pthread_mutex_t pctl_lock = PTHREAD_MUTEX_INITIALIZER;
+
 typedef struct dev {
 	char mac[6];
 	struct dev *next;
@@ -26,6 +65,7 @@

 char lease_key[LEASE_KEY_NUM][LEASE_KEY_MAX_LEN] = {"siflower","apple","alipay","alicdn","taobao","tenpay","wx.gtimg"};
 extern struct mac_node * gpmac_list_hdr;
+
 LDEV *head = NULL;
 pthread_mutex_t llist_lock = PTHREAD_MUTEX_INITIALIZER;

@@ -243,7 +283,6 @@
 	return lease_find_mac(mac);
 }

-/*return 2 drop dns request*/
 int lease_dns_block(char *namebuff, void *s, char is_ipv6){
 	char i;

@@ -319,6 +358,206 @@
 	return 0;
 }

+size_t hash_str(void* key, size_t key_length, size_t slots_num)
+{
+	const char* key_str = (const char *) key;
+	const char *end = key_str + key_length;
+	unsigned long h = 5381;
+
+	while(key_str < end) {
+		h += h << 5;
+		h ^= (unsigned long) *key_str++;
+	}
+
+	return (h % slots_num);
+}
+
+unsigned char pctl_find_mac(char *mac){
+	PDEV *dev;
+	int index = hash_str(mac, 6 ,PCTL_HASH_NUM);
+	unsigned char ctl;
+
+	pthread_mutex_lock(&pctl_lock);
+	for(dev = pctl_devs[index].next; dev != NULL; dev = dev->next){
+		if(memcmp(mac, dev->mac, 6) == 0){
+			SLOG("%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",mac[0], mac[1],mac[2], mac[3], mac[4], mac[5]);
+			ctl = dev->ctl;
+			pthread_mutex_unlock(&pctl_lock);
+			SLOG("Find devcie");
+			return ctl;
+		}
+	}
+	pthread_mutex_unlock(&pctl_lock);
+	return 0;
+}
+
+unsigned char pctl_filter_by_mac(void *sa, char is_ipv6){
+	unsigned char mac[6] = {0};
+	struct sockaddr_in * psin;
+#ifdef HAVE_IPV6
+	if (is_ipv6){
+		if(get_mac_ipv6(sa,mac) != 2){
+			// my_syslog(LOG_WARNING, _("cannot find mac for ipv6"));
+			return -1;
+		}
+		else{
+			// my_syslog(LOG_WARNING, _("mac is %02x:%02x:%02x:%02x:%02x:%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+		}
+	}
+	else{
+#endif
+		// memcpy(&sin, sa, sizeof(sin));
+		psin = sa;
+		if(psin->sin_addr.s_addr == inet_addr("127.0.0.1"))
+		  return 0;
+		// my_syslog(LOG_ERR, _("addr:%s, port:%d\n"), inet_ntoa(psin->sin_addr), ntohs(psin->sin_port));
+
+		if(get_mac_by_ip(mac, sa) < 0){
+			// my_syslog(LOG_WARNING, _("cannot find mac for ip"));
+			return -1;
+		}
+		else{
+			// my_syslog(LOG_WARNING, _("mac is %02x:%02x:%02x:%02x:%02x:%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+		}
+#ifdef HAVE_IPV6
+	}
+#endif
+
+	return pctl_find_mac(mac);
+}
+
+unsigned char sistrstr(char *string, char *substring){
+	char *c = substring;
+	char *b = substring;
+	char *a;
+
+	if(*b == 0){
+		return 0;
+	}
+
+	for(; *string != 0; string +=1){
+		if(*string != *b){
+			continue;
+		}
+
+		a = string;
+		while(1){
+			if(*b == 0){
+				return 1;
+			}
+
+			if(*a++ != *b++){
+				break;
+			}
+		}
+		if(*(b-1) == '*'){
+			c = b;
+			string = a-1;
+		}else{
+			b = c;
+		}
+	}
+
+	return 0;
+}
+
+/*return 1 drop dns request*/
+int pctl_dns_block(char *namebuff, void *s, char is_ipv6){
+	char ctl;
+	unsigned char i,j;
+	ctl = pctl_filter_by_mac(s, is_ipv6);
+	SLOG("check name is %s, ctl is %d",namebuff, ctl);
+	if( ctl > 0 ){
+		for(i=0; i < PCTL_TYPE_NUM; ++i){
+			if (ctl & (0x1 << i)){
+				for(j = 0; j < si_pctl_key.key_num[i];++j ){
+					SLOG("key is %s",si_pctl_key.keywords[i][j]);
+					if(sistrstr(namebuff, si_pctl_key.keywords[i][j]) != NULL){
+						return 1;
+					}
+				}
+			}
+		}
+	}
+	/*not found device*/
+	return 0;
+}
+
+int deal_pctl_cmd(char *buf){
+	int cmd = -1;
+	unsigned char have = 0;
+	int index = 0;
+	cmd = buf[0];
+	char *mac = buf+1;
+	PDEV *dev = NULL;
+	PDEV *pdev = NULL;
+
+	index = hash_str(mac, 6 ,PCTL_HASH_NUM);
+	switch(cmd){
+		case PCTL_CMD_SET_U:
+			for(dev = pctl_devs[index].next; dev != NULL; dev = dev->next){
+				if(memcmp(mac, dev->mac, 6) == 0){
+					have = 1;
+					if(buf[7] & 0x8){
+						dev->ctl = buf[7];
+					}else{
+						dev->ctl = 0;
+					}
+					SLOG("pctl:Add device is exist,ctl is %d",dev->ctl);
+					break;
+				}
+			}
+			if(have == 0){
+				dev = malloc(sizeof(PDEV));
+				if(dev == NULL){
+					SLOG("pctl:Add device malloc fail!");
+					return 0;
+				}
+				memcpy(dev->mac, mac, 6);
+				dev->ctl = buf[7];
+				pthread_mutex_lock(&pctl_lock);
+				dev->next = pctl_devs[index].next;
+				pctl_devs[index].next = dev;
+				pthread_mutex_unlock(&pctl_lock);
+				SLOG("pctl:Add device is success");
+			}
+			break;
+		case PCTL_CMD_DEL_U:
+			pdev = &pctl_devs[index];
+			for(dev = pctl_devs[index].next; dev != NULL; dev = dev->next){
+				if(memcmp(mac, dev->mac, 6) == 0){
+					have = 1;
+					break;
+				}
+				pdev = dev;
+			}
+			if(have == 1){
+				pthread_mutex_lock(&pctl_lock);
+				pdev->next = dev->next;
+				pthread_mutex_unlock(&pctl_lock);
+				free(dev);
+				SLOG("pctl:free device is success");
+			}else{
+				syslog(LOG_ERR,"pctl:Del device is not exist");
+			}
+			break;
+		default:
+			syslog(LOG_ERR,"pctl:Not found lease sub cmd");
+			break;
+	}
+	return 0;
+}
+
+void pctl_dns_block_start(void){
+	int i;
+
+	for(i=0;i<PCTL_HASH_NUM;++i){
+		pctl_devs[i].next = NULL;
+	}
+
+	return;
+}
+
 void *config_server_start(void *arg)
 {
 	socklen_t clt_addr_len;
@@ -378,6 +617,7 @@
				deal_lease_cmd(data_buf+1);
 				break;
 			case 1:
+				deal_pctl_cmd(data_buf+1);
 				break;
 			default:
 				syslog(LOG_ERR,"Not support cmd\n");
@@ -402,7 +642,7 @@
 	return ;
 }

-void *lease_dns_block_start(void){
+void lease_dns_block_start(void){
 	head = malloc(sizeof(LDEV));
 	if(head == NULL){
 		my_syslog(LOG_ERR,"Init lease list head fail\n");
@@ -412,3 +652,8 @@

 	return;
 }
+
+void *dns_block_start(void){
+	lease_dns_block_start();
+	pctl_dns_block_start();
+}
--- a/src/dns_block.h	2018-12-04 14:36:38.275398490 +0800
+++ b/src/dns_block.h	2018-12-05 09:27:42.822246487 +0800
@@ -8,11 +8,14 @@
 int get_mac_ipv6( struct in6_addr* pipv6_src, unsigned char * pmac);
 int get_mac_by_ip(unsigned char* mac,  struct sockaddr *sa);
 int lease_dns_block(char *namebuff, void *s, char is_ipv6);
-void *lease_dns_block_start(void);
+int pctl_dns_block(char *namebuff, void *s, char is_ipv6);
+
+void *dns_block_start(void);
 unsigned short char_to_short(char* src);
 void short_to_char(unsigned short src, char* dst);
 struct mac_node * find_mac_node(unsigned char* mac, struct mac_node * pmac_list_hdr);
 void *config_server_start(void *arg);
+
 struct url_node{
 	struct url_node* pnext;
 	unsigned short str_len;
--- a/src/dnsmasq.c	2018-12-05 09:21:09.602229985 +0800
+++ b/src/dnsmasq.c	2018-12-05 09:24:15.690237794 +0800
@@ -865,7 +865,7 @@
   poll_resolv(1, 0, now);
 #endif
   init_urllist();
-	lease_dns_block_start();
+	dns_block_start();
 	pthread_attr_t att;
 	pthread_attr_init(&att);
 	pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED);
--- a/src/forward.c	2018-12-05 09:44:53.754289751 +0800
+++ b/src/forward.c	2018-12-05 09:43:25.862286062 +0800
@@ -1389,6 +1389,18 @@
 		  my_syslog(LOG_ERR, _("Lease block this request %s"),daemon->namebuff);
 		  return;
 	  }
+
+	  char pctl_ret = 0;
+	  if(listen->family == AF_INET6){
+		  pctl_ret = pctl_dns_block(daemon->namebuff, &source_addr.in6.sin6_addr, 1);
+	  }else{
+		  pctl_ret = pctl_dns_block(daemon->namebuff, &source_addr.sa, 0);
+	  }
+	  if(pctl_ret == 1){
+		  my_syslog(LOG_ERR, _("pctl block this request %s"),daemon->namebuff);
+		  return;
+	  }
+
 #ifdef HAVE_AUTH
       /* find queries for zones we're authoritative for, and answer them directly */
       if (!auth_dns)
--- a/src/dns_block.c	2018-12-05 14:17:55.126977210 +0800
+++ b/src/dns_block.c	2018-12-05 14:19:13.994980520 +0800
@@ -167,14 +167,14 @@
 }
 #endif

-int get_mac_by_ip(unsigned char* mac,  struct sockaddr *sa){
+int get_mac_by_ip(unsigned char* mac,  struct sockaddr *sa, char *ifname){
 	int sock_fd = 0, ret = 0;
 	struct arpreq req;
 	memset(&req, 0, sizeof(struct arpreq));
 	// set ip
 	memcpy(&req.arp_pa, sa, sizeof(struct sockaddr));
 	// set interface
-	strncpy(req.arp_dev, "br-lease", sizeof(req.arp_dev));
+	strncpy(req.arp_dev, ifname, sizeof(req.arp_dev));
 	sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
 	if(sock_fd < 0)
 	{
@@ -215,7 +215,7 @@
 		  return 0;
 		// my_syslog(LOG_ERR, _("addr:%s, port:%d\n"), inet_ntoa(psin>sin_addr), ntohs(psin>sin_port));

-		if(get_mac_by_ip(mac, sa) < 0){
+		if(get_mac_by_ip(mac, sa, "br-lan") < 0){
 			// my_syslog(LOG_WARNING, _("cannot find mac for ip"));
 			return 1;
 		}
@@ -269,7 +269,7 @@
 		  return 0;
 		// my_syslog(LOG_ERR, _("addr:%s, port:%d\n"), inet_ntoa(psin->sin_addr), ntohs(psin->sin_port));

-		if(get_mac_by_ip(mac, sa) < 0){
+		if(get_mac_by_ip(mac, sa, "br-lease") < 0){
 			// my_syslog(LOG_WARNING, _("cannot find mac for ip"));
 			return -1;
 		}
@@ -412,7 +412,7 @@
 		  return 0;
 		// my_syslog(LOG_ERR, _("addr:%s, port:%d\n"), inet_ntoa(psin->sin_addr), ntohs(psin->sin_port));

-		if(get_mac_by_ip(mac, sa) < 0){
+		if(get_mac_by_ip(mac, sa, "br-lan") < 0){
 			// my_syslog(LOG_WARNING, _("cannot find mac for ip"));
 			return -1;
 		}
--- a/src/dns_block.h	2018-12-05 14:22:39.762989155 +0800
+++ b/src/dns_block.h	2018-12-05 14:23:03.470990150 +0800
@@ -6,7 +6,7 @@
 #define EVENT_UPDATE_LIST 25
 #endif
 int get_mac_ipv6( struct in6_addr* pipv6_src, unsigned char * pmac);
-int get_mac_by_ip(unsigned char* mac,  struct sockaddr *sa);
+int get_mac_by_ip(unsigned char* mac,  struct sockaddr *sa, char *ifname);
 int lease_dns_block(char *namebuff, void *s, char is_ipv6);
 int pctl_dns_block(char *namebuff, void *s, char is_ipv6);
