alireza0 / x-ui

xray panel supporting multi-protocol multi-user expire day & traffic (Vmess & Vless & Trojan & Shadowsocks)
https://t.me/XrayUI
GNU General Public License v3.0
2.61k stars 429 forks source link

Suggestions to improve WARP #1055

Open Phoenix-999 opened 4 months ago

Phoenix-999 commented 4 months ago

Here are some suggestions to improve WARP in the outbounds:

In the IPV6 section, consider adding a subnet with a prefix length.

"XXXXXXXXXXXXXXXX/128" // Place IPV6 Here

Example

  "address": [
          "172.16.0.2/32",
          "2606:4800:110:8a79:a425:5c48:2e2e:16a7/128" // Place IPV6 Here
        ],

/128 for Individual Hosts:

Advantage: Provides a single, unique address for a specific host/device. Consideration: No room for additional hosts on the same subnet. It's a point-to-point connection. Use Case: Appropriate for scenarios where each IPv6 address corresponds to a specific, dedicated device.

Larger Subnet (e.g., /64):

Advantage: Allows for multiple hosts within the same subnet. Consideration: Subnets smaller than /64 are generally not recommended due to IPv6 design principles. Use Case: Suitable for scenarios where you have multiple devices on the same network segment.

Consider adding "reserved" field in a WireGuard configuration, such as:

"reserved": ["X", "X", "X"], // Place Reserved Here

Example

"reserved": [
    224,
    83,
    255
]

Advantages:

Conflict Avoidance: The reserved values help prevent conflicts and unintended use of specific IP addresses that might have special meanings or functions. Future-Proofing: By reserving certain values, the configuration is prepared for potential future changes or additions to the network without disrupting existing assignments.

Here an example of the complete WireGuard Outbound

// WARP IPv4 Outbound
{
  "protocol": "freedom",
  "settings": {
    "domainStrategy": "UseIPv4"
  },
  "proxySettings": {
    "tag": "wireguard"
  },
  "tag": "warp-IPv4"
},
// WARP IPv6 Outbound
{
  "protocol": "freedom",
  "settings": {
    "domainStrategy": "UseIPv6"
  },
  "proxySettings": {
    "tag": "wireguard"
  },
  "tag": "warp-IPv6"
},
// WireGuard Outbound
{
  "protocol": "wireguard",
  "settings": {
    "secretKey": "XXXXXXXXXXXXXXXXXXXXX", // Place WireGuard Secret Key
    "address": [
      "172.16.0.2/32",
      "XXXXXXXXXXXXXXXX/128" // Place IPV6 Here
    ],
    "workers": 2,
    "domainStrategy": "ForceIP",
    "peers": [
      {
        "publicKey": "XXXXXXXXXXXXXXXXXXXXX", // Place WireGuard Public Key Here
        "allowedIPs": [
          "0.0.0.0/0",
          "::/0"
        ],
        "endpoint": "engage.cloudflareclient.com:2408",
        "keepAlive": 0
      }
    ],
    "reserved": ["X", "X", "X"], // Place Reserved Here
    "mtu": 1280,
    "domainStrategy": "ForceIPv4"
  },
  "tag": "wireguard"
}

Here are some suggestions to improve WARP in the inbound: Consider adding a manual input field so that users can add any desired web domain to the WARP section.

// WARP IPv4 Inbound
{
          "type": "field",
          "domain": [
            "geosite:google",
            "geosite:openai",
            "geosite:speedtest",
            "geosite:meta",
            "geosite:spotify",
            "domain:ucas.com", // Added manually by the user.
            "domain:bl.uk"      // Added manually by the user.

          ],
          "outboundTag": "warp-IPv4"
        },

Below might help to enhance and make WARP more practical.

package main

import (
    // Import necessary libraries
    "bytes"
    crand "crypto/rand"
    "crypto/tls"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math/rand"
    "net/http"
    "strconv"
    "strings"
    "time"

    "golang.org/x/crypto/curve25519"
)

// Define the Response struct to represent the JSON response structure
type Response struct {
    ID        string `json:"id"`
    Type      string `json:"type"`
    Model     string `json:"model"`
    Name      string `json:"name"`
    Key       string `json:"key"`
    Account   Account
    Config    Config
    Token     string `json:"token"`
    Warp      bool   `json:"warp_enabled"`
    Waitlist  bool   `json:"waitlist_enabled"`
    Created   string `json:"created"`
    Updated   string `json:"updated"`
    TOS       string `json:"tos"`
    Place     int    `json:"place"`
    Locale    string `json:"locale"`
    Enabled   bool   `json:"enabled"`
    InstallID string `json:"install_id"`
    FCMToken  string `json:"fcm_token"`
    SerialNum string `json:"serial_number"`
}

