#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#author:Wos
#a script for windows advance firewall rules automatically generater and execute
#it can block ip,port,app,domain,
import os
import random
import string
import subprocess
import time


#ip_block.txt
#app_block.txt
#port_block.txt
#domian_block.txt


domain_list = []
ip_list = []
iplist = []

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
port_path = os.path.join(BASE_DIR, "port_block.txt")
app_path = os.path.join(BASE_DIR, "app_block.txt")
ip_path = os.path.join(BASE_DIR, "ip_block.txt")
domain_path = os.path.join(BASE_DIR, "domain_block.txt")


def random_rule_name():
    return ''.join(random.sample(string.ascii_letters,6))




def GetDesktopPath():
    return os.path.join(os.path.expanduser("~"), 'Desktop')

def port_block():
    print("generating port block rules...")
    with open(port_path,'r',encoding='utf-8') as f:
        for line in f.readlines():
            line = str(line).strip()
            if line and not str(line).startswith("#"):        
                if str(line).startswith("tcp"):
                    temp = str(line).split(":")[1].strip()
                    cmdline = "netsh advfirewall firewall add rule name=\"tcp_port_block\" dir=in action=block enable=yes localport="+temp+" protocol=tcp remoteip=any  profile=any >NUL"
                    fw.write(cmdline+"\n")
                    child = subprocess.Popen(cmdline,shell=False)
                    child.wait()
                  

                elif str(line).startswith("udp"):
                    temp = str(line).split(":")[1].strip()
                    cmdline = "netsh advfirewall firewall add rule name=\"udp_port_block\" dir=in action=block enable=yes localport="+temp+" protocol=udp remoteip=any  profile=any >NUL"
                    fw.write(cmdline+"\n")                   
                    child = subprocess.Popen(cmdline,shell=False)
                    child.wait()
                else:
                    continue
        f.close()
    time.sleep(1)
    print("port block rules complete!")
    return



def read_ip_block():
    global iplist
    iplist_ = ""   
    print("read ip block.txt ...")
    with open(ip_path,'r',encoding='utf-8') as f:
        for line in f.readlines():
            line = str(line).strip()
            if line and not str(line).startswith("#"):
                iplist.append(line)
        f.close()          
    iplist = list(set(iplist))

def ip_block(): 
    print("generating ip block rules...")
    iplist_ = ""
    if iplist:
    #every ip rules only 12 address or class limited
        i  = 0
        j = 0
        rule_name = "ip_"+random_rule_name()+"_"
        while i < len(iplist):
            if i % 13 != 0  and i != 0 :
                iplist_ = iplist_+','+iplist[i]
                i += 1
                continue
            else:
                if iplist_:
                    temp = str(iplist_).strip(',')
                    cmdline = "netsh advfirewall firewall add rule name=\""+rule_name+str(j)+"\" dir=in action=block enable=yes remoteip="+temp+" profile=any >NUL"
                    fw.write(cmdline+"\n")                 
                    child = subprocess.Popen(cmdline,shell=False)
                    child.wait()                 
                    iplist_ = ""
                    j += 1
                    i += 1
                    continue
                else:
                    j += 1
                    i += 1
                    continue
        print("ip block rules complete!")
        return
    else:
        print("there's no ip to block!")


def domain_block():
    global domain_list,ip_list,iplist
    domain_list2 = []
    i = 0
    while i < len(domain_list):
        # local ISP's dns query test
        cmdline = ("nslookup %s"%(domain_list[i]))
        result = os.popen(cmdline)
        info = result.read()
        try:
            temp = str(info).split("名称:")[1].split("\n")[0].strip()
            if not temp:
                temp = str(info).split("Name:")[1].split("\n")[0].strip()            
            domain_list2.append(temp)
        except:
            pass


        try:
            temp_ = str(info).split("Aliases:")[1].split("\n")
            for j in temp_:
                if str(j).strip() and "Non-existent" not in str(j):
                    domain_list2.append(str(j).strip())
                    print(str(j).strip())
        except:
            pass

        try:
            temp2 = str(info).split("Addresses:")[1].split("Aliases:")[0].split("\n")
            for j in temp2:
                if str(j).strip() and len(str(j).strip()) < 16:
                    ip_list.append(str(j).strip())
                    print(str(j).strip())
        except:
            pass

        i += 1


    result = list(set(domain_list2))
    if len(result) != len(domain_list):
        domain_list = result
        return domain_block()
    else:
        read_ip_block()#get ip_block.txt
        #combine domain_block's ip and ip_block's ip 
        f = open(ip_path,'w',encoding='utf-8').close()
        f = open(ip_path,'a',encoding='utf-8')        
        for i in ip_list:
            if str(i) not in iplist:
                iplist.append(i)
        for i in iplist:
            f.write(str(i)+"\n")
        f.close()              
        ip_block()    
        #overwrite domain_block.txt
        f = open(domain_path,'w',encoding='utf-8').close()
        f = open(domain_path,'a',encoding='utf-8')
        for i in domain_list:
            f.write(str(i)+"\n")
        f.close()
        return

