java.lang.Object
org.klomp.snark.ClientID

public final class ClientIDextends Object
Registry of known BitTorrent client identities.

Two things live here:

  • The peer ID prefix recognition table mapping the first three raw peer ID bytes (as the first four Base64 characters of the ID) to a client name. This is the single source of truth; I2PSnarkServlet delegates to it.
  • Spoofing profiles for well-known clearnet clients, each bundling a peer ID prefix, the HTTP tracker User-Agent, and the BEP 10 extension handshake "v" string, with consistent version numbers across all three surfaces.

Spoofing is opt-in via the i2psnark.clientId property (empty to identify as I2PSnark, "random" to select a random profile per destination per run, or a profile name to always impersonate that client), optionally restricted to a subset via i2psnark.clientIds. Only clients recognizable by our own identification table are spoofable, so the console peers page keeps showing a real client name for our own IDs.

Version strings are pinned to upstream client releases verified as of 2026-08; bump them only when an upstream release changes the UA or "v" format, since point releases do not require updates. All three strings of a profile must carry the same version, as trackers may cross-check them.

  • Field Details

    • OS_NAME

      private static final String OS_NAME
      Operating system named in the client id.
    • JAVA_VERSION

      private static final String JAVA_VERSION
      Java version named in the client id.
    • TAIL_CHARS

      private static final String TAIL_CHARS
      Random tail charset for generated peer IDs, per the BiglyBT/Azureus convention.
      See Also:
    • VUZE

      public static final ClientID.Profile VUZE
      Vuze 5.7.7.0: Azureus-branded peer ID and tracker UA, plain "Vuze" handshake. The mismatch is authentic; version data verified against upstream releases and captures as of 2026-08.
    • BIGLYBT

      public static final ClientID.Profile BIGLYBT
      BiglyBT 4.1.0.0: no OS/Java suffix in either the tracker UA or handshake, matching the upstream config default.
    • TRANSMISSION

      public static final ClientID.Profile TRANSMISSION
      Transmission 4.1.3: slash-separated UA, space-separated handshake string.
    • KTORRENT

      public static final ClientID.Profile KTORRENT
      KTorrent 26.04.3: Gear-era identity, both strings unverified against a capture.
    • DELUGE

      public static final ClientID.Profile DELUGE
      Deluge 2.2.0 paired with libtorrent 2.0.13, announced in both strings. The libtorrent part should pair with a plausible bundled version.
    • QBITTORRENT

      public static final ClientID.Profile QBITTORRENT
      QBittorrent 5.2.3: mixed-case "-qB5230-" prefix, no OS/Java suffix.
    • LIBTORRENT

      public static final ClientID.Profile LIBTORRENT
      Libtorrent 1.2.19: the last fully-authentic 1.2.x identity. Real libtorrent 2.x uses a lowercase -lt prefix we do not recognize, so this profile pins 1.2.x instead.
    • TIXATI

      public static final ClientID.Profile TIXATI
      Tixati 3.44: dash-free "TIX34" peer ID; both strings unverified.
    • PROFILES

      private static final List<ClientID.Profile> PROFILES
      The known identity profiles, current one first.
  • Constructor Details

    • ClientID

      public ClientID()
      Constructor. The recognition table and the spoofing profiles are static, so an instance holds no state and every accessor here is static.
  • Method Details

    • getClientName

      public static String getClientName(String ch)
      The client name for a peer ID prefix, from the same table used to identify remote peers in the console.
      Parameters:
      ch - the first four Base64 characters of the peer ID, i.e. the Base64 of its first three non-zero bytes
      Returns:
      the client name, or null if unknown
    • profiles

      public static List<ClientID.Profile> profiles()
      All spoofable client profiles, unmodifiable.
      Returns:
      an unmodifiable list of profiles, never null
    • getByName

      public static ClientID.Profile getByName(String name)
      Look up a profile by name, case-insensitively.
      Parameters:
      name - the profile name, e.g. "Vuze" or "qbittorrent"
      Returns:
      the profile, or null if unknown
    • getRandomProfile

      public static ClientID.Profile getRandomProfile(Random random, List<ClientID.Profile> candidates)
      A random profile, optionally restricted to a candidate subset.
      Parameters:
      random - the randomness source
      candidates - profiles to choose from; null or empty for all
      Returns:
      one of the candidates, never null
    • parseCandidateList

      public static List<ClientID.Profile> parseCandidateList(String raw)
      Parse a comma-separated i2psnark.clientIds value into profiles, dropping whitespace, duplicates, and names that match no known client.
      Parameters:
      raw - the raw property value, may be null or empty
      Returns:
      the recognized profiles in order, unmodifiable; empty if none