Skip to content

Commit

Permalink
Merge branch 'apernet:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
tomxiang1 authored Nov 12, 2024
2 parents 915e8b5 + 15e31d4 commit 2db2b8d
Show file tree
Hide file tree
Showing 21 changed files with 533 additions and 29 deletions.
20 changes: 12 additions & 8 deletions app/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
Expand Down
3 changes: 3 additions & 0 deletions app/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
55 changes: 55 additions & 0 deletions app/cmd/share.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
2 changes: 1 addition & 1 deletion app/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions app/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
2 changes: 1 addition & 1 deletion core/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions core/go.sum
Original file line number Diff line number Diff line change
@@ -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=
Expand Down
74 changes: 73 additions & 1 deletion core/internal/integration_tests/mocks/mock_TrafficLogger.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions core/internal/integration_tests/trafficlogger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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")
Expand Down
30 changes: 30 additions & 0 deletions core/internal/utils/atomic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
64 changes: 64 additions & 0 deletions core/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"crypto/tls"
"net"
"net/http"
"sync/atomic"
"time"

"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"
)

Expand Down Expand Up @@ -212,4 +214,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)
}
}
9 changes: 7 additions & 2 deletions core/server/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package server
import (
"errors"
"io"
"time"
)

var errDisconnect = errors.New("traffic logger requested disconnect")
Expand Down Expand Up @@ -31,23 +32,27 @@ 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 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 {
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)
})
}()
// Block until one of the two goroutines returns
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)
Expand Down
Loading

0 comments on commit 2db2b8d

Please sign in to comment.