Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added support for multiple custom configs in subscriptions + remarks #2827

Merged
merged 2 commits into from
Feb 10, 2024

Conversation

vfarid
Copy link
Contributor

@vfarid vfarid commented Feb 9, 2024

Accepting both single config and multiple configs i.e: {customConfig} or [{customConfig1}, {customConfig2} ...]

Furtheremore added an optional 'remarks' field to v2rayConfig class to keep remote customConfig name.

Accepting both single config and multiple configs i.e:
{customConfig} or [{customConfig1}, {customConfig2} ...]

Furtheremore added an optional 'remarks' field to v2rayConfig class to keep remote customConfig name.
@ImMohammad20000
Copy link

Its a good change

@2dust 2dust merged commit eb75666 into 2dust:master Feb 10, 2024
@AliM1988
Copy link

@vfarid Thank you. Please give a sample including 2 custumConfigs with remark.

@AliM1988
Copy link

AliM1988 commented Feb 12, 2024

@vfarid @2dust I tested below single-config. It can be imported via subscription successfully, but the "remarks" field doesn't appeared in imported config.

{
  "remarks": "serv1",
  "log": {
    "access": "",
    "error": "",
    "loglevel": "warning"
  },
  "inbounds": [
    {
      "tag": "socks",
      "port": 10808,
      "listen": "127.0.0.1",
      "protocol": "socks",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    },
    {
      "tag": "http",
      "port": 10809,
      "listen": "127.0.0.1",
      "protocol": "http",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "xxx",
            "port": 443,
            "users": [
              {
                "id": "f3e0bd10-e133-11ed-ace2-1495dbb28315",
                "alterId": 0,
                "email": "t@t.tt",
                "security": "auto",
                "encryption": "none",
                "flow": ""
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "serverName": "xxx",
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "chrome",
          "show": false
        },
        "wsSettings": {
          "path": "/downloader/2082",
          "headers": {
            "Host": "xxx"
          }
        },
        "sockopt": {
          "dialerProxy": "fragment",
          "tcpKeepAliveIdle": 100,
          "mark": 255,
          "tcpNoDelay": true
        }
      },
      "mux": {
        "enabled": true,
        "concurrency": 8
      }
    },
    {
      "tag": "fragment",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "AsIs",
        "fragment": {
          "packets": "tlshello",
          "length": "10-100",
          "interval": "50-200"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "tcpKeepAliveIdle": 100
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {
        
      }
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "http"
        }
      }
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "api"
        ],
        "outboundTag": "api",
        "enabled": true
      },
      {
        "id": "5627785659655799759",
        "type": "field",
        "port": "0-65535",
        "outboundTag": "proxy",
        "enabled": true
      }
    ]
  }
}

Also, I tested a multi-config as below. Importing wan not successful.

