Back to Blog

Introducing Snell v6: Deployment-Level Protocol Diversity

Snell v6 moves from a single protocol-level traffic pattern to PSK-derived deployment-level diversity.

In the latest Surge Beta, we have begun testing Snell v6.

Before discussing what has changed in Snell v6, we would like to briefly look back at the history of Snell and the design problems it was originally created to solve.

A Brief History of Snell

Snell v1 was designed to address several practical limitations we observed in existing proxy protocols at the time.

First, most mainstream proxy protocols did not include a structured error reporting mechanism. This made it difficult for Surge to make informed decisions based on the actual failure reason.

For example, an authentication failure usually indicates a serious problem with the proxy policy itself, and Surge should avoid selecting that proxy again. By contrast, a timeout when connecting to a remote host is more likely related to the destination server and should not necessarily affect the proxy’s health evaluation.

This distinction is especially important for Surge’s Smart policy groups, where accurate failure classification directly affects proxy selection and failover behavior.

Second, proxy server deployment was often more complicated than necessary. Snell was designed as a single binary with minimal dependencies, making installation and deployment straightforward.

Third, performance was a primary design goal from the beginning. Snell was built with latency and throughput as first-class priorities, and its performance has consistently remained close to the practical limits of what a proxy protocol can achieve.

Snell v2 later introduced connection multiplexing. Compared with many other proxy protocols, Snell is one of the few that supports both connection multiplexing and a complete TCP state machine. This matters because some websites and network applications rely on TCP half-close behavior to work correctly. Protocols that do not preserve the full TCP state machine may encounter compatibility issues in such cases.

Snell v3 added UDP forwarding support.

Snell v5 introduced QUIC Proxy Mode, which forwarded QUIC traffic over UDP. However, QUIC is inherently difficult to proxy effectively due to its transport design, congestion control behavior, and tight coupling between encryption and transport semantics. In practice, the results did not meet our expectations.

For most proxy scenarios, the better strategy for QUIC traffic remains to block QUIC and allow applications to fall back to HTTP/2 over TCP. For this reason, Snell v6 no longer supports QUIC Proxy Mode.

Snell v4 addressed a different kind of problem. Since Snell is a purely encrypted proxy protocol, its encrypted traffic naturally appears as a high-entropy random data stream. While that may seem featureless at first glance, complete randomness can itself become a recognizable feature and may be subject to detection or interference.

To reduce this risk, Snell v4 introduced controlled random perturbations into the otherwise purely random AES-encrypted data stream, making the traffic no longer appear perfectly random. Over the past four years, this technique has worked well in practice.

We have always understood that this approach had limitations. It was not intended to be a permanent answer to protocol classification. If the perturbation pattern itself were specifically studied and targeted, it could still become a recognizable characteristic.

At the time of Snell v4’s release, we deliberately did not publish the full protocol details. The community largely respected that decision for a long time, and we sincerely appreciate it.

However, as Snell v4 has become more widely studied and implemented outside the original distribution, its traffic characteristics should no longer be considered private. This is why we started the development of Snell v6.

Snell v6

For encrypted proxy protocols, there are broadly two approaches to reducing protocol identifiability.

The first approach is to minimize protocol-specific structure and expose as little recognizable metadata as possible. Traditional encrypted proxy protocols generally fall into this category.

As mentioned above, a purely encrypted protocol produces a high-entropy random data stream. Ironically, the absence of obvious structure can become a structure of its own. This characteristic is already known to be detectable, which is why the design space around encrypted proxy protocols has continued to evolve.

The second approach is to make the protocol closely resemble a common protocol, such as TLS. Many newer proxy protocols have explored this direction, and there are already several excellent projects in this area.

Snell v6 takes a different path.

It does not attempt to impersonate TLS or any other existing protocol. Instead, Snell v6 moves from a single protocol-level traffic pattern to PSK-derived deployment-level diversity.

In Snell v4, all deployments shared the same general protocol behavior, including the same category of randomized perturbation. Snell v6 changes this model by generating a deployment-specific protocol profile.

More specifically, Snell v6 operates based on a protocol profile. This profile contains 42 characteristic parameters and 13 categories of padding and traffic-shaping strategies that can be combined in different ways. These parameters control multiple observable aspects of the encrypted stream, including framing behavior, padding behavior, packet-size distribution, and traffic normalization.

