Skip to content

Repository files navigation

Packet Bridge for iOS

Packet Bridge is a SwiftUI app with an NEPacketTunnelProvider extension. It exposes two independent on-device interfaces:

  1. A loopback SOCKS5 server that forwards TCP and UDP traffic to the internet.
  2. A bidirectional UDP bridge that exchanges raw IP packets with another local process.

The project is intentionally dependency-free and can be edited on Linux. Xcode and an Apple Developer signing identity are required only when it is built and installed on iOS.

The target layout and tunnel lifecycle follow the same useful pattern as LocalDevVPN, while the packet relay and SOCKS5 implementation here are new.

Platform limitation: Apple documents hosting a listener/proxy inside a packet-tunnel provider as an unsupported packet-tunnel use case (TN3120). This project is suitable for controlled development or sideloaded experiments, but that part of the design can encounter OS edge cases and is not a safe assumption for App Store approval. A conventional remote VPN transport is the supported production model.

Architecture

local proxy app
  ├─ TCP/UDP SOCKS5 ──> 127.0.0.1:11080 ──> internet
  │                       PacketTunnelProvider sockets
  │
  └─ raw IP socket bound to 127.0.0.1:9090
        ▲                                  │
        │ returned raw IP                  │ captured raw IP
        │ to 127.0.0.1:9091                ▼
        └──────── connected UDP bridge <── packetFlow
                 extension binds :9091

Default ports are configurable in the UI:

Setting Default Meaning
SOCKS5 listen port 11080 TCP and UDP SOCKS5 endpoint on 127.0.0.1
Maximum SOCKS5 TCP clients 1024 Concurrent TCP clients accepted by the SOCKS5 server; configurable from 128 to 65536
Bridge peer port 9090 Port bound by the local proxy/helper
Bridge extension port 9091 Source/listen port bound by the tunnel extension
DNS servers 1.1.1.1, 1.0.0.1 Resolver addresses advertised by the packet tunnel

All listeners are restricted to IPv4 loopback. No LAN-facing proxy is created.

The packet tunnel advertises 1.1.1.1 and 1.0.0.1 as full-tunnel DNS resolvers. Their DNS packets pass through the raw-IP bridge and follow the same V2Ray routing policy as other tunnel traffic.

SOCKS5 behavior

  • SOCKS5 version 5 with the NO AUTHENTICATION REQUIRED method.
  • TCP CONNECT.
  • UDP ASSOCIATE, using UDP on the same numeric port as the TCP listener.
  • IPv4, IPv6, and domain-name destinations.
  • A configurable concurrent TCP client limit, defaulting to 1024. Higher limits consume more packet-tunnel extension memory.
  • The TCP control connection must remain open for the lifetime of a UDP association.
  • UDP FRAG values other than zero are dropped; fragmentation/reassembly is not implemented.
  • BIND and username/password authentication are not implemented.

The relay's outgoing NWConnection objects are created by the packet-tunnel provider. Provider-originated connections use the provider's underlying network path and are not injected back into its own packet flow.

Raw-IP UDP bridge contract

The local peer binds a UDP socket to 127.0.0.1:<bridge-peer-port>. The extension binds 127.0.0.1:<bridge-extension-port> and connects that socket to the peer.

  • Extension to peer: one UDP datagram contains exactly one complete raw IPv4 or IPv6 packet read from NEPacketTunnelFlow.
  • Peer to extension: send one complete raw IPv4 or IPv6 packet per datagram, from the peer's bound socket to the extension port.
  • There is no extra length, protocol, or channel header. The extension identifies IPv4/IPv6 from the high nibble of the first byte.
  • The configured MTU defaults to 1500, so a bridged packet remains well below the UDP datagram size limit.
  • Packets with an invalid IP version are dropped.

The same peer socket should be used for receive and send. Because the extension uses connected UDP, datagrams from unrelated source ports are not accepted.

Routing

Route all traffic installs IPv4 and, optionally, IPv6 default routes into the packet tunnel. The local peer must then process every captured packet and return valid response packets. If the peer is not running, captured network requests will time out.

Turn off Route all traffic while developing the transport if only traffic addressed to the configured tunnel subnet should enter packetFlow.

Build on a headless Mac

Requirements:

  • Xcode 15 or newer.
  • iOS 16 or newer.
  • A physical iPhone or iPad. Packet-tunnel behavior cannot be validated in the simulator.
  • An Apple Developer team whose App ID and provisioning profiles include the Network Extensions / Packet Tunnel Provider capability.

First configure signing:

cp Config/Signing.xcconfig.example Config/Signing.xcconfig

Edit Config/Signing.xcconfig with the team ID and a globally unique app bundle identifier. The extension identifier is automatically derived as <app-id>.PacketTunnel.

An unsigned compile, useful for finding source or project errors, does not need signing:

./scripts/build-unsigned.sh

For sideloading workflows that re-sign an IPA, first embed ad-hoc signatures so the signer can preserve the Network Extension entitlement on both the containing app and extension:

xcodebuild \
  -project PacketBridge.xcodeproj \
  -scheme PacketBridge \
  -configuration Release \
  -sdk iphoneos \
  -destination "generic/platform=iOS" \
  -derivedDataPath build/DerivedDataRelease \
  CODE_SIGNING_ALLOWED=NO \
  clean build
./scripts/package-adhoc.sh Release build/DerivedDataRelease

If the containing app loses com.apple.developer.networking.networkextension during re-signing, the VPN can still appear connected while iOS rejects sendProviderMessage IPC, preventing Runtime status from updating.

For a signed archive:

PACKETBRIDGE_TEAM_ID=ABCDE12345 \
PACKETBRIDGE_BUNDLE_ID=com.yourcompany.PacketBridge \
./scripts/archive.sh

The signing certificate and provisioning access must already be available to the SSH account's keychain. If Xcode must create/update profiles, run:

PACKETBRIDGE_ALLOW_PROVISIONING_UPDATES=1 \
PACKETBRIDGE_TEAM_ID=ABCDE12345 \
PACKETBRIDGE_BUNDLE_ID=com.yourcompany.PacketBridge \
./scripts/archive.sh

The archive is written under build/PacketBridge.xcarchive. No graphical Xcode interaction is needed.

First run

  1. Install and launch the signed app on a physical device.
  2. Set ports and tunnel addresses.
  3. Start the local peer/proxy, with its raw bridge socket bound to the configured peer port.
  4. Tap Save & Connect and approve the iOS VPN configuration prompt.
  5. Point local proxy clients at 127.0.0.1:<SOCKS5 port>.
  6. Check live packet and SOCKS connection counters in the app.

Runtime status is always visible directly below the connection controls. While connected, it refreshes once per second and shows the packet-tunnel extension's current resident memory, open SOCKS connections versus the configured limit, active UDP associations, and packet/byte counters. Before live data is available, it shows disconnected or waiting placeholders instead of disappearing.

The first VPN approval is an iOS security prompt and must be accepted on the device. SSH access to the builder cannot approve that device-side prompt.

Source map

  • PacketBridgeApp/: SwiftUI configuration and status UI, plus NETunnelProviderManager lifecycle.
  • PacketTunnelExtension/PacketTunnelProvider.swift: network settings, service lifecycle, and runtime status IPC.
  • PacketTunnelExtension/SOCKS5Server.swift: TCP and UDP SOCKS5 sessions and internet relays.
  • PacketTunnelExtension/SOCKS5Protocol.swift: SOCKS5 wire parsing and encoding.
  • PacketTunnelExtension/PacketUDPBridge.swift: raw packet transport between packetFlow and connected UDP.
  • Shared/: property-list-safe configuration and status models compiled into both targets.

Security notes

The server intentionally supports no authentication because it is loopback-only. Do not change the listener host to a wildcard address without adding authentication and access control. This is a development networking tool, not an encrypted VPN protocol; the raw UDP bridge provides no confidentiality by itself.

About

iOS PacketBridge to connect Network Extension and V2Ray (Machine Generated)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages