diff --git a/go.mod b/go.mod index 0282ca5..b7c7377 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( ) require ( - github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/klauspost/cpuid/v2 v2.4.0 // indirect github.com/klauspost/reedsolomon v1.14.1 // indirect github.com/pierrec/lz4/v4 v4.1.27 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 2368d52..759fad6 100644 --- a/go.sum +++ b/go.sum @@ -29,8 +29,8 @@ github.com/insomniacslk/dhcp v0.0.0-20260603135910-a415979eb11e h1:7j1+lOuGBg7PQ github.com/insomniacslk/dhcp v0.0.0-20260603135910-a415979eb11e/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw= +github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU= github.com/klauspost/reedsolomon v1.14.1 h1:swE9kzyWXD/wVG+l5Pe8bWnQ0giIY7D1GjCBKk3kG2U= github.com/klauspost/reedsolomon v1.14.1/go.mod h1:yjqqjgMTQkBUHSG97/rm4zipffCNbCiZcB3kTqr++sQ= github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= diff --git a/proxy/dialer.go b/proxy/dialer.go index 83553e3..b2e468a 100644 --- a/proxy/dialer.go +++ b/proxy/dialer.go @@ -3,7 +3,7 @@ package proxy import ( "errors" "net" - "sort" + "slices" "strings" ) @@ -59,7 +59,7 @@ func DialerFromURL(s string, dialer Dialer) (Dialer, error) { s = s + "://" } - scheme := s[:strings.Index(s, ":")] + scheme, _, _ := strings.Cut(s, ":") c, ok := dialerCreators[strings.ToLower(scheme)] if ok { return c(s, dialer) @@ -74,6 +74,6 @@ func DialerSchemes() string { for name := range dialerCreators { s = append(s, name) } - sort.Strings(s) + slices.Sort(s) return strings.Join(s, " ") } diff --git a/proxy/http/http.go b/proxy/http/http.go index aad08fe..565e91d 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -60,13 +60,15 @@ func NewHTTP(s string, d proxy.Dialer, p proxy.Proxy) (*HTTP, error) { // parseStartLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts. func parseStartLine(line string) (r1, r2, r3 string, ok bool) { - s1 := strings.Index(line, " ") - s2 := strings.Index(line[s1+1:], " ") - if s1 < 0 || s2 < 0 { + r1, rest, ok := strings.Cut(line, " ") + if !ok { return } - s2 += s1 + 1 - return line[:s1], line[s1+1 : s2], line[s2+1:], true + r2, r3, ok = strings.Cut(rest, " ") + if !ok { + return "", "", "", false + } + return } func cleanHeaders(header textproto.MIMEHeader) { @@ -95,22 +97,23 @@ func writeHeaders(w io.Writer, header textproto.MIMEHeader) { } func extractUserPass(auth string) (username, password string, ok bool) { - if !strings.HasPrefix(auth, "Basic ") { + token, ok := strings.CutPrefix(auth, "Basic ") + if !ok { return } - b, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic ")) + b, err := base64.StdEncoding.DecodeString(token) if err != nil { return } s := string(b) - idx := strings.IndexByte(s, ':') - if idx < 0 { + username, password, ok = strings.Cut(s, ":") + if !ok { return } - return s[:idx], s[idx+1:], true + return username, password, true } func init() { diff --git a/proxy/server.go b/proxy/server.go index 89079fc..af20379 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -3,7 +3,7 @@ package proxy import ( "errors" "net" - "sort" + "slices" "strings" ) @@ -44,7 +44,7 @@ func ServerFromURL(s string, proxy Proxy) (Server, error) { s = "mixed://" + s } - scheme := s[:strings.Index(s, ":")] + scheme, _, _ := strings.Cut(s, ":") c, ok := serverCreators[strings.ToLower(scheme)] if ok { return c(s, proxy) @@ -59,6 +59,6 @@ func ServerSchemes() string { for name := range serverCreators { s = append(s, name) } - sort.Strings(s) + slices.Sort(s) return strings.Join(s, " ") } diff --git a/proxy/vmess/auth.go b/proxy/vmess/auth.go index 9228ffe..90e5902 100644 --- a/proxy/vmess/auth.go +++ b/proxy/vmess/auth.go @@ -33,8 +33,7 @@ func sealVMessAEADHeader(key [16]byte, data []byte) []byte { connectionNonce := make([]byte, 8) rand.Read(connectionNonce) - aeadPayloadLengthSerializedByte := make([]byte, 2) - binary.BigEndian.PutUint16(aeadPayloadLengthSerializedByte, uint16(len(data))) + aeadPayloadLengthSerializedByte := binary.BigEndian.AppendUint16(nil, uint16(len(data))) var payloadHeaderLengthAEADEncrypted []byte diff --git a/proxy/ws/ws.go b/proxy/ws/ws.go index 9a4e978..e8d3727 100644 --- a/proxy/ws/ws.go +++ b/proxy/ws/ws.go @@ -93,13 +93,15 @@ func NewWS(s string, d proxy.Dialer, p proxy.Proxy, withTLS bool) (*WS, error) { // parseFirstLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts. // TODO: move to separate http lib package for reuse(also for http proxy module) func parseFirstLine(line string) (r1, r2, r3 string, ok bool) { - s1 := strings.Index(line, " ") - s2 := strings.Index(line[s1+1:], " ") - if s1 < 0 || s2 < 0 { + r1, rest, ok := strings.Cut(line, " ") + if !ok { return } - s2 += s1 + 1 - return line[:s1], line[s1+1 : s2], line[s2+1:], true + r2, r3, ok = strings.Cut(rest, " ") + if !ok { + return "", "", "", false + } + return } func generateClientKey() string { diff --git a/rule/forward.go b/rule/forward.go index 2304220..b1c6e01 100644 --- a/rule/forward.go +++ b/rule/forward.go @@ -33,9 +33,9 @@ type Forwarder struct { func ForwarderFromURL(s, intface string, dialTimeout, relayTimeout time.Duration) (f *Forwarder, err error) { f = &Forwarder{url: s} - ss := strings.Split(s, "#") - if len(ss) > 1 { - err = f.parseOption(ss[1]) + chain, option, found := strings.Cut(s, "#") + if found { + err = f.parseOption(option) } iface := intface @@ -50,7 +50,7 @@ func ForwarderFromURL(s, intface string, dialTimeout, relayTimeout time.Duration } var addrs []string - for _, url := range strings.Split(ss[0], ",") { + for url := range strings.SplitSeq(chain, ",") { d, err = proxy.DialerFromURL(url, d) if err != nil { return nil, err diff --git a/rule/group.go b/rule/group.go index 4ecb3ea..9defdb1 100644 --- a/rule/group.go +++ b/rule/group.go @@ -6,7 +6,7 @@ import ( "net" "net/url" "path/filepath" - "sort" + "slices" "strings" "sync" "sync/atomic" @@ -16,18 +16,11 @@ import ( "github.com/nadoo/glider/proxy" ) -// forwarder slice orderd by priority. -type priSlice []*Forwarder - -func (p priSlice) Len() int { return len(p) } -func (p priSlice) Less(i, j int) bool { return p[i].Priority() > p[j].Priority() } -func (p priSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - // FwdrGroup is a forwarder group. type FwdrGroup struct { name string config *Strategy - fwdrs priSlice + fwdrs []*Forwarder avail []*Forwarder // available forwarders mu sync.RWMutex index uint32 @@ -66,7 +59,16 @@ func NewFwdrGroup(rulePath string, s []string, c *Strategy) *FwdrGroup { // newFwdrGroup returns a new FwdrGroup. func newFwdrGroup(name string, fwdrs []*Forwarder, c *Strategy) *FwdrGroup { p := &FwdrGroup{name: name, fwdrs: fwdrs, config: c} - sort.Sort(p.fwdrs) + slices.SortFunc(p.fwdrs, func(a, b *Forwarder) int { + switch { + case a.Priority() > b.Priority(): + return -1 + case a.Priority() < b.Priority(): + return 1 + default: + return 0 + } + }) p.init() diff --git a/rule/proxy.go b/rule/proxy.go index 495b83e..ee98779 100644 --- a/rule/proxy.go +++ b/rule/proxy.go @@ -56,7 +56,7 @@ func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config) // if there's any forwarder defined in main config, make sure they will be accessed directly. if len(mainForwarders) > 0 { for _, f := range rd.main.fwdrs { - addr := strings.Split(f.addr, ",")[0] + addr, _, _ := strings.Cut(f.addr, ",") host, _, _ := net.SplitHostPort(addr) if _, err := netip.ParseAddr(host); err != nil { rd.domainMap.Store(strings.ToLower(host), direct)