[
  {
    "remarks": "serv1",
    "log": {
      "access": "",
      "error": "",
      "loglevel": "warning"
    },
    "inbounds": [
      {
        "tag": "socks",
        "port": 10808,
        "listen": "127.0.0.1",
        "protocol": "socks",
        "sniffing": {
          "enabled": true,
          "destOverride": [
            "http",
            "tls"
          ],
          "routeOnly": false
        },
        "settings": {
          "auth": "noauth",
          "udp": true,
          "allowTransparent": false
        }
      },
      {
        "tag": "http",
        "port": 10809,
        "listen": "127.0.0.1",
        "protocol": "http",
        "sniffing": {
          "enabled": true,
          "destOverride": [
            "http",
            "tls"
          ],
          "routeOnly": false
        },
        "settings": {
          "auth": "noauth",
          "udp": true,
          "allowTransparent": false
        }
      }
    ],
    "outbounds": [
      {
        "tag": "proxy",
        "protocol": "vless",
        "settings": {
          "vnext": [
            {
              "address": "xxx",
              "port": 443,
              "users": [
                {
                  "id": "f3e0bd10-e133-11ed-ace2-1495dbb28315",
                  "alterId": 0,
                  "email": "t@t.tt",
                  "security": "auto",
                  "encryption": "none",
                  "flow": ""
                }
              ]
            }
          ]
        },
        "streamSettings": {
          "network": "ws",
          "security": "tls",
          "tlsSettings": {
            "allowInsecure": false,
            "serverName": "xxx",
            "alpn": [
              "h2",
              "http/1.1"
            ],
            "fingerprint": "chrome",
            "show": false
          },
          "wsSettings": {
            "path": "/downloader/2082",
            "headers": {
              "Host": "xxx"
            }
          },
          "sockopt": {
            "dialerProxy": "fragment",
            "tcpKeepAliveIdle": 100,
            "mark": 255,
            "tcpNoDelay": true
          }
        },
        "mux": {
          "enabled": true,
          "concurrency": 8
        }
      },
      {
        "tag": "fragment",
        "protocol": "freedom",
        "settings": {
          "domainStrategy": "AsIs",
          "fragment": {
            "packets": "tlshello",
            "length": "10-100",
            "interval": "50-200"
          }
        },
        "streamSettings": {
          "sockopt": {
            "tcpNoDelay": true,
            "tcpKeepAliveIdle": 100
          }
        }
      },
      {
        "tag": "direct",
        "protocol": "freedom",
        "settings": {
          
        }
      },
      {
        "tag": "block",
        "protocol": "blackhole",
        "settings": {
          "response": {
            "type": "http"
          }
        }
      }
    ],
    "routing": {
      "domainStrategy": "AsIs",
      "rules": [
        {
          "type": "field",
          "inboundTag": [
            "api"
          ],
          "outboundTag": "api",
          "enabled": true
        },
        {
          "id": "5627785659655799759",
          "type": "field",
          "port": "0-65535",
          "outboundTag": "proxy",
          "enabled": true
        }
      ]
    }
  },
  {
    "remarks": "serv2",
    "log": {
      "access": "",
      "error": "",
      "loglevel": "warning"
    },
    "inbounds": [
      {
        "tag": "socks",
        "port": 10808,
        "listen": "127.0.0.1",
        "protocol": "socks",
        "sniffing": {
          "enabled": true,
          "destOverride": [
            "http",
            "tls"
          ],
          "routeOnly": false
        },
        "settings": {
          "auth": "noauth",
          "udp": true,
          "allowTransparent": false
        }
      },
      {
        "tag": "http",
        "port": 10809,
        "listen": "127.0.0.1",
        "protocol": "http",
        "sniffing": {
          "enabled": true,
          "destOverride": [
            "http",
            "tls"
          ],
          "routeOnly": false
        },
        "settings": {
          "auth": "noauth",
          "udp": true,
          "allowTransparent": false
        }
      }
    ],
    "outbounds": [
      {
        "tag": "proxy",
        "protocol": "vless",
        "settings": {
          "vnext": [
            {
              "address": "xxx",
              "port": 443,
              "users": [
                {
                  "id": "f3e0bd10-e133-11ed-ace2-1495dbb28315",
                  "alterId": 0,
                  "email": "t@t.tt",
                  "security": "auto",
                  "encryption": "none",
                  "flow": ""
                }
              ]
            }
          ]
        },
        "streamSettings": {
          "network": "ws",
          "security": "tls",
          "tlsSettings": {
            "allowInsecure": false,
            "serverName": "xxx",
            "alpn": [
              "h2",
              "http/1.1"
            ],
            "fingerprint": "chrome",
            "show": false
          },
          "wsSettings": {
            "path": "/downloader/2082",
            "headers": {
              "Host": "xxx"
            }
          },
          "sockopt": {
            "dialerProxy": "fragment",
            "tcpKeepAliveIdle": 100,
            "mark": 255,
            "tcpNoDelay": true
          }
        },
        "mux": {
          "enabled": true,
          "concurrency": 8
        }
      },
      {
        "tag": "fragment",
        "protocol": "freedom",
        "settings": {
          "domainStrategy": "AsIs",
          "fragment": {
            "packets": "tlshello",
            "length": "10-100",
            "interval": "50-200"
          }
        },
        "streamSettings": {
          "sockopt": {
            "tcpNoDelay": true,
            "tcpKeepAliveIdle": 100
          }
        }
      },
      {
        "tag": "direct",
        "protocol": "freedom",
        "settings": {
          
        }
      },
      {
        "tag": "block",
        "protocol": "blackhole",
        "settings": {
          "response": {
            "type": "http"
          }
        }
      }
    ],
    "routing": {
      "domainStrategy": "AsIs",
      "rules": [
        {
          "type": "field",
          "inboundTag": [
            "api"
          ],
          "outboundTag": "api",
          "enabled": true
        },
        {
          "id": "5627785659655799759",
          "type": "field",
          "port": "0-65535",
          "outboundTag": "proxy",
          "enabled": true
        }
      ]
    }
  }
]

@vfarid vfarid mentioned this pull request Feb 14, 2024
@vfarid
Copy link
Contributor Author

vfarid commented Feb 14, 2024

#2749

@vfarid
Copy link
Contributor Author

vfarid commented Feb 14, 2024

#2770

@vfarid
Copy link
Contributor Author

vfarid commented Feb 14, 2024

#2694

@AliM1988
Copy link

@vfarid I posted 2 messages, can you reply?

@vfarid
Copy link
Contributor Author

vfarid commented Feb 14, 2024

@vfarid I posted 2 messages, can you reply?

What do you mean? There is a sample right in previous panel:

#2827 (comment)

@AliM1988
Copy link

@vfarid I posted 2 messages, can you reply?

What do you mean? There is a sample right in previous panel:

#2827 (comment)

I said there, the first sample imported without remark, and the second sample can't be imported.

@vfarid
Copy link
Contributor Author

vfarid commented Feb 15, 2024

@AliM1988

  1. This feature is not for import UI, it is for subscription links.
  2. The remark only work when you have subsription containing multiple custom configs.

@AliM1988
Copy link

@vfarid
In my tests, both samples were into a text file in server, like https://sub.example.com/test.txt and I added them as subscription. For the second sample, by updating subscription no any configs be appeared. Please test it in v1.8.15

@vfarid
Copy link
Contributor Author

vfarid commented Feb 15, 2024

Because 1.8.15 dosent support it, its in master branch and will be available in next release.

@mclovin-2k
Copy link

mclovin-2k commented Feb 18, 2024

I wish the remark can also work on single custom config, please.

@AliM1988
Copy link

AliM1988 commented Feb 18, 2024

I wish the remark can also work on single custom config, please.

You can just encapsulate your single-config in [ ]

@AliM1988
Copy link

AliM1988 commented Feb 18, 2024

@vfarid When we use [{customConfig1}, {customConfig2}, {customConfig3} ...] the order of confings in subscription becomes reversed in v2rayNG:
{customConfig3}
{customConfig2}
{customConfig1}

Also, all elements of each JSON become reversed.

@X-Oracle
Copy link

@vfarid
Is this scenario works ?
2 custom configs and 2 uris.

@APT-ZERO
Copy link

What if we want to deliver like 100 configs to user? 100kb of config file? @vfarid
Isn't better to make multiple dummy Inbounds and route each one to an outbound
Inbound tag = Config name
Client could erase other inbounds and change the selected Inbound and use that inbound and it's routes
This could be the next Standard for all xray-core clients

@vfarid
Copy link
Contributor Author

vfarid commented Feb 21, 2024

What if we want to deliver like 100 configs to user? 100kb of config file? @vfarid Isn't better to make multiple dummy Inbounds and route each one to an outbound Inbound tag = Config name Client could erase other inbounds and change the selected Inbound and use that inbound and it's routes This could be the next Standard for all xray-core clients

Its not that heavy, btw the custom config format is detailed in xray-core. To keep compatibility, we need to follow the format. Furtheremore webservers usually gzip the output and they will reduce the boundle size using compression.

@MrMalekfar
Copy link
Contributor

@vfarid Thank you for implementing this feature. However, I’ve encountered an issue. When I send the ‘x’ JSON config via a sub-link, it functions as expected, but the remark doesn’t seem to work. Conversely, when I send my config enclosed in brackets (for example, [x] or [{x1}, {x2}, …]), the remark operates correctly, but the config(s) fail to initiate. However, if I send each of the individual configs (x1, x2, etc.) as a single config without brackets, they work well.

@vfarid
Copy link
Contributor Author

vfarid commented Feb 23, 2024

@vfarid Thank you for implementing this feature. However, I’ve encountered an issue. When I send the ‘x’ JSON config via a sub-link, it functions as expected, but the remark doesn’t seem to work. Conversely, when I send my config enclosed in brackets (for example, [x] or [{x1}, {x2}, …]), the remark operates correctly, but the config(s) fail to initiate. However, if I send each of the individual configs (x1, x2, etc.) as a single config without brackets, they work well.

I know the remark not working for single config and only works on arrays. I just keep single config for compatibility and didnt touch its functionality. For arrays ive tested several times and it is working as expected. For test, you can add multiple costom configs using sub and export each single configs seperately, you can see the import has been done correctly, so if your config dont work you need to investigate somewere else.
If you see any changes between impoted config and exported one, please send details so i can test.

@ByteMysticRogue
Copy link

ByteMysticRogue commented Feb 23, 2024

Hi @vfarid,

I encountered an issue while importing custom configurations. When I import custom configurations from my sub-link, some integer values are being displayed as float values in the program. This issue is causing my configurations to malfunction. But when I copy the configuration from the browser and import it, the issue does not occur.

Do you have any ideas on how to resolve it?

Configuration when imported:
Screenshot_۲۰۲۴۰۲۲۳-۱۳۰۱۵۷_v2rayNG

Configuration in the browser:
image

@X-Oracle
Copy link

Hi @vfarid,

I encountered an issue while importing custom configurations. When I import custom configurations from my sub-link, some integer values are being displayed as float values in the program. This issue is causing my configurations to malfunction. But when I copy the configuration from the browser and import it, the issue does not occur.

Do you have any ideas on how to resolve it?

Configuration when imported:
Screenshot_۲۰۲۴۰۲۲۳-۱۳۰۱۵۷_v2rayNG

Configuration in the browser:
image

The problem is how it parses Json.
It converts 8 to 8.0 which is not compatible with uint32.

It seems to have effect only on inbounds

@X-Oracle
Copy link

User level and dokem port is effected in my case

@BobZombiE69
Copy link

Thank you very much, this is great. But unfortunately, some Integers parsed as float so it's not working.
For example:
"userLevel": 8 parsed as "userLevel": 8.0

@FransW5
Copy link

FransW5 commented Mar 10, 2024

Some custom-configs with multiple formats in the subscription link are not imported correctly.

For example, the following configuration will be imported correctly And it works properly, if it is individually in the subscription link:

