1
0
Fork 0
mirror of https://github.com/PiMaker/Teletun.git synced 2025-02-12 18:01:52 +00:00
Teletun/teletun.py

205 lines
7 KiB
Python
Raw Normal View History

2020-01-31 01:46:54 +00:00
#!/usr/bin/env python3
2017-01-10 17:07:59 +00:00
2017-01-11 08:42:55 +00:00
# (C) Stefan Reiter 2017
2020-01-31 01:46:54 +00:00
# (C) Radomír Polách 2020
2017-01-11 08:42:55 +00:00
2017-01-10 17:07:59 +00:00
from pytun import TunTapDevice
2020-01-31 01:46:54 +00:00
from pytg import Telegram
2017-01-10 17:07:59 +00:00
from pytg.sender import Sender
from pytg.receiver import Receiver
from pytg.utils import coroutine
2017-01-11 08:42:55 +00:00
from pytg.exceptions import ConnectionError
2017-01-10 17:07:59 +00:00
import base64
import threading
import sys
2017-01-11 10:17:41 +00:00
import psutil
import os
import signal
2020-01-31 01:46:54 +00:00
import logging
import argparse
import time
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
# Init stats
sent = 0
received = 0
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
# 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
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
# 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)
2017-01-10 17:07:59 +00:00
2017-01-11 08:42:55 +00:00
# Retrieve contact list
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
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)
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
# Helper function that can be executed in a thread
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)
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
# Create TUN device for network capture and injections
tun = TunTapDevice(name='teletun')
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
print('Device ' + tun.name + ' has been created, information follows:', file=sys.stderr)
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
if args.server or not args.auto:
# Set IP address based on --server header
setup_tun()
2017-01-11 08:42:55 +00:00
# Start TUN device
2020-01-31 01:46:54 +00:00
tun.up()
up = True
print('Device ' + tun.name + ' is up.', file=sys.stderr)
2017-01-10 17:07:59 +00:00
2020-01-31 01:46:54 +00:00
if not args.server and args.encrypted:
print('Requesting encyption for: ' + username, file=sys.stderr)
sender.msg(username, '--encrypted')
time.sleep(3)
2017-01-10 17:07:59 +00:00
# Create the receive thread via our helper method
2020-01-31 01:46:54 +00:00
thread = threading.Thread(target=main_loop_starter)
2017-01-10 17:07:59 +00:00
# Start the thread for receiving
2020-01-31 01:46:54 +00:00
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)
2017-01-10 17:07:59 +00:00
2017-01-11 08:42:55 +00:00
# Cleanup and stop application
2020-01-31 01:46:54 +00:00
up = False
tun.down()
receiver.stop()
2017-01-11 10:49:21 +00:00
2020-01-31 01:46:54 +00:00
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)
2017-01-11 10:17:41 +00:00
# Literally Overkill
2020-01-31 01:46:54 +00:00
current_process = psutil.Process()
os.kill(current_process.pid, signal.SIGKILL)
2017-01-11 10:17:41 +00:00
2020-01-31 01:46:54 +00:00
if __name__== "__main__":
# Run main
main()