def read_ms_domain_list():
    global domain_list
    if os.path.exists(domain_path):
        with open(domain_path,'r',encoding='utf-8') as f:
            for line in f.readlines():
                line = str(line).strip()
                if line and not str(line).startswith("#"):
                    domain_list.append(line)
            f.close()        
        if not domain_list:
            domain_list = ['windowsupdate.microsoft.com','dlc-shim.trafficmanager.net','redir.update.msft.com.trafficmanager.net',
                           'wustat.windows.com','opencdnmsdl2.jomodns.com','ntservicepack.microsoft.com',
                           'windowsupdate.redir.update.microsoft.com.nsatc.net','windowsupdate.com','download.windowsupdate.com',
                           'download.microsoft.com.ccgslb.com.cn','wu-fg-shim.trafficmanager.net','ntservicepack.microsoft.nsatc.net',
                           'download.windowsupdate.com.a.bdydns.com','download.microsoft.com.lxcvc.com','stats.microsoft.com',
                           'www.update.microsoft.com.nsatc.net','zlxxipv6.v.lxcvc.com','download.microsoft.com',
                           'update.microsoft.com.nsatc.net','redir.update.microsoft.com.nsatc.net','update.microsoft.com']            

        return
    else:
        f = open(domain_path,'w',encoding='utf-8')
        f.write("#black domain list,one per line\n")
        f.close()
        domain_list = ['windowsupdate.microsoft.com','dlc-shim.trafficmanager.net','redir.update.msft.com.trafficmanager.net',
                       'wustat.windows.com','opencdnmsdl2.jomodns.com','ntservicepack.microsoft.com',
                       'windowsupdate.redir.update.microsoft.com.nsatc.net','windowsupdate.com','download.windowsupdate.com',
                       'download.microsoft.com.ccgslb.com.cn','wu-fg-shim.trafficmanager.net','ntservicepack.microsoft.nsatc.net',
                       'download.windowsupdate.com.a.bdydns.com','download.microsoft.com.lxcvc.com','stats.microsoft.com',
                       'www.update.microsoft.com.nsatc.net','zlxxipv6.v.lxcvc.com','download.microsoft.com',
                       'update.microsoft.com.nsatc.net','redir.update.microsoft.com.nsatc.net','update.microsoft.com']


def app_block():
    applist = []
    print("generating app block rules...")
    with open(app_path,'r',encoding='utf-8') as f:
        for line in f.readlines():
            line = line.strip()
            if line and not str(line).startswith("#"):
                applist.append(line)
        f.close()

    if applist:
        rule_name = "app_"+random_rule_name()+"_"
        i = 0
        while  i < len(applist):
            cmdline = "netsh advfirewall firewall add rule name=\""+rule_name+str(i)+"\" dir=in action=block enable=yes program=\""+applist[i]+"\" profile=any >NUL"
            fw.write(cmdline+"\n")                 
            child = subprocess.Popen(cmdline,shell=False)
            child.wait()          
            i += 1
        print("app block rules complete!")
        time.sleep(1)
    else:
        print("there's no app to block!")
        time.sleep(1)


def clean_all_rule():
    print("clean all rules!")
    cmdline = "netsh advfirewall firewall delete rule name=all"
    child = subprocess.Popen(cmdline,shell=False)
    child.wait()    

def check_file():
    if not os.path.exists(ip_path):
        f = open(ip_path,'w',encoding='utf-8')
        f.write("#ip or ip class,one per line\n")
        f.close()
    if not os.path.exists(port_path):
        f = open(port_path,'a',encoding='utf-8')
        f.write("#tcp:21,22,23\n")
        f.write("#udp:135,137,139\n")
        f.close()
    if not os.path.exists(app_path):
        f = open(app_path,'w',encoding='utf-8')
        f.write("#app_absolute_path,one per line\n")
        f.close()
    if not os.path.exists(domain_path):
        f = open(domain_path,'w',encoding='utf-8')
        f.write("#one domain per line\n")
        f.close()    


if __name__ == '__main__':
    os.system('cls')
    check_file()
    print("Welcome to use autoblock")
    print("[this script need administrators priority]")
    print("block type:ip,port,app,domain")
    print("after modify the specific txt,then execute this script")
    sid = input("start rules set Y/N?(N)")
    if sid == 'y' or sid == 'Y':
        fw_rule_path = GetDesktopPath()+"\\fw_rules.bat"
        fw = open(fw_rule_path,'w',encoding='utf-8').close()
        fw = open(fw_rule_path,'a',encoding='utf-8')
        fw.write("@echo off\n")
        fw.write("netsh advfirewall firewall delete rule name=all\n")        
        clean_all_rule()
        port_block()
        app_block()     
        read_ms_domain_list()
        domain_block()
        os.system('cls')
        fw.close()
    else:
        print("GoodBye!")
        time.sleep(1)