├── README.md ├── inject.py ├── pidkill.py ├── proxification ├── redsocks ├── redsocks.conf ├── runvpn.sh ├── settings.ini ├── ssh.py └── tunnel.py /README.md: -------------------------------------------------------------------------------- 1 | # http-ssl-ssh-tunneling 2 | http ssl ssh tunneling vpn for android and linux devices 3 | 4 | # whats new! 5 | 6 | * Now support combination ssl + payload 7 | 8 | # packages : 9 | 10 | [+] - apt install -y git python openssh sshpass netcat-openbsd corkscrew 11 | 12 | [+] - apt install screen 13 | 14 | # configuration : 15 | 16 | past your data into file settings.ini 17 | 18 | ![image](https://user-images.githubusercontent.com/46646744/122469251-9f621400-cfb4-11eb-9d64-f5dbfa2dffa9.png) 19 | 20 | * note : if not woks in defaul auto_replace value , update it to auto_replace = 1 in file settings.ini 21 | 22 | ![image](https://user-images.githubusercontent.com/46646744/121788947-9bf01680-cbc9-11eb-8b84-4682f58d1387.png) 23 | 24 | 25 | # how it works! 26 | 27 | (root is required in android ) 28 | 29 | [+] - git clone https://github.com/tr-tech-guide/http-ssl-ssh-injector.git 30 | 31 | # steps : 32 | 33 | * setup your custom payload and proxy (proxy not required) 34 | 35 | [+] - cd http-ssl-ssh-injector 36 | 37 | [+] - sudo or tsu for termux #run as root 38 | 39 | [+] - chmod +x runvpn.sh 40 | 41 | [+] - ./runvpn.sh 42 | 43 | * choose your connection mode: 44 | 45 | ![image](https://user-images.githubusercontent.com/46646744/122469828-48a90a00-cfb5-11eb-8b2b-48e9870618b2.png) 46 | 47 | 48 | # screenshots 49 | 50 | ![image](https://user-images.githubusercontent.com/46646744/121225010-00853b80-c881-11eb-8cb6-4fcea95f8f88.png) 51 | 52 | * note : to stop the script press CTRL + C 53 | 54 | ![image](https://user-images.githubusercontent.com/46646744/121225175-2c082600-c881-11eb-9c82-27fc2f4200a1.png) 55 | 56 | 57 | -------------------------------------------------------------------------------- /inject.py: -------------------------------------------------------------------------------- 1 | import time 2 | import socket 3 | import configparser 4 | 5 | 6 | bg='' 7 | G = bg+'\033[32m' 8 | O = bg+'\033[33m' 9 | GR = bg+'\033[37m' 10 | R = bg+'\033[31m' 11 | 12 | 13 | 14 | class injector: 15 | def __init__(self): 16 | pass 17 | 18 | def conf(self): 19 | config = configparser.ConfigParser() 20 | try: 21 | config.read_file(open('settings.ini')) 22 | except Exception as e: 23 | self.logs(e) 24 | return config 25 | 26 | def getpayload(self,config): 27 | payload = config['config']['payload'] 28 | return payload 29 | 30 | def proxy(self,config): 31 | proxyhost = config['config']['proxyip'] 32 | proxyport = int(config['config']['proxyport']) 33 | return [proxyhost,proxyport] 34 | def conn_mode(self,config): 35 | mode = config['mode']['connection_mode'] 36 | return mode 37 | 38 | def auto_rep(self,config): 39 | result = config['config']['auto_replace'] 40 | return result 41 | 42 | 43 | def payloadformating(self,payload,host,port): 44 | payload = payload.replace('[crlf]','\r\n') 45 | payload = payload.replace('[crlf*2]','\r\n\r\n') 46 | payload = payload.replace('[cr]','\r') 47 | payload = payload.replace('[lf]','\n') 48 | payload = payload.replace('[protocol]','HTTP/1.0') 49 | payload = payload.replace('[ua]','Dalvik/2.1.0') 50 | payload = payload.replace('[raw]','CONNECT '+host+':'+port+' HTTP/1.0\r\n\r\n') 51 | payload = payload.replace('[real_raw]','CONNECT '+host+':'+port+' HTTP/1.0\r\n\r\n') 52 | payload = payload.replace('[netData]','CONNECT '+host+':'+port +' HTTP/1.0') 53 | payload = payload.replace('[realData]','CONNECT '+host+':'+port+' HTTP/1.0') 54 | payload = payload.replace('[split_delay]','[delay_split]') 55 | payload = payload.replace('[split_instant]','[instant_split]') 56 | payload = payload.replace('[method]','CONNECT') 57 | payload = payload.replace('mip','127.0.0.1') 58 | payload = payload.replace('[ssh]',host+':'+port) 59 | payload = payload.replace('[lfcr]','\n\r') 60 | payload = payload.replace('[host_port]',host+':'+port) 61 | payload = payload.replace('[host]',host) 62 | payload = payload.replace('[port]',port) 63 | payload = payload.replace('[auth]','') 64 | return payload 65 | 66 | def connection(self,client, s,host,port): 67 | if int(self.conn_mode(self.conf())) == 0: 68 | payload = f'CONNECT {host}:{port} HTTP/1.0\r\n\r\n' 69 | else: 70 | payload = self.payloadformating(self.getpayload(self.conf()),host,port) 71 | 72 | if '[split]' in payload or '[instant_split]' in payload or '[delay_split]' in payload: 73 | payload = payload.replace('[split]' ,'||1.0||') 74 | payload = payload.replace('[delay_split]' ,'||1.5||') 75 | payload = payload.replace('[instant_split]','||0.0||') 76 | req = payload.split('||') 77 | for payl in req: 78 | if ('0.5' == payl or '1.5' == payl or '0.0' == payl) : 79 | delay = payl 80 | time.sleep(float(delay)) 81 | else: 82 | s.send(payl.encode()) 83 | 84 | elif '[repeat_split]' in payload : 85 | payload = payload.replace('[repeat_split]','||1||') 86 | payload = payload.replace('[x-split]','||1||') 87 | req = payload.split('||') 88 | payl = [] 89 | for element in req: 90 | if element and element == '1' :pass 91 | else:payl.append(element) 92 | rpspli = payl[0]+payl[0] 93 | s.send(rpspli.encode()) 94 | s.send(payl[1].encode()) 95 | 96 | elif '[reverse_split]' in payload or '[x-split]' in payload: 97 | payload = payload.replace('[reverse_split]','||2|') 98 | payload = payload.replace('[x-split]','||2|') 99 | req = payload.split('||') 100 | payl = [] 101 | for element in req: 102 | if element and element == '2':pass 103 | else:payl.append(element) 104 | rvsplit = payl[0]+payl[1] 105 | s.send(rvsplit.encode()) 106 | s.send(payl[1].encode()) 107 | 108 | elif '[split-x]' in payload: 109 | payload = payload.replace('[split-x]','||3||') 110 | req = payload.split('||') 111 | xsplit = [] 112 | for element in req: 113 | if element and element == '3':pass 114 | else:xsplit.append(element) 115 | alpay = xsplit[0]+xsplit[1] 116 | s.send(alpay.encode()) 117 | 118 | time.sleep(1.0) 119 | s.send(xsplit[1].encode()) 120 | else: 121 | 122 | s.send(payload.encode()) 123 | 124 | if int(self.auto_rep(self.conf())) == 1 or int(self.auto_rep(self.conf())) == 2: 125 | status = s.recv(1024).split('\n'.encode())[0] 126 | self.logs(status.decode()) 127 | 128 | client.send(b"HTTP/1.1 200 Connection Established\r\n\r\n") 129 | if int(self.auto_rep(self.conf())) == 2: 130 | status = s.recv(1024).split('\n'.encode())[0] 131 | self.logs(status.decode()) 132 | 133 | 134 | 135 | def logs(self,log): 136 | logtime = str(time.ctime()).split()[3] 137 | logfile = open('logs.txt','a') 138 | logfile.write(f'[{logtime}] : {str(log)}\n') 139 | -------------------------------------------------------------------------------- /pidkill.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | def handler(): 4 | print('killing process ...') 5 | cmd = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE) 6 | output, error = cmd.communicate() 7 | target_process = "python" 8 | for line in output.splitlines(): 9 | if target_process in str(line): 10 | pid = int(line.split()[0]) 11 | os.system(f'kill {pid}') 12 | 13 | handler() 14 | -------------------------------------------------------------------------------- /proxification: -------------------------------------------------------------------------------- 1 | # create new chain 2 | iptables -t nat -N PROXY 3 | iptables -t nat -I OUTPUT -j PROXY 4 | 5 | # exclude local traffic, see: http://manpages.org/ss-redir 6 | iptables -t nat -A PROXY -d 127.0.0.0/8 -j RETURN 7 | iptables -t nat -A PROXY -d 192.168.0.0/16 -j RETURN 8 | iptables -t nat -A PROXY -d 0.0.0.0/8 -j RETURN 9 | iptables -t nat -A PROXY -d 10.0.0.0/8 -j RETURN 10 | iptables -t nat -A PROXY -d 169.254.0.0/16 -j RETURN 11 | iptables -t nat -A PROXY -d 172.16.0.0/12 -j RETURN 12 | iptables -t nat -A PROXY -d 224.0.0.0/4 -j RETURN 13 | iptables -t nat -A PROXY -d 240.0.0.0/4 -j RETURN 14 | # socksify whole TCP traffic 15 | iptables -t nat -A PROXY -p tcp -j REDIRECT --to-ports 8123 16 | iptables -t nat -A PROXY -p tcp -j REDIRECT --to-ports 8124 17 | 18 | # socksify only DNS UDP traffic 19 | #iptables -t nat -A PROXY -p udp --dport 53 -j REDIRECT --to-ports 7300 20 | #iptables -t nat -A PROXY -p udp --dport 53 -j REDIRECT --to-ports 8125 21 | 22 | 23 | trap "iptables -t nat -D OUTPUT -j PROXY; iptables -t nat -F PROXY; iptables -t nat -X PROXY" EXIT 24 | 25 | # run socksifier 26 | chmod +x redsocks 27 | ./redsocks -c redsocks.conf 28 | -------------------------------------------------------------------------------- /redsocks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TR-TECH-GUIDE/http-ssl-ssh-injector/62b48345880b178edeb86cf9e35a811bc735aa3f/redsocks -------------------------------------------------------------------------------- /redsocks.conf: -------------------------------------------------------------------------------- 1 | base { 2 | 3 | log_debug = off; 4 | log_info = on; 5 | 6 | redirector = iptables; 7 | 8 | } 9 | redsocks { 10 | 11 | local_ip = 0.0.0.0; 12 | local_port = 8123; 13 | 14 | ip = 127.0.0.1; 15 | port = 1080; 16 | 17 | type = socks5; 18 | 19 | 20 | } 21 | redsocks { 22 | 23 | local_ip = 127.0.0.1; 24 | local_port = 8124; 25 | 26 | ip = 10.0.0.1; 27 | port = 1080; 28 | 29 | type = socks5; 30 | 31 | 32 | } 33 | 34 | redudp { 35 | local_ip = 127.0.0.1; 36 | local_port = 7300; 37 | ip = 10.0.0.1; 38 | port = 1080; 39 | dest_ip = 8.8.8.8; dest_port = 53; 40 | udp_timeout = 30; 41 | udp_timeout_stream = 180; 42 | } 43 | redudp { 44 | local_ip = 127.0.0.1; 45 | local_port = 8126; 46 | ip = 10.0.0.1; 47 | port = 1080; 48 | dest_ip = 8.8.8.8; 49 | dest_port = 53; 50 | udp_timeout = 30; 51 | udp_timeout_stream = 180; 52 | } 53 | dnstc { 54 | // fake and really dumb DNS server that returns "truncated answer" to 55 | // every query via UDP, RFC-compliant resolver should repeat same query 56 | // via TCP in this case. 57 | local_ip = 127.0.0.1; 58 | local_port = 5300; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /runvpn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RED='\033[1;31m' 4 | GREEN='\033[1;32m' 5 | YELLOW='\033[1;33m' 6 | SCOLOR='\033[0m' 7 | 8 | 9 | echo -e "${GREEN}Choose Connection Method:" 10 | echo "0 - SSH Direct " 11 | echo "1 - PAYLOAD " 12 | echo "2 - SSL " 13 | echo -e "3 - SSL+PAYLOAD " 14 | 15 | read -p "Enter choice number : " mode 16 | find=`cat settings.ini | grep "connection_mode = " |awk '{print $3}'` 17 | 18 | sed -i "s/connection_mode = $find/connection_mode = $mode/g" settings.ini 19 | 20 | sleep 1 21 | 22 | killprocess() { 23 | echo -e "${RED} vpn service stopped" 24 | python pidkill.py >> /dev/null & 25 | rm logs.txt 26 | echo -e " ${SCOLOR}" 27 | } 28 | 29 | function connect() { 30 | screen -AmdS nohub python tunnel.py 31 | sleep 1 32 | if [ "$mode" = '0' ] || [ "$mode" = '1' ] 33 | then 34 | 35 | screen -AmdS nohub python ssh.py 1 36 | elif [ "$mode" = '2' ] || [ "$mode" = '3' ] 37 | then 38 | 39 | screen -AmdS nohub python ssh.py 2 40 | else 41 | echo -e "${RED}wrong choice\ntry again${SCOLOR}" 42 | python pidkill.py 43 | exit 44 | fi 45 | 46 | echo -e "${YELLOW}---logs----${SCOLOR}" 47 | 48 | sleep 10 49 | cat logs.txt 50 | 51 | var=`cat logs.txt | grep "CONNECTED SUCCESSFULLY"|awk '{print $4}'` 52 | if [ "$var" = "SUCCESSFULLY" ];then 53 | echo -e "${GREEN}---Tunneling starts-----" 54 | chmod +x proxification 55 | ./proxification > /dev/null 56 | echo -e "${SCOLOR}" 57 | iptables --flush 58 | 59 | else 60 | echo -e "${RED}failed! ${SCOLOR}" 61 | fi 62 | } 63 | connect 64 | for i in {1..3} 65 | do 66 | 67 | killprocess 68 | echo -e "${GREEN}" 69 | read -p "reconnect ? [y\n] " reconnect 70 | if [ "$reconnect" = 'y' ] || [ "$reconnect" = 'Y' ] 71 | then 72 | read -p "do yo want changing auto replace value [y\n]" auto_replace 73 | if [ "$auto_replace" = 'y' ] || [ "$auto_replace" = 'Y' ] 74 | then 75 | value=`cat settings.ini | grep "auto_replace ="| awk '{print $3}'` 76 | echo "0 - for payload that doesn't send HTTP RESPONSE" 77 | echo "1 - for payload that send one HTTP RESPONSE" 78 | echo "2 - for payload that send double HTTP RESPONSE" 79 | read -p "Enter your sutable choice : " choice 80 | 81 | sed -i "s/auto_replace = $value/auto_replace = $choice/g" settings.ini 82 | else 83 | echo '' 84 | fi 85 | echo -e "reconnecting ${SCOLOR}" 86 | 87 | connect 88 | else 89 | exit 90 | fi 91 | 92 | done 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /settings.ini: -------------------------------------------------------------------------------- 1 | [mode] 2 | 3 | connection_mode = 0 4 | 5 | [config] 6 | payload = CONNECT [host_port] [protocol][crlf][crlf] 7 | # put proxy if needed else let it empty 8 | proxyip = 9 | proxyport = 10 | 11 | auto_replace = 0 12 | 13 | #ssh acount setting is required . 14 | [ssh] 15 | host = paste host or ssh ip 16 | port = paste here port 17 | username = paste the username 18 | password = paste password 19 | 20 | [sni] 21 | # sni bughost ex : facebook.com 22 | server_name = facebook.com 23 | -------------------------------------------------------------------------------- /ssh.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import socket 3 | import threading 4 | import random 5 | import time 6 | import sys,os,re 7 | import configparser 8 | 9 | # colors 10 | bg='' 11 | G = bg+'\033[32m' 12 | O = bg+'\033[33m' 13 | GR = bg+'\033[37m' 14 | R = bg+'\033[31m' 15 | 16 | class sshRunn: 17 | def __init__(self,inject_host,inject_port): 18 | self.inject_host = inject_host 19 | self.inject_port = inject_port 20 | 21 | def ssh_client(self,socks5_port,host,port,user,password): 22 | try: 23 | 24 | dynamic_port_forwarding = '-CND {}'.format(socks5_port) 25 | host = host 26 | port = port 27 | username = user 28 | password = password 29 | inject_host= self.inject_host 30 | inject_port= self.inject_port 31 | nc_proxies_mode = [f'corkscrew {inject_host} {inject_port} %h %p', f'nc -X CONNECT -x {inject_host}:{inject_port} %h %p'] 32 | arg = str(sys.argv[1]) 33 | if arg == '1': 34 | nc_proxy = nc_proxies_mode[0] 35 | else: 36 | nc_proxy = nc_proxies_mode[1] 37 | response = subprocess.Popen( 38 | ( 39 | f'sshpass -p {password} ssh -o "ProxyCommand={nc_proxy}" {username}@{host} -p {port} -v {dynamic_port_forwarding} ' + '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' 40 | 41 | 42 | ), 43 | shell=True, 44 | stdout=subprocess.PIPE, 45 | stderr=subprocess.STDOUT) 46 | 47 | for line in response.stdout: 48 | line = line.decode('utf-8',errors='ignore').lstrip(r'(debug1|Warning):').strip() + '\r' 49 | if 'compat_banner: no match:' in line: 50 | self.logs(f"{G}handshake starts\nserver :{line.split(':')[2]}") 51 | elif 'Server host key' in line:self.logs(line) 52 | elif 'kex: algorithm:' in line:self.logs(line) 53 | elif 'kex: host key algorithm:' in line:self.logs(line) 54 | elif 'kex: server->client cipher:' in line:self.logs(line) 55 | elif 'Next authentication method: password' in line:self.logs(G+'Authenticate to password'+GR) 56 | elif 'Authentication succeeded (password).' in line:self.logs('Authentication Comleted') 57 | elif 'pledge: proc' in line:self.logs(G+'CONNECTED SUCCESSFULLY '+GR) 58 | elif 'Permission denied' in line:self.logs(R+'username or password are inncorect '+GR) 59 | elif 'Connection closed' in line:self.logs(R+'Connection closed ' +GR) 60 | elif 'Could not request local forwarding' in line:self.logs(R+'Port used by another programs '+GR) 61 | 62 | except KeyboardInterrupt: 63 | sys.exit('stoping ..') 64 | 65 | 66 | def create_connection(self,host,port,user,password): 67 | global soc , payload 68 | try: 69 | soc = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 70 | soc.connect((self.inject_host,int(self.inject_port))) 71 | regx = r'[a-zA-Z0-9_]' 72 | if re.match(regx,host): 73 | try: 74 | ip = socket.gethostbyname(host) 75 | except: 76 | ip = host 77 | thread=threading.Thread(target=self.ssh_client,args=('1080',ip,port,user,password)) 78 | thread.start() 79 | except ConnectionRefusedError: 80 | soc.close() 81 | 82 | except KeyboardInterrupt: 83 | self.logs(R+'ssh stopped'+GR) 84 | 85 | def logs(self,log): 86 | logtime = str(time.ctime()).split()[3] 87 | logfile = open('logs.txt','a') 88 | logfile.write(f'[{logtime}] : {str(log)}\n') 89 | if __name__=='__main__': 90 | 91 | 92 | 93 | start = sshRunn('127.0.0.1','9092') 94 | config = configparser.ConfigParser() 95 | try: 96 | config.read_file(open('settings.ini')) 97 | except Exception as e: 98 | start.logs(f'{R}ERROR {e}') 99 | sys.exit() 100 | 101 | host = config['ssh']['host'] 102 | port = config['ssh']['port'] 103 | user = config['ssh']['username'] 104 | password = config['ssh']['password'] 105 | if host: 106 | start.create_connection(host,port,user,password) 107 | else: 108 | start.logs(f'{R}ssh field is empty in file settings.ini {GR}') 109 | sys.exit 110 | 111 | 112 | -------------------------------------------------------------------------------- /tunnel.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import time 3 | import select 4 | import threading 5 | from inject import injector 6 | import configparser 7 | import ssl 8 | 9 | bg='' 10 | G = bg+'\033[32m' 11 | O = bg+'\033[33m' 12 | GR = bg+'\033[37m' 13 | R = bg+'\033[31m' 14 | 15 | class Tun(injector): 16 | def __init__(self): 17 | self.localip = '127.0.0.1' 18 | self.LISTEN_PORT = 9092 19 | 20 | def conf(self): 21 | config = configparser.ConfigParser() 22 | try: 23 | config.read_file(open('settings.ini')) 24 | except Exception as e: 25 | self.logs(e) 26 | return config 27 | def extraxt_sni(self,config): 28 | sni = config['sni']['server_name'] 29 | return sni 30 | def proxy(self,config): 31 | proxyhost = config['config']['proxyip'] 32 | proxyport = int(config['config']['proxyport']) 33 | return [proxyhost,proxyport] 34 | def conn_mode(self,config): 35 | mode = config['mode']['connection_mode'] 36 | return mode 37 | def tunneling(self,client,sockt): 38 | connected = True 39 | while connected == True: 40 | r, w, x = select.select([client,sockt], [], [client,sockt],3) 41 | if x: connected = False; break 42 | for i in r: 43 | try: 44 | data = i.recv(8192) 45 | if not data: connected = False; break 46 | if i is sockt: 47 | client.send(data) 48 | else: 49 | sockt.send(data) 50 | except: 51 | connected = False;break 52 | client.close() 53 | sockt.close() 54 | self.logs(R+'Disconnected '+GR) 55 | def destination(self,client, address): 56 | try: 57 | self.logs(G+'<#> Client {} received!{}'.format(address[-1],GR)) 58 | request = client.recv(9124).decode() 59 | host = request.split(':')[0].split()[-1] 60 | port = request.split(':')[-1].split()[0] 61 | try: 62 | proxip=self.proxy(self.conf())[0] 63 | proxport=self.proxy(self.conf())[1] 64 | except ValueError: 65 | proxip = host 66 | proxport = port 67 | s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 68 | s.connect((proxip,int(proxport))) 69 | self.logs(f'{G}connected to {proxip}:{proxport}{GR}') 70 | if int(self.conn_mode(self.conf())) == 2: 71 | SNI_HOST = self.extraxt_sni(self.conf()) 72 | context = ssl.SSLContext(ssl.PROTOCOL_TLS) 73 | s = context.wrap_socket(s,server_hostname=str(SNI_HOST)) 74 | self.logs(f'Handshaked successfully to {SNI_HOST}') 75 | self.logs(f"protocol : {context.get_ciphers()[0]['protocol']}") 76 | client.send(b"HTTP/1.1 200 Connection Established\r\n\r\n") 77 | elif int(self.conn_mode(self.conf())) == 3: 78 | SNI_HOST = self.extraxt_sni(self.conf()) 79 | context = ssl.SSLContext(ssl.PROTOCOL_TLS) 80 | s = context.wrap_socket(s,server_hostname=str(SNI_HOST)) 81 | self.logs(f'Handshaked successfully to {SNI_HOST}') 82 | self.logs(f"protocol : {context.get_ciphers()[0]['protocol']}") 83 | injector.connection(self,client, s,str(host),str(port)) 84 | else: 85 | injector.connection(self,client, s,str(host),str(port)) 86 | 87 | 88 | self.tunneling(client,s) 89 | except Exception as e: 90 | self.logs(f'{G}{e}{GR}') 91 | def create_connection(self): 92 | try: 93 | sockt = socket.socket() 94 | sockt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 95 | sockt.bind(('', self.LISTEN_PORT)) 96 | sockt.listen(0) 97 | 98 | self.logs('Waiting for incoming connection to : {}:{}\n'.format(self.localip,self.LISTEN_PORT)) 99 | except OSError: 100 | self.logs(O+'Port already used by another process\nRun script again'+GR) 101 | 102 | 103 | 104 | while True: 105 | try: 106 | client, address = sockt.accept() 107 | thr = threading.Thread(target=self.destination, args=(client, address)) 108 | thr.start() 109 | 110 | except KeyboardInterrupt: 111 | sockt.close() 112 | 113 | 114 | sockt.close() 115 | def logs(self,log): 116 | logtime = str(time.ctime()).split()[3] 117 | logfile = open('logs.txt','a') 118 | logfile.write(f'[{logtime}] : {str(log)}\n') 119 | if __name__=='__main__': 120 | start = Tun() 121 | start.create_connection() 122 | --------------------------------------------------------------------------------