Compare commits

..

7 Commits

Author SHA1 Message Date
Shtorm
6f6af8e902 Fix examples 2026-06-05 00:51:50 +03:00
Shtorm
6cddffd546 provider: replace flag emojis with country codes in removeEmojisFromTags 2026-06-05 00:28:09 +03:00
Shtorm
a59e9ec9e3 Fix TrustTunnel 2026-06-04 10:57:08 +03:00
Shtorm
9ebec50a72 Merge branch 'extended' of https://github.com/shtorm-7/sing-box-extended into extended 2026-06-04 10:12:06 +03:00
Shtorm
7a0354699a Update README.md
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-06-04 08:22:24 +03:00
Shtorm
978b951169 Merge branch 'extended' of https://github.com/shtorm-7/sing-box-extended into extended 2026-06-04 08:20:58 +03:00
Shtorm
0577c28120 Update README.md
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-06-04 04:36:45 +03:00
6 changed files with 69 additions and 13 deletions

View File

@@ -13,7 +13,7 @@ Sing-box with extended features.
- **MASQUE** — Cloudflare MASQUE proxy over QUIC / HTTP-2
- **MTProxy** — Telegram MTProxy server with FakeTLS and domain fronting
- **Mieru** — Secure, hard to classify, hard to probe network protocol
- **OpenVPN** — OpenVPN client with tls-auth, tls-crypt, and tls-crypt-v2 support
- **OpenVPN** — OpenVPN client with tls-auth, tls-crypt and tls-crypt-v2 support
- **TrustTunnel** — AdGuard's obfuscated VPN protocol, indistinguishable from HTTPS traffic
- **Sudoku** — Traffic obfuscation protocol based on 4×4 Sudoku puzzles with low-entropy fingerprints
- **VPN** — Routed tunnel over any TCP sing-box protocol

View File

@@ -289,11 +289,21 @@ func uniquifyTags(opts []option.Outbound) {
func removeEmojisFromTags(opts []option.Outbound) {
for i, opt := range opts {
cleaned := emojiRegex.ReplaceAllString(opt.Tag, "")
cleaned := flagRegex.ReplaceAllStringFunc(opt.Tag, flagToCountryCode)
cleaned = emojiRegex.ReplaceAllString(cleaned, "")
cleaned = multiSpaceRegex.ReplaceAllString(cleaned, " ")
opts[i].Tag = strings.TrimSpace(cleaned)
}
}
func flagToCountryCode(flag string) string {
runes := []rune(flag)
if len(runes) == 2 {
return string(rune(runes[0]-0x1F1E6+'A')) + string(rune(runes[1]-0x1F1E6+'A')) + " "
}
return ""
}
var flagRegex = regexp.MustCompile(`[\x{1F1E6}-\x{1F1FF}]{2}`)
var emojiRegex = regexp.MustCompile(`[\x{1F1E0}-\x{1F1FF}\x{1F300}-\x{1F9FF}\x{2600}-\x{27BF}\x{FE00}-\x{FE0F}\x{200D}]+`)
var multiSpaceRegex = regexp.MustCompile(`\s{2,}`)

View File

@@ -0,0 +1,45 @@
package provider
import (
"testing"
"github.com/sagernet/sing-box/option"
)
func TestFlagToCountryCodeAllFlags(t *testing.T) {
for first := 'A'; first <= 'Z'; first++ {
for second := 'A'; second <= 'Z'; second++ {
flag := string(rune(0x1F1E6+(first-'A'))) + string(rune(0x1F1E6+(second-'A')))
expected := string(first) + string(second)
result := flagToCountryCode(flag)
// flagToCountryCode appends a space
if result != expected+" " {
t.Errorf("flagToCountryCode(%q) = %q, want %q", expected, result, expected+" ")
}
}
}
}
func TestRemoveEmojisFromTags(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"🇺🇸 United States", "US United States"},
{"🇷🇺 Россия", "RU Россия"},
{"🇩🇪 Germany 🚀", "DE Germany"},
{"🇫🇷🇬🇧 France-UK", "FR GB France-UK"},
{"No emojis here", "No emojis here"},
{"🌍 World", "World"},
{"🇯🇵 Tokyo ⚡ Fast", "JP Tokyo Fast"},
{"Germany 🇩🇪", "Germany DE"},
{"Server 🇺🇸 Node", "Server US Node"},
}
for _, tt := range tests {
opts := []option.Outbound{{Tag: tt.input}}
removeEmojisFromTags(opts)
if opts[0].Tag != tt.expected {
t.Errorf("removeEmojisFromTags(%q) = %q, want %q", tt.input, opts[0].Tag, tt.expected)
}
}
}

View File

@@ -29,6 +29,7 @@
"use_ipv6": false,
"profile": {
"detour": "direct",
// For getting existing MASQUE device profile, else sing-box will create new profile
"id": "",
"auth_token": ""
},
@@ -36,7 +37,7 @@
"udp_keepalive_period": "30s",
"udp_initial_packet_size": 0,
"reconnect_delay": "5s",
"tls": {
"tls": { // TLS fields for HTTP2
"insecure": false,
"cipher_suites": [],
"curve_preferences": [],

2
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/sagernet/sing-box
go 1.26.1
go 1.26.4
require (
github.com/AliRizaAynaci/gorl/v2 v2.2.0

View File

@@ -89,6 +89,15 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
}
var err error
if common.Contains(h.network, N.NetworkTCP) {
h.httpTLSConfig, err = tls.NewServer(h.ctx, h.logger, common.PtrValueOrDefault(h.options.TLS))
if err != nil {
return err
}
if len(h.httpTLSConfig.NextProtos()) == 0 {
h.httpTLSConfig.SetNextProtos([]string{http2.NextProtoTLS})
} else if !common.Contains(h.httpTLSConfig.NextProtos(), http2.NextProtoTLS) {
h.httpTLSConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, h.httpTLSConfig.NextProtos()...))
}
listener, err := h.listener.ListenTCP()
if err != nil {
return err
@@ -99,15 +108,6 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
return h.ctx
},
}
h.httpTLSConfig, err = tls.NewServer(h.ctx, h.logger, common.PtrValueOrDefault(h.options.TLS))
if err != nil {
return err
}
if len(h.httpTLSConfig.NextProtos()) == 0 {
h.httpTLSConfig.SetNextProtos([]string{http2.NextProtoTLS})
} else if !common.Contains(h.httpTLSConfig.NextProtos(), http2.NextProtoTLS) {
h.httpTLSConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, h.httpTLSConfig.NextProtos()...))
}
err = h.httpTLSConfig.Start()
if err != nil {
return err