mirror of
				https://github.com/PiMaker/Teletun.git
				synced 2025-03-09 15:40:14 +00:00 
			
		
		
		
	feature: python3, secret chat
This commit is contained in:
		
							parent
							
								
									d4f8a9872c
								
							
						
					
					
						commit
						c8a99a5b5b
					
				
					 1 changed files with 168 additions and 105 deletions
				
			
		
							
								
								
									
										273
									
								
								teletun.py
									
										
									
									
									
								
							
							
						
						
									
										273
									
								
								teletun.py
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,8 +1,10 @@
 | 
			
		|||
#!/usr/bin/env python
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
# (C) Stefan Reiter 2017
 | 
			
		||||
# (C) Radomír Polách 2020
 | 
			
		||||
 | 
			
		||||
from pytun import TunTapDevice
 | 
			
		||||
from pytg import Telegram
 | 
			
		||||
from pytg.sender import Sender
 | 
			
		||||
from pytg.receiver import Receiver
 | 
			
		||||
from pytg.utils import coroutine
 | 
			
		||||
| 
						 | 
				
			
			@ -13,129 +15,190 @@ import sys
 | 
			
		|||
import psutil
 | 
			
		||||
import os
 | 
			
		||||
import signal
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Connect to telegram
 | 
			
		||||
print('Connecting to telegram...')
 | 
			
		||||
 | 
			
		||||
receiver = Receiver(host="localhost", port=4458)
 | 
			
		||||
sender = Sender(host="localhost", port=4458)
 | 
			
		||||
 | 
			
		||||
# Retrieve contact list
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    contacts = [c for c in sender.dialog_list()]
 | 
			
		||||
    for i, user in enumerate(contacts):
 | 
			
		||||
        print(unicode(i) + ': \t' + unicode(user['print_name']))
 | 
			
		||||
except ConnectionError:
 | 
			
		||||
    print('Could not connect to telegram-cli. Start it by issuing "telegram-cli --json -P 4458" in a separate console.')
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
# Ask user to choose contact
 | 
			
		||||
i = int(input('Telegram online, please enter contact to connect to (by number): '))
 | 
			
		||||
 | 
			
		||||
# Print username
 | 
			
		||||
try:
 | 
			
		||||
    username = unicode(contacts[i]['print_name'])
 | 
			
		||||
    peer_id = contacts[i]['peer_id']
 | 
			
		||||
    print('Connecting to partner: ' + username)
 | 
			
		||||
except IndexError:
 | 
			
		||||
    print('Please enter a number in the above range!')
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
# Create TUN device for network capture and injections
 | 
			
		||||
tun = TunTapDevice(name='teletun-device')
 | 
			
		||||
 | 
			
		||||
print(tun.name + ' has been created, information follows:')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Set IP address based on --server flag
 | 
			
		||||
if '--server' in sys.argv:
 | 
			
		||||
    tun.addr = '10.8.0.1'
 | 
			
		||||
    tun.dstaddr = '10.8.0.2'
 | 
			
		||||
else:
 | 
			
		||||
    tun.addr = '10.8.0.2'
 | 
			
		||||
    tun.dstaddr = '10.8.0.1'
 | 
			
		||||
 | 
			
		||||
tun.netmask = '255.255.255.0'
 | 
			
		||||
tun.mtu = 1500
 | 
			
		||||
 | 
			
		||||
print('Address: ' + tun.addr)
 | 
			
		||||
print('Dest.-Address: ' + tun.dstaddr)
 | 
			
		||||
print('Netmask: ' + tun.netmask)
 | 
			
		||||
print('MTU: ' + str(tun.mtu))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Start TUN device
 | 
			
		||||
tun.up()
 | 
			
		||||
up = True
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import argparse
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
# Init stats
 | 
			
		||||
sent = 0
 | 
			
		||||
received = 0
 | 
			
		||||
 | 
			
		||||
# Init status
 | 
			
		||||
up = False 
 | 
			
		||||
 | 
			
		||||
# Tun
 | 
			
		||||
tun = False
 | 
			
		||||
