# Croc's IPv6-First Architecture and IPv4 Fallback Mechanism: A Deep Dive into Dual-Stack Networking

> Explore Croc's IPv6-first architecture and dual-stack networking. Learn how it prioritizes IPv6 and falls back to IPv4 for seamless peer connections.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: deep-dive
- Published: 2026-07-26

---

**Croc prioritizes IPv6 connections during peer discovery and automatically retries with IPv4 if IPv6 fails, using a dual-stack approach defined in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) that filters non-routable addresses and verifies connectivity through comprehensive TCP tests.**

The file-sharing tool Croc, developed by schollz/croc, implements a modern **IPv6-first architecture** with automatic IPv4 fallback to ensure maximum compatibility across diverse network environments. This dual-stack networking approach optimizes for contemporary IPv6 infrastructure while maintaining seamless operation on legacy IPv4-only networks. Understanding Croc's IPv6-first architecture and IPv4 fallback mechanism reveals how the tool achieves reliable peer-to-peer connections without manual configuration.

## How IPv6-First Discovery Works

Croc initiates peer discovery using the `peerdiscovery` library configured explicitly for IPv6. In [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), the discovery settings initialize with `settings.IPVersion = peerdiscovery.IPv6` (lines 1082–1090), forcing the discovery process to prioritize IPv6 addresses when locating peers.

This configuration ensures that in environments where both protocols are available, Croc attempts to establish the more modern IPv6 connection first, reducing reliance on NAT traversal techniques required for IPv4.

## Automatic IPv4 Fallback Mechanism

When IPv6 connectivity fails, Croc implements a transparent retry mechanism using IPv4. The `discoverReceivePeers` function in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) (lines 1512–1536) calls `startDiscovery` sequentially—first with IPv6 settings, then immediately with IPv4 parameters if the initial attempt returns no reachable peers.

This fallback happens automatically without user intervention, ensuring that transfers succeed even when one or both endpoints lack IPv6 internet connectivity.

## Filtering Non-Routable IPv6 Addresses

To prevent connection attempts over non-functional networks, Croc filters out problematic IPv6 address ranges. In [`src/utils/utils.go`](https://github.com/schollz/croc/blob/main/src/utils/utils.go) (lines 505–507), helper functions exclude **IPv6 link-local** addresses (`fe80::/10`) and **unique-local** addresses (`fc00::/7`), ensuring only globally routable IPv6 addresses are considered valid for peer discovery.

This filtering prevents the tool from attempting connections over isolated or non-internet-facing network segments that would inevitably fail.

## Verification Through Dual-Stack Testing

The implementation is validated by the `TestDualStackRelayBridgesIPv4AndIPv6` test in [`src/tcp/tcp_test.go`](https://github.com/schollz/croc/blob/main/src/tcp/tcp_test.go) (lines 321–383), which confirms that Croc relays can bridge connections across both address families simultaneously. This test verifies that the IPv6-first architecture does not compromise IPv4 functionality and that the relay infrastructure properly handles mixed-protocol scenarios.

## Practical Usage Examples

Croc's dual-stack behavior requires no manual flags or configuration. The tool automatically negotiates the best available protocol.

Command-line usage:

```bash

# Sender - automatically uses IPv6 if available, falls back to IPv4

croc send myfile.txt

# Receiver - handles both protocols transparently

croc recv

```

Programmatic implementation:

```go
import "github.com/schollz/peerdiscovery"

// Configure IPv6-first discovery
settings := peerdiscovery.Settings{
    IPVersion: peerdiscovery.IPv6,
}
discoveries, err := peerdiscovery.Discover(settings)
// IPv4 fallback occurs automatically if IPv6 discovery fails

```

## Summary

- **IPv6 Priority**: Croc configures `peerdiscovery` with `IPVersion` set to IPv6 in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) to prioritize modern protocol usage.
- **Automatic Fallback**: The `discoverReceivePeers` function implements dual discovery attempts, retrying with IPv4 if IPv6 fails.
- **Address Validation**: [`src/utils/utils.go`](https://github.com/schollz/croc/blob/main/src/utils/utils.go) filters out link-local and unique-local IPv6 ranges to ensure global routability.
- **Tested Reliability**: [`src/tcp/tcp_test.go`](https://github.com/schollz/croc/blob/main/src/tcp/tcp_test.go) validates dual-stack operation through comprehensive bridge testing.

## Frequently Asked Questions

### Does Croc require IPv6 to be enabled on my network?

No. While Croc prefers IPv6 connections for optimal performance, it functions entirely on IPv4-only networks. The IPv4 fallback mechanism activates automatically whenever IPv6 is unavailable or unreachable, ensuring universal compatibility without configuration changes.

### How does Croc decide between IPv4 and IPv6 during a transfer?

Croc always attempts IPv6 first by setting `settings.IPVersion = peerdiscovery.IPv6` during the discovery phase. If the IPv6 handshake fails or returns no valid peers, the code in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) immediately retries the discovery process using IPv4 parameters, selecting the first successful connection regardless of protocol version.

### What IPv6 address types does Croc ignore during discovery?

According to [`src/utils/utils.go`](https://github.com/schollz/croc/blob/main/src/utils/utils.go), Croc explicitly filters out **link-local addresses** (`fe80::/10`) and **unique-local addresses** (`fc00::/7`). These ranges are excluded because they are not globally routable and would result in failed connection attempts between different networks.

### Can I force Croc to use only IPv4 or only IPv6?

The analysis indicates Croc handles protocol selection automatically through its dual-stack implementation. While the `peerdiscovery` library supports explicit version configuration, the standard Croc implementation in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) manages fallback internally to ensure connectivity without requiring user-specified protocol constraints.