import tkinter as tk
from tkinter import ttk, scrolledtext
from threading import Thread, Lock
import re
import socket
import netifaces

lock = Lock()


def extract_ips(bridge_data):
    pattern = re.compile(r'(\d{1,3}(?:.\d{1,3}){3}:\d+)')
    ips_with_ports = pattern.findall(bridge_data)
    return ips_with_ports


def update_console(message):
    with lock:
        console_display.configure(state='normal')
        console_display.insert(tk.END, message + "\n")
        console_display.configure(state='disabled')
        console_display.yview(tk.END)


def is_port_open(ip, port, timeout):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    try:
        sock.connect((ip, port))
        return True
    except socket.error:
        return False
    finally:
        sock.close()


def check_ip_port(ip, port, timeout):
    if is_port_open(ip, port, timeout):
        update_console(f"Connection successful for {ip}:{port}")
        return True
    else:
        update_console(f"Connection failed for {ip}:{port}")
        return False


def check_bridges():
    raw_data = bridge_input.get('1.0', tk.END)
    ip_port_pairs = extract_ips(raw_data)
    timeout = float(timeout_entry.get())

    def process_ips():
        responsive_bridges = []
        for ip_port in ip_port_pairs:
            try:
                ip, port = ip_port.split(':')
                if check_ip_port(ip, int(port), timeout):
                    responsive_bridges.append(ip_port)
            except ValueError:
                update_console(f"Invalid format for bridge: {ip_port}")

        with lock:
            responsive_data = '\n'.join(
                [line for line in raw_data.split('\n') if any(ip_port in line for ip_port in responsive_bridges)]
            )
            result_display.configure(state='normal')
            result_display.delete('1.0', tk.END)
            result_display.insert(tk.END, responsive_data)
            result_display.configure(state='disabled')
            status_label.config(text="Check completed")

    for _ in range(int(thread_count_entry.get())):
        thread = Thread(target=process_ips)
        thread.start()


def get_network_interfaces():
    interfaces_list = netifaces.interfaces()
    return interfaces_list


def clear_console():
    console_display.configure(state='normal')
    console_display.delete('1.0', tk.END)
    console_display.configure(state='disabled')


def enable_copy_paste(event):
    menu = tk.Menu(root, tearoff=0)
    menu.add_command(label="Copy", command=lambda: event.widget.event_generate('<Control-c>'))
    menu.add_command(label="Paste", command=lambda: event.widget.event_generate('<Control-v>'))
    menu.add_command(label="Select All", command=lambda: event.widget.tag_add(tk.SEL, "1.0", tk.END))
    menu.tk_popup(event.x_root, event.y_root)


root = tk.Tk()
root.title("Tor Bridge Connectivity Checker")

frame = ttk.Frame(root, padding="3")
frame.grid(column=0, row=0, sticky=(tk.W, tk.E, tk.N, tk.S))
frame.columnconfigure(0, weight=1)

interfaces = get_network_interfaces()

net_interface_label = ttk.Label(frame, text="Network Interface:")
net_interface_label.grid(column=0, row=0, sticky=tk.W)
net_interface_selector = ttk.Combobox(frame, values=interfaces)
net_interface_selector.grid(column=1, row=0, sticky=(tk.W, tk.E), columnspan=3)

thread_count_label = ttk.Label(frame, text="Thread Count:")
thread_count_label.grid(column=4, row=0, sticky=tk.W, padx=(4, 0))
thread_count_entry = ttk.Spinbox(frame, from_=1, to=100, increment=1, width=7)
thread_count_entry.set(10)
thread_count_entry.grid(column=5, row=0)

timeout_label = ttk.Label(frame, text="Timeout (s):")
timeout_label.grid(column=6, row=0, sticky=tk.W, padx=(4, 0))
timeout_entry = ttk.Spinbox(frame, from_=1, to=10, increment=0.5, width=7, format="%.1f")
timeout_entry.set(3.0)
timeout_entry.grid(column=7, row=0)

bridge_label = ttk.Label(frame, text="Bridges to Check:")
bridge_label.grid(column=0, row=1, sticky=tk.W)
bridge_input = scrolledtext.ScrolledText(frame, height=10)
bridge_input.grid(column=0, row=2, columnspan=8, sticky=(tk.W, tk.E), pady=(0, 5))
bridge_input.bind('<Button-3>', enable_copy_paste)

result_label = ttk.Label(frame, text="Sorted List:")
result_label.grid(column=0, row=4, sticky=tk.W)
result_display = scrolledtext.ScrolledText(frame, height=10, state='disabled')
result_display.grid(column=0, row=5, columnspan=8, sticky=(tk.W, tk.E), pady=(0, 5))
result_display.bind('<Button-3>', enable_copy_paste)