// Define the Account struct within the Response struct
type Account struct {
    ID                   string `json:"id"`
    AccountType          string `json:"account_type"`
    Created              string `json:"created"`
    Updated              string `json:"updated"`
    PremiumData          int    `json:"premium_data"`
    Quota                int    `json:"quota"`
    Usage                int    `json:"usage"`
    WarpPlus             bool   `json:"warp_plus"`
    ReferralCount        int    `json:"referral_count"`
    ReferralRenewalCount int    `json:"referral_renewal_countdown"`
    Role                 string `json:"role"`
    License              string `json:"license"`
}

// Define the Config struct within the Response struct
type Config struct {
    ClientID  string `json:"client_id"`
    Peers     []Peer `json:"peers"`
    Interface struct {
        Addresses Addresses `json:"addresses"`
    } `json:"interface"`
    Services struct {
        HTTPProxy string `json:"http_proxy"`
    } `json:"services"`
}

// Define the Peer struct within the Config struct
type Peer struct {
    PublicKey string `json:"public_key"`
    Endpoint  struct {
        V4   string `json:"v4"`
        V6   string `json:"v6"`
        Host string `json:"host"`
    } `json:"endpoint"`
}

// Define the Addresses struct within the Config struct
type Addresses struct {
    V4 string `json:"v4"`
    V6 string `json:"v6"`
}

// The main function where the program execution starts
func main() {
    // Generate cryptographic key pair
    err, privateKey, publicKey := GenerateKey()
    if err != nil {
        panic(err)
    }

    // Cloudflare API endpoint and HTTP method
    url := "https://api.cloudflareclient.com/v0a2158/reg"
    method := "POST"

    // Set random seed based on current time
    rand.Seed(time.Now().UnixNano())

    // Generate a 22-character random installation ID
    installID := RandStringRunes(22)

    // Generate a 134-character random FCM token
    fcmtoken := RandStringRunes(134)

    // Prepare payload for HTTP request
    payload := []byte(`{"key":"` + publicKey + `","install_id":"` + installID + `","fcm_token":"` + installID + `:APA91b` + fcmtoken + `","tos":"` + time.Now().UTC().Format("2006-01-02T15:04:05.999Z") + `","model":"Android","serial_number":"` + installID + `","locale":"zh_CN"}`)

    // Create an HTTP client with TLS configuration
    client := &http.Client{Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            MinVersion: tls.VersionTLS12,
            MaxVersion: tls.VersionTLS12},
    }}

    // Create a new HTTP request
    req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
    if err != nil {
        fmt.Println(err)
        return
    }

    // Set HTTP request headers
    req.Header.Add("CF-Client-Version", "a-6.10-2158")
    req.Header.Add("User-Agent", "okhttp/3.12.1")
    req.Header.Add("Content-Type", "application/json; charset=UTF-8")

    // Send the HTTP request and handle the response
    res, err := client.Do(req)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer res.Body.Close()

    // Read the response body
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    // Unmarshal the JSON response into the Response struct
    var response Response
    err = json.Unmarshal(body, &response)
    if err != nil {
        fmt.Println(err)
        return
    }

    // Extract the value of "client_id" from the JSON response body
    clientID := response.Config.ClientID

    // Decode the base64-encoded string and convert it to hexadecimal
    decoded, err := base64.StdEncoding.DecodeString(clientID)
    if err != nil {
        fmt.Println(err)
        return
    }
    hexString := hex.EncodeToString(decoded)

    // Convert the hexadecimal string to decimal values and print them
    var decValues []string
    for i := 0; i < len(hexString); i += 2 {
        hexByte := hexString[i : i+2]
        decValue, _ := strconv.ParseInt(hexByte, 16, 64)
        decValues = append(decValues, fmt.Sprintf("%d%d%d", decValue/100, (decValue/10)%10, decValue%10))
    }

    // Convert hexadecimal bytes to integers and print them
    reserved := []int{}
    for i := 0; i < len(hexString); i += 2 {
        hexByte := hexString[i : i+2]
        decValue, _ := strconv.ParseInt(hexByte, 16, 64)
        reserved = append(reserved, int(decValue))
    }

    // Extract values from the JSON response for printing
    v4 := response.Config.Interface.Addresses.V4
    v6 := response.Config.Interface.Addresses.V6

    // Print relevant information
    fmt.Println("device_id:", response.ID)
    fmt.Println("token:", response.Token)
    fmt.Println("account_id:", response.Account.ID)
    fmt.Println("account_type:", response.Account.AccountType)
    fmt.Println("license:", response.Account.License)
    fmt.Println("private_key:", privateKey)
    fmt.Println("public_key:", response.Config.Peers[0].PublicKey)
    fmt.Println("client_id:", response.Config.ClientID)
    fmt.Println("reserved: [", strings.Trim(strings.Join(strings.Fields(fmt.Sprint(reserved)), ", "), "[]"), "]")
    fmt.Println("v4:", v4)
    fmt.Println("v6:", v6)
    fmt.Println("endpoint:", response.Config.Peers[0].Endpoint.Host)
}

