Update On Mon Aug 11 20:44:01 CEST 2025

This commit is contained in:
github-action[bot]
2025-08-11 20:44:01 +02:00
parent 003692a62c
commit 7a3097a4a2
157 changed files with 3677 additions and 857 deletions

1
.github/update.log vendored
View File

@@ -1086,3 +1086,4 @@ Update On Thu Aug 7 20:45:01 CEST 2025
Update On Fri Aug 8 20:38:56 CEST 2025
Update On Sat Aug 9 20:40:00 CEST 2025
Update On Sun Aug 10 20:40:02 CEST 2025
Update On Mon Aug 11 20:43:53 CEST 2025

View File

@@ -456,7 +456,7 @@ func NewVless(option VlessOption) (*Vless, error) {
option: &option,
}
if s := strings.Split(option.Encryption, "-mlkem768client-"); len(s) == 2 {
if s := strings.SplitN(option.Encryption, "-", 4); len(s) == 4 && s[2] == "mlkem768client" {
var minutes uint32
if s[0] != "1rtt" {
t := strings.TrimSuffix(s[0], "min")
@@ -470,14 +470,22 @@ func NewVless(option VlessOption) (*Vless, error) {
}
minutes = uint32(i)
}
var xor uint32
switch s[1] {
case "vless":
case "aes128xor":
xor = 1
default:
return nil, fmt.Errorf("invaild vless encryption value: %s", option.Encryption)
}
var b []byte
b, err = base64.RawURLEncoding.DecodeString(s[1])
b, err = base64.RawURLEncoding.DecodeString(s[3])
if err != nil {
return nil, fmt.Errorf("invaild vless encryption value: %s", option.Encryption)
}
if len(b) == 1184 {
if len(b) == encryption.MLKEM768ClientLength {
v.encryption = &encryption.ClientInstance{}
if err = v.encryption.Init(b, time.Duration(minutes)*time.Minute); err != nil {
if err = v.encryption.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
}
} else {

View File

@@ -221,6 +221,9 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
if flow := query.Get("flow"); flow != "" {
vless["flow"] = strings.ToLower(flow)
}
if encryption := query.Get("encryption"); encryption != "" {
vless["encryption"] = encryption
}
proxies = append(proxies, vless)
case "vmess":

View File

@@ -46,16 +46,16 @@ func Main(args []string) {
}
fmt.Println("Config:", configBase64)
fmt.Println("Key:", keyPem)
case "vless-mlkem768-keypair":
case "vless-mlkem768":
var seed string
if len(args) > 1 {
seed = args[1]
}
seedBase64, pubBase64, err := encryption.GenMLKEM768(seed)
seedBase64, clientBase64, err := encryption.GenMLKEM768(seed)
if err != nil {
panic(err)
}
fmt.Println("Seed: " + seedBase64)
fmt.Println("Client: " + pubBase64)
fmt.Println("Client: " + clientBase64)
}
}

View File

@@ -170,7 +170,7 @@ type realityVerifier struct {
//var pOffset = utils.MustOK(reflect.TypeOf((*utls.Conn)(nil)).Elem().FieldByName("peerCertificates")).Offset
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
//log.Debugln("REALITY localAddr: %v\t is using X25519MLKEM768 for TLS' communication: %v", c.RemoteAddr(), c.HandshakeState.ServerHello.SelectedGroup == utls.X25519MLKEM768)
log.Debugln("REALITY localAddr: %v is using X25519MLKEM768 for TLS' communication: %v", c.RemoteAddr(), c.HandshakeState.ServerHello.ServerShare.Group == utls.X25519MLKEM768)
//p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
//certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset))
certs := c.Conn.PeerCertificates()

View File

@@ -1,3 +1,12 @@
// Package wildcard modified IGLOU-EU/go-wildcard to support:
//
// `*` matches zero or more characters
// `?` matches exactly one character
//
// The original go-wildcard library used `.` to match exactly one character, and `?` to match zero or one character.
// `.` is a valid delimiter in domain name matching and should not be used as a wildcard.
// The `?` matching logic strictly matches only one character in most scenarios.
// So, the `?` matching logic in the original go-wildcard library has been removed and its wildcard `.` has been replaced with `?`.
package wildcard
// copy and modified from https://github.com/IGLOU-EU/go-wildcard/tree/ce22b7af48e487517a492d3727d9386492043e21
@@ -16,12 +25,10 @@ func Match(pattern, s string) bool {
}
func matchByString(pattern, s string) bool {
var lastErotemeCluster byte
var patternIndex, sIndex, lastStar, lastEroteme int
var patternIndex, sIndex, lastStar int
patternLen := len(pattern)
sLen := len(s)
star := -1
eroteme := -1
Loop:
if sIndex >= sLen {
@@ -38,14 +45,8 @@ Loop:
return false
}
switch pattern[patternIndex] {
// Removed dot matching as it conflicts with dot in domains.
// case '.':
// It matches any single character. So, we don't need to check anything.
case '?':
// '?' matches one character. Store its position and match exactly one character in the string.
eroteme = patternIndex
lastEroteme = sIndex
lastErotemeCluster = byte(s[sIndex])
// It matches any single character. So, we don't need to check anything.
case '*':
// '*' matches zero or more characters. Store its position and increment the pattern index.
star = patternIndex
@@ -53,15 +54,8 @@ Loop:
patternIndex++
goto Loop
default:
// If the characters don't match, check if there was a previous '?' or '*' to backtrack.
// If the characters don't match, check if there was a previous '*' to backtrack.
if pattern[patternIndex] != s[sIndex] {
if eroteme != -1 {
patternIndex = eroteme + 1
sIndex = lastEroteme
eroteme = -1
goto Loop
}
if star != -1 {
patternIndex = star + 1
lastStar++
@@ -71,29 +65,18 @@ Loop:
return false
}
// If the characters match, check if it was not the same to validate the eroteme.
if eroteme != -1 && lastErotemeCluster != byte(s[sIndex]) {
eroteme = -1
}
}
patternIndex++
sIndex++
goto Loop
// Check if the remaining pattern characters are '*' or '?', which can match the end of the string.
// Check if the remaining pattern characters are '*', which can match the end of the string.
checkPattern:
if patternIndex < patternLen {
if pattern[patternIndex] == '*' {
patternIndex++
goto checkPattern
} else if pattern[patternIndex] == '?' {
if sIndex >= sLen {
sIndex--
}
patternIndex++
goto checkPattern
}
}

View File

@@ -25,31 +25,17 @@ func TestMatch(t *testing.T) {
{"", "", true},
{"", "*", true},
{"", "**", true},
{"", "?", true},
{"", "??", true},
{"", "?*", true},
{"", "*?", true},
{"", ".", false},
{"", ".?", false},
{"", "?.", false},
{"", ".*", false},
{"", "*.", false},
{"", "*.?", false},
{"", "?.*", false},
{"", "?", false},
{"", "?*", false},
{"", "*?", false},
{"a", "", false},
{"a", "a", true},
{"a", "*", true},
{"a", "**", true},
{"a", "?", true},
{"a", "??", true},
{"a", ".", false},
{"a", ".?", false},
{"a", "?.", false},
{"a", ".*", false},
{"a", "*.", false},
{"a", "*.?", false},
{"a", "?.*", false},
{"a", "?*", true},
{"a", "*?", true},
{"match the exact string", "match the exact string", true},
{"do not match a different string", "this is a different string", false},
@@ -68,22 +54,27 @@ func TestMatch(t *testing.T) {
{"match a string with a ?", "match ? string with a ?", true},
{"match a string with a ? at the beginning", "?atch a string with a ? at the beginning", true},
{"match a string with two ?", "match a string with two ??", true},
{"match a optional char with a ?", "match a optional? char with a ?", true},
{"match a optional char with a ?", "match a optional? char with a ?", true},
{"do not match a string with extra and a ?", "do not match ? string with extra and a ? like this", false},
{"match a string with two ?", "match a ??ring with two ?", true},
{"do not match a string with extra ?", "do not match a string with extra ??", false},
{"do not match a string with a .", "do not match . string with a .", false},
{"do not match a string with a . at the beginning", "do not .atch a string with a . at the beginning", false},
{"do not match a string with two .", "do not match a ..ring with two .", false},
{"do not match a string with extra .", "do not match a string with extra ..", false},
{"abc.edf.hjg", "abc.edf.hjg", true},
{"abc.edf.hjg", "ab.cedf.hjg", false},
{"abc.edf.hjg", "abc.edfh.jg", false},
{"abc.edf.hjg", "abc.edf.hjq", false},
{"A big brown fox jumps over the lazy dog, with all there wildcards friends", ". big?brown fox jumps over * wildcard. friend??", false},
{"A big brown fox fails to jump over the lazy dog, with all there wildcards friends", ". big?brown fox jumps over * wildcard. friend??", false},
{"abc.edf.hjg", "abc.*.hjg", true},
{"abc.edf.hjg", "abc.*.hjq", false},
{"abc.edf.hjg", "abc*hjg", true},
{"abc.edf.hjg", "abc*hjq", false},
{"abc.edf.hjg", "a*g", true},
{"abc.edf.hjg", "a*q", false},
{"domain a.b.c", "domain a.b.c", true},
{"domain adb.c", "domain a.b.c", false},
{"aaaa", "a*a", true},
{"abc.edf.hjg", "ab?.edf.hjg", true},
{"abc.edf.hjg", "?b?.edf.hjg", true},
{"abc.edf.hjg", "??c.edf.hjg", true},
{"abc.edf.hjg", "a??.edf.hjg", true},
{"abc.edf.hjg", "ab??.edf.hjg", false},
{"abc.edf.hjg", "??.edf.hjg", false},
}
for i, c := range cases {
@@ -96,10 +87,106 @@ func TestMatch(t *testing.T) {
}
}
func match(pattern, name string) bool { // https://research.swtch.com/glob
px := 0
nx := 0
nextPx := 0
nextNx := 0
for px < len(pattern) || nx < len(name) {
if px < len(pattern) {
c := pattern[px]
switch c {
default: // ordinary character
if nx < len(name) && name[nx] == c {
px++
nx++
continue
}
case '?': // single-character wildcard
if nx < len(name) {
px++
nx++
continue
}
case '*': // zero-or-more-character wildcard
// Try to match at nx.
// If that doesn't work out,
// restart at nx+1 next.
nextPx = px
nextNx = nx + 1
px++
continue
}
}
// Mismatch. Maybe restart.
if 0 < nextNx && nextNx <= len(name) {
px = nextPx
nx = nextNx
continue
}
return false
}
// Matched all of pattern to all of name. Success.
return true
}
func FuzzMatch(f *testing.F) {
f.Fuzz(func(t *testing.T, s string) {
if !Match(string(s), string(s)) {
t.Fatalf("%s does not match %s", s, s)
f.Fuzz(func(t *testing.T, pattern, name string) {
result1 := Match(pattern, name)
result2 := match(pattern, name)
if result1 != result2 {
t.Fatalf("Match failed for pattern `%s` and name `%s`", pattern, name)
}
})
}
func BenchmarkMatch(b *testing.B) {
cases := []struct {
s string
pattern string
result bool
}{
{"abc.edf.hjg", "abc.edf.hjg", true},
{"abc.edf.hjg", "ab.cedf.hjg", false},
{"abc.edf.hjg", "abc.edfh.jg", false},
{"abc.edf.hjg", "abc.edf.hjq", false},
{"abc.edf.hjg", "abc.*.hjg", true},
{"abc.edf.hjg", "abc.*.hjq", false},
{"abc.edf.hjg", "abc*hjg", true},
{"abc.edf.hjg", "abc*hjq", false},
{"abc.edf.hjg", "a*g", true},
{"abc.edf.hjg", "a*q", false},
{"abc.edf.hjg", "ab?.edf.hjg", true},
{"abc.edf.hjg", "?b?.edf.hjg", true},
{"abc.edf.hjg", "??c.edf.hjg", true},
{"abc.edf.hjg", "a??.edf.hjg", true},
{"abc.edf.hjg", "ab??.edf.hjg", false},
{"abc.edf.hjg", "??.edf.hjg", false},
{"r4.cdn-aa-wow-this-is-long-a1.video-yajusenpai1145141919810-oh-hell-yeah-this-is-also-very-long-and-sukka-the-fox-has-a-very-big-fluffy-fox-tail-ao-wu-ao-wu-regex-and-wildcard-both-might-have-deadly-back-tracing-issue-be-careful-or-use-linear-matching.com", "*.cdn-*-*.video**.com", true},
}
b.Run("Match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, c := range cases {
result := Match(c.pattern, c.s)
if c.result != result {
b.Errorf("Test %d: Expected `%v`, found `%v`; With Pattern: `%s` and String: `%s`", i+1, c.result, result, c.pattern, c.s)
}
}
}
})
b.Run("match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, c := range cases {
result := match(c.pattern, c.s)
if c.result != result {
b.Errorf("Test %d: Expected `%v`, found `%v`; With Pattern: `%s` and String: `%s`", i+1, c.result, result, c.pattern, c.s)
}
}
}
})
}

View File

@@ -638,7 +638,8 @@ proxies: # socks5
port: 443
uuid: uuid
network: tcp
encryption: "8min-mlkem768client-bas64RawURLEncoding" # 复用八分钟后协商新的 sharedKey需小于服务端的值
encryption: "8min-vless-mlkem768client-bas64RawURLEncoding" # 复用八分钟后协商新的 sharedKey需小于服务端的值
# encryption: "8min-aes128xor-mlkem768client-bas64RawURLEncoding"
tls: false #可以不开启tls
udp: true
@@ -1346,7 +1347,8 @@ listeners:
flow: xtls-rprx-vision
# ws-path: "/" # 如果不为空则开启 websocket 传输层
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
# decryption: "10min-mlkem768seed-bas64RawURLEncoding" # 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式, 后面base64字符串可由可由 mihomo generate vless-mlkem768 命令生成
# decryption: "10min-vless-mlkem768seed-bas64RawURLEncoding" # 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式, 后面base64字符串可由可由 mihomo generate vless-mlkem768 命令生成
# decryption: "10min-aes128xor-mlkem768seed-bas64RawURLEncoding"
# 下面两项如果填写则开启 tls需要同时填写
# certificate: ./server.crt
# private-key: ./server.key

View File

@@ -35,7 +35,7 @@ require (
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
github.com/metacubex/utls v1.8.1-0.20250810142204-d0e55ab2e852
github.com/metacubex/utls v1.8.1-0.20250811145843-49b4f106169a
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20
github.com/mroth/weightedrand/v2 v2.1.0

View File

@@ -139,10 +139,8 @@ github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113a
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/utls v1.8.1-0.20250810142204-d0e55ab2e852 h1:MLHUGmASNH7/AeoGmSrVM2RutRZAqIDSbQWBp0P7ItE=
github.com/metacubex/utls v1.8.1-0.20250810142204-d0e55ab2e852/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/utls v1.8.1-0.20250811145843-49b4f106169a h1:IIzlVmDoB4+7b0BUcLZaY5+AirhhLFep3PhwkAFMRnQ=
github.com/metacubex/utls v1.8.1-0.20250811145843-49b4f106169a/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=

View File

@@ -89,18 +89,29 @@ func TestInboundVless_TLS(t *testing.T) {
}
func TestInboundVless_Encryption(t *testing.T) {
seedBase64, pubBase64, err := encryption.GenMLKEM768("")
seedBase64, clientBase64, err := encryption.GenMLKEM768("")
if err != nil {
t.Fatal(err)
return
}
t.Run("-vless-", func(t *testing.T) {
inboundOptions := inbound.VlessOption{
Decryption: "10min-mlkem768seed-" + seedBase64,
Decryption: "10min-vless-mlkem768seed-" + seedBase64,
}
outboundOptions := outbound.VlessOption{
Encryption: "8min-mlkem768client-" + pubBase64,
Encryption: "8min-vless-mlkem768client-" + clientBase64,
}
testInboundVless(t, inboundOptions, outboundOptions)
})
t.Run("-aes128xor-", func(t *testing.T) {
inboundOptions := inbound.VlessOption{
Decryption: "10min-aes128xor-mlkem768seed-" + seedBase64,
}
outboundOptions := outbound.VlessOption{
Encryption: "8min-aes128xor-mlkem768client-" + clientBase64,
}
testInboundVless(t, inboundOptions, outboundOptions)
})
}
func TestInboundVless_Wss1(t *testing.T) {

View File

@@ -88,7 +88,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
sl = &Listener{config: config, service: service}
if s := strings.Split(config.Decryption, "-mlkem768seed-"); len(s) == 2 {
if s := strings.SplitN(config.Decryption, "-", 4); len(s) == 4 && s[2] == "mlkem768seed" {
var minutes uint32
if s[0] != "1rtt" {
t := strings.TrimSuffix(s[0], "min")
@@ -102,14 +102,22 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
minutes = uint32(i)
}
var xor uint32
switch s[1] {
case "vless":
case "aes128xor":
xor = 1
default:
return nil, fmt.Errorf("invaild vless decryption value: %s", config.Decryption)
}
var b []byte
b, err = base64.RawURLEncoding.DecodeString(s[1])
b, err = base64.RawURLEncoding.DecodeString(s[3])
if err != nil {
return nil, fmt.Errorf("invaild vless decryption value: %s", config.Decryption)
}
if len(b) == 64 {
if len(b) == encryption.MLKEM768SeedLength {
sl.decryption = &encryption.ServerInstance{}
if err = sl.decryption.Init(b, time.Duration(minutes)*time.Minute); err != nil {
if err = sl.decryption.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
}
} else {

View File

@@ -38,17 +38,18 @@ func init() {
type ClientInstance struct {
sync.RWMutex
eKeyNfs *mlkem.EncapsulationKey768
xor uint32
minutes time.Duration
expire time.Time
baseKey []byte
reuse []byte
ticket []byte
}
type ClientConn struct {
net.Conn
instance *ClientInstance
baseKey []byte
reuse []byte
ticket []byte
random []byte
aead cipher.AEAD
nonce []byte
@@ -57,8 +58,9 @@ type ClientConn struct {
peerCache []byte
}
func (i *ClientInstance) Init(eKeyNfsData []byte, minutes time.Duration) (err error) {
func (i *ClientInstance) Init(eKeyNfsData []byte, xor uint32, minutes time.Duration) (err error) {
i.eKeyNfs, err = mlkem.NewEncapsulationKey768(eKeyNfsData)
i.xor = xor
i.minutes = minutes
return
}
@@ -67,6 +69,9 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.eKeyNfs == nil {
return nil, errors.New("uninitialized")
}
if i.xor == 1 {
conn = NewXorConn(conn, i.eKeyNfs.Bytes())
}
c := &ClientConn{Conn: conn}
if i.minutes > 0 {
@@ -74,7 +79,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
if time.Now().Before(i.expire) {
c.instance = i
c.baseKey = i.baseKey
c.reuse = i.reuse
c.ticket = i.ticket
i.RUnlock()
return c, nil
}
@@ -104,7 +109,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
return nil, err
}
encapsulatedPfsKey := peerServerHello[:1088]
c.reuse = peerServerHello[1088:]
c.ticket = peerServerHello[1088:]
pfsKey, err := dKeyPfs.Decapsulate(encapsulatedPfsKey)
if err != nil {
@@ -115,7 +120,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
authKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, encapsulatedNfsKey, eKeyPfs).Read(authKey)
nonce := make([]byte, 12)
VLESS, _ := newAead(ClientCipher, authKey).Open(nil, nonce, c.reuse, encapsulatedPfsKey)
VLESS, _ := newAead(ClientCipher, authKey).Open(nil, nonce, c.ticket, encapsulatedPfsKey)
if !bytes.Equal(VLESS, []byte("VLESS")) { // TODO: more message
return nil, errors.New("invalid server")
}
@@ -124,7 +129,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
i.Lock()
i.expire = time.Now().Add(i.minutes)
i.baseKey = c.baseKey
i.reuse = c.reuse
i.ticket = c.ticket
i.Unlock()
}
@@ -140,12 +145,12 @@ func (c *ClientConn) Write(b []byte) (int, error) {
c.random = make([]byte, 32)
rand.Read(c.random)
key := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, c.random, c.reuse).Read(key)
hkdf.New(sha256.New, c.baseKey, c.random, c.ticket).Read(key)
c.aead = newAead(ClientCipher, key)
c.nonce = make([]byte, 12)
data = make([]byte, 21+32+5+len(b)+16)
copy(data, c.reuse)
copy(data, c.ticket)
copy(data[21:], c.random)
encodeHeader(data[53:], len(b)+16)
c.aead.Seal(data[:58], c.nonce, b, data[53:58])
@@ -210,7 +215,7 @@ func (c *ClientConn) Read(b []byte) (int, error) { // after first Write()
if err != nil {
if c.instance != nil {
c.instance.Lock()
if bytes.Equal(c.reuse, c.instance.reuse) {
if bytes.Equal(c.ticket, c.instance.ticket) {
c.instance.expire = time.Now() // expired
}
c.instance.Unlock()

View File

@@ -1,3 +1,5 @@
// Package encryption copy and modify from xray-core
// https://github.com/XTLS/Xray-core/commit/f61c14e9c63dc41a8a09135db3aea337974f3f37
// https://github.com/XTLS/Xray-core/commit/3e19bf9233bdd9bafc073a71c65b737cc1ffba5e
// https://github.com/XTLS/Xray-core/commit/7ffb555fc8ec51bd1e3e60f26f1d6957984dba80
package encryption

View File

@@ -8,7 +8,10 @@ import (
"github.com/metacubex/utls/mlkem"
)
func GenMLKEM768(seedStr string) (seedBase64, pubBase64 string, err error) {
const MLKEM768SeedLength = mlkem.SeedSize
const MLKEM768ClientLength = mlkem.EncapsulationKeySize768
func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) {
var seed [64]byte
if len(seedStr) > 0 {
s, _ := base64.RawURLEncoding.DecodeString(seedStr)
@@ -27,6 +30,6 @@ func GenMLKEM768(seedStr string) (seedBase64, pubBase64 string, err error) {
key, _ := mlkem.NewDecapsulationKey768(seed[:])
pub := key.EncapsulationKey()
seedBase64 = base64.RawURLEncoding.EncodeToString(seed[:])
pubBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes())
clientBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes())
return
}

View File

@@ -25,6 +25,7 @@ type ServerSession struct {
type ServerInstance struct {
sync.RWMutex
dKeyNfs *mlkem.DecapsulationKey768
xor uint32
minutes time.Duration
sessions map[[21]byte]*ServerSession
stop bool
@@ -34,7 +35,7 @@ type ServerConn struct {
net.Conn
cipher byte
baseKey []byte
reuse []byte
ticket []byte
peerRandom []byte
peerAead cipher.AEAD
peerNonce []byte
@@ -43,8 +44,9 @@ type ServerConn struct {
nonce []byte
}
func (i *ServerInstance) Init(dKeyNfsData []byte, minutes time.Duration) (err error) {
func (i *ServerInstance) Init(dKeyNfsData []byte, xor uint32, minutes time.Duration) (err error) {
i.dKeyNfs, err = mlkem.NewDecapsulationKey768(dKeyNfsData)
i.xor = xor
if minutes > 0 {
i.minutes = minutes
i.sessions = make(map[[21]byte]*ServerSession)
@@ -79,22 +81,25 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.dKeyNfs == nil {
return nil, errors.New("uninitialized")
}
if i.xor == 1 {
conn = NewXorConn(conn, i.dKeyNfs.EncapsulationKey().Bytes())
}
c := &ServerConn{Conn: conn}
peerReuseHello := make([]byte, 21+32)
if _, err := io.ReadFull(c.Conn, peerReuseHello); err != nil {
peerTicketHello := make([]byte, 21+32)
if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil {
return nil, err
}
if i.minutes > 0 {
i.RLock()
s := i.sessions[[21]byte(peerReuseHello)]
s := i.sessions[[21]byte(peerTicketHello)]
i.RUnlock()
if s != nil {
if _, replay := s.randoms.LoadOrStore([32]byte(peerReuseHello[21:]), true); !replay {
if _, replay := s.randoms.LoadOrStore([32]byte(peerTicketHello[21:]), true); !replay {
c.cipher = s.cipher
c.baseKey = s.baseKey
c.reuse = peerReuseHello[:21]
c.peerRandom = peerReuseHello[21:]
c.ticket = peerTicketHello[:21]
c.peerRandom = peerTicketHello[21:]
return c, nil
}
}
@@ -106,11 +111,11 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
}
if l, _ := decodeHeader(peerHeader); l != 0 {
c.Conn.Write(make([]byte, randBetween(100, 1000))) // make client do new handshake
return nil, errors.New("invalid reuse")
return nil, errors.New("invalid ticket")
}
peerClientHello := make([]byte, 1088+1184+1)
copy(peerClientHello, peerReuseHello)
copy(peerClientHello, peerTicketHello)
copy(peerClientHello[53:], peerHeader)
if _, err := io.ReadFull(c.Conn, peerClientHello[58:]); err != nil {
return nil, err
@@ -136,13 +141,13 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
authKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, encapsulatedNfsKey, eKeyPfsData).Read(authKey)
nonce := make([]byte, 12)
c.reuse = newAead(c.cipher, authKey).Seal(nil, nonce, []byte("VLESS"), encapsulatedPfsKey)
c.ticket = newAead(c.cipher, authKey).Seal(nil, nonce, []byte("VLESS"), encapsulatedPfsKey)
padding := randBetween(100, 1000)
serverHello := make([]byte, 1088+21+5+padding)
copy(serverHello, encapsulatedPfsKey)
copy(serverHello[1088:], c.reuse)
copy(serverHello[1088:], c.ticket)
encodeHeader(serverHello[1109:], int(padding))
if _, err := c.Conn.Write(serverHello); err != nil {
@@ -151,7 +156,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.minutes > 0 {
i.Lock()
i.sessions[[21]byte(c.reuse)] = &ServerSession{
i.sessions[[21]byte(c.ticket)] = &ServerSession{
expire: time.Now().Add(i.minutes),
cipher: c.cipher,
baseKey: c.baseKey,
@@ -181,12 +186,12 @@ func (c *ServerConn) Read(b []byte) (int, error) {
return 0, err
}
}
peerIndex := make([]byte, 21)
copy(peerIndex, peerHeader)
if _, err := io.ReadFull(c.Conn, peerIndex[5:]); err != nil {
peerTicket := make([]byte, 21)
copy(peerTicket, peerHeader)
if _, err := io.ReadFull(c.Conn, peerTicket[5:]); err != nil {
return 0, err
}
if !bytes.Equal(peerIndex, c.reuse) {
if !bytes.Equal(peerTicket, c.ticket) {
return 0, errors.New("naughty boy")
}
c.peerRandom = make([]byte, 32)
@@ -195,7 +200,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
}
}
peerKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, c.peerRandom, c.reuse).Read(peerKey)
hkdf.New(sha256.New, c.baseKey, c.peerRandom, c.ticket).Read(peerKey)
c.peerAead = newAead(c.cipher, peerKey)
c.peerNonce = make([]byte, 12)
}

View File

@@ -0,0 +1,63 @@
package encryption
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"net"
)
type XorConn struct {
net.Conn
key []byte
ctr cipher.Stream
peerCtr cipher.Stream
}
func NewXorConn(conn net.Conn, key []byte) *XorConn {
return &XorConn{Conn: conn, key: key[:16]}
}
func (c *XorConn) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
var iv []byte
if c.ctr == nil {
block, _ := aes.NewCipher(c.key)
iv = make([]byte, 16)
rand.Read(iv)
c.ctr = cipher.NewCTR(block, iv)
}
c.ctr.XORKeyStream(b, b) // caller MUST discard b
if iv != nil {
b = append(iv, b...)
}
if _, err := c.Conn.Write(b); err != nil {
return 0, err
}
if iv != nil {
b = b[16:]
}
return len(b), nil
}
func (c *XorConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
if c.peerCtr == nil {
peerIv := make([]byte, 16)
if _, err := io.ReadFull(c.Conn, peerIv); err != nil {
return 0, err
}
block, _ := aes.NewCipher(c.key)
c.peerCtr = cipher.NewCTR(block, peerIv)
}
n, err := c.Conn.Read(b)
if n > 0 {
c.peerCtr.XORKeyStream(b[:n], b[:n])
}
return n, err
}

View File

@@ -32,8 +32,8 @@
"country-emoji": "1.5.6",
"dayjs": "1.11.13",
"framer-motion": "12.23.12",
"i18next": "25.3.2",
"jotai": "2.13.0",
"i18next": "25.3.4",
"jotai": "2.13.1",
"json-schema": "0.4.0",
"material-react-table": "3.2.1",
"monaco-editor": "0.52.2",
@@ -56,12 +56,12 @@
"@csstools/normalize.css": "12.1.1",
"@emotion/babel-plugin": "11.13.5",
"@emotion/react": "11.14.0",
"@iconify/json": "2.2.368",
"@iconify/json": "2.2.371",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.84.2",
"@tanstack/react-router": "1.131.2",
"@tanstack/react-router-devtools": "1.131.2",
"@tanstack/router-plugin": "1.131.2",
"@tanstack/react-router": "1.131.3",
"@tanstack/react-router-devtools": "1.131.3",
"@tanstack/router-plugin": "1.131.3",
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
"@tauri-apps/plugin-dialog": "2.3.0",
"@tauri-apps/plugin-fs": "2.4.0",

View File

@@ -2,10 +2,10 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.12",
"mihomo_alpha": "alpha-e89af72",
"mihomo_alpha": "alpha-3a0d267",
"clash_rs": "v0.8.2",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.8.2-alpha+sha.2a8be3b"
"clash_rs_alpha": "0.8.2-alpha+sha.ec9134e"
},
"arch_template": {
"mihomo": {
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-08-09T22:21:17.093Z"
"updated_at": "2025-08-10T22:21:15.754Z"
}

View File

@@ -250,7 +250,7 @@ importers:
version: 4.1.11
'@tanstack/router-zod-adapter':
specifier: 1.81.5
version: 1.81.5(@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)
version: 1.81.5(@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)
'@tauri-apps/api':
specifier: 2.6.0
version: 2.6.0
@@ -276,11 +276,11 @@ importers:
specifier: 12.23.12
version: 12.23.12(@emotion/is-prop-valid@1.3.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
i18next:
specifier: 25.3.2
version: 25.3.2(typescript@5.9.2)
specifier: 25.3.4
version: 25.3.4(typescript@5.9.2)
jotai:
specifier: 2.13.0
version: 2.13.0(@babel/core@7.28.0)(@babel/template@7.27.2)(@types/react@19.1.9)(react@19.1.1)
specifier: 2.13.1
version: 2.13.1(@babel/core@7.28.0)(@babel/template@7.27.2)(@types/react@19.1.9)(react@19.1.1)
json-schema:
specifier: 0.4.0
version: 0.4.0
@@ -310,7 +310,7 @@ importers:
version: 7.6.2(dc790e3d871a3fe7e1d22dc6e321e397)
react-i18next:
specifier: 15.6.1
version: 15.6.1(i18next@25.3.2(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
version: 15.6.1(i18next@25.3.4(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
react-markdown:
specifier: 10.1.0
version: 10.1.0(@types/react@19.1.9)(react@19.1.1)
@@ -343,8 +343,8 @@ importers:
specifier: 11.14.0
version: 11.14.0(@types/react@19.1.9)(react@19.1.1)
'@iconify/json':
specifier: 2.2.368
version: 2.2.368
specifier: 2.2.371
version: 2.2.371
'@monaco-editor/react':
specifier: 4.7.0
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -352,14 +352,14 @@ importers:
specifier: 5.84.2
version: 5.84.2(react@19.1.1)
'@tanstack/react-router':
specifier: 1.131.2
version: 1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
specifier: 1.131.3
version: 1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-router-devtools':
specifier: 1.131.2
version: 1.131.2(@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.2)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)
specifier: 1.131.3
version: 1.131.3(@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.3)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)
'@tanstack/router-plugin':
specifier: 1.131.2
version: 1.131.2(@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.1(@types/node@22.17.1)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.3)(yaml@2.8.0))
specifier: 1.131.3
version: 1.131.3(@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.1(@types/node@22.17.1)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.3)(yaml@2.8.0))
'@tauri-apps/plugin-clipboard-manager':
specifier: 2.3.0
version: 2.3.0
@@ -509,7 +509,7 @@ importers:
version: 6.0.0(react@19.1.1)
react-i18next:
specifier: 15.6.1
version: 15.6.1(i18next@25.3.2(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
version: 15.6.1(i18next@25.3.4(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2)
react-use:
specifier: 17.6.0
version: 17.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -1753,8 +1753,8 @@ packages:
'@vue/compiler-sfc':
optional: true
'@iconify/json@2.2.368':
resolution: {integrity: sha512-gxz87+V5og+kYRc8jp0YTGgImusCpZLFVd+QzIVH5GwA9zQlMe2BvK9dhIHKSWlP1fZ7blKFKVqKKaCNoRCEiA==}
'@iconify/json@2.2.371':
resolution: {integrity: sha512-dnamUrgw8aDWz4STJOkQqqCz6GB2s7SHGPIY84EVQmlVXzM7T1V7L/csdL7r9bkA3AHF80+OXhx7o4FXn5L8pQ==}
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
@@ -2939,16 +2939,16 @@ packages:
peerDependencies:
react: ^18 || ^19
'@tanstack/react-router-devtools@1.131.2':
resolution: {integrity: sha512-7bJxZadqjZrsdPOcKWp2+sc8cnARHzrgr/eduDJDA79Rbx7qEh8TgAY7xFqlhShCxA90/a9y4wastbs8AqnDcA==}
'@tanstack/react-router-devtools@1.131.3':
resolution: {integrity: sha512-opouR8dbBrDnkHdiyTVPb3rTfSRxWN+ZGi1YuEXNGUXgirvnpQUTWNP6kzDv1at29DxymwwfRRYD602MjZOOlA==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.131.2
'@tanstack/react-router': ^1.131.3
react: '>=18.0.0 || >=19.0.0'
react-dom: '>=18.0.0 || >=19.0.0'
'@tanstack/react-router@1.131.2':
resolution: {integrity: sha512-MGkCPA/7HJ9UWIV27CtKb5i3Sizxywx43/h+ifrEC+2guzQR8yBcI4ibwMmSpsuGqKOzkuvX63RU1SVeCwbg+g==}
'@tanstack/react-router@1.131.3':
resolution: {integrity: sha512-1wxsStYJai0/ssOQeO+8mh5VmMmJWIZOtIEEqDxIhQX4dHyurKl6khl34+qLtDvWFsj6zgiMwjID3GQj5SMz1w==}
engines: {node: '>=12'}
peerDependencies:
react: '>=18.0.0 || >=19.0.0'
@@ -2973,15 +2973,15 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
'@tanstack/router-core@1.131.2':
resolution: {integrity: sha512-ITnzlVk9iZTYNe/1FuLnDhpDTml1PfzUZk3V5He+NrXIcPGd2h3plZlv6NqZirNZMhCoiX52jfM1BOHGuy1ICA==}
'@tanstack/router-core@1.131.3':
resolution: {integrity: sha512-8sby4n2pgRJ7qZrFvuS6v21oBDHCRoFM8p+/HAIra2d32cD5wS5k9DeNltWFUAJFXdsdwpdGVA0iXSAc0WfIHw==}
engines: {node: '>=12'}
'@tanstack/router-devtools-core@1.131.2':
resolution: {integrity: sha512-j7++EKhxbB8JXFqbZH6fRdCge7pujqrFrBEDDpNX7ms3EY7MwAcqiYE4qqY9YsJhfAOjZWo+88KEzX9AB09twA==}
'@tanstack/router-devtools-core@1.131.3':
resolution: {integrity: sha512-GQHVCE0ywJ0ajz9K52RLAhbDSuziD3MVRYYp5S5w2i31Mb9xkzITJe/CZ7WIgOuY+XQm18P8drbJnxdHTNOcWQ==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/router-core': ^1.131.2
'@tanstack/router-core': ^1.131.3
csstype: ^3.0.10
solid-js: '>=1.9.5'
tiny-invariant: ^1.3.3
@@ -2989,16 +2989,16 @@ packages:
csstype:
optional: true
'@tanstack/router-generator@1.131.2':
resolution: {integrity: sha512-A4IW5zmAV5NrRCf2UXONA47DLSEXPaIcPL3Bmi6MHmA8QaWkoJ7frTHv82QE8DmyIsv2Y7c0CfINy2K5KET0Tw==}
'@tanstack/router-generator@1.131.3':
resolution: {integrity: sha512-sTsi9lSxBCpAExQWyh3k2X40biiRHjIRISxVvko5sPG/+NKYFjGaQwgXQ/1jiDSTqe8i7/b/2l94ZJPTa6VPxQ==}
engines: {node: '>=12'}
'@tanstack/router-plugin@1.131.2':
resolution: {integrity: sha512-+F/Orgn4Gi69WBn+aRmVezGbbk/Uk8viciSkdeQUpU2cWtMSR2EFU2xjFG06YCTX92jcZAYfSRQMpStncRXJQQ==}
'@tanstack/router-plugin@1.131.3':
resolution: {integrity: sha512-PLCjxTTHBf5H9TqH+jTNvgSnnCZhvrLj61C5XAtONA7NUv+Lh4xJ/u0nn83ZYb7uFM4rMg1JmpU5mG8iNbGHZw==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=1.0.2'
'@tanstack/react-router': ^1.131.2
'@tanstack/react-router': ^1.131.3
vite: '>=5.0.0 || >=6.0.0'
vite-plugin-solid: ^2.11.2
webpack: '>=5.92.0'
@@ -5482,8 +5482,8 @@ packages:
hyphenate-style-name@1.1.0:
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
i18next@25.3.2:
resolution: {integrity: sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA==}
i18next@25.3.4:
resolution: {integrity: sha512-AHklEYFLiRRxW1Cb6zE9lfnEtYvsydRC8nRS3RSKGX3zCqZ8nLZwMaUsrb80YuccPNv2RNokDL8LkTNnp+6mDw==}
peerDependencies:
typescript: ^5
peerDependenciesMeta:
@@ -5896,8 +5896,8 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
jotai@2.13.0:
resolution: {integrity: sha512-H43zXdanNTdpfOEJ4NVbm4hgmrctpXLZagjJNcqAywhUv+sTE7esvFjwm5oBg/ywT9Qw63lIkM6fjrhFuW8UDg==}
jotai@2.13.1:
resolution: {integrity: sha512-cRsw6kFeGC9Z/D3egVKrTXRweycZ4z/k7i2MrfCzPYsL9SIWcPXTyqv258/+Ay8VUEcihNiE/coBLE6Kic6b8A==}
engines: {node: '>=12.20.0'}
peerDependencies:
'@babel/core': '>=7.0.0'
@@ -9953,7 +9953,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@iconify/json@2.2.368':
'@iconify/json@2.2.371':
dependencies:
'@iconify/types': 2.0.0
pathe: 1.1.2
@@ -11040,10 +11040,10 @@ snapshots:
'@tanstack/query-core': 5.83.1
react: 19.1.1
'@tanstack/react-router-devtools@1.131.2(@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.2)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
'@tanstack/react-router-devtools@1.131.3(@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@tanstack/router-core@1.131.3)(csstype@3.1.3)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/router-devtools-core': 1.131.2(@tanstack/router-core@1.131.2)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
'@tanstack/react-router': 1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/router-devtools-core': 1.131.3(@tanstack/router-core@1.131.3)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
transitivePeerDependencies:
@@ -11052,11 +11052,11 @@ snapshots:
- solid-js
- tiny-invariant
'@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
'@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@tanstack/history': 1.131.2
'@tanstack/react-store': 0.7.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/router-core': 1.131.2
'@tanstack/router-core': 1.131.3
isbot: 5.1.28
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
@@ -11082,7 +11082,7 @@ snapshots:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
'@tanstack/router-core@1.131.2':
'@tanstack/router-core@1.131.3':
dependencies:
'@tanstack/history': 1.131.2
'@tanstack/store': 0.7.0
@@ -11092,9 +11092,9 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
'@tanstack/router-devtools-core@1.131.2(@tanstack/router-core@1.131.2)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
'@tanstack/router-devtools-core@1.131.3(@tanstack/router-core@1.131.3)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/router-core': 1.131.2
'@tanstack/router-core': 1.131.3
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
solid-js: 1.9.5
@@ -11102,9 +11102,9 @@ snapshots:
optionalDependencies:
csstype: 3.1.3
'@tanstack/router-generator@1.131.2':
'@tanstack/router-generator@1.131.3':
dependencies:
'@tanstack/router-core': 1.131.2
'@tanstack/router-core': 1.131.3
'@tanstack/router-utils': 1.131.2
'@tanstack/virtual-file-routes': 1.131.2
prettier: 3.6.2
@@ -11115,7 +11115,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@tanstack/router-plugin@1.131.2(@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.1(@types/node@22.17.1)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.3)(yaml@2.8.0))':
'@tanstack/router-plugin@1.131.3(@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(vite@7.1.1(@types/node@22.17.1)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.3)(yaml@2.8.0))':
dependencies:
'@babel/core': 7.28.0
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0)
@@ -11123,8 +11123,8 @@ snapshots:
'@babel/template': 7.27.2
'@babel/traverse': 7.28.0
'@babel/types': 7.28.1
'@tanstack/router-core': 1.131.2
'@tanstack/router-generator': 1.131.2
'@tanstack/router-core': 1.131.3
'@tanstack/router-generator': 1.131.3
'@tanstack/router-utils': 1.131.2
'@tanstack/virtual-file-routes': 1.131.2
babel-dead-code-elimination: 1.0.10
@@ -11132,7 +11132,7 @@ snapshots:
unplugin: 2.3.5
zod: 3.25.76
optionalDependencies:
'@tanstack/react-router': 1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-router': 1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
vite: 7.1.1(@types/node@22.17.1)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.30.1)(sass-embedded@1.90.0)(sass@1.90.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.20.3)(yaml@2.8.0)
transitivePeerDependencies:
- supports-color
@@ -11148,9 +11148,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)':
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(zod@4.0.17)':
dependencies:
'@tanstack/react-router': 1.131.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-router': 1.131.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
zod: 4.0.17
'@tanstack/store@0.7.0': {}
@@ -14090,9 +14090,9 @@ snapshots:
hyphenate-style-name@1.1.0: {}
i18next@25.3.2(typescript@5.9.2):
i18next@25.3.4(typescript@5.9.2):
dependencies:
'@babel/runtime': 7.27.6
'@babel/runtime': 7.28.2
optionalDependencies:
typescript: 5.9.2
@@ -14464,7 +14464,7 @@ snapshots:
jju@1.4.0: {}
jotai@2.13.0(@babel/core@7.28.0)(@babel/template@7.27.2)(@types/react@19.1.9)(react@19.1.1):
jotai@2.13.1(@babel/core@7.28.0)(@babel/template@7.27.2)(@types/react@19.1.9)(react@19.1.1):
optionalDependencies:
'@babel/core': 7.28.0
'@babel/template': 7.27.2
@@ -15717,11 +15717,11 @@ snapshots:
dependencies:
react: 19.1.1
react-i18next@15.6.1(i18next@25.3.2(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2):
react-i18next@15.6.1(i18next@25.3.4(typescript@5.9.2))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.9.2):
dependencies:
'@babel/runtime': 7.27.6
html-parse-stringify: 3.0.1
i18next: 25.3.2(typescript@5.9.2)
i18next: 25.3.4(typescript@5.9.2)
react: 19.1.1
optionalDependencies:
react-dom: 19.1.1(react@19.1.1)

View File

@@ -2304,6 +2304,7 @@ CONFIG_HARDEN_BRANCH_HISTORY=y
# CONFIG_HI6421V600_IRQ is not set
# CONFIG_HI8435 is not set
# CONFIG_HIBERNATION is not set
# CONFIG_HIBERNATION_COMP_LZ4 is not set
# CONFIG_HID is not set
# CONFIG_HIDRAW is not set
# CONFIG_HID_A4TECH is not set

View File

@@ -11,6 +11,7 @@ FEATURES:=audio display ext4 pcie boot-part rootfs-part rtc usb targz
SUBTARGETS:=generic
KERNEL_PATCHVER:=6.6
KERNEL_TESTING_PATCHVER:=6.12
KERNELNAME:=vmlinuz.efi dtbs

View File

@@ -0,0 +1,754 @@
# CONFIG_16KB_2LEVEL is not set
CONFIG_16KB_3LEVEL=y
# CONFIG_4KB_3LEVEL is not set
# CONFIG_4KB_4LEVEL is not set
CONFIG_64BIT=y
# CONFIG_64KB_2LEVEL is not set
# CONFIG_64KB_3LEVEL is not set
CONFIG_AC97_BUS=y
CONFIG_ACPI=y
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
# CONFIG_ACPI_BGRT is not set
CONFIG_ACPI_BUTTON=y
CONFIG_ACPI_CONTAINER=y
CONFIG_ACPI_CPU_FREQ_PSS=y
# CONFIG_ACPI_DEBUG is not set
# CONFIG_ACPI_DEBUGGER is not set
# CONFIG_ACPI_DOCK is not set
# CONFIG_ACPI_EC_DEBUGFS is not set
CONFIG_ACPI_FAN=y
# CONFIG_ACPI_FFH is not set
CONFIG_ACPI_GENERIC_GSI=y
CONFIG_ACPI_HOTPLUG_CPU=y
CONFIG_ACPI_I2C_OPREGION=y
CONFIG_ACPI_MCFG=y
CONFIG_ACPI_NHLT=y
# CONFIG_ACPI_PCI_SLOT is not set
# CONFIG_ACPI_PFRUT is not set
CONFIG_ACPI_PPTT=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_ACPI_SLEEP=y
# CONFIG_ACPI_SPCR_TABLE is not set
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
CONFIG_ACPI_TABLE_UPGRADE=y
# CONFIG_ACPI_TAD is not set
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_THERMAL_LIB=y
CONFIG_ACPI_VIDEO=y
CONFIG_APERTURE_HELPERS=y
CONFIG_ARCH_DISABLE_KASAN_INLINE=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
# CONFIG_ARCH_IOREMAP is not set
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_ARCH_MMAP_RND_BITS=12
CONFIG_ARCH_MMAP_RND_BITS_MAX=18
CONFIG_ARCH_MMAP_RND_BITS_MIN=12
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_STACKWALK=y
CONFIG_ARCH_STRICT_ALIGN=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_WANTS_NO_INSTR=y
CONFIG_ARCH_WANTS_THP_SWAP=y
# CONFIG_ARCH_WRITECOMBINE is not set
CONFIG_ASN1=y
CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_ATA=y
CONFIG_ATA_ACPI=y
CONFIG_ATA_FORCE=y
# CONFIG_ATA_SFF is not set
CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_AUDIT=y
CONFIG_AUDITSYSCALL=y
CONFIG_AUDIT_GENERIC=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BLK_CGROUP=y
CONFIG_BLK_CGROUP_IOCOST=y
CONFIG_BLK_CGROUP_RWSTAT=y
CONFIG_BLK_DEBUG_FS=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_DEV_INTEGRITY=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NVME=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_BLK_DEV_ZONED=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_PM=y
CONFIG_BLK_RQ_ALLOC_TIME=y
CONFIG_BLK_SED_OPAL=y
CONFIG_BLK_WBT=y
CONFIG_BLK_WBT_MQ=y
CONFIG_BLOCK_LEGACY_AUTOLOAD=y
CONFIG_BOOT_PRINTK_DELAY=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_BUFFER_HEAD=y
CONFIG_BUG_ON_DATA_CORRUPTION=y
# CONFIG_BUILTIN_DTB is not set
CONFIG_CACHESTAT_SYSCALL=y
CONFIG_CDROM=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_CGROUPS=y
# CONFIG_CGROUP_BPF is not set
# CONFIG_CGROUP_CPUACCT is not set
# CONFIG_CGROUP_DEBUG is not set
# CONFIG_CGROUP_DEVICE is not set
# CONFIG_CGROUP_FREEZER is not set
# CONFIG_CGROUP_HUGETLB is not set
# CONFIG_CGROUP_NET_CLASSID is not set
# CONFIG_CGROUP_NET_PRIO is not set
# CONFIG_CGROUP_PIDS is not set
# CONFIG_CGROUP_RDMA is not set
CONFIG_CGROUP_SCHED=y
CONFIG_CHECKPOINT_RESTORE=y
CONFIG_CHR_DEV_SG=y
CONFIG_CLZ_TAB=y
CONFIG_CMA=y
CONFIG_CMA_ALIGNMENT=8
CONFIG_CMA_AREAS=7
# CONFIG_CMA_DEBUGFS is not set
CONFIG_CMA_SIZE_MBYTES=16
# CONFIG_CMA_SIZE_SEL_MAX is not set
CONFIG_CMA_SIZE_SEL_MBYTES=y
# CONFIG_CMA_SIZE_SEL_MIN is not set
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
# CONFIG_CMA_SYSFS is not set
CONFIG_CMDLINE_BOOTLOADER=y
CONFIG_COMMON_CLK=y
# CONFIG_COMMON_CLK_LOONGSON2 is not set
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
# CONFIG_COMPAT_32BIT_TIME is not set
CONFIG_CONNECTOR=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTEXT_TRACKING_IDLE=y
CONFIG_CONTIG_ALLOC=y
CONFIG_COREDUMP=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_CPUSETS=y
# CONFIG_CPUSETS_V1 is not set
CONFIG_CPU_HAS_FPU=y
CONFIG_CPU_HAS_LASX=y
CONFIG_CPU_HAS_LBT=y
CONFIG_CPU_HAS_LSX=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_ISOLATION=y
CONFIG_CPU_MITIGATIONS=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CRC16=y
CONFIG_CRC64=y
CONFIG_CRC64_ROCKSOFT=y
CONFIG_CRC_T10DIF=y
CONFIG_CROSS_MEMORY_ATTACH=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CRC32=y
CONFIG_CRYPTO_CRC32C=y
# CONFIG_CRYPTO_CRC32_LOONGARCH is not set
CONFIG_CRYPTO_CRC64_ROCKSOFT=y
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
CONFIG_CRYPTO_LIB_SHA1=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_RSA=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_MISC=y
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_DEVFREQ_GOV_PASSIVE is not set
# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set
# CONFIG_DEVFREQ_GOV_USERSPACE is not set
CONFIG_DEVFREQ_THERMAL=y
CONFIG_DEVMEM=y
CONFIG_DEVTMPFS=y
CONFIG_DMA_CMA=y
CONFIG_DMA_NEED_SYNC=y
CONFIG_DMA_SHARED_BUFFER=y
CONFIG_DMI=y
CONFIG_DMIID=y
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
CONFIG_DMI_SYSFS=y
CONFIG_DRM=y
CONFIG_DRM_BRIDGE=y
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
CONFIG_DRM_KMS_HELPER=y
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
CONFIG_DRM_LOONGSON=y
CONFIG_DRM_PANEL=y
CONFIG_DRM_PANEL_BRIDGE=y
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
CONFIG_DRM_TTM=y
CONFIG_DRM_TTM_HELPER=y
# CONFIG_DRM_WERROR is not set
CONFIG_DTC=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_EFI=y
CONFIG_EFIVAR_FS=m
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_COCO_SECRET is not set
CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
# CONFIG_EFI_DISABLE_PCI_DMA is not set
# CONFIG_EFI_DISABLE_RUNTIME is not set
CONFIG_EFI_EARLYCON=y
CONFIG_EFI_ESRT=y
CONFIG_EFI_GENERIC_STUB=y
CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_STUB=y
# CONFIG_EFI_TEST is not set
CONFIG_EFI_ZBOOT=y
CONFIG_ELF_CORE=y
CONFIG_ENCRYPTED_KEYS=y
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
CONFIG_EXPORTFS_BLOCK_OPS=y
CONFIG_EXT4_FS=y
CONFIG_FAILOVER=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_FANOTIFY=y
CONFIG_FB=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_CORE=y
CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_DEVICE=y
CONFIG_FB_EFI=y
CONFIG_FB_IOMEM_FOPS=y
CONFIG_FB_IOMEM_HELPERS=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_SIMPLE=y
CONFIG_FB_SYSMEM_FOPS=y
CONFIG_FB_SYSMEM_HELPERS=y
CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_IMAGEBLIT=y
CONFIG_FB_TILEBLITTING=y
CONFIG_FHANDLE=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FIRMWARE_TABLE=y
CONFIG_FIX_EARLYCON_MEM=y
# CONFIG_FLATMEM_MANUAL is not set
CONFIG_FONTS=y
# CONFIG_FONT_10x18 is not set
# CONFIG_FONT_6x10 is not set
# CONFIG_FONT_6x11 is not set
# CONFIG_FONT_7x14 is not set
CONFIG_FONT_8x16=y
CONFIG_FONT_8x8=y
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_SUN8x16 is not set
CONFIG_FONT_SUPPORT=y
CONFIG_FONT_TER16x32=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FREEZER=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_FUNCTION_ALIGNMENT=0
CONFIG_FW_CACHE=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_FW_LOADER_SYSFS=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_DEVICES=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_GENERIC_CSUM=y
CONFIG_GENERIC_ENTRY=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IOREMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_LIB_ASHLDI3=y
CONFIG_GENERIC_LIB_ASHRDI3=y
CONFIG_GENERIC_LIB_CMPDI2=y
CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
CONFIG_GENERIC_LIB_LSHRDI3=y
CONFIG_GENERIC_LIB_UCMPDI2=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GLOB=y
CONFIG_GPIO_ACPI=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_CDEV_V1=y
# CONFIG_GPIO_LOONGSON_64BIT is not set
CONFIG_GROUP_SCHED_WEIGHT=y
CONFIG_HAMRADIO=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HDMI=y
CONFIG_HIBERNATE_CALLBACKS=y
CONFIG_HIBERNATION=y
CONFIG_HIBERNATION_COMP_LZO=y
CONFIG_HIBERNATION_DEF_COMP="lzo"
CONFIG_HIBERNATION_SNAPSHOT_DEV=y
CONFIG_HID=y
CONFIG_HIDRAW=y
CONFIG_HID_GENERIC=y
CONFIG_HID_SUPPORT=y
CONFIG_HOTPLUG_CPU=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
CONFIG_HWMON=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
CONFIG_HZ_PERIODIC=y
CONFIG_I2C=y
CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_AMD_MP2 is not set
CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_LS2X is not set
# CONFIG_I2C_ZHAOXIN is not set
CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INIT_STACK_ALL_ZERO=y
# CONFIG_INIT_STACK_NONE is not set
CONFIG_INPUT=y
CONFIG_INPUT_KEYBOARD=y
CONFIG_INPUT_LEDS=y
# CONFIG_INPUT_MISC is not set
CONFIG_INPUT_MOUSE=y
CONFIG_INPUT_MOUSEDEV=y
CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_SPARSEKMAP=y
# CONFIG_IOMMUFD is not set
# CONFIG_IOMMU_DEBUGFS is not set
CONFIG_IOMMU_SUPPORT=y
CONFIG_IO_URING=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_LOONGARCH_CPU=y
CONFIG_IRQ_MSI_LIB=y
CONFIG_IRQ_POLL=y
CONFIG_IRQ_WORK=y
# CONFIG_ISCSI_IBFT is not set
CONFIG_ISO9660_FS=y
CONFIG_JBD2=y
CONFIG_JUMP_LABEL=y
CONFIG_KALLSYMS=y
CONFIG_KCMP=y
CONFIG_KERNEL_GZIP=y
CONFIG_KEYS=y
CONFIG_KSM=y
CONFIG_L1_CACHE_SHIFT=6
CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_LEDS_TRIGGER_DISK=y
CONFIG_LEDS_TRIGGER_MTD=y
CONFIG_LEDS_TRIGGER_PANIC=y
CONFIG_LEGACY_TIOCSTI=y
CONFIG_LIBFDT=y
CONFIG_LOCKUP_DETECTOR=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LOONGARCH=y
CONFIG_LOONGARCH_PLATFORM_DEVICES=y
# CONFIG_LOONGSON2_GUTS is not set
# CONFIG_LOONGSON2_PM is not set
# CONFIG_LOONGSON2_THERMAL is not set
CONFIG_LOONGSON_EIOINTC=y
CONFIG_LOONGSON_HTVEC=y
CONFIG_LOONGSON_LAPTOP=y
CONFIG_LOONGSON_LIOINTC=y
CONFIG_LOONGSON_PCH_LPC=y
CONFIG_LOONGSON_PCH_MSI=y
CONFIG_LOONGSON_PCH_PIC=y
CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf"
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MACH_LOONGSON64=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
CONFIG_MAGIC_SYSRQ_SERIAL=y
# CONFIG_MEMCG is not set
CONFIG_MEMORY=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_MIGRATION=y
CONFIG_MMU_GATHER_MERGE_VMAS=y
CONFIG_MMU_LAZY_TLB_REFCOUNT=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MOUSE_BCM5974 is not set
# CONFIG_MOUSE_CYAPA is not set
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
CONFIG_MOUSE_PS2_BYD=y
CONFIG_MOUSE_PS2_CYPRESS=y
# CONFIG_MOUSE_PS2_ELANTECH is not set
CONFIG_MOUSE_PS2_LOGIPS2PP=y
CONFIG_MOUSE_PS2_SMBUS=y
CONFIG_MOUSE_PS2_SYNAPTICS=y
CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y
# CONFIG_MOUSE_PS2_TOUCHKIT is not set
CONFIG_MOUSE_PS2_TRACKPOINT=y
# CONFIG_MOUSE_SERIAL is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
CONFIG_MPILIB=y
CONFIG_MQ_IOSCHED_DEADLINE=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
# CONFIG_NET_CLS_CGROUP is not set
CONFIG_NET_DEVMEM=y
CONFIG_NET_EGRESS=y
CONFIG_NET_FAILOVER=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_INGRESS=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NET_XGRESS=y
CONFIG_NLS=y
CONFIG_NR_CPUS=64
CONFIG_NVMEM=y
CONFIG_NVMEM_LAYOUTS=y
CONFIG_NVMEM_SYSFS=y
CONFIG_NVME_CORE=y
CONFIG_NVME_HWMON=y
CONFIG_NVME_MULTIPATH=y
CONFIG_NVME_VERBOSE_ERRORS=y
# CONFIG_N_HDLC is not set
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OID_REGISTRY=y
CONFIG_PADATA=y
CONFIG_PAGE_EXTENSION=y
CONFIG_PAGE_POISONING=y
CONFIG_PAGE_POOL=y
CONFIG_PAGE_POOL_STATS=y
CONFIG_PAGE_REPORTING=y
CONFIG_PAGE_SHIFT=14
CONFIG_PAGE_SIZE_16KB=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
# CONFIG_PANIC_ON_OOPS is not set
CONFIG_PANIC_ON_OOPS_VALUE=0
CONFIG_PATA_TIMINGS=y
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_PERFORMANCE is not set
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
CONFIG_PCIEPORTBUS=y
CONFIG_PCIE_DPC=y
# CONFIG_PCIE_EDR is not set
CONFIG_PCIE_PME=y
CONFIG_PCIE_PTM=y
CONFIG_PCI_ATS=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_ECAM=y
CONFIG_PCI_IOV=y
CONFIG_PCI_LABEL=y
CONFIG_PCI_LOONGSON=y
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_ARCH_FALLBACKS=y
CONFIG_PCI_REALLOC_ENABLE_AUTO=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_3LEVEL=y
CONFIG_PGTABLE_HAS_HUGE_LEAVES=y
CONFIG_PGTABLE_LEVELS=3
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_PM=y
# CONFIG_PMIC_OPREGION is not set
CONFIG_PM_ADVANCED_DEBUG=y
CONFIG_PM_CLK=y
CONFIG_PM_DEBUG=y
CONFIG_PM_DEVFREQ=y
# CONFIG_PM_DEVFREQ_EVENT is not set
CONFIG_PM_OPP=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_DEBUG=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_PM_STD_PARTITION=""
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_PNP=y
CONFIG_PNPACPI=y
# CONFIG_PNP_DEBUG_MESSAGES is not set
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_POWER_SUPPLY=y
CONFIG_POWER_SUPPLY_HWMON=y
CONFIG_PPS=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_PREEMPT_VOLUNTARY_BUILD=y
CONFIG_PRINTK_TIME=y
CONFIG_PROC_CHILDREN=y
CONFIG_PROC_EVENTS=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RANDSTRUCT_NONE=y
CONFIG_RAS=y
CONFIG_RATIONAL=y
# CONFIG_RAVE_SP_CORE is not set
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGMAP_SPI=y
CONFIG_RELAY=y
CONFIG_RELOCATABLE=y
CONFIG_RESET_ATTACK_MITIGATION=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RSEQ=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_LOONGSON=y
CONFIG_RTC_I2C_AND_SPI=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_HOST=y
# CONFIG_SATA_ZPODD is not set
CONFIG_SCHEDSTATS=y
CONFIG_SCHED_AUTOGROUP=y
# CONFIG_SCHED_CORE is not set
CONFIG_SCHED_DEBUG=y
CONFIG_SCHED_INFO=y
CONFIG_SCHED_MM_CID=y
CONFIG_SCHED_SMT=y
CONFIG_SCREEN_INFO=y
CONFIG_SCSI=y
CONFIG_SCSI_COMMON=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_PCILIB=y
CONFIG_SERIAL_8250_PERICOM=y
CONFIG_SERIAL_8250_PNP=y
CONFIG_SERIAL_8250_RSA=y
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_DEV_BUS=y
CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_NONSTANDARD=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_LIBPS2=y
CONFIG_SERIO_SERPORT=y
CONFIG_SGL_ALLOC=y
CONFIG_SG_POOL=y
CONFIG_SMP=y
CONFIG_SND=y
CONFIG_SND_AC97_CODEC=y
CONFIG_SND_COMPRESS_OFFLOAD=y
CONFIG_SND_CTL_LED=y
CONFIG_SND_DYNAMIC_MINORS=y
CONFIG_SND_HDA=y
# CONFIG_SND_HDA_CODEC_ANALOG is not set
# CONFIG_SND_HDA_CODEC_CA0110 is not set
# CONFIG_SND_HDA_CODEC_CA0132 is not set
# CONFIG_SND_HDA_CODEC_CIRRUS is not set
# CONFIG_SND_HDA_CODEC_CMEDIA is not set
CONFIG_SND_HDA_CODEC_CONEXANT=y
CONFIG_SND_HDA_CODEC_HDMI=y
# CONFIG_SND_HDA_CODEC_REALTEK is not set
# CONFIG_SND_HDA_CODEC_SI3054 is not set
# CONFIG_SND_HDA_CODEC_SIGMATEL is not set
# CONFIG_SND_HDA_CODEC_VIA is not set
CONFIG_SND_HDA_CORE=y
CONFIG_SND_HDA_GENERIC=y
CONFIG_SND_HDA_GENERIC_LEDS=y
CONFIG_SND_HDA_HWDEP=y
# CONFIG_SND_HDA_INPUT_BEEP is not set
CONFIG_SND_HDA_INTEL=y
# CONFIG_SND_HDA_PATCH_LOADER is not set
# CONFIG_SND_HDA_RECONFIG is not set
CONFIG_SND_HWDEP=y
CONFIG_SND_INTEL_DSP_CONFIG=y
CONFIG_SND_INTEL_NHLT=y
CONFIG_SND_INTEL_SOUNDWIRE_ACPI=y
CONFIG_SND_JACK=y
CONFIG_SND_JACK_INPUT_DEV=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM=y
CONFIG_SND_PCM_OSS=y
CONFIG_SND_PCM_TIMER=y
CONFIG_SND_RAWMIDI=y
CONFIG_SND_SEQUENCER=y
CONFIG_SND_SEQUENCER_OSS=y
CONFIG_SND_SEQ_DEVICE=y
CONFIG_SND_SEQ_DUMMY=y
CONFIG_SND_SEQ_MIDI=y
CONFIG_SND_SEQ_MIDI_EVENT=y
CONFIG_SND_SEQ_VIRMIDI=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_AC97_BUS=y
CONFIG_SND_SOC_AC97_CODEC=y
CONFIG_SND_SOC_I2C_AND_SPI=y
CONFIG_SND_SOC_LOONGSON_CARD=y
CONFIG_SND_SOC_LOONGSON_I2S_PCI=y
CONFIG_SND_TIMER=y
CONFIG_SND_VIRMIDI=y
CONFIG_SND_VMASTER=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SOFTLOCKUP_DETECTOR=y
CONFIG_SOUND=y
CONFIG_SOUND_OSS_CORE=y
CONFIG_SOUND_OSS_CORE_PRECLAIM=y
CONFIG_SPARSEMEM=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_DYNAMIC=y
CONFIG_SPI_LOONGSON_CORE=y
CONFIG_SPI_LOONGSON_PCI=y
CONFIG_SPI_LOONGSON_PLATFORM=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPLIT_PTE_PTLOCKS=y
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
CONFIG_SQUASHFS_DECOMP_SINGLE=y
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y
CONFIG_STACKTRACE=y
CONFIG_STRICT_DEVMEM=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_SWIOTLB=y
CONFIG_SYNC_FILE=y
CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW=y
CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYSFB=y
# CONFIG_SYSFB_SIMPLEFB is not set
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_TASK_XACCT=y
CONFIG_THERMAL=y
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_GOV_BANG_BANG=y
CONFIG_THERMAL_GOV_FAIR_SHARE=y
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_USER_SPACE=y
CONFIG_THERMAL_HWMON=y
CONFIG_THERMAL_OF=y
CONFIG_THERMAL_STATISTICS=y
CONFIG_THP_SWAP=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TMPFS_INODE64=y
CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
# CONFIG_TRANSPARENT_HUGEPAGE_NEVER is not set
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_UCS2_STRING=y
# CONFIG_UEVENT_HELPER is not set
# CONFIG_UNWINDER_GUESS is not set
# CONFIG_UNWINDER_ORC is not set
CONFIG_UNWINDER_PROLOGUE=y
CONFIG_USB=y
CONFIG_USB_COMMON=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_HCD_PLATFORM is not set
CONFIG_USB_EHCI_PCI=y
CONFIG_USB_HID=y
CONFIG_USB_HIDDEV=y
# CONFIG_USB_LJCA is not set
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PCI=y
# CONFIG_USB_OHCI_HCD_PLATFORM is not set
CONFIG_USB_PCI=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_UAS=y
# CONFIG_USB_UHCI_HCD is not set
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PCI=y
# CONFIG_USB_XHCI_PLATFORM is not set
CONFIG_USERFAULTFD=y
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
CONFIG_VDSO_GETRANDOM=y
CONFIG_VGA_ARB=y
CONFIG_VGA_ARB_MAX_GPUS=16
CONFIG_VIDEO=y
CONFIG_VIRTIO_VSOCKETS_COMMON=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_VSOCKETS=y
CONFIG_VSOCKETS_LOOPBACK=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_XARRAY_MULTI=y
CONFIG_XPS=y
CONFIG_XXHASH=y
# CONFIG_ZONEFS_FS is not set
CONFIG_ZONE_DMA32=y

View File

@@ -32,7 +32,7 @@ PROJECT_NAME=$(shell basename "${ROOT}")
# - pkg/version/current.go
#
# Use `tools/bump_version.sh` script to change all those files at one shot.
VERSION="3.17.1"
VERSION="3.18.0"
# Build binaries and installation packages.
.PHONY: build

View File

@@ -1,5 +1,5 @@
Package: mieru
Version: 3.17.1
Version: 3.18.0
Section: net
Priority: optional
Architecture: amd64

View File

@@ -1,5 +1,5 @@
Name: mieru
Version: 3.17.1
Version: 3.18.0
Release: 1%{?dist}
Summary: Mieru proxy client
License: GPLv3+

View File

@@ -1,5 +1,5 @@
Package: mieru
Version: 3.17.1
Version: 3.18.0
Section: net
Priority: optional
Architecture: arm64

View File

@@ -1,5 +1,5 @@
Name: mieru
Version: 3.17.1
Version: 3.18.0
Release: 1%{?dist}
Summary: Mieru proxy client
License: GPLv3+

View File

@@ -1,5 +1,5 @@
Package: mita
Version: 3.17.1
Version: 3.18.0
Section: net
Priority: optional
Architecture: amd64

View File

@@ -1,5 +1,5 @@
Name: mita
Version: 3.17.1
Version: 3.18.0
Release: 1%{?dist}
Summary: Mieru proxy server
License: GPLv3+

View File

@@ -1,5 +1,5 @@
Package: mita
Version: 3.17.1
Version: 3.18.0
Section: net
Priority: optional
Architecture: arm64

View File

@@ -1,5 +1,5 @@
Name: mita
Version: 3.17.1
Version: 3.18.0
Release: 1%{?dist}
Summary: Mieru proxy server
License: GPLv3+

View File

@@ -25,7 +25,8 @@
"mtu": 1400,
"multiplexing": {
"level": "MULTIPLEXING_HIGH"
}
},
"handshakeMode": "HANDSHAKE_NO_WAIT"
}
],
"activeProfile": "default",

View File

@@ -25,7 +25,8 @@
"mtu": 1400,
"multiplexing": {
"level": "MULTIPLEXING_HIGH"
}
},
"handshakeMode": "HANDSHAKE_NO_WAIT"
}
],
"activeProfile": "default",

View File

@@ -46,7 +46,8 @@ An example of client configuration is as follows.
"mtu": 1400,
"multiplexing": {
"level": "MULTIPLEXING_HIGH"
}
},
"handshakeMode": "HANDSHAKE_NO_WAIT"
}
],
"activeProfile": "default",
@@ -67,11 +68,12 @@ Please use a text editor to modify the following fields.
4. [Optional] If you have registered a domain name for the proxy server, please fill in the domain name in `profiles` -> `servers` -> `domainName`. Otherwise, do not modify this property.
5. Fill in `profiles` -> `servers` -> `portBindings` -> `port` with the TCP or UDP port number that mita is listening to. The port number must be the same as the one set in the proxy server. If you want to listen to a range of consecutive port numbers, you can also use the `portRange` property instead.
6. [Optional] Specify a value between 1280 and 1400 for the `profiles` -> `mtu` property. The default value is 1400. This value must be the same as proxy server.
7. [Optional] If you want to adjust the frequency of multiplexing, you can set a value for the `profiles` -> `multiplexing` -> `level` property. The values you can use here include `MULTIPLEXING_OFF`, `MULTIPLEXING_LOW`, `MULTIPLEXING_MIDDLE`, and `MULTIPLEXING_HIGH`. `MULTIPLEXING_OFF` will disable multiplexing, and the default value is `MULTIPLEXING_LOW`.
8. Please specify a value between 1025 and 65535 for the `rpcPort` property.
9. Please specify a value between 1025 and 65535 for the `socks5Port` property. This port cannot be the same as `rpcPort`.
10. [Optional] If the client needs to provide proxy services to other devices on the LAN, set the `socks5ListenLAN` property to `true`.
11. [Optional] If you want to enable HTTP / HTTPS proxy, Please specify a value between 1025 and 65535 for the `httpProxyPort` property. This port cannot be the same as `rpcPort` or `socks5Port`. If the client needs to provide HTTP / HTTPS proxy services to other devices on the LAN, set the `httpProxyListenLAN` property to `true`. If you want to disable HTTP / HTTPS proxy, please delete `httpProxyPort` and `httpProxyListenLAN` property.
7. [Optional] If you want to adjust the frequency of multiplexing, you can set a value for the `profiles` -> `multiplexing` -> `level` property. The values you can use here include `MULTIPLEXING_OFF`, `MULTIPLEXING_LOW`, `MULTIPLEXING_MIDDLE`, and `MULTIPLEXING_HIGH`. `MULTIPLEXING_OFF` will disable multiplexing. The default value is `MULTIPLEXING_LOW`.
8. [Optional] If you want to enable 0-RTT handshake, you can set the value of `profiles` -> `handshakeMode` property to `HANDSHAKE_NO_WAIT`, otherwise set it to `HANDSHAKE_STANDARD`. The default value is `HANDSHAKE_STANDARD`.
9. Please specify a value between 1025 and 65535 for the `rpcPort` property.
10. Please specify a value between 1025 and 65535 for the `socks5Port` property. This port cannot be the same as `rpcPort`.
11. [Optional] If the client needs to provide proxy services to other devices on the LAN, set the `socks5ListenLAN` property to `true`.
12. [Optional] If you want to enable HTTP / HTTPS proxy, Please specify a value between 1025 and 65535 for the `httpProxyPort` property. This port cannot be the same as `rpcPort` or `socks5Port`. If the client needs to provide HTTP / HTTPS proxy services to other devices on the LAN, set the `httpProxyListenLAN` property to `true`. If you want to disable HTTP / HTTPS proxy, please delete `httpProxyPort` and `httpProxyListenLAN` property.
If you have multiple proxy servers installed, or one server listening on multiple ports, you can add them all to the client settings. Each time a new connection is created, mieru will randomly select one of the servers and one of the ports. **If you are using multiple servers, make sure that each server has the mita proxy service started.**

View File

@@ -46,7 +46,8 @@ mieru apply config <FILE>
"mtu": 1400,
"multiplexing": {
"level": "MULTIPLEXING_HIGH"
}
},
"handshakeMode": "HANDSHAKE_NO_WAIT"
}
],
"activeProfile": "default",
@@ -68,10 +69,11 @@ mieru apply config <FILE>
5.`profiles` -> `servers` -> `portBindings` -> `port` 中填写 mita 监听的 TCP 或 UDP 端口号。这个端口号必须与代理服务器中的设置相同。如果想要监听连续的端口号,也可以改为使用 `portRange` 属性。
6. 【可选】请为 `profiles` -> `mtu` 属性中指定一个从 1280 到 1400 之间的值。默认值为 1400。这个值必须与代理服务器相同。
7. 【可选】如果想要调整多路复用的频率,是更多地创建新连接,还是更多地重用旧连接,可以为 `profiles` -> `multiplexing` -> `level` 属性设定一个值。这里可以使用的值包括 `MULTIPLEXING_OFF`, `MULTIPLEXING_LOW`, `MULTIPLEXING_MIDDLE`, `MULTIPLEXING_HIGH`。其中 `MULTIPLEXING_OFF` 会关闭多路复用功能。默认值为 `MULTIPLEXING_LOW`
8. 请为 `rpcPort` 属性指定一个从 1025 到 65535 之间的数值
9. 请为 `socks5Port` 属性指定一个从 1025 到 65535 之间的数值。该端口不能与 `rpcPort` 相同。
10. 【可选】如果客户端需要为局域网中的其他设备提供代理服务,请将 `socks5ListenLAN` 属性设置为 `true`
11. 【可选】如果要启动 HTTP / HTTPS 代理,请为 `httpProxyPort` 属性指定一个从 1025 到 65535 之间的数值。该端口不能与 `rpcPort``socks5Port` 相同。如果需要为局域网中的其他设备提供 HTTP / HTTPS 代理,请将 `httpProxyListenLAN` 属性设置为 `true`。如果不需要 HTTP / HTTPS 代理,请删除 `httpProxyPort``httpProxyListenLAN` 属性
8. 【可选】如果想开启 0-RTT 握手,请将 `profiles` -> `handshakeMode` 属性的值设置为 `HANDSHAKE_NO_WAIT`,否则请设置为 `HANDSHAKE_STANDARD`。默认值为 `HANDSHAKE_STANDARD`
9. 请为 `rpcPort` 属性指定一个从 1025 到 65535 之间的数值。
10. 请为 `socks5Port` 属性指定一个从 1025 到 65535 之间的数值。该端口不能与 `rpcPort` 相同
11. 【可选】如果客户端需要为局域网中的其他设备提供代理服务,请将 `socks5ListenLAN` 属性设置为 `true`
12. 【可选】如果要启动 HTTP / HTTPS 代理,请为 `httpProxyPort` 属性指定一个从 1025 到 65535 之间的数值。该端口不能与 `rpcPort``socks5Port` 相同。如果需要为局域网中的其他设备提供 HTTP / HTTPS 代理,请将 `httpProxyListenLAN` 属性设置为 `true`。如果不需要 HTTP / HTTPS 代理,请删除 `httpProxyPort``httpProxyListenLAN` 属性。
如果你安装了多台代理服务器或者一台服务器监听多个端口可以把它们都添加到客户端设置中。每次发起新的连接时mieru 会随机选取其中的一台服务器和一个端口。**如果使用了多台服务器,请确保每一台服务器都启动了 mita 代理服务。**

View File

@@ -18,32 +18,32 @@ Or you can manually install and configure proxy server using the steps below.
```sh
# Debian / Ubuntu - X86_64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita_3.17.1_amd64.deb
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita_3.18.0_amd64.deb
# Debian / Ubuntu - ARM 64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita_3.17.1_arm64.deb
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita_3.18.0_arm64.deb
# RedHat / CentOS / Rocky Linux - X86_64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita-3.17.1-1.x86_64.rpm
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita-3.18.0-1.x86_64.rpm
# RedHat / CentOS / Rocky Linux - ARM 64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita-3.17.1-1.aarch64.rpm
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita-3.18.0-1.aarch64.rpm
```
## Install mita package
```sh
# Debian / Ubuntu - X86_64
sudo dpkg -i mita_3.17.1_amd64.deb
sudo dpkg -i mita_3.18.0_amd64.deb
# Debian / Ubuntu - ARM 64
sudo dpkg -i mita_3.17.1_arm64.deb
sudo dpkg -i mita_3.18.0_arm64.deb
# RedHat / CentOS / Rocky Linux - X86_64
sudo rpm -Uvh --force mita-3.17.1-1.x86_64.rpm
sudo rpm -Uvh --force mita-3.18.0-1.x86_64.rpm
# RedHat / CentOS / Rocky Linux - ARM 64
sudo rpm -Uvh --force mita-3.17.1-1.aarch64.rpm
sudo rpm -Uvh --force mita-3.18.0-1.aarch64.rpm
```
Those instructions can also be used to upgrade the version of mita software package.
@@ -230,7 +230,7 @@ Below is an example to configure a proxy chain.
```
1. In the `egress` -> `proxies` property, list the information of outbound proxy servers. The current version only supports socks5 outbound, so the value of `protocol` must be set to `SOCKS5_PROXY_PROTOCOL`. If the outbound proxy server requires socks5 username and password authentication, please fill in the `socks5Authentication` property. Otherwise, please remove the `socks5Authentication` property.
2. In the `egress` -> `rules` property, list outbound rules. Outbound actions include `DIRECT`, `PROXY` and `REJECT`. `proxyNames` must be set if `PROXY` action is used. `proxyNames` needs to point to proxies that exist in `egress` -> `proxies` property.
2. In the `egress` -> `rules` property, list outbound rules. From begin to end, the first rule that matches IP address range or DNS suffix is executed. Use wildcard `"*"` to match all IP addresses or domain names. Outbound actions include `DIRECT`, `PROXY` and `REJECT`. `proxyNames` must be set if `PROXY` action is used. `proxyNames` needs to point to proxies that exist in `egress` -> `proxies` property. The default outbound action is `DIRECT`.
If you want to turn off the outbound proxy feature, simply set the `egress` property to an empty value `{}`.

View File

@@ -18,32 +18,32 @@ sudo python3 setup.py --lang=zh
```sh
# Debian / Ubuntu - X86_64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita_3.17.1_amd64.deb
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita_3.18.0_amd64.deb
# Debian / Ubuntu - ARM 64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita_3.17.1_arm64.deb
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita_3.18.0_arm64.deb
# RedHat / CentOS / Rocky Linux - X86_64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita-3.17.1-1.x86_64.rpm
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita-3.18.0-1.x86_64.rpm
# RedHat / CentOS / Rocky Linux - ARM 64
curl -LSO https://github.com/enfein/mieru/releases/download/v3.17.1/mita-3.17.1-1.aarch64.rpm
curl -LSO https://github.com/enfein/mieru/releases/download/v3.18.0/mita-3.18.0-1.aarch64.rpm
```
## 安装 mita 软件包
```sh
# Debian / Ubuntu - X86_64
sudo dpkg -i mita_3.17.1_amd64.deb
sudo dpkg -i mita_3.18.0_amd64.deb
# Debian / Ubuntu - ARM 64
sudo dpkg -i mita_3.17.1_arm64.deb
sudo dpkg -i mita_3.18.0_arm64.deb
# RedHat / CentOS / Rocky Linux - X86_64
sudo rpm -Uvh --force mita-3.17.1-1.x86_64.rpm
sudo rpm -Uvh --force mita-3.18.0-1.x86_64.rpm
# RedHat / CentOS / Rocky Linux - ARM 64
sudo rpm -Uvh --force mita-3.17.1-1.aarch64.rpm
sudo rpm -Uvh --force mita-3.18.0-1.aarch64.rpm
```
上述指令也可以用来升级 mita 软件包的版本。
@@ -230,7 +230,7 @@ mieru 客户端 -> GFW -> mita 服务器 -> cloudflare 代理客户端 -> cloudf
```
1.`egress` -> `proxies` 属性中列举出站代理服务器的信息。当前版本只支持 socks5 出站,因此 `protocol` 的值必须设定为 `SOCKS5_PROXY_PROTOCOL`。如果出站代理服务器需要 socks5 用户名和密码验证,请填写 `socks5Authentication` 属性。否则,请删除 `socks5Authentication` 属性。
2.`egress` -> `rules` 属性中列举出站规则。出站行为包括 `DIRECT``PROXY``REJECT`。其中 `PROXY` 行为必须指定 `proxyNames``proxyNames` 需要指向 `egress` -> `proxies` 属性中存在的代理。
2.`egress` -> `rules` 属性中列举出站规则。从上到下,第一条匹配 IP 地址段或 DNS 后缀的规则会被执行。使用通配符 `"*"` 匹配所有 IP 地址或域名。出站行为包括 `DIRECT``PROXY``REJECT`。其中 `PROXY` 行为必须指定 `proxyNames``proxyNames` 需要指向 `egress` -> `proxies` 属性中存在的代理。默认的出站行为是 `DIRECT`
如果想要关闭出站代理功能,将 `egress` 属性设置为空 `{}` 即可。

View File

@@ -16,5 +16,5 @@
package version
const (
AppVersion = "3.17.1"
AppVersion = "3.18.0"
)

View File

@@ -461,7 +461,8 @@ class ClientConfig:
'servers': [{
'ipAddress': '',
'portBindings': [{}],
}]
}],
'handshakeMode': 'HANDSHAKE_NO_WAIT'
}],
'activeProfile': 'default',
'rpcPort': 0,

View File

@@ -456,7 +456,7 @@ func NewVless(option VlessOption) (*Vless, error) {
option: &option,
}
if s := strings.Split(option.Encryption, "-mlkem768client-"); len(s) == 2 {
if s := strings.SplitN(option.Encryption, "-", 4); len(s) == 4 && s[2] == "mlkem768client" {
var minutes uint32
if s[0] != "1rtt" {
t := strings.TrimSuffix(s[0], "min")
@@ -470,14 +470,22 @@ func NewVless(option VlessOption) (*Vless, error) {
}
minutes = uint32(i)
}
var xor uint32
switch s[1] {
case "vless":
case "aes128xor":
xor = 1
default:
return nil, fmt.Errorf("invaild vless encryption value: %s", option.Encryption)
}
var b []byte
b, err = base64.RawURLEncoding.DecodeString(s[1])
b, err = base64.RawURLEncoding.DecodeString(s[3])
if err != nil {
return nil, fmt.Errorf("invaild vless encryption value: %s", option.Encryption)
}
if len(b) == 1184 {
if len(b) == encryption.MLKEM768ClientLength {
v.encryption = &encryption.ClientInstance{}
if err = v.encryption.Init(b, time.Duration(minutes)*time.Minute); err != nil {
if err = v.encryption.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
}
} else {

View File

@@ -221,6 +221,9 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
if flow := query.Get("flow"); flow != "" {
vless["flow"] = strings.ToLower(flow)
}
if encryption := query.Get("encryption"); encryption != "" {
vless["encryption"] = encryption
}
proxies = append(proxies, vless)
case "vmess":

View File

@@ -46,16 +46,16 @@ func Main(args []string) {
}
fmt.Println("Config:", configBase64)
fmt.Println("Key:", keyPem)
case "vless-mlkem768-keypair":
case "vless-mlkem768":
var seed string
if len(args) > 1 {
seed = args[1]
}
seedBase64, pubBase64, err := encryption.GenMLKEM768(seed)
seedBase64, clientBase64, err := encryption.GenMLKEM768(seed)
if err != nil {
panic(err)
}
fmt.Println("Seed: " + seedBase64)
fmt.Println("Client: " + pubBase64)
fmt.Println("Client: " + clientBase64)
}
}

View File

@@ -170,7 +170,7 @@ type realityVerifier struct {
//var pOffset = utils.MustOK(reflect.TypeOf((*utls.Conn)(nil)).Elem().FieldByName("peerCertificates")).Offset
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
//log.Debugln("REALITY localAddr: %v\t is using X25519MLKEM768 for TLS' communication: %v", c.RemoteAddr(), c.HandshakeState.ServerHello.SelectedGroup == utls.X25519MLKEM768)
log.Debugln("REALITY localAddr: %v is using X25519MLKEM768 for TLS' communication: %v", c.RemoteAddr(), c.HandshakeState.ServerHello.ServerShare.Group == utls.X25519MLKEM768)
//p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
//certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset))
certs := c.Conn.PeerCertificates()

View File

@@ -1,3 +1,12 @@
// Package wildcard modified IGLOU-EU/go-wildcard to support:
//
// `*` matches zero or more characters
// `?` matches exactly one character
//
// The original go-wildcard library used `.` to match exactly one character, and `?` to match zero or one character.
// `.` is a valid delimiter in domain name matching and should not be used as a wildcard.
// The `?` matching logic strictly matches only one character in most scenarios.
// So, the `?` matching logic in the original go-wildcard library has been removed and its wildcard `.` has been replaced with `?`.
package wildcard
// copy and modified from https://github.com/IGLOU-EU/go-wildcard/tree/ce22b7af48e487517a492d3727d9386492043e21
@@ -16,12 +25,10 @@ func Match(pattern, s string) bool {
}
func matchByString(pattern, s string) bool {
var lastErotemeCluster byte
var patternIndex, sIndex, lastStar, lastEroteme int
var patternIndex, sIndex, lastStar int
patternLen := len(pattern)
sLen := len(s)
star := -1
eroteme := -1
Loop:
if sIndex >= sLen {
@@ -38,14 +45,8 @@ Loop:
return false
}
switch pattern[patternIndex] {
// Removed dot matching as it conflicts with dot in domains.
// case '.':
// It matches any single character. So, we don't need to check anything.
case '?':
// '?' matches one character. Store its position and match exactly one character in the string.
eroteme = patternIndex
lastEroteme = sIndex
lastErotemeCluster = byte(s[sIndex])
// It matches any single character. So, we don't need to check anything.
case '*':
// '*' matches zero or more characters. Store its position and increment the pattern index.
star = patternIndex
@@ -53,15 +54,8 @@ Loop:
patternIndex++
goto Loop
default:
// If the characters don't match, check if there was a previous '?' or '*' to backtrack.
// If the characters don't match, check if there was a previous '*' to backtrack.
if pattern[patternIndex] != s[sIndex] {
if eroteme != -1 {
patternIndex = eroteme + 1
sIndex = lastEroteme
eroteme = -1
goto Loop
}
if star != -1 {
patternIndex = star + 1
lastStar++
@@ -71,29 +65,18 @@ Loop:
return false
}
// If the characters match, check if it was not the same to validate the eroteme.
if eroteme != -1 && lastErotemeCluster != byte(s[sIndex]) {
eroteme = -1
}
}
patternIndex++
sIndex++
goto Loop
// Check if the remaining pattern characters are '*' or '?', which can match the end of the string.
// Check if the remaining pattern characters are '*', which can match the end of the string.
checkPattern:
if patternIndex < patternLen {
if pattern[patternIndex] == '*' {
patternIndex++
goto checkPattern
} else if pattern[patternIndex] == '?' {
if sIndex >= sLen {
sIndex--
}
patternIndex++
goto checkPattern
}
}

View File

@@ -25,31 +25,17 @@ func TestMatch(t *testing.T) {
{"", "", true},
{"", "*", true},
{"", "**", true},
{"", "?", true},
{"", "??", true},
{"", "?*", true},
{"", "*?", true},
{"", ".", false},
{"", ".?", false},
{"", "?.", false},
{"", ".*", false},
{"", "*.", false},
{"", "*.?", false},
{"", "?.*", false},
{"", "?", false},
{"", "?*", false},
{"", "*?", false},
{"a", "", false},
{"a", "a", true},
{"a", "*", true},
{"a", "**", true},
{"a", "?", true},
{"a", "??", true},
{"a", ".", false},
{"a", ".?", false},
{"a", "?.", false},
{"a", ".*", false},
{"a", "*.", false},
{"a", "*.?", false},
{"a", "?.*", false},
{"a", "?*", true},
{"a", "*?", true},
{"match the exact string", "match the exact string", true},
{"do not match a different string", "this is a different string", false},
@@ -68,22 +54,27 @@ func TestMatch(t *testing.T) {
{"match a string with a ?", "match ? string with a ?", true},
{"match a string with a ? at the beginning", "?atch a string with a ? at the beginning", true},
{"match a string with two ?", "match a string with two ??", true},
{"match a optional char with a ?", "match a optional? char with a ?", true},
{"match a optional char with a ?", "match a optional? char with a ?", true},
{"do not match a string with extra and a ?", "do not match ? string with extra and a ? like this", false},
{"match a string with two ?", "match a ??ring with two ?", true},
{"do not match a string with extra ?", "do not match a string with extra ??", false},
{"do not match a string with a .", "do not match . string with a .", false},
{"do not match a string with a . at the beginning", "do not .atch a string with a . at the beginning", false},
{"do not match a string with two .", "do not match a ..ring with two .", false},
{"do not match a string with extra .", "do not match a string with extra ..", false},
{"abc.edf.hjg", "abc.edf.hjg", true},
{"abc.edf.hjg", "ab.cedf.hjg", false},
{"abc.edf.hjg", "abc.edfh.jg", false},
{"abc.edf.hjg", "abc.edf.hjq", false},
{"A big brown fox jumps over the lazy dog, with all there wildcards friends", ". big?brown fox jumps over * wildcard. friend??", false},
{"A big brown fox fails to jump over the lazy dog, with all there wildcards friends", ". big?brown fox jumps over * wildcard. friend??", false},
{"abc.edf.hjg", "abc.*.hjg", true},
{"abc.edf.hjg", "abc.*.hjq", false},
{"abc.edf.hjg", "abc*hjg", true},
{"abc.edf.hjg", "abc*hjq", false},
{"abc.edf.hjg", "a*g", true},
{"abc.edf.hjg", "a*q", false},
{"domain a.b.c", "domain a.b.c", true},
{"domain adb.c", "domain a.b.c", false},
{"aaaa", "a*a", true},
{"abc.edf.hjg", "ab?.edf.hjg", true},
{"abc.edf.hjg", "?b?.edf.hjg", true},
{"abc.edf.hjg", "??c.edf.hjg", true},
{"abc.edf.hjg", "a??.edf.hjg", true},
{"abc.edf.hjg", "ab??.edf.hjg", false},
{"abc.edf.hjg", "??.edf.hjg", false},
}
for i, c := range cases {
@@ -96,10 +87,106 @@ func TestMatch(t *testing.T) {
}
}
func match(pattern, name string) bool { // https://research.swtch.com/glob
px := 0
nx := 0
nextPx := 0
nextNx := 0
for px < len(pattern) || nx < len(name) {
if px < len(pattern) {
c := pattern[px]
switch c {
default: // ordinary character
if nx < len(name) && name[nx] == c {
px++
nx++
continue
}
case '?': // single-character wildcard
if nx < len(name) {
px++
nx++
continue
}
case '*': // zero-or-more-character wildcard
// Try to match at nx.
// If that doesn't work out,
// restart at nx+1 next.
nextPx = px
nextNx = nx + 1
px++
continue
}
}
// Mismatch. Maybe restart.
if 0 < nextNx && nextNx <= len(name) {
px = nextPx
nx = nextNx
continue
}
return false
}
// Matched all of pattern to all of name. Success.
return true
}
func FuzzMatch(f *testing.F) {
f.Fuzz(func(t *testing.T, s string) {
if !Match(string(s), string(s)) {
t.Fatalf("%s does not match %s", s, s)
f.Fuzz(func(t *testing.T, pattern, name string) {
result1 := Match(pattern, name)
result2 := match(pattern, name)
if result1 != result2 {
t.Fatalf("Match failed for pattern `%s` and name `%s`", pattern, name)
}
})
}
func BenchmarkMatch(b *testing.B) {
cases := []struct {
s string
pattern string
result bool
}{
{"abc.edf.hjg", "abc.edf.hjg", true},
{"abc.edf.hjg", "ab.cedf.hjg", false},
{"abc.edf.hjg", "abc.edfh.jg", false},
{"abc.edf.hjg", "abc.edf.hjq", false},
{"abc.edf.hjg", "abc.*.hjg", true},
{"abc.edf.hjg", "abc.*.hjq", false},
{"abc.edf.hjg", "abc*hjg", true},
{"abc.edf.hjg", "abc*hjq", false},
{"abc.edf.hjg", "a*g", true},
{"abc.edf.hjg", "a*q", false},
{"abc.edf.hjg", "ab?.edf.hjg", true},
{"abc.edf.hjg", "?b?.edf.hjg", true},
{"abc.edf.hjg", "??c.edf.hjg", true},
{"abc.edf.hjg", "a??.edf.hjg", true},
{"abc.edf.hjg", "ab??.edf.hjg", false},
{"abc.edf.hjg", "??.edf.hjg", false},
{"r4.cdn-aa-wow-this-is-long-a1.video-yajusenpai1145141919810-oh-hell-yeah-this-is-also-very-long-and-sukka-the-fox-has-a-very-big-fluffy-fox-tail-ao-wu-ao-wu-regex-and-wildcard-both-might-have-deadly-back-tracing-issue-be-careful-or-use-linear-matching.com", "*.cdn-*-*.video**.com", true},
}
b.Run("Match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, c := range cases {
result := Match(c.pattern, c.s)
if c.result != result {
b.Errorf("Test %d: Expected `%v`, found `%v`; With Pattern: `%s` and String: `%s`", i+1, c.result, result, c.pattern, c.s)
}
}
}
})
b.Run("match", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, c := range cases {
result := match(c.pattern, c.s)
if c.result != result {
b.Errorf("Test %d: Expected `%v`, found `%v`; With Pattern: `%s` and String: `%s`", i+1, c.result, result, c.pattern, c.s)
}
}
}
})
}

View File

@@ -638,7 +638,8 @@ proxies: # socks5
port: 443
uuid: uuid
network: tcp
encryption: "8min-mlkem768client-bas64RawURLEncoding" # 复用八分钟后协商新的 sharedKey需小于服务端的值
encryption: "8min-vless-mlkem768client-bas64RawURLEncoding" # 复用八分钟后协商新的 sharedKey需小于服务端的值
# encryption: "8min-aes128xor-mlkem768client-bas64RawURLEncoding"
tls: false #可以不开启tls
udp: true
@@ -1346,7 +1347,8 @@ listeners:
flow: xtls-rprx-vision
# ws-path: "/" # 如果不为空则开启 websocket 传输层
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
# decryption: "10min-mlkem768seed-bas64RawURLEncoding" # 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式, 后面base64字符串可由可由 mihomo generate vless-mlkem768 命令生成
# decryption: "10min-vless-mlkem768seed-bas64RawURLEncoding" # 同时允许 1-RTT 模式与十分钟复用的 0-RTT 模式, 后面base64字符串可由可由 mihomo generate vless-mlkem768 命令生成
# decryption: "10min-aes128xor-mlkem768seed-bas64RawURLEncoding"
# 下面两项如果填写则开启 tls需要同时填写
# certificate: ./server.crt
# private-key: ./server.key

View File

@@ -35,7 +35,7 @@ require (
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
github.com/metacubex/utls v1.8.1-0.20250810142204-d0e55ab2e852
github.com/metacubex/utls v1.8.1-0.20250811145843-49b4f106169a
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20
github.com/mroth/weightedrand/v2 v2.1.0

View File

@@ -139,10 +139,8 @@ github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113a
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/utls v1.8.1-0.20250810142204-d0e55ab2e852 h1:MLHUGmASNH7/AeoGmSrVM2RutRZAqIDSbQWBp0P7ItE=
github.com/metacubex/utls v1.8.1-0.20250810142204-d0e55ab2e852/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/utls v1.8.1-0.20250811145843-49b4f106169a h1:IIzlVmDoB4+7b0BUcLZaY5+AirhhLFep3PhwkAFMRnQ=
github.com/metacubex/utls v1.8.1-0.20250811145843-49b4f106169a/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=

View File

@@ -89,18 +89,29 @@ func TestInboundVless_TLS(t *testing.T) {
}
func TestInboundVless_Encryption(t *testing.T) {
seedBase64, pubBase64, err := encryption.GenMLKEM768("")
seedBase64, clientBase64, err := encryption.GenMLKEM768("")
if err != nil {
t.Fatal(err)
return
}
t.Run("-vless-", func(t *testing.T) {
inboundOptions := inbound.VlessOption{
Decryption: "10min-mlkem768seed-" + seedBase64,
Decryption: "10min-vless-mlkem768seed-" + seedBase64,
}
outboundOptions := outbound.VlessOption{
Encryption: "8min-mlkem768client-" + pubBase64,
Encryption: "8min-vless-mlkem768client-" + clientBase64,
}
testInboundVless(t, inboundOptions, outboundOptions)
})
t.Run("-aes128xor-", func(t *testing.T) {
inboundOptions := inbound.VlessOption{
Decryption: "10min-aes128xor-mlkem768seed-" + seedBase64,
}
outboundOptions := outbound.VlessOption{
Encryption: "8min-aes128xor-mlkem768client-" + clientBase64,
}
testInboundVless(t, inboundOptions, outboundOptions)
})
}
func TestInboundVless_Wss1(t *testing.T) {

View File

@@ -88,7 +88,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
sl = &Listener{config: config, service: service}
if s := strings.Split(config.Decryption, "-mlkem768seed-"); len(s) == 2 {
if s := strings.SplitN(config.Decryption, "-", 4); len(s) == 4 && s[2] == "mlkem768seed" {
var minutes uint32
if s[0] != "1rtt" {
t := strings.TrimSuffix(s[0], "min")
@@ -102,14 +102,22 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
}
minutes = uint32(i)
}
var xor uint32
switch s[1] {
case "vless":
case "aes128xor":
xor = 1
default:
return nil, fmt.Errorf("invaild vless decryption value: %s", config.Decryption)
}
var b []byte
b, err = base64.RawURLEncoding.DecodeString(s[1])
b, err = base64.RawURLEncoding.DecodeString(s[3])
if err != nil {
return nil, fmt.Errorf("invaild vless decryption value: %s", config.Decryption)
}
if len(b) == 64 {
if len(b) == encryption.MLKEM768SeedLength {
sl.decryption = &encryption.ServerInstance{}
if err = sl.decryption.Init(b, time.Duration(minutes)*time.Minute); err != nil {
if err = sl.decryption.Init(b, xor, time.Duration(minutes)*time.Minute); err != nil {
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
}
} else {

View File

@@ -38,17 +38,18 @@ func init() {
type ClientInstance struct {
sync.RWMutex
eKeyNfs *mlkem.EncapsulationKey768
xor uint32
minutes time.Duration
expire time.Time
baseKey []byte
reuse []byte
ticket []byte
}
type ClientConn struct {
net.Conn
instance *ClientInstance
baseKey []byte
reuse []byte
ticket []byte
random []byte
aead cipher.AEAD
nonce []byte
@@ -57,8 +58,9 @@ type ClientConn struct {
peerCache []byte
}
func (i *ClientInstance) Init(eKeyNfsData []byte, minutes time.Duration) (err error) {
func (i *ClientInstance) Init(eKeyNfsData []byte, xor uint32, minutes time.Duration) (err error) {
i.eKeyNfs, err = mlkem.NewEncapsulationKey768(eKeyNfsData)
i.xor = xor
i.minutes = minutes
return
}
@@ -67,6 +69,9 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.eKeyNfs == nil {
return nil, errors.New("uninitialized")
}
if i.xor == 1 {
conn = NewXorConn(conn, i.eKeyNfs.Bytes())
}
c := &ClientConn{Conn: conn}
if i.minutes > 0 {
@@ -74,7 +79,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
if time.Now().Before(i.expire) {
c.instance = i
c.baseKey = i.baseKey
c.reuse = i.reuse
c.ticket = i.ticket
i.RUnlock()
return c, nil
}
@@ -104,7 +109,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
return nil, err
}
encapsulatedPfsKey := peerServerHello[:1088]
c.reuse = peerServerHello[1088:]
c.ticket = peerServerHello[1088:]
pfsKey, err := dKeyPfs.Decapsulate(encapsulatedPfsKey)
if err != nil {
@@ -115,7 +120,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
authKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, encapsulatedNfsKey, eKeyPfs).Read(authKey)
nonce := make([]byte, 12)
VLESS, _ := newAead(ClientCipher, authKey).Open(nil, nonce, c.reuse, encapsulatedPfsKey)
VLESS, _ := newAead(ClientCipher, authKey).Open(nil, nonce, c.ticket, encapsulatedPfsKey)
if !bytes.Equal(VLESS, []byte("VLESS")) { // TODO: more message
return nil, errors.New("invalid server")
}
@@ -124,7 +129,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
i.Lock()
i.expire = time.Now().Add(i.minutes)
i.baseKey = c.baseKey
i.reuse = c.reuse
i.ticket = c.ticket
i.Unlock()
}
@@ -140,12 +145,12 @@ func (c *ClientConn) Write(b []byte) (int, error) {
c.random = make([]byte, 32)
rand.Read(c.random)
key := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, c.random, c.reuse).Read(key)
hkdf.New(sha256.New, c.baseKey, c.random, c.ticket).Read(key)
c.aead = newAead(ClientCipher, key)
c.nonce = make([]byte, 12)
data = make([]byte, 21+32+5+len(b)+16)
copy(data, c.reuse)
copy(data, c.ticket)
copy(data[21:], c.random)
encodeHeader(data[53:], len(b)+16)
c.aead.Seal(data[:58], c.nonce, b, data[53:58])
@@ -210,7 +215,7 @@ func (c *ClientConn) Read(b []byte) (int, error) { // after first Write()
if err != nil {
if c.instance != nil {
c.instance.Lock()
if bytes.Equal(c.reuse, c.instance.reuse) {
if bytes.Equal(c.ticket, c.instance.ticket) {
c.instance.expire = time.Now() // expired
}
c.instance.Unlock()

View File

@@ -1,3 +1,5 @@
// Package encryption copy and modify from xray-core
// https://github.com/XTLS/Xray-core/commit/f61c14e9c63dc41a8a09135db3aea337974f3f37
// https://github.com/XTLS/Xray-core/commit/3e19bf9233bdd9bafc073a71c65b737cc1ffba5e
// https://github.com/XTLS/Xray-core/commit/7ffb555fc8ec51bd1e3e60f26f1d6957984dba80
package encryption

View File

@@ -8,7 +8,10 @@ import (
"github.com/metacubex/utls/mlkem"
)
func GenMLKEM768(seedStr string) (seedBase64, pubBase64 string, err error) {
const MLKEM768SeedLength = mlkem.SeedSize
const MLKEM768ClientLength = mlkem.EncapsulationKeySize768
func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) {
var seed [64]byte
if len(seedStr) > 0 {
s, _ := base64.RawURLEncoding.DecodeString(seedStr)
@@ -27,6 +30,6 @@ func GenMLKEM768(seedStr string) (seedBase64, pubBase64 string, err error) {
key, _ := mlkem.NewDecapsulationKey768(seed[:])
pub := key.EncapsulationKey()
seedBase64 = base64.RawURLEncoding.EncodeToString(seed[:])
pubBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes())
clientBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes())
return
}

View File

@@ -25,6 +25,7 @@ type ServerSession struct {
type ServerInstance struct {
sync.RWMutex
dKeyNfs *mlkem.DecapsulationKey768
xor uint32
minutes time.Duration
sessions map[[21]byte]*ServerSession
stop bool
@@ -34,7 +35,7 @@ type ServerConn struct {
net.Conn
cipher byte
baseKey []byte
reuse []byte
ticket []byte
peerRandom []byte
peerAead cipher.AEAD
peerNonce []byte
@@ -43,8 +44,9 @@ type ServerConn struct {
nonce []byte
}
func (i *ServerInstance) Init(dKeyNfsData []byte, minutes time.Duration) (err error) {
func (i *ServerInstance) Init(dKeyNfsData []byte, xor uint32, minutes time.Duration) (err error) {
i.dKeyNfs, err = mlkem.NewDecapsulationKey768(dKeyNfsData)
i.xor = xor
if minutes > 0 {
i.minutes = minutes
i.sessions = make(map[[21]byte]*ServerSession)
@@ -79,22 +81,25 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.dKeyNfs == nil {
return nil, errors.New("uninitialized")
}
if i.xor == 1 {
conn = NewXorConn(conn, i.dKeyNfs.EncapsulationKey().Bytes())
}
c := &ServerConn{Conn: conn}
peerReuseHello := make([]byte, 21+32)
if _, err := io.ReadFull(c.Conn, peerReuseHello); err != nil {
peerTicketHello := make([]byte, 21+32)
if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil {
return nil, err
}
if i.minutes > 0 {
i.RLock()
s := i.sessions[[21]byte(peerReuseHello)]
s := i.sessions[[21]byte(peerTicketHello)]
i.RUnlock()
if s != nil {
if _, replay := s.randoms.LoadOrStore([32]byte(peerReuseHello[21:]), true); !replay {
if _, replay := s.randoms.LoadOrStore([32]byte(peerTicketHello[21:]), true); !replay {
c.cipher = s.cipher
c.baseKey = s.baseKey
c.reuse = peerReuseHello[:21]
c.peerRandom = peerReuseHello[21:]
c.ticket = peerTicketHello[:21]
c.peerRandom = peerTicketHello[21:]
return c, nil
}
}
@@ -106,11 +111,11 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
}
if l, _ := decodeHeader(peerHeader); l != 0 {
c.Conn.Write(make([]byte, randBetween(100, 1000))) // make client do new handshake
return nil, errors.New("invalid reuse")
return nil, errors.New("invalid ticket")
}
peerClientHello := make([]byte, 1088+1184+1)
copy(peerClientHello, peerReuseHello)
copy(peerClientHello, peerTicketHello)
copy(peerClientHello[53:], peerHeader)
if _, err := io.ReadFull(c.Conn, peerClientHello[58:]); err != nil {
return nil, err
@@ -136,13 +141,13 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
authKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, encapsulatedNfsKey, eKeyPfsData).Read(authKey)
nonce := make([]byte, 12)
c.reuse = newAead(c.cipher, authKey).Seal(nil, nonce, []byte("VLESS"), encapsulatedPfsKey)
c.ticket = newAead(c.cipher, authKey).Seal(nil, nonce, []byte("VLESS"), encapsulatedPfsKey)
padding := randBetween(100, 1000)
serverHello := make([]byte, 1088+21+5+padding)
copy(serverHello, encapsulatedPfsKey)
copy(serverHello[1088:], c.reuse)
copy(serverHello[1088:], c.ticket)
encodeHeader(serverHello[1109:], int(padding))
if _, err := c.Conn.Write(serverHello); err != nil {
@@ -151,7 +156,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.minutes > 0 {
i.Lock()
i.sessions[[21]byte(c.reuse)] = &ServerSession{
i.sessions[[21]byte(c.ticket)] = &ServerSession{
expire: time.Now().Add(i.minutes),
cipher: c.cipher,
baseKey: c.baseKey,
@@ -181,12 +186,12 @@ func (c *ServerConn) Read(b []byte) (int, error) {
return 0, err
}
}
peerIndex := make([]byte, 21)
copy(peerIndex, peerHeader)
if _, err := io.ReadFull(c.Conn, peerIndex[5:]); err != nil {
peerTicket := make([]byte, 21)
copy(peerTicket, peerHeader)
if _, err := io.ReadFull(c.Conn, peerTicket[5:]); err != nil {
return 0, err
}
if !bytes.Equal(peerIndex, c.reuse) {
if !bytes.Equal(peerTicket, c.ticket) {
return 0, errors.New("naughty boy")
}
c.peerRandom = make([]byte, 32)
@@ -195,7 +200,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
}
}
peerKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, c.peerRandom, c.reuse).Read(peerKey)
hkdf.New(sha256.New, c.baseKey, c.peerRandom, c.ticket).Read(peerKey)
c.peerAead = newAead(c.cipher, peerKey)
c.peerNonce = make([]byte, 12)
}

View File

@@ -0,0 +1,63 @@
package encryption
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"net"
)
type XorConn struct {
net.Conn
key []byte
ctr cipher.Stream
peerCtr cipher.Stream
}
func NewXorConn(conn net.Conn, key []byte) *XorConn {
return &XorConn{Conn: conn, key: key[:16]}
}
func (c *XorConn) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
var iv []byte
if c.ctr == nil {
block, _ := aes.NewCipher(c.key)
iv = make([]byte, 16)
rand.Read(iv)
c.ctr = cipher.NewCTR(block, iv)
}
c.ctr.XORKeyStream(b, b) // caller MUST discard b
if iv != nil {
b = append(iv, b...)
}
if _, err := c.Conn.Write(b); err != nil {
return 0, err
}
if iv != nil {
b = b[16:]
}
return len(b), nil
}
func (c *XorConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
if c.peerCtr == nil {
peerIv := make([]byte, 16)
if _, err := io.ReadFull(c.Conn, peerIv); err != nil {
return 0, err
}
block, _ := aes.NewCipher(c.key)
c.peerCtr = cipher.NewCTR(block, peerIv)
}
n, err := c.Conn.Read(b)
if n > 0 {
c.peerCtr.XORKeyStream(b[:n], b[:n])
}
return n, err
}

View File

@@ -16,7 +16,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-amlogic
PKG_VERSION:=3.1.265
PKG_VERSION:=3.1.266
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0 License

View File

@@ -173,7 +173,7 @@ check_kernel() {
latest_version="$(
curl -fsSL -m 10 \
${kernel_api}/releases/expanded_assets/kernel_${kernel_tag} |
grep -oE "${main_line_version}\.[0-9]+.*\.tar\.gz" | sed 's/.tar.gz//' |
grep -oE "${main_line_version}\.[0-9]+\.tar\.gz" | sed 's/.tar.gz//' |
sort -urV | head -n 1
)"
[[ -n "${latest_version}" ]] || tolog "02.03 No kernel available, please use another kernel branch." "1"

View File

@@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=Argon Theme
LUCI_DEPENDS:=+curl +jsonfilter
LUCI_DEPENDS:=+wget +jsonfilter
PKG_VERSION:=2.4.3
PKG_RELEASE:=20250722

View File

@@ -27,7 +27,6 @@
local fs = require "nixio.fs"
local nutil = require "nixio.util"
local json = require "luci.jsonc"
local sys = require "luci.sys"
local uci = require 'luci.model.uci'.cursor()
-- Fetch Local Background Media
@@ -74,9 +73,9 @@
if fs.access("/etc/config/argon") then
local online_wallpaper = uci:get_first('argon', 'global', 'online_wallpaper') or (uci:get_first('argon', 'global', 'bing_background') == '1' and 'bing')
if (online_wallpaper and online_wallpaper ~= "none") then
local picurl = sys.exec("/usr/libexec/argon/online_wallpaper")
if (picurl and picurl ~= '') then
return picurl, "Image", ""
local picurl = util.ubus("luci.argon_wallpaper", "get_url") or {}
if (picurl.url and picurl.url ~= '') then
return picurl.url, "Image", ""
end
end
end

View File

@@ -1,105 +0,0 @@
#!/bin/sh
# author jjm2473
# the script will be excuted when `argon.@global[0].bing_background == '1'`
# defaults to 'bing' to be compatible with old config
WEB_PIC_SRC=$(uci -q get argon.@global[0].online_wallpaper || echo 'bing')
# For now, the next two variables are used for wallhaven.cc with specified Tag ID
# API_KEY if user has an account with wallhaven and want to use their apikey to allow for more images
# EXACT_RESO is used for exact resolution by default, if not use 'atleast' instead of 'resolutions'
API_KEY=$(uci -q get argon.@global[0].use_api_key)
EXACT_RESO=$(uci -q get argon.@global[0].use_exact_resolution || echo '1')
CACHE=/var/run/argon_${WEB_PIC_SRC}.url
WRLOCK=/var/lock/argon_${WEB_PIC_SRC}.lock
fetch_pic_url() {
case $WEB_PIC_SRC in
bing)
local picpath=$(curl -fks --max-time 3 \
"https://www.bing.com/HPImageArchive.aspx?format=js&n=1" |
jsonfilter -qe '@.images[0].url')
[ -n "${picpath}" ] && echo "//www.bing.com${picpath}"
;;
unsplash)
if [ -z "$API_KEY" ]; then
curl -fks --max-time 3 \
"https://source.unsplash.com/1920x1080/daily?wallpapers" |
sed -E 's#^.*href="([^?]+)\?.*$#\1?fm=jpg\&fit=crop\&w=1920\&h=1080#'
else
curl -fks --max-time 3 \
"https://api.unsplash.com/photos/random?client_id=${API_KEY}" |
jsonfilter -qe '@["urls"]["regular"]'
fi
;;
unsplash_*)
local collection_id=${WEB_PIC_SRC#unsplash_}
if [ -z "$API_KEY" ]; then
curl -fks --max-time 3 \
"https://source.unsplash.com/collection/${collection_id}/1920x1080" |
sed -E 's#^.*href="([^?]+)\?.*$#\1?fm=jpg\&fit=crop\&w=1920\&h=1080#'
else
curl -fks --max-time 3 \
"https://api.unsplash.com/photos/random?client_id=${API_KEY}&collections=${collection_id}" |
jsonfilter -qe '@["urls"]["regular"]'
fi
;;
wallhaven)
curl -fks --max-time 3 \
"https://wallhaven.cc/api/v1/search?resolutions=1920x1080&sorting=random" |
jsonfilter -qe '@.data[0].path'
;;
wallhaven_*)
local tag_id=${WEB_PIC_SRC#wallhaven_}
local has_api_key=""
[ -n "$API_KEY" ] && has_api_key="apikey=$API_KEY&" || has_api_key=""
local use_reso="resolutions"
[ "$EXACT_RESO" -eq "1" ] && use_reso='resolutions' || use_reso='atleast'
curl -fks --max-time 3 \
"https://wallhaven.cc/api/v1/search?${has_api_key}q=id%3A${tag_id}&${use_reso}=1920x1080&sorting=random" |
jsonfilter -qe '@.data[0].path'
;;
esac
}
try_update() {
local lock="$WRLOCK"
exec 200>$lock
if flock -n 200 >/dev/null 2>&1; then
local picurl=$(fetch_pic_url)
if [[ "$WEB_PIC_SRC" == wallhave* ]] ; then
curl -fks --max-time 3 --url "${picurl}" > /dev/null
fi
if [ -n "$picurl" ]; then
echo "${picurl}" | tee "$CACHE"
else
if [ -s "$CACHE" ]; then
cat "$CACHE"
else
touch "$CACHE"
fi
fi
flock -u 200 >/dev/null 2>&1
elif [ -s "$CACHE" ]; then
cat "$CACHE"
fi
}
get_url() {
if [ -f "$CACHE" ]; then
local idle_t=$(($(date '+%s') - $(date -r "$CACHE" '+%s' 2>/dev/null || echo '0')))
if [ -s "$CACHE" ]; then
if [ $idle_t -le 43200 ]; then
cat "$CACHE"
return
fi
else
if [ $idle_t -le 120 ]; then
return
fi
fi
fi
try_update
}
get_url

View File

@@ -0,0 +1,129 @@
#!/bin/sh
# author jjm2473
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
# the script will be excuted when `argon.@global[0].bing_background == '1'`
# defaults to 'bing' to be compatible with old config
WEB_PIC_SRC="$(uci -q get argon.@global[0].online_wallpaper || echo 'bing')"
# For now, the next two variables are used for wallhaven.cc with specified Tag ID
# API_KEY if user has an account with wallhaven and want to use their apikey to allow for more images
# EXACT_RESO is used for exact resolution by default, if not use 'atleast' instead of 'resolutions'
API_KEY="$(uci -q get argon.@global[0].use_api_key)"
EXACT_RESO="$(uci -q get argon.@global[0].use_exact_resolution || echo '1')"
CACHE="/var/run/argon_${WEB_PIC_SRC}.url"
WRLOCK="/var/lock/argon_${WEB_PIC_SRC}.lock"
fetch_pic_url() {
case "$WEB_PIC_SRC" in
bing)
local picpath="$(wget -T3 -qO- \
"https://www.bing.com/HPImageArchive.aspx?format=js&n=1" |
jsonfilter -qe '@.images[0].url' |
sed 's/1920x1080/UHD/g')"
[ -n "${picpath}" ] && echo "//www.bing.com${picpath}"
;;
unsplash)
if [ -z "$API_KEY" ]; then
local pic_id="$(wget -T3 --spider \
"https://source.unsplash.com/1920x1080/daily?wallpapers" 2>&1 |
grep -Eo "photo-\w+-\w+" | head -n1)"
[ -n "${pic_id}" ] && echo "https://images.unsplash.com/${pic_id}?fm=jpg&fit=crop&w=1920&h=1080"
else
wget -T3 -qO- "https://api.unsplash.com/photos/random?client_id=${API_KEY}" |
jsonfilter -qe '@["urls"]["regular"]'
fi
;;
unsplash_*)
local collection_id="${WEB_PIC_SRC#unsplash_}"
if [ -z "$API_KEY" ]; then
local pic_id="$(wget -T3 --spider \
"https://source.unsplash.com/collection/${collection_id}/1920x1080" 2>&1 |
grep -Eo "photo-\w+-\w+" | head -n1)"
[ -n "${pic_id}" ] && echo "https://images.unsplash.com/${pic_id}?fm=jpg&fit=crop&w=1920&h=1080"
else
wget -T3 -qO- \
"https://api.unsplash.com/photos/random?client_id=${API_KEY}&collections=${collection_id}" |
jsonfilter -qe '@["urls"]["regular"]'
fi
;;
wallhaven)
wget -T3 -qO- \
"https://wallhaven.cc/api/v1/search?resolutions=1920x1080&sorting=random" |
jsonfilter -qe "@.data[0].path"
;;
wallhaven_*)
local tag_id="${WEB_PIC_SRC#wallhaven_}"
local use_reso="resolutions"
[ "$EXACT_RESO" -eq "1" ] || use_reso="atleast"
[ -z "$API_KEY" ] || API_KEY="apikey=$API_KEY&"
wget -T3 -qO- \
"https://wallhaven.cc/api/v1/search?${API_KEY}q=id%3A${tag_id}&${use_reso}=1920x1080&sorting=random" |
jsonfilter -qe '@.data[0].path'
;;
esac
}
try_update() {
local lock="$WRLOCK"
exec 200>"$lock"
if flock -n 200 >"/dev/null" 2>&1; then
local picurl="$(fetch_pic_url)"
if [ -n "$picurl" ]; then
echo "$picurl" | tee "$CACHE"
else
if [ -s "$CACHE" ]; then
cat "$CACHE"
else
touch "$CACHE"
fi
fi
flock -u 200 >"/dev/null" 2>&1
elif [ -s "$CACHE" ]; then
cat "$CACHE"
fi
}
case "$1" in
"list")
json_init
json_add_object "get_url"
json_close_object
json_dump
json_cleanup
;;
"call")
case "$2" in
"get_url")
read -r input
if [ -f "$CACHE" ]; then
idle_t="$(($(date '+%s') - $(date -r "$CACHE" '+%s' 2>/dev/null || echo '0')))"
if [ -s "$CACHE" ]; then
if [ "$idle_t" -le "43200" ]; then
json_init
json_add_string "url" "$(cat "$CACHE")"
json_dump
json_cleanup
return 0
fi
else
if [ "$idle_t" -le 120 ]; then
echo '{ "url": "" }'
return 1
fi
fi
fi
json_init
json_add_string "url" "$(try_update)"
json_dump
json_cleanup
return 0
;;
esac
;;
esac

View File

@@ -10,11 +10,11 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_quickstart:=$(ARCH)
PKG_NAME:=quickstart
PKG_VERSION:=0.11.1
PKG_VERSION:=0.11.2
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
PKG_HASH:=5f59e69dc1a8dc5606e53936cc7a34f6d37c9102cbf378576420ef9fdd7e7d2f
PKG_HASH:=b22f430f08fb12739179e4b983133afb84a37be1e702d5b4e9fb30b1e701824d
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-binary-$(PKG_VERSION)

View File

@@ -475,30 +475,30 @@ if singbox_tags:find("with_utls") then
o:value("firefox")
o:value("edge")
o:value("safari")
-- o:value("360")
o:value("360")
o:value("qq")
o:value("ios")
-- o:value("android")
o:value("android")
o:value("random")
-- o:value("randomized")
o:value("randomized")
o.default = "chrome"
o:depends({ [_n("tls")] = true, [_n("utls")] = true })
o:depends({ [_n("utls")] = true })
-- [[ REALITY部分 ]] --
o = s:option(Flag, _n("reality"), translate("REALITY"))
o.default = 0
o:depends({ [_n("protocol")] = "vless", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "vmess", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "shadowsocks", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "socks", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "trojan", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "anytls", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "shadowsocks", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "socks", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "trojan", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "anytls", [_n("tls")] = true })
o = s:option(Value, _n("reality_publicKey"), translate("Public Key"))
o:depends({ [_n("utls")] = true, [_n("reality")] = true })
o:depends({ [_n("reality")] = true })
o = s:option(Value, _n("reality_shortId"), translate("Short Id"))
o:depends({ [_n("utls")] = true, [_n("reality")] = true })
o:depends({ [_n("reality")] = true })
end
o = s:option(ListValue, _n("transport"), translate("Transport"))

View File

@@ -21,7 +21,7 @@ const (
func NewClient(addr string, server string, target string, timeout int, key int,
tcpmode int, tcpmode_buffersize int, tcpmode_maxwin int, tcpmode_resend_timems int, tcpmode_compress int,
tcpmode_stat int, open_sock5 int, maxconn int, sock5_filter *func(addr string) bool) (*Client, error) {
tcpmode_stat int, open_sock5 int, maxconn int, sock5_filter *func(addr string) bool, cryptoConfig *CryptoConfig) (*Client, error) {
var ipaddr *net.UDPAddr
var tcpaddr *net.TCPAddr
@@ -67,6 +67,7 @@ func NewClient(addr string, server string, target string, timeout int, key int,
maxconn: maxconn,
pongTime: time.Now(),
sock5_filter: sock5_filter,
cryptoConfig: cryptoConfig,
}, nil
}
@@ -92,6 +93,7 @@ type Client struct {
open_sock5 int
sock5_filter *func(addr string) bool
cryptoConfig *CryptoConfig
ipaddr *net.UDPAddr
tcpaddr *net.TCPAddr
@@ -214,7 +216,7 @@ func (p *Client) Run() error {
recv := make(chan *Packet, 10000)
p.recvcontrol = make(chan int, 1)
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv)
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv, p.cryptoConfig)
go func() {
defer common.CrashLog()
@@ -346,7 +348,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn, targetAddr string) {
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
SEND_PROTO, RECV_PROTO, p.key,
p.tcpmode, p.tcpmode_buffersize, p.tcpmode_maxwin, p.tcpmode_resend_timems, p.tcpmode_compress, p.tcpmode_stat,
p.timeout)
p.timeout, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(len(mb))
}
@@ -409,7 +411,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn, targetAddr string) {
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
SEND_PROTO, RECV_PROTO, p.key,
p.tcpmode, 0, 0, 0, 0, 0,
0)
0, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(len(mb))
}
@@ -472,7 +474,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn, targetAddr string) {
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
SEND_PROTO, RECV_PROTO, p.key,
p.tcpmode, 0, 0, 0, 0, 0,
0)
0, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(len(mb))
}
@@ -550,7 +552,7 @@ func (p *Client) Accept() error {
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, clientConn.id, (uint32)(MyMsg_DATA), bytes[:n],
SEND_PROTO, RECV_PROTO, p.key,
p.tcpmode, 0, 0, 0, 0, 0,
p.timeout)
p.timeout, p.cryptoConfig)
p.sequence++
@@ -675,7 +677,7 @@ func (p *Client) ping() {
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, "", "", (uint32)(MyMsg_PING), b,
SEND_PROTO, RECV_PROTO, p.key,
0, 0, 0, 0, 0, 0,
0)
0, p.cryptoConfig)
loggo.Info("ping %s %s %d %d %d %d", p.addrServer, now.String(), p.sproto, p.rproto, p.id, p.sequence)
p.sequence++
if now.Sub(p.pongTime) > time.Second*3 {
@@ -775,7 +777,7 @@ func (p *Client) remoteError(uuid string) {
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, "", uuid, (uint32)(MyMsg_KICK), []byte{},
SEND_PROTO, RECV_PROTO, p.key,
0, 0, 0, 0, 0, 0,
0)
0, p.cryptoConfig)
}
func (p *Client) AcceptDirectTcpConn(conn *net.TCPConn, targetAddr string) {

View File

@@ -78,6 +78,12 @@ Usage:
-key 设置的密码默认0
Set password, default 0
-encrypt 加密模式支持aes128, aes256, chacha20
Encryption mode: aes128, aes256, chacha20
-encrypt-key 加密密钥支持base64编码或密码短语
Encryption key, supports base64 encoded key or passphrase
-tcp 设置是否转发tcp默认0
Set the switch to forward tcp, the default is 0
@@ -128,6 +134,8 @@ func main() {
server := flag.String("s", "", "server addr")
timeout := flag.Int("timeout", 60, "conn timeout")
key := flag.Int("key", 0, "key")
encryption := flag.String("encrypt", "", "encryption mode: aes128, aes256, chacha20")
encryptionKey := flag.String("encrypt-key", "", "encryption key (base64 or passphrase)")
tcpmode := flag.Int("tcp", 0, "tcp mode")
tcpmode_buffersize := flag.Int("tcp_bs", 1*1024*1024, "tcp mode buffer size")
tcpmode_maxwin := flag.Int("tcp_mw", 20000, "tcp mode max win")
@@ -173,6 +181,28 @@ func main() {
return
}
// Validate encryption parameters
encryptionMode, err := pingtunnel.ParseEncryptionMode(*encryption)
if err != nil {
fmt.Printf("Invalid encryption mode: %v\n", err)
return
}
if encryptionMode != pingtunnel.NoEncryption && *encryptionKey == "" {
fmt.Println("Encryption key is required when encryption mode is specified")
return
}
// Create crypto configuration
var cryptoConfig *pingtunnel.CryptoConfig
if encryptionMode != pingtunnel.NoEncryption {
cryptoConfig, err = pingtunnel.NewCryptoConfig(encryptionMode, *encryptionKey)
if err != nil {
fmt.Printf("Failed to create crypto config: %v\n", err)
return
}
}
level := loggo.LEVEL_INFO
if loggo.NameToLevel(*loglevel) >= 0 {
level = loggo.NameToLevel(*loglevel)
@@ -188,7 +218,7 @@ func main() {
loggo.Info("key %d", *key)
if *t == "server" {
s, err := pingtunnel.NewServer(*key, *maxconn, *max_process_thread, *max_process_buffer, *conntt)
s, err := pingtunnel.NewServer(*key, *maxconn, *max_process_thread, *max_process_buffer, *conntt, cryptoConfig)
if err != nil {
loggo.Error("ERROR: %s", err.Error())
return
@@ -243,7 +273,7 @@ func main() {
c, err := pingtunnel.NewClient(*listen, *server, *target, *timeout, *key,
*tcpmode, *tcpmode_buffersize, *tcpmode_maxwin, *tcpmode_resend_timems, *tcpmode_compress,
*tcpmode_stat, *open_sock5, *maxconn, &filter)
*tcpmode_stat, *open_sock5, *maxconn, &filter, cryptoConfig)
if err != nil {
loggo.Error("ERROR: %s", err.Error())
return

191
pingtunnel/crypto.go Normal file
View File

@@ -0,0 +1,191 @@
package pingtunnel
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/pbkdf2"
)
// EncryptionMode represents the encryption mode
type EncryptionMode int
const (
NoEncryption EncryptionMode = iota
AES128
AES256
CHACHA20
)
// CryptoConfig holds encryption configuration
type CryptoConfig struct {
Mode EncryptionMode
Key []byte
Cipher cipher.AEAD
}
// NewCryptoConfig creates a new crypto configuration
func NewCryptoConfig(mode EncryptionMode, keyInput string) (*CryptoConfig, error) {
if mode == NoEncryption {
return &CryptoConfig{Mode: NoEncryption}, nil
}
var keySize int
switch mode {
case AES128:
keySize = 16 // 128 bits
case AES256:
keySize = 32 // 256 bits
case CHACHA20:
keySize = chacha20poly1305.KeySize // 32 bytes
default:
return nil, fmt.Errorf("unsupported encryption mode: %d", mode)
}
key, err := deriveKey(keyInput, keySize)
if err != nil {
return nil, fmt.Errorf("failed to derive key: %v", err)
}
// Create AEAD based on mode
var aead cipher.AEAD
switch mode {
case AES128, AES256:
// AES-GCM
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("failed to create AES cipher: %v", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("failed to create GCM: %v", err)
}
aead = gcm
case CHACHA20:
// ChaCha20-Poly1305
cc20, err := chacha20poly1305.New(key)
if err != nil {
return nil, fmt.Errorf("failed to create ChaCha20-Poly1305: %v", err)
}
aead = cc20
default:
return nil, fmt.Errorf("unsupported encryption mode: %d", mode)
}
return &CryptoConfig{
Mode: mode,
Key: key,
Cipher: aead,
}, nil
}
// deriveKey derives an encryption key from the input string
func deriveKey(keyInput string, keySize int) ([]byte, error) {
if keyInput == "" {
return nil, errors.New("encryption key cannot be empty")
}
// First, try to decode as base64
if decoded, err := base64.StdEncoding.DecodeString(keyInput); err == nil {
if len(decoded) == keySize {
return decoded, nil
}
}
// If not valid base64 or wrong size, use PBKDF2 to derive key
salt := []byte("pingtunnel-salt") // Fixed salt for deterministic key derivation
iterations := 10000 // Standard iteration count
return pbkdf2.Key([]byte(keyInput), salt, iterations, keySize, sha256.New), nil
}
// Encrypt encrypts the given data
func (c *CryptoConfig) Encrypt(data []byte) ([]byte, error) {
if c.Mode == NoEncryption {
return data, nil
}
if c.Cipher == nil {
return nil, errors.New("cipher not initialized")
}
// Generate a random nonce
nonce := make([]byte, c.Cipher.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return nil, fmt.Errorf("failed to generate nonce: %v", err)
}
// Encrypt the data
ciphertext := c.Cipher.Seal(nil, nonce, data, nil)
// Prepend nonce to ciphertext
result := make([]byte, len(nonce)+len(ciphertext))
copy(result, nonce)
copy(result[len(nonce):], ciphertext)
return result, nil
}
// Decrypt decrypts the given data
func (c *CryptoConfig) Decrypt(data []byte) ([]byte, error) {
if c.Mode == NoEncryption {
return data, nil
}
if c.Cipher == nil {
return nil, errors.New("cipher not initialized")
}
nonceSize := c.Cipher.NonceSize()
if len(data) < nonceSize {
return nil, errors.New("ciphertext too short")
}
// Extract nonce and ciphertext
nonce := data[:nonceSize]
ciphertext := data[nonceSize:]
// Decrypt the data
plaintext, err := c.Cipher.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, fmt.Errorf("decryption failed: %v", err)
}
return plaintext, nil
}
// String returns a string representation of the encryption mode
func (m EncryptionMode) String() string {
switch m {
case NoEncryption:
return "none"
case AES128:
return "aes128"
case AES256:
return "aes256"
case CHACHA20:
return "chacha20"
default:
return "unknown"
}
}
// ParseEncryptionMode parses a string into an EncryptionMode
func ParseEncryptionMode(s string) (EncryptionMode, error) {
switch s {
case "", "none":
return NoEncryption, nil
case "aes128":
return AES128, nil
case "aes256":
return AES256, nil
case "chacha20", "chacha20-poly1305":
return CHACHA20, nil
default:
return NoEncryption, fmt.Errorf("invalid encryption mode: %s", s)
}
}

183
pingtunnel/crypto_test.go Normal file
View File

@@ -0,0 +1,183 @@
package pingtunnel
import (
"bytes"
"testing"
)
func TestCryptoConfig_AES128(t *testing.T) {
// Test with a base64 encoded key
key := "MTIzNDU2Nzg5MDEyMzQ1Ng==" // "1234567890123456" in base64
config, err := NewCryptoConfig(AES128, key)
if err != nil {
t.Fatalf("Failed to create crypto config: %v", err)
}
testData := []byte("Hello, World! This is a test message for encryption.")
// Test encryption
encrypted, err := config.Encrypt(testData)
if err != nil {
t.Fatalf("Failed to encrypt data: %v", err)
}
// Encrypted data should be different from original
if bytes.Equal(testData, encrypted) {
t.Fatal("Encrypted data should be different from original")
}
// Test decryption
decrypted, err := config.Decrypt(encrypted)
if err != nil {
t.Fatalf("Failed to decrypt data: %v", err)
}
// Decrypted data should match original
if !bytes.Equal(testData, decrypted) {
t.Fatalf("Decrypted data doesn't match original. Got: %s, Expected: %s", string(decrypted), string(testData))
}
}
func TestCryptoConfig_AES256(t *testing.T) {
// Test with a passphrase (will be derived using PBKDF2)
config, err := NewCryptoConfig(AES256, "my-secret-passphrase")
if err != nil {
t.Fatalf("Failed to create crypto config: %v", err)
}
testData := []byte("This is a longer test message to verify AES-256 encryption works correctly with derived keys.")
// Test encryption
encrypted, err := config.Encrypt(testData)
if err != nil {
t.Fatalf("Failed to encrypt data: %v", err)
}
// Test decryption
decrypted, err := config.Decrypt(encrypted)
if err != nil {
t.Fatalf("Failed to decrypt data: %v", err)
}
// Decrypted data should match original
if !bytes.Equal(testData, decrypted) {
t.Fatalf("Decrypted data doesn't match original. Got: %s, Expected: %s", string(decrypted), string(testData))
}
}
func TestCryptoConfig_ChaCha20(t *testing.T) {
// Test with a passphrase (PBKDF2 to 32 bytes)
config, err := NewCryptoConfig(CHACHA20, "another-secret-passphrase")
if err != nil {
t.Fatalf("Failed to create crypto config: %v", err)
}
testData := []byte("Testing ChaCha20-Poly1305 AEAD for encryption and decryption correctness.")
encrypted, err := config.Encrypt(testData)
if err != nil {
t.Fatalf("Failed to encrypt data: %v", err)
}
if bytes.Equal(testData, encrypted) {
t.Fatal("Encrypted data should be different from original")
}
decrypted, err := config.Decrypt(encrypted)
if err != nil {
t.Fatalf("Failed to decrypt data: %v", err)
}
if !bytes.Equal(testData, decrypted) {
t.Fatalf("Decrypted data doesn't match original. Got: %s, Expected: %s", string(decrypted), string(testData))
}
}
func TestCryptoConfig_NoEncryption(t *testing.T) {
config, err := NewCryptoConfig(NoEncryption, "")
if err != nil {
t.Fatalf("Failed to create crypto config: %v", err)
}
testData := []byte("This should not be encrypted")
// Test "encryption" (should return original data)
encrypted, err := config.Encrypt(testData)
if err != nil {
t.Fatalf("Failed to encrypt data: %v", err)
}
if !bytes.Equal(testData, encrypted) {
t.Fatal("No encryption should return original data")
}
// Test "decryption" (should return original data)
decrypted, err := config.Decrypt(encrypted)
if err != nil {
t.Fatalf("Failed to decrypt data: %v", err)
}
if !bytes.Equal(testData, decrypted) {
t.Fatal("No encryption should return original data")
}
}
func TestParseEncryptionMode(t *testing.T) {
tests := []struct {
input string
expected EncryptionMode
hasError bool
}{
{"", NoEncryption, false},
{"none", NoEncryption, false},
{"aes128", AES128, false},
{"aes256", AES256, false},
{"chacha20", CHACHA20, false},
{"chacha20-poly1305", CHACHA20, false},
{"invalid", NoEncryption, true},
}
for _, test := range tests {
result, err := ParseEncryptionMode(test.input)
if test.hasError && err == nil {
t.Fatalf("Expected error for input %s, but got none", test.input)
}
if !test.hasError && err != nil {
t.Fatalf("Unexpected error for input %s: %v", test.input, err)
}
if result != test.expected {
t.Fatalf("For input %s, expected %v, got %v", test.input, test.expected, result)
}
}
}
func TestKeyDerivation(t *testing.T) {
// Test with valid base64 key
validBase64 := "MTIzNDU2Nzg5MDEyMzQ1Ng==" // 16 bytes when decoded
key, err := deriveKey(validBase64, 16)
if err != nil {
t.Fatalf("Failed to derive key from valid base64: %v", err)
}
if len(key) != 16 {
t.Fatalf("Expected key length 16, got %d", len(key))
}
// Test with passphrase (should use PBKDF2)
passphrase := "my-secret-passphrase"
key2, err := deriveKey(passphrase, 32)
if err != nil {
t.Fatalf("Failed to derive key from passphrase: %v", err)
}
if len(key2) != 32 {
t.Fatalf("Expected key length 32, got %d", len(key2))
}
// Same passphrase should produce same key (deterministic)
key3, err := deriveKey(passphrase, 32)
if err != nil {
t.Fatalf("Failed to derive key from passphrase (second time): %v", err)
}
if !bytes.Equal(key2, key3) {
t.Fatal("Same passphrase should produce same derived key")
}
}

View File

@@ -5,6 +5,7 @@ go 1.24.1
require (
github.com/esrrhs/gohome v0.0.0-20250426022937-504d912bccf7
github.com/golang/protobuf v1.5.4
golang.org/x/crypto v0.37.0
golang.org/x/net v0.39.0
)
@@ -27,8 +28,6 @@ require (
github.com/xtaci/smux v1.5.34 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/mock v0.5.1 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect

View File

@@ -14,7 +14,6 @@ github.com/esrrhs/gohome v0.0.0-20250426022937-504d912bccf7 h1:EpgZzfBgtv89nRgnp
github.com/esrrhs/gohome v0.0.0-20250426022937-504d912bccf7/go.mod h1:4kAeSdLmMeWMOpzi/Jx82YvDnrBHcbWcLT18FwTujFA=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -34,27 +33,20 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4=
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA=
github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
@@ -63,9 +55,9 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
@@ -80,33 +72,21 @@ github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZ
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
github.com/xtaci/smux v1.5.31 h1:3ha7sHtH46h85Iv7MfQogxasuRt1KPRhoFB3S4rmHgU=
github.com/xtaci/smux v1.5.31/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
github.com/xtaci/smux v1.5.34 h1:OUA9JaDFHJDT8ZT3ebwLWPAgEfE6sWo2LaTy3anXqwg=
github.com/xtaci/smux v1.5.34/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -115,40 +95,29 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -166,8 +135,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

BIN
pingtunnel/pingtunnel Executable file

Binary file not shown.

View File

@@ -15,7 +15,7 @@ import (
func sendICMP(id int, sequence int, conn icmp.PacketConn, server *net.IPAddr, target string,
connId string, msgType uint32, data []byte, sproto int, rproto int, key int,
tcpmode int, tcpmode_buffer_size int, tcpmode_maxwin int, tcpmode_resend_time int, tcpmode_compress int, tcpmode_stat int,
timeout int) {
timeout int, cryptoConfig *CryptoConfig) {
m := &MyMsg{
Id: connId,
@@ -40,6 +40,15 @@ func sendICMP(id int, sequence int, conn icmp.PacketConn, server *net.IPAddr, ta
return
}
// Encrypt the marshaled data if encryption is enabled
if cryptoConfig != nil {
mb, err = cryptoConfig.Encrypt(mb)
if err != nil {
loggo.Error("sendICMP Encrypt error %s %s", server.String(), err)
return
}
}
body := &icmp.Echo{
ID: id,
Seq: sequence,
@@ -61,7 +70,7 @@ func sendICMP(id int, sequence int, conn icmp.PacketConn, server *net.IPAddr, ta
conn.WriteTo(bytes, server)
}
func recvICMP(workResultLock *sync.WaitGroup, exit *bool, conn icmp.PacketConn, recv chan<- *Packet) {
func recvICMP(workResultLock *sync.WaitGroup, exit *bool, conn icmp.PacketConn, recv chan<- *Packet, cryptoConfig *CryptoConfig) {
defer common.CrashLog()
@@ -88,8 +97,20 @@ func recvICMP(workResultLock *sync.WaitGroup, exit *bool, conn icmp.PacketConn,
echoId := int(binary.BigEndian.Uint16(bytes[4:6]))
echoSeq := int(binary.BigEndian.Uint16(bytes[6:8]))
// Extract the payload data
payloadData := bytes[8:n]
// Decrypt the data if encryption is enabled
if cryptoConfig != nil {
payloadData, err = cryptoConfig.Decrypt(payloadData)
if err != nil {
loggo.Debug("recvICMP Decrypt error: %s", err)
continue
}
}
my := &MyMsg{}
err = proto.Unmarshal(bytes[8:n], my)
err = proto.Unmarshal(payloadData, my)
if err != nil {
loggo.Debug("Unmarshal MyMsg error: %s", err)
continue

View File

@@ -12,7 +12,7 @@ import (
"time"
)
func NewServer(key int, maxconn int, maxprocessthread int, maxprocessbuffer int, connecttmeout int) (*Server, error) {
func NewServer(key int, maxconn int, maxprocessthread int, maxprocessbuffer int, connecttmeout int, cryptoConfig *CryptoConfig) (*Server, error) {
s := &Server{
exit: false,
key: key,
@@ -20,6 +20,7 @@ func NewServer(key int, maxconn int, maxprocessthread int, maxprocessbuffer int,
maxprocessthread: maxprocessthread,
maxprocessbuffer: maxprocessbuffer,
connecttmeout: connecttmeout,
cryptoConfig: cryptoConfig,
}
if maxprocessthread > 0 {
@@ -40,6 +41,7 @@ type Server struct {
maxprocessthread int
maxprocessbuffer int
connecttmeout int
cryptoConfig *CryptoConfig
conn *icmp.PacketConn
@@ -85,7 +87,7 @@ func (p *Server) Run() error {
recv := make(chan *Packet, 10000)
p.recvcontrol = make(chan int, 1)
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv)
go recvICMP(&p.workResultLock, &p.exit, *p.conn, recv, p.cryptoConfig)
go func() {
defer common.CrashLog()
@@ -141,7 +143,7 @@ func (p *Server) processPacket(packet *Packet) {
sendICMP(packet.echoId, packet.echoSeq, *p.conn, packet.src, "", "", (uint32)(MyMsg_PING), packet.my.Data,
(int)(packet.my.Rproto), -1, p.key,
0, 0, 0, 0, 0, 0,
0)
0, p.cryptoConfig)
return
}
@@ -297,9 +299,9 @@ func (p *Server) RecvTCP(conn *ServerConn, id string, src *net.IPAddr) {
f := e.Value.(*network.Frame)
mb, _ := conn.fm.MarshalFrame(f)
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), mb,
conn.rproto, -1, p.key,
0, 0, 0, 0, 0, 0,
0)
conn.rproto, -1, p.key, 0,
0, 0, 0, 0, 0,
0, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(len(mb))
}
@@ -360,9 +362,9 @@ func (p *Server) RecvTCP(conn *ServerConn, id string, src *net.IPAddr) {
continue
}
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), mb,
conn.rproto, -1, p.key,
0, 0, 0, 0, 0, 0,
0)
conn.rproto, -1, p.key, 0,
0, 0, 0, 0, 0,
0, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(len(mb))
}
@@ -422,9 +424,9 @@ func (p *Server) RecvTCP(conn *ServerConn, id string, src *net.IPAddr) {
f := e.Value.(*network.Frame)
mb, _ := conn.fm.MarshalFrame(f)
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), mb,
conn.rproto, -1, p.key,
0, 0, 0, 0, 0, 0,
0)
conn.rproto, -1, p.key, 0,
0, 0, 0, 0, 0,
0, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(len(mb))
}
@@ -489,9 +491,9 @@ func (p *Server) Recv(conn *ServerConn, id string, src *net.IPAddr) {
conn.activeSendTime = now
sendICMP(conn.echoId, conn.echoSeq, *p.conn, src, "", id, (uint32)(MyMsg_DATA), bytes[:n],
conn.rproto, -1, p.key,
0, 0, 0, 0, 0, 0,
0)
conn.rproto, -1, p.key, 0,
0, 0, 0, 0, 0,
0, p.cryptoConfig)
p.sendPacket++
p.sendPacketSize += (uint64)(n)
@@ -577,8 +579,8 @@ func (p *Server) deleteServerConn(uuid string) {
func (p *Server) remoteError(echoId int, echoSeq int, uuid string, rprpto int, src *net.IPAddr) {
sendICMP(echoId, echoSeq, *p.conn, src, "", uuid, (uint32)(MyMsg_KICK), []byte{},
rprpto, -1, p.key,
0, 0, 0, 0, 0, 0,
0)
0, 0, 0, 0, 0, 0, 0,
p.cryptoConfig)
}
func (p *Server) addConnError(addr string) {

View File

@@ -269,38 +269,18 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
[[package]]
name = "bindgen"
version = "0.69.5"
version = "0.72.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
dependencies = [
"bitflags 2.9.1",
"cexpr",
"clang-sys",
"itertools 0.12.1",
"lazy_static",
"lazycell",
"itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn 2.0.104",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags 2.9.1",
"cexpr",
"clang-sys",
"itertools 0.13.0",
"proc-macro2",
"quote",
"regex",
"rustc-hash 2.1.1",
"rustc-hash",
"shlex",
"syn 2.0.104",
]
@@ -1833,15 +1813,6 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
@@ -1958,17 +1929,11 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.174"
version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libloading"
@@ -1977,7 +1942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.53.2",
]
[[package]]
@@ -2002,11 +1967,11 @@ dependencies = [
[[package]]
name = "librocksdb-sys"
version = "0.17.1+9.9.3"
version = "0.17.3+10.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b7869a512ae9982f4d46ba482c2a304f1efd80c6412a3d4bf57bb79a619679f"
checksum = "cef2a00ee60fe526157c9023edab23943fae1ce2ab6f4abb2a807c1746835de9"
dependencies = [
"bindgen 0.69.5",
"bindgen",
"bzip2-sys",
"cc",
"libc",
@@ -2700,7 +2665,7 @@ dependencies = [
"pin-project-lite",
"quinn-proto",
"quinn-udp",
"rustc-hash 2.1.1",
"rustc-hash",
"rustls",
"socket2 0.5.10",
"thiserror 2.0.12",
@@ -2720,7 +2685,7 @@ dependencies = [
"lru-slab",
"rand 0.9.2",
"ring",
"rustc-hash 2.1.1",
"rustc-hash",
"rustls",
"rustls-pki-types",
"slab",
@@ -2976,9 +2941,9 @@ dependencies = [
[[package]]
name = "rocksdb"
version = "0.23.0"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26ec73b20525cb235bad420f911473b69f9fe27cc856c5461bccd7e4af037f43"
checksum = "ddb7af00d2b17dbd07d82c0063e25411959748ff03e8d4f96134c2ff41fce34f"
dependencies = [
"libc",
"librocksdb-sys",
@@ -3031,12 +2996,6 @@ version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.1.1"
@@ -4384,7 +4343,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -4941,7 +4900,6 @@ version = "2.0.15+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
dependencies = [
"bindgen 0.71.1",
"cc",
"pkg-config",
]

View File

@@ -134,7 +134,7 @@ bytes = "1.7"
byte_string = "1.0"
byteorder = "1.5"
rand = { version = "0.9", features = ["small_rng"] }
rocksdb = { version = "0.23", optional = true }
rocksdb = { version = "0.24", optional = true }
futures = "0.3"
tokio = { version = "1.38", features = [

View File

@@ -543,7 +543,7 @@ impl AccessControl {
/// Returns the ASCII representation a domain name,
/// if conversion fails returns original string
fn convert_to_ascii(host: &str) -> Cow<str> {
fn convert_to_ascii(host: &str) -> Cow<'_, str> {
idna::domain_to_ascii(host)
.map(From::from)
.unwrap_or_else(|_| host.into())

View File

@@ -46,7 +46,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Check input version
if: github.event_name == 'workflow_dispatch'
run: |-
@@ -109,7 +109,7 @@ jobs:
if: ${{ ! matrix.legacy_go }}
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Cache Legacy Go
if: matrix.require_legacy_go
id: cache-legacy-go
@@ -294,7 +294,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Setup Android NDK
id: setup-ndk
uses: nttld/setup-ndk@v1
@@ -374,7 +374,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Setup Android NDK
id: setup-ndk
uses: nttld/setup-ndk@v1
@@ -472,7 +472,7 @@ jobs:
if: matrix.if
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Setup Xcode stable
if: matrix.if && github.ref == 'refs/heads/main-next'
run: |-

View File

@@ -28,7 +28,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:

View File

@@ -7,6 +7,11 @@ on:
description: "Version name"
required: true
type: string
forceBeta:
description: "Force beta"
required: false
type: boolean
default: false
release:
types:
- published
@@ -25,7 +30,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Check input version
if: github.event_name == 'workflow_dispatch'
run: |-
@@ -66,7 +71,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.24.5
go-version: ^1.24.6
- name: Setup Android NDK
if: matrix.os == 'android'
uses: nttld/setup-ndk@v1
@@ -99,11 +104,11 @@ jobs:
run: |-
TZ=UTC touch -t '197001010000' dist/sing-box
- name: Set name
if: ${{ ! contains(needs.calculate_version.outputs.version, '-') }}
if: (! contains(needs.calculate_version.outputs.version, '-')) && !inputs.forceBeta
run: |-
echo "NAME=sing-box" >> "$GITHUB_ENV"
- name: Set beta name
if: contains(needs.calculate_version.outputs.version, '-')
if: contains(needs.calculate_version.outputs.version, '-') || inputs.forceBeta
run: |-
echo "NAME=sing-box-beta" >> "$GITHUB_ENV"
- name: Set version

View File

@@ -5,12 +5,13 @@ plugins {
id "kotlin-android"
id "kotlin-parcelize"
id "com.google.devtools.ksp"
id "org.jetbrains.kotlin.plugin.compose"
id "com.github.triplet.play"
}
android {
namespace "io.nekohasekai.sfa"
compileSdk 35
compileSdk 36
ndkVersion "28.0.13004108"
@@ -85,6 +86,7 @@ android {
buildFeatures {
viewBinding true
aidl true
compose true
}
applicationVariants.configureEach { variant ->
@@ -103,10 +105,10 @@ dependencies {
implementation "androidx.appcompat:appcompat:1.7.1"
implementation "com.google.android.material:material:1.12.0"
implementation "androidx.constraintlayout:constraintlayout:2.2.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.9.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.1"
implementation "androidx.navigation:navigation-fragment-ktx:2.9.1"
implementation "androidx.navigation:navigation-ui-ktx:2.9.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.9.2"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.2"
implementation "androidx.navigation:navigation-fragment-ktx:2.9.3"
implementation "androidx.navigation:navigation-ui-ktx:2.9.3"
implementation "com.google.zxing:core:3.5.3"
implementation "androidx.room:room-runtime:2.7.2"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.3.0"
@@ -115,8 +117,8 @@ dependencies {
implementation "androidx.camera:camera-lifecycle:1.4.2"
implementation "androidx.camera:camera-camera2:1.4.2"
ksp "androidx.room:room-compiler:2.7.2"
implementation "androidx.work:work-runtime-ktx:2.10.2"
implementation "androidx.browser:browser:1.8.0"
implementation "androidx.work:work-runtime-ktx:2.10.3"
implementation "androidx.browser:browser:1.9.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2"
// DO NOT UPDATE (minSdkVersion updated)
@@ -129,6 +131,19 @@ dependencies {
implementation "com.google.guava:guava:33.4.8-android"
playImplementation "com.google.android.play:app-update-ktx:2.1.0"
playImplementation "com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1"
def composeBom = platform('androidx.compose:compose-bom:2025.07.00')
implementation composeBom
androidTestImplementation composeBom
implementation 'androidx.compose.material3:material3'
implementation 'androidx.compose.ui:ui-tooling-preview'
debugImplementation 'androidx.compose.ui:ui-tooling'
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
debugImplementation 'androidx.compose.ui:ui-test-manifest'
implementation 'androidx.compose.material:material-icons-extended'
implementation 'androidx.activity:activity-compose:1.10.1'
implementation 'me.zhanghai.compose.preference:library:1.1.1'
implementation "androidx.navigation:navigation-compose:2.9.3"
}
def playCredentialsJSON = rootProject.file("service-account-credentials.json")

View File

@@ -5,10 +5,11 @@ buildscript {
}
plugins {
id 'com.android.application' version '8.11.0' apply false
id 'com.android.library' version '8.11.0' apply false
id 'org.jetbrains.kotlin.android' version '2.1.0' apply false
id 'com.google.devtools.ksp' version '2.1.0-1.0.29' apply false
id 'com.github.triplet.play' version '3.8.4' apply false
id 'com.android.application' version '8.11.1' apply false
id 'com.android.library' version '8.11.1' apply false
id 'org.jetbrains.kotlin.android' version '2.2.0' apply false
id 'com.google.devtools.ksp' version '2.2.0-2.0.2' apply false
id 'com.github.triplet.play' version '3.12.1' apply false
id 'org.jetbrains.kotlin.plugin.compose' version '2.2.0' apply false
}

View File

@@ -1,3 +1,3 @@
VERSION_CODE=549
VERSION_NAME=1.12.0
GO_VERSION=go1.24.5
VERSION_CODE=550
VERSION_NAME=1.12.1
GO_VERSION=go1.24.6

View File

@@ -423,4 +423,12 @@ public class ExtensionPlatformInterface: NSObject, LibboxPlatformInterfaceProtoc
}
#endif
}
public func localDNSTransport() -> (any LibboxLocalDNSTransportProtocol)? {
nil
}
public func systemCertificates() -> (any LibboxStringIteratorProtocol)? {
nil
}
}

View File

@@ -2163,7 +2163,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = 1.12.0;
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt;
PRODUCT_NAME = "sing-box";
SDKROOT = appletvos;
@@ -2198,7 +2198,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = 1.12.0;
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt;
PRODUCT_NAME = "sing-box";
SDKROOT = appletvos;
@@ -2503,7 +2503,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = 1.12.10;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt;
PRODUCT_NAME = "sing-box";
@@ -2545,7 +2545,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = 1.12.10;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt;
PRODUCT_NAME = "sing-box";
@@ -2586,7 +2586,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = 1.12.0;
OTHER_CODE_SIGN_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt;
PRODUCT_NAME = "sing-box";
@@ -2626,7 +2626,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = 1.12.0;
OTHER_CODE_SIGN_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt;
PRODUCT_NAME = "sing-box";
@@ -2754,7 +2754,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = "1.12.0-beta.2";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt.system;
PRODUCT_NAME = "$(inherited)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2790,7 +2790,7 @@
"@executable_path/../../../../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = "1.12.0-beta.2";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt.system;
PRODUCT_NAME = "$(inherited)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2832,7 +2832,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = "1.12.0-beta.2";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt.standalone;
PRODUCT_NAME = SFM;
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2873,7 +2873,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.11.5;
MARKETING_VERSION = "1.12.0-beta.2";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfavt.standalone;
PRODUCT_NAME = SFM;
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -107,13 +107,13 @@ func buildAndroid() {
}
if !debugEnabled {
sharedFlags[3] = sharedFlags[3] + " -checklinkname=0"
args = append(args, sharedFlags...)
} else {
debugFlags[1] = debugFlags[1] + " -checklinkname=0"
args = append(args, debugFlags...)
}
args = append(args, "-ldflags", "-checklinkname=0")
tags := append(sharedTags, memcTags...)
if debugEnabled {
tags = append(tags, debugTags...)

View File

@@ -454,5 +454,5 @@ func parseADGuardIPCIDRLine(ruleLine string) (netip.Prefix, error) {
for len(ruleParts) < 4 {
ruleParts = append(ruleParts, 0)
}
return netip.PrefixFrom(netip.AddrFrom4(*(*[4]byte)(ruleParts)), bitLen), nil
return netip.PrefixFrom(netip.AddrFrom4([4]byte(ruleParts)), bitLen), nil
}

View File

@@ -111,7 +111,7 @@ func NewWithOptions(options Options) (N.Dialer, error) {
dnsQueryOptions.Transport = dnsTransport.Default()
} else if options.NewDialer {
return nil, E.New("missing domain resolver for domain server address")
} else if !options.DirectOutbound {
} else {
deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver)
}
}

View File

@@ -96,11 +96,11 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
switch {
case flag&0x1 > 0 && isIPv4:
// ipv4
srcIP = netip.AddrFrom4(*(*[4]byte)(buf[inp+76 : inp+80]))
srcIP = netip.AddrFrom4([4]byte(buf[inp+76 : inp+80]))
srcIsIPv4 = true
case flag&0x2 > 0 && !isIPv4:
// ipv6
srcIP = netip.AddrFrom16(*(*[16]byte)(buf[inp+64 : inp+80]))
srcIP = netip.AddrFrom16([16]byte(buf[inp+64 : inp+80]))
default:
continue
}

View File

@@ -2,6 +2,8 @@ package tls
import (
"context"
"crypto/tls"
"errors"
"net"
"os"
@@ -41,6 +43,13 @@ func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, e
ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
defer cancel()
tlsConn, err := aTLS.ClientHandshake(ctx, conn, config)
var echErr *tls.ECHRejectionError
if errors.As(err, &echErr) && len(echErr.RetryConfigList) > 0 {
if echConfig, isECH := config.(ECHCapableConfig); isECH {
echConfig.SetECHConfigList(echErr.RetryConfigList)
tlsConn, err = aTLS.ClientHandshake(ctx, conn, config)
}
}
if err != nil {
return nil, err
}

View File

@@ -20,8 +20,8 @@ import (
)
func dnsReadConfig(_ context.Context, _ string) *dnsConfig {
var state C.res_state
if C.res_ninit(state) != 0 {
var state C.struct___res_state
if C.res_ninit(&state) != 0 {
return &dnsConfig{
servers: defaultNS,
search: dnsDefaultSearch(),

View File

@@ -0,0 +1,13 @@
package local
import (
"context"
"testing"
"github.com/stretchr/testify/require"
)
func TestDNSReadConfig(t *testing.T) {
t.Parallel()
require.NoError(t, dnsReadConfig(context.Background(), "/etc/resolv.conf").err)
}

View File

@@ -2,6 +2,10 @@
icon: material/alert-decagram
---
#### 1.12.1
* Fixes and improvements
#### 1.12.0
* Refactor DNS servers **1**

View File

@@ -61,7 +61,7 @@ WireGuard MTU。
==必填==
接口的 IPv4/IPv6 地址或地址段的列表
接口的 IPv4/IPv6 地址或地址段的列表。
要分配给接口的 IPv4 或 v6地址段列表。

View File

@@ -88,7 +88,7 @@ icon: material/delete-clock
==必填==
接口的 IPv4/IPv6 地址或地址段的列表
接口的 IPv4/IPv6 地址或地址段的列表。
要分配给接口的 IPv4 或 v6地址段列表。

View File

@@ -108,7 +108,7 @@ flowchart TB
"inbounds": [
{
"type": "tun",
"inet4_address": "172.19.0.1/30",
"address": ["172.19.0.1/30"],
"auto_route": true,
// "auto_redirect": true, // On linux
"strict_route": true
@@ -162,8 +162,7 @@ flowchart TB
"inbounds": [
{
"type": "tun",
"inet4_address": "172.19.0.1/30",
"inet6_address": "fdfe:dcba:9876::1/126",
"address": ["172.19.0.1/30", "fdfe:dcba:9876::1/126"],
"auto_route": true,
// "auto_redirect": true, // On linux
"strict_route": true
@@ -233,8 +232,7 @@ flowchart TB
"inbounds": [
{
"type": "tun",
"inet4_address": "172.19.0.1/30",
"inet6_address": "fdfe:dcba:9876::1/126",
"address": ["172.19.0.1/30","fdfe:dcba:9876::1/126"],
"auto_route": true,
// "auto_redirect": true, // On linux
"strict_route": true

View File

@@ -8,7 +8,7 @@ icon: material/arrange-bring-forward
DNS 服务器已经重构。
!!! info "用"
!!! info "用"
[DNS 服务器](/configuration/dns/server/) /
[旧 DNS 服务器](/configuration/dns/server/legacy/)

View File

@@ -14,6 +14,7 @@ import (
func cacheRouter(ctx context.Context) http.Handler {
r := chi.NewRouter()
r.Post("/fakeip/flush", flushFakeip(ctx))
r.Post("/dns/flush", flushDNS(ctx))
return r
}
@@ -31,3 +32,13 @@ func flushFakeip(ctx context.Context) func(w http.ResponseWriter, r *http.Reques
render.NoContent(w, r)
}
}
func flushDNS(ctx context.Context) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
if dnsRouter != nil {
dnsRouter.ClearCache()
}
render.NoContent(w, r)
}
}

View File

@@ -27,7 +27,7 @@ require (
github.com/sagernet/gomobile v0.1.7
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
github.com/sagernet/quic-go v0.52.0-beta.1
github.com/sagernet/sing v0.7.0-beta.2
github.com/sagernet/sing v0.7.5
github.com/sagernet/sing-mux v0.3.2
github.com/sagernet/sing-quic v0.5.0-beta.3
github.com/sagernet/sing-shadowsocks v0.2.8

View File

@@ -167,8 +167,8 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.0-beta.2 h1:UImAKtHGQX205lGYYXKA2qnEeVSml+hKS1oaOwvA14c=
github.com/sagernet/sing v0.7.0-beta.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.5 h1:gNMwZCLPqR+4e0g6dwi0sSsrvOmoMjpZgqxKsuJZatc=
github.com/sagernet/sing v0.7.5/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
github.com/sagernet/sing-quic v0.5.0-beta.3 h1:X/acRNsqQNfDlmwE7SorHfaZiny5e67hqIzM/592ric=

View File

@@ -26,7 +26,7 @@ func defaultRouteIP() (netip.Addr, error) {
for _, addr := range addrs {
ip := addr.(*net.IPNet).IP
if ip.To4() != nil {
return netip.AddrFrom4(*(*[4]byte)(ip)), nil
return netip.AddrFrom4([4]byte(ip)), nil
}
}

Some files were not shown because too many files have changed in this diff Show More