Subscription link content:
{
  "log": {
    "access": "",
    "error": "",
    "loglevel": "none",
    "dnsLog": false
  },
  "dns": {
    "tag": "dns",
    "hosts": {
      "cloudflare-dns.com": [
        "104.16.248.249",
        "104.16.249.249"
      ],
      "domain:youtube.com": [
        "google.com"
      ]
    },
    "servers": [
      "https://cloudflare-dns.com/dns-query"
    ]
  },
  "inbounds": [
    {
      "domainOverride": [
        "http",
        "tls"
      ],
      "protocol": "socks",
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "settings": {
        "auth": "noauth",
        "udp": true,
        "userLevel": 8
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    },
    {
      "protocol": "http",
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "settings": {
        "userLevel": 8
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "fragment-out",
      "domainStrategy": "UseIP",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      },
      "settings": {
        "fragment": {
          "packets": "tlshello",
          "length": "100-200",
          "interval": "10-20"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "domainStrategy": "UseIP"
        }
      }
    },
    {
      "protocol": "dns",
      "tag": "dns-out"
    },
    {
      "protocol": "vless",
      "tag": "fakeproxy-out",
      "domainStrategy": "",
      "settings": {
        "vnext": [
          {
            "address": "google.com",
            "port": 443,
            "users": [
              {
                "encryption": "none",
                "flow": "",
                "id": "3e992e24-b4de-4fea-9e34-2ae3d9aee34e",
                "level": 8,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "randomized",
          "publicKey": "",
          "serverName": "google.com",
          "shortId": "",
          "show": false,
          "spiderX": ""
        },
        "wsSettings": {
          "headers": {
            "Host": "google.com"
          },
          "path": "/"
        }
      },
      "mux": {
        "concurrency": 8,
        "enabled": false
      }
    }
  ],
  "policy": {
    "levels": {
      "8": {
        "connIdle": 300,
        "downlinkOnly": 1,
        "handshake": 4,
        "uplinkOnly": 1
      }
    },
    "system": {
      "statsOutboundUplink": true,
      "statsOutboundDownlink": true
    }
  },
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "inboundTag": [
          "socks-in",
          "http-in"
        ],
        "type": "field",
        "port": "8443",
        "outboundTag": "dns-out",
        "enabled": true
      },
      {
        "inboundTag": [
          "socks-in",
          "http-in"
        ],
        "type": "field",
        "port": "0-65535",
        "outboundTag": "fragment-out",
        "enabled": true
      }
    ],
    "strategy": "rules"
  },
  "stats": {}
}

But if the above configuration is in multiple formats, it will not be imported correctly and some of its lines will be moved and will not work properly (The connection is established, but the fragment does not work):

Subscription link content:
[
{
  "remarks": "ServerLess_TLSFrag",
  "log": {
    "access": "",
    "error": "",
    "loglevel": "none",
    "dnsLog": false
  },
  "dns": {
    "tag": "dns",
    "hosts": {
      "cloudflare-dns.com": [
        "104.16.248.249",
        "104.16.249.249"
      ],
      "domain:youtube.com": [
        "google.com"
      ]
    },
    "servers": [
      "https://cloudflare-dns.com/dns-query"
    ]
  },
  "inbounds": [
    {
      "domainOverride": [
        "http",
        "tls"
      ],
      "protocol": "socks",
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "settings": {
        "auth": "noauth",
        "udp": true,
        "userLevel": 8
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    },
    {
      "protocol": "http",
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "settings": {
        "userLevel": 8
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "fragment-out",
      "domainStrategy": "UseIP",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      },
      "settings": {
        "fragment": {
          "packets": "tlshello",
          "length": "100-200",
          "interval": "10-20"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "domainStrategy": "UseIP"
        }
      }
    },
    {
      "protocol": "dns",
      "tag": "dns-out"
    },
    {
      "protocol": "vless",
      "tag": "fakeproxy-out",
      "domainStrategy": "",
      "settings": {
        "vnext": [
          {
            "address": "google.com",
            "port": 443,
            "users": [
              {
                "encryption": "none",
                "flow": "",
                "id": "3e992e24-b4de-4fea-9e34-2ae3d9aee34e",
                "level": 8,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "randomized",
          "publicKey": "",
          "serverName": "google.com",
          "shortId": "",
          "show": false,
          "spiderX": ""
        },
        "wsSettings": {
          "headers": {
            "Host": "google.com"
          },
          "path": "/"
        }
      },
      "mux": {
        "concurrency": 8,
        "enabled": false
      }
    }
  ],
  "policy": {
    "levels": {
      "8": {
        "connIdle": 300,
        "downlinkOnly": 1,
        "handshake": 4,
        "uplinkOnly": 1
      }
    },
    "system": {
      "statsOutboundUplink": true,
      "statsOutboundDownlink": true
    }
  },
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "inboundTag": [
          "socks-in",
          "http-in"
        ],
        "type": "field",
        "port": "8443",
        "outboundTag": "dns-out",
        "enabled": true
      },
      {
        "inboundTag": [
          "socks-in",
          "http-in"
        ],
        "type": "field",
        "port": "0-65535",
        "outboundTag": "fragment-out",
        "enabled": true
      }
    ],
    "strategy": "rules"
  },
  "stats": {}
}
]

I guess, because some Integers parsed as float so it's not working.
For example: "userLevel": 8 parsed as "userLevel": 8.0

V2rayNG v1.8.17 (Lib v26, Xray core v1.8.8)

@FransW5
Copy link

FransW5 commented Mar 10, 2024

display order of multiple custom-configs (Imported via subscription link) is sometimes reversed (sort from the last to the first), and sometimes the last config is displayed at the top of the list and the others are displayed in reverse (from the last to the first).

In the example below, the configs are imported as follows:

ServerLess_TLSFrag
Server-1
Server-2
Server-3

But the order is expected to be like this:

Server-3
Server-2
Server-1
ServerLess_TLSFrag

Subscription link content:
[
{
  "remarks": "Server-3",
  "inbounds": [
    {
      "tag": "socks",
      "port": 10808,
      "listen": "127.0.0.1",
      "protocol": "socks",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    },
    {
      "tag": "http",
      "port": 10809,
      "listen": "127.0.0.1",
      "protocol": "http",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "www.test3.com",
            "port": 443,
            "users": [
              {
                "id": "785cfb16-a06e-4f97-a07c-fbee93a5d6ca",
                "alterId": 0,
                "security": "auto",
                "encryption": "none",
                "flow": ""
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "serverName": "www.test3.com",
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "chrome",
          "show": false
        },
        "wsSettings": {
          "path": "/?ed=2048",
          "headers": {
            "Host": "www.test3.com"
          }
        },
         "sockopt": {
          "dialerProxy": "fragment",
          "tcpKeepAliveIdle": 100,
          "mark": 255,
          "tcpNoDelay": true
        }
      },
      "mux": {
        "enabled": true,
        "concurrency": 8,
        "xudpConcurrency": 8,
        "xudpProxyUDP443": "reject"
      }
    },
     {
      "tag": "fragment",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "AsIs",
        "fragment": {
          "packets": "tlshello",
          "length": "10-20",
          "interval": "3-4"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "tcpKeepAliveIdle": 100
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "http"
        }
      }
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "api"
        ],
        "outboundTag": "api",
        "enabled": true
      }
    ]
  }
},
{
  "remarks": "Server-2",
  "inbounds": [
    {
      "tag": "socks",
      "port": 10808,
      "listen": "127.0.0.1",
      "protocol": "socks",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    },
    {
      "tag": "http",
      "port": 10809,
      "listen": "127.0.0.1",
      "protocol": "http",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "www.test2.com",
            "port": 443,
            "users": [
              {
                "id": "785cfb16-a06e-4f97-a07c-fbee93a5d6ca",
                "alterId": 0,
                "security": "auto",
                "encryption": "none",
                "flow": ""
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "serverName": "www.test2.com",
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "chrome",
          "show": false
        },
        "wsSettings": {
          "path": "/?ed=2048",
          "headers": {
            "Host": "www.test2.com"
          }
        },
         "sockopt": {
          "dialerProxy": "fragment",
          "tcpKeepAliveIdle": 100,
          "mark": 255,
          "tcpNoDelay": true
        }
      },
      "mux": {
        "enabled": true,
        "concurrency": 8,
        "xudpConcurrency": 8,
        "xudpProxyUDP443": "reject"
      }
    },
     {
      "tag": "fragment",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "AsIs",
        "fragment": {
          "packets": "tlshello",
          "length": "10-20",
          "interval": "3-4"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "tcpKeepAliveIdle": 100
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "http"
        }
      }
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "api"
        ],
        "outboundTag": "api",
        "enabled": true
      }
    ]
  }
},
{
  "remarks": "Server-1",
  "inbounds": [
    {
      "tag": "socks",
      "port": 10808,
      "listen": "127.0.0.1",
      "protocol": "socks",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    },
    {
      "tag": "http",
      "port": 10809,
      "listen": "127.0.0.1",
      "protocol": "http",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ],
        "routeOnly": false
      },
      "settings": {
        "auth": "noauth",
        "udp": true,
        "allowTransparent": false
      }
    }
  ],
  "outbounds": [
    {
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "www.test1.com",
            "port": 443,
            "users": [
              {
                "id": "785cfb16-a06e-4f97-a07c-fbee93a5d6ca",
                "alterId": 0,
                "security": "auto",
                "encryption": "none",
                "flow": ""
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "serverName": "www.test1.com",
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "chrome",
          "show": false
        },
        "wsSettings": {
          "path": "/?ed=2048",
          "headers": {
            "Host": "www.test1.com"
          }
        },
         "sockopt": {
          "dialerProxy": "fragment",
          "tcpKeepAliveIdle": 100,
          "mark": 255,
          "tcpNoDelay": true
        }
      },
      "mux": {
        "enabled": true,
        "concurrency": 8,
        "xudpConcurrency": 8,
        "xudpProxyUDP443": "reject"
      }
    },
     {
      "tag": "fragment",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "AsIs",
        "fragment": {
          "packets": "tlshello",
          "length": "10-20",
          "interval": "3-4"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "tcpKeepAliveIdle": 100
        }
      }
    },
    {
      "tag": "direct",
      "protocol": "freedom",
      "settings": {}
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "http"
        }
      }
    }
  ],
  "routing": {
    "domainStrategy": "AsIs",
    "rules": [
      {
        "type": "field",
        "inboundTag": [
          "api"
        ],
        "outboundTag": "api",
        "enabled": true
      }
    ]
  }
},
{
  "remarks": "ServerLess_TLSFrag",
  "log": {
    "access": "",
    "error": "",
    "loglevel": "none",
    "dnsLog": false
  },
  "dns": {
    "tag": "dns",
    "hosts": {
      "cloudflare-dns.com": [
        "104.16.248.249",
        "104.16.249.249"
      ],
      "domain:youtube.com": [
        "google.com"
      ]
    },
    "servers": [
      "https://cloudflare-dns.com/dns-query"
    ]
  },
  "inbounds": [
    {
      "domainOverride": [
        "http",
        "tls"
      ],
      "protocol": "socks",
      "tag": "socks-in",
      "listen": "127.0.0.1",
      "port": 10808,
      "settings": {
        "auth": "noauth",
        "udp": true,
        "userLevel": 8
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    },
    {
      "protocol": "http",
      "tag": "http-in",
      "listen": "127.0.0.1",
      "port": 10809,
      "settings": {
        "userLevel": 8
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "fragment-out",
      "domainStrategy": "UseIP",
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      },
      "settings": {
        "fragment": {
          "packets": "tlshello",
          "length": "100-200",
          "interval": "10-20"
        }
      },
      "streamSettings": {
        "sockopt": {
          "tcpNoDelay": true,
          "domainStrategy": "UseIP"
        }
      }
    },
    {
      "protocol": "dns",
      "tag": "dns-out"
    },
    {
      "protocol": "vless",
      "tag": "fakeproxy-out",
      "domainStrategy": "",
      "settings": {
        "vnext": [
          {
            "address": "google.com",
            "port": 443,
            "users": [
              {
                "encryption": "none",
                "flow": "",
                "id": "3e992e24-b4de-4fea-9e34-2ae3d9aee34e",
                "level": 8,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "tlsSettings": {
          "allowInsecure": false,
          "alpn": [
            "h2",
            "http/1.1"
          ],
          "fingerprint": "randomized",
          "publicKey": "",
          "serverName": "google.com",
          "shortId": "",
          "show": false,
          "spiderX": ""
        },
        "wsSettings": {
          "headers": {
            "Host": "google.com"
          },
          "path": "/"
        }
      },
      "mux": {
        "concurrency": 8,
        "enabled": false
      }
    }
  ],
  "policy": {
    "levels": {
      "8": {
        "connIdle": 300,
        "downlinkOnly": 1,
        "handshake": 4,
        "uplinkOnly": 1
      }
    },
    "system": {
      "statsOutboundUplink": true,
      "statsOutboundDownlink": true
    }
  },
  "routing": {
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      {
        "inboundTag": [
          "socks-in",
          "http-in"
        ],
        "type": "field",
        "port": "8443",
        "outboundTag": "dns-out",
        "enabled": true
      },
      {
        "inboundTag": [
          "socks-in",
          "http-in"
        ],
        "type": "field",
        "port": "0-65535",
        "outboundTag": "fragment-out",
        "enabled": true
      }
    ],
    "strategy": "rules"
  },
  "stats": {}
}
]

V2rayNG v1.8.17 (Lib v26, Xray core v1.8.8)

@XRaySup
Copy link

XRaySup commented Mar 24, 2024

Hi @vfarid
Farid jan,
When we import multiple json config then it drops the observatory section of the json config.

"routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "ip": [ "1.1.1.1" ], "outboundTag": "direct", "port": "53", "type": "field" }, { "domain": [ "geosite:private", "geosite:category-ir", "domain:.ir" ], "outboundTag": "direct", "type": "field" }, { "ip": [ "geoip:private", "geoip:ir" ], "outboundTag": "direct", "type": "field" }, { "domain": [ "geosite:category-ads-all", "geosite:category-ads-ir" ], "outboundTag": "block", "type": "field" }, { "balancerTag": "all", "type": "field", "network": "tcp,udp" } ], "balancers": [ { "tag": "all", "selector": [ "proxy" ], "strategy": { "type": "leastPing" } } ] }, "observatory": { "probeInterval": "5m", "probeURL": "https:\/\/api.github.com\/_private\/browser\/stats", "subjectSelector": [ "proxy" ], "EnableConcurrency": true },

If i import a single config then its ok. But if i use the new feature this will drop this section and this config wont work.

@vfarid
Copy link
Contributor Author

vfarid commented Mar 24, 2024

Hi @vfarid Farid jan, When we import multiple json config then it drops the observatory section of the json config.

"routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "ip": [ "1.1.1.1" ], "outboundTag": "direct", "port": "53", "type": "field" }, { "domain": [ "geosite:private", "geosite:category-ir", "domain:.ir" ], "outboundTag": "direct", "type": "field" }, { "ip": [ "geoip:private", "geoip:ir" ], "outboundTag": "direct", "type": "field" }, { "domain": [ "geosite:category-ads-all", "geosite:category-ads-ir" ], "outboundTag": "block", "type": "field" }, { "balancerTag": "all", "type": "field", "network": "tcp,udp" } ], "balancers": [ { "tag": "all", "selector": [ "proxy" ], "strategy": { "type": "leastPing" } } ] }, "observatory": { "probeInterval": "5m", "probeURL": "https:\/\/api.github.com\/_private\/browser\/stats", "subjectSelector": [ "proxy" ], "EnableConcurrency": true },

If i import a single config then its ok. But if i use the new feature this will drop this section and this config wont work.

According to the documentation, observatory field is not supportrd by xray-core.

@XRaySup
Copy link

XRaySup commented Mar 24, 2024

Hi @vfarid Farid jan, When we import multiple json config then it drops the observatory section of the json config.
"routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "ip": [ "1.1.1.1" ], "outboundTag": "direct", "port": "53", "type": "field" }, { "domain": [ "geosite:private", "geosite:category-ir", "domain:.ir" ], "outboundTag": "direct", "type": "field" }, { "ip": [ "geoip:private", "geoip:ir" ], "outboundTag": "direct", "type": "field" }, { "domain": [ "geosite:category-ads-all", "geosite:category-ads-ir" ], "outboundTag": "block", "type": "field" }, { "balancerTag": "all", "type": "field", "network": "tcp,udp" } ], "balancers": [ { "tag": "all", "selector": [ "proxy" ], "strategy": { "type": "leastPing" } } ] }, "observatory": { "probeInterval": "5m", "probeURL": "https:\/\/api.github.com\/_private\/browser\/stats", "subjectSelector": [ "proxy" ], "EnableConcurrency": true },
If i import a single config then its ok. But if i use the new feature this will drop this section and this config wont work.

According to the documentation, observatory field is not supportrd by xray-core.

We already use it in v2rayng .
Refer to this code in xray core
https://github.com/XTLS/Xray-core/blob/9a619f9e7c5d92867b248f6bba55c35cbff7dfdd/features/extension/observatory.go#L10

@XRaySup
Copy link

XRaySup commented Mar 24, 2024

Also note that it has been considered in sanaei
MHSanaei/3x-ui@ac5d8af
We have leastping leastload
Which needs these observatory

@X-Oracle
Copy link

According to the documentation, observatory field is not supportrd by xray-core.

It is supported but not documented
You can look at the code and you will understand .

Also why does it even should be added. Shouldn't it just copy the configs?

@vfarid
Copy link
Contributor Author

vfarid commented Mar 24, 2024

According to the documentation, observatory field is not supportrd by xray-core.

It is supported but not documented You can look at the code and you will understand .

Also why does it even should be added. Shouldn't it just copy the configs?

It is not implemented in v2rayNG till now, if you sure it is supported by xray-core (i didnt find it inside documentation), you may create a seperate issue/pr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet