diff --git a/.gitignore b/.gitignore index 510c73d..9eaa774 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ dmypy.json # Pyre type checker .pyre/ + +# Pickle +*.p/ diff --git a/GTAIP.py b/GTAIP.py new file mode 100644 index 0000000..4099cfb --- /dev/null +++ b/GTAIP.py @@ -0,0 +1,11 @@ +from dataclasses import dataclass +from datetime import datetime + +@dataclass +class GTAIP: + ipaddress : str + firstseen : datetime + lastseen : datetime + country : str + region : str + city : str \ No newline at end of file diff --git a/GTAO_Session_Blocker.py b/GTAO_Session_Blocker.py new file mode 100644 index 0000000..d631f1c --- /dev/null +++ b/GTAO_Session_Blocker.py @@ -0,0 +1,32 @@ +import psutil, ctypes, sys, os, atexit +from MainWindow import * + +def kill_proc_tree(): + try: + pid = os.getpid() + + firewall.delete_firewall_rule() + parent = psutil.Process(pid) + + print('cleanup done') + parent.kill() + + except: + print("Something really went wrong") + +def is_admin(): + try: return ctypes.windll.shell32.IsUserAnAdmin() + except: return False + +def main(): + if is_admin(): + os.chdir(os.path.dirname(sys.argv[0])) + app = MainWindow() + app.mainloop() + atexit.register(kill_proc_tree()) + else: + # Re-run the program with admin rights + ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/MainWindow.py b/MainWindow.py new file mode 100644 index 0000000..56abe59 --- /dev/null +++ b/MainWindow.py @@ -0,0 +1,337 @@ +from SnifferThread import SnifferThread +from tksheet import Sheet +from tkinter import messagebox +from tkinter import filedialog as fd +from tkinter import ttk +from tkinter import Menu +import tkinter.simpledialog +import PopUps +from datetime import datetime +import psutil, os, re, pickle, firewall, time +import tkinter as tk + +class MainWindow(tk.Tk): + def __init__(self): + tk.Tk.__init__(self) + + self.runSnifferThread() + self.firewallEnabled = False + self.localIP = '' + self.ipDictonary = {} + self.ipWhiteListDictionary = {} + + self.title('GTA Session Blocker') + + self.setMenuElements() + self.setTopElements() + self.setIPScannerTable() + + self.spawnMiddleScreen() + + self.grid_columnconfigure(0, weight = 1) + self.grid_rowconfigure(0, weight = 1) + + self.loadWhiteList() + self.printDictionary() + + self.resizable(False, False) + + def cleanup(self): + firewall.delete_firewall_rule() + self.snifferThread.stop() + + def runSnifferThread(self): + self.snifferThread = SnifferThread() + self.snifferThread.daemon = True + self.snifferThread.start() + + def spawnMiddleScreen(self): + # Gets the requested values of the height and width. + windowWidth = self.winfo_reqwidth() + windowHeight = self.winfo_reqheight() + + # Gets both half the screen width/height and window width/height + positionRight = int(self.winfo_screenwidth()/2 - windowWidth/2) + positionDown = int(self.winfo_screenheight()/2 - windowHeight) + + # Positions the window in the center of the page. + self.geometry("+{}+{}".format(positionRight, positionDown)) + + def setMenuElements(self): + menubar = Menu(self) + self.config(menu=menubar) + + # create a menu + file_menu = Menu(menubar,tearoff=False) + # add a menu item to the menu + file_menu.add_command(label='Exit',command=self.destroy) + # add the File menu to the menubar + menubar.add_cascade(label="File",menu=file_menu) + + # create the Help menu + help_menu = Menu(menubar,tearoff=0) + help_menu.add_command(label='How To', command=PopUps.HowTo ) + help_menu.add_command(label='About', command=PopUps.About ) + # add the Help menu to the menubar + menubar.add_cascade(label="Help",menu=help_menu) + + def setTopElements(self): + self.topframe = tk.Frame(self) + + # Row 0 + tk.Label(self.topframe, text="GTA V exe path").grid(row=0,column=0, padx=10, pady=2, sticky="w") + self.entryGTAPath = tk.Entry(self.topframe, width=30) + self.entryGTAPath.grid(row=0, column=1, padx=5, pady=2, columnspan=2, sticky="nwe") + for proc in psutil.process_iter(['pid', 'name']): + try: + if proc.name() == "GTA5.exe": + self.entryGTAPath.insert(0,proc.cwd()+'\\'+ 'GTA5.exe') + except psutil.AccessDenied: + continue + self.openfiledialog = ttk.Button(self.topframe,text='Get GTA V Path',command=self.openGTA5Path,width=18) + self.openfiledialog.grid(row=0, column=4, padx=5, pady=2, sticky="nwe") + + # Row 1 + tk.Label(self.topframe, text="Add IP Manually").grid(row=1,column=0, padx=10, pady=2, sticky="w") + self.entryAddIP = tk.Entry(self.topframe,width=30) + self.entryAddIP.grid(row=1, column=1, padx=5, pady=2, columnspan=2, sticky="nwe") + self.btnAddIP = tk.Button(self.topframe, text="Add IP to whitelist",command=self.addIPManually,width=15) + self.btnAddIP.grid(row=1,column=4, padx=5, pady=2, sticky="nwe") + + # Row 2 + tk.Label(self.topframe, text="Whitelist ->").grid(row=2,column=0, padx=10, pady=2,rowspan=1, sticky="w") + tk.Label(self.topframe, text="Right-Click to delete").grid(row=3,column=0, padx=10, rowspan=1, sticky="sw") + tk.Label(self.topframe, text="or insert/edit note").grid(row=4,column=0, padx=10, rowspan=1, sticky="nw") + + # Set whitelist table + self.setWhiteListTable() + + # Row 8 + tk.Label(self.topframe, text="Step 1 >").grid(row=8,column=0, padx=10, pady=2, sticky="w") + tk.Label(self.topframe, text="Suspend GTA and be the host session").grid(row=8,column=1, padx=10, pady=2,columnspan=2, sticky="w") + self.btnSuspendProc = tk.Button(self.topframe, text="Suspend for 10 sec",command=self.suspendGTA) + self.btnSuspendProc.grid(row=8,column=4, padx=5, pady=2, columnspan=1, sticky="we") + + # Row 9 + tk.Label(self.topframe, text="Step 2 >").grid(row=9,column=0, padx=10, pady=2, sticky="w") + tk.Label(self.topframe, text="Invite your friend to join your session and whitelist their IP").grid(row=9,column=1, padx=10, pady=2,columnspan=4, sticky="w") + + # Row 10 + tk.Label(self.topframe, text="Step 3 >").grid(row=10,column=0, padx=10, pady=2, sticky="w") + tk.Label(self.topframe, text="Toggle on/off the firewall").grid(row=10,column=1, padx=10, pady=2,columnspan=2, sticky="w") + self.EnableFirewall = tk.Button(self.topframe, text="Firewall not actived", command=self.togglefirewall,background="yellow") + self.EnableFirewall.grid(row=10,column=4, padx=5, pady=2, columnspan=1, sticky="we") + + # Row 12 + tk.Label(self.topframe, text="IP in session. Right click and Add to White List").grid(row=12,column=0, padx=10, pady=2,columnspan=3, sticky="w") + self.btnRefreshIPData = tk.Button(self.topframe, text="Clear IP table", command=self.clearIPTable) + self.btnRefreshIPData.grid(row=12,column=4, padx=5, pady=2, columnspan=1, sticky="we") + #self.topframe.pack(padx=10,pady=10) + self.topframe.grid(row = 0, column = 0, sticky = "n") + + def setWhiteListTable(self): + headers = ['IP Address','Notes'] + self.ipwhitelistsheet = Sheet(self.topframe, + page_up_down_select_row = True, + expand_sheet_if_paste_too_big = True, + headers = [f"{c}" for c in headers], + height = 200 + ) + + self.ipwhitelistsheet.column_width(column = 0, width = 100) + self.ipwhitelistsheet.column_width(column = 1, width = 200) + self.ipwhitelistsheet.enable_bindings(("single_select", #"single_select" or "toggle_select" + "drag_select", #enables shift click selection as well + "select_all", + "column_drag_and_drop", + "row_drag_and_drop", + "column_select", + "row_select", + "column_width_resize", + "double_click_column_resize", + "row_width_resize", + "column_height_resize", + "arrowkeys", + "row_height_resize", + "double_click_row_resize", + "right_click_popup_menu", + "rc_select", + "copy" + )) + self.ipwhitelistsheet.grid(row=2,column=1, padx=5, pady=2, columnspan=5, rowspan=4, sticky="nwe") + self.ipwhitelistsheet.popup_menu_add_command("Insert/Edit Note", self.whitelistInsertNotes) + self.ipwhitelistsheet.popup_menu_add_command("Delete Entry", self.whitelistDeleteEntry) + + def setIPScannerTable(self): + headers = ['IP Address','Country', 'Firstseen', 'Lastseen', 'Ago', ' Region', 'City'] + self.ipscannerframe = tk.Frame(self) + self.ipscannerframe.grid_columnconfigure(0, weight = 1) + self.ipscannerframe.grid_rowconfigure(0, weight = 1) + self.ipscannersheet = Sheet(self.ipscannerframe, + page_up_down_select_row = True, + expand_sheet_if_paste_too_big = True, + headers = [f"{c}" for c in headers], + height = 300 #height and width arguments are optional + ) + + self.ipscannersheet.column_width(column = 0, width = 100) + self.ipscannersheet.column_width(column = 1, width = 50) + self.ipscannersheet.column_width(column = 2, width = 60) + self.ipscannersheet.column_width(column = 3, width = 60) + self.ipscannersheet.column_width(column = 4, width = 60) + self.ipscannersheet.column_width(column = 5, width = 80) + self.ipscannersheet.column_width(column = 5, width = 150) + self.ipscannersheet.column_width(column = 6, width = 350) + self.ipscannersheet.enable_bindings(("single_select", #"single_select" or "toggle_select" + "drag_select", #enables shift click selection as well + "select_all", + "column_drag_and_drop", + "row_drag_and_drop", + "column_select", + "row_select", + "column_width_resize", + "double_click_column_resize", + "row_width_resize", + "column_height_resize", + "arrowkeys", + "row_height_resize", + "double_click_row_resize", + "right_click_popup_menu", + "rc_select", + "copy" + )) + self.ipscannerframe.grid(row = 1, column = 0, sticky = "swe") + self.ipscannersheet.grid(row = 1, column = 0, sticky = "swe") + self.ipscannersheet.popup_menu_add_command("Add to whitelist", self.rcAddToWhitelist) + + def openGTA5Path(self): + # file type + filetypes = ('exe files', '*.exe') + # show the open file dialog + f = fd.askopenfilename(title="GTA V Exe Path", filetypes =(("GTA5", "GTA5.exe"),("EXE","*.exe"))) + self.entryGTAPath.insert(0, f.replace('/','\\')) + + def addIPManually(self): + if not len(self.entryAddIP.get().strip()) or not self.isValidIP(self.entryAddIP.get().strip()) : + messagebox.showinfo('Invalid IP', 'Please key in a valid IP address') + else: + iptoadd = self.entryAddIP.get().strip() + if self.ipwhitelistsheet.total_rows() > 0: + for i in range(self.ipwhitelistsheet.total_rows()): + if iptoadd in self.ipwhitelistsheet.get_cell_data(i,0).strip(): + messagebox.showinfo('Information',"IP is already in the white list.") + return False + self.ipwhitelistsheet.insert_row([iptoadd,'']) + self.ipwhitelistsheet.display_columns( refresh = True) + self.ipWhiteListDictionary[self.entryAddIP.get().strip()] = '' + self.saveWhiteList() + + def isValidIP(self,address): + pat = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") + check = pat.match(address) + if check: + return True + else: + return False + + def rcAddToWhitelist(self, event = None): + iptoadd = self.ipscannersheet.get_cell_data(self.ipscannersheet.get_currently_selected()[0], 0) + if self.ipwhitelistsheet.total_rows() > 0: + for i in range(self.ipwhitelistsheet.total_rows()): + if iptoadd in self.ipwhitelistsheet.get_cell_data(i,0): + messagebox.showinfo('Information',"IP is already in the white list.") + return False + self.ipwhitelistsheet.insert_row([iptoadd,'']) + self.ipwhitelistsheet.display_columns( refresh = True) + self.ipWhiteListDictionary[iptoadd] = '' + self.saveWhiteList() + + def whitelistInsertNotes(self): + # the input dialog + USER_INP = tkinter.simpledialog.askstring(title="Insert Note",prompt="Please key in your notes below:") + + self.ipwhitelistsheet.set_cell_data(self.ipwhitelistsheet.get_currently_selected()[0], 1,USER_INP) + self.ipwhitelistsheet.display_columns( refresh = True) + self.ipWhiteListDictionary[self.ipwhitelistsheet.get_cell_data(self.ipwhitelistsheet.get_currently_selected()[0], 0)] = USER_INP + self.saveWhiteList() + + def whitelistDeleteEntry(self): + self.ipWhiteListDictionary.pop(self.ipwhitelistsheet.get_cell_data(self.ipwhitelistsheet.get_currently_selected()[0], 0)) + self.ipwhitelistsheet.delete_row(self.ipwhitelistsheet.get_currently_selected()[0]) + self.ipwhitelistsheet.display_columns( refresh = True) + self.saveWhiteList() + + def suspendGTA(self): + psid = 0 + for proc in psutil.process_iter(['pid', 'name']): + try: + if proc.name() == "GTA5.exe": + psid = proc.pid + except psutil.AccessDenied: + continue + if psid: + gta_process = psutil.Process(psid) + + gta_process.suspend() + seconds = 10 + while seconds != 0: + time.sleep(1) + seconds -= 1 + gta_process.resume() + else: + messagebox.showinfo('Error', 'Unable to find GTA processs') + + def togglefirewall(self): + if self.firewallEnabled: + firewall.delete_firewall_rule() + self.EnableFirewall.configure(text="Firewall not actived",background="yellow",foreground="black") + self.firewallEnabled = False + else: + programpath = self.entryGTAPath.get().strip() + if os.path.isfile(programpath): + self.enableFirewall(programpath) + time.sleep(0.5) + + self.EnableFirewall.configure(text="Firewall actived",background="green",foreground="white") + self.firewallEnabled = True + else: + messagebox.showinfo('Missing Game Path','Missing/invalid GTA Online EXE path!') + + + #def disableFirewall(self): + + def enableFirewall(self, programpath): + success = firewall.add_firewall_rule(programpath) + if success: + # Add scope + for ip in list(self.ipWhiteListDictionary.keys()): + firewall.add_white_list(str(ip).strip()) + # Enable Firewall + time.sleep(2) + firewall.enable_firewall_rule() + + def clearIPTable(self): + self.snifferThread.clearIPDictionary() + self.ipscannersheet.display_columns( refresh = True ) + + def printDictionary(self) -> None: + if self.ipscannersheet.total_rows() > 0: + for i in range(self.ipscannersheet.total_rows()): + self.ipscannersheet.delete_row(self.ipscannersheet.total_rows()-1) + for ip, info in self.snifferThread.getIPDictionary().items(): + self.ipscannersheet.insert_row([ip, info.country, info.firstseen.strftime("%H:%M:%S"), info.lastseen.strftime("%H:%M:%S"), str(datetime.now() - info.lastseen).split(".")[0] ,info.region, info.city]) + self.ipscannersheet.display_columns( refresh = True) + self.after(1000, self.printDictionary) + + def saveWhiteList(self): + with open('ipwhitelist.p', 'wb') as fp: + pickle.dump(self.ipWhiteListDictionary, fp, protocol=pickle.HIGHEST_PROTOCOL) + + def loadWhiteList(self): + if os.path.isfile('ipwhitelist.p'): + with open('ipwhitelist.p', 'rb') as fp: + self.ipWhiteListDictionary = pickle.load(fp) + for k,v in self.ipWhiteListDictionary.items(): + self.ipwhitelistsheet.insert_row([k,v]) + self.ipwhitelistsheet.display_columns( refresh = True) + \ No newline at end of file diff --git a/PopUps.py b/PopUps.py new file mode 100644 index 0000000..fe272a0 --- /dev/null +++ b/PopUps.py @@ -0,0 +1,78 @@ +import tkinter as tk +from tkinter import ttk +import webbrowser + +def callback(url): + webbrowser.open_new_tab(url) + +def About(): + win = tk.Toplevel() + win.wm_title("About") + + tk.Label(win, text="About",font=("Arial", 25)).grid(row=0, column=0, padx=5, pady=2, columnspan=2, sticky='ew') + + tk.Label(win, text="Created by Aki [rarakat#3152]",font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=2, columnspan=2, sticky='ew') + + tk.Label(win, text="GitHub:",font=("Arial", 12)).grid(row=3, column=0, sticky='w', padx=5,pady=5) + githublbl = tk.Label(win, text=r"https://github.com/fscene8/GTAO_Session_Blocker", font=("Arial", 12), fg="blue", cursor="hand2") + githublbl.grid(row=3, column=1, padx=5, pady=5, sticky='w') + githublbl.bind("", lambda e: callback("https://github.com/fscene8/GTAO_Session_Blocker")) + + tk.Label(win, text="GTA Crew:",font=("Arial", 12)).grid(row=4, column=0, sticky='w', padx=5, pady=5) + sclbl = tk.Label(win, text="https://socialclub.rockstargames.com/crew/sgpckias/", font=("Arial", 12), fg="blue", cursor="hand2") + sclbl.grid(row=4, column=1, padx=5, pady=5, sticky='w') + sclbl.bind("", lambda e: callback("https://socialclub.rockstargames.com/crew/sgpckias/")) + + b = ttk.Button(win, text="Okay", command=win.destroy) + b.grid(row=5, column=0, columnspan=2, padx=5, pady=10, sticky='s') + + win.resizable(False, False) + + # Gets the requested values of the height and width. + windowWidth = win.winfo_reqwidth() + windowHeight = win.winfo_reqheight() + + # Gets both half the screen width/height and window width/height + positionRight = int(win.winfo_screenwidth()/2 - windowWidth / 2) + positionDown = int(win.winfo_screenheight()/2 - windowHeight/ 2) + + # Positions the window in the center of the page. + win.geometry("+{}+{}".format(positionRight, positionDown)) + + +def HowTo(): + win = tk.Toplevel() + win.wm_title("About") + + tk.Label(win, text="How to use",font=("Arial", 25)).grid(row=0, column=0, padx=5, pady=2, columnspan=2, sticky='ew') + + tk.Label(win, text="Step 1 > ",font=("Arial", 11)).grid(row=1, column=0, padx=5, pady=2, sticky='w') + tk.Label(win, text="Run GTA Online", font=("Arial", 11)).grid(row=1, column=1, padx=5, pady=2, sticky='w') + + tk.Label(win, text="Step 2 > ",font=("Arial", 11)).grid(row=2, column=0, padx=5, pady=2, sticky='w') + tk.Label(win, text="Suspend the process and be the session host", font=("Arial", 12)).grid(row=2, column=1, padx=5, pady=2, sticky='w') + + tk.Label(win, text="Step 3 > ",font=("Arial", 11)).grid(row=3, column=0, padx=5, pady=2, sticky='w') + tk.Label(win, text="Invite your friend to your session and right click their IP to whitelist", font=("Arial", 11)).grid(row=3, column=1, padx=5, pady=2, sticky='w') + + tk.Label(win, text="Step 4 > ",font=("Arial", 11)).grid(row=4, column=0, padx=5, pady=2, sticky='w') + tk.Label(win, text="Toggle on the firewall to prevent public from entering", font=("Arial", 11)).grid(row=4, column=1, padx=5, pady=2, sticky='w') + + tk.Label(win, text="Notes > ",font=("Arial", 11)).grid(row=5, column=0, padx=5, pady=2, sticky='w') + tk.Label(win, text="You might need to toggle off your firewall for your friend to rejoin the session again", font=("Arial", 11)).grid(row=5, column=1, padx=5, pady=2, sticky='w') + + b = ttk.Button(win, text="Okay", command=win.destroy) + b.grid(row=6, column=0, columnspan=2, padx=5, pady=2, sticky='s') + + win.resizable(False, False) + + # Gets the requested values of the height and width. + windowWidth = win.winfo_reqwidth() + windowHeight = win.winfo_reqheight() + + # Gets both half the screen width/height and window width/height + positionRight = int(win.winfo_screenwidth()/2 - windowWidth / 2) + positionDown = int(win.winfo_screenheight()/2 - windowHeight/ 2) + + # Positions the window in the center of the page. + win.geometry("+{}+{}".format(positionRight, positionDown)) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c733663 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# GTAO Session Blocker +My first python project with multithreading and subprocess with GUI tkinter. +I had enough of grievers in game! + +### Features +* Play Grand Theft Auto Online with friends only. +* Detect other players IP in session, with more details (lastseen, location) +* Whitelist IP addresses and play with your friends without modder/hackers +* Auto saves and leave notes your whitelist IP list + +### Installation +1. Install [npcap](https://nmap.org/npcap/) for packet sniffing +2. Run `GTAO_Session_Blocker.exe` + +### How to use +1. Run GTA Online +2. Run `GTAO_Session_Blocker.exe` +3. Load to a session, suspend GTA5 process and be the session host +4. Invite your friend over to your session +5. Whitelist their IP (right click the table below) +6. Turn on firewall + +# Requirements + +### Drivers +| Driver | Description | +|----|---| +| [npcap](https://nmap.org/npcap/) | Packet sniffing | + +### Modules + +| Module | Description | +|-------------|------------------------------------------| +| [tksheet](https://github.com/ragardner/tksheet) | Table widget for displaying tabular data | +| [scapy](https://github.com/secdev/scapy) | Packet manipulation | +| [ip2geotools](https://github.com/tomas-net/ip2geotools) | Geolocation information IP address | +| [psutil](https://github.com/giampaolo/psutil) | Process and system monitoring in Python | + +### Special Thanks +* @abdulmudhir for sharing [firewall.py](https://github.com/AbdulMudhir/GTA_V_Firewall_Public_Online/blob/master/firewall.py), which made this project possible \ No newline at end of file diff --git a/SnifferThread.py b/SnifferThread.py new file mode 100644 index 0000000..85ab747 --- /dev/null +++ b/SnifferThread.py @@ -0,0 +1,52 @@ +import socket +from GTAIP import GTAIP +from scapy.all import * +from ip2geotools.databases.noncommercial import DbIpCity +from datetime import datetime + +class SnifferThread(Thread): + def __init__(self): + # Call the Thread class's init function + Thread.__init__(self) + self.ipDictionary = {} + + def pc(self, packet): + if packet.proto == 17: + udp = packet.payload + + def stop(self): + self.keeprunning = False + + def getlocalIPAddress(self) -> str: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + ip = s.getsockname()[0] + s.close() + return ip + + def clearIPDictionary(self): + self.ipDictionary = {} + + def getIPDictionary(self): + return self.ipDictionary + + def run(self) -> None: + print('Sniffer thread spawned') + + self.keeprunning = True + self.ipDictionary = {} + localIP = self.getlocalIPAddress() + while True: + packet = sniff(filter="udp and port 6672", prn=self.pc, store=1, count=1) # GTA V Online UDP default Port is 6672 + #y = x[0][IP].src + dest = packet[0][IP].dst + if dest == localIP: + pass + else: + if not dest in self.ipDictionary.keys(): + try: + self.ipDictionary[dest] = GTAIP(dest,datetime.now(), datetime.now(), DbIpCity.get(dest, api_key='free').country, DbIpCity.get(dest, api_key='free').region, DbIpCity.get(dest, api_key='free').city) + except: + self.ipDictionary[dest] = GTAIP(dest,datetime.now(), datetime.now(), DbIpCity.get(dest, api_key='free').country, "Spoof", "IP") + else: + self.ipDictionary[dest].lastseen = datetime.now() \ No newline at end of file diff --git a/firewall.py b/firewall.py new file mode 100644 index 0000000..060488a --- /dev/null +++ b/firewall.py @@ -0,0 +1,230 @@ +from subprocess import Popen, PIPE +import re +import ctypes + +firewall_rule_name = "GTAO Session Blocker Rule" + +# shell = True will remove console output when using .exe from pyinstaller +def running_as_admin(): + return ctypes.windll.shell32.IsUserAnAdmin() + + +def firewall_exist(): + netsh_firewall_exist = f'''netsh advfirewall firewall show rule name="{firewall_rule_name}"''' + in_command = Popen(netsh_firewall_exist, stdout=PIPE, stderr=PIPE, shell=True) + output_message, _ = in_command.communicate() + + return "No rules match the specified criteria." != output_message.decode().strip() + + +def firewall_scopes_list(): + if firewall_exist(): + netsh_firewall_exist = f'''netsh advfirewall firewall show rule name="{firewall_rule_name}" dir=in ''' + in_command = Popen(netsh_firewall_exist, stdout=PIPE, stderr=PIPE, shell=True) + + output_message, _ = in_command.communicate() + + output_message_decoded = output_message.decode().strip() + + remote_ip_address = output_message_decoded.split()[17] + + return remote_ip_address + + +def firewall_active(): + netsh_firewall_exist = f'''netsh advfirewall firewall show rule name="{firewall_rule_name}" dir=in ''' + in_command = Popen(netsh_firewall_exist, stdout=PIPE, stderr=PIPE, shell=True) + + output_message, _ = in_command.communicate() + + output_message_decoded = output_message.decode().strip() + + status = output_message_decoded.split()[8] + return status != "No" + + +def valid_ip_address(ip_address): + ip_address_pattern = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/?\d?\d?" + check_ip = re.match(ip_address_pattern, ip_address) + + return check_ip is not None + + +def add_firewall_rule(program_path): + netsh_add_firewall_command_in = f'''netsh advfirewall firewall add rule name="{firewall_rule_name}" dir=in action=block program="{program_path}" enable=no profile=domain,private,public protocol=UDP localport=6672''' + netsh_add_firewall_command_out = f'''netsh advfirewall firewall add rule name="{firewall_rule_name}" dir=out action=block program="{program_path}" enable=no profile=domain,private,public protocol=UDP localport=6672''' + in_command = Popen(netsh_add_firewall_command_in, stdout=PIPE, stderr=PIPE, shell=True) + out_command = Popen(netsh_add_firewall_command_out, stdout=PIPE, stderr=PIPE, shell=True) + + output_message, _ = in_command.communicate() + + return "Ok." == output_message.decode().strip() + + +def split_ip_addresss(ip_address): + # will be split to compare the different IP octet + split_ip = ip_address.split(".") + return int(split_ip[0]), int(split_ip[1]), int(split_ip[2]), int(split_ip[3]) + + +def ip_address_above_and_below(ip_address): + # split ip address to get different octet + ip_address = ip_address.split('.') + last_octet = ip_address[-1] + other_remaining = '.'.join(ip_address[0:3]) + first_ip = f"{other_remaining}.{int(last_octet) - 1}" + second_ip = f"{other_remaining}.{int(last_octet) + 1}" + + return first_ip, second_ip + + +def new_ip_address_scope(previous_scope, ip_address): + # will be used to sort out ip address from smallest to biggest + previous_split_scope = "-".join(previous_scope.split(",")) + + multiple_ip_address = [] + + + # check if multiple ip_address are passed through + if "," in ip_address: + + + new_ip_address_split = ip_address.split(",") + + for ip in new_ip_address_split: + # splitting the ip address so we can get a +1 and -1 range of the current ip address + first_ip, second_ip = ip_address_above_and_below(ip) + # keep track of both ip addresses + multiple_ip_address.append(first_ip) + multiple_ip_address.append(second_ip) + + new_unsorted_scope = previous_split_scope.split("-") + multiple_ip_address + + + else: + # splitting the ip address so we can get a +1 and -1 range of the current ip address + first_ip, second_ip = ip_address_above_and_below(ip_address) + + # joining first and second ip to the scope list rather than having to loop twice + new_unsorted_scope = f"{previous_split_scope}-{first_ip}-{second_ip}".split("-") + + + new_sorted_scope = sorted(new_unsorted_scope, key=split_ip_addresss) + # looping through the sorted list and combine two ip address to get the range we need + new_scope = [f"{new_sorted_scope[index - 1]}-{ip}" for index, ip in enumerate(new_sorted_scope) if + (index + 1) % 2 == 0] + + return ','.join(new_scope) + + +def add_white_list(ip_address): + previous_scope = firewall_scopes_list() + # will be used to create a new scope if none exist + zero_IP = "0.0.0.0" + last_IP = "255.255.255.255" + + if previous_scope != "Any": + + new_scope = new_ip_address_scope(previous_scope, ip_address) + + netsh_allow_remote_address = f'''netsh advfirewall firewall set rule name="{firewall_rule_name}" new remoteip={new_scope} ''' + Popen(netsh_allow_remote_address, shell=True) + + + else: + + first_ip, second_ip = ip_address_above_and_below(ip_address) + + first_range = f"{zero_IP}-{first_ip}" + second_range = f"{second_ip}-{last_IP}" + + new_scope = f'{first_range},{second_range}' + + netsh_allow_remote_address = f'''netsh advfirewall firewall set rule name="{firewall_rule_name}" new remoteip={new_scope} ''' + Popen(netsh_allow_remote_address, shell=True) + + +def ip_address_without_scope(): + ip_scope = firewall_scopes_list() + + ip_address_in_firewall = re.split('[,-]', ip_scope) + + ip_address_in_scope = [] + + for index, ip_address in enumerate(ip_address_in_firewall, start=1): + + if index % 2 == 0 and index != len(ip_address_in_firewall): + ip_address = ip_address.split('.') + last_octet = ip_address[-1] + original_ip = f"{'.'.join(ip_address[0:3])}.{int(last_octet) + 1}" + ip_address_in_scope.append(original_ip) + + return ip_address_in_scope + + +def ip_address_exist_in_scope(ip_address): + current_ip_scope = ip_address_without_scope() + for ip in current_ip_scope: + if ip == ip_address: + return True + return False + + +def remove_white_list(ip_address): + ip_scope = re.split("[,-]", firewall_scopes_list()) + + + + + if "," in ip_address: + ip_addresses = ip_address.split(",") + + for ip in ip_addresses: + + first_ip, second_ip = ip_address_above_and_below(ip) + + try: + ip_scope.remove(first_ip) + ip_scope.remove(second_ip) + # will be used if a value was already removed form the scope + except ValueError: + pass + else: + first_ip, second_ip = ip_address_above_and_below(ip_address) + + try: + ip_scope.remove(first_ip) + ip_scope.remove(second_ip) + # will be used if a value was already removed form the scope + except ValueError: + pass + + new_scope = ",".join([f"{ip_scope[index - 1]}-{ip}" for index, ip in enumerate(ip_scope) if + (index + 1) % 2 == 0]) + + + + if len(new_scope) != 1: + netsh_allow_remote_address = f'''netsh advfirewall firewall set rule name="{firewall_rule_name}" dir=in new remoteip={new_scope} ''' + Popen(netsh_allow_remote_address, shell=True) + + else: + netsh_allow_remote_address = f'''netsh advfirewall firewall set rule name="{firewall_rule_name}" dir=in new remoteip="" ''' + Popen(netsh_allow_remote_address, shell=True) + + +def enable_firewall_rule(): + netsh_add_firewall_command = f'''netsh advfirewall firewall set rule name="{firewall_rule_name}" new enable=yes ''' + Popen(netsh_add_firewall_command, shell=True) + print('rule enabled') + +def disable_firewall_rule(): + netsh_add_firewall_command = f'''netsh advfirewall firewall set rule name="{firewall_rule_name}" new enable=no ''' + Popen(netsh_add_firewall_command, shell=True) + +def delete_firewall_rule(): + netsh_add_firewall_command = f'''netsh advfirewall firewall delete rule name="{firewall_rule_name}" ''' + in_command = Popen(netsh_add_firewall_command, stdout=PIPE, stderr=PIPE, shell=True) + output_message, _ = in_command.communicate() + print('rule deleted') + return "Ok." in output_message.decode().strip() diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..40b8ec5 Binary files /dev/null and b/icon.ico differ