check_button = tk.Button(frame, text="Check Bridges", command=check_bridges)
check_button.grid(column=0, row=6, sticky=tk.W, pady=(0, 5))

clear_console_button = tk.Button(frame, text="Clear Log", command=clear_console)
clear_console_button.grid(column=1, row=6, sticky=tk.W)

console_label = ttk.Label(frame, text="Console Log:")
console_label.grid(column=0, row=7, sticky=tk.W)
console_display = scrolledtext.ScrolledText(frame, height=8, state='disabled', background='black', foreground='white')
console_display.grid(column=0, row=8, columnspan=8, sticky=(tk.W, tk.E))
console_display.bind('<Button-3>', enable_copy_paste)

status_label = tk.Label(frame, bd=1, relief=tk.SUNKEN, anchor=tk.W)
status_label.grid(column=0, row=9, columnspan=8, sticky=(tk.W, tk.E))

root.mainloop()





need to exclude all non tcpv4 bridges string in parsing and processing. need to do two checkboxes for tcpv4 enabled by default and tcpv6 disable and not parsed/implemented yet.

need do normal threading mechanism for each IP in query in one strict thread per IP in range of available bridge strings, defaulted to some 5 threads max in total.

here is some bridges strings as example:

"""

webtunnel [2001:db8:77cb:5ce6:9995:7466:7ffa:b3f8]:443 770EA6412C8D3997ABFFF7173A3E53F1D3660167 url=https://shallotfarm.org/jcHgyp7m90iQr9QaVSprq1wP ver=0.0.1

 webtunnel [2001:db8:e80a:7d8e:8814:3b1b:1fdd:23ec]:443 89C890285B8973D3A2156E15346B50FC185C814D url=https://consolehub.uk/zeix2sahlaluRoniPhoo ver=0.0.1

 webtunnel [2001:db8:1434:dd5:ea31:fea5:10ec:5793]:443 46B4F76EFFFD98709EB0C650FFFAC93DD6E1F4B9 url=https://hello.serifos.uk/3DCVvExMUCHV6xu0EzconFt3 ver=0.0.1

 webtunnel [2001:db8:3d87:58ab:4ec3:21ba:913f:99d8]:443 E4B91C347D685E929C1B7CE84CC27EB073127EA6 url=https://borntec.autos/poh8aiteaqu6oophaiXo ver=0.0.1

 193.182.111.21:80 F31C3DDFB2ECF41BEF693EC866BFE6B7E9A06A90
195.20.236.150:8080 AF96A8185165A37ED5CEC4FD0F78B259DAA511A5
 80.67.172.3:443 088ACF1F2F1720AA41BE8575F45AD202FBD59296
151.115.78.42:7002 4D877AB9773E6E1EEFC8AB84A705B2A9ABDDA379
 38.180.22.86:11111 4CA863D0DFF09A1D07277E03646FBF3B235CDF74
213.108.108.145:17674 A39C0FE47963B6E8CFE9815549864DE544935A31
 95.117.102.83:443 2154DB58231A01333F76160E6DC438BDBA66AD62
37.27.32.233:28710 38F848796D85A1705E4922DF8726E3FB3464807B

 obfs4 212.227.193.159:8082 94F987600D8539445A78908035A331608C88D0E2 cert=JopFFuvSS2cewOdvb2emOQdfMYNgjVXS6LoVc47VjMWaBRz7xCHGiHqRo5EOzcXZJd2+Cg iat-mode=0
obfs4 78.141.218.179:4443 1FB333CA0BDDA6030E47C39405838B6E14342F20 cert=DISSrAzwpY+lc+ctk8DHLriwOsdfd1Cgcqp1lmuTlUsb0Zew6ltCOuikEx5x83tNZ+oxQw iat-mode=0
 obfs4 79.215.106.83:9531 DC1A7B010A348F3A6BE0750D38428D1EAD976D69 cert=TX3XOj1SX3fAB9yoA4dCx8Geu325i564gwIBgnAMyhP6NBdd9dW90gJpWQXKL/VC2BlTNQ iat-mode=0
obfs4 82.64.115.17:993 C1FFD364E11928D9C84ECF76987693CF58355749 cert=Nwv7E2pul9jzCa+4ltAjL4sdAnI5Fu/XVoVv6IkYnCQn976NHEgK2+WwBY7+zVPUhL8fAQ iat-mode=0

""".