Update On Tue Apr 1 20:37:32 CEST 2025

This commit is contained in:
github-action[bot]
2025-04-01 20:37:32 +02:00
parent 65c359fa66
commit 2ca4683e7a
161 changed files with 2308 additions and 3540 deletions
+1
View File
@@ -959,3 +959,4 @@ Update On Fri Mar 28 19:38:10 CET 2025
Update On Sat Mar 29 19:34:26 CET 2025
Update On Sun Mar 30 20:34:10 CEST 2025
Update On Mon Mar 31 20:36:40 CEST 2025
Update On Tue Apr 1 20:37:22 CEST 2025
+2 -2
View File
@@ -46,8 +46,8 @@ subprojects {
minSdk = 21
targetSdk = 35
versionName = "2.11.7"
versionCode = 211007
versionName = "2.11.8"
versionCode = 211008
resValue("string", "release_name", "v$versionName")
resValue("integer", "release_code", "$versionCode")
@@ -8,11 +8,13 @@ import (
"strconv"
"sync"
CN "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
mieruclient "github.com/enfein/mieru/v3/apis/client"
mierucommon "github.com/enfein/mieru/v3/apis/common"
mierumodel "github.com/enfein/mieru/v3/apis/model"
mierupb "github.com/enfein/mieru/v3/pkg/appctl/appctlpb"
"google.golang.org/protobuf/proto"
@@ -32,6 +34,7 @@ type MieruOption struct {
Port int `proxy:"port,omitempty"`
PortRange string `proxy:"port-range,omitempty"`
Transport string `proxy:"transport"`
UDP bool `proxy:"udp,omitempty"`
UserName string `proxy:"username"`
Password string `proxy:"password"`
Multiplexing string `proxy:"multiplexing,omitempty"`
@@ -50,6 +53,23 @@ func (m *Mieru) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
return NewConn(c, m), nil
}
// ListenPacketContext implements C.ProxyAdapter
func (m *Mieru) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
if err := m.ensureClientIsRunning(opts...); err != nil {
return nil, err
}
c, err := m.client.DialContext(ctx, metadata.UDPAddr())
if err != nil {
return nil, fmt.Errorf("dial to %s failed: %w", metadata.UDPAddr(), err)
}
return newPacketConn(CN.NewRefPacketConn(CN.NewThreadSafePacketConn(mierucommon.NewUDPAssociateWrapper(mierucommon.NewPacketOverStreamTunnel(c))), m), m), nil
}
// SupportUOT implements C.ProxyAdapter
func (m *Mieru) SupportUOT() bool {
return true
}
// ProxyInfo implements C.ProxyAdapter
func (m *Mieru) ProxyInfo() C.ProxyInfo {
info := m.Base.ProxyInfo()
@@ -113,7 +133,7 @@ func NewMieru(option MieruOption) (*Mieru, error) {
addr: addr,
iface: option.Interface,
tp: C.Mieru,
udp: false,
udp: option.UDP,
xudp: false,
rmark: option.RoutingMark,
prefer: C.NewDNSPrefer(option.IPVersion),
@@ -45,7 +45,11 @@ func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr,
addr = &net.UDPAddr{IP: ip[:], Port: from.Port}
case *syscall.SockaddrInet6:
ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes
addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)}
zone := ""
if from.ZoneId != 0 {
zone = strconv.FormatInt(int64(from.ZoneId), 10)
}
addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: zone}
}
}
// udp should not convert readN == 0 to io.EOF
@@ -54,7 +54,11 @@ func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr,
addr = &net.UDPAddr{IP: ip[:], Port: from.Port}
case *windows.SockaddrInet6:
ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes
addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)}
zone := ""
if from.ZoneId != 0 {
zone = strconv.FormatInt(int64(from.ZoneId), 10)
}
addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: zone}
}
}
// udp should not convert readN == 0 to io.EOF
@@ -75,7 +75,15 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string
//log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16])
ecdheKey := uConn.HandshakeState.State13.EcdheKey
keyShareKeys := uConn.HandshakeState.State13.KeyShareKeys
if keyShareKeys == nil {
// WTF???
if retry > 2 {
return nil, errors.New("nil keyShareKeys")
}
continue // retry
}
ecdheKey := keyShareKeys.Ecdhe
if ecdheKey == nil {
// WTF???
if retry > 2 {
@@ -3,8 +3,9 @@
package dns
import (
"net"
"net/netip"
"os"
"strconv"
"syscall"
"unsafe"
@@ -23,28 +24,31 @@ func dnsReadConfig() (servers []string, err error) {
if err != nil {
continue
}
var ip net.IP
var ip netip.Addr
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
ip = net.IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
ip = netip.AddrFrom4(sa.Addr)
case *syscall.SockaddrInet6:
ip = make(net.IP, net.IPv6len)
copy(ip, sa.Addr[:])
if ip[0] == 0xfe && ip[1] == 0xc0 {
if sa.Addr[0] == 0xfe && sa.Addr[1] == 0xc0 {
// Ignore these fec0/10 ones. Windows seems to
// populate them as defaults on its misc rando
// interfaces.
continue
}
ip = netip.AddrFrom16(sa.Addr)
if sa.ZoneId != 0 {
ip = ip.WithZone(strconv.FormatInt(int64(sa.ZoneId), 10))
}
//continue
default:
// Unexpected type.
continue
}
if slices.Contains(servers, ip.String()) {
ipStr := ip.String()
if slices.Contains(servers, ipStr) {
continue
}
servers = append(servers, ip.String())
servers = append(servers, ipStr)
}
}
return
@@ -879,6 +879,7 @@ proxies: # socks5
port: 2999
# port-range: 2090-2099 #(不可同时填写 port 和 port-range
transport: TCP # 只支持 TCP
udp: true # 支持 UDP over TCP
username: user
password: password
# 可以使用的值包括 MULTIPLEXING_OFF, MULTIPLEXING_LOW, MULTIPLEXING_MIDDLE, MULTIPLEXING_HIGH。其中 MULTIPLEXING_OFF 会关闭多路复用功能。默认值为 MULTIPLEXING_LOW。
@@ -7,7 +7,7 @@ require (
github.com/bahlo/generic-list-go v0.2.0
github.com/coreos/go-iptables v0.8.0
github.com/dlclark/regexp2 v1.11.5
github.com/enfein/mieru/v3 v3.12.0
github.com/enfein/mieru/v3 v3.13.0
github.com/go-chi/chi/v5 v5.2.1
github.com/go-chi/render v1.0.3
github.com/gobwas/ws v1.4.0
@@ -32,7 +32,7 @@ require (
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422
github.com/metacubex/utls v1.6.6
github.com/metacubex/utls v1.6.8-alpha.4
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181
github.com/miekg/dns v1.1.63
github.com/mroth/weightedrand/v2 v2.1.0
@@ -91,7 +91,7 @@ require (
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
@@ -28,8 +28,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.12.0 h1:sV3moozWpRjjqwqFZJjGtMB0EacN8+D7BpjzsmacsXM=
github.com/enfein/mieru/v3 v3.12.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/enfein/mieru/v3 v3.13.0 h1:eGyxLGkb+lut9ebmx+BGwLJ5UMbEc/wGIYO0AXEKy98=
github.com/enfein/mieru/v3 v3.13.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -105,8 +105,8 @@ github.com/metacubex/chacha v0.1.1 h1:OHIv11Nd9CISAIzegpjfupIoZp9DYm6uQw41RxvmU/
github.com/metacubex/chacha v0.1.1/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a h1:cZ6oNVrsmsi3SNlnSnRio4zOgtQq+/XidwsaNgKICcg=
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a/go.mod h1:xBw/SYJPgUMPQ1tklV/brGn2nxhfr3BnvBzNlyi4Nic=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM9MQ2ySuqu2aeBqcA8rtfWUYLZ8RtI=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 h1:B+AP/Pj2/jBDS/kCYjz/x+0BCOKfd2VODYevyeIt+Ds=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996/go.mod h1:ExVjGyEwTUjCFqx+5uxgV7MOoA3fZI+th4D40H35xmY=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
@@ -129,8 +129,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8=
github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo=
github.com/metacubex/utls v1.6.8-alpha.4 h1:5EvsCHxDNneaOtAyc8CztoNSpmonLvkvuGs01lIeeEI=
github.com/metacubex/utls v1.6.8-alpha.4/go.mod h1:MEZ5WO/VLKYs/s/dOzEK/mlXOQxc04ESeLzRgjmLYtk=
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=
@@ -174,6 +174,12 @@ func (l *Listener) HandleConn(conn net.Conn, h *sing.ListenerHandler) {
return
}
// It seems that mihomo does not implement a connection error reporting mechanism, so we report success directly.
err = stream.HandshakeSuccess()
if err != nil {
return
}
h.NewConnection(ctx, stream, M.Metadata{
Source: M.SocksaddrFromNet(conn.RemoteAddr()),
Destination: destination,
@@ -47,7 +47,7 @@ func removeExtraHTTPHostPort(req *http.Request) {
host = req.URL.Host
}
if pHost, port, err := net.SplitHostPort(host); err == nil && (port == "80" || port == "443") {
if pHost, port, err := net.SplitHostPort(host); err == nil && port == "80" {
host = pHost
if ip, err := netip.ParseAddr(pHost); err == nil && ip.Is6() {
// RFC 2617 Sec 3.2.2, for IPv6 literal
@@ -76,6 +76,7 @@ func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPLi
rAddr, err := getOrigDst(oob[:oobn])
if err != nil {
pool.Put(buf)
continue
}
@@ -15,10 +15,10 @@ import (
const CheckMark = -1
var DefaultPaddingScheme = []byte(`stop=8
0=34-120
0=30-30
1=100-400
2=400-500,c,500-1000,c,400-500,c,500-1000,c,500-1000,c,400-500
3=500-1000
2=400-500,c,500-1000,c,500-1000,c,500-1000,c,500-1000
3=9-9,500-1000
4=500-1000
5=500-1000
6=500-1000
@@ -83,11 +83,7 @@ func (c *Client) CreateStream(ctx context.Context) (net.Conn, error) {
}
stream.dieHook = func() {
if session.IsClosed() {
if session.dieHook != nil {
session.dieHook()
}
} else {
if !session.IsClosed() {
select {
case <-c.die.Done():
// Now client has been closed
@@ -154,10 +150,10 @@ func (c *Client) Close() error {
c.sessionsLock.Lock()
sessionToClose := make([]*Session, 0, len(c.sessions))
for seq, session := range c.sessions {
for _, session := range c.sessions {
sessionToClose = append(sessionToClose, session)
delete(c.sessions, seq)
}
c.sessions = make(map[uint64]*Session)
c.sessionsLock.Unlock()
for _, session := range sessionToClose {
@@ -9,9 +9,14 @@ const ( // cmds
cmdSYN = 1 // stream open
cmdPSH = 2 // data push
cmdFIN = 3 // stream close, a.k.a EOF mark
cmdSettings = 4 // Settings
cmdSettings = 4 // Settings (Client send to Server)
cmdAlert = 5 // Alert
cmdUpdatePaddingScheme = 6 // update padding scheme
// Since version 2
cmdSYNACK = 7 // Server reports to the client that the stream has been opened
cmdHeartRequest = 8 // Keep alive command
cmdHeartResponse = 9 // Keep alive command
cmdServerSettings = 10 // Settings (Server send to client)
)
const (
@@ -3,9 +3,11 @@ package session
import (
"crypto/md5"
"encoding/binary"
"fmt"
"io"
"net"
"runtime/debug"
"strconv"
"sync"
"time"
@@ -30,11 +32,16 @@ type Session struct {
die chan struct{}
dieHook func()
synDone func()
synDoneLock sync.Mutex
// pool
seq uint64
idleSince time.Time
padding *atomic.TypedValue[*padding.PaddingFactory]
peerVersion byte
// client
isClient bool
sendPadding bool
@@ -76,7 +83,7 @@ func (s *Session) Run() {
}
settings := util.StringMap{
"v": "1",
"v": "2",
"client": "mihomo/" + constant.Version,
"padding-md5": s.padding.Load().Md5,
}
@@ -105,15 +112,16 @@ func (s *Session) Close() error {
close(s.die)
once = true
})
if once {
if s.dieHook != nil {
s.dieHook()
s.dieHook = nil
}
s.streamLock.Lock()
for k := range s.streams {
s.streams[k].sessionClose()
for _, stream := range s.streams {
stream.Close()
}
s.streams = make(map[uint32]*Stream)
s.streamLock.Unlock()
return s.conn.Close()
} else {
@@ -132,6 +140,17 @@ func (s *Session) OpenStream() (*Stream, error) {
//logrus.Debugln("stream open", sid, s.streams)
if sid >= 2 && s.peerVersion >= 2 {
s.synDoneLock.Lock()
if s.synDone != nil {
s.synDone()
}
s.synDone = util.NewDeadlineWatcher(time.Second*3, func() {
s.Close()
})
s.synDoneLock.Unlock()
}
if _, err := s.writeFrame(newFrame(cmdSYN, sid)); err != nil {
return nil, err
}
@@ -195,13 +214,37 @@ func (s *Session) recvLoop() error {
if _, ok := s.streams[sid]; !ok {
stream := newStream(sid, s)
s.streams[sid] = stream
if s.onNewStream != nil {
go s.onNewStream(stream)
} else {
go s.Close()
}
go func() {
if s.onNewStream != nil {
s.onNewStream(stream)
} else {
stream.Close()
}
}()
}
s.streamLock.Unlock()
case cmdSYNACK: // should be client only
s.synDoneLock.Lock()
if s.synDone != nil {
s.synDone()
s.synDone = nil
}
s.synDoneLock.Unlock()
if hdr.Length() > 0 {
buffer := pool.Get(int(hdr.Length()))
if _, err := io.ReadFull(s.conn, buffer); err != nil {
pool.Put(buffer)
return err
}
// report error
s.streamLock.RLock()
stream, ok := s.streams[sid]
s.streamLock.RUnlock()
if ok {
stream.CloseWithError(fmt.Errorf("remote: %s", string(buffer)))
}
pool.Put(buffer)
}
case cmdFIN:
s.streamLock.RLock()
stream, ok := s.streams[sid]
@@ -240,6 +283,20 @@ func (s *Session) recvLoop() error {
return err
}
}
// check client's version
if v, err := strconv.Atoi(m["v"]); err == nil && v >= 2 {
s.peerVersion = byte(v)
// send cmdServerSettings
f := newFrame(cmdServerSettings, 0)
f.data = util.StringMap{
"v": "2",
}.ToBytes()
_, err = s.writeFrame(f)
if err != nil {
pool.Put(buffer)
return err
}
}
}
pool.Put(buffer)
}
@@ -265,12 +322,35 @@ func (s *Session) recvLoop() error {
}
if s.isClient {
if padding.UpdatePaddingScheme(rawScheme, s.padding) {
log.Infoln("[Update padding succeed] %x\n", md5.Sum(rawScheme))
log.Debugln("[Update padding succeed] %x\n", md5.Sum(rawScheme))
} else {
log.Warnln("[Update padding failed] %x\n", md5.Sum(rawScheme))
}
}
}
case cmdHeartRequest:
if _, err := s.writeFrame(newFrame(cmdHeartResponse, sid)); err != nil {
return err
}
case cmdHeartResponse:
// Active keepalive checking is not implemented yet
break
case cmdServerSettings:
if hdr.Length() > 0 {
buffer := pool.Get(int(hdr.Length()))
if _, err := io.ReadFull(s.conn, buffer); err != nil {
pool.Put(buffer)
return err
}
if s.isClient {
// check server's version
m := util.StringMapFromBytes(buffer)
if v, err := strconv.Atoi(m["v"]); err == nil {
s.peerVersion = byte(v)
}
}
pool.Put(buffer)
}
default:
// I don't know what command it is (can't have data)
}
@@ -280,8 +360,10 @@ func (s *Session) recvLoop() error {
}
}
// notify the session that a stream has closed
func (s *Session) streamClosed(sid uint32) error {
if s.IsClosed() {
return io.ErrClosedPipe
}
_, err := s.writeFrame(newFrame(cmdFIN, sid))
s.streamLock.Lock()
delete(s.streams, sid)
@@ -22,6 +22,9 @@ type Stream struct {
dieOnce sync.Once
dieHook func()
dieErr error
reportOnce sync.Once
}
// newStream initiates a Stream struct
@@ -36,7 +39,11 @@ func newStream(id uint32, sess *Session) *Stream {
// Read implements net.Conn
func (s *Stream) Read(b []byte) (n int, err error) {
return s.pipeR.Read(b)
n, err = s.pipeR.Read(b)
if s.dieErr != nil {
err = s.dieErr
}
return
}
// Write implements net.Conn
@@ -54,25 +61,28 @@ func (s *Stream) Write(b []byte) (n int, err error) {
// Close implements net.Conn
func (s *Stream) Close() error {
if s.sessionClose() {
// notify remote
return s.sess.streamClosed(s.id)
} else {
return io.ErrClosedPipe
}
return s.CloseWithError(io.ErrClosedPipe)
}
// sessionClose close stream from session side, do not notify remote
func (s *Stream) sessionClose() (once bool) {
func (s *Stream) CloseWithError(err error) error {
// if err != io.ErrClosedPipe {
// logrus.Debugln(err)
// }
var once bool
s.dieOnce.Do(func() {
s.dieErr = err
s.pipeR.Close()
once = true
})
if once {
if s.dieHook != nil {
s.dieHook()
s.dieHook = nil
}
})
return
return s.sess.streamClosed(s.id)
} else {
return s.dieErr
}
}
func (s *Stream) SetReadDeadline(t time.Time) error {
@@ -108,3 +118,33 @@ func (s *Stream) RemoteAddr() net.Addr {
}
return nil
}
// HandshakeFailure should be called when Server fail to create outbound proxy
func (s *Stream) HandshakeFailure(err error) error {
var once bool
s.reportOnce.Do(func() {
once = true
})
if once && err != nil && s.sess.peerVersion >= 2 {
f := newFrame(cmdSYNACK, s.id)
f.data = []byte(err.Error())
if _, err := s.sess.writeFrame(f); err != nil {
return err
}
}
return nil
}
// HandshakeSuccess should be called when Server success to create outbound proxy
func (s *Stream) HandshakeSuccess() error {
var once bool
s.reportOnce.Do(func() {
once = true
})
if once && s.sess.peerVersion >= 2 {
if _, err := s.sess.writeFrame(newFrame(cmdSYNACK, s.id)); err != nil {
return err
}
}
return nil
}
@@ -0,0 +1,25 @@
package util
import (
"sync"
"time"
)
func NewDeadlineWatcher(ddl time.Duration, timeOut func()) (done func()) {
t := time.NewTimer(ddl)
closeCh := make(chan struct{})
go func() {
defer t.Stop()
select {
case <-closeCh:
case <-t.C:
timeOut()
}
}()
var once sync.Once
return func() {
once.Do(func() {
close(closeCh)
})
}
}
@@ -16,7 +16,7 @@ require (
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/enfein/mieru/v3 v3.12.0 // indirect
github.com/enfein/mieru/v3 v3.13.0 // indirect
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
@@ -49,7 +49,7 @@ require (
github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 // indirect
github.com/metacubex/chacha v0.1.1 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/mihomo v1.7.0 // indirect
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 // indirect
github.com/metacubex/randv2 v0.2.0 // indirect
@@ -61,7 +61,7 @@ require (
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 // indirect
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 // indirect
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect
github.com/metacubex/utls v1.6.6 // indirect
github.com/metacubex/utls v1.6.8-alpha.4 // indirect
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
@@ -28,8 +28,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.12.0 h1:sV3moozWpRjjqwqFZJjGtMB0EacN8+D7BpjzsmacsXM=
github.com/enfein/mieru/v3 v3.12.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/enfein/mieru/v3 v3.13.0 h1:eGyxLGkb+lut9ebmx+BGwLJ5UMbEc/wGIYO0AXEKy98=
github.com/enfein/mieru/v3 v3.13.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -105,8 +105,8 @@ github.com/metacubex/chacha v0.1.1 h1:OHIv11Nd9CISAIzegpjfupIoZp9DYm6uQw41RxvmU/
github.com/metacubex/chacha v0.1.1/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a h1:cZ6oNVrsmsi3SNlnSnRio4zOgtQq+/XidwsaNgKICcg=
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a/go.mod h1:xBw/SYJPgUMPQ1tklV/brGn2nxhfr3BnvBzNlyi4Nic=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM9MQ2ySuqu2aeBqcA8rtfWUYLZ8RtI=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 h1:B+AP/Pj2/jBDS/kCYjz/x+0BCOKfd2VODYevyeIt+Ds=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996/go.mod h1:ExVjGyEwTUjCFqx+5uxgV7MOoA3fZI+th4D40H35xmY=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
@@ -129,8 +129,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8=
github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo=
github.com/metacubex/utls v1.6.8-alpha.4 h1:5EvsCHxDNneaOtAyc8CztoNSpmonLvkvuGs01lIeeEI=
github.com/metacubex/utls v1.6.8-alpha.4/go.mod h1:MEZ5WO/VLKYs/s/dOzEK/mlXOQxc04ESeLzRgjmLYtk=
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=
@@ -24,7 +24,7 @@ require (
github.com/cloudflare/circl v1.3.7 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/enfein/mieru/v3 v3.12.0 // indirect
github.com/enfein/mieru/v3 v3.13.0 // indirect
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
@@ -58,7 +58,7 @@ require (
github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 // indirect
github.com/metacubex/chacha v0.1.1 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 // indirect
github.com/metacubex/randv2 v0.2.0 // indirect
github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 // indirect
@@ -69,7 +69,7 @@ require (
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 // indirect
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 // indirect
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect
github.com/metacubex/utls v1.6.6 // indirect
github.com/metacubex/utls v1.6.8-alpha.4 // indirect
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
@@ -28,8 +28,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.12.0 h1:sV3moozWpRjjqwqFZJjGtMB0EacN8+D7BpjzsmacsXM=
github.com/enfein/mieru/v3 v3.12.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/enfein/mieru/v3 v3.13.0 h1:eGyxLGkb+lut9ebmx+BGwLJ5UMbEc/wGIYO0AXEKy98=
github.com/enfein/mieru/v3 v3.13.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -106,8 +106,8 @@ github.com/metacubex/chacha v0.1.1 h1:OHIv11Nd9CISAIzegpjfupIoZp9DYm6uQw41RxvmU/
github.com/metacubex/chacha v0.1.1/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a h1:cZ6oNVrsmsi3SNlnSnRio4zOgtQq+/XidwsaNgKICcg=
github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a/go.mod h1:xBw/SYJPgUMPQ1tklV/brGn2nxhfr3BnvBzNlyi4Nic=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM9MQ2ySuqu2aeBqcA8rtfWUYLZ8RtI=
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 h1:B+AP/Pj2/jBDS/kCYjz/x+0BCOKfd2VODYevyeIt+Ds=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996/go.mod h1:ExVjGyEwTUjCFqx+5uxgV7MOoA3fZI+th4D40H35xmY=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
@@ -130,8 +130,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8=
github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo=
github.com/metacubex/utls v1.6.8-alpha.4 h1:5EvsCHxDNneaOtAyc8CztoNSpmonLvkvuGs01lIeeEI=
github.com/metacubex/utls v1.6.8-alpha.4/go.mod h1:MEZ5WO/VLKYs/s/dOzEK/mlXOQxc04ESeLzRgjmLYtk=
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=
@@ -11,7 +11,7 @@
"build": "tsc"
},
"dependencies": {
"@tanstack/react-query": "5.71.0",
"@tanstack/react-query": "5.71.1",
"@tauri-apps/api": "2.4.0",
"ahooks": "3.8.4",
"dayjs": "1.11.13",
@@ -53,12 +53,12 @@
"@csstools/normalize.css": "12.1.1",
"@emotion/babel-plugin": "11.13.5",
"@emotion/react": "11.14.0",
"@iconify/json": "2.2.321",
"@iconify/json": "2.2.322",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.71.0",
"@tanstack/react-query": "5.71.1",
"@tanstack/react-router": "1.114.29",
"@tanstack/router-devtools": "1.114.29",
"@tanstack/router-plugin": "1.114.30",
"@tanstack/router-devtools": "1.114.31",
"@tanstack/router-plugin": "1.114.31",
"@tauri-apps/plugin-clipboard-manager": "2.2.2",
"@tauri-apps/plugin-dialog": "2.2.0",
"@tauri-apps/plugin-fs": "2.2.0",
@@ -80,7 +80,7 @@
"meta-json-schema": "1.19.3",
"monaco-yaml": "5.3.1",
"nanoid": "5.1.5",
"sass-embedded": "1.86.0",
"sass-embedded": "1.86.1",
"shiki": "2.5.0",
"unplugin-auto-import": "19.1.2",
"unplugin-icons": "22.1.0",
+1 -1
View File
@@ -43,7 +43,7 @@
"@types/d3-interpolate-path": "2.0.3",
"clsx": "2.1.1",
"d3-interpolate-path": "2.3.0",
"sass-embedded": "1.86.0",
"sass-embedded": "1.86.1",
"tailwind-merge": "3.0.2",
"typescript-plugin-css-modules": "5.1.0",
"vite-plugin-dts": "4.5.3"
+2 -2
View File
@@ -65,7 +65,7 @@
"@tauri-apps/cli": "2.4.0",
"@types/fs-extra": "11.0.4",
"@types/lodash-es": "4.17.12",
"@types/node": "22.13.14",
"@types/node": "22.13.15",
"@typescript-eslint/eslint-plugin": "8.28.0",
"@typescript-eslint/parser": "8.28.0",
"autoprefixer": "10.4.21",
@@ -85,7 +85,7 @@
"eslint-plugin-react-compiler": "19.0.0-beta-e552027-20250112",
"eslint-plugin-react-hooks": "5.2.0",
"globals": "16.0.0",
"knip": "5.46.3",
"knip": "5.46.4",
"lint-staged": "15.5.0",
"neostandard": "0.12.1",
"npm-run-all2": "7.0.2",
+195 -195
View File
@@ -20,7 +20,7 @@ importers:
devDependencies:
'@commitlint/cli':
specifier: 19.8.0
version: 19.8.0(@types/node@22.13.14)(typescript@5.8.2)
version: 19.8.0(@types/node@22.13.15)(typescript@5.8.2)
'@commitlint/config-conventional':
specifier: 19.8.0
version: 19.8.0
@@ -43,8 +43,8 @@ importers:
specifier: 4.17.12
version: 4.17.12
'@types/node':
specifier: 22.13.14
version: 22.13.14
specifier: 22.13.15
version: 22.13.15
'@typescript-eslint/eslint-plugin':
specifier: 8.28.0
version: 8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)
@@ -103,8 +103,8 @@ importers:
specifier: 16.0.0
version: 16.0.0
knip:
specifier: 5.46.3
version: 5.46.3(@types/node@22.13.14)(typescript@5.8.2)
specifier: 5.46.4
version: 5.46.4(@types/node@22.13.15)(typescript@5.8.2)
lint-staged:
specifier: 15.5.0
version: 15.5.0
@@ -175,8 +175,8 @@ importers:
frontend/interface:
dependencies:
'@tanstack/react-query':
specifier: 5.71.0
version: 5.71.0(react@19.1.0)
specifier: 5.71.1
version: 5.71.1(react@19.1.0)
'@tauri-apps/api':
specifier: 2.4.0
version: 2.4.0
@@ -333,23 +333,23 @@ importers:
specifier: 11.14.0
version: 11.14.0(@types/react@19.0.12)(react@19.1.0)
'@iconify/json':
specifier: 2.2.321
version: 2.2.321
specifier: 2.2.322
version: 2.2.322
'@monaco-editor/react':
specifier: 4.7.0
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/react-query':
specifier: 5.71.0
version: 5.71.0(react@19.1.0)
specifier: 5.71.1
version: 5.71.1(react@19.1.0)
'@tanstack/react-router':
specifier: 1.114.29
version: 1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/router-devtools':
specifier: 1.114.29
version: 1.114.29(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)
specifier: 1.114.31
version: 1.114.31(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)
'@tanstack/router-plugin':
specifier: 1.114.30
version: 1.114.30(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
specifier: 1.114.31
version: 1.114.31(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
'@tauri-apps/plugin-clipboard-manager':
specifier: 2.2.2
version: 2.2.2
@@ -385,13 +385,13 @@ importers:
version: 13.12.3
'@vitejs/plugin-legacy':
specifier: 6.0.2
version: 6.0.2(terser@5.36.0)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 6.0.2(terser@5.36.0)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
'@vitejs/plugin-react':
specifier: 4.3.4
version: 4.3.4(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 4.3.4(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
'@vitejs/plugin-react-swc':
specifier: 3.8.1
version: 3.8.1(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 3.8.1(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
change-case:
specifier: 5.4.4
version: 5.4.4
@@ -414,8 +414,8 @@ importers:
specifier: 5.1.5
version: 5.1.5
sass-embedded:
specifier: 1.86.0
version: 1.86.0
specifier: 1.86.1
version: 1.86.1
shiki:
specifier: 2.5.0
version: 2.5.0
@@ -430,19 +430,19 @@ importers:
version: 13.15.0
vite:
specifier: 6.2.3
version: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
version: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite-plugin-html:
specifier: 3.2.2
version: 3.2.2(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 3.2.2(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
vite-plugin-sass-dts:
specifier: 1.3.31
version: 1.3.31(postcss@8.5.3)(prettier@3.5.3)(sass-embedded@1.86.0)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 1.3.31(postcss@8.5.3)(prettier@3.5.3)(sass-embedded@1.86.1)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
vite-plugin-svgr:
specifier: 4.3.0
version: 4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
vite-tsconfig-paths:
specifier: 5.1.4
version: 5.1.4(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 5.1.4(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
zod:
specifier: 3.24.2
version: 3.24.2
@@ -478,7 +478,7 @@ importers:
version: 19.0.12
'@vitejs/plugin-react':
specifier: 4.3.4
version: 4.3.4(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 4.3.4(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
ahooks:
specifier: 3.8.4
version: 3.8.4(react@19.1.0)
@@ -508,10 +508,10 @@ importers:
version: 4.0.17
vite:
specifier: 6.2.3
version: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
version: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite-tsconfig-paths:
specifier: 5.1.4
version: 5.1.4(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 5.1.4(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
devDependencies:
'@emotion/react':
specifier: 11.14.0
@@ -526,8 +526,8 @@ importers:
specifier: 2.3.0
version: 2.3.0
sass-embedded:
specifier: 1.86.0
version: 1.86.0
specifier: 1.86.1
version: 1.86.1
tailwind-merge:
specifier: 3.0.2
version: 3.0.2
@@ -536,7 +536,7 @@ importers:
version: 5.1.0(typescript@5.8.2)
vite-plugin-dts:
specifier: 4.5.3
version: 4.5.3(@types/node@22.13.14)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
version: 4.5.3(@types/node@22.13.15)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))
scripts:
dependencies:
@@ -1680,8 +1680,8 @@ packages:
'@vue/compiler-sfc':
optional: true
'@iconify/json@2.2.321':
resolution: {integrity: sha512-0D1OjRK77jD7dhrb4IhGiBTqLufi6I6HaYso6qkSkvm0WqbWgzGnoNEpw+g/jzSJAiLfuBwOGz6b7Q/ZJqsYrw==}
'@iconify/json@2.2.322':
resolution: {integrity: sha512-/P2UFkVgzrCwkTKEfvOITzjrEQB9jfPd03LicRYFrNWpycP/pzxq1jt+bt6Zq8iaPVSddTMLMPQqdNgeAkWfnQ==}
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
@@ -2782,16 +2782,16 @@ packages:
resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==}
engines: {node: '>=12'}
'@tanstack/query-core@5.71.0':
resolution: {integrity: sha512-p4+T7CIEe1kMhii4booWiw42nuaiYI9La/bRCNzBaj1P3PDb0dEZYDhc/7oBifKJfHYN+mtS1ynW1qsmzQW7Og==}
'@tanstack/query-core@5.71.1':
resolution: {integrity: sha512-4+ZswCHOfJX+ikhXNoocamTUmJcHtB+Ljjz/oJkC7/eKB5IrzEwR4vEwZUENiPi+wISucJHR5TUbuuJ26w3kdQ==}
'@tanstack/react-query@5.71.0':
resolution: {integrity: sha512-Udhlz9xHwk0iB7eLDchIqvu666NZFxPZZF80KnL8sZy+5J0kMvnJkzQNYRJwF70g8Vc1nn0TSMkPJgvx6+Pn4g==}
'@tanstack/react-query@5.71.1':
resolution: {integrity: sha512-6BTkaSIGT58MroI4kIGXNdx/NhirXPU+75AJObLq+WBa39WmoxhzSk0YX+hqWJ/bvqZJFxslbEU4qIHaRZq+8Q==}
peerDependencies:
react: ^18 || ^19
'@tanstack/react-router-devtools@1.114.29':
resolution: {integrity: sha512-T2yzpAkhSKzJt9Une8B37UahD5bmtzVHdhoQgj9/L/7FuxInppbMzKBHZM9VXg/WtWO53EVFba+Gi4A0npZ9iw==}
'@tanstack/react-router-devtools@1.114.31':
resolution: {integrity: sha512-xdc4SCi3LgfpDePGWJQ5o1NY66em+mP3Y4fQSmsMkNyiBJuxKw0+v7FojMmMEnLFgu2i6uU+M2+0ugS8HW6UUQ==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.114.29
@@ -2828,8 +2828,8 @@ packages:
resolution: {integrity: sha512-CLf7HhHNiTz3cW1uB+DGyxiVwkEY+2YO36MXjtTLLtt5tQozDe3Kp7Dtb6B7aacMpvnLLwWtfmgptOce4Y8TQQ==}
engines: {node: '>=12'}
'@tanstack/router-devtools-core@1.114.29':
resolution: {integrity: sha512-QDtVcUGalFi9e5lFABOchGQI7gyxnk2z8cUET+DpZF8LWS0eJTv5+QWvLc7F7UHhz1MeFPbmIR2vQ4PDspWRfA==}
'@tanstack/router-devtools-core@1.114.31':
resolution: {integrity: sha512-/Tne2a2xQXIt351eyHD2QaBwxe0c6WTzo9Nz5RcIVpgj7kbN6B6jv9NwZ3ozSUyDLL6o34XPbTaQB94FnYQgXQ==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/router-core': ^1.114.29
@@ -2840,8 +2840,8 @@ packages:
csstype:
optional: true
'@tanstack/router-devtools@1.114.29':
resolution: {integrity: sha512-bfTD3qyFh1TZEEq6iVnj5RgnC/iKV94yNo7BMMY+B2puO1mQJpvFSwEc4RQfTNC5MgEvpn7LY6R3Q8E1ya5o7Q==}
'@tanstack/router-devtools@1.114.31':
resolution: {integrity: sha512-oSV6hIETSELdUwZPSAeM+UeSRyE+LrVFR/dT0pi2NJ5L4vYKpnOiJLkoHbQ5RadNcJEUufGgoajhCpiITg6qEQ==}
engines: {node: '>=12'}
peerDependencies:
'@tanstack/react-router': ^1.114.29
@@ -2861,8 +2861,8 @@ packages:
'@tanstack/react-router':
optional: true
'@tanstack/router-plugin@1.114.30':
resolution: {integrity: sha512-CvCQ/Iv91QEmus/cCH6LFDktCR5mMyfhugoWEzJ1y1zopCYHdYSLvsTwpmYdNOru83NqFu/4EcGS0P2mXukNAQ==}
'@tanstack/router-plugin@1.114.31':
resolution: {integrity: sha512-goWZ9bnHJJHHsCUUhc2B/DoprCzRmQ44HlxP+fg7bLpZ+KGEHptq/AqUHxr3R6dgMc4sDI8cC81rHahw5gNE4A==}
engines: {node: '>=12'}
peerDependencies:
'@rsbuild/core': '>=1.0.2'
@@ -3200,8 +3200,8 @@ packages:
'@types/node@22.10.1':
resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
'@types/node@22.13.14':
resolution: {integrity: sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==}
'@types/node@22.13.15':
resolution: {integrity: sha512-imAbQEEbVni6i6h6Bd5xkCRwLqFc8hihCsi2GbtDoAtUcAFQ6Zs4pFXTZUUbroTkXdImczWM9AI8eZUuybXE3w==}
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -5665,8 +5665,8 @@ packages:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
knip@5.46.3:
resolution: {integrity: sha512-DpxZYvFDh0POjgnfXie39zd4SCxmw3iQTSLPgnf1Umq+k+sCHjcv553UmI3hfo39qlVIq2c8XSsjS3IeZfdAoA==}
knip@5.46.4:
resolution: {integrity: sha512-iU2VGdXOPOj6Y8jEeixYMjlf2MCLZNjB63u2pfuP14gprRFjxgF+8wZiCgrjvogWt9H2WT+ytLYouXoEFAcm5g==}
engines: {node: '>=18.18.0'}
hasBin: true
peerDependencies:
@@ -7016,128 +7016,128 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sass-embedded-android-arm64@1.86.0:
resolution: {integrity: sha512-r7MZtlAI2VFUnKE8B5UOrpoE6OGpdf1dIB6ndoxb3oiURgMyfTVU7yvJcL12GGvtVwQ2boCj6dq//Lqq9CXPlQ==}
sass-embedded-android-arm64@1.86.1:
resolution: {integrity: sha512-SMY79YhNfq/gdz8MHqwEsnf/IjSnQFAmSEGDDv0vjL0yy9VZC/zhsxpsho8vbFEvTSEGFFlkGgPdzDuoozRrOg==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [android]
sass-embedded-android-arm@1.86.0:
resolution: {integrity: sha512-NS8v6BCbzskXUMBtzfuB+j2yQMgiwg5edKHTYfQU7gAWai2hkRhS06YNEMff3aRxV0IFInxPRHOobd8xWPHqeA==}
sass-embedded-android-arm@1.86.1:
resolution: {integrity: sha512-bcmKB67uCb9znune+QsE6cWIiKAHE9P+24/9vDPHwwN3BmmH1B/4mznNKKakdYMuxpgbeLrPcEScHEpQbdrIpA==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [android]
sass-embedded-android-ia32@1.86.0:
resolution: {integrity: sha512-UjfElrGaOTNOnxLZLxf6MFndFIe7zyK+81f83BioZ7/jcoAd6iCHZT8yQMvu8wINyVodPcaXZl8KxlKcl62VAA==}
sass-embedded-android-ia32@1.86.1:
resolution: {integrity: sha512-AX6I5qS8GbgcbBJ1o3uKVI5/7tq6evg/BO/wa0XaNqnzP4i/PojBaGh7EcZrg/spl//SfpS55eA18a0/AOi71w==}
engines: {node: '>=14.0.0'}
cpu: [ia32]
os: [android]
sass-embedded-android-riscv64@1.86.0:
resolution: {integrity: sha512-TsqCLxHWLFS2mbpUkL/nge3jSkaPK2VmLkkoi5iO/EQT4SFvm1lNUgPwlLXu9DplZ+aqGVzRS9Y6Psjv+qW7kw==}
sass-embedded-android-riscv64@1.86.1:
resolution: {integrity: sha512-Af6ZzRTRfIfx6KICJZ19je6OjOXhxo+v6z/lf/SXm5/1EaHGpGC5xIw4ivtj4nNINNoqkykfIDCjpzm1qWEPPQ==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [android]
sass-embedded-android-x64@1.86.0:
resolution: {integrity: sha512-8Q263GgwGjz7Jkf7Eghp7NrwqskDL95WO9sKrNm9iOd2re/M48W7RN/lpdcZwrUnEOhueks0RRyYyZYBNRz8Tg==}
sass-embedded-android-x64@1.86.1:
resolution: {integrity: sha512-GW47z1AH8gXB7IG6EUbC5aDBDtiITeP5nUfEenE6vaaN0H17mBjIwSnEcKPPA1IdxzDpj+4bE/SGfiF0W/At4g==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [android]
sass-embedded-darwin-arm64@1.86.0:
resolution: {integrity: sha512-d8oMEaIweq1tjrb/BT43igDviOMS1TeDpc51QF7vAHkt9drSjPmqEmbqStdFYPAGZj1j0RA4WCRoVl6jVixi/w==}
sass-embedded-darwin-arm64@1.86.1:
resolution: {integrity: sha512-grBnDW5Rg+mEmZM7I9hJySS4MMXDwLMd+RyegQnr+SIJ3WA807Cw830+raALxgDY+UKKKhVEoq3FgbTo40Awgw==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [darwin]
sass-embedded-darwin-x64@1.86.0:
resolution: {integrity: sha512-5NLRtn0ZUDBkfpKOsgLGl9B34po4Qui8Nff/lXTO+YkxBQFX4GoMkYNk9EJqHwoLLzICsxIhNDMMDiPGz7Fdrw==}
sass-embedded-darwin-x64@1.86.1:
resolution: {integrity: sha512-XxSCMcmeADNouiJAr8G1oRnEhkivHKVLV5DRpfFnUK5FqtFCuSk3K18I+xIfpQDeZnjRL3t2VjsmEJuFiBYV8w==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [darwin]
sass-embedded-linux-arm64@1.86.0:
resolution: {integrity: sha512-50A+0rhahRDRkKkv+qS7GDAAkW1VPm2RCX4zY4JWydhV4NwMXr6HbkLnsJ2MGixCyibPh59iflMpNBhe7SEMNg==}
sass-embedded-linux-arm64@1.86.1:
resolution: {integrity: sha512-zchms0BtaOrkvfvjRnl1PDWK931DxAeYEY2yKQceO/0OFtcBz1r480Kh/RjIffTNreJqIr9Mx4wFdP+icKwLpg==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [linux]
sass-embedded-linux-arm@1.86.0:
resolution: {integrity: sha512-b6wm0+Il+blJDleRXAqA6JISGMjRb0/thTEg4NWgmiJwUoZjDycj5FTbfYPnLXjCEIMGaYmW3patrJ3JMJcT3Q==}
sass-embedded-linux-arm@1.86.1:
resolution: {integrity: sha512-Z57ZUcWPuoOHpnl3TiUf/x9wWF2dFtkjdv7hZQpFXYwK5eudHFeBErK6KNCos6jkif1KyeFELXT/HWOznitU/w==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [linux]
sass-embedded-linux-ia32@1.86.0:
resolution: {integrity: sha512-h0mr9w71TV3BRPk9JHr0flnRCznhkraY14gaj5T+t78vUFByOUMxp4hTr+JpZAR5mv0mIeoMwrQYwWJoqKI0mw==}
sass-embedded-linux-ia32@1.86.1:
resolution: {integrity: sha512-WHntVnCgpiJPCmTeQrn5rtl1zJdd693TwpNGAFPzKD4FILPcVBKtWutl7COL6bKe/mKTf9OW0t6GBJ6mav2hAA==}
engines: {node: '>=14.0.0'}
cpu: [ia32]
os: [linux]
sass-embedded-linux-musl-arm64@1.86.0:
resolution: {integrity: sha512-5OZjiJIUyhvKJIGNDEjyRUWDe+W91hq4Bji27sy8gdEuDzPWLx4NzwpKwsBUALUfyW/J5dxgi0ZAQnI3HieyQg==}
sass-embedded-linux-musl-arm64@1.86.1:
resolution: {integrity: sha512-CwuHMRWSJFByHpgqcVtCSt29dMWhr0lpUTjaBCh9xOl0Oyz89dIqOxA0aMq+XU+thaDtOziJtMIfW6l35ZeykQ==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [linux]
sass-embedded-linux-musl-arm@1.86.0:
resolution: {integrity: sha512-KZU70jBMVykC9HzS+o2FhrJaprFLDk3LWXVPtBFxgLlkcQ/apCkUCh2WVNViLhI2U4NrMSnTvd4kDnC/0m8qIw==}
sass-embedded-linux-musl-arm@1.86.1:
resolution: {integrity: sha512-DlPpyp3bIL8YMtxR22hkWBtuZY6ch3KAmQvqIONippPv96WTHi1iq5jclbE1YXpDtI8Wcus0x6apoDSKq8o95g==}
engines: {node: '>=14.0.0'}
cpu: [arm]
os: [linux]
sass-embedded-linux-musl-ia32@1.86.0:
resolution: {integrity: sha512-vq9wJ7kaELrsNU6Ld6kvrIHxoIUWaD+5T6TQVj4SJP/iw1NjonyCDMQGGs6UgsIEzvaIwtlSlDbRewAq+4PchA==}
sass-embedded-linux-musl-ia32@1.86.1:
resolution: {integrity: sha512-yjvVpAW1YS0VQNnIUtZTf0IrRDMa0wRjFWUtsLthVIxuXyjLy44+YULlfduxqcZe3rvI4+EqT7GorvviWo9NfQ==}
engines: {node: '>=14.0.0'}
cpu: [ia32]
os: [linux]
sass-embedded-linux-musl-riscv64@1.86.0:
resolution: {integrity: sha512-UZJPu4zKe3phEzoSVRh5jcSicBBPe+jEbVNALHSSz881iOAYnDQXHITGeQ4mM1/7e/LTyryHk6EPBoaLOv6JrA==}
sass-embedded-linux-musl-riscv64@1.86.1:
resolution: {integrity: sha512-0zCUOMwX/hwPV1zimxM46dq/MdATSqbw6G646DwQ3/2V2Db1t9lfXBZqSavx8p/cqRp1JYTUPbJQV1gT4J7NYw==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [linux]
sass-embedded-linux-musl-x64@1.86.0:
resolution: {integrity: sha512-8taAgbWMk4QHneJcouWmWZJlmKa2O03g4I/CFo4bfMPL87bibY90pAsSDd+C+t81g0+2aK0/lY/BoB0r3qXLiA==}
sass-embedded-linux-musl-x64@1.86.1:
resolution: {integrity: sha512-8KJ6kEj1N16V9E0g5PDSd4aVe1LwcVKROJcVqnzTKPMa/4j2VuNWep7D81OYchdQMm9Egn1RqV0jCwm0b2aSHQ==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [linux]
sass-embedded-linux-riscv64@1.86.0:
resolution: {integrity: sha512-yREY6o2sLwiiA03MWHVpnUliLscz0flEmFW/wzxYZJDqg9eZteB3hUWgZD63eLm2PTZsYxDQpjAHpa48nnIEmA==}
sass-embedded-linux-riscv64@1.86.1:
resolution: {integrity: sha512-rNJ1EfIkQpvBfMS1fBdyb+Gsji4yK0AwsV1T7NEcy21yDxDt7mdCgkAJiaN9qf7UEXuCuueQoed7WZoDaSpjww==}
engines: {node: '>=14.0.0'}
cpu: [riscv64]
os: [linux]
sass-embedded-linux-x64@1.86.0:
resolution: {integrity: sha512-sH0F8np9PTgTbFcJWxfr1NzPkL5ID2NcpMtZyKPTdnn9NkE/L2UwXSo6xOvY0Duc4Hg+58wSrDnj6KbvdeHCPg==}
sass-embedded-linux-x64@1.86.1:
resolution: {integrity: sha512-DGCdUoYRRUKzRZz/q7plbB5Nean2+Uk4CqKF4RWAU0v1tHnDKKWmYfETryhWdB2WJM8QSn7O8qRebe6FCobB5g==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [linux]
sass-embedded-win32-arm64@1.86.0:
resolution: {integrity: sha512-4O1XVUxLTIjMOvrziYwEZgvFqC5sF6t0hTAPJ+h2uiAUZg9Joo0PvuEedXurjISgDBsb5W5DTL9hH9q1BbP4cQ==}
sass-embedded-win32-arm64@1.86.1:
resolution: {integrity: sha512-qRLZR3yLuk/3y64YhcltkwGclhPoK6EdiLP1e5SVw5+kughcs+mNUZ3rdvSAmCSA4vDv+XOiOjRpjxmpeon95Q==}
engines: {node: '>=14.0.0'}
cpu: [arm64]
os: [win32]
sass-embedded-win32-ia32@1.86.0:
resolution: {integrity: sha512-zuSP2axkGm4VaJWt38P464H+4424Swr9bzFNfbbznxe3Ue4RuqSBqwiLiYdg9Q1cecTQ2WGH7G7WO56KK7WLwg==}
sass-embedded-win32-ia32@1.86.1:
resolution: {integrity: sha512-o860a7/YGHZnGeY3l/e6yt3+ZMeDdDHmthTaKnw2wpJNEq0nmytYLTJQmjWPxEMz7O8AQ0LtcbDDrhivSog+KQ==}
engines: {node: '>=14.0.0'}
cpu: [ia32]
os: [win32]
sass-embedded-win32-x64@1.86.0:
resolution: {integrity: sha512-GVX0CHtukr3kjqfqretSlPiJzV7V4JxUjpRZV+yC9gUMTiDErilJh2Chw1r0+MYiYvumCDUSDlticmvJs7v0tA==}
sass-embedded-win32-x64@1.86.1:
resolution: {integrity: sha512-7Z3wsVKfseJodmv689dDEV/JrXJH5TAclWNvHrEYW5BtoViOTU2pIDxRgLYzdKU9teIw5g6R0nJZb9M105oIKA==}
engines: {node: '>=14.0.0'}
cpu: [x64]
os: [win32]
sass-embedded@1.86.0:
resolution: {integrity: sha512-Ibq5DzxjSf9f/IJmKeHVeXlVqiZWdRJF+RXy6v6UupvMYVMU5Ei+teSFBvvpPD5bB2QhhnU/OJlSM0EBCtfr9g==}
sass-embedded@1.86.1:
resolution: {integrity: sha512-LMJvytHh7lIUtmjGCqpM4cRdIDvPllLJKznNIK4L7EZJ77BLeUFoOSRXEOHq4G4gqy5CVhHUKlHslzCANkDOhQ==}
engines: {node: '>=16.0.0'}
hasBin: true
@@ -9105,11 +9105,11 @@ snapshots:
'@bufbuild/protobuf@2.2.3': {}
'@commitlint/cli@19.8.0(@types/node@22.13.14)(typescript@5.8.2)':
'@commitlint/cli@19.8.0(@types/node@22.13.15)(typescript@5.8.2)':
dependencies:
'@commitlint/format': 19.8.0
'@commitlint/lint': 19.8.0
'@commitlint/load': 19.8.0(@types/node@22.13.14)(typescript@5.8.2)
'@commitlint/load': 19.8.0(@types/node@22.13.15)(typescript@5.8.2)
'@commitlint/read': 19.8.0
'@commitlint/types': 19.8.0
tinyexec: 0.3.2
@@ -9156,7 +9156,7 @@ snapshots:
'@commitlint/rules': 19.8.0
'@commitlint/types': 19.8.0
'@commitlint/load@19.8.0(@types/node@22.13.14)(typescript@5.8.2)':
'@commitlint/load@19.8.0(@types/node@22.13.15)(typescript@5.8.2)':
dependencies:
'@commitlint/config-validator': 19.8.0
'@commitlint/execute-rule': 19.8.0
@@ -9164,7 +9164,7 @@ snapshots:
'@commitlint/types': 19.8.0
chalk: 5.4.1
cosmiconfig: 9.0.0(typescript@5.8.2)
cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.14)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2)
cosmiconfig-typescript-loader: 6.1.0(@types/node@22.13.15)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2)
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
@@ -9533,7 +9533,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@iconify/json@2.2.321':
'@iconify/json@2.2.322':
dependencies:
'@iconify/types': 2.0.0
pathe: 1.1.2
@@ -9596,23 +9596,23 @@ snapshots:
'@material/material-color-utilities@0.3.0': {}
'@microsoft/api-extractor-model@7.30.3(@types/node@22.13.14)':
'@microsoft/api-extractor-model@7.30.3(@types/node@22.13.15)':
dependencies:
'@microsoft/tsdoc': 0.15.1
'@microsoft/tsdoc-config': 0.17.1
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.14)
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.15)
transitivePeerDependencies:
- '@types/node'
'@microsoft/api-extractor@7.51.0(@types/node@22.13.14)':
'@microsoft/api-extractor@7.51.0(@types/node@22.13.15)':
dependencies:
'@microsoft/api-extractor-model': 7.30.3(@types/node@22.13.14)
'@microsoft/api-extractor-model': 7.30.3(@types/node@22.13.15)
'@microsoft/tsdoc': 0.15.1
'@microsoft/tsdoc-config': 0.17.1
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.14)
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.15)
'@rushstack/rig-package': 0.5.3
'@rushstack/terminal': 0.15.0(@types/node@22.13.14)
'@rushstack/ts-command-line': 4.23.5(@types/node@22.13.14)
'@rushstack/terminal': 0.15.0(@types/node@22.13.15)
'@rushstack/ts-command-line': 4.23.5(@types/node@22.13.15)
lodash: 4.17.21
minimatch: 3.0.8
resolve: 1.22.8
@@ -10325,7 +10325,7 @@ snapshots:
'@rtsao/scc@1.1.0': {}
'@rushstack/node-core-library@5.11.0(@types/node@22.13.14)':
'@rushstack/node-core-library@5.11.0(@types/node@22.13.15)':
dependencies:
ajv: 8.13.0
ajv-draft-04: 1.0.0(ajv@8.13.0)
@@ -10336,23 +10336,23 @@ snapshots:
resolve: 1.22.8
semver: 7.5.4
optionalDependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
'@rushstack/rig-package@0.5.3':
dependencies:
resolve: 1.22.8
strip-json-comments: 3.1.1
'@rushstack/terminal@0.15.0(@types/node@22.13.14)':
'@rushstack/terminal@0.15.0(@types/node@22.13.15)':
dependencies:
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.14)
'@rushstack/node-core-library': 5.11.0(@types/node@22.13.15)
supports-color: 8.1.1
optionalDependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
'@rushstack/ts-command-line@4.23.5(@types/node@22.13.14)':
'@rushstack/ts-command-line@4.23.5(@types/node@22.13.15)':
dependencies:
'@rushstack/terminal': 0.15.0(@types/node@22.13.14)
'@rushstack/terminal': 0.15.0(@types/node@22.13.15)
'@types/argparse': 1.0.38
argparse: 1.0.10
string-argv: 0.3.2
@@ -10608,17 +10608,17 @@ snapshots:
dependencies:
remove-accents: 0.5.0
'@tanstack/query-core@5.71.0': {}
'@tanstack/query-core@5.71.1': {}
'@tanstack/react-query@5.71.0(react@19.1.0)':
'@tanstack/react-query@5.71.1(react@19.1.0)':
dependencies:
'@tanstack/query-core': 5.71.0
'@tanstack/query-core': 5.71.1
react: 19.1.0
'@tanstack/react-router-devtools@1.114.29(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)':
'@tanstack/react-router-devtools@1.114.31(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/router-devtools-core': 1.114.29(@tanstack/router-core@1.114.29)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
'@tanstack/router-devtools-core': 1.114.31(@tanstack/router-core@1.114.29)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
solid-js: 1.9.5
@@ -10663,7 +10663,7 @@ snapshots:
'@tanstack/store': 0.7.0
tiny-invariant: 1.3.3
'@tanstack/router-devtools-core@1.114.29(@tanstack/router-core@1.114.29)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
'@tanstack/router-devtools-core@1.114.31(@tanstack/router-core@1.114.29)(csstype@3.1.3)(solid-js@1.9.5)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/router-core': 1.114.29
clsx: 2.1.1
@@ -10673,10 +10673,10 @@ snapshots:
optionalDependencies:
csstype: 3.1.3
'@tanstack/router-devtools@1.114.29(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)':
'@tanstack/router-devtools@1.114.31(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)':
dependencies:
'@tanstack/react-router': 1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/react-router-devtools': 1.114.29(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)
'@tanstack/react-router-devtools': 1.114.31(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@tanstack/router-core@1.114.29)(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tiny-invariant@1.3.3)
clsx: 2.1.1
goober: 2.1.16(csstype@3.1.3)
react: 19.1.0
@@ -10696,7 +10696,7 @@ snapshots:
optionalDependencies:
'@tanstack/react-router': 1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tanstack/router-plugin@1.114.30(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
'@tanstack/router-plugin@1.114.31(@tanstack/react-router@1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.26.9
'@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9)
@@ -10717,7 +10717,7 @@ snapshots:
zod: 3.24.2
optionalDependencies:
'@tanstack/react-router': 1.114.29(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -10874,12 +10874,12 @@ snapshots:
dependencies:
'@types/http-cache-semantics': 4.0.4
'@types/keyv': 3.1.4
'@types/node': 22.13.14
'@types/node': 22.13.15
'@types/responselike': 1.0.3
'@types/conventional-commits-parser@5.0.0':
dependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
'@types/d3-array@3.2.1': {}
@@ -11015,7 +11015,7 @@ snapshots:
'@types/fs-extra@11.0.4':
dependencies:
'@types/jsonfile': 6.1.4
'@types/node': 22.13.14
'@types/node': 22.13.15
'@types/geojson@7946.0.14': {}
@@ -11033,11 +11033,11 @@ snapshots:
'@types/jsonfile@6.1.4':
dependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
'@types/keyv@3.1.4':
dependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
'@types/lodash-es@4.17.12':
dependencies:
@@ -11057,7 +11057,7 @@ snapshots:
dependencies:
undici-types: 6.20.0
'@types/node@22.13.14':
'@types/node@22.13.15':
dependencies:
undici-types: 6.20.0
@@ -11087,7 +11087,7 @@ snapshots:
'@types/responselike@1.0.3':
dependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
'@types/retry@0.12.2': {}
@@ -11107,7 +11107,7 @@ snapshots:
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
optional: true
'@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2)':
@@ -11226,7 +11226,7 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-legacy@6.0.2(terser@5.36.0)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
'@vitejs/plugin-legacy@6.0.2(terser@5.36.0)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.26.9
'@babel/preset-env': 7.26.9(@babel/core@7.26.9)
@@ -11237,25 +11237,25 @@ snapshots:
regenerator-runtime: 0.14.1
systemjs: 6.15.1
terser: 5.36.0
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-react-swc@3.8.1(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
'@vitejs/plugin-react-swc@3.8.1(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
'@swc/core': 1.11.11
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- '@swc/helpers'
'@vitejs/plugin-react@4.3.4(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
'@vitejs/plugin-react@4.3.4(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.26.0
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -11895,9 +11895,9 @@ snapshots:
core-js@3.41.0: {}
cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.14)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2):
cosmiconfig-typescript-loader@6.1.0(@types/node@22.13.15)(cosmiconfig@9.0.0(typescript@5.8.2))(typescript@5.8.2):
dependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
cosmiconfig: 9.0.0(typescript@5.8.2)
jiti: 2.4.2
typescript: 5.8.2
@@ -13876,11 +13876,11 @@ snapshots:
kind-of@6.0.3: {}
knip@5.46.3(@types/node@22.13.14)(typescript@5.8.2):
knip@5.46.4(@types/node@22.13.15)(typescript@5.8.2):
dependencies:
'@nodelib/fs.walk': 3.0.1
'@snyk/github-codeowners': 1.1.0
'@types/node': 22.13.14
'@types/node': 22.13.15
easy-table: 1.2.0
enhanced-resolve: 5.18.1
fast-glob: 3.3.3
@@ -15337,7 +15337,7 @@ snapshots:
rxjs@7.8.1:
dependencies:
tslib: 2.7.0
tslib: 2.8.1
safe-array-concat@1.1.2:
dependencies:
@@ -15370,67 +15370,67 @@ snapshots:
safer-buffer@2.1.2: {}
sass-embedded-android-arm64@1.86.0:
sass-embedded-android-arm64@1.86.1:
optional: true
sass-embedded-android-arm@1.86.0:
sass-embedded-android-arm@1.86.1:
optional: true
sass-embedded-android-ia32@1.86.0:
sass-embedded-android-ia32@1.86.1:
optional: true
sass-embedded-android-riscv64@1.86.0:
sass-embedded-android-riscv64@1.86.1:
optional: true
sass-embedded-android-x64@1.86.0:
sass-embedded-android-x64@1.86.1:
optional: true
sass-embedded-darwin-arm64@1.86.0:
sass-embedded-darwin-arm64@1.86.1:
optional: true
sass-embedded-darwin-x64@1.86.0:
sass-embedded-darwin-x64@1.86.1:
optional: true
sass-embedded-linux-arm64@1.86.0:
sass-embedded-linux-arm64@1.86.1:
optional: true
sass-embedded-linux-arm@1.86.0:
sass-embedded-linux-arm@1.86.1:
optional: true
sass-embedded-linux-ia32@1.86.0:
sass-embedded-linux-ia32@1.86.1:
optional: true
sass-embedded-linux-musl-arm64@1.86.0:
sass-embedded-linux-musl-arm64@1.86.1:
optional: true
sass-embedded-linux-musl-arm@1.86.0:
sass-embedded-linux-musl-arm@1.86.1:
optional: true
sass-embedded-linux-musl-ia32@1.86.0:
sass-embedded-linux-musl-ia32@1.86.1:
optional: true
sass-embedded-linux-musl-riscv64@1.86.0:
sass-embedded-linux-musl-riscv64@1.86.1:
optional: true
sass-embedded-linux-musl-x64@1.86.0:
sass-embedded-linux-musl-x64@1.86.1:
optional: true
sass-embedded-linux-riscv64@1.86.0:
sass-embedded-linux-riscv64@1.86.1:
optional: true
sass-embedded-linux-x64@1.86.0:
sass-embedded-linux-x64@1.86.1:
optional: true
sass-embedded-win32-arm64@1.86.0:
sass-embedded-win32-arm64@1.86.1:
optional: true
sass-embedded-win32-ia32@1.86.0:
sass-embedded-win32-ia32@1.86.1:
optional: true
sass-embedded-win32-x64@1.86.0:
sass-embedded-win32-x64@1.86.1:
optional: true
sass-embedded@1.86.0:
sass-embedded@1.86.1:
dependencies:
'@bufbuild/protobuf': 2.2.3
buffer-builder: 0.2.0
@@ -15441,26 +15441,26 @@ snapshots:
sync-child-process: 1.0.2
varint: 6.0.0
optionalDependencies:
sass-embedded-android-arm: 1.86.0
sass-embedded-android-arm64: 1.86.0
sass-embedded-android-ia32: 1.86.0
sass-embedded-android-riscv64: 1.86.0
sass-embedded-android-x64: 1.86.0
sass-embedded-darwin-arm64: 1.86.0
sass-embedded-darwin-x64: 1.86.0
sass-embedded-linux-arm: 1.86.0
sass-embedded-linux-arm64: 1.86.0
sass-embedded-linux-ia32: 1.86.0
sass-embedded-linux-musl-arm: 1.86.0
sass-embedded-linux-musl-arm64: 1.86.0
sass-embedded-linux-musl-ia32: 1.86.0
sass-embedded-linux-musl-riscv64: 1.86.0
sass-embedded-linux-musl-x64: 1.86.0
sass-embedded-linux-riscv64: 1.86.0
sass-embedded-linux-x64: 1.86.0
sass-embedded-win32-arm64: 1.86.0
sass-embedded-win32-ia32: 1.86.0
sass-embedded-win32-x64: 1.86.0
sass-embedded-android-arm: 1.86.1
sass-embedded-android-arm64: 1.86.1
sass-embedded-android-ia32: 1.86.1
sass-embedded-android-riscv64: 1.86.1
sass-embedded-android-x64: 1.86.1
sass-embedded-darwin-arm64: 1.86.1
sass-embedded-darwin-x64: 1.86.1
sass-embedded-linux-arm: 1.86.1
sass-embedded-linux-arm64: 1.86.1
sass-embedded-linux-ia32: 1.86.1
sass-embedded-linux-musl-arm: 1.86.1
sass-embedded-linux-musl-arm64: 1.86.1
sass-embedded-linux-musl-ia32: 1.86.1
sass-embedded-linux-musl-riscv64: 1.86.1
sass-embedded-linux-musl-x64: 1.86.1
sass-embedded-linux-riscv64: 1.86.1
sass-embedded-linux-x64: 1.86.1
sass-embedded-win32-arm64: 1.86.1
sass-embedded-win32-ia32: 1.86.1
sass-embedded-win32-x64: 1.86.1
sass@1.83.0:
dependencies:
@@ -16402,9 +16402,9 @@ snapshots:
- rollup
- supports-color
vite-plugin-dts@4.5.3(@types/node@22.13.14)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
vite-plugin-dts@4.5.3(@types/node@22.13.15)(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
dependencies:
'@microsoft/api-extractor': 7.51.0(@types/node@22.13.14)
'@microsoft/api-extractor': 7.51.0(@types/node@22.13.15)
'@rollup/pluginutils': 5.1.4(rollup@4.34.3)
'@volar/typescript': 2.4.11
'@vue/language-core': 2.2.0(typescript@5.8.2)
@@ -16415,13 +16415,13 @@ snapshots:
magic-string: 0.30.17
typescript: 5.8.2
optionalDependencies:
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- '@types/node'
- rollup
- supports-color
vite-plugin-html@3.2.2(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
vite-plugin-html@3.2.2(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
dependencies:
'@rollup/pluginutils': 4.2.1
colorette: 2.0.20
@@ -16435,51 +16435,51 @@ snapshots:
html-minifier-terser: 6.1.0
node-html-parser: 5.4.2
pathe: 0.2.0
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite-plugin-sass-dts@1.3.31(postcss@8.5.3)(prettier@3.5.3)(sass-embedded@1.86.0)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
vite-plugin-sass-dts@1.3.31(postcss@8.5.3)(prettier@3.5.3)(sass-embedded@1.86.1)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
dependencies:
postcss: 8.5.3
postcss-js: 4.0.1(postcss@8.5.3)
prettier: 3.5.3
sass-embedded: 1.86.0
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
sass-embedded: 1.86.1
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite-plugin-svgr@4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
vite-plugin-svgr@4.3.0(rollup@4.34.3)(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
dependencies:
'@rollup/pluginutils': 5.1.3(rollup@4.34.3)
'@svgr/core': 8.1.0(typescript@5.8.2)
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.8.2))
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- rollup
- supports-color
- typescript
vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)):
dependencies:
debug: 4.3.7
globrex: 0.1.2
tsconfck: 3.0.3(typescript@5.8.2)
optionalDependencies:
vite: 6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
vite: 6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
- typescript
vite@6.2.3(@types/node@22.13.14)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.0)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0):
vite@6.2.3(@types/node@22.13.15)(jiti@2.4.2)(less@4.2.0)(lightningcss@1.29.2)(sass-embedded@1.86.1)(sass@1.83.0)(stylus@0.62.0)(terser@5.36.0)(tsx@4.19.3)(yaml@2.7.0):
dependencies:
esbuild: 0.25.0
postcss: 8.5.3
rollup: 4.34.3
optionalDependencies:
'@types/node': 22.13.14
'@types/node': 22.13.15
fsevents: 2.3.3
jiti: 2.4.2
less: 4.2.0
lightningcss: 1.29.2
sass: 1.83.0
sass-embedded: 1.86.0
sass-embedded: 1.86.1
stylus: 0.62.0
terser: 5.36.0
tsx: 4.19.3
+5
View File
@@ -13,6 +13,7 @@
- MacOS 自定义托盘图标显示速率时图标和文本间隙过大
- MacOS 托盘速率显示不全
- Linux 在系统服务模式下无法拉起 Mihomo 内核
- 使用异步操作,避免获取系统信息和切换代理模式可能带来的崩溃
#### 新增了:
- Clash Verge Rev 从现在开始不再强依赖系统服务和管理权限
@@ -23,11 +24,15 @@
- 统一运行模式检测,支持管理员模式下开启TUN模式
- 托盘切换代理模式会根据设置自动断开之前连接
#### 移除了:
- 实时保存窗口位置和大小。这个功能可能会导致窗口异常大小和位置,还需观察。
#### 优化了:
- 重构了后端内核管理逻辑,更轻量化和有效的管理内核,提高了性能和稳定性
- 前端统一刷新应用数据,优化数据获取和刷新逻辑
- 优化首页流量图表代码,调整图表文字边距
- MacOS 托盘速率更好的显示样式和更新逻辑
- 首页仅在有流量图表时显示流量图表区域
## v2.2.2
+2 -2
View File
@@ -23,7 +23,7 @@ static APP_START_TIME: Lazy<AtomicI64> = Lazy::new(|| {
#[tauri::command]
pub async fn export_diagnostic_info() -> CmdResult<()> {
let sysinfo = PlatformSpecification::new();
let sysinfo = PlatformSpecification::new_async().await;
let info = format!("{:?}", sysinfo);
let app_handle = handle::Handle::global().app_handle().unwrap();
@@ -36,7 +36,7 @@ pub async fn export_diagnostic_info() -> CmdResult<()> {
#[tauri::command]
pub async fn get_system_info() -> CmdResult<String> {
let sysinfo = PlatformSpecification::new();
let sysinfo = PlatformSpecification::new_async().await;
let info = format!("{:?}", sysinfo);
Ok(info)
}
+19 -13
View File
@@ -29,25 +29,31 @@ pub fn restart_app() {
tauri::async_runtime::spawn_blocking(|| {
tauri::async_runtime::block_on(async {
logging_error!(Type::Core, true, CoreManager::global().stop_core().await);
resolve::resolve_reset_async().await;
let app_handle = handle::Handle::global().app_handle().unwrap();
std::thread::sleep(std::time::Duration::from_secs(1));
tauri::process::restart(&app_handle.env());
});
resolve::resolve_reset();
let app_handle = handle::Handle::global().app_handle().unwrap();
std::thread::sleep(std::time::Duration::from_secs(1));
tauri::process::restart(&app_handle.env());
});
}
fn after_change_clash_mode() {
let _ = tauri::async_runtime::block_on(tauri::async_runtime::spawn_blocking(|| {
tauri::async_runtime::block_on(async {
let connections = MihomoManager::global().get_connections().await.unwrap();
let connections = connections["connections"].as_array().unwrap();
for connection in connections {
let id = connection["id"].as_str().unwrap();
let _ = MihomoManager::global().delete_connection(id).await;
tauri::async_runtime::spawn(async {
match MihomoManager::global().get_connections().await {
Ok(connections) => {
if let Some(connections_array) = connections["connections"].as_array() {
for connection in connections_array {
if let Some(id) = connection["id"].as_str() {
let _ = MihomoManager::global().delete_connection(id).await;
}
}
}
}
})
}));
Err(err) => {
log::error!(target: "app", "Failed to get connections: {}", err);
}
}
});
}
/// Change Clash mode (rule/global/direct/script)
@@ -36,13 +36,8 @@ impl PlatformSpecification {
let config = handler.config();
let verge_version = config.version.clone().unwrap_or("Null".into());
// Get running mode asynchronously
let running_mode = tokio::task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(async {
let running_mode = CoreManager::global().get_running_mode().await;
running_mode.to_string()
})
});
// 使用默认值避免在同步上下文中执行异步操作
let running_mode = "NotRunning".to_string();
let is_admin = match system::is_admin() {
Ok(value) => value,
@@ -59,4 +54,14 @@ impl PlatformSpecification {
is_admin,
}
}
// 异步方法来获取完整的系统信息
pub async fn new_async() -> Self {
let mut info = Self::new();
let running_mode = CoreManager::global().get_running_mode().await;
info.running_mode = running_mode.to_string();
info
}
}
+17 -19
View File
@@ -130,26 +130,24 @@ pub async fn resolve_setup(app: &mut App) {
}
}
/// reset system proxy
pub fn resolve_reset() {
tauri::async_runtime::block_on(async move {
#[cfg(target_os = "macos")]
logging!(info, Type::Tray, true, "Unsubscribing from traffic updates");
#[cfg(target_os = "macos")]
tray::Tray::global().unsubscribe_traffic();
/// reset system proxy (异步版)
pub async fn resolve_reset_async() {
#[cfg(target_os = "macos")]
logging!(info, Type::Tray, true, "Unsubscribing from traffic updates");
#[cfg(target_os = "macos")]
tray::Tray::global().unsubscribe_traffic();
logging_error!(
Type::System,
true,
sysopt::Sysopt::global().reset_sysproxy().await
);
logging_error!(Type::Core, true, CoreManager::global().stop_core().await);
#[cfg(target_os = "macos")]
{
logging!(info, Type::System, true, "Restoring system DNS settings");
restore_public_dns().await;
}
});
logging_error!(
Type::System,
true,
sysopt::Sysopt::global().reset_sysproxy().await
);
logging_error!(Type::Core, true, CoreManager::global().stop_core().await);
#[cfg(target_os = "macos")]
{
logging!(info, Type::System, true, "Restoring system DNS settings");
restore_public_dns().await;
}
}
/// create main window
@@ -401,10 +401,12 @@ export const EnhancedTrafficStats = () => {
return (
<Grid container spacing={1} columns={{ xs: 8, sm: 8, md: 12 }}>
<Grid size={12}>
{/* 流量图表区域 */}
{trafficGraphComponent}
</Grid>
{trafficGraph && (
<Grid size={12}>
{/* 流量图表区域 */}
{trafficGraphComponent}
</Grid>
)}
{/* 统计卡片区域 */}
{statCards.map((card, index) => (
<Grid key={index} size={4}>
-1
View File
@@ -322,7 +322,6 @@ export const HomePage = () => {
title={t("Traffic Stats")}
icon={<SpeedOutlined />}
iconColor="secondary"
minHeight={280}
>
<EnhancedTrafficStats />
</EnhancedCard>
@@ -0,0 +1,33 @@
From 4c4baed29b168e9bf39545a945a9523ea280cb44 Mon Sep 17 00:00:00 2001
From: Daniel Golle <daniel@makrotopia.org>
Date: Sat, 1 Feb 2025 04:24:17 +0000
Subject: [PATCH 1/2] Revert "arm64: dts: mediatek: fix t-phy unit name"
This reverts commit 963c3b0c47ec29b4c49c9f45965cd066f419d17f.
---
arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +-
arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
@@ -908,7 +908,7 @@
status = "disabled";
};
- sata_phy: t-phy {
+ sata_phy: t-phy@1a243000 {
compatible = "mediatek,mt7622-tphy",
"mediatek,generic-tphy-v1";
#address-cells = <2>;
--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -428,7 +428,7 @@
};
};
- pcie_phy: t-phy {
+ pcie_phy: t-phy@11c00000 {
compatible = "mediatek,mt7986-tphy",
"mediatek,generic-tphy-v2";
ranges;
@@ -0,0 +1,33 @@
From 98bc223d174c7f544e8f6c4f0caa8fa144f2f4dc Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Fri, 28 Jun 2024 12:55:40 +0200
Subject: [PATCH 2/2] arm64: dts: mediatek: mt7622: readd syscon to pciesys
node
Sata node reference the pciesys with the property mediatek,phy-node
and that is used as a syscon to access the pciesys regs.
Readd the syscon compatible to pciesys node to restore correct
functionality of the SATA interface.
Fixes: 3ba5a6159434 ("arm64: dts: mediatek: mt7622: fix clock controllers")
Reported-by: Frank Wunderlich <frank-w@public-files.de>
Co-developed-by: Frank Wunderlich <frank-w@public-files.de>
Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Cc: stable@vger.kernel.org
---
arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
@@ -798,7 +798,7 @@
};
pciesys: clock-controller@1a100800 {
- compatible = "mediatek,mt7622-pciesys";
+ compatible = "mediatek,mt7622-pciesys", "syscon";
reg = <0 0x1a100800 0 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
+132 -59
View File
@@ -259,6 +259,58 @@ func (TransportProtocol) EnumDescriptor() ([]byte, []int) {
return file_base_proto_rawDescGZIP(), []int{3}
}
type Cipher int32
const (
Cipher_CIPHER_DEFAULT Cipher = 0
Cipher_CIPHER_XCHACHA20_POLY1305 Cipher = 1
Cipher_CIPHER_AES_128_GCM Cipher = 2
Cipher_CIPHER_AES_256_GCM Cipher = 3
)
// Enum value maps for Cipher.
var (
Cipher_name = map[int32]string{
0: "CIPHER_DEFAULT",
1: "CIPHER_XCHACHA20_POLY1305",
2: "CIPHER_AES_128_GCM",
3: "CIPHER_AES_256_GCM",
}
Cipher_value = map[string]int32{
"CIPHER_DEFAULT": 0,
"CIPHER_XCHACHA20_POLY1305": 1,
"CIPHER_AES_128_GCM": 2,
"CIPHER_AES_256_GCM": 3,
}
)
func (x Cipher) Enum() *Cipher {
p := new(Cipher)
*p = x
return p
}
func (x Cipher) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Cipher) Descriptor() protoreflect.EnumDescriptor {
return file_base_proto_enumTypes[4].Descriptor()
}
func (Cipher) Type() protoreflect.EnumType {
return &file_base_proto_enumTypes[4]
}
func (x Cipher) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Cipher.Descriptor instead.
func (Cipher) EnumDescriptor() ([]byte, []int) {
return file_base_proto_rawDescGZIP(), []int{4}
}
type Empty struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -497,6 +549,8 @@ type User struct {
// User quotas.
// This has no effect at the client side.
Quotas []*Quota `protobuf:"bytes,4,rep,name=quotas,proto3" json:"quotas,omitempty"`
// Encryption and decryption algorithm.
Cipher *Cipher `protobuf:"varint,5,opt,name=cipher,proto3,enum=appctl.Cipher,oneof" json:"cipher,omitempty"`
}
func (x *User) Reset() {
@@ -559,6 +613,13 @@ func (x *User) GetQuotas() []*Quota {
return nil
}
func (x *User) GetCipher() Cipher {
if x != nil && x.Cipher != nil {
return *x.Cipher
}
return Cipher_CIPHER_DEFAULT
}
type Quota struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -705,7 +766,7 @@ var file_base_proto_rawDesc = []byte{
0x09, 0x48, 0x02, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x88, 0x01,
0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x70, 0x6f, 0x72, 0x74,
0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xbd, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x17,
0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x17,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x70, 0x61, 0x73,
@@ -714,46 +775,56 @@ var file_base_proto_rawDesc = []byte{
0x48, 0x02, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x06, 0x71, 0x75, 0x6f, 0x74, 0x61, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x51,
0x75, 0x6f, 0x74, 0x61, 0x52, 0x06, 0x71, 0x75, 0x6f, 0x74, 0x61, 0x73, 0x42, 0x07, 0x0a, 0x05,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x50, 0x61, 0x73,
0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x5a, 0x0a, 0x05, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x12, 0x17,
0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x04,
0x64, 0x61, 0x79, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x6d, 0x65, 0x67, 0x61, 0x62,
0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x09, 0x6d, 0x65,
0x67, 0x61, 0x62, 0x79, 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64,
0x61, 0x79, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x67, 0x61, 0x62, 0x79, 0x74, 0x65,
0x73, 0x22, 0x56, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x17, 0x0a, 0x04, 0x75, 0x73, 0x65,
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x88,
0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x42, 0x0b, 0x0a, 0x09,
0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2a, 0x4b, 0x0a, 0x09, 0x41, 0x70, 0x70,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a,
0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52,
0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50,
0x50, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x2a, 0x5b, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e,
0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c,
0x54, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x09,
0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52,
0x4e, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x12, 0x09, 0x0a,
0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43,
0x45, 0x10, 0x06, 0x2a, 0x5d, 0x0a, 0x09, 0x44, 0x75, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x63, 0x6b,
0x12, 0x10, 0x0a, 0x0c, 0x55, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x52, 0x53, 0x54, 0x5f, 0x49, 0x50,
0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f, 0x49, 0x50, 0x76,
0x34, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x45, 0x46, 0x45, 0x52, 0x5f, 0x49, 0x50,
0x76, 0x36, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x4f, 0x4e, 0x4c, 0x59, 0x5f, 0x49, 0x50, 0x76,
0x34, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4f, 0x4e, 0x4c, 0x59, 0x5f, 0x49, 0x50, 0x76, 0x36,
0x10, 0x04, 0x2a, 0x45, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
0x57, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x50, 0x52, 0x4f,
0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01,
0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x02, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, 0x66, 0x65, 0x69, 0x6e, 0x2f, 0x6d,
0x69, 0x65, 0x72, 0x75, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x70, 0x63,
0x74, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
0x75, 0x6f, 0x74, 0x61, 0x52, 0x06, 0x71, 0x75, 0x6f, 0x74, 0x61, 0x73, 0x12, 0x2b, 0x0a, 0x06,
0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x61,
0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x48, 0x03, 0x52, 0x06,
0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61,
0x6d, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x42,
0x11, 0x0a, 0x0f, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x22, 0x5a, 0x0a,
0x05, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x04, 0x64, 0x61, 0x79, 0x73, 0x88, 0x01, 0x01, 0x12,
0x21, 0x0a, 0x09, 0x6d, 0x65, 0x67, 0x61, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x05, 0x48, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x67, 0x61, 0x62, 0x79, 0x74, 0x65, 0x73, 0x88,
0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f,
0x6d, 0x65, 0x67, 0x61, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x04, 0x41, 0x75, 0x74,
0x68, 0x12, 0x17, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
0x00, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08,
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f,
0x75, 0x73, 0x65, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x2a, 0x4b, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b,
0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49,
0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e,
0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03,
0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x2a, 0x5b,
0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0b,
0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x46,
0x41, 0x54, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10,
0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x49,
0x4e, 0x46, 0x4f, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x05,
0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x06, 0x2a, 0x5d, 0x0a, 0x09, 0x44,
0x75, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x53, 0x45, 0x5f,
0x46, 0x49, 0x52, 0x53, 0x54, 0x5f, 0x49, 0x50, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52,
0x45, 0x46, 0x45, 0x52, 0x5f, 0x49, 0x50, 0x76, 0x34, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x50,
0x52, 0x45, 0x46, 0x45, 0x52, 0x5f, 0x49, 0x50, 0x76, 0x36, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09,
0x4f, 0x4e, 0x4c, 0x59, 0x5f, 0x49, 0x50, 0x76, 0x34, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x4f,
0x4e, 0x4c, 0x59, 0x5f, 0x49, 0x50, 0x76, 0x36, 0x10, 0x04, 0x2a, 0x45, 0x0a, 0x11, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12,
0x1e, 0x0a, 0x1a, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53,
0x50, 0x4f, 0x52, 0x54, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x00, 0x12,
0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10,
0x02, 0x2a, 0x6b, 0x0a, 0x06, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x43,
0x49, 0x50, 0x48, 0x45, 0x52, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12,
0x1d, 0x0a, 0x19, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x5f, 0x58, 0x43, 0x48, 0x41, 0x43, 0x48,
0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x01, 0x12, 0x16,
0x0a, 0x12, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38,
0x5f, 0x47, 0x43, 0x4d, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52,
0x5f, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x03, 0x42, 0x30,
0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, 0x66,
0x65, 0x69, 0x6e, 0x2f, 0x6d, 0x69, 0x65, 0x72, 0x75, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67,
0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x70, 0x62,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -768,31 +839,33 @@ func file_base_proto_rawDescGZIP() []byte {
return file_base_proto_rawDescData
}
var file_base_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
var file_base_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_base_proto_goTypes = []interface{}{
(AppStatus)(0), // 0: appctl.AppStatus
(LoggingLevel)(0), // 1: appctl.LoggingLevel
(DualStack)(0), // 2: appctl.DualStack
(TransportProtocol)(0), // 3: appctl.TransportProtocol
(*Empty)(nil), // 4: appctl.Empty
(*AppStatusMsg)(nil), // 5: appctl.AppStatusMsg
(*ServerEndpoint)(nil), // 6: appctl.ServerEndpoint
(*PortBinding)(nil), // 7: appctl.PortBinding
(*User)(nil), // 8: appctl.User
(*Quota)(nil), // 9: appctl.Quota
(*Auth)(nil), // 10: appctl.Auth
(Cipher)(0), // 4: appctl.Cipher
(*Empty)(nil), // 5: appctl.Empty
(*AppStatusMsg)(nil), // 6: appctl.AppStatusMsg
(*ServerEndpoint)(nil), // 7: appctl.ServerEndpoint
(*PortBinding)(nil), // 8: appctl.PortBinding
(*User)(nil), // 9: appctl.User
(*Quota)(nil), // 10: appctl.Quota
(*Auth)(nil), // 11: appctl.Auth
}
var file_base_proto_depIdxs = []int32{
0, // 0: appctl.AppStatusMsg.status:type_name -> appctl.AppStatus
7, // 1: appctl.ServerEndpoint.portBindings:type_name -> appctl.PortBinding
3, // 2: appctl.PortBinding.protocol:type_name -> appctl.TransportProtocol
9, // 3: appctl.User.quotas:type_name -> appctl.Quota
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
0, // 0: appctl.AppStatusMsg.status:type_name -> appctl.AppStatus
8, // 1: appctl.ServerEndpoint.portBindings:type_name -> appctl.PortBinding
3, // 2: appctl.PortBinding.protocol:type_name -> appctl.TransportProtocol
10, // 3: appctl.User.quotas:type_name -> appctl.Quota
4, // 4: appctl.User.cipher:type_name -> appctl.Cipher
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_base_proto_init() }
@@ -897,7 +970,7 @@ func file_base_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_base_proto_rawDesc,
NumEnums: 4,
NumEnums: 5,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
+10
View File
@@ -91,6 +91,13 @@ enum TransportProtocol {
TCP = 2;
}
enum Cipher {
CIPHER_DEFAULT = 0;
CIPHER_XCHACHA20_POLY1305 = 1;
CIPHER_AES_128_GCM = 2;
CIPHER_AES_256_GCM = 3;
}
message User {
// User name is also the ID of user.
@@ -108,6 +115,9 @@ message User {
// User quotas.
// This has no effect at the client side.
repeated Quota quotas = 4;
// Encryption and decryption algorithm.
optional Cipher cipher = 5;
}
message Quota {
+24 -15
View File
@@ -32,10 +32,12 @@ const (
type AEADType uint8
// The AEADType values need to match the definitions in protobuf.
const (
AES256GCM AEADType = iota
ChaCha20Poly1305
XChaCha20Poly1305
XChaCha20Poly1305 AEADType = iota + 1
AES128GCM
AES256GCM
ChaCha20Poly1305 // TODO: remove this
)
var (
@@ -56,8 +58,8 @@ type AEADBlockCipher struct {
// newAESGCMBlockCipher creates a new AES-GCM cipher with the supplied key.
func newAESGCMBlockCipher(key []byte) (*AEADBlockCipher, error) {
keyLen := len(key)
if keyLen != 16 && keyLen != 24 && keyLen != 32 {
return nil, fmt.Errorf("AES key length is %d, want 16 or 24 or 32", keyLen)
if keyLen != 16 && keyLen != 32 {
return nil, fmt.Errorf("AES key length is %d bytes, want 16 bytes or 32 bytes", keyLen)
}
block, err := aes.NewCipher(key)
@@ -70,20 +72,27 @@ func newAESGCMBlockCipher(key []byte) (*AEADBlockCipher, error) {
return nil, fmt.Errorf("cipher.NewGCM() failed: %w", err)
}
return &AEADBlockCipher{
c := &AEADBlockCipher{
aead: aead,
aeadType: AES256GCM,
enableImplicitNonce: false,
key: key,
implicitNonce: nil,
}, nil
}
if keyLen == 16 {
c.aeadType = AES128GCM
} else if keyLen == 32 {
c.aeadType = AES256GCM
} else {
panic(fmt.Sprintf("invalid AES key length: %d bytes", keyLen))
}
return c, nil
}
// newChaCha20Poly1305BlockCipher creates a new ChaCha20-Poly1305 cipher with the supplied key.
func newChaCha20Poly1305BlockCipher(key []byte) (*AEADBlockCipher, error) {
keyLen := len(key)
if keyLen != 32 {
return nil, fmt.Errorf("ChaCha20-Poly1305 key length is %d, want 32", keyLen)
return nil, fmt.Errorf("ChaCha20-Poly1305 key length is %d bytes, want 32 bytes", keyLen)
}
aead, err := chacha20poly1305.New(key)
@@ -104,7 +113,7 @@ func newChaCha20Poly1305BlockCipher(key []byte) (*AEADBlockCipher, error) {
func newXChaCha20Poly1305BlockCipher(key []byte) (*AEADBlockCipher, error) {
keyLen := len(key)
if keyLen != 32 {
return nil, fmt.Errorf("XChaCha20-Poly1305 key length is %d, want 32", keyLen)
return nil, fmt.Errorf("XChaCha20-Poly1305 key length is %d bytes, want 32 bytes", keyLen)
}
aead, err := chacha20poly1305.NewX(key)
@@ -175,8 +184,8 @@ func (c *AEADBlockCipher) EncryptWithNonce(plaintext, nonce []byte) ([]byte, err
if c.enableImplicitNonce {
return nil, fmt.Errorf("EncryptWithNonce() is not supported when implicit nonce is enabled")
}
if len(nonce) != DefaultNonceSize {
return nil, fmt.Errorf("want nonce size %d, got %d", DefaultNonceSize, len(nonce))
if len(nonce) != c.NonceSize() {
return nil, fmt.Errorf("want nonce size %d, got %d", c.NonceSize(), len(nonce))
}
return c.aead.Seal(nil, nonce, plaintext, nil), nil
}
@@ -218,8 +227,8 @@ func (c *AEADBlockCipher) DecryptWithNonce(ciphertext, nonce []byte) ([]byte, er
if c.enableImplicitNonce {
return nil, fmt.Errorf("EncryptWithNonce() is not supported when implicit nonce is enabled")
}
if len(nonce) != DefaultNonceSize {
return nil, fmt.Errorf("want nonce size %d, got %d", DefaultNonceSize, len(nonce))
if len(nonce) != c.NonceSize() {
return nil, fmt.Errorf("want nonce size %d, got %d", c.NonceSize(), len(nonce))
}
plaintext, err := c.aead.Open(nil, nonce, ciphertext, nil)
if err != nil {
@@ -234,7 +243,7 @@ func (c *AEADBlockCipher) Clone() BlockCipher {
var newCipher *AEADBlockCipher
var err error
if c.aeadType == AES256GCM {
if c.aeadType == AES128GCM || c.aeadType == AES256GCM {
newCipher, err = newAESGCMBlockCipher(c.key)
} else if c.aeadType == ChaCha20Poly1305 {
newCipher, err = newChaCha20Poly1305BlockCipher(c.key)
+1 -1
View File
@@ -87,7 +87,7 @@ func NewMux(isClinet bool) *Mux {
done: make(chan struct{}),
cleaner: time.NewTicker(idleUnderlayTickerInterval),
}
mux.ctx, mux.ctxCancelFunc = context.WithCancel(context.TODO())
mux.ctx, mux.ctxCancelFunc = context.WithCancel(context.Background())
// Run maintenance tasks in the background.
go func() {
@@ -14,7 +14,7 @@ PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Sirpdboy <herboy2008@gmail.com>
LUCI_TITLE:=LuCI Support for Automatic Partition Mount
LUCI_DEPENDS:=+fdisk +block-mount +bc +blkid +parted
LUCI_DEPENDS:=+fdisk +block-mount +bc +blkid +parted +btrfs-progs
LUCI_PKGARCH:=all
@@ -276,17 +276,30 @@ fdiskB(){
local b=$a$1
log "开始检测目标$a信息"
log "检测/dev/$b是否需要分区和格式化$format_type"
[ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd stop >/dev/null 2> /dev/null
if [ $target_function = '/opt' ] ;then
/etc/init.d/dockerd stop >/dev/null 2> /dev/null
amount=`mount |grep /opt | awk '{print $1}'`
if [ -n $amount ] ;then
umount $amount >/dev/null 2> /dev/null
log "取消/opt之前的挂载$amount成功!"
fi
for OPT in $(mount |grep /opt | awk '{print $3}');do
umount $OPT >/dev/null 2> /dev/null
log "取消/opt之前的挂载$OPT成功!"
done
fi
[ -e "/etc/config/fstab" ] || block detect > /etc/config/fstab
[ -d "/mnt/$b" ] || mkdir -p /mnt/$b
if is_disk_mounted "/dev/$b"; then
log "设备 /dev/$b 已挂载,尝试取消挂载..."
if check_shared_mount $b; then
usamba samba4 $MOUNT
usamba samba $MOUNT
sleep 5
fi
umount_disk "/dev/$b" || umount_disk "/mnt/$b"
if check_shared_mount $b; then
usamba samba4 $MOUNT
usamba samba $MOUNT
sleep 5
fi
umount_disk "/dev/$b" || umount_disk "/mnt/$b"
else
log "设备/dev/$b未挂载"
isfdisk=0
@@ -412,10 +425,7 @@ fdiskB(){
umount /dev/$b >/dev/null 2> /dev/null
[ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null
[ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null
for OPT in $(mount |grep /opt | awk '{print $1}');do
umount $OPT >/dev/null 2> /dev/null
log "取消/opt之前的挂载$OPT成功!"
done
block detect > /etc/config/fstab
mkdir -p $target_function
msum=$(grep -c "'mount'" /etc/config/fstab)
@@ -524,9 +534,10 @@ get_all_disks() {
check_free_space() {
DISK=$1
PARTED_OUTPUT=$(parted /dev/$DISK unit GB print free 2>/dev/null)
PARTED_OUTPUT=$(echo i | parted /dev/$DISK unit GB print free 2>/dev/null)
FREE_SPACE=$(echo "$PARTED_OUTPUT" | grep "Free Space" | awk '{print $3}' )
echo $FREE_SPACE |awk -F '.' '{print $1}'
echo $FREE_SPACE |awk -F '.' '{print $1}' | sed 's/[A-Za-z]//g'
}
# 获取下一个新的可用的分区号
@@ -579,7 +590,7 @@ autopart() {
log "硬盘信息列表:" $DISKSALL
SYSTEM_DISK=$(get_system_disk)
log "系统盘: "$SYSTEM_DISK
if [ "/dev/$DISK" == "$SYSTEM_DISK" ] ;then
if [[ $SYSTEM_DISK =~ ^/dev/$DISK ]] ;then
fdisksave /dev/$DISK
log "此次执行操作功能:$target_function ,目标盘是系统盘:/dev/$DISK"
PARTITIONSUM=$(get_partition_number $DISK)
@@ -1,5 +1,5 @@
#
# Copyright (c) 2022-2023 SMALLPROGRAM <https://github.com/smallprogram>
# Copyright (c) 2022-2025 SMALLPROGRAM <https://github.com/smallprogram>
# Description: Auto compile
#
name: "Auto compile with openwrt sdk"
@@ -15,6 +15,7 @@ env:
TZ: Asia/Shanghai
passwall: ${{ github.repository }}
packages: xiaorouji/openwrt-passwall-packages
package_names: "chinadns-ng dns2socks geoview hysteria ipt2socks microsocks naiveproxy tcping trojan-plus tuic-client shadowsocks-rust shadowsocksr-libev simple-obfs sing-box v2ray-geodata v2ray-plugin xray-core xray-plugin"
jobs:
@@ -325,7 +326,7 @@ jobs:
id: compile
run: |
cd sdk
for package in $(ls feeds/passwall_packages); do
for package in ${{ env.package_names }}; do
if [ -d "feeds/passwall_packages/$package" ]; then
echo "-----------begin compile $package ---------------"
sleep 10s
@@ -363,7 +364,7 @@ jobs:
echo "**package name**|**package version**" >> release.txt
echo "-|-" >> release.txt
pkgs=$(ls feeds/passwall_packages -I v2ray-geodata)
pkgs=$(ls feeds/passwall_packages -I v2ray-geodata | grep -E "$(echo "${{ env.package_names }}" | sed 's/ /|/g')")
for pkg in $pkgs; do
version=$(awk -F ':=' '/PKG_VERSION:=/{print $2}' feeds/passwall_packages/$pkg/Makefile | sed 's/\r//g')
[ -z "${version}" ] && version=$(awk -F ':=' '/PKG_SOURCE_DATE:=/{print $2}' feeds/passwall_packages/$pkg/Makefile | sed 's/\r//g')
@@ -362,7 +362,7 @@ o.default = 0
o:depends({ [_n("fallback")] = true })
]]--
o = s:option(DynamicList, _n("fallback_list"), "Fallback", translate("dest,path"))
o = s:option(DynamicList, _n("fallback_list"), "Fallback", translate("format: dest,path,xver"))
o:depends({ [_n("fallback")] = true })
o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost."))
@@ -371,19 +371,19 @@ function gen_config_server(node)
local fallbackStr = node.fallback_list[i]
if fallbackStr then
local tmp = {}
string.gsub(fallbackStr, '[^' .. "," .. ']+', function(w)
string.gsub(fallbackStr, '[^,]+', function(w)
table.insert(tmp, w)
end)
local dest = tmp[1] or ""
local path = tmp[2]
if dest:find("%.") then
else
local xver = tonumber(tmp[3])
if not dest:find("%.") then
dest = tonumber(dest)
end
fallbacks[i] = {
path = path,
dest = dest,
xver = 1
xver = xver
}
end
end
@@ -564,6 +564,9 @@ function gen_config(var)
local local_http_password = var["-local_http_password"]
local dns_listen_port = var["-dns_listen_port"]
local dns_cache = var["-dns_cache"]
local direct_dns_port = var["-direct_dns_port"]
local direct_dns_udp_server = var["-direct_dns_udp_server"]
local direct_dns_tcp_server = var["-direct_dns_tcp_server"]
local direct_dns_query_strategy = var["-direct_dns_query_strategy"]
local remote_dns_tcp_server = var["-remote_dns_tcp_server"]
local remote_dns_tcp_port = var["-remote_dns_tcp_port"]
@@ -578,6 +581,7 @@ function gen_config(var)
local dns_socks_port = var["-dns_socks_port"]
local loglevel = var["-loglevel"] or "warning"
local dns_domain_rules = {}
local dns = nil
local fakedns = nil
local routing = nil
@@ -1034,11 +1038,21 @@ function gen_config(var)
end
local domains = nil
if e.domain_list then
local domain_table = {
shunt_rule_name = e[".name"],
outboundTag = outbound_tag,
balancerTag = balancer_tag,
domain = {},
}
domains = {}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
table.insert(domains, w)
table.insert(domain_table.domain, w)
end)
if outbound_tag or balancer_tag then
table.insert(dns_domain_rules, api.clone(domain_table))
end
if #domains == 0 then domains = nil end
end
local ip = nil
@@ -1154,7 +1168,7 @@ function gen_config(var)
end
dns = {
tag = "dns-in1",
tag = "dns-global",
hosts = {},
disableCache = (dns_cache and dns_cache == "0") and true or false,
disableFallback = true,
@@ -1164,8 +1178,39 @@ function gen_config(var)
queryStrategy = "UseIP"
}
local _direct_dns = {
tag = "dns-global-direct",
queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP"
}
if direct_dns_udp_server or direct_dns_tcp_server then
local domain = {}
local nodes_domain_text = sys.exec('uci show passwall | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u')
string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w)
table.insert(domain, w)
end)
if #domain > 0 then
table.insert(dns_domain_rules, 1, {
shunt_rule_name = "logic-vpslist",
outboundTag = "direct",
domain = domain
})
end
if direct_dns_udp_server then
local port = tonumber(direct_dns_port) or 53
_direct_dns.port = port
_direct_dns.address = direct_dns_udp_server
elseif direct_dns_tcp_server then
local port = tonumber(direct_dns_port) or 53
_direct_dns.address = "tcp://" .. direct_dns_tcp_server .. ":" .. port
end
table.insert(dns.servers, _direct_dns)
end
local _remote_dns = {
_flag = "remote",
--tag = "dns-global-remote",
queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4",
address = "tcp://" .. remote_dns_tcp_server .. ":" .. tonumber(remote_dns_tcp_port) or 53
}
@@ -1182,6 +1227,11 @@ function gen_config(var)
table.insert(dns.servers, _remote_dns)
local _remote_fakedns = {
--tag = "dns-global-remote-fakedns",
address = "fakedns",
}
if remote_dns_fake then
fakedns = {}
local fakedns4 = {
@@ -1200,41 +1250,9 @@ function gen_config(var)
elseif remote_dns_query_strategy == "UseIPv6" then
table.insert(fakedns, fakedns6)
end
local _remote_fakedns = {
_flag = "remote_fakedns",
address = "fakedns",
}
table.insert(dns.servers, 1, _remote_fakedns)
end
--[[
local default_dns_flag = "remote"
if (not COMMON.default_balancer_tag and not COMMON.default_outbound_tag) or COMMON.default_outbound_tag == "direct" then
default_dns_flag = "direct"
end
if dns.servers and #dns.servers > 0 then
local dns_servers = nil
for index, value in ipairs(dns.servers) do
if not dns_servers and value["_flag"] == default_dns_flag then
if value["_flag"] == "remote" and remote_dns_fake then
value["_flag"] = "default"
break
end
dns_servers = {
_flag = "default",
address = value.address,
port = value.port,
queryStrategy = value.queryStrategy
}
break
end
end
if dns_servers then
table.insert(dns.servers, 1, dns_servers)
end
end
]]--
local dns_outbound_tag = "direct"
if dns_socks_address and dns_socks_port then
dns_outbound_tag = "out"
@@ -1299,43 +1317,56 @@ function gen_config(var)
outboundTag = "dns-out"
})
end
table.insert(rules, {
if direct_dns_udp_server or direct_dns_tcp_server then
table.insert(routing.rules, {
inboundTag = {
"dns-global-direct"
},
outboundTag = "direct"
})
end
--按分流顺序DNS
if dns_domain_rules and #dns_domain_rules > 0 then
for index, value in ipairs(dns_domain_rules) do
if value.domain and (value.outboundTag or value.balancerTag) then
local dns_server = nil
if value.outboundTag == "direct" and _direct_dns.address then
dns_server = api.clone(_direct_dns)
else
if remote_dns_fake then
dns_server = api.clone(_remote_fakedns)
else
dns_server = api.clone(_remote_dns)
end
end
dns_server.domains = value.domain
if value.shunt_rule_name then
dns_server.tag = "dns-in-" .. value.shunt_rule_name
end
if dns_server then
table.insert(dns.servers, dns_server)
table.insert(routing.rules, {
inboundTag = {
dns_server.tag
},
outboundTag = value.outboundTag or nil,
balancerTag = value.balancerTag or nil
})
end
end
end
end
table.insert(routing.rules, {
inboundTag = {
"dns-in1"
"dns-global"
},
ip = {
remote_dns_tcp_server
},
port = tonumber(remote_dns_tcp_port),
balancerTag = COMMON.default_balancer_tag,
outboundTag = dns_outbound_tag
})
if _remote_dns_host then
table.insert(rules, {
inboundTag = {
"dns-in1"
},
domain = {
_remote_dns_host
},
port = tonumber(remote_dns_doh_port),
balancerTag = COMMON.default_balancer_tag,
outboundTag = dns_outbound_tag
})
end
if remote_dns_doh_ip then
table.insert(rules, {
inboundTag = {
"dns-in1"
},
ip = {
remote_dns_doh_ip
},
port = tonumber(remote_dns_doh_port),
balancerTag = COMMON.default_balancer_tag,
outboundTag = dns_outbound_tag
})
end
local default_rule_index = #routing.rules > 0 and #routing.rules or 1
for index, value in ipairs(routing.rules) do
@@ -202,7 +202,7 @@ geosite:category-games'
config shunt_rules 'AIGC'
option remarks 'AIGC'
option domain_list 'geosite:category-ai-!cn
domain:apple-relay.apple.com'
geosite:apple-intelligence'
config shunt_rules 'Streaming'
option remarks 'Streaming'
@@ -497,7 +497,7 @@ run_singbox() {
run_xray() {
local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_query_strategy remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port
local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port
local loglevel log_file config_file server_host server_port
local _extra_param=""
eval_set_val $@
@@ -526,6 +526,20 @@ run_xray() {
[ -n "$http_username" ] && [ -n "$http_password" ] && _extra_param="${_extra_param} -local_http_username $http_username -local_http_password $http_password"
[ -n "$dns_socks_address" ] && [ -n "$dns_socks_port" ] && _extra_param="${_extra_param} -dns_socks_address ${dns_socks_address} -dns_socks_port ${dns_socks_port}"
[ -n "$dns_listen_port" ] && _extra_param="${_extra_param} -dns_listen_port ${dns_listen_port}"
if [ -n "$direct_dns_udp_server" ]; then
direct_dns_port=$(echo ${direct_dns_udp_server} | awk -F '#' '{print $2}')
_extra_param="${_extra_param} -direct_dns_udp_server $(echo ${direct_dns_udp_server} | awk -F '#' '{print $1}')"
elif [ -n "$direct_dns_tcp_server" ]; then
direct_dns_port=$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $2}')
_extra_param="${_extra_param} -direct_dns_tcp_server $(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')"
else
local local_dns=$(echo -n $(echo "${LOCAL_DNS}" | sed "s/,/\n/g" | head -n1) | tr " " ",")
_extra_param="${_extra_param} -direct_dns_udp_server $(echo ${local_dns} | awk -F '#' '{print $1}')"
direct_dns_port=$(echo ${local_dns} | awk -F '#' '{print $2}')
fi
_extra_param="${_extra_param} -direct_dns_port ${direct_dns_port:-53}"
direct_dns_query_strategy=${direct_dns_query_strategy:-UseIP}
_extra_param="${_extra_param} -direct_dns_query_strategy ${direct_dns_query_strategy}"
[ -n "$remote_dns_query_strategy" ] && _extra_param="${_extra_param} -remote_dns_query_strategy ${remote_dns_query_strategy}"
@@ -996,6 +1010,16 @@ run_redir() {
[ "${DNS_CACHE}" == "0" ] && _args="${_args} dns_cache=0"
resolve_dns_port=${NEXT_DNS_LISTEN_PORT}
_args="${_args} dns_listen_port=${resolve_dns_port}"
case "$(config_t_get global direct_dns_mode "auto")" in
udp)
_args="${_args} direct_dns_udp_server=$(config_t_get global direct_dns_udp 223.5.5.5 | sed 's/:/#/g')"
;;
tcp)
_args="${_args} direct_dns_tcp_server=$(config_t_get global direct_dns_tcp 223.5.5.5 | sed 's/:/#/g')"
;;
esac
_args="${_args} remote_dns_tcp_server=${REMOTE_DNS}"
if [ "$v2ray_dns_mode" = "tcp+doh" ]; then
remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query")
-3
View File
@@ -11,9 +11,6 @@ release/config/config.json=/etc/sing-box/config.json
release/config/sing-box.service=/usr/lib/systemd/system/sing-box.service
release/config/sing-box@.service=/usr/lib/systemd/system/sing-box@.service
release/config/sing-box.sysusers=/usr/lib/sysusers.d/sing-box.conf
release/config/sing-box.rules=usr/share/polkit-1/rules.d/sing-box.rules
release/config/sing-box-split-dns.xml=/usr/share/dbus-1/system.d/sing-box-split-dns.conf
release/completions/sing-box.bash=/usr/share/bash-completion/completions/sing-box.bash
release/completions/sing-box.fish=/usr/share/fish/vendor_completions.d/sing-box.fish
-6
View File
@@ -56,12 +56,6 @@ nfpms:
dst: /usr/lib/systemd/system/sing-box.service
- src: release/config/sing-box@.service
dst: /usr/lib/systemd/system/sing-box@.service
- src: release/config/sing-box.sysusers
dst: /usr/lib/sysusers.d/sing-box.conf
- src: release/config/sing-box.rules
dst: /usr/share/polkit-1/rules.d/sing-box.rules
- src: release/config/sing-box-split-dns.xml
dst: /usr/share/dbus-1/system.d/sing-box-split-dns.conf
- src: release/completions/sing-box.bash
dst: /usr/share/bash-completion/completions/sing-box.bash
-6
View File
@@ -138,12 +138,6 @@ nfpms:
dst: /usr/lib/systemd/system/sing-box.service
- src: release/config/sing-box@.service
dst: /usr/lib/systemd/system/sing-box@.service
- src: release/config/sing-box.sysusers
dst: /usr/lib/sysusers.d/sing-box.conf
- src: release/config/sing-box.rules
dst: /usr/share/polkit-1/rules.d/sing-box.rules
- src: release/config/sing-box-split-dns.xml
dst: /usr/share/dbus-1/system.d/sing-box-split-dns.conf
- src: release/completions/sing-box.bash
dst: /usr/share/bash-completion/completions/sing-box.bash
+5 -26
View File
@@ -7,9 +7,7 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/service"
"github.com/miekg/dns"
)
@@ -33,30 +31,11 @@ type DNSClient interface {
}
type DNSQueryOptions struct {
Transport DNSTransport
Strategy C.DomainStrategy
LookupStrategy C.DomainStrategy
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
}
func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptions) (*DNSQueryOptions, error) {
if options == nil {
return &DNSQueryOptions{}, nil
}
transportManager := service.FromContext[DNSTransportManager](ctx)
transport, loaded := transportManager.Transport(options.Server)
if !loaded {
return nil, E.New("domain resolver not found: " + options.Server)
}
return &DNSQueryOptions{
Transport: transport,
Strategy: C.DomainStrategy(options.Strategy),
DisableCache: options.DisableCache,
RewriteTTL: options.RewriteTTL,
ClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
}, nil
Transport DNSTransport
Strategy C.DomainStrategy
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
}
type RDRCStore interface {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
type FakeIPStore interface {
SimpleLifecycle
Service
Contains(address netip.Addr) bool
Create(domain string, isIPv6 bool) (netip.Addr, error)
Lookup(address netip.Addr) (string, bool)
+2 -3
View File
@@ -37,14 +37,13 @@ func NewManager(logger log.ContextLogger, registry adapter.InboundRegistry, endp
func (m *Manager) Start(stage adapter.StartStage) error {
m.access.Lock()
defer m.access.Unlock()
if m.started && m.stage >= stage {
panic("already started")
}
m.started = true
m.stage = stage
inbounds := m.inbounds
m.access.Unlock()
for _, inbound := range inbounds {
for _, inbound := range m.inbounds {
err := adapter.LegacyStart(inbound, stage)
if err != nil {
return E.Cause(err, stage, " inbound/", inbound.Type(), "[", inbound.Tag(), "]")
-5
View File
@@ -2,11 +2,6 @@ package adapter
import E "github.com/sagernet/sing/common/exceptions"
type SimpleLifecycle interface {
Start() error
Close() error
}
type StartStage uint8
const (
+6 -6
View File
@@ -28,14 +28,14 @@ func LegacyStart(starter any, stage StartStage) error {
}
type lifecycleServiceWrapper struct {
SimpleLifecycle
Service
name string
}
func NewLifecycleService(service SimpleLifecycle, name string) LifecycleService {
func NewLifecycleService(service Service, name string) LifecycleService {
return &lifecycleServiceWrapper{
SimpleLifecycle: service,
name: name,
Service: service,
name: name,
}
}
@@ -44,9 +44,9 @@ func (l *lifecycleServiceWrapper) Name() string {
}
func (l *lifecycleServiceWrapper) Start(stage StartStage) error {
return LegacyStart(l.SimpleLifecycle, stage)
return LegacyStart(l.Service, stage)
}
func (l *lifecycleServiceWrapper) Close() error {
return l.SimpleLifecycle.Close()
return l.Service.Close()
}
+1 -1
View File
@@ -11,7 +11,7 @@ type HeadlessRule interface {
type Rule interface {
HeadlessRule
SimpleLifecycle
Service
Type() string
Action() RuleAction
}
+2 -23
View File
@@ -1,27 +1,6 @@
package adapter
import (
"context"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
)
type Service interface {
Lifecycle
Type() string
Tag() string
}
type ServiceRegistry interface {
option.ServiceOptionsRegistry
Create(ctx context.Context, logger log.ContextLogger, tag string, serviceType string, options any) (Service, error)
}
type ServiceManager interface {
Lifecycle
Services() []Service
Get(tag string) (Service, bool)
Remove(tag string) error
Create(ctx context.Context, logger log.ContextLogger, tag string, serviceType string, options any) error
Start() error
Close() error
}
-21
View File
@@ -1,21 +0,0 @@
package service
type Adapter struct {
serviceType string
serviceTag string
}
func NewAdapter(serviceType string, serviceTag string) Adapter {
return Adapter{
serviceType: serviceType,
serviceTag: serviceTag,
}
}
func (a *Adapter) Type() string {
return a.serviceType
}
func (a *Adapter) Tag() string {
return a.serviceTag
}
-144
View File
@@ -1,144 +0,0 @@
package service
import (
"context"
"os"
"sync"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/taskmonitor"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
var _ adapter.ServiceManager = (*Manager)(nil)
type Manager struct {
logger log.ContextLogger
registry adapter.ServiceRegistry
access sync.Mutex
started bool
stage adapter.StartStage
services []adapter.Service
serviceByTag map[string]adapter.Service
}
func NewManager(logger log.ContextLogger, registry adapter.ServiceRegistry) *Manager {
return &Manager{
logger: logger,
registry: registry,
serviceByTag: make(map[string]adapter.Service),
}
}
func (m *Manager) Start(stage adapter.StartStage) error {
m.access.Lock()
if m.started && m.stage >= stage {
panic("already started")
}
m.started = true
m.stage = stage
services := m.services
m.access.Unlock()
for _, service := range services {
err := adapter.LegacyStart(service, stage)
if err != nil {
return E.Cause(err, stage, " service/", service.Type(), "[", service.Tag(), "]")
}
}
return nil
}
func (m *Manager) Close() error {
m.access.Lock()
defer m.access.Unlock()
if !m.started {
return nil
}
m.started = false
services := m.services
m.services = nil
monitor := taskmonitor.New(m.logger, C.StopTimeout)
var err error
for _, service := range services {
monitor.Start("close service/", service.Type(), "[", service.Tag(), "]")
err = E.Append(err, service.Close(), func(err error) error {
return E.Cause(err, "close service/", service.Type(), "[", service.Tag(), "]")
})
monitor.Finish()
}
return nil
}
func (m *Manager) Services() []adapter.Service {
m.access.Lock()
defer m.access.Unlock()
return m.services
}
func (m *Manager) Get(tag string) (adapter.Service, bool) {
m.access.Lock()
service, found := m.serviceByTag[tag]
m.access.Unlock()
return service, found
}
func (m *Manager) Remove(tag string) error {
m.access.Lock()
service, found := m.serviceByTag[tag]
if !found {
m.access.Unlock()
return os.ErrInvalid
}
delete(m.serviceByTag, tag)
index := common.Index(m.services, func(it adapter.Service) bool {
return it == service
})
if index == -1 {
panic("invalid service index")
}
m.services = append(m.services[:index], m.services[index+1:]...)
started := m.started
m.access.Unlock()
if started {
return service.Close()
}
return nil
}
func (m *Manager) Create(ctx context.Context, logger log.ContextLogger, tag string, serviceType string, options any) error {
service, err := m.registry.Create(ctx, logger, tag, serviceType, options)
if err != nil {
return err
}
m.access.Lock()
defer m.access.Unlock()
if m.started {
for _, stage := range adapter.ListStartStages {
err = adapter.LegacyStart(service, stage)
if err != nil {
return E.Cause(err, stage, " service/", service.Type(), "[", service.Tag(), "]")
}
}
}
if existsService, loaded := m.serviceByTag[tag]; loaded {
if m.started {
err = existsService.Close()
if err != nil {
return E.Cause(err, "close service/", existsService.Type(), "[", existsService.Tag(), "]")
}
}
existsIndex := common.Index(m.services, func(it adapter.Service) bool {
return it == existsService
})
if existsIndex == -1 {
panic("invalid service index")
}
m.services = append(m.services[:existsIndex], m.services[existsIndex+1:]...)
}
m.services = append(m.services, service)
m.serviceByTag[tag] = service
return nil
}
-72
View File
@@ -1,72 +0,0 @@
package service
import (
"context"
"sync"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
type ConstructorFunc[T any] func(ctx context.Context, logger log.ContextLogger, tag string, options T) (adapter.Service, error)
func Register[Options any](registry *Registry, outboundType string, constructor ConstructorFunc[Options]) {
registry.register(outboundType, func() any {
return new(Options)
}, func(ctx context.Context, logger log.ContextLogger, tag string, rawOptions any) (adapter.Service, error) {
var options *Options
if rawOptions != nil {
options = rawOptions.(*Options)
}
return constructor(ctx, logger, tag, common.PtrValueOrDefault(options))
})
}
var _ adapter.ServiceRegistry = (*Registry)(nil)
type (
optionsConstructorFunc func() any
constructorFunc func(ctx context.Context, logger log.ContextLogger, tag string, options any) (adapter.Service, error)
)
type Registry struct {
access sync.Mutex
optionsType map[string]optionsConstructorFunc
constructor map[string]constructorFunc
}
func NewRegistry() *Registry {
return &Registry{
optionsType: make(map[string]optionsConstructorFunc),
constructor: make(map[string]constructorFunc),
}
}
func (m *Registry) CreateOptions(outboundType string) (any, bool) {
m.access.Lock()
defer m.access.Unlock()
optionsConstructor, loaded := m.optionsType[outboundType]
if !loaded {
return nil, false
}
return optionsConstructor(), true
}
func (m *Registry) Create(ctx context.Context, logger log.ContextLogger, tag string, outboundType string, options any) (adapter.Service, error) {
m.access.Lock()
defer m.access.Unlock()
constructor, loaded := m.constructor[outboundType]
if !loaded {
return nil, E.New("outbound type not found: " + outboundType)
}
return constructor(ctx, logger, tag, options)
}
func (m *Registry) register(outboundType string, optionsConstructor optionsConstructorFunc, constructor constructorFunc) {
m.access.Lock()
defer m.access.Unlock()
m.optionsType[outboundType] = optionsConstructor
m.constructor[outboundType] = constructor
}
+1 -1
View File
@@ -3,6 +3,6 @@ package adapter
import "time"
type TimeService interface {
SimpleLifecycle
Service
TimeFunc() func() time.Time
}
+46 -77
View File
@@ -12,7 +12,6 @@ import (
"github.com/sagernet/sing-box/adapter/endpoint"
"github.com/sagernet/sing-box/adapter/inbound"
"github.com/sagernet/sing-box/adapter/outbound"
boxService "github.com/sagernet/sing-box/adapter/service"
"github.com/sagernet/sing-box/common/certificate"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/taskmonitor"
@@ -35,23 +34,22 @@ import (
"github.com/sagernet/sing/service/pause"
)
var _ adapter.SimpleLifecycle = (*Box)(nil)
var _ adapter.Service = (*Box)(nil)
type Box struct {
createdAt time.Time
logFactory log.Factory
logger log.ContextLogger
network *route.NetworkManager
endpoint *endpoint.Manager
inbound *inbound.Manager
outbound *outbound.Manager
service *boxService.Manager
dnsTransport *dns.TransportManager
dnsRouter *dns.Router
connection *route.ConnectionManager
router *route.Router
internalService []adapter.LifecycleService
done chan struct{}
createdAt time.Time
logFactory log.Factory
logger log.ContextLogger
network *route.NetworkManager
endpoint *endpoint.Manager
inbound *inbound.Manager
outbound *outbound.Manager
dnsTransport *dns.TransportManager
dnsRouter *dns.Router
connection *route.ConnectionManager
router *route.Router
services []adapter.LifecycleService
done chan struct{}
}
type Options struct {
@@ -66,7 +64,6 @@ func Context(
outboundRegistry adapter.OutboundRegistry,
endpointRegistry adapter.EndpointRegistry,
dnsTransportRegistry adapter.DNSTransportRegistry,
serviceRegistry adapter.ServiceRegistry,
) context.Context {
if service.FromContext[option.InboundOptionsRegistry](ctx) == nil ||
service.FromContext[adapter.InboundRegistry](ctx) == nil {
@@ -87,10 +84,6 @@ func Context(
ctx = service.ContextWith[option.DNSTransportOptionsRegistry](ctx, dnsTransportRegistry)
ctx = service.ContextWith[adapter.DNSTransportRegistry](ctx, dnsTransportRegistry)
}
if service.FromContext[adapter.ServiceRegistry](ctx) == nil {
ctx = service.ContextWith[option.ServiceOptionsRegistry](ctx, serviceRegistry)
ctx = service.ContextWith[adapter.ServiceRegistry](ctx, serviceRegistry)
}
return ctx
}
@@ -106,7 +99,6 @@ func New(options Options) (*Box, error) {
inboundRegistry := service.FromContext[adapter.InboundRegistry](ctx)
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
dnsTransportRegistry := service.FromContext[adapter.DNSTransportRegistry](ctx)
serviceRegistry := service.FromContext[adapter.ServiceRegistry](ctx)
if endpointRegistry == nil {
return nil, E.New("missing endpoint registry in context")
@@ -117,12 +109,6 @@ func New(options Options) (*Box, error) {
if outboundRegistry == nil {
return nil, E.New("missing outbound registry in context")
}
if dnsTransportRegistry == nil {
return nil, E.New("missing DNS transport registry in context")
}
if serviceRegistry == nil {
return nil, E.New("missing service registry in context")
}
ctx = pause.WithDefaultManager(ctx)
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
@@ -156,7 +142,7 @@ func New(options Options) (*Box, error) {
return nil, E.Cause(err, "create log factory")
}
var internalServices []adapter.LifecycleService
var services []adapter.LifecycleService
certificateOptions := common.PtrValueOrDefault(options.Certificate)
if C.IsAndroid || certificateOptions.Store != "" && certificateOptions.Store != C.CertificateStoreSystem ||
len(certificateOptions.Certificate) > 0 ||
@@ -167,7 +153,7 @@ func New(options Options) (*Box, error) {
return nil, err
}
service.MustRegister[adapter.CertificateStore](ctx, certificateStore)
internalServices = append(internalServices, certificateStore)
services = append(services, certificateStore)
}
routeOptions := common.PtrValueOrDefault(options.Route)
@@ -176,12 +162,10 @@ func New(options Options) (*Box, error) {
inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager)
outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final)
dnsTransportManager := dns.NewTransportManager(logFactory.NewLogger("dns/transport"), dnsTransportRegistry, outboundManager, dnsOptions.Final)
serviceManager := boxService.NewManager(logFactory.NewLogger("service"), serviceRegistry)
service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
service.MustRegister[adapter.InboundManager](ctx, inboundManager)
service.MustRegister[adapter.OutboundManager](ctx, outboundManager)
service.MustRegister[adapter.DNSTransportManager](ctx, dnsTransportManager)
service.MustRegister[adapter.ServiceManager](ctx, serviceManager)
dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions)
service.MustRegister[adapter.DNSRouter](ctx, dnsRouter)
networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions)
@@ -296,24 +280,6 @@ func New(options Options) (*Box, error) {
return nil, E.Cause(err, "initialize outbound[", i, "]")
}
}
for i, serviceOptions := range options.Services {
var tag string
if serviceOptions.Tag != "" {
tag = serviceOptions.Tag
} else {
tag = F.ToString(i)
}
err = serviceManager.Create(
ctx,
logFactory.NewLogger(F.ToString("service/", serviceOptions.Type, "[", tag, "]")),
tag,
serviceOptions.Type,
serviceOptions.Options,
)
if err != nil {
return nil, E.Cause(err, "initialize service[", i, "]")
}
}
outboundManager.Initialize(common.Must1(
direct.NewOutbound(
ctx,
@@ -339,7 +305,7 @@ func New(options Options) (*Box, error) {
if needCacheFile {
cacheFile := cachefile.New(ctx, common.PtrValueOrDefault(experimentalOptions.CacheFile))
service.MustRegister[adapter.CacheFile](ctx, cacheFile)
internalServices = append(internalServices, cacheFile)
services = append(services, cacheFile)
}
if needClashAPI {
clashAPIOptions := common.PtrValueOrDefault(experimentalOptions.ClashAPI)
@@ -350,7 +316,7 @@ func New(options Options) (*Box, error) {
}
router.SetTracker(clashServer)
service.MustRegister[adapter.ClashServer](ctx, clashServer)
internalServices = append(internalServices, clashServer)
services = append(services, clashServer)
}
if needV2RayAPI {
v2rayServer, err := experimental.NewV2RayServer(logFactory.NewLogger("v2ray-api"), common.PtrValueOrDefault(experimentalOptions.V2RayAPI))
@@ -359,7 +325,7 @@ func New(options Options) (*Box, error) {
}
if v2rayServer.StatsService() != nil {
router.SetTracker(v2rayServer.StatsService())
internalServices = append(internalServices, v2rayServer)
services = append(services, v2rayServer)
service.MustRegister[adapter.V2RayServer](ctx, v2rayServer)
}
}
@@ -377,23 +343,22 @@ func New(options Options) (*Box, error) {
WriteToSystem: ntpOptions.WriteToSystem,
})
timeService.TimeService = ntpService
internalServices = append(internalServices, adapter.NewLifecycleService(ntpService, "ntp service"))
services = append(services, adapter.NewLifecycleService(ntpService, "ntp service"))
}
return &Box{
network: networkManager,
endpoint: endpointManager,
inbound: inboundManager,
outbound: outboundManager,
dnsTransport: dnsTransportManager,
service: serviceManager,
dnsRouter: dnsRouter,
connection: connectionManager,
router: router,
createdAt: createdAt,
logFactory: logFactory,
logger: logFactory.Logger(),
internalService: internalServices,
done: make(chan struct{}),
network: networkManager,
endpoint: endpointManager,
inbound: inboundManager,
outbound: outboundManager,
dnsTransport: dnsTransportManager,
dnsRouter: dnsRouter,
connection: connectionManager,
router: router,
createdAt: createdAt,
logFactory: logFactory,
logger: logFactory.Logger(),
services: services,
done: make(chan struct{}),
}, nil
}
@@ -443,11 +408,11 @@ func (s *Box) preStart() error {
if err != nil {
return E.Cause(err, "start logger")
}
err = adapter.StartNamed(adapter.StartStateInitialize, s.internalService) // cache-file clash-api v2ray-api
err = adapter.StartNamed(adapter.StartStateInitialize, s.services) // cache-file clash-api v2ray-api
if err != nil {
return err
}
err = adapter.Start(adapter.StartStateInitialize, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint, s.service)
err = adapter.Start(adapter.StartStateInitialize, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint)
if err != nil {
return err
}
@@ -463,27 +428,31 @@ func (s *Box) start() error {
if err != nil {
return err
}
err = adapter.StartNamed(adapter.StartStateStart, s.internalService)
err = adapter.StartNamed(adapter.StartStateStart, s.services)
if err != nil {
return err
}
err = adapter.Start(adapter.StartStateStart, s.inbound, s.endpoint, s.service)
err = s.inbound.Start(adapter.StartStateStart)
if err != nil {
return err
}
err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.inbound, s.endpoint, s.service)
err = adapter.Start(adapter.StartStateStart, s.endpoint)
if err != nil {
return err
}
err = adapter.StartNamed(adapter.StartStatePostStart, s.internalService)
err = adapter.Start(adapter.StartStatePostStart, s.outbound, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.inbound, s.endpoint)
if err != nil {
return err
}
err = adapter.Start(adapter.StartStateStarted, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint, s.service)
err = adapter.StartNamed(adapter.StartStatePostStart, s.services)
if err != nil {
return err
}
err = adapter.StartNamed(adapter.StartStateStarted, s.internalService)
err = adapter.Start(adapter.StartStateStarted, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint)
if err != nil {
return err
}
err = adapter.StartNamed(adapter.StartStateStarted, s.services)
if err != nil {
return err
}
@@ -500,7 +469,7 @@ func (s *Box) Close() error {
err := common.Close(
s.inbound, s.outbound, s.endpoint, s.router, s.connection, s.dnsRouter, s.dnsTransport, s.network,
)
for _, lifecycleService := range s.internalService {
for _, lifecycleService := range s.services {
err = E.Append(err, lifecycleService.Close(), func(err error) error {
return E.Cause(err, "close ", lifecycleService.Name())
})
+1 -1
View File
@@ -69,5 +69,5 @@ func preRun(cmd *cobra.Command, args []string) {
configPaths = append(configPaths, "config.json")
}
globalCtx = service.ContextWith(globalCtx, deprecated.NewStderrManager(log.StdLogger()))
globalCtx = box.Context(globalCtx, include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), include.DNSTransportRegistry(), include.ServiceRegistry())
globalCtx = box.Context(globalCtx, include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), include.DNSTransportRegistry())
}
+2 -1
View File
@@ -24,6 +24,7 @@ type Options struct {
ResolverOnDetour bool
NewDialer bool
LegacyDNSDialer bool
DirectOutbound bool
}
// TODO: merge with NewWithOptions
@@ -108,7 +109,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 {
} else if !options.DirectOutbound {
deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver)
}
}
+1 -1
View File
@@ -37,7 +37,7 @@ func (w *acmeWrapper) Close() error {
return nil
}
func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Config, adapter.SimpleLifecycle, error) {
func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Config, adapter.Service, error) {
var acmeServer string
switch options.Provider {
case "", "letsencrypt":
+1 -1
View File
@@ -11,6 +11,6 @@ import (
E "github.com/sagernet/sing/common/exceptions"
)
func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Config, adapter.SimpleLifecycle, error) {
func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Config, adapter.Service, error) {
return nil, nil, E.New(`ACME is not included in this build, rebuild with -tags with_acme`)
}
+2 -2
View File
@@ -21,7 +21,7 @@ var errInsecureUnused = E.New("tls: insecure unused")
type STDServerConfig struct {
config *tls.Config
logger log.Logger
acmeService adapter.SimpleLifecycle
acmeService adapter.Service
certificate []byte
key []byte
certificatePath string
@@ -164,7 +164,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
return nil, nil
}
var tlsConfig *tls.Config
var acmeService adapter.SimpleLifecycle
var acmeService adapter.Service
var err error
if options.ACME != nil && len(options.ACME.Domain) > 0 {
//nolint:staticcheck
-3
View File
@@ -25,9 +25,6 @@ const (
TypeTUIC = "tuic"
TypeHysteria2 = "hysteria2"
TypeTailscale = "tailscale"
TypeDERP = "derp"
TypeDERPSTUN = "derp-stun"
TypeResolved = "resolved"
)
const (
+15 -44
View File
@@ -243,15 +243,9 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, domain string, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error) {
domain = FqdnToDomain(domain)
dnsName := dns.Fqdn(domain)
var strategy C.DomainStrategy
if options.LookupStrategy != C.DomainStrategyAsIS {
strategy = options.LookupStrategy
} else {
strategy = options.Strategy
}
if strategy == C.DomainStrategyIPv4Only {
if options.Strategy == C.DomainStrategyIPv4Only {
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, options, responseChecker)
} else if strategy == C.DomainStrategyIPv6Only {
} else if options.Strategy == C.DomainStrategyIPv6Only {
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, options, responseChecker)
}
var response4 []netip.Addr
@@ -277,7 +271,7 @@ func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, dom
if len(response4) == 0 && len(response6) == 0 {
return nil, err
}
return sortAddresses(response4, response6, strategy), nil
return sortAddresses(response4, response6, options.Strategy), nil
}
func (c *Client) ClearCache() {
@@ -533,26 +527,12 @@ func transportTagFromContext(ctx context.Context) (string, bool) {
return value, loaded
}
func FixedResponseStatus(message *dns.Msg, rcode int) *dns.Msg {
return &dns.Msg{
MsgHdr: dns.MsgHdr{
Id: message.Id,
Rcode: rcode,
Response: true,
},
Question: message.Question,
}
}
func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, timeToLive uint32) *dns.Msg {
response := dns.Msg{
MsgHdr: dns.MsgHdr{
Id: id,
Response: true,
Authoritative: true,
RecursionDesired: true,
RecursionAvailable: true,
Rcode: dns.RcodeSuccess,
Id: id,
Rcode: dns.RcodeSuccess,
Response: true,
},
Question: []dns.Question{question},
}
@@ -585,12 +565,9 @@ func FixedResponse(id uint16, question dns.Question, addresses []netip.Addr, tim
func FixedResponseCNAME(id uint16, question dns.Question, record string, timeToLive uint32) *dns.Msg {
response := dns.Msg{
MsgHdr: dns.MsgHdr{
Id: id,
Response: true,
Authoritative: true,
RecursionDesired: true,
RecursionAvailable: true,
Rcode: dns.RcodeSuccess,
Id: id,
Rcode: dns.RcodeSuccess,
Response: true,
},
Question: []dns.Question{question},
Answer: []dns.RR{
@@ -611,12 +588,9 @@ func FixedResponseCNAME(id uint16, question dns.Question, record string, timeToL
func FixedResponseTXT(id uint16, question dns.Question, records []string, timeToLive uint32) *dns.Msg {
response := dns.Msg{
MsgHdr: dns.MsgHdr{
Id: id,
Response: true,
Authoritative: true,
RecursionDesired: true,
RecursionAvailable: true,
Rcode: dns.RcodeSuccess,
Id: id,
Rcode: dns.RcodeSuccess,
Response: true,
},
Question: []dns.Question{question},
Answer: []dns.RR{
@@ -637,12 +611,9 @@ func FixedResponseTXT(id uint16, question dns.Question, records []string, timeTo
func FixedResponseMX(id uint16, question dns.Question, records []*net.MX, timeToLive uint32) *dns.Msg {
response := dns.Msg{
MsgHdr: dns.MsgHdr{
Id: id,
Response: true,
Authoritative: true,
RecursionDesired: true,
RecursionAvailable: true,
Rcode: dns.RcodeSuccess,
Id: id,
Rcode: dns.RcodeSuccess,
Response: true,
},
Question: []dns.Question{question},
}
-5
View File
@@ -285,12 +285,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte
} else if errors.Is(err, ErrResponseRejected) {
rejected = true
r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
/*} else if responseCheck!= nil && errors.Is(err, RcodeError(mDNS.RcodeNameError)) {
rejected = true
r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())))
*/
} else if len(message.Question) > 0 {
rejected = true
r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String())))
} else {
r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for <empty query>"))
+3 -7
View File
@@ -57,17 +57,13 @@ func NewTLS(ctx context.Context, logger log.ContextLogger, tag string, options o
if serverAddr.Port == 0 {
serverAddr.Port = 853
}
return NewTLSRaw(logger, dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeTLS, tag, options.RemoteDNSServerOptions), transportDialer, serverAddr, tlsConfig), nil
}
func NewTLSRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer N.Dialer, serverAddr M.Socksaddr, tlsConfig tls.Config) *TLSTransport {
return &TLSTransport{
TransportAdapter: adapter,
TransportAdapter: dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeTLS, tag, options.RemoteDNSServerOptions),
logger: logger,
dialer: dialer,
dialer: transportDialer,
serverAddr: serverAddr,
tlsConfig: tlsConfig,
}
}, nil
}
func (t *TLSTransport) Start(stage adapter.StartStage) error {
+1 -1
View File
@@ -2,7 +2,7 @@
icon: material/alert-decagram
---
#### 1.12.0-alpha.23
#### 1.12.0-beta.1
* Fixes and improvements
+1 -1
View File
@@ -33,7 +33,7 @@ func BaseContext(platformInterface PlatformInterface) context.Context {
})
}
}
return box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), dnsRegistry, include.ServiceRegistry())
return box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), dnsRegistry)
}
func parseConfig(ctx context.Context, configContent string) (option.Options, error) {
-13
View File
@@ -7,7 +7,6 @@ import (
"github.com/sagernet/sing-box/adapter/endpoint"
"github.com/sagernet/sing-box/adapter/inbound"
"github.com/sagernet/sing-box/adapter/outbound"
"github.com/sagernet/sing-box/adapter/service"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/dns/transport"
@@ -34,7 +33,6 @@ import (
"github.com/sagernet/sing-box/protocol/tun"
"github.com/sagernet/sing-box/protocol/vless"
"github.com/sagernet/sing-box/protocol/vmess"
"github.com/sagernet/sing-box/service/resolved"
E "github.com/sagernet/sing/common/exceptions"
)
@@ -112,7 +110,6 @@ func DNSTransportRegistry() *dns.TransportRegistry {
hosts.RegisterTransport(registry)
local.RegisterTransport(registry)
fakeip.RegisterTransport(registry)
resolved.RegisterTransport(registry)
registerQUICTransports(registry)
registerDHCPTransport(registry)
@@ -121,16 +118,6 @@ func DNSTransportRegistry() *dns.TransportRegistry {
return registry
}
func ServiceRegistry() *service.Registry {
registry := service.NewRegistry()
resolved.RegisterService(registry)
registerDERPService(registry)
return registry
}
func registerStubForRemovedInbounds(registry *inbound.Registry) {
inbound.Register[option.ShadowsocksInboundOptions](registry, C.TypeShadowsocksR, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksInboundOptions) (adapter.Inbound, error) {
return nil, E.New("ShadowsocksR is deprecated and removed in sing-box 1.6.0")
-7
View File
@@ -4,10 +4,8 @@ package include
import (
"github.com/sagernet/sing-box/adapter/endpoint"
"github.com/sagernet/sing-box/adapter/service"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/protocol/tailscale"
"github.com/sagernet/sing-box/service/derp"
)
func registerTailscaleEndpoint(registry *endpoint.Registry) {
@@ -17,8 +15,3 @@ func registerTailscaleEndpoint(registry *endpoint.Registry) {
func registerTailscaleTransport(registry *dns.TransportRegistry) {
tailscale.RegistryTransport(registry)
}
func registerDERPService(registry *service.Registry) {
derp.Register(registry)
derp.RegisterSTUN(registry)
}
-10
View File
@@ -7,7 +7,6 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/endpoint"
"github.com/sagernet/sing-box/adapter/service"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/log"
@@ -26,12 +25,3 @@ func registerTailscaleTransport(registry *dns.TransportRegistry) {
return nil, E.New(`Tailscale is not included in this build, rebuild with -tags with_tailscale`)
})
}
func registerDERPService(registry *service.Registry) {
service.Register[option.DERPServiceOptions](registry, C.TypeDERP, func(ctx context.Context, logger log.ContextLogger, tag string, options option.DERPServiceOptions) (adapter.Service, error) {
return nil, E.New(`DERP is not included in this build, rebuild with -tags with_tailscale`)
})
service.Register[option.DERPSTUNServiceOptions](registry, C.TypeDERP, func(ctx context.Context, logger log.ContextLogger, tag string, options option.DERPSTUNServiceOptions) (adapter.Service, error) {
return nil, E.New(`STUN (DERP) is not included in this build, rebuild with -tags with_tailscale`)
})
}
+1
View File
@@ -121,6 +121,7 @@ type LegacyDNSFakeIPOptions struct {
type DNSTransportOptionsRegistry interface {
CreateOptions(transportType string) (any, bool)
}
type _DNSServerOptions struct {
Type string `json:"type,omitempty"`
Tag string `json:"tag,omitempty"`
+2 -2
View File
@@ -32,11 +32,11 @@ func (h *Endpoint) UnmarshalJSONContext(ctx context.Context, content []byte) err
}
registry := service.FromContext[EndpointOptionsRegistry](ctx)
if registry == nil {
return E.New("missing endpoint fields registry in context")
return E.New("missing Endpoint fields registry in context")
}
options, loaded := registry.CreateOptions(h.Type)
if !loaded {
return E.New("unknown endpoint type: ", h.Type)
return E.New("unknown inbound type: ", h.Type)
}
err = badjson.UnmarshallExcludedContext(ctx, content, (*_Endpoint)(h), options)
if err != nil {
+1 -1
View File
@@ -34,7 +34,7 @@ func (h *Inbound) UnmarshalJSONContext(ctx context.Context, content []byte) erro
}
registry := service.FromContext[InboundOptionsRegistry](ctx)
if registry == nil {
return E.New("missing inbound fields registry in context")
return E.New("missing Inbound fields registry in context")
}
options, loaded := registry.CreateOptions(h.Type)
if !loaded {
-1
View File
@@ -19,7 +19,6 @@ type _Options struct {
Inbounds []Inbound `json:"inbounds,omitempty"`
Outbounds []Outbound `json:"outbounds,omitempty"`
Route *RouteOptions `json:"route,omitempty"`
Services []Service `json:"services,omitempty"`
Experimental *ExperimentalOptions `json:"experimental,omitempty"`
}
-49
View File
@@ -1,49 +0,0 @@
package option
import (
"context"
"net/netip"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badoption"
)
type _ResolvedServiceOptions struct {
ListenOptions
}
type ResolvedServiceOptions _ResolvedServiceOptions
func (r ResolvedServiceOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
if r.Listen != nil && netip.Addr(*r.Listen) == (netip.AddrFrom4([4]byte{127, 0, 0, 53})) {
r.Listen = nil
}
if r.ListenPort == 53 {
r.ListenPort = 0
}
return json.MarshalContext(ctx, (*_ResolvedServiceOptions)(&r))
}
func (r *ResolvedServiceOptions) UnmarshalJSONContext(ctx context.Context, bytes []byte) error {
err := json.UnmarshalContextDisallowUnknownFields(ctx, bytes, (*_ResolvedServiceOptions)(r))
if err != nil {
return err
}
if r.Listen == nil {
r.Listen = (*badoption.Addr)(common.Ptr(netip.AddrFrom4([4]byte{127, 0, 0, 53})))
}
if r.ListenPort == 0 {
r.ListenPort = 53
}
return nil
}
type SplitDNSServerOptions struct {
Service string `json:"Service"`
AcceptDefaultResolvers bool `json:"accept_default_resolvers,omitempty"`
// NDots int `json:"ndots,omitempty"`
// Timeout badoption.Duration `json:"timeout,omitempty"`
// Attempts int `json:"attempts,omitempty"`
// Rotate bool `json:"rotate,omitempty"`
}
-47
View File
@@ -1,47 +0,0 @@
package option
import (
"context"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badjson"
"github.com/sagernet/sing/service"
)
type ServiceOptionsRegistry interface {
CreateOptions(serviceType string) (any, bool)
}
type _Service struct {
Type string `json:"type"`
Tag string `json:"tag,omitempty"`
Options any `json:"-"`
}
type Service _Service
func (h *Service) MarshalJSONContext(ctx context.Context) ([]byte, error) {
return badjson.MarshallObjectsContext(ctx, (*_Service)(h), h.Options)
}
func (h *Service) UnmarshalJSONContext(ctx context.Context, content []byte) error {
err := json.UnmarshalContext(ctx, content, (*_Service)(h))
if err != nil {
return err
}
registry := service.FromContext[ServiceOptionsRegistry](ctx)
if registry == nil {
return E.New("missing service fields registry in context")
}
options, loaded := registry.CreateOptions(h.Type)
if !loaded {
return E.New("unknown inbound type: ", h.Type)
}
err = badjson.UnmarshallExcludedContext(ctx, content, (*_Service)(h), options)
if err != nil {
return err
}
h.Options = options
return nil
}
-62
View File
@@ -2,12 +2,6 @@ package option
import (
"net/netip"
"net/url"
"reflect"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/json/badoption"
M "github.com/sagernet/sing/common/metadata"
)
type TailscaleEndpointOptions struct {
@@ -28,59 +22,3 @@ type TailscaleDNSServerOptions struct {
Endpoint string `json:"endpoint,omitempty"`
AcceptDefaultResolvers bool `json:"accept_default_resolvers,omitempty"`
}
type DERPServiceOptions struct {
ListenOptions
InboundTLSOptionsContainer
ConfigPath string `json:"config_path,omitempty"`
VerifyClientEndpoint badoption.Listable[string] `json:"verify_client_endpoint,omitempty"`
VerifyClientURL badoption.Listable[DERPVerifyClientURLOptions] `json:"verify_client_url,omitempty"`
MeshWith badoption.Listable[DERPMeshOptions] `json:"mesh_with,omitempty"`
MeshPSK string `json:"mesh_psk,omitempty"`
MeshPSKFile string `json:"mesh_psk_file,omitempty"`
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
}
type _DERPVerifyClientURLOptions struct {
URL string `json:"url,omitempty"`
DialerOptions
}
type DERPVerifyClientURLOptions _DERPVerifyClientURLOptions
func (d DERPVerifyClientURLOptions) ServerIsDomain() bool {
verifyURL, err := url.Parse(d.URL)
if err != nil {
return false
}
return M.IsDomainName(verifyURL.Host)
}
func (d DERPVerifyClientURLOptions) MarshalJSON() ([]byte, error) {
if reflect.DeepEqual(d, _DERPVerifyClientURLOptions{}) {
return json.Marshal(d.URL)
} else {
return json.Marshal(_DERPVerifyClientURLOptions(d))
}
}
func (d *DERPVerifyClientURLOptions) UnmarshalJSON(bytes []byte) error {
var stringValue string
err := json.Unmarshal(bytes, &stringValue)
if err == nil {
d.URL = stringValue
return nil
}
return json.Unmarshal(bytes, (*_DERPVerifyClientURLOptions)(d))
}
type DERPMeshOptions struct {
ServerOptions
Host string `json:"host,omitempty"`
OutboundTLSOptionsContainer
DialerOptions
}
type DERPSTUNServiceOptions struct {
ListenOptions
}
+6 -1
View File
@@ -48,7 +48,12 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
if options.Detour != "" {
return nil, E.New("`detour` is not supported in direct context")
}
outboundDialer, err := dialer.New(ctx, options.DialerOptions, true)
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
Context: ctx,
Options: options.DialerOptions,
RemoteIsDomain: true,
DirectOutbound: true,
})
if err != nil {
return nil, err
}
@@ -1,15 +0,0 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own_prefix="org.freedesktop.resolve1"/>
<allow send_destination="org.freedesktop.resolve1"/>
<allow send_interface="org.freedesktop.resolve1.Manager"/>
</policy>
<policy user="sing-box">
<allow own_prefix="org.freedesktop.resolve1"/>
<allow send_destination="org.freedesktop.resolve1"/>
<allow send_interface="org.freedesktop.resolve1.Manager"/>
</policy>
</busconfig>
-8
View File
@@ -1,8 +0,0 @@
polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.resolve1.set-domains" ||
action.id == "org.freedesktop.resolve1.set-default-route" ||
action.id == "org.freedesktop.resolve1.set-dns-servers") &&
subject.user == "sing-box") {
return polkit.Result.YES;
}
});
-2
View File
@@ -4,8 +4,6 @@ Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target network-online.target
[Service]
User=sing-box
StateDirectory=sing-box
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
ExecStart=/usr/bin/sing-box -D /var/lib/sing-box -C /etc/sing-box run
@@ -1 +0,0 @@
u! sing-box - "sing-box Service"
@@ -4,8 +4,6 @@ Documentation=https://sing-box.sagernet.org
After=network.target nss-lookup.target network-online.target
[Service]
User=sing-box
StateDirectory=sing-box-%i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
ExecStart=/usr/bin/sing-box -D /var/lib/sing-box-%i -c /etc/sing-box/%i.json run
+5 -10
View File
@@ -27,16 +27,12 @@ func (r *Router) hijackDNSStream(ctx context.Context, conn net.Conn, metadata ad
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
err := dnsOutbound.HandleStreamDNSRequest(ctx, r.dns, conn, metadata)
if err != nil {
if !E.IsClosedOrCanceled(err) {
return err
} else {
return nil
}
return err
}
}
}
func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext) error {
func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext) {
if natConn, isNatConn := conn.(udpnat.Conn); isNatConn {
metadata.Destination = M.Socksaddr{}
for _, packet := range packetBuffers {
@@ -52,19 +48,18 @@ func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetB
ctx: ctx,
metadata: metadata,
})
return nil
return
}
err := dnsOutbound.NewDNSPacketConnection(ctx, r.dns, conn, packetBuffers, metadata)
if err != nil && !E.IsClosedOrCanceled(err) {
return E.Cause(err, "process DNS packet")
r.logger.ErrorContext(ctx, E.Cause(err, "process DNS packet connection"))
}
return nil
}
func ExchangeDNSPacket(ctx context.Context, router adapter.DNSRouter, logger logger.ContextLogger, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) {
err := exchangeDNSPacket(ctx, router, conn, buffer, metadata, destination)
if err != nil && !errors.Is(err, tun.ErrDrop) && !E.IsClosedOrCanceled(err) {
logger.ErrorContext(ctx, E.Cause(err, "process DNS packet"))
logger.ErrorContext(ctx, E.Cause(err, "process DNS packet connection"))
}
}
+16 -16
View File
@@ -6,6 +6,7 @@ import (
"net"
"net/netip"
"os"
"os/user"
"strings"
"time"
@@ -60,8 +61,6 @@ func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata
func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
if r.pauseManager.IsDevicePaused() {
return E.New("reject connection to ", metadata.Destination, " while device paused")
} else if metadata.InboundType == C.TypeResolved {
return r.hijackDNSStream(ctx, conn, metadata)
}
//nolint:staticcheck
@@ -118,12 +117,14 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
}
case *rule.RuleActionReject:
buf.ReleaseMulti(buffers)
return action.Error(ctx)
N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx))
return nil
case *rule.RuleActionHijackDNS:
for _, buffer := range buffers {
conn = bufio.NewCachedConn(conn, buffer)
}
return r.hijackDNSStream(ctx, conn, metadata)
r.hijackDNSStream(ctx, conn, metadata)
return nil
}
}
if selectedRule == nil {
@@ -186,8 +187,6 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn,
func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
if r.pauseManager.IsDevicePaused() {
return E.New("reject packet connection to ", metadata.Destination, " while device paused")
} else if metadata.InboundType == C.TypeResolved {
return r.hijackDNSPacket(ctx, conn, nil, metadata)
}
//nolint:staticcheck
if metadata.InboundDetour != "" {
@@ -239,10 +238,11 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
}
case *rule.RuleActionReject:
N.ReleaseMultiPacketBuffer(packetBuffers)
return action.Error(ctx)
N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx))
return nil
case *rule.RuleActionHijackDNS:
return r.hijackDNSPacket(ctx, conn, packetBuffers, metadata)
r.hijackDNSPacket(ctx, conn, packetBuffers, metadata)
return nil
}
}
if selectedRule == nil || selectReturn {
@@ -305,16 +305,16 @@ func (r *Router) matchRule(
r.logger.InfoContext(ctx, "failed to search process: ", fErr)
} else {
if processInfo.ProcessPath != "" {
if processInfo.User != "" {
r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath, ", user: ", processInfo.User)
} else if processInfo.UserId != -1 {
r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath, ", user id: ", processInfo.UserId)
} else {
r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath)
}
r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath)
} else if processInfo.PackageName != "" {
r.logger.InfoContext(ctx, "found package name: ", processInfo.PackageName)
} else if processInfo.UserId != -1 {
if /*needUserName &&*/ true {
osUser, _ := user.LookupId(F.ToString(processInfo.UserId))
if osUser != nil {
processInfo.User = osUser.Username
}
}
if processInfo.User != "" {
r.logger.InfoContext(ctx, "found user: ", processInfo.User)
} else {
-463
View File
@@ -1,463 +0,0 @@
package derp
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/listener"
"github.com/sagernet/sing-box/common/tls"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
boxScale "github.com/sagernet/sing-box/protocol/tailscale"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
aTLS "github.com/sagernet/sing/common/tls"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/filemanager"
"github.com/sagernet/tailscale/client/tailscale"
"github.com/sagernet/tailscale/derp"
"github.com/sagernet/tailscale/derp/derphttp"
"github.com/sagernet/tailscale/net/netmon"
"github.com/sagernet/tailscale/net/wsconn"
"github.com/sagernet/tailscale/tsweb"
"github.com/sagernet/tailscale/types/key"
"github.com/coder/websocket"
"github.com/go-chi/render"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
func Register(registry *boxService.Registry) {
boxService.Register[option.DERPServiceOptions](registry, C.TypeDERP, NewService)
}
type Service struct {
boxService.Adapter
ctx context.Context
logger logger.ContextLogger
listener *listener.Listener
tlsConfig tls.ServerConfig
server *derp.Server
configPath string
verifyClientEndpoint []string
verifyClientURL []option.DERPVerifyClientURLOptions
home string
domainResolveOptions *option.DomainResolveOptions
domainResolver *adapter.DNSQueryOptions
meshKey string
meshKeyPath string
meshWith []option.DERPMeshOptions
}
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.DERPServiceOptions) (adapter.Service, error) {
if options.TLS == nil || !options.TLS.Enabled {
return nil, E.New("TLS is required for DERP server")
}
tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS))
if err != nil {
return nil, err
}
var configPath string
if options.ConfigPath != "" {
configPath = filemanager.BasePath(ctx, os.ExpandEnv(options.ConfigPath))
} else if os.Getuid() == 0 {
configPath = "/var/lib/derper/derper.key"
} else {
return nil, E.New("missing config_path")
}
if options.MeshPSK != "" {
err = checkMeshKey(options.MeshPSK)
if err != nil {
return nil, E.Cause(err, "invalid mesh_psk")
}
}
return &Service{
Adapter: boxService.NewAdapter(C.TypeDERP, tag),
ctx: ctx,
logger: logger,
listener: listener.New(listener.Options{
Context: ctx,
Logger: logger,
Network: []string{N.NetworkTCP},
Listen: options.ListenOptions,
}),
tlsConfig: tlsConfig,
configPath: configPath,
verifyClientEndpoint: options.VerifyClientEndpoint,
verifyClientURL: options.VerifyClientURL,
meshKey: options.MeshPSK,
meshKeyPath: options.MeshPSKFile,
meshWith: options.MeshWith,
domainResolveOptions: options.DomainResolver,
}, nil
}
func (d *Service) Start(stage adapter.StartStage) error {
switch stage {
case adapter.StartStateInitialize:
domainResolver, err := adapter.DNSQueryOptionsFrom(d.ctx, d.domainResolveOptions)
if err != nil {
return err
}
d.domainResolver = domainResolver
case adapter.StartStateStart:
config, err := readDERPConfig(d.configPath)
if err != nil {
return err
}
server := derp.NewServer(config.PrivateKey, func(format string, args ...any) {
d.logger.Debug(fmt.Sprintf(format, args...))
})
if len(d.verifyClientURL) > 0 {
var httpClients []*http.Client
var urls []string
for index, options := range d.verifyClientURL {
verifyDialer, createErr := dialer.NewWithOptions(dialer.Options{
Context: d.ctx,
Options: options.DialerOptions,
RemoteIsDomain: options.ServerIsDomain(),
})
if createErr != nil {
return E.Cause(createErr, "verify_client_url[", index, "]")
}
httpClients = append(httpClients, &http.Client{
Transport: &http.Transport{
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return verifyDialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
},
},
})
urls = append(urls, options.URL)
}
server.SetVerifyClientHTTPClient(httpClients)
server.SetVerifyClientURL(urls)
}
if d.meshKey != "" {
server.SetMeshKey(d.meshKey)
} else if d.meshKeyPath != "" {
var meshKeyContent []byte
meshKeyContent, err = os.ReadFile(d.meshKeyPath)
if err != nil {
return err
}
err = checkMeshKey(string(meshKeyContent))
if err != nil {
return E.Cause(err, "invalid mesh_psk_path file")
}
server.SetMeshKey(string(meshKeyContent))
}
d.server = server
derpMux := http.NewServeMux()
derpHandler := derphttp.Handler(server)
derpHandler = addWebSocketSupport(server, derpHandler)
derpMux.Handle("/derp", derpHandler)
homeHandler, ok := getHomeHandler(d.home)
if !ok {
return E.New("invalid home value: ", d.home)
}
derpMux.HandleFunc("/derp/probe", derphttp.ProbeHandler)
derpMux.HandleFunc("/derp/latency-check", derphttp.ProbeHandler)
derpMux.HandleFunc("/bootstrap-dns", tsweb.BrowserHeaderHandlerFunc(handleBootstrapDNS(d.ctx, d.domainResolver)))
derpMux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tsweb.AddBrowserHeaders(w)
homeHandler.ServeHTTP(w, r)
}))
derpMux.Handle("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tsweb.AddBrowserHeaders(w)
io.WriteString(w, "User-agent: *\nDisallow: /\n")
}))
derpMux.Handle("/generate_204", http.HandlerFunc(derphttp.ServeNoContent))
err = d.tlsConfig.Start()
if err != nil {
return err
}
tcpListener, err := d.listener.ListenTCP()
if err != nil {
return err
}
if len(d.tlsConfig.NextProtos()) == 0 {
d.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
} else if !common.Contains(d.tlsConfig.NextProtos(), http2.NextProtoTLS) {
d.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, d.tlsConfig.NextProtos()...))
}
tcpListener = aTLS.NewListener(tcpListener, d.tlsConfig)
httpServer := &http.Server{
Handler: h2c.NewHandler(derpMux, &http2.Server{}),
}
go httpServer.Serve(tcpListener)
case adapter.StartStatePostStart:
if len(d.verifyClientEndpoint) > 0 {
var endpoints []*tailscale.LocalClient
endpointManager := service.FromContext[adapter.EndpointManager](d.ctx)
for _, endpointTag := range d.verifyClientEndpoint {
endpoint, loaded := endpointManager.Get(endpointTag)
if !loaded {
return E.New("verify_client_endpoint: endpoint not found: ", endpointTag)
}
tsEndpoint, isTailscale := endpoint.(*boxScale.Endpoint)
if !isTailscale {
return E.New("verify_client_endpoint: endpoint is not Tailscale: ", endpointTag)
}
localClient, err := tsEndpoint.Server().LocalClient()
if err != nil {
return err
}
endpoints = append(endpoints, localClient)
}
d.server.SetVerifyClientLocalClient(endpoints)
}
if len(d.meshWith) > 0 {
if !d.server.HasMeshKey() {
return E.New("missing mesh psk")
}
for _, options := range d.meshWith {
err := d.startMeshWithHost(d.server, options)
if err != nil {
return err
}
}
}
}
return nil
}
func checkMeshKey(meshKey string) error {
checkRegex, err := regexp.Compile(`^[0-9a-f]{64}$`)
if err != nil {
return err
}
if !checkRegex.MatchString(meshKey) {
return E.New("key must contain exactly 64 hex digits")
}
return nil
}
func (d *Service) startMeshWithHost(derpServer *derp.Server, server option.DERPMeshOptions) error {
meshDialer, err := dialer.NewWithOptions(dialer.Options{
Context: d.ctx,
Options: server.DialerOptions,
RemoteIsDomain: server.ServerIsDomain(),
NewDialer: true,
})
if err != nil {
return err
}
var hostname string
if server.Host != "" {
hostname = server.Host
} else {
hostname = server.Server
}
var stdConfig *tls.STDConfig
if server.TLS != nil && server.TLS.Enabled {
tlsConfig, err := tls.NewClient(d.ctx, hostname, common.PtrValueOrDefault(server.TLS))
if err != nil {
return err
}
stdConfig, err = tlsConfig.Config()
if err != nil {
return err
}
}
logf := func(format string, args ...any) {
d.logger.Debug(F.ToString("mesh(", hostname, "): ", fmt.Sprintf(format, args...)))
}
var meshHost string
if server.ServerPort == 0 || server.ServerPort == 443 {
meshHost = hostname
} else {
meshHost = M.ParseSocksaddrHostPort(hostname, server.ServerPort).String()
}
meshClient, err := derphttp.NewClient(derpServer.PrivateKey(), "https://"+meshHost+"/derp", logf, netmon.NewStatic())
if err != nil {
return err
}
meshClient.TLSConfig = stdConfig
meshClient.MeshKey = derpServer.MeshKey()
meshClient.WatchConnectionChanges = true
meshClient.SetURLDialer(func(ctx context.Context, network, addr string) (net.Conn, error) {
return meshDialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
})
add := func(m derp.PeerPresentMessage) { derpServer.AddPacketForwarder(m.Key, meshClient) }
remove := func(m derp.PeerGoneMessage) { derpServer.RemovePacketForwarder(m.Peer, meshClient) }
go meshClient.RunWatchConnectionLoop(context.Background(), derpServer.PublicKey(), logf, add, remove)
return nil
}
func (d *Service) Close() error {
return common.Close(
common.PtrOrNil(d.listener),
d.tlsConfig,
)
}
var homePage = `
<h1>DERP</h1>
<p>
This is a <a href="https://tailscale.com/">Tailscale</a> DERP server.
</p>
<p>
It provides STUN, interactive connectivity establishment, and relaying of end-to-end encrypted traffic
for Tailscale clients.
</p>
<p>
Documentation:
</p>
<ul>
<li><a href="https://tailscale.com/kb/1232/derp-servers">About DERP</a></li>
<li><a href="https://pkg.go.dev/tailscale.com/derp">Protocol & Go docs</a></li>
<li><a href="https://github.com/tailscale/tailscale/tree/main/cmd/derper#derp">How to run a DERP server</a></li>
</body>
</html>
`
func getHomeHandler(val string) (_ http.Handler, ok bool) {
if val == "" {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(200)
w.Write([]byte(homePage))
}), true
}
if val == "blank" {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(200)
}), true
}
if strings.HasPrefix(val, "http://") || strings.HasPrefix(val, "https://") {
return http.RedirectHandler(val, http.StatusFound), true
}
return nil, false
}
func addWebSocketSupport(s *derp.Server, base http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
up := strings.ToLower(r.Header.Get("Upgrade"))
// Very early versions of Tailscale set "Upgrade: WebSocket" but didn't actually
// speak WebSockets (they still assumed DERP's binary framing). So to distinguish
// clients that actually want WebSockets, look for an explicit "derp" subprotocol.
if up != "websocket" || !strings.Contains(r.Header.Get("Sec-Websocket-Protocol"), "derp") {
base.ServeHTTP(w, r)
return
}
c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
Subprotocols: []string{"derp"},
OriginPatterns: []string{"*"},
// Disable compression because we transmit WireGuard messages that
// are not compressible.
// Additionally, Safari has a broken implementation of compression
// (see https://github.com/nhooyr/websocket/issues/218) that makes
// enabling it actively harmful.
CompressionMode: websocket.CompressionDisabled,
})
if err != nil {
return
}
defer c.Close(websocket.StatusInternalError, "closing")
if c.Subprotocol() != "derp" {
c.Close(websocket.StatusPolicyViolation, "client must speak the derp subprotocol")
return
}
wc := wsconn.NetConn(r.Context(), c, websocket.MessageBinary, r.RemoteAddr)
brw := bufio.NewReadWriter(bufio.NewReader(wc), bufio.NewWriter(wc))
s.Accept(r.Context(), wc, brw, r.RemoteAddr)
})
}
func handleBootstrapDNS(ctx context.Context, queryOptions *adapter.DNSQueryOptions) http.HandlerFunc {
dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Connection", "close")
if queryDomain := r.URL.Query().Get("q"); queryDomain != "" {
addresses, err := dnsRouter.Lookup(ctx, queryDomain, *queryOptions)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
render.JSON(w, r, render.M{
queryDomain: addresses,
})
return
}
w.Write([]byte("{}"))
}
}
type derpConfig struct {
PrivateKey key.NodePrivate
}
func readDERPConfig(path string) (*derpConfig, error) {
content, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return writeNewDERPConfig(path)
}
return nil, err
}
var config derpConfig
err = json.Unmarshal(content, &config)
if err != nil {
return nil, err
}
return &config, nil
}
func writeNewDERPConfig(path string) (*derpConfig, error) {
newKey := key.NewNode()
err := os.MkdirAll(filepath.Dir(path), 0o777)
if err != nil {
return nil, err
}
config := derpConfig{
PrivateKey: newKey,
}
content, err := json.Marshal(config)
if err != nil {
return nil, err
}
err = os.WriteFile(path, content, 0o644)
if err != nil {
return nil, err
}
return &config, nil
}
-89
View File
@@ -1,89 +0,0 @@
package derp
import (
"context"
"net"
"net/netip"
"time"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
"github.com/sagernet/sing-box/common/listener"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/tailscale/net/stun"
)
func RegisterSTUN(registry *boxService.Registry) {
boxService.Register[option.DERPSTUNServiceOptions](registry, C.TypeDERPSTUN, NewSTUNService)
}
type STUNService struct {
boxService.Adapter
ctx context.Context
logger logger.ContextLogger
listener *listener.Listener
}
func NewSTUNService(ctx context.Context, logger log.ContextLogger, tag string, options option.DERPSTUNServiceOptions) (adapter.Service, error) {
return &STUNService{
Adapter: boxService.NewAdapter(C.TypeDERPSTUN, tag),
ctx: ctx,
logger: logger,
listener: listener.New(listener.Options{
Context: ctx,
Logger: logger,
Network: []string{N.NetworkUDP},
Listen: options.ListenOptions,
}),
}, nil
}
func (d *STUNService) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateStart {
return nil
}
packetConn, err := d.listener.ListenUDP()
if err != nil {
return err
}
go d.loopPacket(packetConn.(*net.UDPConn))
return nil
}
func (d *STUNService) Close() error {
return d.listener.Close()
}
func (d *STUNService) loopPacket(packetConn *net.UDPConn) {
buffer := make([]byte, 65535)
oob := make([]byte, 1024)
var (
n int
oobN int
addrPort netip.AddrPort
err error
)
for {
n, oobN, _, addrPort, err = packetConn.ReadMsgUDPAddrPort(buffer, oob)
if err != nil {
if E.IsClosedOrCanceled(err) {
return
}
time.Sleep(time.Second)
continue
}
if !stun.Is(buffer[:n]) {
continue
}
txid, err := stun.ParseBindingRequest(buffer[:n])
if err != nil {
continue
}
packetConn.WriteMsgUDPAddrPort(stun.Response(txid, addrPort), oob[:oobN], addrPort)
}
}
-625
View File
@@ -1,625 +0,0 @@
package resolved
import (
"context"
"errors"
"fmt"
"net/netip"
"os"
"os/user"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/process"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
M "github.com/sagernet/sing/common/metadata"
"github.com/godbus/dbus/v5"
mDNS "github.com/miekg/dns"
)
type resolve1Manager Service
type Address struct {
IfIndex int32
Family int32
Address []byte
}
type Name struct {
IfIndex int32
Hostname string
}
type ResourceRecord struct {
IfIndex int32
Type uint16
Class uint16
Data []byte
}
type SRVRecord struct {
Priority uint16
Weight uint16
Port uint16
Hostname string
Addresses []Address
CNAME string
}
type TXTRecord []byte
type LinkDNS struct {
Family int32
Address []byte
}
type LinkDNSEx struct {
Family int32
Address []byte
Port uint16
Name string
}
type LinkDomain struct {
Domain string
RoutingOnly bool
}
func (t *resolve1Manager) getLink(ifIndex int32) (*TransportLink, *dbus.Error) {
link, loaded := t.links[ifIndex]
if !loaded {
link = &TransportLink{}
t.links[ifIndex] = link
iif, err := t.network.InterfaceFinder().ByIndex(int(ifIndex))
if err != nil {
return nil, wrapError(err)
}
link.iif = iif
}
return link, nil
}
func (t *resolve1Manager) getSenderProcess(sender dbus.Sender) (int32, error) {
var senderPid int32
dbusObject := t.systemBus.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
if dbusObject == nil {
return 0, E.New("missing dbus object")
}
err := dbusObject.Call("org.freedesktop.DBus.GetConnectionUnixProcessID", 0, string(sender)).Store(&senderPid)
if err != nil {
return 0, E.Cause(err, "GetConnectionUnixProcessID")
}
return senderPid, nil
}
func (t *resolve1Manager) createMetadata(sender dbus.Sender) adapter.InboundContext {
var metadata adapter.InboundContext
metadata.Inbound = t.Tag()
metadata.InboundType = C.TypeResolved
senderPid, err := t.getSenderProcess(sender)
if err != nil {
return metadata
}
var processInfo process.Info
metadata.ProcessInfo = &processInfo
processInfo.ProcessID = uint32(senderPid)
processPath, err := os.Readlink(F.ToString("/proc/", senderPid, "/exe"))
if err == nil {
processInfo.ProcessPath = processPath
} else {
processPath, err = os.Readlink(F.ToString("/proc/", senderPid, "/comm"))
if err == nil {
processInfo.ProcessPath = processPath
}
}
var uidFound bool
statusContent, err := os.ReadFile(F.ToString("/proc/", senderPid, "/status"))
if err == nil {
for _, line := range strings.Split(string(statusContent), "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "Uid:") {
fields := strings.Fields(line)
if len(fields) >= 2 {
uid, parseErr := strconv.ParseUint(fields[1], 10, 32)
if parseErr != nil {
break
}
processInfo.UserId = int32(uid)
uidFound = true
if osUser, _ := user.LookupId(F.ToString(uid)); osUser != nil {
processInfo.User = osUser.Username
}
break
}
}
}
}
if !uidFound {
metadata.ProcessInfo.UserId = -1
}
return metadata
}
func (t *resolve1Manager) logRequest(sender dbus.Sender, message ...any) context.Context {
ctx := log.ContextWithNewID(t.ctx)
metadata := t.createMetadata(sender)
if metadata.ProcessInfo != nil {
var prefix string
if metadata.ProcessInfo.ProcessPath != "" {
prefix = filepath.Base(metadata.ProcessInfo.ProcessPath)
} else if metadata.ProcessInfo.User != "" {
prefix = F.ToString("user:", metadata.ProcessInfo.User)
} else if metadata.ProcessInfo.UserId != 0 {
prefix = F.ToString("uid:", metadata.ProcessInfo.UserId)
}
t.logger.InfoContext(ctx, "(", prefix, ") ", F.ToString(message...))
} else {
t.logger.InfoContext(ctx, F.ToString(message...))
}
return adapter.WithContext(ctx, &metadata)
}
func familyToString(family int32) string {
switch family {
case syscall.AF_UNSPEC:
return "AF_UNSPEC"
case syscall.AF_INET:
return "AF_INET"
case syscall.AF_INET6:
return "AF_INET6"
default:
return F.ToString(family)
}
}
func (t *resolve1Manager) ResolveHostname(sender dbus.Sender, ifIndex int32, hostname string, family int32, flags uint64) (addresses []Address, canonical string, outflags uint64, err *dbus.Error) {
t.linkAccess.Lock()
link, err := t.getLink(ifIndex)
if err != nil {
return
}
t.linkAccess.Unlock()
var strategy C.DomainStrategy
switch family {
case syscall.AF_UNSPEC:
strategy = C.DomainStrategyAsIS
case syscall.AF_INET:
strategy = C.DomainStrategyIPv4Only
case syscall.AF_INET6:
strategy = C.DomainStrategyIPv6Only
}
ctx := t.logRequest(sender, "ResolveHostname ", link.iif.Name, " ", hostname, " ", familyToString(family), " ", flags)
responseAddresses, lookupErr := t.dnsRouter.Lookup(ctx, hostname, adapter.DNSQueryOptions{
LookupStrategy: strategy,
})
if lookupErr != nil {
err = wrapError(err)
return
}
addresses = common.Map(responseAddresses, func(it netip.Addr) Address {
var addrFamily int32
if it.Is4() {
addrFamily = syscall.AF_INET
} else {
addrFamily = syscall.AF_INET6
}
return Address{
IfIndex: ifIndex,
Family: addrFamily,
Address: it.AsSlice(),
}
})
canonical = mDNS.CanonicalName(hostname)
return
}
func (t *resolve1Manager) ResolveAddress(sender dbus.Sender, ifIndex int32, family int32, address []byte, flags uint64) (names []Name, outflags uint64, err *dbus.Error) {
t.linkAccess.Lock()
link, err := t.getLink(ifIndex)
if err != nil {
return
}
t.linkAccess.Unlock()
addr, ok := netip.AddrFromSlice(address)
if !ok {
err = wrapError(E.New("invalid address"))
return
}
var nibbles []string
for i := len(address) - 1; i >= 0; i-- {
b := address[i]
nibbles = append(nibbles, fmt.Sprintf("%x", b&0x0F))
nibbles = append(nibbles, fmt.Sprintf("%x", b>>4))
}
var ptrDomain string
if addr.Is4() {
ptrDomain = strings.Join(nibbles, ".") + ".in-addr.arpa."
} else {
ptrDomain = strings.Join(nibbles, ".") + ".ip6.arpa."
}
request := &mDNS.Msg{
MsgHdr: mDNS.MsgHdr{
RecursionDesired: true,
},
Question: []mDNS.Question{
{
Name: mDNS.Fqdn(ptrDomain),
Qtype: mDNS.TypePTR,
Qclass: mDNS.ClassINET,
},
},
}
ctx := t.logRequest(sender, "ResolveAddress ", link.iif.Name, familyToString(family), addr, flags)
response, lookupErr := t.dnsRouter.Exchange(ctx, request, adapter.DNSQueryOptions{})
if lookupErr != nil {
err = wrapError(err)
return
}
if response.Rcode != mDNS.RcodeSuccess {
err = rcodeError(response.Rcode)
return
}
for _, rawRR := range response.Answer {
switch rr := rawRR.(type) {
case *mDNS.PTR:
names = append(names, Name{
IfIndex: ifIndex,
Hostname: rr.Ptr,
})
}
}
return
}
func (t *resolve1Manager) ResolveRecord(sender dbus.Sender, ifIndex int32, family int32, hostname string, qClass uint16, qType uint16, flags uint64) (records []ResourceRecord, outflags uint64, err *dbus.Error) {
t.linkAccess.Lock()
link, err := t.getLink(ifIndex)
if err != nil {
return
}
t.linkAccess.Unlock()
request := &mDNS.Msg{
MsgHdr: mDNS.MsgHdr{
RecursionDesired: true,
},
Question: []mDNS.Question{
{
Name: mDNS.Fqdn(hostname),
Qtype: qType,
Qclass: qClass,
},
},
}
ctx := t.logRequest(sender, "ResolveRecord ", link.iif.Name, familyToString(family), hostname, mDNS.Class(qClass), mDNS.Type(qType), flags)
response, exchangeErr := t.dnsRouter.Exchange(ctx, request, adapter.DNSQueryOptions{})
if exchangeErr != nil {
err = wrapError(exchangeErr)
return
}
if response.Rcode != mDNS.RcodeSuccess {
err = rcodeError(response.Rcode)
return
}
for _, rr := range response.Answer {
var record ResourceRecord
record.IfIndex = ifIndex
record.Type = rr.Header().Rrtype
record.Class = rr.Header().Class
data := make([]byte, mDNS.Len(rr))
_, unpackErr := mDNS.PackRR(rr, data, 0, nil, false)
if unpackErr != nil {
err = wrapError(unpackErr)
}
record.Data = data
}
return
}
func (t *resolve1Manager) ResolveService(sender dbus.Sender, ifIndex int32, hostname string, sType string, domain string, family int32, flags uint64) (srvData []SRVRecord, txtData []TXTRecord, canonicalName string, canonicalType string, canonicalDomain string, outflags uint64, err *dbus.Error) {
t.linkAccess.Lock()
link, err := t.getLink(ifIndex)
if err != nil {
return
}
t.linkAccess.Unlock()
serviceName := hostname
if hostname != "" && !strings.HasSuffix(hostname, ".") {
serviceName += "."
}
serviceName += sType
if !strings.HasSuffix(serviceName, ".") {
serviceName += "."
}
serviceName += domain
if !strings.HasSuffix(serviceName, ".") {
serviceName += "."
}
ctx := t.logRequest(sender, "ResolveService ", link.iif.Name, " ", hostname, " ", sType, " ", domain, " ", familyToString(family), " ", flags)
srvRequest := &mDNS.Msg{
MsgHdr: mDNS.MsgHdr{
RecursionDesired: true,
},
Question: []mDNS.Question{
{
Name: serviceName,
Qtype: mDNS.TypeSRV,
Qclass: mDNS.ClassINET,
},
},
}
srvResponse, exchangeErr := t.dnsRouter.Exchange(ctx, srvRequest, adapter.DNSQueryOptions{})
if exchangeErr != nil {
err = wrapError(exchangeErr)
return
}
if srvResponse.Rcode != mDNS.RcodeSuccess {
err = rcodeError(srvResponse.Rcode)
return
}
txtRequest := &mDNS.Msg{
MsgHdr: mDNS.MsgHdr{
RecursionDesired: true,
},
Question: []mDNS.Question{
{
Name: serviceName,
Qtype: mDNS.TypeTXT,
Qclass: mDNS.ClassINET,
},
},
}
txtResponse, exchangeErr := t.dnsRouter.Exchange(ctx, txtRequest, adapter.DNSQueryOptions{})
if exchangeErr != nil {
err = wrapError(exchangeErr)
return
}
for _, rawRR := range srvResponse.Answer {
switch rr := rawRR.(type) {
case *mDNS.SRV:
var srvRecord SRVRecord
srvRecord.Priority = rr.Priority
srvRecord.Weight = rr.Weight
srvRecord.Port = rr.Port
srvRecord.Hostname = rr.Target
var strategy C.DomainStrategy
switch family {
case syscall.AF_UNSPEC:
strategy = C.DomainStrategyAsIS
case syscall.AF_INET:
strategy = C.DomainStrategyIPv4Only
case syscall.AF_INET6:
strategy = C.DomainStrategyIPv6Only
}
addrs, lookupErr := t.dnsRouter.Lookup(ctx, rr.Target, adapter.DNSQueryOptions{
LookupStrategy: strategy,
})
if lookupErr == nil {
srvRecord.Addresses = common.Map(addrs, func(it netip.Addr) Address {
var addrFamily int32
if it.Is4() {
addrFamily = syscall.AF_INET
} else {
addrFamily = syscall.AF_INET6
}
return Address{
IfIndex: ifIndex,
Family: addrFamily,
Address: it.AsSlice(),
}
})
}
for _, a := range srvResponse.Answer {
if cname, ok := a.(*mDNS.CNAME); ok && cname.Header().Name == rr.Target {
srvRecord.CNAME = cname.Target
break
}
}
srvData = append(srvData, srvRecord)
}
}
for _, rawRR := range txtResponse.Answer {
switch rr := rawRR.(type) {
case *mDNS.TXT:
data := make([]byte, mDNS.Len(rr))
_, packErr := mDNS.PackRR(rr, data, 0, nil, false)
if packErr == nil {
txtData = append(txtData, data)
}
}
}
canonicalName = mDNS.CanonicalName(hostname)
canonicalType = mDNS.CanonicalName(sType)
canonicalDomain = mDNS.CanonicalName(domain)
return
}
func (t *resolve1Manager) SetLinkDNS(sender dbus.Sender, ifIndex int32, addresses []LinkDNS) *dbus.Error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
link, err := t.getLink(ifIndex)
if err != nil {
return wrapError(err)
}
link.address = addresses
if len(addresses) > 0 {
t.logRequest(sender, "SetLinkDNS ", link.iif.Name, " ", strings.Join(common.Map(addresses, func(it LinkDNS) string {
return M.AddrFromIP(it.Address).String()
}), ", "))
} else {
t.logRequest(sender, "SetLinkDNS ", link.iif.Name, " (empty)")
}
return t.postUpdate(link)
}
func (t *resolve1Manager) SetLinkDNSEx(sender dbus.Sender, ifIndex int32, addresses []LinkDNSEx) *dbus.Error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
link, err := t.getLink(ifIndex)
if err != nil {
return wrapError(err)
}
link.addressEx = addresses
if len(addresses) > 0 {
t.logRequest(sender, "SetLinkDNSEx ", link.iif.Name, " ", strings.Join(common.Map(addresses, func(it LinkDNSEx) string {
return M.SocksaddrFrom(M.AddrFromIP(it.Address), it.Port).String()
}), ", "))
} else {
t.logRequest(sender, "SetLinkDNSEx ", link.iif.Name, " (empty)")
}
return t.postUpdate(link)
}
func (t *resolve1Manager) SetLinkDomains(sender dbus.Sender, ifIndex int32, domains []LinkDomain) *dbus.Error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
link, err := t.getLink(ifIndex)
if err != nil {
return wrapError(err)
}
link.domain = domains
if len(domains) > 0 {
t.logRequest(sender, "SetLinkDomains ", link.iif.Name, " ", strings.Join(common.Map(domains, func(domain LinkDomain) string {
if !domain.RoutingOnly {
return domain.Domain
} else {
return "~" + domain.Domain
}
}), ", "))
} else {
t.logRequest(sender, "SetLinkDomains ", link.iif.Name, " (empty)")
}
return t.postUpdate(link)
}
func (t *resolve1Manager) SetLinkDefaultRoute(sender dbus.Sender, ifIndex int32, defaultRoute bool) *dbus.Error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
link, err := t.getLink(ifIndex)
if err != nil {
return err
}
link.defaultRoute = defaultRoute
t.defaultRouteSequence = append(t.defaultRouteSequence, ifIndex)
var defaultRouteString string
if defaultRoute {
defaultRouteString = "yes"
} else {
defaultRouteString = "no"
}
t.logRequest(sender, "SetLinkDefaultRoute ", link.iif.Name, " ", defaultRouteString)
return t.postUpdate(link)
}
func (t *resolve1Manager) SetLinkLLMNR(ifIndex int32, llmnrMode string) *dbus.Error {
return nil
}
func (t *resolve1Manager) SetLinkMulticastDNS(ifIndex int32, mdnsMode string) *dbus.Error {
return nil
}
func (t *resolve1Manager) SetLinkDNSOverTLS(sender dbus.Sender, ifIndex int32, dotMode string) *dbus.Error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
link, err := t.getLink(ifIndex)
if err != nil {
return wrapError(err)
}
switch dotMode {
case "yes":
link.dnsOverTLS = true
case "":
dotMode = "no"
fallthrough
case "opportunistic", "no":
link.dnsOverTLS = false
}
t.logRequest(sender, "SetLinkDNSOverTLS ", link.iif.Name, " ", dotMode)
return t.postUpdate(link)
}
func (t *resolve1Manager) SetLinkDNSSEC(ifIndex int32, dnssecMode string) *dbus.Error {
return nil
}
func (t *resolve1Manager) SetLinkDNSSECNegativeTrustAnchors(ifIndex int32, domains []string) *dbus.Error {
return nil
}
func (t *resolve1Manager) RevertLink(sender dbus.Sender, ifIndex int32) *dbus.Error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
link, err := t.getLink(ifIndex)
if err != nil {
return wrapError(err)
}
delete(t.links, ifIndex)
t.logRequest(sender, "RevertLink ", link.iif.Name)
return t.postUpdate(link)
}
// TODO: implement RegisterService, UnregisterService
func (t *resolve1Manager) RegisterService(sender dbus.Sender, identifier string, nameTemplate string, serviceType string, port uint16, priority uint16, weight uint16, txtRecords []TXTRecord) (objectPath dbus.ObjectPath, dbusErr *dbus.Error) {
return "", wrapError(E.New("not implemented"))
}
func (t *resolve1Manager) UnregisterService(sender dbus.Sender, servicePath dbus.ObjectPath) error {
return wrapError(E.New("not implemented"))
}
func (t *resolve1Manager) ResetStatistics() *dbus.Error {
return nil
}
func (t *resolve1Manager) FlushCaches(sender dbus.Sender) *dbus.Error {
t.dnsRouter.ClearCache()
t.logRequest(sender, "FlushCaches")
return nil
}
func (t *resolve1Manager) ResetServerFeatures() *dbus.Error {
return nil
}
func (t *resolve1Manager) postUpdate(link *TransportLink) *dbus.Error {
if t.updateCallback != nil {
return wrapError(t.updateCallback(link))
}
return nil
}
func rcodeError(rcode int) *dbus.Error {
return dbus.NewError("org.freedesktop.resolve1.DnsError."+mDNS.RcodeToString[rcode], []any{mDNS.RcodeToString[rcode]})
}
func wrapError(err error) *dbus.Error {
if err == nil {
return nil
}
var rcode dns.RcodeError
if errors.As(err, &rcode) {
return rcodeError(int(rcode))
}
return dbus.MakeFailedError(err)
}
-247
View File
@@ -1,247 +0,0 @@
package resolved
import (
"context"
"net"
"strings"
"sync"
"time"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
"github.com/sagernet/sing-box/common/listener"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
dnsOutbound "github.com/sagernet/sing-box/protocol/dns"
tun "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/x/list"
"github.com/sagernet/sing/service"
"github.com/godbus/dbus/v5"
mDNS "github.com/miekg/dns"
)
func RegisterService(registry *boxService.Registry) {
boxService.Register[option.ResolvedServiceOptions](registry, C.TypeResolved, NewService)
}
type Service struct {
boxService.Adapter
ctx context.Context
logger log.ContextLogger
network adapter.NetworkManager
dnsRouter adapter.DNSRouter
listener *listener.Listener
systemBus *dbus.Conn
linkAccess sync.Mutex
links map[int32]*TransportLink
defaultRouteSequence []int32
networkUpdateCallback *list.Element[tun.NetworkUpdateCallback]
updateCallback func(*TransportLink) error
deleteCallback func(*TransportLink)
}
type TransportLink struct {
iif *control.Interface
address []LinkDNS
addressEx []LinkDNSEx
domain []LinkDomain
defaultRoute bool
dnsOverTLS bool
//dnsOverTLSFallback bool
}
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.ResolvedServiceOptions) (adapter.Service, error) {
inbound := &Service{
Adapter: boxService.NewAdapter(C.TypeResolved, tag),
ctx: ctx,
logger: logger,
network: service.FromContext[adapter.NetworkManager](ctx),
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
links: make(map[int32]*TransportLink),
}
inbound.listener = listener.New(listener.Options{
Context: ctx,
Logger: logger,
Network: []string{N.NetworkTCP, N.NetworkUDP},
Listen: options.ListenOptions,
ConnectionHandler: inbound,
OOBPacketHandler: inbound,
ThreadUnsafePacketWriter: true,
})
return inbound, nil
}
func (i *Service) Start(stage adapter.StartStage) error {
switch stage {
case adapter.StartStateInitialize:
inboundManager := service.FromContext[adapter.ServiceManager](i.ctx)
for _, transport := range inboundManager.Services() {
if transport.Type() == C.TypeResolved && transport != i {
return E.New("multiple resolved service are not supported")
}
}
case adapter.StartStateStart:
err := i.listener.Start()
if err != nil {
return err
}
systemBus, err := dbus.SystemBus()
if err != nil {
return err
}
i.systemBus = systemBus
reply, err := systemBus.RequestName("org.freedesktop.resolve1", dbus.NameFlagDoNotQueue)
if err != nil {
return err
}
switch reply {
case dbus.RequestNameReplyPrimaryOwner:
case dbus.RequestNameReplyExists:
return E.New("D-Bus object already exists, maybe real resolved is running")
default:
return E.New("unknown request name reply: ", reply)
}
err = systemBus.Export((*resolve1Manager)(i), "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager")
if err != nil {
return err
}
i.networkUpdateCallback = i.network.NetworkMonitor().RegisterCallback(i.onNetworkUpdate)
}
return nil
}
func (i *Service) Close() error {
if i.networkUpdateCallback != nil {
i.network.NetworkMonitor().UnregisterCallback(i.networkUpdateCallback)
}
if i.systemBus != nil {
i.systemBus.ReleaseName("org.freedesktop.resolve1")
i.systemBus.Close()
}
return i.listener.Close()
}
func (i *Service) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
metadata.Inbound = i.Tag()
metadata.InboundType = i.Type()
metadata.Destination = M.Socksaddr{}
for {
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
err := dnsOutbound.HandleStreamDNSRequest(ctx, i.dnsRouter, conn, metadata)
if err != nil {
N.CloseOnHandshakeFailure(conn, onClose, err)
return
}
}
}
func (i *Service) NewPacketEx(buffer *buf.Buffer, oob []byte, source M.Socksaddr) {
go i.exchangePacket(buffer, oob, source)
}
func (i *Service) exchangePacket(buffer *buf.Buffer, oob []byte, source M.Socksaddr) {
ctx := log.ContextWithNewID(i.ctx)
err := i.exchangePacket0(ctx, buffer, oob, source)
if err != nil {
i.logger.ErrorContext(ctx, "process DNS packet: ", err)
}
}
func (i *Service) exchangePacket0(ctx context.Context, buffer *buf.Buffer, oob []byte, source M.Socksaddr) error {
var message mDNS.Msg
err := message.Unpack(buffer.Bytes())
buffer.Release()
if err != nil {
return E.Cause(err, "unpack request")
}
var metadata adapter.InboundContext
metadata.Source = source
response, err := i.dnsRouter.Exchange(adapter.WithContext(ctx, &metadata), &message, adapter.DNSQueryOptions{})
if err != nil {
return err
}
responseBuffer, err := dns.TruncateDNSMessage(&message, response, 0)
if err != nil {
return err
}
defer responseBuffer.Release()
_, _, err = i.listener.UDPConn().WriteMsgUDPAddrPort(responseBuffer.Bytes(), oob, source.AddrPort())
return err
}
func (i *Service) onNetworkUpdate() {
i.linkAccess.Lock()
defer i.linkAccess.Unlock()
var deleteIfIndex []int
for ifIndex, link := range i.links {
iif, err := i.network.InterfaceFinder().ByIndex(int(ifIndex))
if err != nil || iif != link.iif {
deleteIfIndex = append(deleteIfIndex, int(ifIndex))
}
if i.deleteCallback != nil {
i.deleteCallback(link)
}
}
for _, ifIndex := range deleteIfIndex {
delete(i.links, int32(ifIndex))
}
}
func (conf *TransportLink) nameList(ndots int, name string) []string {
search := common.Map(common.Filter(conf.domain, func(it LinkDomain) bool {
return !it.RoutingOnly
}), func(it LinkDomain) string {
return it.Domain
})
l := len(name)
rooted := l > 0 && name[l-1] == '.'
if l > 254 || l == 254 && !rooted {
return nil
}
if rooted {
if avoidDNS(name) {
return nil
}
return []string{name}
}
hasNdots := strings.Count(name, ".") >= ndots
name += "."
// l++
names := make([]string, 0, 1+len(search))
if hasNdots && !avoidDNS(name) {
names = append(names, name)
}
for _, suffix := range search {
fqdn := name + suffix
if !avoidDNS(fqdn) && len(fqdn) <= 254 {
names = append(names, fqdn)
}
}
if !hasNdots && !avoidDNS(name) {
names = append(names, name)
}
return names
}
func avoidDNS(name string) bool {
if name == "" {
return true
}
if name[len(name)-1] == '.' {
name = name[:len(name)-1]
}
return strings.HasSuffix(name, ".onion")
}
-278
View File
@@ -1,278 +0,0 @@
package resolved
import (
"context"
"net/netip"
"os"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/tls"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/dns/transport"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/service"
mDNS "github.com/miekg/dns"
)
func RegisterTransport(registry *dns.TransportRegistry) {
dns.RegisterTransport[option.SplitDNSServerOptions](registry, C.TypeResolved, NewTransport)
}
var _ adapter.DNSTransport = (*Transport)(nil)
type Transport struct {
dns.TransportAdapter
ctx context.Context
logger logger.ContextLogger
serviceTag string
acceptDefaultResolvers bool
ndots int
timeout time.Duration
attempts int
rotate bool
service *Service
linkAccess sync.RWMutex
linkServers map[*TransportLink]*LinkServers
}
type LinkServers struct {
Link *TransportLink
Servers []adapter.DNSTransport
serverOffset uint32
}
func (c *LinkServers) ServerOffset(rotate bool) uint32 {
if rotate {
return atomic.AddUint32(&c.serverOffset, 1) - 1
}
return 0
}
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.SplitDNSServerOptions) (adapter.DNSTransport, error) {
if !C.IsLinux {
return nil, E.New("split DNS server is only supported on Linux")
}
return &Transport{
TransportAdapter: dns.NewTransportAdapter(C.DNSTypeDHCP, tag, nil),
ctx: ctx,
logger: logger,
serviceTag: options.Service,
acceptDefaultResolvers: options.AcceptDefaultResolvers,
// ndots: options.NDots,
// timeout: time.Duration(options.Timeout),
// attempts: options.Attempts,
// rotate: options.Rotate,
ndots: 1,
timeout: 5 * time.Second,
attempts: 2,
linkServers: make(map[*TransportLink]*LinkServers),
}, nil
}
func (t *Transport) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateInitialize {
return nil
}
serviceManager := service.FromContext[adapter.ServiceManager](t.ctx)
service, loaded := serviceManager.Get(t.serviceTag)
if !loaded {
return E.New("service not found: ", t.serviceTag)
}
resolvedInbound, isResolved := service.(*Service)
if !isResolved {
return E.New("service is not resolved: ", t.serviceTag)
}
resolvedInbound.updateCallback = t.updateTransports
t.service = resolvedInbound
return nil
}
func (t *Transport) Close() error {
t.linkAccess.RLock()
defer t.linkAccess.RUnlock()
for _, servers := range t.linkServers {
for _, server := range servers.Servers {
server.Close()
}
}
return nil
}
func (t *Transport) updateTransports(link *TransportLink) error {
t.linkAccess.Lock()
defer t.linkAccess.Unlock()
if servers, loaded := t.linkServers[link]; loaded {
for _, server := range servers.Servers {
server.Close()
}
}
serverDialer := common.Must1(dialer.NewDefault(t.ctx, option.DialerOptions{
BindInterface: link.iif.Name,
UDPFragmentDefault: true,
}))
var transports []adapter.DNSTransport
for _, address := range link.address {
serverAddr, ok := netip.AddrFromSlice(address.Address)
if !ok {
return os.ErrInvalid
}
if link.dnsOverTLS {
tlsConfig := common.Must1(tls.NewClient(t.ctx, serverAddr.String(), option.OutboundTLSOptions{
Enabled: true,
ServerName: serverAddr.String(),
}))
transports = append(transports, transport.NewTLSRaw(t.logger, t.TransportAdapter, serverDialer, M.SocksaddrFrom(serverAddr, 53), tlsConfig))
} else {
transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, M.SocksaddrFrom(serverAddr, 53)))
}
}
for _, address := range link.addressEx {
serverAddr, ok := netip.AddrFromSlice(address.Address)
if !ok {
return os.ErrInvalid
}
if link.dnsOverTLS {
var serverName string
if address.Name != "" {
serverName = address.Name
} else {
serverName = serverAddr.String()
}
tlsConfig := common.Must1(tls.NewClient(t.ctx, serverAddr.String(), option.OutboundTLSOptions{
Enabled: true,
ServerName: serverName,
}))
transports = append(transports, transport.NewTLSRaw(t.logger, t.TransportAdapter, serverDialer, M.SocksaddrFrom(serverAddr, address.Port), tlsConfig))
} else {
transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, M.SocksaddrFrom(serverAddr, address.Port)))
}
}
t.linkServers[link] = &LinkServers{
Link: link,
Servers: transports,
}
return nil
}
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
question := message.Question[0]
var selectedLink *TransportLink
for _, link := range t.service.links {
for _, domain := range link.domain {
if strings.HasSuffix(question.Name, domain.Domain) {
selectedLink = link
}
}
}
if selectedLink == nil && t.acceptDefaultResolvers {
for _, link := range t.service.links {
if link.defaultRoute {
selectedLink = link
}
}
}
if selectedLink == nil {
t.logger.DebugContext(ctx, "missing selected interface")
return dns.FixedResponseStatus(message, mDNS.RcodeNameError), nil
}
servers := t.linkServers[selectedLink]
if len(servers.Servers) == 0 {
t.logger.DebugContext(ctx, "missing DNS servers")
return dns.FixedResponseStatus(message, mDNS.RcodeNameError), nil
}
if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
return t.exchangeParallel(ctx, servers, message)
} else {
return t.exchangeSingleRequest(ctx, servers, message)
}
}
func (t *Transport) exchangeSingleRequest(ctx context.Context, servers *LinkServers, message *mDNS.Msg) (*mDNS.Msg, error) {
var lastErr error
for _, fqdn := range servers.Link.nameList(t.ndots, message.Question[0].Name) {
response, err := t.tryOneName(ctx, servers, message, fqdn)
if err != nil {
lastErr = err
continue
}
return response, nil
}
return nil, lastErr
}
func (t *Transport) tryOneName(ctx context.Context, servers *LinkServers, message *mDNS.Msg, fqdn string) (*mDNS.Msg, error) {
serverOffset := servers.ServerOffset(t.rotate)
sLen := uint32(len(servers.Servers))
var lastErr error
for i := 0; i < t.attempts; i++ {
for j := uint32(0); j < sLen; j++ {
server := servers.Servers[(serverOffset+j)%sLen]
question := message.Question[0]
question.Name = fqdn
exchangeMessage := *message
exchangeMessage.Question = []mDNS.Question{question}
exchangeCtx, cancel := context.WithTimeout(ctx, t.timeout)
response, err := server.Exchange(exchangeCtx, &exchangeMessage)
cancel()
if err != nil {
lastErr = err
continue
}
return response, nil
}
}
return nil, E.Cause(lastErr, fqdn)
}
func (t *Transport) exchangeParallel(ctx context.Context, servers *LinkServers, message *mDNS.Msg) (*mDNS.Msg, error) {
returned := make(chan struct{})
defer close(returned)
type queryResult struct {
response *mDNS.Msg
err error
}
results := make(chan queryResult)
startRacer := func(ctx context.Context, fqdn string) {
response, err := t.tryOneName(ctx, servers, message, fqdn)
select {
case results <- queryResult{response, err}:
case <-returned:
}
}
queryCtx, queryCancel := context.WithCancel(ctx)
defer queryCancel()
var nameCount int
for _, fqdn := range servers.Link.nameList(t.ndots, message.Question[0].Name) {
nameCount++
go startRacer(queryCtx, fqdn)
}
var errors []error
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
case result := <-results:
if result.err == nil {
return result.response, nil
}
errors = append(errors, result.err)
if len(errors) == nameCount {
return nil, E.Errors(errors...)
}
}
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ func TestMain(m *testing.M) {
var globalCtx context.Context
func init() {
globalCtx = box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), include.DNSTransportRegistry(), include.ServiceRegistry())
globalCtx = box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry(), include.DNSTransportRegistry())
}
func startInstance(t *testing.T, options option.Options) *box.Box {
@@ -564,6 +564,9 @@ function gen_config(var)
local local_http_password = var["-local_http_password"]
local dns_listen_port = var["-dns_listen_port"]
local dns_cache = var["-dns_cache"]
local direct_dns_port = var["-direct_dns_port"]
local direct_dns_udp_server = var["-direct_dns_udp_server"]
local direct_dns_tcp_server = var["-direct_dns_tcp_server"]
local direct_dns_query_strategy = var["-direct_dns_query_strategy"]
local remote_dns_tcp_server = var["-remote_dns_tcp_server"]
local remote_dns_tcp_port = var["-remote_dns_tcp_port"]
@@ -578,6 +581,7 @@ function gen_config(var)
local dns_socks_port = var["-dns_socks_port"]
local loglevel = var["-loglevel"] or "warning"
local dns_domain_rules = {}
local dns = nil
local fakedns = nil
local routing = nil
@@ -1034,11 +1038,21 @@ function gen_config(var)
end
local domains = nil
if e.domain_list then
local domain_table = {
shunt_rule_name = e[".name"],
outboundTag = outbound_tag,
balancerTag = balancer_tag,
domain = {},
}
domains = {}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
table.insert(domains, w)
table.insert(domain_table.domain, w)
end)
if outbound_tag or balancer_tag then
table.insert(dns_domain_rules, api.clone(domain_table))
end
if #domains == 0 then domains = nil end
end
local ip = nil
@@ -1154,7 +1168,7 @@ function gen_config(var)
end
dns = {
tag = "dns-in1",
tag = "dns-global",
hosts = {},
disableCache = (dns_cache and dns_cache == "0") and true or false,
disableFallback = true,
@@ -1164,8 +1178,39 @@ function gen_config(var)
queryStrategy = "UseIP"
}
local _direct_dns = {
tag = "dns-global-direct",
queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP"
}
if direct_dns_udp_server or direct_dns_tcp_server then
local domain = {}
local nodes_domain_text = sys.exec('uci show passwall | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u')
string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w)
table.insert(domain, w)
end)
if #domain > 0 then
table.insert(dns_domain_rules, 1, {
shunt_rule_name = "logic-vpslist",
outboundTag = "direct",
domain = domain
})
end
if direct_dns_udp_server then
local port = tonumber(direct_dns_port) or 53
_direct_dns.port = port
_direct_dns.address = direct_dns_udp_server
elseif direct_dns_tcp_server then
local port = tonumber(direct_dns_port) or 53
_direct_dns.address = "tcp://" .. direct_dns_tcp_server .. ":" .. port
end
table.insert(dns.servers, _direct_dns)
end
local _remote_dns = {
_flag = "remote",
--tag = "dns-global-remote",
queryStrategy = (remote_dns_query_strategy and remote_dns_query_strategy ~= "") and remote_dns_query_strategy or "UseIPv4",
address = "tcp://" .. remote_dns_tcp_server .. ":" .. tonumber(remote_dns_tcp_port) or 53
}
@@ -1182,6 +1227,11 @@ function gen_config(var)
table.insert(dns.servers, _remote_dns)
local _remote_fakedns = {
--tag = "dns-global-remote-fakedns",
address = "fakedns",
}
if remote_dns_fake then
fakedns = {}
local fakedns4 = {
@@ -1200,41 +1250,9 @@ function gen_config(var)
elseif remote_dns_query_strategy == "UseIPv6" then
table.insert(fakedns, fakedns6)
end
local _remote_fakedns = {
_flag = "remote_fakedns",
address = "fakedns",
}
table.insert(dns.servers, 1, _remote_fakedns)
end
--[[
local default_dns_flag = "remote"
if (not COMMON.default_balancer_tag and not COMMON.default_outbound_tag) or COMMON.default_outbound_tag == "direct" then
default_dns_flag = "direct"
end
if dns.servers and #dns.servers > 0 then
local dns_servers = nil
for index, value in ipairs(dns.servers) do
if not dns_servers and value["_flag"] == default_dns_flag then
if value["_flag"] == "remote" and remote_dns_fake then
value["_flag"] = "default"
break
end
dns_servers = {
_flag = "default",
address = value.address,
port = value.port,
queryStrategy = value.queryStrategy
}
break
end
end
if dns_servers then
table.insert(dns.servers, 1, dns_servers)
end
end
]]--
local dns_outbound_tag = "direct"
if dns_socks_address and dns_socks_port then
dns_outbound_tag = "out"
@@ -1299,43 +1317,56 @@ function gen_config(var)
outboundTag = "dns-out"
})
end
table.insert(rules, {
if direct_dns_udp_server or direct_dns_tcp_server then
table.insert(routing.rules, {
inboundTag = {
"dns-global-direct"
},
outboundTag = "direct"
})
end
--按分流顺序DNS
if dns_domain_rules and #dns_domain_rules > 0 then
for index, value in ipairs(dns_domain_rules) do
if value.domain and (value.outboundTag or value.balancerTag) then
local dns_server = nil
if value.outboundTag == "direct" and _direct_dns.address then
dns_server = api.clone(_direct_dns)
else
if remote_dns_fake then
dns_server = api.clone(_remote_fakedns)
else
dns_server = api.clone(_remote_dns)
end
end
dns_server.domains = value.domain
if value.shunt_rule_name then
dns_server.tag = "dns-in-" .. value.shunt_rule_name
end
if dns_server then
table.insert(dns.servers, dns_server)
table.insert(routing.rules, {
inboundTag = {
dns_server.tag
},
outboundTag = value.outboundTag or nil,
balancerTag = value.balancerTag or nil
})
end
end
end
end
table.insert(routing.rules, {
inboundTag = {
"dns-in1"
"dns-global"
},
ip = {
remote_dns_tcp_server
},
port = tonumber(remote_dns_tcp_port),
balancerTag = COMMON.default_balancer_tag,
outboundTag = dns_outbound_tag
})
if _remote_dns_host then
table.insert(rules, {
inboundTag = {
"dns-in1"
},
domain = {
_remote_dns_host
},
port = tonumber(remote_dns_doh_port),
balancerTag = COMMON.default_balancer_tag,
outboundTag = dns_outbound_tag
})
end
if remote_dns_doh_ip then
table.insert(rules, {
inboundTag = {
"dns-in1"
},
ip = {
remote_dns_doh_ip
},
port = tonumber(remote_dns_doh_port),
balancerTag = COMMON.default_balancer_tag,
outboundTag = dns_outbound_tag
})
end
local default_rule_index = #routing.rules > 0 and #routing.rules or 1
for index, value in ipairs(routing.rules) do
@@ -202,7 +202,7 @@ geosite:category-games'
config shunt_rules 'AIGC'
option remarks 'AIGC'
option domain_list 'geosite:category-ai-!cn
domain:apple-relay.apple.com'
geosite:apple-intelligence'
config shunt_rules 'Streaming'
option remarks 'Streaming'

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