libXray

repository·main·Indexed 41 days ago

https://github.com/xtls/libxray

A wrapper around Xray-core designed to integrate Xray functionality into client applications for Android, iOS, macOS, Linux, and Windows. It provides a unified invocation API for tasks such as running the Xray core, converting share links (VMessAEAD, VLESS, SS, SOCKS, Trojan) to Xray JSON, handling age-encrypted subscriptions, and performing batch pings. Includes specialized Android support for VPN-aware DNS resolution and per-app routing via ProcessFinder.

Tokens
8.1K
Snippets
34
Records
38
Agent score
52%

What's inside libXray

  1. Critical: Single Go runtime restriction

    main

    WARNING

    Use only one Go runtime per process.

    Every native libXray artifact (whether produced via cgo or gomobile) embeds a Go runtime. Do not load libXray alongside any other independently built Go, cgo, or gomobile library in the same executable or process. Doing so will cause build, link, or load failures, or runtime crashes during initialization.

    Correct Pattern: If your process needs Go packages from multiple libraries, include them in a single Go build or gomobile bind invocation to produce one native artifact that shares a single runtime.

  2. Critical: Single Go runtime constraint

    main

    WARNING

    Each process can only use one Go runtime.

    Go does not support loading multiple independent Go runtimes within the same process. Since all libXray products embed a Go runtime (via cgo or gomobile), you must not load libXray and another independent Go/cgo/gomobile library in the same executable or process. Doing so will cause failures during building, linking, loading, or runtime initialization.

    Solution: If you need multiple Go packages in one process, they must be included in a single Go build or gomobile bind command so they share a single runtime. Simply re-packaging or merging existing frameworks, archives, AARs, or DLLs will not work.

  3. Install libXray via Go modules

    main

    libXray uses CalVer for releases (e.g., v26.3.27), but Go modules require a SemVer-compatible import path. To install a specific version, use the mirrored SemVer tag (e.g., v1.260327.0 for release v26.3.27).

    Always pin against the SemVer mirror to ensure compatibility with Go's module system.

    go get github.com/xtls/libxray@v1.260327.0
  4. Build libXray using the build script

    main

    It is highly recommended to use the provided Python build script (build/main.py) to compile libXray. The script handles dependencies and platform-specific requirements.

    Requirements:

    • git and go installed.
    • For Linux/Windows: gcc and g++ in PATH.
    • For Android: gomobile.
    • For Apple: gomobile or go (requires "iOS Simulator Runtime").

    Options:

    • Use the local argument to use an existing local checkout of Xray-core at ../Xray-core via a Go module replace directive.
    • For gomobile builds, set the LIBXRAY_GOMOBILE_VERSION environment variable to select a specific Go module version.
    # Android (min Android API level 21)
    python3 build/main.py android
    
    # Apple (gomobile or go)
    python3 build/main.py apple gomobile
    python3 build/main.py apple go
    
    # Linux
    python3 build/main.py linux
    
    # Windows
    python3 build/main.py windows
    
    # Using a local Xray-core checkout
    python3 build/main.py linux local
  5. Handle age-encrypted subscriptions

    main

    libXray supports decrypting subscriptions encrypted with age.

    Supported Identities

    • X25519 (AGE-SECRET-KEY-1...)
    • ML-KEM-768 + X25519 hybrid (AGE-SECRET-KEY-PQ-1...)

    Workflow

    1. Generate Keys: Use generateAgeKeyPair with keyType set to x25519 or hybrid (defaults to x25519).
    2. Persist Keys: The integrating application must persist the secretKey and publicKey.
    3. Decryption: When calling convertShareLinksToXrayJson, provide the secretKey in the payload.
    4. Security: Applications must never send the secretKey over HTTP or write decrypted subscription text to disk. libXray decrypts in memory (limit 16 MiB).

    Note: libXray does not perform the subscription HTTP request or manage headers; the application must handle the network request and provide the publicKey as X-Age-Public-Key if required by the provider.

    // Generate a new keypair
    {
      "apiVersion": 3,
      "method": "generateAgeKeyPair",
      "payload": {
        "keyType": "hybrid"
      }
    }
  6. Configure DNS for Android (Socket Protection)

    main

    To prevent Android VPN runtimes from providing loopback DNS addresses to the Go resolver, use the controller API to set a specific DNS and protect the socket.

    1. Call LibXray.setDNS(controller, "<IP:port>") before runXray.
    2. The DNS must be an IP endpoint with a port (e.g., 8.8.8.8:53 or [2001:4860:4860::8888]:53).
    3. After stopping the core, call LibXray.resetDNS().

    Note: These APIs are only available in Android builds and modify the Go process-level default resolver.

    // Android usage pattern
    LibXray.setDNS(controller, "8.8.8.8:53");
    LibXray.invoke(runXrayRequest);
    
    // Later, when stopping the Core:
    LibXray.invoke(stopXrayRequest);
    LibXray.resetDNS();
  7. Read Xray traffic metrics via HTTP API

    main

    libXray does not sample or save traffic data itself. Instead, the application should read metrics directly from the Xray instance's built-in HTTP API.

    Setup Requirements:

    1. The Xray configuration must include a metrics object with a listen address.
    2. The Xray configuration must enable statistics in the policy.system section.

    How to access: Once Xray is running, use an HTTP client to query the /debug/vars endpoint at the specified listen address.

    Example Configuration:

    {
      "metrics" : {
        "listen": "127.0.0.1:49227"
      },
      "policy" : {
        "system" : {
          "statsInboundDownlink" : true,
          "statsInboundUplink" : true,
          "statsOutboundDownlink" : true,
          "statsOutboundUplink" : true
        }
      }
    }

    Example Request: GET http://127.0.0.1:49227/debug/vars

    http://localhost:49227/debug/vars
  8. Use the libXray invocation API

    main

    libXray uses a unified invocation pattern to execute various Xray-related tasks. All requests are structured using the LibXrayInvokeRequest type, which specifies the APIVersion, the Method to be called, and a Payload containing the method-specific data as a json.RawMessage.

    // Conceptual structure of an invocation request
    request := LibXrayInvokeRequest{
        APIVersion: LibXrayAPIVersion,
        Method:     LibXrayMethodRunXray,
        Payload:    jsonPayload, // json.RawMessage containing RunXrayRequest
    }
  9. Access Xray runtime metrics via HTTP

    main

    libXray allows you to expose Xray runtime counters through an HTTP server. To enable this, include a metrics block in your Xray JSON configuration.

    Configuration Example

    To expose metrics on 127.0.0.1:49227 and enable outbound/inbound statistics, use the following structure:

    {
      "metrics" : {
        "listen": "127.0.0.1:49227"
      },
      "policy" : {
        "system" : {
          "statsInboundDownlink" : true,
          "statsInboundUplink" : true,
          "statsOutboundDownlink" : true,
          "statsOutboundUplink" : true
        }
      },
      "stats" : {}
    }

    Accessing Data

    Once the Xray instance is running, query the /debug/vars endpoint directly using an HTTP client: http://localhost:49227/debug/vars

  10. Convert share links to Xray JSON with `convertShareLinksToXrayJson`

    main

    Use convertShareLinksToXrayJson to parse various share link formats (VMessAEAD, VLESS, SS, SOCKS, Trojan) into Xray JSON outbounds.

    Key Behaviors:

    • Supported Formats: VMessAEAD, VLESS, SS, SOCKS, Trojan. Note that old vmess://Base64(JSON) is not supported.
    • Unsupported Formats: Clash/Mihomo configurations and hysteria2:// / hy2:// URIs are not supported for link conversion (though Hysteria2 is supported in native Xray JSON).
    • Mapping Details:
      • mKCP: Preserves mtu and tti.
      • XHTTP: Preserves extra JSON and fm (FinalMask) with quicParams.
      • TLS/REALITY: Preserves ech, pcs, vcn, pbk, sid, pqv, spx, sni, fp, and alpn.
      • gRPC: Supports gun and multi.
    • Response Structure: Returns a payload containing text (the JSON string) and an optional age field. Successful conversion returns data: {"outbounds":[...]}.
    • Error Handling: Invalid individual items are skipped without failing the whole batch. If no valid nodes are found, or if there is a syntax/decryption error, it returns success: false and data: null.
    {
      "apiVersion": 3,
      "method": "convertShareLinksToXrayJson",
      "payload": {
        "text": "<share_link_or_subscription_text>",
        "age": {
          "secretKey": "AGE-SECRET-KEY-1..."
        }
      }
    }
  11. Configure DNS Resolver for Android

    main

    To prevent Go's resolver from using a loopback DNS server exposed by a VPN, use the SetDNS and ResetDNS APIs available in the Android artifact. This protects the DNS socket from the VPN tunnel.

    1. Call SetDNS with an IP endpoint and port (e.g., 8.8.8.8:53) before calling runXray.
    2. Call ResetDNS after the Xray core has stopped.
    // Set the DNS before running Xray
    LibXray.setDNS(controller, "8.8.8.8:53");
    LibXray.invoke(runXrayRequest);
    
    // Later, when stopping the core:
    LibXray.invoke(stopXrayRequest);
    LibXray.resetDNS();
  12. Batch test outbound configurations with `pingBatch`

    main

    The pingBatch method tests multiple Xray outbound configurations concurrently within a temporary Xray instance.

    Usage Details:

    • Batch Limit: A single request can contain a maximum of 5 configurations. Requests exceeding this will fail immediately.
    • Targeting: Each xrayJson in the configs array is parsed for outbounds. The target outbound is selected based on outboundTag, proxy tag, or the first available outbound.
    • Parameters:
      • url: The target URL to test latency against.
      • locationUrl (Optional): An absolute HTTP(S) address. If provided, libXray performs a HEAD request to the URL, then a GET request to fetch location data. The location request uses the same outbound. The location result is returned in locationJson.
    • Results:
      • The response array matches the input array's length and order.
      • delay: Latency in milliseconds. A value of 10000 indicates an error; 11000 indicates a timeout.
      • success: Boolean indicating if the latency test passed.
      • locationError: Returned if the location GET request fails (after a successful latency test).
    {
      "apiVersion": 3,
      "method": "pingBatch",
      "payload": {
        "configs": [
          {
            "xrayJson": "{\"outbounds\":[...]}"
          },
          {
            "xrayJson": "{\"outbounds\":[...]}",
            "outboundTag": "media"
          }
        ],
        "timeout": 5,
        "url": "https://cp.cloudflare.com/",
        "locationUrl": "https://ip-check-perf.radar.cloudflare.com/"
      }
    }