How it works

One packet, four handoffs

PLY plugs into the system rather than the application. macOS hands a whole IP packet to the system Packet Tunnel, and the server brings the answer back the same protected way.

  1. 01 · Client

    The application uses the ordinary network

    A browser, a terminal, a call, or a protocol you wrote yourself sees a system interface and treats it as usual. PLY never inspects the contents of TCP and UDP or rewrites their semantics, so there is nothing for an application to trip over.

  2. 02 · Packet Tunnel

    The system hands over raw IP

    A Network System Extension brings up utun and passes whole IP packets to the Rust client over a local bridge. The bridge admits only a process belonging to the same user.

  3. 03 · Transport

    The scheduler spreads packets across links

    Encrypted UDP datagrams travel over the paths the server confirmed by probe. The scheduler decides which path takes a packet and how much redundancy to spend on it. Acknowledgements, FEC, and congestion control keep working while a link degrades.

  4. 04 · Egress

    Linux routes the traffic or applies NAT

    A persistent TUN on the server releases permitted traffic into a routed network, or through a chosen uplink with MASQUERADE. To the outside world the traffic leaves from the server's address rather than the Mac's.

Inside the data path

What happens to a packet along the way

  • MTU and fragmentation

    The client sets an explicit MTU on utun. Anything larger the transport splits itself and rebuilds on the far side, so a link with a small MTU does not take the whole connection down.

  • Encryption

    Every datagram leaves encrypted. Keys live in epochs and rotate as the session runs, one counter issues every nonce in the project, and the receiver drops a replayed datagram against its anti-replay window.

  • Path choice and redundancy

    Importance comes from the packet header alone: the DSCP an application or router already set, and the role of a TCP packet, since losing a bare acknowledgement costs a whole timeout while losing one segment of a bulk transfer costs a single retransmit. Nothing reads the payload. Redundancy is then worked out per message from that importance, the path scores and the time left on the deadline.

  • The return path

    The answer comes back the same way. The server remembers which device holds which address and will not hand someone else's reply to a matching port.

When a path fails

A path counts as live once its exit is verified

Binding a socket to an address proves nothing. The system can still move that traffic onto another interface, leaving two rows in the UI that are really one physical link and multipath that exists only on paper. PLY sends probes and checks which public address they reach the server from. Until that address is confirmed, the path carries no real traffic.

  • ACTIVEExit verified; the path is carrying.
  • PROBINGProbes are running; no real traffic yet.
  • MUTEDSet aside for now, still being checked.
  • DEADWithdrawn. It returns only through a fresh check.