encrypted = False
 | 
			
		||||
 | 
			
		||||
# Arguments
 | 
			
		||||
args = False
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    global sent, received, up, tun, encrypted, args;
 | 
			
		||||
 | 
			
		||||
# Process arguments
 | 
			
		||||
    parser = argparse.ArgumentParser(description='Teletun - IP over Telegram')
 | 
			
		||||
    parser.add_argument('peer_id', help='peer id (list for contact list)')
 | 
			
		||||
    parser.add_argument('-r', '--server', help='server', action='store_true')
 | 
			
		||||
    parser.add_argument('-e', '--encrypted', help='secret chat', action='store_true')
 | 
			
		||||
    parser.add_argument('-p', '--src', help='peer address', default='10.8.0.2')
 | 
			
		||||
    parser.add_argument('-s', '--dst', help='server address', default='10.8.0.1')
 | 
			
		||||
    parser.add_argument('-m', '--mask', help='mask', default='255.255.255.0')
 | 
			
		||||
    parser.add_argument('-n', '--mtu', help='MTU', default=1500)
 | 
			
		||||
    parser.add_argument('-H', '--host', help='Telegram host address', default='localhost')
 | 
			
		||||
    parser.add_argument('-P', '--port', help='Telegram port', default=4458)
 | 
			
		||||
    parser.add_argument('-a', '--auto', help='autoconfig from server', action='store_true')
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    peer_id = None
 | 
			
		||||
 | 
			
		||||
# Connect to telegram
 | 
			
		||||
    print('Connecting to Telegram...', file=sys.stderr)
 | 
			
		||||
    receiver = Receiver(host=args.host, port=args.port)
 | 
			
		||||
    sender = Sender(host=args.host, port=args.port)
 | 
			
		||||
 | 
			
		||||
# Retrieve contact list
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        contacts = [c for c in sender.dialog_list()]
 | 
			
		||||
        for i, user in enumerate(contacts):
 | 
			
		||||
            if args.peer_id == 'list':
 | 
			
		||||
                print('{:16s} {}'.format(str(user['peer_id']), str(user['print_name'])))
 | 
			
		||||
            elif str(user['peer_id']) == args.peer_id:
 | 
			
		||||
                peer_id = args.peer_id
 | 
			
		||||
                username = str(user['print_name']) 
 | 
			
		||||
        if args.peer_id == 'list':
 | 
			
		||||
            sys.exit(0)
 | 
			
		||||
    except ConnectionError:
 | 
			
		||||
        print('Could not connect to telegram-cli. Start it by issuing "telegram-cli --json -P 4458" in a separate console.', file=sys.stderr)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
    if peer_id is None:
 | 
			
		||||
        print('Could not find peer_id in contact list.', file=sys.stderr)
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
 | 
			
		||||
    print('Connecting to partner: ' + username, file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
# Helper function that can be executed in a thread
 | 
			
		||||
def main_loop_starter():
 | 
			
		||||
    receiver.start()
 | 
			
		||||
    # Start the receive loop
 | 
			
		||||
    receiver.message(main_loop())
 | 
			
		||||
    def main_loop_starter():
 | 
			
		||||
        receiver.start()
 | 
			
		||||
        # Start the receive loop
 | 
			
		||||
        receiver.message(main_loop())
 | 
			
		||||
 | 
			
		||||
    @coroutine
 | 
			
		||||
    def main_loop():
 | 
			
		||||
        global args, received, tun, encrypted;
 | 
			
		||||
        while up:
 | 
			
		||||
            # Receive message from telegram, this includes ALL messages
 | 
			
		||||
            msg = (yield)
 | 
			
		||||
            # Check if it is an actual "message" message and if the sender is our peer
 | 
			
		||||
            if (
 | 
			
		||||
                msg is not None and
 | 
			
		||||
                msg.event == str('message') and
 | 
			
		||||
                not msg.own and
 | 
			
		||||
                str(msg.sender.peer_id) == peer_id
 | 
			
		||||
            ):
 | 
			
		||||
                print('Msg: ' + msg.text, file=sys.stderr)
 | 
			
		||||
                if msg.text[0] == '-' and msg.text[1] == '-':
 | 
			
		||||
                    if args.server:
 | 
			
		||||
                        if msg.text == '--encrypted':
 | 
			
		||||
                            print('Requested encyption for: ' + username, file=sys.stderr)
 | 
			
		||||
                            try:
 | 
			
		||||
                                sender.create_secret_chat(username)
 | 
			
		||||
                            except Exception:
 | 
			
		||||
                                pass
 | 
			
		||||
                            encrypted = True
 | 
			
		||||
                        elif msg.text == '--server':
 | 
			
		||||
                            command_line = '--src={} --dst={} --mask={} --mtu={:d}'.format(args.src, args.dst, args.mask, args.mtu)
 | 
			
		||||
                            print('Requested encyption for: ' + command_line, file=sys.stderr)
 | 
			
		||||
                            print('Sending configuration:' + command_line, file=sys.stderr)
 | 
			
		||||
                            sender.msg(username, str(command_line))
 | 
			
		||||
                    else:
 | 
			
		||||
                        print('Receiving configuration:' + data, file=sys.stderr)
 | 
			
		||||
                        args = parser.parse_args(sys.argv + data.split())
 | 
			
		||||
                        tun.down()
 | 
			
		||||
                        setup_tun()
 | 
			
		||||
                        tun.up()
 | 
			
		||||
                else:
 | 
			
		||||
                    # Decode data and write it to the tunnel
 | 
			
		||||
                    data = base64.b64decode(msg.text)
 | 
			
		||||
                    received += len(data)
 | 
			
		||||
                    tun.write(data)
 | 
			
		||||
                    #print('Packet written', file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
    def setup_tun():
 | 
			
		||||
        if args.server:
 | 
			
		||||
            tun.addr = args.dst
 | 
			
		||||
            tun.dstaddr = args.src 
 | 
			
		||||
        else:
 | 
			
		||||
            tun.addr = args.src + ' '
 | 
			
		||||
            tun.dstaddr = args.dst 
 | 
			
		||||
 | 
			
		||||
        tun.netmask = args.mask
 | 
			
		||||
        tun.mtu = args.mtu
 | 
			
		||||
 | 
			
		||||
        print('\tSrc:  ' + tun.addr, file=sys.stderr)
 | 
			
		||||
        print('\tDst:  ' + tun.dstaddr, file=sys.stderr)
 | 
			
		||||
        print('\tMask: ' + tun.netmask, file=sys.stderr)
 | 
			
		||||
        print('\tMTU:  ' + str(tun.mtu), file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@coroutine
 | 
			
		||||
def main_loop():
 | 
			
		||||
    global up
 | 
			
		||||
    global received
 | 
			
		||||
    while up:
 | 
			
		||||
        # Receive message from telegram, this includes ALL messages
 | 
			
		||||
        msg = (yield)
 | 
			
		||||
        # Check if it is an actual "message" message and if the sender is our peer
 | 
			
		||||
        if (
 | 
			
		||||
            msg is not None and
 | 
			
		||||
            msg['event'] == unicode('message') and
 | 
			
		||||
            not msg['own'] and
 | 
			
		||||
            msg['sender']['peer_id'] == peer_id
 | 
			
		||||
        ):
 | 
			
		||||
            # Decode data and write it to the tunnel
 | 
			
		||||
            data = base64.b64decode(msg.text)
 | 
			
		||||
            received += len(data)
 | 
			
		||||
            tun.write(data)
 | 
			
		||||
# Create TUN device for network capture and injections
 | 
			
		||||
    tun = TunTapDevice(name='teletun')
 | 
			
		||||
 | 
			
		||||
    print('Device ' + tun.name + ' has been created, information follows:', file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
print('TUN is up')
 | 
			
		||||
    if args.server or not args.auto:
 | 
			
		||||
# Set IP address based on --server header
 | 
			
		||||
        setup_tun()
 | 
			
		||||
 | 
			
		||||
# Start TUN device
 | 
			
		||||
    tun.up()
 | 
			
		||||
    up = True
 | 
			
		||||
        
 | 
			
		||||
    print('Device ' + tun.name + ' is up.', file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
    if not args.server and args.encrypted:
 | 
			
		||||
        print('Requesting encyption for: ' + username, file=sys.stderr)
 | 
			
		||||
        sender.msg(username, '--encrypted')
 | 
			
		||||
        time.sleep(3)
 | 
			
		||||
 | 
			
		||||
# Create the receive thread via our helper method
 | 
			
		||||
thread = threading.Thread(target=main_loop_starter)
 | 
			
		||||
    thread = threading.Thread(target=main_loop_starter)
 | 
			
		||||
 | 
			
		||||
# Start the thread for receiving
 | 
			
		||||
print('Connecting to peer...')
 | 
			
		||||
thread.start()
 | 
			
		||||
print('Connected! Sending Invitation!')
 | 
			
		||||
 | 
			
		||||
# Send the invitation message
 | 
			
		||||
sender.msg(username, unicode('Hello, I would like to establish a Layer 3 Tunnel with you! -teletun'))
 | 
			
		||||
 | 
			
		||||
while up:
 | 
			
		||||
    # Continually read from the tunnel and write data to telegram in base64
 | 
			
		||||
    # TODO: Telegram supports unicode, base64 can probably be replaced for something less overhead-inducing
 | 
			
		||||
    buf = tun.read(tun.mtu)
 | 
			
		||||
    data = base64.b64encode(buf)
 | 
			
		||||
    sent += len(data)
 | 
			
		||||
    sender.msg(username, unicode(data))
 | 
			
		||||
    print('Connecting...', file=sys.stderr)
 | 
			
		||||
    thread.start()
 | 
			
		||||
    
 | 
			
		||||
    if not args.server and args.auto:
 | 
			
		||||
        print('Waiting for configuration...', file=sys.stderr)
 | 
			
		||||
        command_line = '--server'
 | 
			
		||||
        sender.msg(username, str(command_line))
 | 
			
		||||
    
 | 
			
		||||
    while up:
 | 
			
		||||
        # Continually read from the tunnel and write data to telegram in base64
 | 
			
		||||
        # TODO: Telegram supports str, base64 can probably be replaced for something less overhead-inducing
 | 
			
		||||
        buf = tun.read(tun.mtu)
 | 
			
		||||
        data = base64.b64encode(buf)
 | 
			
		||||
        data = ''.join(map(chr, data))
 | 
			
		||||
        sent += len(data)
 | 
			
		||||
        if (not args.server and args.encrypted) or encrypted:
 | 
			
		||||
            sender.msg('!_' + username, data)
 | 
			
		||||
        elif not args.encrypted:
 | 
			
		||||
            sender.msg(username, data)
 | 
			
		||||
 | 
			
		||||
# Cleanup and stop application
 | 
			
		||||
up = False
 | 
			
		||||
tun.down()
 | 
			
		||||
receiver.stop()
 | 
			
		||||
    up = False
 | 
			
		||||
    tun.down()
 | 
			
		||||
    receiver.stop()
 | 
			
		||||
 | 
			
		||||
print('Bytes sent via Telegram: ' + str(sent))
 | 
			
		||||
print('Bytes received via Telegram: ' + str(received))
 | 
			
		||||
 | 
			
		||||
print('~~ Bye bye! ~~')
 | 
			
		||||
    print('Bytes sent via Telegram: ' + str(sent), file=sys.stderr)
 | 
			
		||||
    print('Bytes received via Telegram: ' + str(received), file=sys.stderr)
 | 
			
		||||
    print('Done.', file=sys.stderr)
 | 
			
		||||
 | 
			
		||||
# Literally Overkill
 | 
			
		||||
    current_process = psutil.Process()
 | 
			
		||||
    os.kill(current_process.pid, signal.SIGKILL)
 | 
			
		||||
 | 
			
		||||
current_process = psutil.Process()
 | 
			
		||||
os.kill(current_process.pid, signal.SIGKILL)
 | 
			
		||||
if __name__== "__main__":
 | 
			
		||||
# Run main
 | 
			
		||||
    main()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue