Skip to content

Instantly share code, notes, and snippets.

@abdelrahman-t
Last active August 1, 2024 18:33
Show Gist options
  • Select an option

  • Save abdelrahman-t/e39869f39ec6010ddea3cecb03aea648 to your computer and use it in GitHub Desktop.

Select an option

Save abdelrahman-t/e39869f39ec6010ddea3cecb03aea648 to your computer and use it in GitHub Desktop.
TUN tunneling/routing
"""tun_routing.py"""
import logging as LOGGER
import subprocess
from ipaddress import IPv4Address
from itertools import count
from typing import Union
# pip install pypacker
from pypacker.layer3.ip import IP as IPv4Packet
from pypacker.layer3.ip import IP_PROTO_UDP
from pypacker.layer3.ip6 import IP6 as IPv6Packet
from pypacker.layer4.udp import UDP
# Module available at: https://gist.github.com/abdelrahman-t/a23f57986a40f54108a71d4b91f145b2
from tun import TUNInterface
LOGGER.basicConfig(level=LOGGER.DEBUG)
def packet_version(packet: bytes) -> int:
# Credit: https://github.com/povilasb/iptun/blob/master/iptun/ip.py#L26
return packet[0] >> 4
def parse_packet(data: bytes) -> Union[IPv4Packet, IPv6Packet]:
# Credit: https://github.com/povilasb/iptun/blob/master/iptun/ip.py#L30
packet_ver = packet_version(data)
if packet_ver == 4:
packet = IPv4Packet(data)
elif packet_ver == 6:
packet = IPv6Packet(data)
else:
raise ValueError(f'Unsupported IP packet version: {packet_ver}')
return packet
def test() -> None:
# Enable IPv4 routing.
subprocess.call(['/sbin/sysctl', '-w', 'net.ipv4.ip_forward=1'])
interface = TUNInterface('custom-tunnel', address=IPv4Address('10.1.0.0'))
interface.up()
counter = count()
while 1:
packet = parse_packet(interface.read(4096)
)
LOGGER.warning('[%-5s] %-25s -> %-25s',
packet.highest_layer.__class__.__name__,
packet.src_s, packet.dst_s)
if packet[UDP]:
# A UDP packet was received, Let's send a reply.
# Packets written to the TUN interface should have the TUN interface as the destination address
# and not originating interface (e.g. eth0).
# The Linux kernel will automatically detect that a packet is a response to a previously sent packet and
# automatically route it to the originating interface (e.g. eth0).
echo = IPv4Packet(src_s=packet.dst_s, dst_s=str(interface.address), p=IP_PROTO_UDP) +\
UDP(sport=packet[UDP].dport, dport=packet[UDP].sport)
echo[UDP].body_bytes = f'Reply: {next(counter)}! '.encode('UTF-8')
interface.write(echo.bin())
if __name__ == '__main__':
test()
Copy link

ghost commented Mar 29, 2022

will this work in android?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment