Pure-Python, zero-dependency TCP/IP stack — Ethernet through RFC 9293 TCP — running in user space on a TAP/TUN interface, with a Berkeley-sockets API.
Project description
PyTCP
Pure-Python, zero-dependency TCP/IP stack — Ethernet through RFC 9293 TCP — running in user space on a TAP/TUN interface, with a Berkeley-sockets API.
from pytcp import socket, stack
What it is
A full, RFC-grounded TCP/IP stack implemented entirely in Python: Ethernet II / 802.3 (LLC/SNAP), ARP, IPv4 / IPv6 (with Hop-by-Hop / Destination-Options / Routing / Fragment extension headers), ICMPv4 / ICMPv6 (incl. Neighbor Discovery, MLDv2 with MLDv1 fallback, and IGMP IPv4 multicast group membership), DHCPv4 and DHCPv6 clients, UDP, and a RFC 9293 TCP with a real FSM, congestion control (Reno / NewReno / CUBIC), SACK / timestamps / window-scaling, and a BSD-sockets facade. It runs on a TAP/TUN interface in user space — no kernel module, no privileged data path.
The project's north star is feature-equivalence with the Linux
host network stack: where an RFC is unambiguous PyTCP follows it,
and where it is silent or offers a menu PyTCP picks the Linux
choice. Per-RFC adherence is audited under
docs/rfc/.
The three distributions
PyTCP is strictly layered into three independently-published dists (one invariant: project folder == import name):
| Distribution | Import | Role |
|---|---|---|
PyTCP-net_addr |
net_addr |
Address value types (IPv4/IPv6/MAC, networks, masks, wildcards, interface-addresses). |
PyTCP-net_proto |
net_proto |
Protocol packet parse / assemble / validate. |
PyTCP |
pytcp |
The running stack: subsystems/threads, sockets, FIB, ARP/ND caches, RX/TX rings. |
Installing PyTCP pulls the other two automatically (lockstep
version pin).
Runtime architecture
TAP/TUN fd ─> RxRing ─> PacketHandler (per protocol, RX) ─> Socket queues / ARP+ND caches / fragment store
<─ TxRing <─ PacketHandler (per protocol, TX) <─ Socket send / ND / DHCP / ACD
Subsystembase — every background service (RX/TX rings, neighbor caches, timer, DHCPv4 / DHCPv6 clients, link-local / ACD) extendsSubsystemand runs its own thread with an event-driven loop.- Packet handlers — RX and TX paths are composed from
per-protocol sub-handlers (
packet_handler__<proto>__<rx|tx>.py). Every branch bumps a per-protocol stat counter for observability. - Event-driven timer — a heap-based deadline scheduler (no polling tick); subsystems register deadlines and are woken on the nearest one.
- Per-interface model — a
PacketHandleris an interface. A multi-homed host runs one handler per interface; global tables (routing FIB, socket table, neighbor caches) are shared and lock-guarded.
Free-threaded (no-GIL) safety
Per-interface state is partitioned (single-writer TX ring hand-off);
the shared global tables (RouteTable, SocketTable,
InterfaceTable) guard their compound (check-then-act) operations
with a small threading.Lock and hand readers consistent snapshots.
Single built-in dict/list ops are left lock-free (individually
atomic).
Control-plane APIs (the Phase-3 kernel/userspace boundary)
Consumers talk to the stack only through sanctioned surfaces — never by reaching into runtime internals — mirroring how a Linux process talks to its kernel:
| API | Linux equivalent |
|---|---|
pytcp.socket — BSD socket() factory + methods (TCP / UDP / raw / AF_PACKET) |
socket(2) |
pytcp.stack.sysctl — runtime-tunable policy registry |
/proc/sys/net/ |
pytcp.stack.link — per-interface MAC / MTU / state / counters |
ip link / RTM_*LINK |
pytcp.stack.address — assign / remove IPv4 / IPv6 host addresses |
ip addr / RTM_*ADDR |
pytcp.stack.route — add / remove / list routes (FIB); Route / RouteProtocol / RouteScope |
ip route / RTM_*ROUTE |
pytcp.stack.neighbor — static ARP / ND entries, cache flush |
ip neighbor / RTM_*NEIGH |
| read-only snapshots (route table, neighbor cache, socket list, counters) | /proc/net/*, ss |
Lifecycle
stack.init(...) builds the singletons, stack.add_interface(...) /
stack.remove_interface(...) attach / detach interfaces at runtime
(RTNETLINK RTM_NEWLINK / RTM_DELLINK semantics, including the
address / route / neighbor / session teardown cascade), stack.start()
spawns the subsystem threads, and stack.stop() winds them down.
A stack can init() with zero interfaces and gain them later — the
daemon / multi-homed shape.
Sockets
pytcp.socket mirrors the stdlib socket module: a socket(...)
factory returns TcpSocket / UdpSocket / RawSocket /
PacketSocket, with bind / listen / accept / connect /
send / recv / close, fileno() + eventfd for selectors
integration, blocking & non-blocking modes, errno-mapped OSError,
getaddrinfo, common setsockopt options, IPv4/IPv6 multicast group
membership and source-filter options (IP_ADD_MEMBERSHIP,
IP_ADD_SOURCE_MEMBERSHIP, IPV6_JOIN_GROUP, …), and an
IP_RECVERR / MSG_ERRQUEUE error queue. Stdlib-parity constants
(AF_INET, SOCK_STREAM, IP_*, SO_*, MSG_*) are exposed as
bare module names backed by IntEnums.
Install
pip install PyTCP
Brings in PyTCP-net_proto and PyTCP-net_addr — no other
runtime dependencies (the whole stack is stdlib-only).
Fully typed (ships py.typed, PEP 561); strict-mypy clean.
Running the stack
Running needs a TAP/TUN interface (root for interface / bridge setup):
make tap7 # create the tap7 interface (sudo)
make bridge # set up the bridge (sudo)
make run # run the stack on tap7
make run_multi # multi-interface demo
PyTCP is consumed as a library through the stack lifecycle API and
the pytcp.socket BSD-sockets API. See
examples/ — examples/stack.py is the complete
runnable reference (TAP/TUN open, stack.init(...), multi-interface
bind, runtime interface removal on SIGUSR1).
Requirements
Python 3.14+, Linux (TAP/TUN), POSIX.
Current state (3.0.6)
- ~175 source modules; the pytcp suite runs ~4,000 unit + integration tests (the full repo suite, across all three packages + examples, is ~12,400). Lint clean (codespell + isort + black + flake8 + mypy strict + pylint).
- Host-stack feature-complete (North Star Phase 1). Phase-2
router/forwarding sits behind the
forward_or_deliverseam as a stub. Authoring contracts in.claude/rules/pytcp.md; per-RFC adherence indocs/rfc/.
License
GPL-3.0-or-later. PyTCP by Sebastian Majewski.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytcp-3.0.6.tar.gz.
File metadata
- Download URL: pytcp-3.0.6.tar.gz
- Upload date:
- Size: 505.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea0297f2e87e8d9ee50499d81f11440388385c144f5e97ba6b0e67c76b6b3d51
|
|
| MD5 |
799c269d3d27f71bcb62d5ab2205c8bf
|
|
| BLAKE2b-256 |
e5d3f5cf45974dc0e298d206345f2357955ed65fcaae40d0298f49885629974a
|
Provenance
The following attestation bundles were made for pytcp-3.0.6.tar.gz:
Publisher:
publish.yml on ccie18643/PyTCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytcp-3.0.6.tar.gz -
Subject digest:
ea0297f2e87e8d9ee50499d81f11440388385c144f5e97ba6b0e67c76b6b3d51 - Sigstore transparency entry: 1677691593
- Sigstore integration time:
-
Permalink:
ccie18643/PyTCP@fdfb57f4a868a89818045a9a5641ba0240a7ce60 -
Branch / Tag:
refs/tags/v3.0.6 - Owner: https://github.com/ccie18643
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fdfb57f4a868a89818045a9a5641ba0240a7ce60 -
Trigger Event:
release
-
Statement type:
File details
Details for the file pytcp-3.0.6-py3-none-any.whl.
File metadata
- Download URL: pytcp-3.0.6-py3-none-any.whl
- Upload date:
- Size: 669.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bb9a5e47e5aeb8506b2e535a5a1badcaf7980837002c77e688eb1e2fc87bf44
|
|
| MD5 |
7c301dc7ab2f23cf039fe62a242b3972
|
|
| BLAKE2b-256 |
872dd9e7ea6e99c27071bb1c9771d7ade692df8532920e1144af8fbde4d94a48
|
Provenance
The following attestation bundles were made for pytcp-3.0.6-py3-none-any.whl:
Publisher:
publish.yml on ccie18643/PyTCP
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytcp-3.0.6-py3-none-any.whl -
Subject digest:
1bb9a5e47e5aeb8506b2e535a5a1badcaf7980837002c77e688eb1e2fc87bf44 - Sigstore transparency entry: 1677691628
- Sigstore integration time:
-
Permalink:
ccie18643/PyTCP@fdfb57f4a868a89818045a9a5641ba0240a7ce60 -
Branch / Tag:
refs/tags/v3.0.6 - Owner: https://github.com/ccie18643
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fdfb57f4a868a89818045a9a5641ba0240a7ce60 -
Trigger Event:
release
-
Statement type: