Skip to content

Latest commit

 

History

50 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-p2p-netcat

English | Русский

CI PWA Release Go Reference Go Report Card Container License

Quick install

Install the latest tagged version:

curl -fsSL \
  https://raw.githubusercontent.com/santaklouse/go-p2p-netcat/main/deploy/deploy.sh |
  bash

The deploy script detects Linux, macOS, or Android and the processor architecture, downloads the matching release, verifies it against the keyless Sigstore signature on SHA256SUMS, verifies the archive checksum, and installs p2p-nc, pnc, and p2p-netcat. Cosign v3 is required. See installation for version pinning, a custom destination, and uninstalling.

Install through Homebrew on macOS or Linux:

brew install santaklouse/tap/p2p-netcat

Debian and Ubuntu users can add the signed APT repository and then use sudo apt install p2p-netcat. See package-manager installation for the repository command and signing-key fingerprint.

The Linux amd64/arm64 container is published to GitHub Packages:

docker pull ghcr.io/santaklouse/go-p2p-netcat:latest
docker run --rm ghcr.io/santaklouse/go-p2p-netcat:latest --version

The container runs as a non-root user and stores its persistent identity under /config. See Docker and GitHub Packages for listener, UDP, networking, version-tag, and local-build examples.

Alternatively, install with Go:

GOTOOLCHAIN=auto CGO_ENABLED=0 go install -ldflags="-s -w" \
  github.com/santaklouse/go-p2p-netcat/cmd/p2p-nc@latest
GOTOOLCHAIN=auto CGO_ENABLED=0 go install -ldflags="-s -w" \
  github.com/santaklouse/go-p2p-netcat/cmd/pnc@latest

CGO_ENABLED=0 is intentional: the project does not require CGO, and this avoids macOS DWARF linking failures when Homebrew LLVM takes precedence over Apple's toolchain. If CGO is explicitly required, select Apple Clang:

GOTOOLCHAIN=auto CGO_ENABLED=1 CC=/usr/bin/clang CXX=/usr/bin/clang++ \
  go install github.com/santaklouse/go-p2p-netcat/cmd/p2p-nc@latest

On macOS and Linux, install it and immediately create the p2p-netcat command as a symbolic link next to p2p-nc:

set -e

GOTOOLCHAIN=auto CGO_ENABLED=0 go install -ldflags="-s -w" \
  github.com/santaklouse/go-p2p-netcat/cmd/p2p-nc@latest
GOTOOLCHAIN=auto CGO_ENABLED=0 go install -ldflags="-s -w" \
  github.com/santaklouse/go-p2p-netcat/cmd/pnc@latest
P2PNC_BIN_DIR="$(go env GOBIN)"
if [ -z "$P2PNC_BIN_DIR" ]; then
  P2PNC_BIN_DIR="$(go env GOPATH)/bin"
fi
ln -sf "$P2PNC_BIN_DIR/p2p-nc" "$P2PNC_BIN_DIR/p2p-netcat"
export PATH="$P2PNC_BIN_DIR:$PATH"
p2p-netcat --version

A Go implementation of p2p-netcat: a bidirectional netcat-like stream addressed by a libp2p PeerId instead of an IP address. The existing /p2p-netcat/1.0.0/<logical-port> stream protocol, identity files, pairing tokens, admission handshake, and PTY frames are compatible with the original JavaScript implementation. Go peers additionally support framed UDP forwarding through /p2p-netcat/udp/1.0.0/<logical-port>.

Porting status

Implemented:

  • persistent Ed25519 identities in the compatible protobuf format;
  • TCP, QUIC v1, WebSocket, and standard libp2p WebRTC Direct;
  • Noise/TLS, Yamux, and Circuit Relay v2;
  • mDNS, GossipSub peer discovery, and the IPFS Amino DHT, including provider records;
  • private rotating DHT rendezvous identifiers derived from pnc1_ tokens;
  • a mutual admission handshake before application bytes are exposed;
  • canonical CBOR, HKDF-SHA-256, AES-256-GCM, and signed RouteRecords;
  • native WebRTC v2 with Nostr/WebTorrent signaling, channel-bound PeerId authentication over exact SDP hashes, pairing-token encryption, flow control, 120-second stream resumption, and libp2p route racing;
  • raw stdin/stdout, -e, TCP and packet-preserving UDP forwarding, SOCKS4/4a/5, and PTY sessions, including Windows ConPTY;
  • -l, -k, -w, -d, -p, -u, -q, -S, -T, -i, -z, -e, -4, -6, relay, id, and token commands;
  • the p2p-nc and short pnc command names;
  • the browser-safe core and static English/Russian PWA in packages/core and web.

The migration from the JavaScript repository is complete. The Go CLI keeps the same application protocols and can interoperate with the old CLI and browser client. Browser code remains TypeScript because it runs directly in browser Web APIs; it is now versioned and deployed from this repository.

The native WebRTC stability matrix was ported from Node.js to a real-Pion Go runner. Run the smoke profile locally with:

go run ./cmd/webrtc-soak \
  --profile smoke \
  --report artifacts/webrtc-soak-local.json

Profiles, scenarios, JSON output, and limitations are documented in the native WebRTC migration record.

Installation

The current stable version is v0.7.0. Release archives contain the p2p-nc and pnc executables, the MIT license, and both README files. Verify the downloaded archive against SHA256SUMS before installing it. Starting with v0.7.0, verify the Sigstore bundle for SHA256SUMS before trusting any checksum.

Linux releases also provide optional p2p-nc-linux-amd64-upx.tar.gz and p2p-nc-linux-arm64-upx.tar.gz archives alongside the original, unpacked archives. These variants use standard UPX packing and remain testable and unpackable with UPX. The deploy script deliberately installs the original archive unless an operator selects an UPX archive manually.

Linux

The following command selects amd64 or arm64, verifies the archive, and installs the executable into /usr/local/bin:

set -euo pipefail

P2PNC_VERSION="v0.7.0"
case "$(uname -m)" in
  x86_64|amd64) P2PNC_ARCH="amd64" ;;
  aarch64|arm64) P2PNC_ARCH="arm64" ;;
  *) echo "Unsupported Linux architecture: $(uname -m)" >&2; exit 1 ;;
esac

P2PNC_ARCHIVE="p2p-nc-linux-${P2PNC_ARCH}.tar.gz"
P2PNC_RELEASE_URL="https://github.com/santaklouse/go-p2p-netcat/releases/download/${P2PNC_VERSION}"

curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/${P2PNC_ARCHIVE}"
curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/SHA256SUMS"
curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/SHA256SUMS.sigstore.json"
cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.sigstore.json \
  --certificate-identity "https://github.com/santaklouse/go-p2p-netcat/.github/workflows/release-main.yml@refs/tags/${P2PNC_VERSION}" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
grep "  ${P2PNC_ARCHIVE}$" SHA256SUMS | sha256sum --check -
tar -xzf "$P2PNC_ARCHIVE"
sudo install -m 0755 "p2p-nc-linux-${P2PNC_ARCH}/p2p-nc" /usr/local/bin/p2p-nc
p2p-nc --version

macOS

The macOS archives support Intel and Apple Silicon. This command detects the processor architecture automatically:

set -euo pipefail

P2PNC_VERSION="v0.7.0"
case "$(uname -m)" in
  x86_64|amd64) P2PNC_ARCH="amd64" ;;
  arm64|aarch64) P2PNC_ARCH="arm64" ;;
  *) echo "Unsupported macOS architecture: $(uname -m)" >&2; exit 1 ;;
esac

P2PNC_ARCHIVE="p2p-nc-darwin-${P2PNC_ARCH}.tar.gz"
P2PNC_RELEASE_URL="https://github.com/santaklouse/go-p2p-netcat/releases/download/${P2PNC_VERSION}"

curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/${P2PNC_ARCHIVE}"
curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/SHA256SUMS"
curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/SHA256SUMS.sigstore.json"
cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.sigstore.json \
  --certificate-identity "https://github.com/santaklouse/go-p2p-netcat/.github/workflows/release-main.yml@refs/tags/${P2PNC_VERSION}" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
grep "  ${P2PNC_ARCHIVE}$" SHA256SUMS | shasum -a 256 --check
tar -xzf "$P2PNC_ARCHIVE"
sudo mkdir -p /usr/local/bin
sudo install -m 0755 "p2p-nc-darwin-${P2PNC_ARCH}/p2p-nc" /usr/local/bin/p2p-nc
p2p-nc --version

The release binary is not Apple-notarized. If Gatekeeper quarantines it after a browser download, inspect the file first and then remove only its quarantine attribute:

sudo xattr -d com.apple.quarantine /usr/local/bin/p2p-nc

Windows

Open PowerShell and run:

$ErrorActionPreference = 'Stop'
$Version = 'v0.7.0'
$Architecture = switch ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()) {
    'X64' { 'amd64' }
    'Arm64' { 'arm64' }
    default { throw "Unsupported Windows architecture: $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)" }
}
$Archive = "p2p-nc-windows-$Architecture.zip"
$ReleaseUrl = "https://github.com/santaklouse/go-p2p-netcat/releases/download/$Version"

Invoke-WebRequest "$ReleaseUrl/$Archive" -OutFile $Archive
Invoke-WebRequest "$ReleaseUrl/SHA256SUMS" -OutFile 'SHA256SUMS'
Invoke-WebRequest "$ReleaseUrl/SHA256SUMS.sigstore.json" -OutFile 'SHA256SUMS.sigstore.json'
cosign verify-blob SHA256SUMS `
    --bundle SHA256SUMS.sigstore.json `
    --certificate-identity "https://github.com/santaklouse/go-p2p-netcat/.github/workflows/release-main.yml@refs/tags/$Version" `
    --certificate-oidc-issuer https://token.actions.githubusercontent.com
if ($LASTEXITCODE -ne 0) { throw 'Sigstore verification failed for SHA256SUMS' }
$ChecksumLine = Get-Content 'SHA256SUMS' | Where-Object { $_ -match ([regex]::Escape($Archive) + '$') }
if (-not $ChecksumLine) { throw "Checksum for $Archive was not found" }
$ExpectedHash = ($ChecksumLine -split '\s+')[0].ToLowerInvariant()
$ActualHash = (Get-FileHash $Archive -Algorithm SHA256).Hash.ToLowerInvariant()
if ($ActualHash -ne $ExpectedHash) { throw "SHA-256 verification failed for $Archive" }

Expand-Archive $Archive -DestinationPath . -Force
$InstallDir = Join-Path $env:LOCALAPPDATA 'Programs\p2p-netcat'
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
Copy-Item "p2p-nc-windows-$Architecture\p2p-nc.exe" "$InstallDir\p2p-nc.exe" -Force

$CurrentPath = [Environment]::GetEnvironmentVariable('Path', 'User')
if (($CurrentPath -split ';') -notcontains $InstallDir) {
    $NewPath = if ([string]::IsNullOrWhiteSpace($CurrentPath)) { $InstallDir } else { "$CurrentPath;$InstallDir" }
    [Environment]::SetEnvironmentVariable('Path', $NewPath, 'User')
}
& "$InstallDir\p2p-nc.exe" --version

The updated user PATH is available in newly opened terminals. Windows SmartScreen can warn because the release executable is not code-signed.

Android phones

Android builds are standalone shell executables, not APK files. They require Android 7.0 or newer and do not require root when launched through adb shell. Enable USB debugging, connect the phone, install Android Platform Tools, and run:

set -euo pipefail

P2PNC_VERSION="v0.7.0"
P2PNC_ANDROID_ABI="$(adb shell getprop ro.product.cpu.abi | tr -d '\r')"
case "$P2PNC_ANDROID_ABI" in
  arm64-v8a) P2PNC_ANDROID_ARCH="arm64" ;;
  armeabi-v7a|armeabi) P2PNC_ANDROID_ARCH="armv7" ;;
  *) echo "Unsupported Android ABI: $P2PNC_ANDROID_ABI" >&2; exit 1 ;;
esac

P2PNC_ARCHIVE="p2p-nc-android-${P2PNC_ANDROID_ARCH}.tar.gz"
P2PNC_RELEASE_URL="https://github.com/santaklouse/go-p2p-netcat/releases/download/${P2PNC_VERSION}"

curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/${P2PNC_ARCHIVE}"
curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/SHA256SUMS"
curl --fail --location --remote-name "${P2PNC_RELEASE_URL}/SHA256SUMS.sigstore.json"
cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.sigstore.json \
  --certificate-identity "https://github.com/santaklouse/go-p2p-netcat/.github/workflows/release-main.yml@refs/tags/${P2PNC_VERSION}" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
if command -v sha256sum >/dev/null 2>&1; then
  grep "  ${P2PNC_ARCHIVE}$" SHA256SUMS | sha256sum --check -
else
  grep "  ${P2PNC_ARCHIVE}$" SHA256SUMS | shasum -a 256 --check
fi
tar -xzf "$P2PNC_ARCHIVE"
adb push "p2p-nc-android-${P2PNC_ANDROID_ARCH}/p2p-nc" /data/local/tmp/p2p-nc
adb shell chmod 755 /data/local/tmp/p2p-nc
adb shell /data/local/tmp/p2p-nc --version

Run the command with an explicit writable identity path when persistent identity is required:

adb shell /data/local/tmp/p2p-nc id --identity /data/local/tmp/p2p-nc-identity.key

Android releases use /data/local/tmp/p2p-netcat/listeners for listener lock files. The explicit environment override below also makes releases that predate the Android default work correctly:

adb shell 'P2P_NETCAT_LISTENER_LOCK_DIR=/data/local/tmp/p2p-netcat/listeners /data/local/tmp/p2p-nc -lik --allow-unauthenticated-listener --identity /data/local/tmp/p2p-nc-identity.key 31337'

This Android command intentionally demonstrates the explicit public-access override. Use a pairing token for any real PTY listener.

Install with Go

With a recent Go installation and automatic toolchain downloads enabled:

GOTOOLCHAIN=auto CGO_ENABLED=0 go install -ldflags="-s -w" \
  github.com/santaklouse/go-p2p-netcat/cmd/p2p-nc@v0.7.0
GOTOOLCHAIN=auto CGO_ENABLED=0 go install -ldflags="-s -w" \
  github.com/santaklouse/go-p2p-netcat/cmd/pnc@v0.7.0
"$(go env GOPATH)/bin/p2p-nc" --version

Build from source

The module pins Go 1.25.7 in go.mod. A recent Go installation with GOTOOLCHAIN=auto downloads the required toolchain automatically.

cd /Users/alexnevpryaga/projects/santaklouse/go-p2p-netcat
GOTOOLCHAIN=auto /opt/homebrew/bin/go build -o p2p-nc ./cmd/p2p-nc
GOTOOLCHAIN=auto /opt/homebrew/bin/go build -o pnc ./cmd/pnc
./p2p-nc --version

Install the command into GOBIN:

GOTOOLCHAIN=auto /opt/homebrew/bin/go install ./cmd/p2p-nc
GOTOOLCHAIN=auto /opt/homebrew/bin/go install ./cmd/pnc

On this development machine, /usr/local/bin/go is an obsolete Intel build of Go 1.13. Use /opt/homebrew/bin/go or correct PATH:

export PATH="/opt/homebrew/bin:$PATH"
go version

Quick start

Start a listener:

./p2p-nc -l 8080

Only one local listener can own a logical port at a time. This applies across raw, PTY, exec, SOCKS, TCP-forwarding, and UDP-forwarding modes. A second listener exits with status 1 and reports:

[p2p-nc] error: logical port 8080 already has an active listener

The command prints its PeerId and available multiaddrs to stderr. Connect from the client:

./p2p-nc 12D3KooWJ7satLo5LXjhSZBMVTWRG1AZ77sQYtX81qHHf2VtscdL 8080

Use the actual PeerId printed by the listener. The following complete example performs a local check without DHT discovery:

DEMO_DIR="$(mktemp -d)"
DEMO_KEY="$DEMO_DIR/listener.key"
DEMO_ID="$(./p2p-nc id --identity "$DEMO_KEY")"
./p2p-nc -l 8080 \
  --transport-port 43127 \
  --no-dht \
  --no-mdns \
  --no-quic \
  --no-webrtc \
  --identity "$DEMO_KEY" \
  >"$DEMO_DIR/received.txt" &
DEMO_PID=$!
sleep 2
printf 'hello over go-libp2p\n' | ./p2p-nc \
  --no-dht \
  --no-mdns \
  --no-quic \
  --no-webrtc \
  "/ip4/127.0.0.1/tcp/43127/p2p/$DEMO_ID" \
  8080
wait "$DEMO_PID"
cat "$DEMO_DIR/received.txt"

Security defaults

Raw stream listeners remain public for netcat-style use. Listener -i, -e, -S, TCP forwarding, and UDP forwarding require a pairing token. The explicit --allow-unauthenticated-listener override is intended only for a deliberately public service and prints a warning. Custom Nostr/WebTorrent Native WebRTC is enabled only with a pairing token; the separate --allow-unauthenticated-native-webrtc escape hatch is unsafe. Standard libp2p WebRTC Direct remains available without a token because Noise binds it to the expected PeerId.

Private pairing

Create a token from the listener's persistent identity:

./p2p-nc token 31337 \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  >"$HOME/.config/p2p-netcat/pairing.token"
chmod 600 "$HOME/.config/p2p-netcat/pairing.token"

Start the listener:

./p2p-nc -l -i \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  --pairing-token-file "$HOME/.config/p2p-netcat/pairing.token"

After securely transferring the token file, start the client:

./p2p-nc -i \
  --pairing-token-file "$HOME/.config/p2p-netcat/pairing.token"

The token contains the PeerId and logical port, so private mode does not require separate positional arguments. Keep the token file private and set its permissions to 0600.

For password-protected storage or transfer, create an encrypted token file:

./p2p-nc token 31337 \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  --encrypt-to "$HOME/.config/p2p-netcat/pairing.token.enc"

The command prompts for the password twice without echoing it. After receiving the encrypted file, unlock it once on each machine:

./p2p-nc token unlock \
  "$HOME/.config/p2p-netcat/pairing.token.enc" \
  --output "$HOME/.config/p2p-netcat/pairing.token"

Unlocking prompts for the password once and creates a new bearer-token file with mode 0600 on Unix or a protected DACL for the current user, LocalSystem, and built-in Administrators on Windows. Subsequent listener and client commands use --pairing-token-file without a password. Neither command overwrites an existing output file. Existing Windows secrets are read only when their DACL grants sensitive access to the owner, current user, LocalSystem, or built-in Administrators.

Forwarding, SOCKS, and PTY

Create service-scoped tokens for the examples below:

install -d -m 0700 "$HOME/.config/p2p-netcat"
./p2p-nc token --identity "$HOME/.config/p2p-netcat/identity.key" 15432 >"$HOME/.config/p2p-netcat/postgres.token"
./p2p-nc token --identity "$HOME/.config/p2p-netcat/identity.key" 35182 >"$HOME/.config/p2p-netcat/wireguard.token"
./p2p-nc token --identity "$HOME/.config/p2p-netcat/identity.key" 1080 >"$HOME/.config/p2p-netcat/socks.token"
./p2p-nc token --identity "$HOME/.config/p2p-netcat/identity.key" 2222 >"$HOME/.config/p2p-netcat/shell.token"
chmod 0600 "$HOME/.config/p2p-netcat/"*.token

Forward a local TCP port to 127.0.0.1:5432 on the remote peer:

./p2p-nc -l -p 5432 \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  --pairing-token-file "$HOME/.config/p2p-netcat/postgres.token"
./p2p-nc -p 15432 \
  --pairing-token-file "$HOME/.config/p2p-netcat/postgres.token"

Forward a local UDP endpoint to WireGuard on the remote peer:

# WireGuard host
./p2p-nc -u -l -d 127.0.0.1 -p 51820 \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  --pairing-token-file "$HOME/.config/p2p-netcat/wireguard.token"

# WireGuard client host
sudo ./deploy/wireguard-full-tunnel.sh -- \
  /usr/local/bin/p2p-nc -u --udp-idle-timeout 0 -p 15182 \
  --pairing-token-file "$HOME/.config/p2p-netcat/wireguard.token"

Set the WireGuard peer endpoint on the client to 127.0.0.1:15182. p2p-nc keeps UDP packet boundaries while carrying the packets through the selected reliable stream. Native WebRTC uses public Nostr/WebTorrent signaling and ICE/STUN to cross compatible NATs without a user-operated relay. Standard libp2p TCP, QUIC, WebRTC Direct, WSS, and Circuit Relay routes remain available. For AllowedIPs = 0.0.0.0/0, the Linux wrapper is required so signaling and carrier sockets keep using the physical main route instead of recursively entering WireGuard. The complete gateway, NAT, and verification configuration is in the WireGuard cookbook.

Run a SOCKS server on the remote peer:

./p2p-nc -l -S \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  --pairing-token-file "$HOME/.config/p2p-netcat/socks.token"
./p2p-nc -p 1080 \
  --pairing-token-file "$HOME/.config/p2p-netcat/socks.token"
curl --socks5-hostname 127.0.0.1:1080 https://example.com/

Start an interactive login shell:

./p2p-nc -l -i \
  --identity "$HOME/.config/p2p-netcat/identity.key" \
  --pairing-token-file "$HOME/.config/p2p-netcat/shell.token"
./p2p-nc -i \
  --pairing-token-file "$HOME/.config/p2p-netcat/shell.token"

In the PTY client, press Ctrl-E followed by q to close the session.

Running a relay

Run a local Circuit Relay v2 instance:

./p2p-nc relay -4 -p 9090 --websocket-port 9091

On a public VPS, add the server's actual public multiaddrs with --announce. TCP and UDP port 9090 must be reachable from the internet. Open TCP port 9091 as well when WebSocket access is required.

Verification

GOTOOLCHAIN=auto /opt/homebrew/bin/go fmt ./...
GOTOOLCHAIN=auto /opt/homebrew/bin/go vet ./...
GOTOOLCHAIN=auto /opt/homebrew/bin/go test ./...

The test suite includes the published JavaScript interoperability vectors for tokens, all four HKDF keys, rendezvous IDs, provider CIDs, AES-GCM envelopes, and both admission frames.

Automated releases

Every push to main, including merged pull requests, and every semantic v*.*.* tag runs .github/workflows/release-main.yml. After tests and static analysis pass, the workflow publishes a GitHub Release with these builds:

Before creating a release tag, run the WebRTC ci profile:

go run ./cmd/webrtc-soak --profile ci \
  --report artifacts/webrtc-soak-release.json

The separate .github/workflows/webrtc-soak.yml workflow runs the longer soak profile every Monday on Ubuntu and macOS and supports manual profile selection.

  • Linux: amd64, arm64, with original and optional -upx archives;
  • Debian packages: amd64, arm64;
  • macOS: amd64, arm64;
  • Windows: amd64, arm64;
  • Android 7.0 (API 24) and newer: arm64, armv7.

Linux and macOS builds are distributed as .tar.gz archives. Windows builds are distributed as .zip archives, and Android builds as .tar.gz archives. Only the Linux amd64 and arm64 release binaries receive separate, explicitly named UPX variants; macOS binaries are never UPX-packed. Every release also contains SHA256SUMS and keyless Sigstore bundles for every artifact. New stable releases additionally contain p2p-netcat.rb for the Homebrew tap. The deploy script authenticates the signed checksum manifest before checking an archive. Semantic tags such as v0.7.0 produce stable releases. Builds from main are marked as prereleases and use a deterministic tag that starts with main- and ends with the first 12 characters of the commit SHA. Rerunning a workflow updates the same release instead of creating a duplicate.

The Android artifacts are command-line executables for Android's shell, not APK files. Use android-arm64 for almost all current physical phones and tablets. android-armv7 supports older 32-bit ARM devices. For example:

tar -xzf p2p-nc-android-arm64.tar.gz
adb push p2p-nc-android-arm64/p2p-nc /data/local/tmp/p2p-nc
adb shell chmod 755 /data/local/tmp/p2p-nc
adb shell /data/local/tmp/p2p-nc --version

Documentation

Project structure

cmd/p2p-nc/             CLI entry point
internal/cli/           parsing, validation, and lifecycle
internal/identity/      compatible persistent Ed25519 keys
p2p/                    host, transports, DHT, mDNS, and relay
protocol/pairing/       token, HKDF, rendezvous, and AEAD
protocol/admission/     mutual fixed-frame handshake
protocol/routerecord/   deterministic CBOR and identity signatures
protocol/pty/           binary PTY frames
session/                raw, exec, forwarding, SOCKS, and PTY

License

MIT.

Releases

Sponsor this project

Packages

Used by

Contributors

Languages