A sample profile looks like this:

static const sn_shape_profile_t sample_profile = {
    .profile_id = 0x6a31c4d2,

    .pre_salt_min = 37,
    .pre_salt_max = 91,
    .salt_permutation_rounds = 5,
    .salt_mask_stride = 11,

    .header_prefix_min = 12,
    .header_prefix_max = 44,

    .padding_generator = SN_SHAPE_PAD_GEN_BLOCK_MIXTURE,
    .padding_min = 48,
    .padding_max = 220,
    .padding_chunk_count = 4,
    .padding_interval = 3,
    .padding_small_payload_limit = 384,

    .bit_ratio_min = 86,
    .bit_ratio_max = 132,

    .histogram_low_weight = 38,
    .histogram_mid_weight = 146,
    .histogram_high_weight = 73,
    .nibble_low_mask = 0x5b,
    .block_motif_count = 5,
    .block_repeat_window = 17,

    .mix_mode = SN_SHAPE_MIX_OFFSET_STRIDE_SWAP,
    .mix_rounds = 3,
    .mix_stride = 19,
    .mix_offset = 7,
    .mix_block_size = 11,

    .chunk_policy = SN_SHAPE_CHUNK_BUCKETED,
    .chunk_initial_size = 612,
    .chunk_max_size = 4096,
    .chunk_growth_step = 431,
    .chunk_jitter = 96,
    .chunk_bucket_count = 5,
    .chunk_buckets = {
        517, 863, 1291, 2047, 3079
    },
    .idle_reset_seconds = 8,

    .write_policy = SN_SHAPE_WRITE_FIXED_SEQUENCE,
    .first_write_count = 5,
    .write_bucket_count = 5,
    .write_buckets = {
        233, 377, 610, 987, 1597
    },
    .write_sequence_count = 6,
    .write_sequence = {
        233, 610, 377, 987, 610, 1597
    },
    .write_jitter = 64,
    .write_payload_factor = 3,
};

Different profiles result in different observable traffic characteristics. As long as different servers use different profiles, there is no longer a single stable traffic pattern shared by all Snell v6 deployments.

This significantly increases the cost of protocol classification. Instead of matching one fixed protocol fingerprint, a classifier would need to account for a large number of deployment-specific behaviors.

Auto-configuration

At the same time, users do not need to manually configure or tune these complex profiles. The Snell v6 client and server automatically derive the protocol profile from the configured PSK.

In other words, as long as the PSK is different, the resulting protocol characteristics will also be different.

This design has two important benefits.

First, it keeps deployment simple. Users can continue to configure Snell in a familiar way without learning or maintaining a large number of low-level protocol parameters.

Second, it prevents profile homogenization. If users had to manually choose or copy protocol profiles, many deployments would inevitably end up sharing the same configuration, which would defeat the purpose of fingerprint diversity. By deriving the profile automatically from the PSK, Snell v6 ensures that deployments naturally diverge from one another.

With Snell v6, our goal is not to imitate a specific existing protocol. Instead, Snell v6 introduces controlled protocol diversity at the deployment level, while preserving Snell’s long-standing priorities: performance, deployment simplicity, accurate error reporting, and full TCP semantics.

More Features

This release adds more flexible network stack control capabilities to the server. First, a new dns-ip-preference configuration item has been added, allowing an IP address family preference to be specified when using DNS resolution results. It supports five modes: default, prefer-ipv4, prefer-ipv6, ipv4-only, and ipv6-only, making it easier to stably control connection behavior in dual-stack networks, IPv6-preferred networks, or environments with only IPv4/IPv6 egress.

Second, listen now supports configuring multiple listening addresses simultaneously, for example, listen = 0.0.0.0:7177,[::]:7177, so the server can explicitly listen on both IPv4 and IPv6 addresses at the same time, without relying on the system’s compatibility behavior for IPv6 sockets. The new --help has also been updated with the relevant configuration descriptions.

Availability

The beta version of Surge Mac now supports Snell v6, and the TestFlight version of Surge iOS will be released in the coming days. The Snell v6 server binary can be downloaded from here:

https://kb.nssurge.com/surge-knowledge-base/release-notes/snell

Please note that Snell v6 is still in beta. During the beta period, we may make incompatible protocol changes. To ensure connectivity, both the client and the server should be kept updated to the latest beta version.