From af2d75d1d008d29dd8305a393c60a389cac19ff8 Mon Sep 17 00:00:00 2001 From: "Haruue Icymoon (usamimi-wsl)" Date: Sat, 19 Oct 2024 16:27:16 +0800 Subject: [PATCH 01/31] fix: check masq url scheme in server cfg parsing Check the url scheme of masquerade.proxy.url when parsing server config and fail fast if it is not "http" or "https". ref: #1227 The user assigned the URL with a naked hostname and got errors until the request was handled. --- app/cmd/server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/cmd/server.go b/app/cmd/server.go index 3da748d..a4b8470 100644 --- a/app/cmd/server.go +++ b/app/cmd/server.go @@ -804,6 +804,9 @@ func (c *serverConfig) fillMasqHandler(hyConfig *server.Config) error { if err != nil { return configError{Field: "masquerade.proxy.url", Err: err} } + if u.Scheme != "http" && u.Scheme != "https" { + return configError{Field: "masquerade.proxy.url", Err: fmt.Errorf("unsupported protocol scheme \"%s\"", u.Scheme)} + } handler = &httputil.ReverseProxy{ Rewrite: func(r *httputil.ProxyRequest) { r.SetURL(u) From 99e959f8c96276038b500635efa81bfa79917874 Mon Sep 17 00:00:00 2001 From: "Haruue Icymoon (usamimi-wsl)" Date: Sat, 19 Oct 2024 17:24:52 +0800 Subject: [PATCH 02/31] feat: share subcommand Useful for third-party scripts/clients that just want to generate the sharing URI without starting the client. --- app/cmd/share.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 app/cmd/share.go diff --git a/app/cmd/share.go b/app/cmd/share.go new file mode 100644 index 0000000..ad96e80 --- /dev/null +++ b/app/cmd/share.go @@ -0,0 +1,55 @@ +package cmd + +import ( + "fmt" + + "github.com/apernet/hysteria/app/v2/internal/utils" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.uber.org/zap" +) + +var ( + noText bool + withQR bool +) + +// shareCmd represents the share command +var shareCmd = &cobra.Command{ + Use: "share", + Short: "Generate share URI", + Long: "Generate a hysteria2:// URI from a client config for sharing", + Run: runShare, +} + +func init() { + initShareFlags() + rootCmd.AddCommand(shareCmd) +} + +func initShareFlags() { + shareCmd.Flags().BoolVar(&noText, "notext", false, "do not show URI as text") + shareCmd.Flags().BoolVar(&withQR, "qr", false, "show URI as QR code") +} + +func runShare(cmd *cobra.Command, args []string) { + if err := viper.ReadInConfig(); err != nil { + logger.Fatal("failed to read client config", zap.Error(err)) + } + var config clientConfig + if err := viper.Unmarshal(&config); err != nil { + logger.Fatal("failed to parse client config", zap.Error(err)) + } + if _, err := config.Config(); err != nil { + logger.Fatal("failed to load client config", zap.Error(err)) + } + + u := config.URI() + + if !noText { + fmt.Println(u) + } + if withQR { + utils.PrintQR(u) + } +} From d65997c02b1312cf1950ba0d42ea3973d91e3b36 Mon Sep 17 00:00:00 2001 From: Haruue Date: Tue, 5 Nov 2024 00:44:04 +0900 Subject: [PATCH 03/31] fix: inf loop in PortUnion.Ports() when end=65535 fix: #1240 Any uint16 value is less than or equal to 65535. --- extras/utils/portunion.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extras/utils/portunion.go b/extras/utils/portunion.go index 20a31d0..07326e4 100644 --- a/extras/utils/portunion.go +++ b/extras/utils/portunion.go @@ -1,6 +1,7 @@ package utils import ( + "math" "sort" "strconv" "strings" @@ -91,6 +92,9 @@ func (u PortUnion) Ports() []uint16 { for _, r := range u { for i := r.Start; i <= r.End; i++ { ports = append(ports, i) + if i == math.MaxUint16 { + break + } } } return ports From a9422e63be8f55c9e097523e98ee8169ca12f54f Mon Sep 17 00:00:00 2001 From: Haruue Date: Tue, 5 Nov 2024 00:46:16 +0900 Subject: [PATCH 04/31] test: add ut for PortUnion.Ports() --- extras/utils/portunion_test.go | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/extras/utils/portunion_test.go b/extras/utils/portunion_test.go index 551bae1..0a9bd0c 100644 --- a/extras/utils/portunion_test.go +++ b/extras/utils/portunion_test.go @@ -2,6 +2,7 @@ package utils import ( "reflect" + "slices" "testing" ) @@ -90,3 +91,50 @@ func TestParsePortUnion(t *testing.T) { }) } } + +func TestPortUnion_Ports(t *testing.T) { + tests := []struct { + name string + pu PortUnion + want []uint16 + }{ + { + name: "single port", + pu: PortUnion{{1234, 1234}}, + want: []uint16{1234}, + }, + { + name: "multiple ports", + pu: PortUnion{{1234, 1236}}, + want: []uint16{1234, 1235, 1236}, + }, + { + name: "multiple ports and ranges", + pu: PortUnion{{1234, 1236}, {5678, 5680}, {9000, 9002}}, + want: []uint16{1234, 1235, 1236, 5678, 5679, 5680, 9000, 9001, 9002}, + }, + { + name: "single port 65535", + pu: PortUnion{{65535, 65535}}, + want: []uint16{65535}, + }, + { + name: "port range with 65535", + pu: PortUnion{{65530, 65535}}, + want: []uint16{65530, 65531, 65532, 65533, 65534, 65535}, + }, + { + name: "multiple ports and ranges with 65535", + pu: PortUnion{{65530, 65535}, {1234, 1236}}, + want: []uint16{65530, 65531, 65532, 65533, 65534, 65535, 1234, 1235, 1236}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.pu.Ports(); !slices.Equal(got, tt.want) { + t.Errorf("PortUnion.Ports() = %v, want %v", got, tt.want) + } + }) + } +} From 9a21e2e8c661642c9cb664b214f70f147f78aa49 Mon Sep 17 00:00:00 2001 From: Haruue Date: Tue, 5 Nov 2024 01:30:44 +0900 Subject: [PATCH 05/31] chore: a better fix to portunion --- extras/utils/portunion.go | 10 +++------- extras/utils/portunion_test.go | 10 ++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/extras/utils/portunion.go b/extras/utils/portunion.go index 07326e4..f76a6fd 100644 --- a/extras/utils/portunion.go +++ b/extras/utils/portunion.go @@ -1,7 +1,6 @@ package utils import ( - "math" "sort" "strconv" "strings" @@ -75,7 +74,7 @@ func (u PortUnion) Normalize() PortUnion { normalized := PortUnion{u[0]} for _, current := range u[1:] { last := &normalized[len(normalized)-1] - if current.Start <= last.End+1 { + if uint32(current.Start) <= uint32(last.End)+1 { if current.End > last.End { last.End = current.End } @@ -90,11 +89,8 @@ func (u PortUnion) Normalize() PortUnion { func (u PortUnion) Ports() []uint16 { var ports []uint16 for _, r := range u { - for i := r.Start; i <= r.End; i++ { - ports = append(ports, i) - if i == math.MaxUint16 { - break - } + for i := uint32(r.Start); i <= uint32(r.End); i++ { + ports = append(ports, uint16(i)) } } return ports diff --git a/extras/utils/portunion_test.go b/extras/utils/portunion_test.go index 0a9bd0c..ba056a3 100644 --- a/extras/utils/portunion_test.go +++ b/extras/utils/portunion_test.go @@ -52,6 +52,16 @@ func TestParsePortUnion(t *testing.T) { s: "5678,1200-1236,9100-9012,1234-1240", want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}}, }, + { + name: "multiple ports and ranges with 65535 (reversed, unsorted, overlapping)", + s: "5678,1200-1236,65531-65535,65532-65534,9100-9012,1234-1240", + want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}, {65531, 65535}}, + }, + { + name: "multiple ports and ranges with 65535 (reversed, unsorted, overlapping) 2", + s: "5678,1200-1236,65532-65535,65531-65534,9100-9012,1234-1240", + want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}, {65531, 65535}}, + }, { name: "invalid 1", s: "1234-", From 04cf6f2e1ad56b0de791d42220273288b6cd9429 Mon Sep 17 00:00:00 2001 From: Toby Date: Mon, 4 Nov 2024 11:32:58 -0800 Subject: [PATCH 06/31] feat: quic-go v0.48.1 --- app/go.mod | 2 +- app/go.sum | 4 ++-- core/go.mod | 2 +- core/go.sum | 4 ++-- extras/go.mod | 2 +- extras/go.sum | 4 ++-- go.work.sum | 2 ++ 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/go.mod b/app/go.mod index 7353f6a..dab7e51 100644 --- a/app/go.mod +++ b/app/go.mod @@ -30,7 +30,7 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d // indirect + github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/app/go.sum b/app/go.sum index 73ee963..dec519b 100644 --- a/app/go.sum +++ b/app/go.sum @@ -42,8 +42,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM= -github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d h1:KWRCWISqJOgY9/0hhH8Bevjw/k4tCQ7oJlXLyFv8u9s= -github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d/go.mod h1:x0paLlmCzNOUDDQIgmgFWmnpWQIEuH1GNfA6NdgSTuM= +github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 h1:zO38yBOvQ1dLHbSuaU5BFZ8zalnSDQslj+i/9AGOk9s= +github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7/go.mod h1:LoSUY2chVqNQCDyi4IZGqPpXLy1FuCkE37PKwtJvNGg= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad h1:QzQ2sKpc9o42HNRR8ukM5uMC/RzR2HgZd/Nvaqol2C0= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= diff --git a/core/go.mod b/core/go.mod index 8d4cec0..beb0372 100644 --- a/core/go.mod +++ b/core/go.mod @@ -5,7 +5,7 @@ go 1.22 toolchain go1.23.2 require ( - github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d + github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 github.com/stretchr/testify v1.9.0 go.uber.org/goleak v1.2.1 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 diff --git a/core/go.sum b/core/go.sum index 4af12ad..d65498b 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,5 +1,5 @@ -github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d h1:KWRCWISqJOgY9/0hhH8Bevjw/k4tCQ7oJlXLyFv8u9s= -github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d/go.mod h1:x0paLlmCzNOUDDQIgmgFWmnpWQIEuH1GNfA6NdgSTuM= +github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 h1:zO38yBOvQ1dLHbSuaU5BFZ8zalnSDQslj+i/9AGOk9s= +github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7/go.mod h1:LoSUY2chVqNQCDyi4IZGqPpXLy1FuCkE37PKwtJvNGg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= diff --git a/extras/go.mod b/extras/go.mod index be48ce6..3da331a 100644 --- a/extras/go.mod +++ b/extras/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.2 require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 - github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d + github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/hashicorp/golang-lru/v2 v2.0.5 github.com/miekg/dns v1.1.59 diff --git a/extras/go.sum b/extras/go.sum index d1f42ea..d07ba7c 100644 --- a/extras/go.sum +++ b/extras/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d h1:KWRCWISqJOgY9/0hhH8Bevjw/k4tCQ7oJlXLyFv8u9s= -github.com/apernet/quic-go v0.47.1-0.20241004180137-a80d14e2080d/go.mod h1:x0paLlmCzNOUDDQIgmgFWmnpWQIEuH1GNfA6NdgSTuM= +github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 h1:zO38yBOvQ1dLHbSuaU5BFZ8zalnSDQslj+i/9AGOk9s= +github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7/go.mod h1:LoSUY2chVqNQCDyi4IZGqPpXLy1FuCkE37PKwtJvNGg= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/go.work.sum b/go.work.sum index b00f726..79da3fa 100644 --- a/go.work.sum +++ b/go.work.sum @@ -290,6 +290,7 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= @@ -298,6 +299,7 @@ golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852 h1:xYq6+9AtI+xP3M4r0N1hCkHr golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 685cd3663b4f1df0659f072fa08919ee95f254c9 Mon Sep 17 00:00:00 2001 From: Toby Date: Mon, 4 Nov 2024 12:01:00 -0800 Subject: [PATCH 07/31] feat: add toolchain & quic-go to version info --- app/cmd/root.go | 20 ++++++++++++-------- hyperbole.py | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/app/cmd/root.go b/app/cmd/root.go index cc7f39f..a58e2bc 100644 --- a/app/cmd/root.go +++ b/app/cmd/root.go @@ -29,20 +29,24 @@ const ( var ( // These values will be injected by the build system - appVersion = "Unknown" - appDate = "Unknown" - appType = "Unknown" // aka channel - appCommit = "Unknown" - appPlatform = "Unknown" - appArch = "Unknown" + appVersion = "Unknown" + appDate = "Unknown" + appType = "Unknown" // aka channel + appToolchain = "Unknown" + appCommit = "Unknown" + appPlatform = "Unknown" + appArch = "Unknown" + libVersion = "Unknown" appVersionLong = fmt.Sprintf("Version:\t%s\n"+ "BuildDate:\t%s\n"+ "BuildType:\t%s\n"+ + "Toolchain:\t%s\n"+ "CommitHash:\t%s\n"+ "Platform:\t%s\n"+ - "Architecture:\t%s", - appVersion, appDate, appType, appCommit, appPlatform, appArch) + "Architecture:\t%s\n"+ + "LibVersion:\t%s", + appVersion, appDate, appType, appToolchain, appCommit, appPlatform, appArch, libVersion) appAboutLong = fmt.Sprintf("%s\n%s\n%s\n\n%s", appLogo, appDesc, appAuthors, appVersionLong) ) diff --git a/hyperbole.py b/hyperbole.py index fc38eba..ecc248d 100755 --- a/hyperbole.py +++ b/hyperbole.py @@ -145,12 +145,33 @@ def get_app_commit(): return app_commit +def get_toolchain(): + try: + output = subprocess.check_output(["go", "version"]).decode().strip() + if output.startswith("go version "): + output = output[11:] + return output + except Exception: + return "Unknown" + + def get_current_os_arch(): d_os = subprocess.check_output(["go", "env", "GOOS"]).decode().strip() d_arch = subprocess.check_output(["go", "env", "GOARCH"]).decode().strip() return (d_os, d_arch) +def get_lib_version(): + try: + with open(CORE_SRC_DIR + "/go.mod") as f: + for line in f: + line = line.strip() + if line.startswith("github.com/apernet/quic-go"): + return line.split(" ")[1].strip() + except Exception: + return "Unknown" + + def get_app_platforms(): platforms = os.environ.get("HY_APP_PLATFORMS") if not platforms: @@ -176,8 +197,12 @@ def cmd_build(pprof=False, release=False, race=False): os.makedirs(BUILD_DIR, exist_ok=True) app_version = get_app_version() - app_date = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") + app_date = datetime.datetime.now(datetime.timezone.utc).strftime( + "%Y-%m-%dT%H:%M:%SZ" + ) + app_toolchain = get_toolchain() app_commit = get_app_commit() + lib_version = get_lib_version() ldflags = [ "-X", @@ -190,7 +215,11 @@ def cmd_build(pprof=False, release=False, race=False): + ("release" if release else "dev") + ("-pprof" if pprof else ""), "-X", + '"' + APP_SRC_CMD_PKG + ".appToolchain=" + app_toolchain + '"', + "-X", APP_SRC_CMD_PKG + ".appCommit=" + app_commit, + "-X", + APP_SRC_CMD_PKG + ".libVersion=" + lib_version, ] if release: ldflags.append("-s") @@ -267,8 +296,12 @@ def cmd_run(args, pprof=False, race=False): return app_version = get_app_version() - app_date = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") + app_date = datetime.datetime.now(datetime.timezone.utc).strftime( + "%Y-%m-%dT%H:%M:%SZ" + ) + app_toolchain = get_toolchain() app_commit = get_app_commit() + lib_version = get_lib_version() current_os, current_arch = get_current_os_arch() @@ -280,11 +313,15 @@ def cmd_run(args, pprof=False, race=False): "-X", APP_SRC_CMD_PKG + ".appType=dev-run", "-X", + '"' + APP_SRC_CMD_PKG + ".appToolchain=" + app_toolchain + '"', + "-X", APP_SRC_CMD_PKG + ".appCommit=" + app_commit, "-X", APP_SRC_CMD_PKG + ".appPlatform=" + current_os, "-X", APP_SRC_CMD_PKG + ".appArch=" + current_arch, + "-X", + APP_SRC_CMD_PKG + ".libVersion=" + lib_version, ] cmd = ["go", "run", "-ldflags", " ".join(ldflags)] From d4a1c2b58067e9c9ff13071a028615beb97d722e Mon Sep 17 00:00:00 2001 From: Haruue Date: Tue, 5 Nov 2024 10:00:19 +0900 Subject: [PATCH 08/31] fix(scripts): extra line in installed version Checking for installed version ... v2.5.2 v0.47.1 Checking for latest version ... v2.5.2 --- scripts/install_server.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install_server.sh b/scripts/install_server.sh index 0c85dc7..4277ab9 100644 --- a/scripts/install_server.sh +++ b/scripts/install_server.sh @@ -872,7 +872,7 @@ is_hysteria1_version() { get_installed_version() { if is_hysteria_installed; then if "$EXECUTABLE_INSTALL_PATH" version > /dev/null 2>&1; then - "$EXECUTABLE_INSTALL_PATH" version | grep Version | grep -o 'v[.0-9]*' + "$EXECUTABLE_INSTALL_PATH" version | grep '^Version' | grep -o 'v[.0-9]*' elif "$EXECUTABLE_INSTALL_PATH" -v > /dev/null 2>&1; then # hysteria 1 "$EXECUTABLE_INSTALL_PATH" -v | cut -d ' ' -f 3 From 068163856833891a6e46a745197044a84ec6a727 Mon Sep 17 00:00:00 2001 From: Haruue Date: Fri, 8 Nov 2024 15:28:50 +0900 Subject: [PATCH 09/31] feat(trafficlogger): dump streams stats --- core/internal/utils/atomic.go | 30 +++++++ core/server/config.go | 65 +++++++++++++++ core/server/copy.go | 7 +- core/server/server.go | 32 +++++++- extras/trafficlogger/http.go | 147 ++++++++++++++++++++++++++++++++++ 5 files changed, 277 insertions(+), 4 deletions(-) diff --git a/core/internal/utils/atomic.go b/core/internal/utils/atomic.go index e3c3d97..7739013 100644 --- a/core/internal/utils/atomic.go +++ b/core/internal/utils/atomic.go @@ -22,3 +22,33 @@ func (t *AtomicTime) Set(new time.Time) { func (t *AtomicTime) Get() time.Time { return t.v.Load().(time.Time) } + +type Atomic[T any] struct { + v atomic.Value +} + +func (a *Atomic[T]) Load() T { + value := a.v.Load() + if value == nil { + var zero T + return zero + } + return value.(T) +} + +func (a *Atomic[T]) Store(value T) { + a.v.Store(value) +} + +func (a *Atomic[T]) Swap(new T) T { + old := a.v.Swap(new) + if old == nil { + var zero T + return zero + } + return old.(T) +} + +func (a *Atomic[T]) CompareAndSwap(old, new T) bool { + return a.v.CompareAndSwap(old, new) +} diff --git a/core/server/config.go b/core/server/config.go index f90c820..19aae53 100644 --- a/core/server/config.go +++ b/core/server/config.go @@ -4,8 +4,11 @@ import ( "crypto/tls" "net" "net/http" + "sync/atomic" "time" + "github.com/apernet/hysteria/core/v2/internal/utils" + "github.com/apernet/hysteria/core/v2/errors" "github.com/apernet/hysteria/core/v2/internal/pmtud" "github.com/apernet/quic-go" @@ -212,4 +215,66 @@ type EventLogger interface { type TrafficLogger interface { LogTraffic(id string, tx, rx uint64) (ok bool) LogOnlineState(id string, online bool) + TraceStream(stream quic.Stream, stats *StreamStats) + UntraceStream(stream quic.Stream) +} + +type StreamState int + +const ( + // StreamStateInitial indicates the initial state of a stream. + // Client has opened the stream, but we have not received the proxy request yet. + StreamStateInitial StreamState = iota + + // StreamStateHooking indicates that the hook (usually sniff) is processing. + // Client has sent the proxy request, but sniff requires more data to complete. + StreamStateHooking + + // StreamStateConnecting indicates that we are connecting to the proxy target. + StreamStateConnecting + + // StreamStateEstablished indicates the proxy is established. + StreamStateEstablished + + // StreamStateClosed indicates the stream is closed. + StreamStateClosed +) + +func (s StreamState) String() string { + switch s { + case StreamStateInitial: + return "init" + case StreamStateHooking: + return "hook" + case StreamStateConnecting: + return "connect" + case StreamStateEstablished: + return "estab" + case StreamStateClosed: + return "closed" + default: + return "unknown" + } +} + +type StreamStats struct { + State utils.Atomic[StreamState] + + AuthID string + ConnID uint32 + InitialTime time.Time + + ReqAddr utils.Atomic[string] + HookedReqAddr utils.Atomic[string] + + Tx atomic.Uint64 + Rx atomic.Uint64 + + LastActiveTime utils.Atomic[time.Time] +} + +func (s *StreamStats) setHookedReqAddr(addr string) { + if addr != s.ReqAddr.Load() { + s.HookedReqAddr.Store(addr) + } } diff --git a/core/server/copy.go b/core/server/copy.go index d55dcef..2f99ae4 100644 --- a/core/server/copy.go +++ b/core/server/copy.go @@ -3,6 +3,7 @@ package server import ( "errors" "io" + "time" ) var errDisconnect = errors.New("traffic logger requested disconnect") @@ -31,15 +32,19 @@ func copyBufferLog(dst io.Writer, src io.Reader, log func(n uint64) bool) error } } -func copyTwoWayWithLogger(id string, serverRw, remoteRw io.ReadWriter, l TrafficLogger) error { +func copyTwoWayWithLogger(id string, serverRw, remoteRw io.ReadWriter, l TrafficLogger, stats *StreamStats) error { errChan := make(chan error, 2) go func() { errChan <- copyBufferLog(serverRw, remoteRw, func(n uint64) bool { + stats.LastActiveTime.Store(time.Now()) + stats.Rx.Add(n) return l.LogTraffic(id, 0, n) }) }() go func() { errChan <- copyBufferLog(remoteRw, serverRw, func(n uint64) bool { + stats.LastActiveTime.Store(time.Now()) + stats.Tx.Add(n) return l.LogTraffic(id, n, 0) }) }() diff --git a/core/server/server.go b/core/server/server.go index ba55b31..f7ad957 100644 --- a/core/server/server.go +++ b/core/server/server.go @@ -3,8 +3,10 @@ package server import ( "context" "crypto/tls" + "math/rand" "net/http" "sync" + "time" "github.com/apernet/quic-go" "github.com/apernet/quic-go/http3" @@ -100,6 +102,7 @@ type h3sHandler struct { authenticated bool authMutex sync.Mutex authID string + connID uint32 // a random id for dump streams udpSM *udpSessionManager // Only set after authentication } @@ -108,6 +111,7 @@ func newH3sHandler(config *Config, conn quic.Connection) *h3sHandler { return &h3sHandler{ config: config, conn: conn, + connID: rand.Uint32(), } } @@ -205,12 +209,29 @@ func (h *h3sHandler) ProxyStreamHijacker(ft http3.FrameType, id quic.ConnectionT } func (h *h3sHandler) handleTCPRequest(stream quic.Stream) { + trafficLogger := h.config.TrafficLogger + streamStats := &StreamStats{ + AuthID: h.authID, + ConnID: h.connID, + InitialTime: time.Now(), + } + streamStats.State.Store(StreamStateInitial) + streamStats.LastActiveTime.Store(time.Now()) + defer func() { + streamStats.State.Store(StreamStateClosed) + }() + if trafficLogger != nil { + trafficLogger.TraceStream(stream, streamStats) + defer trafficLogger.UntraceStream(stream) + } + // Read request reqAddr, err := protocol.ReadTCPRequest(stream) if err != nil { _ = stream.Close() return } + streamStats.ReqAddr.Store(reqAddr) // Call the hook if set var putback []byte var hooked bool @@ -220,12 +241,14 @@ func (h *h3sHandler) handleTCPRequest(stream quic.Stream) { // so that the client will send whatever request the hook wants to see. // This is essentially a server-side fast-open. if hooked { + streamStats.State.Store(StreamStateHooking) _ = protocol.WriteTCPResponse(stream, true, "RequestHook enabled") putback, err = h.config.RequestHook.TCP(stream, &reqAddr) if err != nil { _ = stream.Close() return } + streamStats.setHookedReqAddr(reqAddr) } } // Log the event @@ -233,6 +256,7 @@ func (h *h3sHandler) handleTCPRequest(stream quic.Stream) { h.config.EventLogger.TCPRequest(h.conn.RemoteAddr(), h.authID, reqAddr) } // Dial target + streamStats.State.Store(StreamStateConnecting) tConn, err := h.config.Outbound.TCP(reqAddr) if err != nil { if !hooked { @@ -248,13 +272,15 @@ func (h *h3sHandler) handleTCPRequest(stream quic.Stream) { if !hooked { _ = protocol.WriteTCPResponse(stream, true, "Connected") } + streamStats.State.Store(StreamStateEstablished) // Put back the data if the hook requested if len(putback) > 0 { - _, _ = tConn.Write(putback) + n, _ := tConn.Write(putback) + streamStats.Tx.Add(uint64(n)) } // Start proxying - if h.config.TrafficLogger != nil { - err = copyTwoWayWithLogger(h.authID, stream, tConn, h.config.TrafficLogger) + if trafficLogger != nil { + err = copyTwoWayWithLogger(h.authID, stream, tConn, trafficLogger, streamStats) } else { // Use the fast path if no traffic logger is set err = copyTwoWay(stream, tConn) diff --git a/extras/trafficlogger/http.go b/extras/trafficlogger/http.go index 9ab943a..87eb919 100644 --- a/extras/trafficlogger/http.go +++ b/extras/trafficlogger/http.go @@ -1,10 +1,17 @@ package trafficlogger import ( + "cmp" "encoding/json" + "fmt" "net/http" + "slices" "strconv" + "strings" "sync" + "time" + + "github.com/apernet/quic-go" "github.com/apernet/hysteria/core/v2/server" ) @@ -25,6 +32,7 @@ func NewTrafficStatsServer(secret string) TrafficStatsServer { StatsMap: make(map[string]*trafficStatsEntry), KickMap: make(map[string]struct{}), OnlineMap: make(map[string]int), + StreamMap: make(map[quic.Stream]*server.StreamStats), Secret: secret, } } @@ -33,6 +41,7 @@ type trafficStatsServerImpl struct { Mutex sync.RWMutex StatsMap map[string]*trafficStatsEntry OnlineMap map[string]int + StreamMap map[quic.Stream]*server.StreamStats KickMap map[string]struct{} Secret string } @@ -78,6 +87,20 @@ func (s *trafficStatsServerImpl) LogOnlineState(id string, online bool) { } } +func (s *trafficStatsServerImpl) TraceStream(stream quic.Stream, stats *server.StreamStats) { + s.Mutex.Lock() + defer s.Mutex.Unlock() + + s.StreamMap[stream] = stats +} + +func (s *trafficStatsServerImpl) UntraceStream(stream quic.Stream) { + s.Mutex.Lock() + defer s.Mutex.Unlock() + + delete(s.StreamMap, stream) +} + func (s *trafficStatsServerImpl) ServeHTTP(w http.ResponseWriter, r *http.Request) { if s.Secret != "" && r.Header.Get("Authorization") != s.Secret { http.Error(w, "unauthorized", http.StatusUnauthorized) @@ -99,6 +122,10 @@ func (s *trafficStatsServerImpl) ServeHTTP(w http.ResponseWriter, r *http.Reques s.getOnline(w, r) return } + if r.Method == http.MethodGet && r.URL.Path == "/dump/streams" { + s.getDumpStreams(w, r) + return + } http.NotFound(w, r) } @@ -137,6 +164,126 @@ func (s *trafficStatsServerImpl) getOnline(w http.ResponseWriter, r *http.Reques _, _ = w.Write(jb) } +type dumpStreamEntry struct { + State string `json:"state"` + + Auth string `json:"auth"` + Connection uint32 `json:"connection"` + Stream uint64 `json:"stream"` + + ReqAddr string `json:"req_addr"` + HookedReqAddr string `json:"hooked_req_addr"` + + Tx uint64 `json:"tx"` + Rx uint64 `json:"rx"` + + InitialAt string `json:"initial_at"` + LastActiveAt string `json:"last_active_at"` + + // for text/plain output + initialTime time.Time + lastActiveTime time.Time +} + +func (e *dumpStreamEntry) fromStreamStats(stream quic.Stream, s *server.StreamStats) { + e.State = s.State.Load().String() + e.Auth = s.AuthID + e.Connection = s.ConnID + e.Stream = uint64(stream.StreamID()) + e.ReqAddr = s.ReqAddr.Load() + e.HookedReqAddr = s.HookedReqAddr.Load() + e.Tx = s.Tx.Load() + e.Rx = s.Rx.Load() + e.initialTime = s.InitialTime + e.lastActiveTime = s.LastActiveTime.Load() + e.InitialAt = e.initialTime.Format(time.RFC3339Nano) + e.LastActiveAt = e.lastActiveTime.Format(time.RFC3339Nano) +} + +func formatDumpStreamLine(state, auth, connection, stream, reqAddr, hookedReqAddr, tx, rx, lifetime, lastActive string) string { + return fmt.Sprintf("%-8s %-12s %12s %8s %12s %12s %12s %12s %-16s %s", state, auth, connection, stream, tx, rx, lifetime, lastActive, reqAddr, hookedReqAddr) +} + +func (e *dumpStreamEntry) String() string { + stateText := strings.ToUpper(e.State) + connectionText := fmt.Sprintf("%08X", e.Connection) + streamText := strconv.FormatUint(e.Stream, 10) + reqAddrText := e.ReqAddr + if reqAddrText == "" { + reqAddrText = "-" + } + hookedReqAddrText := e.HookedReqAddr + if hookedReqAddrText == "" { + hookedReqAddrText = "-" + } + txText := strconv.FormatUint(e.Tx, 10) + rxText := strconv.FormatUint(e.Rx, 10) + lifetime := time.Now().Sub(e.initialTime) + if lifetime < 10*time.Minute { + lifetime = lifetime.Round(time.Millisecond) + } else { + lifetime = lifetime.Round(time.Second) + } + lastActive := time.Now().Sub(e.lastActiveTime) + if lastActive < 10*time.Minute { + lastActive = lastActive.Round(time.Millisecond) + } else { + lastActive = lastActive.Round(time.Second) + } + + return formatDumpStreamLine(stateText, e.Auth, connectionText, streamText, reqAddrText, hookedReqAddrText, txText, rxText, lifetime.String(), lastActive.String()) +} + +func (s *trafficStatsServerImpl) getDumpStreams(w http.ResponseWriter, r *http.Request) { + var entries []dumpStreamEntry + + s.Mutex.RLock() + entries = make([]dumpStreamEntry, len(s.StreamMap)) + index := 0 + for stream, stats := range s.StreamMap { + entries[index].fromStreamStats(stream, stats) + index++ + } + s.Mutex.RUnlock() + + slices.SortFunc(entries, func(lhs, rhs dumpStreamEntry) int { + if ret := cmp.Compare(lhs.Auth, rhs.Auth); ret != 0 { + return ret + } + if ret := cmp.Compare(lhs.Connection, rhs.Connection); ret != 0 { + return ret + } + if ret := cmp.Compare(lhs.Stream, rhs.Stream); ret != 0 { + return ret + } + return 0 + }) + + accept := r.Header.Get("Accept") + + if strings.Contains(accept, "text/plain") { + // Generate netstat-like output for humans + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + + // Print table header + _, _ = fmt.Fprintln(w, formatDumpStreamLine("State", "Auth", "Connection", "Stream", "Req-Addr", "Hooked-Req-Addr", "TX-Bytes", "RX-Bytes", "Lifetime", "Last-Active")) + for _, entry := range entries { + _, _ = fmt.Fprintln(w, entry.String()) + } + return + } + + // Response with json by default + wrapper := struct { + Streams []dumpStreamEntry `json:"streams"` + }{entries} + w.Header().Set("Content-Type", "application/json; charset=utf-8") + err := json.NewEncoder(w).Encode(&wrapper) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + func (s *trafficStatsServerImpl) kick(w http.ResponseWriter, r *http.Request) { var ids []string err := json.NewDecoder(r.Body).Decode(&ids) From 7ac8d87ddae55af435738e4430ce6dcffc2ae140 Mon Sep 17 00:00:00 2001 From: Haruue Date: Fri, 8 Nov 2024 16:03:48 +0900 Subject: [PATCH 10/31] test: fix integration_tests for trafficlogger --- .../mocks/mock_TrafficLogger.go | 74 ++++++++++++++++++- .../integration_tests/trafficlogger_test.go | 2 + 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/core/internal/integration_tests/mocks/mock_TrafficLogger.go b/core/internal/integration_tests/mocks/mock_TrafficLogger.go index 9de44b9..1ed977e 100644 --- a/core/internal/integration_tests/mocks/mock_TrafficLogger.go +++ b/core/internal/integration_tests/mocks/mock_TrafficLogger.go @@ -2,7 +2,12 @@ package mocks -import mock "github.com/stretchr/testify/mock" +import ( + quic "github.com/apernet/quic-go" + mock "github.com/stretchr/testify/mock" + + server "github.com/apernet/hysteria/core/v2/server" +) // MockTrafficLogger is an autogenerated mock type for the TrafficLogger type type MockTrafficLogger struct { @@ -99,6 +104,73 @@ func (_c *MockTrafficLogger_LogTraffic_Call) RunAndReturn(run func(string, uint6 return _c } +// TraceStream provides a mock function with given fields: stream, stats +func (_m *MockTrafficLogger) TraceStream(stream quic.Stream, stats *server.StreamStats) { + _m.Called(stream, stats) +} + +// MockTrafficLogger_TraceStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TraceStream' +type MockTrafficLogger_TraceStream_Call struct { + *mock.Call +} + +// TraceStream is a helper method to define mock.On call +// - stream quic.Stream +// - stats *server.StreamStats +func (_e *MockTrafficLogger_Expecter) TraceStream(stream interface{}, stats interface{}) *MockTrafficLogger_TraceStream_Call { + return &MockTrafficLogger_TraceStream_Call{Call: _e.mock.On("TraceStream", stream, stats)} +} + +func (_c *MockTrafficLogger_TraceStream_Call) Run(run func(stream quic.Stream, stats *server.StreamStats)) *MockTrafficLogger_TraceStream_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(quic.Stream), args[1].(*server.StreamStats)) + }) + return _c +} + +func (_c *MockTrafficLogger_TraceStream_Call) Return() *MockTrafficLogger_TraceStream_Call { + _c.Call.Return() + return _c +} + +func (_c *MockTrafficLogger_TraceStream_Call) RunAndReturn(run func(quic.Stream, *server.StreamStats)) *MockTrafficLogger_TraceStream_Call { + _c.Call.Return(run) + return _c +} + +// UntraceStream provides a mock function with given fields: stream +func (_m *MockTrafficLogger) UntraceStream(stream quic.Stream) { + _m.Called(stream) +} + +// MockTrafficLogger_UntraceStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UntraceStream' +type MockTrafficLogger_UntraceStream_Call struct { + *mock.Call +} + +// UntraceStream is a helper method to define mock.On call +// - stream quic.Stream +func (_e *MockTrafficLogger_Expecter) UntraceStream(stream interface{}) *MockTrafficLogger_UntraceStream_Call { + return &MockTrafficLogger_UntraceStream_Call{Call: _e.mock.On("UntraceStream", stream)} +} + +func (_c *MockTrafficLogger_UntraceStream_Call) Run(run func(stream quic.Stream)) *MockTrafficLogger_UntraceStream_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(quic.Stream)) + }) + return _c +} + +func (_c *MockTrafficLogger_UntraceStream_Call) Return() *MockTrafficLogger_UntraceStream_Call { + _c.Call.Return() + return _c +} + +func (_c *MockTrafficLogger_UntraceStream_Call) RunAndReturn(run func(quic.Stream)) *MockTrafficLogger_UntraceStream_Call { + _c.Call.Return(run) + return _c +} + // NewMockTrafficLogger creates a new instance of MockTrafficLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewMockTrafficLogger(t interface { diff --git a/core/internal/integration_tests/trafficlogger_test.go b/core/internal/integration_tests/trafficlogger_test.go index b5355ff..841f4ff 100644 --- a/core/internal/integration_tests/trafficlogger_test.go +++ b/core/internal/integration_tests/trafficlogger_test.go @@ -62,6 +62,7 @@ func TestClientServerTrafficLoggerTCP(t *testing.T) { return nil }) serverOb.EXPECT().TCP(addr).Return(sobConn, nil).Once() + trafficLogger.EXPECT().TraceStream(mock.Anything, mock.Anything).Return().Once() conn, err := c.TCP(addr) assert.NoError(t, err) @@ -84,6 +85,7 @@ func TestClientServerTrafficLoggerTCP(t *testing.T) { time.Sleep(1 * time.Second) // Need some time for the server to receive the data // Client reads from server again but blocked + trafficLogger.EXPECT().UntraceStream(mock.Anything).Return().Once() trafficLogger.EXPECT().LogTraffic("nobody", uint64(0), uint64(4)).Return(false).Once() trafficLogger.EXPECT().LogOnlineState("nobody", false).Return().Once() sobConnCh <- []byte("nope") From 3e8c20518db0e97ad67b638e85cbe643b26d777a Mon Sep 17 00:00:00 2001 From: Toby Date: Fri, 8 Nov 2024 14:29:50 -0800 Subject: [PATCH 11/31] chore: minor code tweaks --- core/server/config.go | 3 +-- core/server/copy.go | 4 ++-- core/server/server.go | 2 +- extras/trafficlogger/http.go | 3 +-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/server/config.go b/core/server/config.go index 19aae53..a01f478 100644 --- a/core/server/config.go +++ b/core/server/config.go @@ -7,10 +7,9 @@ import ( "sync/atomic" "time" - "github.com/apernet/hysteria/core/v2/internal/utils" - "github.com/apernet/hysteria/core/v2/errors" "github.com/apernet/hysteria/core/v2/internal/pmtud" + "github.com/apernet/hysteria/core/v2/internal/utils" "github.com/apernet/quic-go" ) diff --git a/core/server/copy.go b/core/server/copy.go index 2f99ae4..7123fc8 100644 --- a/core/server/copy.go +++ b/core/server/copy.go @@ -32,7 +32,7 @@ func copyBufferLog(dst io.Writer, src io.Reader, log func(n uint64) bool) error } } -func copyTwoWayWithLogger(id string, serverRw, remoteRw io.ReadWriter, l TrafficLogger, stats *StreamStats) error { +func copyTwoWayEx(id string, serverRw, remoteRw io.ReadWriter, l TrafficLogger, stats *StreamStats) error { errChan := make(chan error, 2) go func() { errChan <- copyBufferLog(serverRw, remoteRw, func(n uint64) bool { @@ -52,7 +52,7 @@ func copyTwoWayWithLogger(id string, serverRw, remoteRw io.ReadWriter, l Traffic return <-errChan } -// copyTwoWay is the "fast-path" version of copyTwoWayWithLogger that does not log traffic. +// copyTwoWay is the "fast-path" version of copyTwoWayEx that does not log traffic or update stream stats. // It uses the built-in io.Copy instead of our own copyBufferLog. func copyTwoWay(serverRw, remoteRw io.ReadWriter) error { errChan := make(chan error, 2) diff --git a/core/server/server.go b/core/server/server.go index f7ad957..696f1d0 100644 --- a/core/server/server.go +++ b/core/server/server.go @@ -280,7 +280,7 @@ func (h *h3sHandler) handleTCPRequest(stream quic.Stream) { } // Start proxying if trafficLogger != nil { - err = copyTwoWayWithLogger(h.authID, stream, tConn, trafficLogger, streamStats) + err = copyTwoWayEx(h.authID, stream, tConn, trafficLogger, streamStats) } else { // Use the fast path if no traffic logger is set err = copyTwoWay(stream, tConn) diff --git a/extras/trafficlogger/http.go b/extras/trafficlogger/http.go index 87eb919..d8e6ebd 100644 --- a/extras/trafficlogger/http.go +++ b/extras/trafficlogger/http.go @@ -11,9 +11,8 @@ import ( "sync" "time" - "github.com/apernet/quic-go" - "github.com/apernet/hysteria/core/v2/server" + "github.com/apernet/quic-go" ) const ( From 16c964b3e143f6b2c3384d6f02e85e635984a4fc Mon Sep 17 00:00:00 2001 From: Haruue Date: Fri, 22 Nov 2024 13:47:44 +0900 Subject: [PATCH 12/31] feat(server): tcp fast open on direct outbounds --- app/cmd/server.go | 21 +-- app/cmd/server_test.go | 1 + app/cmd/server_test.yaml | 1 + app/go.mod | 4 +- app/go.sum | 8 +- extras/go.mod | 4 +- extras/go.sum | 8 +- extras/outbounds/fastopen.go | 230 +++++++++++++++++++++++++++ extras/outbounds/ob_direct.go | 113 +++++++++---- extras/outbounds/ob_direct_linux.go | 38 ++--- extras/outbounds/ob_direct_others.go | 7 +- 11 files changed, 363 insertions(+), 72 deletions(-) create mode 100644 extras/outbounds/fastopen.go diff --git a/app/cmd/server.go b/app/cmd/server.go index a4b8470..1384dd8 100644 --- a/app/cmd/server.go +++ b/app/cmd/server.go @@ -204,6 +204,7 @@ type serverConfigOutboundDirect struct { BindIPv4 string `mapstructure:"bindIPv4"` BindIPv6 string `mapstructure:"bindIPv6"` BindDevice string `mapstructure:"bindDevice"` + FastOpen bool `mapstructure:"fastOpen"` } type serverConfigOutboundSOCKS5 struct { @@ -518,18 +519,18 @@ func (c *serverConfig) fillQUICConfig(hyConfig *server.Config) error { } func serverConfigOutboundDirectToOutbound(c serverConfigOutboundDirect) (outbounds.PluggableOutbound, error) { - var mode outbounds.DirectOutboundMode + opts := outbounds.DirectOutboundOptions{} switch strings.ToLower(c.Mode) { case "", "auto": - mode = outbounds.DirectOutboundModeAuto + opts.Mode = outbounds.DirectOutboundModeAuto case "64": - mode = outbounds.DirectOutboundMode64 + opts.Mode = outbounds.DirectOutboundMode64 case "46": - mode = outbounds.DirectOutboundMode46 + opts.Mode = outbounds.DirectOutboundMode46 case "6": - mode = outbounds.DirectOutboundMode6 + opts.Mode = outbounds.DirectOutboundMode6 case "4": - mode = outbounds.DirectOutboundMode4 + opts.Mode = outbounds.DirectOutboundMode4 default: return nil, configError{Field: "outbounds.direct.mode", Err: errors.New("unsupported mode")} } @@ -546,12 +547,14 @@ func serverConfigOutboundDirectToOutbound(c serverConfigOutboundDirect) (outboun if len(c.BindIPv6) > 0 && ip6 == nil { return nil, configError{Field: "outbounds.direct.bindIPv6", Err: errors.New("invalid IPv6 address")} } - return outbounds.NewDirectOutboundBindToIPs(mode, ip4, ip6) + opts.BindIP4 = ip4 + opts.BindIP6 = ip6 } if bindDevice { - return outbounds.NewDirectOutboundBindToDevice(mode, c.BindDevice) + opts.DeviceName = c.BindDevice } - return outbounds.NewDirectOutboundSimple(mode), nil + opts.FastOpen = c.FastOpen + return outbounds.NewDirectOutboundWithOptions(opts) } func serverConfigOutboundSOCKS5ToOutbound(c serverConfigOutboundSOCKS5) (outbounds.PluggableOutbound, error) { diff --git a/app/cmd/server_test.go b/app/cmd/server_test.go index f35edfb..bcf61c3 100644 --- a/app/cmd/server_test.go +++ b/app/cmd/server_test.go @@ -138,6 +138,7 @@ func TestServerConfig(t *testing.T) { BindIPv4: "2.4.6.8", BindIPv6: "0:0:0:0:0:ffff:0204:0608", BindDevice: "eth233", + FastOpen: true, }, }, { diff --git a/app/cmd/server_test.yaml b/app/cmd/server_test.yaml index b7d1a3e..dda6d98 100644 --- a/app/cmd/server_test.yaml +++ b/app/cmd/server_test.yaml @@ -108,6 +108,7 @@ outbounds: bindIPv4: 2.4.6.8 bindIPv6: 0:0:0:0:0:ffff:0204:0608 bindDevice: eth233 + fastOpen: true - name: badstuff type: socks5 socks5: diff --git a/app/go.mod b/app/go.mod index dab7e51..2d36411 100644 --- a/app/go.mod +++ b/app/go.mod @@ -25,7 +25,7 @@ require ( github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 go.uber.org/zap v1.24.0 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/sys v0.23.0 + golang.org/x/sys v0.25.0 ) require ( @@ -33,6 +33,8 @@ require ( github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect github.com/cloudflare/circl v1.3.9 // indirect + github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect + github.com/database64128/tfo-go/v2 v2.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect diff --git a/app/go.sum b/app/go.sum index dec519b..1b30feb 100644 --- a/app/go.sum +++ b/app/go.sum @@ -63,6 +63,10 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a h1:t4SDi0pmNkryzKdM4QF3o5vqSP4GRjeZD/6j3nyxNP0= +github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a/go.mod h1:7K2NQKbabB5mBl41vF6YayYl5g7YpDwc4dQ5iMpP3Lg= +github.com/database64128/tfo-go/v2 v2.2.2 h1:BxynF4qGF5ct3DpPLEG62uyJZ3LQhqaf0Ken+kyy7PM= +github.com/database64128/tfo-go/v2 v2.2.2/go.mod h1:2IW8jppdBwdVMjA08uEyMNnqiAHKUlqAA+J8NrsfktY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -463,8 +467,8 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/extras/go.mod b/extras/go.mod index 3da331a..67ef38f 100644 --- a/extras/go.mod +++ b/extras/go.mod @@ -8,6 +8,7 @@ require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 + github.com/database64128/tfo-go/v2 v2.2.2 github.com/hashicorp/golang-lru/v2 v2.0.5 github.com/miekg/dns v1.1.59 github.com/refraction-networking/utls v1.6.6 @@ -21,6 +22,7 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/cloudflare/circl v1.3.9 // indirect + github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect @@ -36,7 +38,7 @@ require ( golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/extras/go.sum b/extras/go.sum index d07ba7c..98616ca 100644 --- a/extras/go.sum +++ b/extras/go.sum @@ -10,6 +10,10 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a h1:t4SDi0pmNkryzKdM4QF3o5vqSP4GRjeZD/6j3nyxNP0= +github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a/go.mod h1:7K2NQKbabB5mBl41vF6YayYl5g7YpDwc4dQ5iMpP3Lg= +github.com/database64128/tfo-go/v2 v2.2.2 h1:BxynF4qGF5ct3DpPLEG62uyJZ3LQhqaf0Ken+kyy7PM= +github.com/database64128/tfo-go/v2 v2.2.2/go.mod h1:2IW8jppdBwdVMjA08uEyMNnqiAHKUlqAA+J8NrsfktY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -92,8 +96,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/extras/outbounds/fastopen.go b/extras/outbounds/fastopen.go new file mode 100644 index 0000000..a607500 --- /dev/null +++ b/extras/outbounds/fastopen.go @@ -0,0 +1,230 @@ +package outbounds + +import ( + "net" + "sync" + "time" + + "github.com/database64128/tfo-go/v2" +) + +type fastOpenDialer struct { + dialer *tfo.Dialer +} + +func newFastOpenDialer(netDialer *net.Dialer) *fastOpenDialer { + return &fastOpenDialer{ + dialer: &tfo.Dialer{ + Dialer: *netDialer, + Fallback: true, + }, + } +} + +// Dial returns immediately without actually establishing a connection. +// The connection will be established by the first Write() call. +func (d *fastOpenDialer) Dial(network, address string) (net.Conn, error) { + return &fastOpenConn{ + dialer: d.dialer, + network: network, + address: address, + readyChan: make(chan struct{}), + }, nil +} + +type fastOpenConn struct { + dialer *tfo.Dialer + network string + address string + + conn net.Conn + connLock sync.RWMutex + readyChan chan struct{} + + // States before connection ready + deadline *time.Time + readDeadline *time.Time + writeDeadline *time.Time +} + +func (c *fastOpenConn) Read(b []byte) (n int, err error) { + c.connLock.RLock() + conn := c.conn + c.connLock.RUnlock() + + if conn != nil { + return conn.Read(b) + } + + // Wait until the connection is ready or closed + <-c.readyChan + + if c.conn == nil { + // This is equivalent to isClosedBeforeReady() == true + return 0, net.ErrClosed + } + + return c.conn.Read(b) +} + +func (c *fastOpenConn) Write(b []byte) (n int, err error) { + c.connLock.RLock() + conn := c.conn + c.connLock.RUnlock() + + if conn != nil { + return conn.Write(b) + } + + c.connLock.RLock() + closed := c.isClosedBeforeReady() + c.connLock.RUnlock() + + if closed { + return 0, net.ErrClosed + } + + c.connLock.Lock() + defer c.connLock.Unlock() + + if c.isClosedBeforeReady() { + // Closed by other goroutine + return 0, net.ErrClosed + } + + conn = c.conn + if conn != nil { + // Established by other goroutine + return conn.Write(b) + } + + conn, err = c.dialer.Dial(c.network, c.address, b) + if err != nil { + close(c.readyChan) + return 0, err + } + + // Apply pre-set states + if c.deadline != nil { + _ = conn.SetDeadline(*c.deadline) + } + if c.readDeadline != nil { + _ = conn.SetReadDeadline(*c.readDeadline) + } + if c.writeDeadline != nil { + _ = conn.SetWriteDeadline(*c.writeDeadline) + } + + c.conn = conn + close(c.readyChan) + return len(b), nil +} + +func (c *fastOpenConn) Close() error { + c.connLock.RLock() + defer c.connLock.RUnlock() + + if c.isClosedBeforeReady() { + return net.ErrClosed + } + + if c.conn != nil { + return c.conn.Close() + } + + close(c.readyChan) + return nil +} + +// isClosedBeforeReady returns true if the connection is closed before the real connection is established. +// This function should be called with connLock.RLock(). +func (c *fastOpenConn) isClosedBeforeReady() bool { + select { + case <-c.readyChan: + if c.conn == nil { + return true + } + default: + } + return false +} + +func (c *fastOpenConn) LocalAddr() net.Addr { + c.connLock.RLock() + defer c.connLock.RUnlock() + + if c.conn != nil { + return c.conn.LocalAddr() + } + + return nil +} + +func (c *fastOpenConn) RemoteAddr() net.Addr { + c.connLock.RLock() + conn := c.conn + c.connLock.RUnlock() + + if conn != nil { + return conn.RemoteAddr() + } + + addr, err := net.ResolveTCPAddr(c.network, c.address) + if err != nil { + return nil + } + return addr +} + +func (c *fastOpenConn) SetDeadline(t time.Time) error { + c.connLock.RLock() + defer c.connLock.RUnlock() + + c.deadline = &t + + if c.conn != nil { + return c.conn.SetDeadline(t) + } + + if c.isClosedBeforeReady() { + return net.ErrClosed + } + + return nil +} + +func (c *fastOpenConn) SetReadDeadline(t time.Time) error { + c.connLock.RLock() + defer c.connLock.RUnlock() + + c.readDeadline = &t + + if c.conn != nil { + return c.conn.SetReadDeadline(t) + } + + if c.isClosedBeforeReady() { + return net.ErrClosed + } + + return nil +} + +func (c *fastOpenConn) SetWriteDeadline(t time.Time) error { + c.connLock.RLock() + defer c.connLock.RUnlock() + + c.writeDeadline = &t + + if c.conn != nil { + return c.conn.SetWriteDeadline(t) + } + + if c.isClosedBeforeReady() { + return net.ErrClosed + } + + return nil +} + +var _ net.Conn = (*fastOpenConn)(nil) diff --git a/extras/outbounds/ob_direct.go b/extras/outbounds/ob_direct.go index b80ac00..de7ddd2 100644 --- a/extras/outbounds/ob_direct.go +++ b/extras/outbounds/ob_direct.go @@ -35,8 +35,8 @@ type directOutbound struct { Mode DirectOutboundMode // Dialer4 and Dialer6 are used for IPv4 and IPv6 TCP connections respectively. - Dialer4 *net.Dialer - Dialer6 *net.Dialer + DialFunc4 func(network, address string) (net.Conn, error) + DialFunc6 func(network, address string) (net.Conn, error) // DeviceName & BindIPs are for UDP connections. They don't use dialers, so we // need to bind them when creating the connection. @@ -45,6 +45,16 @@ type directOutbound struct { BindIP6 net.IP } +type DirectOutboundOptions struct { + Mode DirectOutboundMode + + DeviceName string + BindIP4 net.IP + BindIP6 net.IP + + FastOpen bool +} + type noAddressError struct { IPv4 bool IPv6 bool @@ -84,6 +94,57 @@ func (e resolveError) Unwrap() error { return e.Err } +func NewDirectOutboundWithOptions(opts DirectOutboundOptions) (PluggableOutbound, error) { + dialer4 := &net.Dialer{ + Timeout: defaultDialerTimeout, + } + if opts.BindIP4 != nil { + if opts.BindIP4.To4() == nil { + return nil, errors.New("BindIP4 must be an IPv4 address") + } + dialer4.LocalAddr = &net.TCPAddr{ + IP: opts.BindIP4, + } + } + dialer6 := &net.Dialer{ + Timeout: defaultDialerTimeout, + } + if opts.BindIP6 != nil { + if opts.BindIP6.To4() != nil { + return nil, errors.New("BindIP6 must be an IPv6 address") + } + dialer6.LocalAddr = &net.TCPAddr{ + IP: opts.BindIP6, + } + } + if opts.DeviceName != "" { + err := dialerBindToDevice(dialer4, opts.DeviceName) + if err != nil { + return nil, err + } + err = dialerBindToDevice(dialer6, opts.DeviceName) + if err != nil { + return nil, err + } + } + + dialFunc4 := dialer4.Dial + dialFunc6 := dialer6.Dial + if opts.FastOpen { + dialFunc4 = newFastOpenDialer(dialer4).Dial + dialFunc6 = newFastOpenDialer(dialer6).Dial + } + + return &directOutbound{ + Mode: opts.Mode, + DialFunc4: dialFunc4, + DialFunc6: dialFunc6, + DeviceName: opts.DeviceName, + BindIP4: opts.BindIP4, + BindIP6: opts.BindIP6, + }, nil +} + // NewDirectOutboundSimple creates a new directOutbound with the given mode, // without binding to a specific device. Works on all platforms. func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound { @@ -91,9 +152,9 @@ func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound { Timeout: defaultDialerTimeout, } return &directOutbound{ - Mode: mode, - Dialer4: d, - Dialer6: d, + Mode: mode, + DialFunc4: d.Dial, + DialFunc6: d.Dial, } } @@ -102,34 +163,20 @@ func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound { // can be nil, in which case the directOutbound will not bind to a specific address // for that family. func NewDirectOutboundBindToIPs(mode DirectOutboundMode, bindIP4, bindIP6 net.IP) (PluggableOutbound, error) { - if bindIP4 != nil && bindIP4.To4() == nil { - return nil, errors.New("bindIP4 must be an IPv4 address") - } - if bindIP6 != nil && bindIP6.To4() != nil { - return nil, errors.New("bindIP6 must be an IPv6 address") - } - ob := &directOutbound{ - Mode: mode, - Dialer4: &net.Dialer{ - Timeout: defaultDialerTimeout, - }, - Dialer6: &net.Dialer{ - Timeout: defaultDialerTimeout, - }, + return NewDirectOutboundWithOptions(DirectOutboundOptions{ + Mode: mode, BindIP4: bindIP4, BindIP6: bindIP6, - } - if bindIP4 != nil { - ob.Dialer4.LocalAddr = &net.TCPAddr{ - IP: bindIP4, - } - } - if bindIP6 != nil { - ob.Dialer6.LocalAddr = &net.TCPAddr{ - IP: bindIP6, - } - } - return ob, nil + }) +} + +// NewDirectOutboundBindToDevice creates a new directOutbound with the given mode, +// and binds to the given device. Only works on Linux. +func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) { + return NewDirectOutboundWithOptions(DirectOutboundOptions{ + Mode: mode, + DeviceName: deviceName, + }) } // resolve is our built-in DNS resolver for handling the case when @@ -201,9 +248,9 @@ func (d *directOutbound) TCP(reqAddr *AddrEx) (net.Conn, error) { func (d *directOutbound) dialTCP(ip net.IP, port uint16) (net.Conn, error) { if ip.To4() != nil { - return d.Dialer4.Dial("tcp4", net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))) + return d.DialFunc4("tcp4", net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))) } else { - return d.Dialer6.Dial("tcp6", net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))) + return d.DialFunc6("tcp6", net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))) } } diff --git a/extras/outbounds/ob_direct_linux.go b/extras/outbounds/ob_direct_linux.go index 33b7d09..5607e50 100644 --- a/extras/outbounds/ob_direct_linux.go +++ b/extras/outbounds/ob_direct_linux.go @@ -6,31 +6,31 @@ import ( "syscall" ) -// NewDirectOutboundBindToDevice creates a new directOutbound with the given mode, -// and binds to the given device. Only works on Linux. -func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) { +func dialerBindToDevice(dialer *net.Dialer, deviceName string) error { if err := verifyDeviceName(deviceName); err != nil { - return nil, err + return err } - d := &net.Dialer{ - Timeout: defaultDialerTimeout, - Control: func(network, address string, c syscall.RawConn) error { - var errBind error - err := c.Control(func(fd uintptr) { - errBind = syscall.BindToDevice(int(fd), deviceName) - }) + + originControl := dialer.Control + dialer.Control = func(network, address string, c syscall.RawConn) error { + if originControl != nil { + // Chaining other control function + err := originControl(network, address, c) if err != nil { return err } - return errBind - }, + } + + var errBind error + err := c.Control(func(fd uintptr) { + errBind = syscall.BindToDevice(int(fd), deviceName) + }) + if err != nil { + return err + } + return errBind } - return &directOutbound{ - Mode: mode, - Dialer4: d, - Dialer6: d, - DeviceName: deviceName, - }, nil + return nil } func verifyDeviceName(deviceName string) error { diff --git a/extras/outbounds/ob_direct_others.go b/extras/outbounds/ob_direct_others.go index b416c30..eeedc84 100644 --- a/extras/outbounds/ob_direct_others.go +++ b/extras/outbounds/ob_direct_others.go @@ -7,11 +7,8 @@ import ( "net" ) -// NewDirectOutboundBindToDevice creates a new directOutbound with the given mode, -// and binds to the given device. This doesn't work on non-Linux platforms, so this -// is just a stub function that always returns an error. -func NewDirectOutboundBindToDevice(mode DirectOutboundMode, deviceName string) (PluggableOutbound, error) { - return nil, errors.New("binding to device is not supported on this platform") +func dialerBindToDevice(dialer *net.Dialer, deviceName string) error { + return errors.New("binding to device is not supported on this platform") } func udpConnBindToDevice(conn *net.UDPConn, deviceName string) error { From d8c61c59d746a2c496c0a61751dc5ebf25da9beb Mon Sep 17 00:00:00 2001 From: Haruue Date: Sat, 23 Nov 2024 22:31:14 +0900 Subject: [PATCH 13/31] chore: disable fallback mode of tfo dialer tfo-go caches the "unsupported" status when fallback mode is enabled. In other words, if the hysteria server is started with net.ipv4.tcp_fastopen=0 and it fails once, the tfo will not be enabled until it is restarted, even if the user later sets sysctl net.ipv4.tcp_fastopen=3. --- extras/outbounds/fastopen.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extras/outbounds/fastopen.go b/extras/outbounds/fastopen.go index a607500..1d5d1ee 100644 --- a/extras/outbounds/fastopen.go +++ b/extras/outbounds/fastopen.go @@ -15,8 +15,7 @@ type fastOpenDialer struct { func newFastOpenDialer(netDialer *net.Dialer) *fastOpenDialer { return &fastOpenDialer{ dialer: &tfo.Dialer{ - Dialer: *netDialer, - Fallback: true, + Dialer: *netDialer, }, } } From 5e11ea18fb9d02e19d545eee2749e350640419ed Mon Sep 17 00:00:00 2001 From: Toby Date: Tue, 10 Dec 2024 22:42:25 -0800 Subject: [PATCH 14/31] chore: update core/go.mod --- core/go.mod | 2 +- core/go.sum | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/core/go.mod b/core/go.mod index beb0372..213ff5a 100644 --- a/core/go.mod +++ b/core/go.mod @@ -27,7 +27,7 @@ require ( golang.org/x/crypto v0.26.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/protobuf v1.34.1 // indirect diff --git a/core/go.sum b/core/go.sum index d65498b..fdb5c63 100644 --- a/core/go.sum +++ b/core/go.sum @@ -58,8 +58,7 @@ golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= From 400fed3bd607d5f529487aa07d7f4d630c802ae4 Mon Sep 17 00:00:00 2001 From: Haruue Date: Wed, 11 Dec 2024 18:05:11 +0900 Subject: [PATCH 15/31] chore(version): rename LibVersion to Libraries close: #1271 A key that also contains "Version" broke the version parsing of some third-party clients. --- app/cmd/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/cmd/root.go b/app/cmd/root.go index a58e2bc..13f9705 100644 --- a/app/cmd/root.go +++ b/app/cmd/root.go @@ -45,7 +45,7 @@ var ( "CommitHash:\t%s\n"+ "Platform:\t%s\n"+ "Architecture:\t%s\n"+ - "LibVersion:\t%s", + "Libraries:\tquic-go=%s", appVersion, appDate, appType, appToolchain, appCommit, appPlatform, appArch, libVersion) appAboutLong = fmt.Sprintf("%s\n%s\n%s\n\n%s", appLogo, appDesc, appAuthors, appVersionLong) From 53a4ce2598f6b169554cf17c74500e662979a614 Mon Sep 17 00:00:00 2001 From: Haruue Date: Sun, 29 Dec 2024 13:33:32 +0900 Subject: [PATCH 16/31] fix: tun failed on linux when ipv6.disable=1 close: #1285 --- app/internal/tun/check_ipv6_others.go | 14 ++++++++++++++ app/internal/tun/check_ipv6_unix.go | 16 ++++++++++++++++ app/internal/tun/check_ipv6_windows.go | 24 ++++++++++++++++++++++++ app/internal/tun/server.go | 4 ++++ 4 files changed, 58 insertions(+) create mode 100644 app/internal/tun/check_ipv6_others.go create mode 100644 app/internal/tun/check_ipv6_unix.go create mode 100644 app/internal/tun/check_ipv6_windows.go diff --git a/app/internal/tun/check_ipv6_others.go b/app/internal/tun/check_ipv6_others.go new file mode 100644 index 0000000..7cfd9ab --- /dev/null +++ b/app/internal/tun/check_ipv6_others.go @@ -0,0 +1,14 @@ +//go:build !unix && !windows + +package tun + +import "net" + +func isIPv6Supported() bool { + lis, err := net.ListenPacket("udp6", "[::1]:0") + if err != nil { + return false + } + _ = lis.Close() + return true +} diff --git a/app/internal/tun/check_ipv6_unix.go b/app/internal/tun/check_ipv6_unix.go new file mode 100644 index 0000000..8fdffaf --- /dev/null +++ b/app/internal/tun/check_ipv6_unix.go @@ -0,0 +1,16 @@ +//go:build unix + +package tun + +import ( + "golang.org/x/sys/unix" +) + +func isIPv6Supported() bool { + sock, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_UDP) + if err != nil { + return false + } + _ = unix.Close(sock) + return true +} diff --git a/app/internal/tun/check_ipv6_windows.go b/app/internal/tun/check_ipv6_windows.go new file mode 100644 index 0000000..d488d7e --- /dev/null +++ b/app/internal/tun/check_ipv6_windows.go @@ -0,0 +1,24 @@ +//go:build windows + +package tun + +import ( + "golang.org/x/sys/windows" +) + +func isIPv6Supported() bool { + var wsaData windows.WSAData + err := windows.WSAStartup(uint32(0x202), &wsaData) + if err != nil { + // Failing silently: it is not our duty to report such errors + return true + } + defer windows.WSACleanup() + + sock, err := windows.Socket(windows.AF_INET6, windows.SOCK_DGRAM, windows.IPPROTO_UDP) + if err != nil { + return false + } + _ = windows.Closesocket(sock) + return true +} diff --git a/app/internal/tun/server.go b/app/internal/tun/server.go index 303d4ec..a999051 100644 --- a/app/internal/tun/server.go +++ b/app/internal/tun/server.go @@ -49,6 +49,10 @@ type EventLogger interface { } func (s *Server) Serve() error { + if !isIPv6Supported() { + s.Logger.Warn("tun-pre-check", zap.String("msg", "IPv6 is not supported or enabled on this system, TUN device is created without IPv6 support.")) + s.Inet6Address = nil + } tunOpts := tun.Options{ Name: s.IfName, Inet4Address: s.Inet4Address, From 2bdaf7b46ad9fc5e7a24196400c7acf1796a1aa5 Mon Sep 17 00:00:00 2001 From: Haruue Date: Sun, 29 Dec 2024 13:58:12 +0900 Subject: [PATCH 17/31] feat: allow skip cert verify in masquerade.proxy close: #1278 masquerade.proxy.insecureSkipVerify --- app/cmd/server.go | 25 +++++++++++++++++++++++-- app/cmd/server_test.go | 5 +++-- app/cmd/server_test.yaml | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/cmd/server.go b/app/cmd/server.go index 1384dd8..2368c38 100644 --- a/app/cmd/server.go +++ b/app/cmd/server.go @@ -236,8 +236,9 @@ type serverConfigMasqueradeFile struct { } type serverConfigMasqueradeProxy struct { - URL string `mapstructure:"url"` - RewriteHost bool `mapstructure:"rewriteHost"` + URL string `mapstructure:"url"` + RewriteHost bool `mapstructure:"rewriteHost"` + InsecureSkipVerify bool `mapstructure:"insecureSkipVerify"` } type serverConfigMasqueradeString struct { @@ -810,6 +811,25 @@ func (c *serverConfig) fillMasqHandler(hyConfig *server.Config) error { if u.Scheme != "http" && u.Scheme != "https" { return configError{Field: "masquerade.proxy.url", Err: fmt.Errorf("unsupported protocol scheme \"%s\"", u.Scheme)} } + transport := http.DefaultTransport + if c.Masquerade.Proxy.InsecureSkipVerify { + transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + // use default configs from http.DefaultTransport + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } + } handler = &httputil.ReverseProxy{ Rewrite: func(r *httputil.ProxyRequest) { r.SetURL(u) @@ -819,6 +839,7 @@ func (c *serverConfig) fillMasqHandler(hyConfig *server.Config) error { r.Out.Host = r.In.Host } }, + Transport: transport, ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { logger.Error("HTTP reverse proxy error", zap.Error(err)) w.WriteHeader(http.StatusBadGateway) diff --git a/app/cmd/server_test.go b/app/cmd/server_test.go index bcf61c3..dd2c909 100644 --- a/app/cmd/server_test.go +++ b/app/cmd/server_test.go @@ -169,8 +169,9 @@ func TestServerConfig(t *testing.T) { Dir: "/www/masq", }, Proxy: serverConfigMasqueradeProxy{ - URL: "https://some.site.net", - RewriteHost: true, + URL: "https://some.site.net", + RewriteHost: true, + InsecureSkipVerify: true, }, String: serverConfigMasqueradeString{ Content: "aint nothin here", diff --git a/app/cmd/server_test.yaml b/app/cmd/server_test.yaml index dda6d98..3d9a308 100644 --- a/app/cmd/server_test.yaml +++ b/app/cmd/server_test.yaml @@ -132,6 +132,7 @@ masquerade: proxy: url: https://some.site.net rewriteHost: true + insecureSkipVerify: true string: content: aint nothin here headers: From 8aa80c233e2c6b28448fc28e08559ff24fa9d887 Mon Sep 17 00:00:00 2001 From: Toby Date: Sun, 29 Dec 2024 11:25:08 -0800 Subject: [PATCH 18/31] fix: rename insecureSkipVerify to insecure for consistency --- app/cmd/server.go | 8 ++++---- app/cmd/server_test.go | 6 +++--- app/cmd/server_test.yaml | 2 +- core/go.sum | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/cmd/server.go b/app/cmd/server.go index 2368c38..5f2d562 100644 --- a/app/cmd/server.go +++ b/app/cmd/server.go @@ -236,9 +236,9 @@ type serverConfigMasqueradeFile struct { } type serverConfigMasqueradeProxy struct { - URL string `mapstructure:"url"` - RewriteHost bool `mapstructure:"rewriteHost"` - InsecureSkipVerify bool `mapstructure:"insecureSkipVerify"` + URL string `mapstructure:"url"` + RewriteHost bool `mapstructure:"rewriteHost"` + Insecure bool `mapstructure:"insecure"` } type serverConfigMasqueradeString struct { @@ -812,7 +812,7 @@ func (c *serverConfig) fillMasqHandler(hyConfig *server.Config) error { return configError{Field: "masquerade.proxy.url", Err: fmt.Errorf("unsupported protocol scheme \"%s\"", u.Scheme)} } transport := http.DefaultTransport - if c.Masquerade.Proxy.InsecureSkipVerify { + if c.Masquerade.Proxy.Insecure { transport = &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, diff --git a/app/cmd/server_test.go b/app/cmd/server_test.go index dd2c909..5849a38 100644 --- a/app/cmd/server_test.go +++ b/app/cmd/server_test.go @@ -169,9 +169,9 @@ func TestServerConfig(t *testing.T) { Dir: "/www/masq", }, Proxy: serverConfigMasqueradeProxy{ - URL: "https://some.site.net", - RewriteHost: true, - InsecureSkipVerify: true, + URL: "https://some.site.net", + RewriteHost: true, + Insecure: true, }, String: serverConfigMasqueradeString{ Content: "aint nothin here", diff --git a/app/cmd/server_test.yaml b/app/cmd/server_test.yaml index 3d9a308..b989b97 100644 --- a/app/cmd/server_test.yaml +++ b/app/cmd/server_test.yaml @@ -132,7 +132,7 @@ masquerade: proxy: url: https://some.site.net rewriteHost: true - insecureSkipVerify: true + insecure: true string: content: aint nothin here headers: diff --git a/core/go.sum b/core/go.sum index fdb5c63..3caf57a 100644 --- a/core/go.sum +++ b/core/go.sum @@ -59,6 +59,7 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= From 817d6c9a2d0899210d848c885bf4e7a655f32c73 Mon Sep 17 00:00:00 2001 From: zyppe <734935956@qq.com> Date: Sat, 4 Jan 2025 22:45:11 +0800 Subject: [PATCH 19/31] Add support for loongarch64 Test on Loongson 3A5000 --- hyperbole.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hyperbole.py b/hyperbole.py index ecc248d..13dcd0a 100755 --- a/hyperbole.py +++ b/hyperbole.py @@ -74,6 +74,9 @@ ARCH_ALIASES = { "GOARCH": "amd64", "GOAMD64": "v3", }, + "loong64": { + "GOARCH": "loong64", + }, } From 537e8144ea5eea314dd6c5393f31f88533822054 Mon Sep 17 00:00:00 2001 From: Haruue Date: Wed, 8 Jan 2025 14:56:15 +0900 Subject: [PATCH 20/31] ci: add linux/loong64 to platforms.txt --- platforms.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/platforms.txt b/platforms.txt index ea0ddf3..9059333 100644 --- a/platforms.txt +++ b/platforms.txt @@ -22,6 +22,7 @@ linux/s390x linux/mipsle linux/mipsle-sf linux/riscv64 +linux/loong64 # Android android/386 From d86aa0b4e21ffb8b8175b29af99d2d8d612ecb06 Mon Sep 17 00:00:00 2001 From: Haruue Date: Wed, 8 Jan 2025 14:57:02 +0900 Subject: [PATCH 21/31] chore(scripts): detect arch for loong64 --- scripts/install_server.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/install_server.sh b/scripts/install_server.sh index 4277ab9..93c06d9 100644 --- a/scripts/install_server.sh +++ b/scripts/install_server.sh @@ -436,6 +436,9 @@ check_environment_architecture() { 's390x') ARCHITECTURE='s390x' ;; + 'loongarch64') + ARCHITECTURE='loong64' + ;; *) error "The architecture '$(uname -a)' is not supported." note "Specify ARCHITECTURE= to bypass this check and force this script to run on this $(uname -m)." From e1df8aa4e2aa0100cd46790afbbb0788e0d741f5 Mon Sep 17 00:00:00 2001 From: Haruue Date: Mon, 3 Feb 2025 12:27:44 +0900 Subject: [PATCH 22/31] chore: make username of userpass case insensitive close: #1297 Just a workaround for "uppercase usernames do not work". Usernames in different cases (like "Gawr" and "gawR") will now conflict. --- app/cmd/server.go | 2 +- extras/auth/userpass.go | 13 ++++++++++++- extras/auth/userpass_test.go | 20 +++++++++++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/cmd/server.go b/app/cmd/server.go index 5f2d562..a2aa9a4 100644 --- a/app/cmd/server.go +++ b/app/cmd/server.go @@ -755,7 +755,7 @@ func (c *serverConfig) fillAuthenticator(hyConfig *server.Config) error { if len(c.Auth.UserPass) == 0 { return configError{Field: "auth.userpass", Err: errors.New("empty auth userpass")} } - hyConfig.Authenticator = &auth.UserPassAuthenticator{Users: c.Auth.UserPass} + hyConfig.Authenticator = auth.NewUserPassAuthenticator(c.Auth.UserPass) return nil case "http", "https": if c.Auth.HTTP.URL == "" { diff --git a/extras/auth/userpass.go b/extras/auth/userpass.go index 8faf87a..f1c0184 100644 --- a/extras/auth/userpass.go +++ b/extras/auth/userpass.go @@ -19,6 +19,16 @@ type UserPassAuthenticator struct { Users map[string]string } +func NewUserPassAuthenticator(users map[string]string) *UserPassAuthenticator { + // Usernames are case-insensitive, as they are already lowercased by viper. + // Lowercase it again on our own to make it explicit. + lcUsers := make(map[string]string, len(users)) + for user, pass := range users { + lcUsers[strings.ToLower(user)] = pass + } + return &UserPassAuthenticator{Users: lcUsers} +} + func (a *UserPassAuthenticator) Authenticate(addr net.Addr, auth string, tx uint64) (ok bool, id string) { u, p, ok := splitUserPass(auth) if !ok { @@ -36,5 +46,6 @@ func splitUserPass(auth string) (user, pass string, ok bool) { if len(rs) != 2 { return "", "", false } - return rs[0], rs[1], true + // Usernames are case-insensitive + return strings.ToLower(rs[0]), rs[1], true } diff --git a/extras/auth/userpass_test.go b/extras/auth/userpass_test.go index 05f788e..0f1b568 100644 --- a/extras/auth/userpass_test.go +++ b/extras/auth/userpass_test.go @@ -85,12 +85,26 @@ func TestUserPassAuthenticator(t *testing.T) { wantOk: false, wantId: "", }, + { + name: "case insensitive username", + fields: fields{ + Users: map[string]string{ + "gawR": "gura", + "fubuki": "shirakami", + }, + }, + args: args{ + addr: nil, + auth: "Gawr:gura", + tx: 0, + }, + wantOk: true, + wantId: "gawr", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a := &UserPassAuthenticator{ - Users: tt.fields.Users, - } + a := NewUserPassAuthenticator(tt.fields.Users) gotOk, gotId := a.Authenticate(tt.args.addr, tt.args.auth, tt.args.tx) if gotOk != tt.wantOk { t.Errorf("Authenticate() gotOk = %v, want %v", gotOk, tt.wantOk) From 7652ddcd994caa5c0f1a6ea9025886155547af9c Mon Sep 17 00:00:00 2001 From: Haruue Date: Mon, 3 Feb 2025 12:39:52 +0900 Subject: [PATCH 23/31] chore: unexport UserPassAuthenticator.Users --- extras/auth/userpass.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/auth/userpass.go b/extras/auth/userpass.go index f1c0184..9d11cd9 100644 --- a/extras/auth/userpass.go +++ b/extras/auth/userpass.go @@ -16,7 +16,7 @@ var _ server.Authenticator = &UserPassAuthenticator{} // UserPassAuthenticator checks the provided auth string against a map of username/password pairs. // The format of the auth string must be "username:password". type UserPassAuthenticator struct { - Users map[string]string + users map[string]string } func NewUserPassAuthenticator(users map[string]string) *UserPassAuthenticator { @@ -26,7 +26,7 @@ func NewUserPassAuthenticator(users map[string]string) *UserPassAuthenticator { for user, pass := range users { lcUsers[strings.ToLower(user)] = pass } - return &UserPassAuthenticator{Users: lcUsers} + return &UserPassAuthenticator{users: lcUsers} } func (a *UserPassAuthenticator) Authenticate(addr net.Addr, auth string, tx uint64) (ok bool, id string) { @@ -34,7 +34,7 @@ func (a *UserPassAuthenticator) Authenticate(addr net.Addr, auth string, tx uint if !ok { return false, "" } - rp, ok := a.Users[u] + rp, ok := a.users[u] if !ok || rp != p { return false, "" } From e11ad2b93b0d950e23fcb3ab81650a9dfe5e6a4e Mon Sep 17 00:00:00 2001 From: Toby Date: Mon, 3 Feb 2025 18:04:17 -0800 Subject: [PATCH 24/31] feat: quic-go v0.49.0 --- app/go.mod | 8 ++++---- app/go.sum | 16 ++++++++-------- core/go.mod | 9 +++++---- core/go.sum | 16 ++++++++-------- extras/go.mod | 8 ++++---- extras/go.sum | 16 ++++++++-------- go.work.sum | 2 ++ 7 files changed, 39 insertions(+), 36 deletions(-) diff --git a/app/go.mod b/app/go.mod index 2d36411..8bd01dd 100644 --- a/app/go.mod +++ b/app/go.mod @@ -30,7 +30,7 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 // indirect + github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect @@ -71,16 +71,16 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/vultr/govultr/v3 v3.6.4 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/crypto v0.26.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/app/go.sum b/app/go.sum index 1b30feb..85c45a7 100644 --- a/app/go.sum +++ b/app/go.sum @@ -42,8 +42,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM= -github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 h1:zO38yBOvQ1dLHbSuaU5BFZ8zalnSDQslj+i/9AGOk9s= -github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7/go.mod h1:LoSUY2chVqNQCDyi4IZGqPpXLy1FuCkE37PKwtJvNGg= +github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 h1:oc6//C91pY9gGOBioHeyJrmmpKv/nS8fvTeDpKNPLnI= +github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0/go.mod h1:/mMPNt1MHqduzaVB2qFHnJwam3BR5r5b35GvYouJs/o= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad h1:QzQ2sKpc9o42HNRR8ukM5uMC/RzR2HgZd/Nvaqol2C0= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -300,8 +300,8 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -358,8 +358,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -538,8 +538,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/core/go.mod b/core/go.mod index 213ff5a..1eac2dc 100644 --- a/core/go.mod +++ b/core/go.mod @@ -5,7 +5,7 @@ go 1.22 toolchain go1.23.2 require ( - github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 + github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 github.com/stretchr/testify v1.9.0 go.uber.org/goleak v1.2.1 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 @@ -23,13 +23,14 @@ require ( github.com/quic-go/qpack v0.5.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/mock v0.5.0 // indirect golang.org/x/crypto v0.26.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/core/go.sum b/core/go.sum index 3caf57a..33e6d03 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,5 +1,5 @@ -github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 h1:zO38yBOvQ1dLHbSuaU5BFZ8zalnSDQslj+i/9AGOk9s= -github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7/go.mod h1:LoSUY2chVqNQCDyi4IZGqPpXLy1FuCkE37PKwtJvNGg= +github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 h1:oc6//C91pY9gGOBioHeyJrmmpKv/nS8fvTeDpKNPLnI= +github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0/go.mod h1:/mMPNt1MHqduzaVB2qFHnJwam3BR5r5b35GvYouJs/o= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -45,14 +45,14 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= @@ -64,8 +64,8 @@ golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/extras/go.mod b/extras/go.mod index 67ef38f..1ae6146 100644 --- a/extras/go.mod +++ b/extras/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.2 require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 - github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 + github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/database64128/tfo-go/v2 v2.2.2 github.com/hashicorp/golang-lru/v2 v2.0.5 @@ -34,13 +34,13 @@ require ( github.com/quic-go/qpack v0.5.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/mock v0.5.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.18.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/tools v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/extras/go.sum b/extras/go.sum index 98616ca..31595de 100644 --- a/extras/go.sum +++ b/extras/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7 h1:zO38yBOvQ1dLHbSuaU5BFZ8zalnSDQslj+i/9AGOk9s= -github.com/apernet/quic-go v0.48.2-0.20241104191913-cb103fcecfe7/go.mod h1:LoSUY2chVqNQCDyi4IZGqPpXLy1FuCkE37PKwtJvNGg= +github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 h1:oc6//C91pY9gGOBioHeyJrmmpKv/nS8fvTeDpKNPLnI= +github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0/go.mod h1:/mMPNt1MHqduzaVB2qFHnJwam3BR5r5b35GvYouJs/o= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -66,8 +66,8 @@ github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301/go.mod h1:ntmMHL github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= @@ -76,8 +76,8 @@ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -113,8 +113,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/go.work.sum b/go.work.sum index 79da3fa..95d2882 100644 --- a/go.work.sum +++ b/go.work.sum @@ -312,6 +312,8 @@ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= +golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= From ffab01730a6cee644ff091a2ed09e09f9d8ea8d6 Mon Sep 17 00:00:00 2001 From: Toby Date: Tue, 18 Mar 2025 20:44:59 -0700 Subject: [PATCH 25/31] chore: add LICENSE to packages --- app/LICENSE.md | 7 +++++++ core/LICENSE.md | 7 +++++++ extras/LICENSE.md | 7 +++++++ 3 files changed, 21 insertions(+) create mode 100644 app/LICENSE.md create mode 100644 core/LICENSE.md create mode 100644 extras/LICENSE.md diff --git a/app/LICENSE.md b/app/LICENSE.md new file mode 100644 index 0000000..208e8f2 --- /dev/null +++ b/app/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2023 Toby + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/core/LICENSE.md b/core/LICENSE.md new file mode 100644 index 0000000..208e8f2 --- /dev/null +++ b/core/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2023 Toby + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extras/LICENSE.md b/extras/LICENSE.md new file mode 100644 index 0000000..208e8f2 --- /dev/null +++ b/extras/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2023 Toby + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 5239a23aee96c54a372cbb6bd4dd82e65e09321f Mon Sep 17 00:00:00 2001 From: dropbigfish Date: Sun, 20 Apr 2025 12:06:13 +0800 Subject: [PATCH 26/31] chore: fix function name in comment Signed-off-by: dropbigfish --- core/internal/congestion/bbr/packet_number_indexed_queue.go | 2 +- extras/trafficlogger/http.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/internal/congestion/bbr/packet_number_indexed_queue.go b/core/internal/congestion/bbr/packet_number_indexed_queue.go index 86fe52d..08b99de 100644 --- a/core/internal/congestion/bbr/packet_number_indexed_queue.go +++ b/core/internal/congestion/bbr/packet_number_indexed_queue.go @@ -152,7 +152,7 @@ func (p *packetNumberIndexedQueue[T]) EntrySlotsUsed() int { return p.entries.Len() } -// LastPacket returns packet number of the first entry in the queue. +// FirstPacket returns packet number of the first entry in the queue. func (p *packetNumberIndexedQueue[T]) FirstPacket() (packetNumber congestion.PacketNumber) { return p.firstPacket } diff --git a/extras/trafficlogger/http.go b/extras/trafficlogger/http.go index d8e6ebd..8b26217 100644 --- a/extras/trafficlogger/http.go +++ b/extras/trafficlogger/http.go @@ -71,7 +71,7 @@ func (s *trafficStatsServerImpl) LogTraffic(id string, tx, rx uint64) (ok bool) return true } -// LogOnlineStateChanged updates the online state to the online map. +// LogOnlineState updates the online state to the online map. func (s *trafficStatsServerImpl) LogOnlineState(id string, online bool) { s.Mutex.Lock() defer s.Mutex.Unlock() From 29cd04fdef147136afaaafd29c1274f1cbcd8bea Mon Sep 17 00:00:00 2001 From: Toby Date: Sun, 20 Apr 2025 14:04:53 -0700 Subject: [PATCH 27/31] feat: quic-go v0.51.0 (wip) --- app/go.mod | 6 +++--- app/go.sum | 6 ++---- core/client/client.go | 22 +++++++++++++--------- core/go.mod | 6 +++--- core/go.sum | 4 ++-- extras/go.mod | 6 +++--- extras/go.sum | 6 ++---- go.work | 4 ++-- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/go.mod b/app/go.mod index 8bd01dd..be67c49 100644 --- a/app/go.mod +++ b/app/go.mod @@ -1,8 +1,8 @@ module github.com/apernet/hysteria/app/v2 -go 1.22 +go 1.23 -toolchain go1.23.2 +toolchain go1.24.2 require ( github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f @@ -30,7 +30,7 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 // indirect + github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect diff --git a/app/go.sum b/app/go.sum index 85c45a7..2e988eb 100644 --- a/app/go.sum +++ b/app/go.sum @@ -42,8 +42,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM= -github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 h1:oc6//C91pY9gGOBioHeyJrmmpKv/nS8fvTeDpKNPLnI= -github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0/go.mod h1:/mMPNt1MHqduzaVB2qFHnJwam3BR5r5b35GvYouJs/o= +github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c h1:C3a7C/cvdMmgZ1nGc+ctPwVfWlPhcE7J2C63bmlAOD8= +github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad h1:QzQ2sKpc9o42HNRR8ukM5uMC/RzR2HgZd/Nvaqol2C0= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -485,8 +485,6 @@ golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/core/client/client.go b/core/client/client.go index 91d59fd..b9ad433 100644 --- a/core/client/client.go +++ b/core/client/client.go @@ -3,6 +3,7 @@ package client import ( "context" "crypto/tls" + "errors" "net" "net/http" "net/url" @@ -221,18 +222,21 @@ func (c *clientImpl) Close() error { return nil } +var nonPermanentErrors = []error{ + quic.StreamLimitReachedError{}, +} + // wrapIfConnectionClosed checks if the error returned by quic-go -// indicates that the QUIC connection has been permanently closed, -// and if so, wraps the error with coreErrs.ClosedError. -// PITFALL: sometimes quic-go has "internal errors" that are not net.Error, -// but we still need to treat them as ClosedError. +// is recoverable (listed in nonPermanentErrors) or permanent. +// Recoverable errors are returned as-is, +// permanent ones are wrapped as ClosedError. func wrapIfConnectionClosed(err error) error { - netErr, ok := err.(net.Error) - if !ok || !netErr.Temporary() { - return coreErrs.ClosedError{Err: err} - } else { - return err + for _, e := range nonPermanentErrors { + if errors.Is(err, e) { + return err + } } + return coreErrs.ClosedError{Err: err} } type tcpConn struct { diff --git a/core/go.mod b/core/go.mod index 1eac2dc..1cd8e99 100644 --- a/core/go.mod +++ b/core/go.mod @@ -1,11 +1,11 @@ module github.com/apernet/hysteria/core/v2 -go 1.22 +go 1.23 -toolchain go1.23.2 +toolchain go1.24.2 require ( - github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 + github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c github.com/stretchr/testify v1.9.0 go.uber.org/goleak v1.2.1 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 diff --git a/core/go.sum b/core/go.sum index 33e6d03..74f0b3c 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,5 +1,5 @@ -github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 h1:oc6//C91pY9gGOBioHeyJrmmpKv/nS8fvTeDpKNPLnI= -github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0/go.mod h1:/mMPNt1MHqduzaVB2qFHnJwam3BR5r5b35GvYouJs/o= +github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c h1:C3a7C/cvdMmgZ1nGc+ctPwVfWlPhcE7J2C63bmlAOD8= +github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= diff --git a/extras/go.mod b/extras/go.mod index 1ae6146..5bda6c6 100644 --- a/extras/go.mod +++ b/extras/go.mod @@ -1,12 +1,12 @@ module github.com/apernet/hysteria/extras/v2 -go 1.22 +go 1.23 -toolchain go1.23.2 +toolchain go1.24.2 require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 - github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 + github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/database64128/tfo-go/v2 v2.2.2 github.com/hashicorp/golang-lru/v2 v2.0.5 diff --git a/extras/go.sum b/extras/go.sum index 31595de..9bbb21a 100644 --- a/extras/go.sum +++ b/extras/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0 h1:oc6//C91pY9gGOBioHeyJrmmpKv/nS8fvTeDpKNPLnI= -github.com/apernet/quic-go v0.49.1-0.20250204013113-43c72b1281a0/go.mod h1:/mMPNt1MHqduzaVB2qFHnJwam3BR5r5b35GvYouJs/o= +github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c h1:C3a7C/cvdMmgZ1nGc+ctPwVfWlPhcE7J2C63bmlAOD8= +github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -107,8 +107,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/go.work b/go.work index 1ff4f48..1d4fa8b 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,6 @@ -go 1.22 +go 1.23 -toolchain go1.23.2 +toolchain go1.24.2 use ( ./app From c2c4a9545ec5801aab7ce55e19b202229e46461c Mon Sep 17 00:00:00 2001 From: Toby Date: Sun, 20 Apr 2025 14:27:45 -0700 Subject: [PATCH 28/31] fix: broken cc after connection migration --- app/go.mod | 2 +- app/go.sum | 4 ++-- core/go.mod | 2 +- core/go.sum | 4 ++-- extras/go.mod | 2 +- extras/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/go.mod b/app/go.mod index be67c49..d8a68a2 100644 --- a/app/go.mod +++ b/app/go.mod @@ -30,7 +30,7 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c // indirect + github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect diff --git a/app/go.sum b/app/go.sum index 2e988eb..bbacee8 100644 --- a/app/go.sum +++ b/app/go.sum @@ -42,8 +42,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM= -github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c h1:C3a7C/cvdMmgZ1nGc+ctPwVfWlPhcE7J2C63bmlAOD8= -github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= +github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a h1:3UksCgxkac5L2hSbs3rZZVIOSX0EMQEg3K0HtTCoois= +github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad h1:QzQ2sKpc9o42HNRR8ukM5uMC/RzR2HgZd/Nvaqol2C0= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= diff --git a/core/go.mod b/core/go.mod index 1cd8e99..68eed04 100644 --- a/core/go.mod +++ b/core/go.mod @@ -5,7 +5,7 @@ go 1.23 toolchain go1.24.2 require ( - github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c + github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a github.com/stretchr/testify v1.9.0 go.uber.org/goleak v1.2.1 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 diff --git a/core/go.sum b/core/go.sum index 74f0b3c..957f4c5 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,5 +1,5 @@ -github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c h1:C3a7C/cvdMmgZ1nGc+ctPwVfWlPhcE7J2C63bmlAOD8= -github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= +github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a h1:3UksCgxkac5L2hSbs3rZZVIOSX0EMQEg3K0HtTCoois= +github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= diff --git a/extras/go.mod b/extras/go.mod index 5bda6c6..19f1ffc 100644 --- a/extras/go.mod +++ b/extras/go.mod @@ -6,7 +6,7 @@ toolchain go1.24.2 require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 - github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c + github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/database64128/tfo-go/v2 v2.2.2 github.com/hashicorp/golang-lru/v2 v2.0.5 diff --git a/extras/go.sum b/extras/go.sum index 9bbb21a..8457569 100644 --- a/extras/go.sum +++ b/extras/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c h1:C3a7C/cvdMmgZ1nGc+ctPwVfWlPhcE7J2C63bmlAOD8= -github.com/apernet/quic-go v0.51.1-0.20250420202007-25ded0c7e74c/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= +github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a h1:3UksCgxkac5L2hSbs3rZZVIOSX0EMQEg3K0HtTCoois= +github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= From aa5f68a6f7c436b8891a2f2e0b185f13e8312c0d Mon Sep 17 00:00:00 2001 From: Toby Date: Sun, 20 Apr 2025 14:33:40 -0700 Subject: [PATCH 29/31] chore: update go version to 1.24 in workflows --- .github/workflows/master.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 2b852fc..e5689e7 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: "1.23" + go-version: "1.24" - name: Setup Python # This is for the build script uses: actions/setup-python@v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7a2433..a966d86 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: "1.23" + go-version: "1.24" - name: Setup Python # This is for the build script uses: actions/setup-python@v5 From 3a9e952af088649016a595d754964a61a2296279 Mon Sep 17 00:00:00 2001 From: Haruue Date: Tue, 27 May 2025 18:27:54 +0900 Subject: [PATCH 30/31] fix(client): remove share uri in log close: #1355 Since we already have the "share" subcommand, this feature is unnecessary for the "client" subcommand. This commit disables printing the share URI after the client starts, but keeps this behavior for users who specified the `--qr` flag (who may still rely on it) and shows a deprecation warning. --- app/cmd/client.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/cmd/client.go b/app/cmd/client.go index 65bc7e0..05fec80 100644 --- a/app/cmd/client.go +++ b/app/cmd/client.go @@ -470,8 +470,10 @@ func runClient(cmd *cobra.Command, args []string) { defer c.Close() uri := config.URI() - logger.Info("use this URI to share your server", zap.String("uri", uri)) if showQR { + logger.Warn("--qr flag is deprecated and will be removed in future release, " + + "please use `share` subcommand to generate share URI and QR code") + logger.Info("use this URI to share your server", zap.String("uri", uri)) utils.PrintQR(uri) } From b5ddcb5bc49cdee6a2c58084e6afff4063748b3a Mon Sep 17 00:00:00 2001 From: Toby Date: Sat, 7 Jun 2025 11:59:30 -0700 Subject: [PATCH 31/31] feat: quic-go v0.52.0 --- app/go.mod | 2 +- app/go.sum | 4 ++-- core/client/client.go | 1 + core/go.mod | 2 +- core/go.sum | 4 ++-- core/server/server.go | 1 + extras/go.mod | 2 +- extras/go.sum | 4 ++-- 8 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/go.mod b/app/go.mod index d8a68a2..25d1fd3 100644 --- a/app/go.mod +++ b/app/go.mod @@ -30,7 +30,7 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a // indirect + github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431 // indirect github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/database64128/netx-go v0.0.0-20240905055117-62795b8b054a // indirect diff --git a/app/go.sum b/app/go.sum index bbacee8..9bc7ae7 100644 --- a/app/go.sum +++ b/app/go.sum @@ -42,8 +42,8 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f h1:uVh0qpEslrWjgzx9vOcyCqsOY3c9kofDZ1n+qaw35ZY= github.com/apernet/go-tproxy v0.0.0-20230809025308-8f4723fd742f/go.mod h1:xkkq9D4ygcldQQhKS/w9CadiCKwCngU7K9E3DaKahpM= -github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a h1:3UksCgxkac5L2hSbs3rZZVIOSX0EMQEg3K0HtTCoois= -github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= +github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431 h1:9/jM7e+kVALd7Jfu1c27dcEpT/Fd/Gzq2OsQjKjakKI= +github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad h1:QzQ2sKpc9o42HNRR8ukM5uMC/RzR2HgZd/Nvaqol2C0= github.com/apernet/sing-tun v0.2.6-0.20240323130332-b9f6511036ad/go.mod h1:S5IydyLSN/QAfvY+r2GoomPJ6hidtXWm/Ad18sJVssk= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= diff --git a/core/client/client.go b/core/client/client.go index b9ad433..3691d1e 100644 --- a/core/client/client.go +++ b/core/client/client.go @@ -84,6 +84,7 @@ func (c *clientImpl) connect() (*HandshakeInfo, error) { KeepAlivePeriod: c.config.QUICConfig.KeepAlivePeriod, DisablePathMTUDiscovery: c.config.QUICConfig.DisablePathMTUDiscovery, EnableDatagrams: true, + DisablePathManager: true, } // Prepare RoundTripper var conn quic.EarlyConnection diff --git a/core/go.mod b/core/go.mod index 68eed04..a6ba575 100644 --- a/core/go.mod +++ b/core/go.mod @@ -5,7 +5,7 @@ go 1.23 toolchain go1.24.2 require ( - github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a + github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431 github.com/stretchr/testify v1.9.0 go.uber.org/goleak v1.2.1 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 diff --git a/core/go.sum b/core/go.sum index 957f4c5..f44407d 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,5 +1,5 @@ -github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a h1:3UksCgxkac5L2hSbs3rZZVIOSX0EMQEg3K0HtTCoois= -github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= +github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431 h1:9/jM7e+kVALd7Jfu1c27dcEpT/Fd/Gzq2OsQjKjakKI= +github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= diff --git a/core/server/server.go b/core/server/server.go index 696f1d0..89645e0 100644 --- a/core/server/server.go +++ b/core/server/server.go @@ -43,6 +43,7 @@ func NewServer(config *Config) (Server, error) { MaxIncomingStreams: config.QUICConfig.MaxIncomingStreams, DisablePathMTUDiscovery: config.QUICConfig.DisablePathMTUDiscovery, EnableDatagrams: true, + DisablePathManager: true, } listener, err := quic.Listen(config.Conn, tlsConfig, quicConfig) if err != nil { diff --git a/extras/go.mod b/extras/go.mod index 19f1ffc..23b060a 100644 --- a/extras/go.mod +++ b/extras/go.mod @@ -6,7 +6,7 @@ toolchain go1.24.2 require ( github.com/apernet/hysteria/core/v2 v2.0.0-00010101000000-000000000000 - github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a + github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/database64128/tfo-go/v2 v2.2.2 github.com/hashicorp/golang-lru/v2 v2.0.5 diff --git a/extras/go.sum b/extras/go.sum index 8457569..ac6d04a 100644 --- a/extras/go.sum +++ b/extras/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a h1:3UksCgxkac5L2hSbs3rZZVIOSX0EMQEg3K0HtTCoois= -github.com/apernet/quic-go v0.51.1-0.20250420212127-ede9b032759a/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= +github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431 h1:9/jM7e+kVALd7Jfu1c27dcEpT/Fd/Gzq2OsQjKjakKI= +github.com/apernet/quic-go v0.52.1-0.20250607183305-9320c9d14431/go.mod h1:I/47OIGG5H/IfAm+nz2c6hm6b/NkEhpvptAoiPcY7jQ= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=