PyTun-PMD3 (IPv6-ONLY TUN device)
pytun-pmd3 is a fork of the original python-pytun library, providing support for TUN/TAP network devices on Darwin (macOS), Windows, and Linux. It exclusively supports IPv6, making it suitable for applications like VPNs that specifically require IPv6 tunneling. The library is currently at version 3.0.3 and has a moderate release cadence, focusing on bug fixes and platform compatibility.
Common errors
-
AttributeError: module 'pytun' has no attribute 'TunTapDevice'
cause You likely have the original `pytun` library installed, or pytun-pmd3 is not correctly installed/accessible, leading to the wrong `pytun` module being imported.fixEnsure `pip uninstall pytun` if you only intend to use `pytun-pmd3`. Then `pip install pytun-pmd3`. The import `from pytun import TunTapDevice` will then correctly resolve to the `pytun-pmd3` version. -
PermissionError: [Errno 13] Permission denied
cause Operating system permission restrictions prevent the creation or configuration of the TUN/TAP device.fixRun your Python script with elevated privileges (e.g., `sudo python your_script.py` on Linux/macOS, or 'Run as administrator' on Windows). On Linux, you can also add your user to the 'tun' group: `sudo usermod -a -G tun $(whoami) && sudo reboot`. -
OSError: [Errno 19] No such device (Windows) or similar driver-related errors.
cause On Windows, the Wintun driver might not be installed or accessible, preventing the TUN device from being created.fixVerify that the Wintun driver is correctly installed on your system. Sometimes, a system reboot after installation is required. Ensure the driver files are where `pytun-pmd3` expects them. -
IPv4 traffic is not flowing through the TUN device, or `tun.ifconfig(ipv4='...')` fails.
cause pytun-pmd3 is explicitly designed for IPv6-ONLY operation. It does not support IPv4.fixUse IPv6 addresses for all configurations (`tun.ifconfig(ipv6='...')`) and ensure your application sends and expects IPv6 packets through the device. If IPv4 support is required, you must use the original `pytun` library, not `pytun-pmd3`.
Warnings
- breaking pytun-pmd3 is strictly IPv6-ONLY. If you are migrating from the original `pytun` library, any existing IPv4 configurations or attempts to send/receive IPv4 packets will not work.
- gotcha Creating and configuring TUN/TAP devices typically requires elevated permissions (root/administrator). Running your Python script without these permissions will result in `PermissionError`.
- gotcha On Windows, pytun-pmd3 relies on the Wintun driver. While the library attempts to manage this, you might occasionally need to manually ensure the Wintun driver is installed and accessible for device creation.
- deprecated Prior to v3.0.0, the internal implementation relied on C extensions. Version 3.0.0 refactored the library to use pure Python with `ctypes`. While the public API is largely consistent, if you were relying on any internal C-level details, this change could affect you.
Install
-
pip install pytun-pmd3
Imports
- TunTapDevice
from pytun import TunTapDevice
- IFF_TUN
from pytun import IFF_TUN
- IFF_NO_PI
from pytun import IFF_NO_PI
Quickstart
import os
import sys
import time
from pytun import TunTapDevice, IFF_TUN, IFF_NO_PI
# Note: Requires appropriate permissions (e.g., run as root/administrator
# or user added to 'tun' group on Linux). On Windows, the wintun driver
# might need manual installation first, though pytun-pmd3 attempts to manage it.
try:
# Use a unique name to avoid conflicts, or a fixed one for specific setup
device_name = os.environ.get('PYTUN_DEV_NAME', 'pytun-pmd3-tun0')
tun = TunTapDevice(name=device_name, flags=IFF_TUN | IFF_NO_PI)
print(f"Created TUN device: {tun.name}")
tun.up()
print(f"Device {tun.name} is up.")
# Configure IPv6 address (pytun-pmd3 is IPv6-ONLY)
ipv6_address = os.environ.get('PYTUN_IPV6', 'fcd0::1/64')
tun.ifconfig(ipv6=ipv6_address)
print(f"Configured IPv6 address {ipv6_address} on {tun.name}")
print(f"\nDevice {tun.name} configured. You can now try pinging its address.")
print("Example: ping fcd0::1 (from another host/interface that can route to it)")
print("Waiting for 10 seconds. Press Ctrl+C to stop.")
start_time = time.time()
while time.time() - start_time < 10:
try:
# Read up to 1500 bytes with a 1-second timeout
packet = tun.read(1500, timeout=1)
if packet:
print(f"Received {len(packet)} bytes from TUN device.")
sys.stdout.flush()
except Exception as e:
# Ignore common 'Resource temporarily unavailable' when no packets
pass
time.sleep(0.1)
except PermissionError:
print("Error: Permission denied. Try running as root/administrator or")
print("ensure your user has appropriate permissions (e.g., added to 'tun' group).")
print("On Linux: sudo usermod -a -G tun $(whoami) && sudo reboot")
except FileNotFoundError as e:
print(f"Error: File not found: {e}")
print("On Windows, ensure the wintun driver is correctly installed and accessible.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
if 'tun' in locals():
try:
print(f"Closing TUN device: {tun.name}")
tun.close()
print("Device closed.")
except Exception as e:
print(f"Error closing TUN device: {e}")