// Generate a random string of specified length using given runes
func RandStringRunes(n int) string {
    var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")
    b := make([]rune, n)
    for i := range b {
        b[i] = letterRunes[rand.Intn(len(letterRunes))]
    }
    return string(b)
}

// Generate cryptographic key pair using curve25519
func GenerateKey() (error, string, string) {
    // Generate 32 random bytes
    b := make([]byte, 32)
    if _, err := crand.Read(b); err != nil {
        return fmt.Errorf("unable to read random bytes: %v", err), "", ""
    }

    // Mask and format the random bytes to create a private key
    b[0] &= 248
    b[31] &= 127
    b[31] |= 64
    var pub, priv [32]byte
    copy(priv[:], b)

    // Perform scalar multiplication to derive the public key
    curve25519.ScalarBaseMult(&pub, &priv)

    // Encode the private and public keys to base64 strings
    return nil, base64.StdEncoding.EncodeToString(priv[:]), base64.StdEncoding.EncodeToString(pub[:])
}

Output information

For more management interface descriptions, please refer to official-warp-api.txt. official-warp-api.txt


Ps: I understand that the phrase 'Thank you' might be a rare sentiment and an uncommon commodity in your department, but we want you to know that we all genuinely appreciate your efforts. Even those who use the free internet every day without knowing the risks you take for our safety and security to ensure we can connect to the free internet. Thank you for shouldering these burdens with strength and dedication.

"When injustice becomes law, resistance becomes duty."

MJamshidnejad commented 4 months ago

@Phoenix-999 Thanks for your informative suggestions. I would like to know what is the benefit of the WireGuard Outbound suggestion? Is not it better to use Wireguard outbound as the primary outbound? And what is the reason of difference between DomainStrategy of peer and outbound?

Phoenix-999 commented 4 months ago

Hi @MJamshidnejad

Of course, these are only suggestions, and both approaches should be considered ideal for use.

In summary, the benefits of WireGuard Outbound Configuration lie in its flexibility, enabling the use of different protocols for specific types of traffic. WireGuard is chosen for its efficiency and security features, while WARP IPv4 and IPv6 are employed for specific domain strategies.

The decision to use WireGuard Outbound as the primary outbound depends on factors such as speed, simplicity, and security, aligning with the specific requirements and goals of the network.

Regarding the difference in Domain Strategy, WARP IPv4 and IPv6 are utilized to direct traffic to specific IP versions. In contrast, WireGuard uses "ForceIP," ensuring that traffic is forced to use IPv4. This distinction may be based on optimization needs for specific applications or services in the network.

I hope the above makes sense, and I am eager to see more knowledgeable individuals on this platform contribute to creating a robust way for using this amazing feature.

PS : I'm still a newbie and learning my way around all this. 😊

MJamshidnejad commented 4 months ago

Hi @MJamshidnejad

Of course, these are only suggestions, and both approaches should be considered ideal for use.

In summary, the benefits of WireGuard Outbound Configuration lie in its flexibility, enabling the use of different protocols for specific types of traffic. WireGuard is chosen for its efficiency and security features, while WARP IPv4 and IPv6 are employed for specific domain strategies.

The decision to use WireGuard Outbound as the primary outbound depends on factors such as speed, simplicity, and security, aligning with the specific requirements and goals of the network.

Regarding the difference in Domain Strategy, WARP IPv4 and IPv6 are utilized to direct traffic to specific IP versions. In contrast, WireGuard uses "ForceIP," ensuring that traffic is forced to use IPv4. This distinction may be based on optimization needs for specific applications or services in the network.

I hope the above makes sense, and I am eager to see more knowledgeable individuals on this platform contribute to creating a robust way for using this amazing feature.

PS : I'm still a newbie and learning my way around all this. 😊

As far as I know, most the cases you mentioned is related to the core not the panel. However, they are interesting. it would be better if you learn Go and work on your ideas. Your suggestion for Warp took my attention because I tried to use WG as the first and primary outbound but It seems the implementation is not CPU-friend and it cannot handle traffic flow (just) when it is used as primary outbound. I thought that fixes this problem.