diff --git a/.github/conf/.goreleaser.yml b/.github/conf/.goreleaser.yml index 0bc5137..ecd783f 100644 --- a/.github/conf/.goreleaser.yml +++ b/.github/conf/.goreleaser.yml @@ -5,7 +5,7 @@ builds: - binary: client env: - CGO_ENABLED=0 - main: ./main.go + main: ./cmd/main.go goos: - linux - windows diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 89059dd..97f41d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,5 +17,5 @@ jobs: with: go-version: 1.21 - name: Build - run: go build --ldflags "-s -w -X github.com/DVKunion/SeaMoon/pkg/consts.Version=${{github.ref_name}}" main.go + run: go build --ldflags "-s -w -X github.com/DVKunion/SeaMoon/pkg/consts.Version=${{github.ref_name}}" cmd/main.go diff --git a/Dockerfile b/Dockerfile index 11d4f21..08b6def 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ COPY .. /src WORKDIR /src ENV CGO_ENABLED 0 ENV VERSION=${VERSION} -RUN go build -ldflags "-X github.com/DVKunion/SeaMoon/server/consts.Version=${VERSION}" -o /tmp/seamoon main.go +RUN go build -ldflags "-X github.com/DVKunion/SeaMoon/server/consts.Version=${VERSION}" -o /tmp/seamoon cmd/main.go RUN chmod +x /tmp/seamoon # run stage FROM alpine:3.19 diff --git a/pkg/client/client.go b/cmd/client/client.go similarity index 84% rename from pkg/client/client.go rename to cmd/client/client.go index 7e736b6..2283056 100644 --- a/pkg/client/client.go +++ b/cmd/client/client.go @@ -1,39 +1,27 @@ package client import ( - "bufio" "context" "html/template" "io" "log/slog" - "net" "net/http" "os" "github.com/gin-gonic/gin" - "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/static" - _ "net/http/pprof" -) - -type Client struct { - net.Conn - br *bufio.Reader -} -func (c *Client) Read(b []byte) (int, error) { - return c.br.Read(b) -} + "github.com/DVKunion/SeaMoon/cmd/client/static" + "github.com/DVKunion/SeaMoon/pkg/consts" +) func Serve(ctx context.Context, verbose bool, debug bool) { ctx, cancel := context.WithCancel(ctx) defer cancel() sg := NewSigGroup() - go Controller(sg, verbose, debug) - go HttpController(ctx, sg) - go Socks5Controller(ctx, sg) + go API(sg, verbose, debug) + go Control(ctx, sg) Config().Load(sg) <-sg.WatchChannel @@ -44,7 +32,7 @@ func Serve(ctx context.Context, verbose bool, debug bool) { sg.wg.Wait() } -func Controller(sg *SigGroup, verbose bool, debug bool) { +func API(sg *SigGroup, verbose bool, debug bool) { slog.Info(consts.CONTROLLER_START, "addr", Config().Control.ConfigAddr) if consts.Version != "dev" || !debug { diff --git a/pkg/client/config.go b/cmd/client/config.go similarity index 88% rename from pkg/client/config.go rename to cmd/client/config.go index 5fa836e..419bb34 100644 --- a/pkg/client/config.go +++ b/cmd/client/config.go @@ -8,6 +8,7 @@ import ( "github.com/BurntSushi/toml" "github.com/DVKunion/SeaMoon/pkg/consts" + "github.com/DVKunion/SeaMoon/pkg/transfer" ) type clientConfig struct { @@ -17,6 +18,16 @@ type clientConfig struct { Socks5 proxyConfig `toml:"socks5"` } +func (c *clientConfig) Addr(t transfer.Type) string { + switch t { + case transfer.HTTP: + return c.Http.ListenAddr + case transfer.SOCKS5: + return c.Socks5.ListenAddr + } + return "" +} + type controlConfig struct { ConfigAddr string `toml:"addr"` LogPath string `toml:"logPath"` diff --git a/cmd/client/control.go b/cmd/client/control.go new file mode 100644 index 0000000..a0bab28 --- /dev/null +++ b/cmd/client/control.go @@ -0,0 +1,83 @@ +package client + +import ( + "context" + "errors" + "log/slog" + "net" + "strings" + + "github.com/DVKunion/SeaMoon/pkg/consts" + "github.com/DVKunion/SeaMoon/pkg/network" + "github.com/DVKunion/SeaMoon/pkg/service" + "github.com/DVKunion/SeaMoon/pkg/transfer" + "github.com/DVKunion/SeaMoon/pkg/tunnel" +) + +func Control(ctx context.Context, sg *SigGroup) { + c, cancel := context.WithCancel(ctx) + defer cancel() + for { + select { + case t := <-sg.StartChannel: + slog.Info(consts.LISTEN_START, "type", t) + sg.wg.Add(1) + go func() { + if err := doListen(c, t); err != nil { + slog.Error(consts.LISTEN_ERROR, "type", t, "err", err) + } + }() + sg.wg.Done() + case t := <-sg.StopChannel: + slog.Info(consts.LISTEN_STOP, "type", t) + cancel() + } + } +} + +func doListen(ctx context.Context, t transfer.Type) error { + server, err := net.Listen("tcp", Config().Addr(t)) + if err != nil { + return err + } + var proxyAddr string + var proxyType tunnel.Type + for _, p := range Config().ProxyAddr { + if strings.HasPrefix(p, "ws://") { + proxyAddr = strings.TrimPrefix(p, "ws://") + proxyType = tunnel.WST + break + } + if strings.HasPrefix(p, "grpc://") { + proxyAddr = p + proxyType = tunnel.GRT + break + } + } + if proxyAddr == "" || proxyType == "" { + return errors.New(consts.PROXY_ADDR_ERROR) + } + go listen(ctx, server, proxyAddr, proxyType, t) + <-ctx.Done() + return nil +} + +func listen(ctx context.Context, server net.Listener, pa string, pt tunnel.Type, t transfer.Type) { + defer server.Close() + for { + conn, err := server.Accept() + if err != nil { + slog.Error(consts.ACCEPT_ERROR, "err", err) + } + if srv, ok := service.Factory[pt]; ok { + destConn, err := srv.Conn(ctx, t, service.WithAddr(pa)) + if err != nil { + slog.Error(consts.CONNECT_RMOET_ERROR, "err", err) + continue + } + if err := network.Transport(conn, destConn); err != nil { + slog.Error(consts.CONNECT_TRANS_ERROR, "err", err) + } + } + } +} diff --git a/pkg/client/signal.go b/cmd/client/signal.go similarity index 66% rename from pkg/client/signal.go rename to cmd/client/signal.go index 2687017..e3b11bd 100644 --- a/pkg/client/signal.go +++ b/cmd/client/signal.go @@ -5,34 +5,23 @@ import ( "os/signal" "sync" "syscall" -) - -type ControlSignal int8 -const ( - HttpProxyStartSignal ControlSignal = iota + 1 - HttpProxyStopSignal - SocksProxyStartSignal - SocksProxyStopSignal + "github.com/DVKunion/SeaMoon/pkg/transfer" ) type SigGroup struct { - wg *sync.WaitGroup - WatchChannel chan os.Signal - HttpStartChannel chan ControlSignal - HttpStopChannel chan ControlSignal - SocksStartChannel chan ControlSignal - SocksStopChannel chan ControlSignal + wg *sync.WaitGroup + WatchChannel chan os.Signal + StartChannel chan transfer.Type + StopChannel chan transfer.Type } func NewSigGroup() *SigGroup { sg := &SigGroup{ new(sync.WaitGroup), make(chan os.Signal, 1), - make(chan ControlSignal, 1), - make(chan ControlSignal, 1), - make(chan ControlSignal, 1), - make(chan ControlSignal, 1), + make(chan transfer.Type, 1), + make(chan transfer.Type, 1), } signal.Notify(sg.WatchChannel, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) return sg @@ -42,7 +31,7 @@ func (sg *SigGroup) StartHttpProxy() { if Config().Http.Status == "active" { return } - sg.HttpStartChannel <- HttpProxyStartSignal + sg.StartChannel <- transfer.HTTP Config().Http.Status = "active" } @@ -50,7 +39,7 @@ func (sg *SigGroup) StopHttpProxy() { if Config().Http.Status == "inactive" { return } - sg.HttpStopChannel <- HttpProxyStopSignal + sg.StopChannel <- transfer.HTTP Config().Http.Status = "inactive" } @@ -58,7 +47,7 @@ func (sg *SigGroup) StartSocksProxy() { if Config().Socks5.Status == "active" { return } - sg.SocksStartChannel <- SocksProxyStartSignal + sg.StartChannel <- transfer.SOCKS5 Config().Socks5.Status = "active" } @@ -66,7 +55,7 @@ func (sg *SigGroup) StopSocksProxy() { if Config().Socks5.Status == "inactive" { return } - sg.SocksStopChannel <- SocksProxyStopSignal + sg.StopChannel <- transfer.SOCKS5 Config().Socks5.Status = "inactive" } diff --git a/static/embed.go b/cmd/client/static/embed.go similarity index 100% rename from static/embed.go rename to cmd/client/static/embed.go diff --git a/static/public/css/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2 b/cmd/client/static/public/css/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2 similarity index 100% rename from static/public/css/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2 rename to cmd/client/static/public/css/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2 diff --git a/static/public/css/S6uyw4BMUTPHjx4wXiWtFCc.woff2 b/cmd/client/static/public/css/S6uyw4BMUTPHjx4wXiWtFCc.woff2 similarity index 100% rename from static/public/css/S6uyw4BMUTPHjx4wXiWtFCc.woff2 rename to cmd/client/static/public/css/S6uyw4BMUTPHjx4wXiWtFCc.woff2 diff --git a/static/public/css/brand-icons.eot b/cmd/client/static/public/css/brand-icons.eot similarity index 100% rename from static/public/css/brand-icons.eot rename to cmd/client/static/public/css/brand-icons.eot diff --git a/static/public/css/brand-icons.svg b/cmd/client/static/public/css/brand-icons.svg similarity index 100% rename from static/public/css/brand-icons.svg rename to cmd/client/static/public/css/brand-icons.svg diff --git a/static/public/css/brand-icons.ttf b/cmd/client/static/public/css/brand-icons.ttf similarity index 100% rename from static/public/css/brand-icons.ttf rename to cmd/client/static/public/css/brand-icons.ttf diff --git a/static/public/css/brand-icons.woff b/cmd/client/static/public/css/brand-icons.woff similarity index 100% rename from static/public/css/brand-icons.woff rename to cmd/client/static/public/css/brand-icons.woff diff --git a/static/public/css/brand-icons.woff2 b/cmd/client/static/public/css/brand-icons.woff2 similarity index 100% rename from static/public/css/brand-icons.woff2 rename to cmd/client/static/public/css/brand-icons.woff2 diff --git a/static/public/css/font.css b/cmd/client/static/public/css/font.css similarity index 94% rename from static/public/css/font.css rename to cmd/client/static/public/css/font.css index 1147a47..201796a 100644 --- a/static/public/css/font.css +++ b/cmd/client/static/public/css/font.css @@ -3,7 +3,7 @@ font-family: 'Lato'; font-style: normal; font-weight: 400; - src: url(/static/public/css/S6uyw4BMUTPHjx4wXiWtFCc.woff2) format('woff2'); + src: url(S6uyw4BMUTPHjx4wXiWtFCc.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @@ -12,7 +12,7 @@ font-family: 'Lato'; font-style: normal; font-weight: 700; - src: url(/static/public/css/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2) format('woff2'); + src: url(S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } diff --git a/static/public/css/icon.min.css b/cmd/client/static/public/css/icon.min.css similarity index 100% rename from static/public/css/icon.min.css rename to cmd/client/static/public/css/icon.min.css diff --git a/static/public/css/icons.eot b/cmd/client/static/public/css/icons.eot similarity index 100% rename from static/public/css/icons.eot rename to cmd/client/static/public/css/icons.eot diff --git a/static/public/css/icons.otf b/cmd/client/static/public/css/icons.otf similarity index 100% rename from static/public/css/icons.otf rename to cmd/client/static/public/css/icons.otf diff --git a/static/public/css/icons.svg b/cmd/client/static/public/css/icons.svg similarity index 100% rename from static/public/css/icons.svg rename to cmd/client/static/public/css/icons.svg diff --git a/static/public/css/icons.ttf b/cmd/client/static/public/css/icons.ttf similarity index 100% rename from static/public/css/icons.ttf rename to cmd/client/static/public/css/icons.ttf diff --git a/static/public/css/icons.woff b/cmd/client/static/public/css/icons.woff similarity index 100% rename from static/public/css/icons.woff rename to cmd/client/static/public/css/icons.woff diff --git a/static/public/css/icons.woff2 b/cmd/client/static/public/css/icons.woff2 similarity index 100% rename from static/public/css/icons.woff2 rename to cmd/client/static/public/css/icons.woff2 diff --git a/static/public/css/index.css b/cmd/client/static/public/css/index.css similarity index 100% rename from static/public/css/index.css rename to cmd/client/static/public/css/index.css diff --git a/static/public/css/outline-icons.eot b/cmd/client/static/public/css/outline-icons.eot similarity index 100% rename from static/public/css/outline-icons.eot rename to cmd/client/static/public/css/outline-icons.eot diff --git a/static/public/css/outline-icons.svg b/cmd/client/static/public/css/outline-icons.svg similarity index 100% rename from static/public/css/outline-icons.svg rename to cmd/client/static/public/css/outline-icons.svg diff --git a/static/public/css/outline-icons.ttf b/cmd/client/static/public/css/outline-icons.ttf similarity index 100% rename from static/public/css/outline-icons.ttf rename to cmd/client/static/public/css/outline-icons.ttf diff --git a/static/public/css/outline-icons.woff b/cmd/client/static/public/css/outline-icons.woff similarity index 100% rename from static/public/css/outline-icons.woff rename to cmd/client/static/public/css/outline-icons.woff diff --git a/static/public/css/outline-icons.woff2 b/cmd/client/static/public/css/outline-icons.woff2 similarity index 100% rename from static/public/css/outline-icons.woff2 rename to cmd/client/static/public/css/outline-icons.woff2 diff --git a/static/public/css/semantic.min.css b/cmd/client/static/public/css/semantic.min.css similarity index 100% rename from static/public/css/semantic.min.css rename to cmd/client/static/public/css/semantic.min.css diff --git a/static/public/img/favicon.ico b/cmd/client/static/public/img/favicon.ico similarity index 100% rename from static/public/img/favicon.ico rename to cmd/client/static/public/img/favicon.ico diff --git a/static/public/img/logo.png b/cmd/client/static/public/img/logo.png similarity index 100% rename from static/public/img/logo.png rename to cmd/client/static/public/img/logo.png diff --git a/static/public/js/index.js b/cmd/client/static/public/js/index.js similarity index 100% rename from static/public/js/index.js rename to cmd/client/static/public/js/index.js diff --git a/static/public/js/jquery-3.1.1.min.js b/cmd/client/static/public/js/jquery-3.1.1.min.js similarity index 100% rename from static/public/js/jquery-3.1.1.min.js rename to cmd/client/static/public/js/jquery-3.1.1.min.js diff --git a/static/public/js/semantic.min.js b/cmd/client/static/public/js/semantic.min.js similarity index 100% rename from static/public/js/semantic.min.js rename to cmd/client/static/public/js/semantic.min.js diff --git a/static/templates/index.html b/cmd/client/static/templates/index.html similarity index 95% rename from static/templates/index.html rename to cmd/client/static/templates/index.html index 8a2cd60..d650455 100644 --- a/static/templates/index.html +++ b/cmd/client/static/templates/index.html @@ -119,12 +119,12 @@

代理

高级功能

-
-
- - -
-
+{{/*
*/}} +{{/*
*/}} +{{/* */}} +{{/* */}} +{{/*
*/}} +{{/*
*/}} diff --git a/main.go b/cmd/main.go similarity index 95% rename from main.go rename to cmd/main.go index 9018263..706d2de 100644 --- a/main.go +++ b/cmd/main.go @@ -6,9 +6,9 @@ import ( "github.com/spf13/cobra" - "github.com/DVKunion/SeaMoon/pkg/client" + "github.com/DVKunion/SeaMoon/cmd/client" + "github.com/DVKunion/SeaMoon/cmd/server" "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/server" ) var ( diff --git a/server/options.go b/cmd/server/options.go similarity index 100% rename from server/options.go rename to cmd/server/options.go diff --git a/server/server.go b/cmd/server/server.go similarity index 96% rename from server/server.go rename to cmd/server/server.go index 285693e..2d1cf2a 100644 --- a/server/server.go +++ b/cmd/server/server.go @@ -7,7 +7,7 @@ import ( "strings" net "github.com/DVKunion/SeaMoon/pkg/network" - "github.com/DVKunion/SeaMoon/server/service" + "github.com/DVKunion/SeaMoon/pkg/service" ) type Server struct { diff --git a/go.mod b/go.mod index 69c1ea6..778b900 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,7 @@ go 1.21 require ( github.com/BurntSushi/toml v1.3.2 github.com/gin-gonic/gin v1.9.1 - github.com/google/martian/v3 v3.3.2 github.com/gorilla/websocket v1.5.1 - github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.8.0 github.com/tg123/go-htpasswd v1.2.0 github.com/xtaci/smux v1.5.24 @@ -26,7 +24,6 @@ require ( github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect diff --git a/go.sum b/go.sum index 6b72fd1..a2357ef 100644 --- a/go.sum +++ b/go.sum @@ -51,9 +51,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -63,8 +60,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= @@ -86,8 +81,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -131,7 +124,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -164,7 +156,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/client/http.go b/pkg/client/http.go deleted file mode 100644 index d3ec9b0..0000000 --- a/pkg/client/http.go +++ /dev/null @@ -1,100 +0,0 @@ -package client - -import ( - "context" - "crypto/tls" - "log/slog" - "net" - "net/http" - "net/url" - "strings" - "time" - - "github.com/google/martian/v3" - - "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/network" -) - -func HttpController(ctx context.Context, sg *SigGroup) { - c, cancel := context.WithCancel(ctx) - defer cancel() - for { - select { - case <-sg.HttpStartChannel: - server, err := net.Listen("tcp", Config().Http.ListenAddr) - if err != nil { - slog.Error(consts.HTTP_LISTEN_ERROR, "err", err) - return - } - var proxyAddr string - for _, p := range Config().ProxyAddr { - if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") { - proxyAddr = p - } else if strings.HasPrefix(p, "http-proxy") { - proxyAddr = "http://" + p - } - } - if proxyAddr == "" { - slog.Error(consts.PROXY_ADDR_ERROR) - break - } - sg.wg.Add(1) - go func() { - NewHttpClient(c, server, proxyAddr) - sg.wg.Done() - }() - case <-sg.HttpStopChannel: - slog.Info(consts.HTTP_LISTEN_STOP) - cancel() - } - } -} - -func NewRequestModifier(pAddr string) *RequestModifier { - return &RequestModifier{pAddr} -} - -// RequestModifier impl martian.RequestModifier -type RequestModifier struct { - pAddr string -} - -// ModifyRequest is a RequestModifier logs all request url -func (r RequestModifier) ModifyRequest(req *http.Request) error { - if req.Method == http.MethodConnect { - return nil - } - req.Header.Set("SM-Host", network.GetUrl(req)) - req.URL, _ = url.Parse(r.pAddr) - req.Host = req.URL.Host - return nil -} - -func NewHttpClient(ctx context.Context, l net.Listener, pAddr string) { - slog.Info(consts.HTTP_LISTEN_START, "addr", l.Addr()) - p := martian.NewProxy() - defer p.Close() - tr := &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 10 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: time.Second, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - } - p.SetRoundTripper(tr) - logger := NewRequestModifier(pAddr) - - p.SetRequestModifier(logger) - - go func() { - if err := p.Serve(l); err != nil { - slog.Error("client server error:", "err", err) - } - }() - - <-ctx.Done() -} diff --git a/pkg/client/socks.go b/pkg/client/socks.go deleted file mode 100644 index 3cce6c2..0000000 --- a/pkg/client/socks.go +++ /dev/null @@ -1,168 +0,0 @@ -package client - -import ( - "bufio" - "context" - "log/slog" - "net" - "net/http" - "strings" - "sync" - - "github.com/gorilla/websocket" - - "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/network" - "github.com/DVKunion/SeaMoon/pkg/tunnel" -) - -type bufferedConn struct { - net.Conn - br *bufio.Reader -} - -func (c *bufferedConn) Read(b []byte) (int, error) { - return c.br.Read(b) -} - -func Socks5Controller(ctx context.Context, sg *SigGroup) { - c, cancel := context.WithCancel(ctx) - defer cancel() - for { - select { - case <-sg.SocksStartChannel: - - server, err := net.Listen("tcp", Config().Socks5.ListenAddr) - if err != nil { - slog.Error(consts.SOCKS5_LISTEN_ERROR, err) - return - } - var proxyAddr string - for _, p := range Config().ProxyAddr { - if strings.HasPrefix(p, "ws://") || strings.HasPrefix(p, "wss://") { - proxyAddr = p - } else if strings.HasPrefix(p, "socks-proxy") { - proxyAddr = "ws://" + p - } - } - if proxyAddr == "" { - slog.Error(consts.PROXY_ADDR_ERROR) - break - } - sg.wg.Add(1) - go func() { - NewSocks5Client(c, server, proxyAddr) - sg.wg.Done() - }() - case <-sg.SocksStopChannel: - slog.Info(consts.SOCKS5_LISTEN_STOP) - cancel() - } - } -} - -func NewSocks5Client(ctx context.Context, server net.Listener, proxyAddr string) { - var closeFlag = false - slog.Info(consts.SOCKS5_LISTEN_START, "addr", server.Addr()) - slog.Debug(consts.PROXY_ADDR, "proxy", proxyAddr) - defer func() { - closeFlag = true - server.Close() - }() - go func() { - for { - lock := &sync.Mutex{} - conn, err := server.Accept() - if err == nil { - slog.Debug(consts.SOCKS5_ACCEPT_START, "addr", conn.RemoteAddr()) - br := bufio.NewReader(conn) - b, err := br.Peek(1) - if err != nil || b[0] != network.SOCKS5Version { - slog.Error(consts.CLIENT_PROTOCOL_UNSUPPORT_ERROR, "err", err) - } else { - go Socks5Handler(&bufferedConn{conn, br}, proxyAddr, lock) - } - } else { - if closeFlag { - // except close - return - } else { - slog.Error(consts.SOCKS5_ACCEPT_ERROR, "err", err) - } - } - } - }() - <-ctx.Done() -} - -func Socks5Handler(conn net.Conn, raddr string, lock *sync.Mutex) { - // select method - _, err := network.ReadMethods(conn) - if err != nil { - slog.Error(`[socks5] read methods failed`, "err", err) - return - } - - // TODO AUTH - if err := network.WriteMethod(network.MethodNoAuth, conn); err != nil { - if err != nil { - slog.Error(`[socks5] write method failed`, "err", err) - } else { - slog.Error(`[socks5] methods is not acceptable`) - } - return - } - - // read command - request, err := network.ReadSOCKS5Request(conn) - if err != nil { - slog.Error(`[socks5] read command failed`, "err", err) - return - } - switch request.Cmd { - case network.SOCKS5CmdConnect: - handleConnect(conn, request, raddr, lock) - break - case network.SOCKS5CmdBind: - slog.Error("not support cmd bind") - //handleBind(conn, request) - break - case network.SOCKS5CmdUDPOverTCP: - //handleUDP(conn, request) - slog.Error("not support cmd upd") - break - } -} - -func handleConnect(conn net.Conn, req *network.SOCKS5Request, rAddr string, lock *sync.Mutex) { - - slog.Info(consts.SOCKS5_CONNECT_SERVER, "src", conn.RemoteAddr(), "dest", req.Addr) - - dialer := &websocket.Dialer{} - s := http.Header{} - s.Set("SM-CMD", "CONNECT") - s.Set("SM-TARGET", req.Addr.String()) - wsConn, _, err := dialer.Dial(rAddr, s) - - if err != nil { - slog.Error(consts.SOCKS_UPGRADE_ERROR, "err", err) - return - } - - newConn := tunnel.WsWrapConn(wsConn) - - defer newConn.Close() - - if err := network.NewReply(network.SOCKS5RespSucceeded, nil).Write(conn); err != nil { - slog.Error(consts.SOCKS5_CONNECT_WRITE_ERROR, "err", err) - return - } - slog.Info(consts.SOCKS5_CONNECT_ESTAB, "src", conn.RemoteAddr(), "dest", req.Addr) - - if err := network.Transport(conn, newConn); err != nil { - slog.Error(consts.SOCKS5_CONNECT_TRANS_ERROR, "err", err) - } - - slog.Info(consts.SOCKS5_CONNECT_DIS, "src", conn.RemoteAddr(), "dest", req.Addr) - -} diff --git a/pkg/consts/log.go b/pkg/consts/log.go index 97244ea..d6edbc0 100644 --- a/pkg/consts/log.go +++ b/pkg/consts/log.go @@ -6,10 +6,10 @@ const ( CA_ERROR string = "CA Init Error" DEFAULT_HTTP string = "SeaMoon Listening For The HTTP/S Request" DEFAULT_SOCKS string = "SeaMoon Listening For The SOCKS5 Request" - HTTP_LISTEN_ERROR string = "[Http] Client Start Listen Error" + LISTEN_ERROR string = "Client Start Listen Error" HTTP_ACCEPT_ERROR string = "[Http] Server Accept Error" SOCKS5_LISTEN_ERROR string = "[Socks5] Client Start Listen Error" - SOCKS5_ACCEPT_ERROR string = "[Socks5] Client Accept Error" + ACCEPT_ERROR string = "Client Accept Error" SOCKS5_READ_METHOD_ERROR string = "[Socks5] Read Methods Failed" SOCKS5_WRITE_METHOD_ERROR string = "[Socks5] Write Method Failed" SOCKS5_METHOD_ERROR string = "[Socks5] Methods Is Not Acceptable" @@ -17,7 +17,8 @@ const ( SOCKS5_WRITE_COMMAND_ERROR string = "[Socks5] Write Command Replay Failed" SOCKS5_CONNECT_DIAL_ERROR string = "[Socks5] Connect Dial Remote Failed" SOCKS5_CONNECT_WRITE_ERROR string = "[Socks5] Connect Write Reply Failed" - SOCKS5_CONNECT_TRANS_ERROR string = "[Socks5] Connect Transport Failed" + CONNECT_RMOET_ERROR string = "Connect Remote Failed" + CONNECT_TRANS_ERROR string = "Connect Transport Failed" SOCKS5_BIND_LISTEN_ERROR string = "[Socks5] Bind Failed On Listen" SOCKS5_BIND_WRITE_ERROR string = "[Socks5] Bind Write Reply Failed" SOCKS5_BIND_ACCEPT_ERROR string = "[Socks5] Bind Failed On Accept" @@ -37,8 +38,8 @@ const ( CA_NOT_EXIST string = "Ca Not Exists, Run Auto Generate" CA_LOAD_SUCCESS string = "Ca Loaded Success" PROXY_ADDR string = "Proxy Addr" - HTTP_LISTEN_START string = "[Http] Client Start Listen At" - HTTP_LISTEN_STOP string = "[Http] Client Stop Listen" + LISTEN_START string = "Client Start Listen At" + LISTEN_STOP string = "Client Stop Listen" HTTP_ACCEPT_START string = "[Http] Server Accept Conn From" HTTP_CONNECT_STOP_WAIT string = "[Http] Server Stopping Conn, Please Wait..." HTTP_BODY_DIS string = "[Http] Server Conn Disconnected" diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go deleted file mode 100644 index 6db4c53..0000000 --- a/pkg/errors/errors.go +++ /dev/null @@ -1,49 +0,0 @@ -package errors - -import ( - "github.com/pkg/errors" -) - -func New(message string) error { - return errors.New(message) -} - -func Errorf(format string, args ...interface{}) error { - return errors.Errorf(format, args...) -} - -func WithStack(err error) error { - return errors.WithStack(err) -} - -func Wrap(err error, message string) error { - return errors.Wrap(err, message) -} - -func Wrapf(err error, format string, args ...interface{}) error { - return errors.Wrapf(err, format, args...) -} - -func WithMessage(err error, message string) error { - return errors.WithMessage(err, message) -} - -func WithMessagef(err error, format string, args ...interface{}) error { - return errors.WithMessagef(err, format, args...) -} - -func Cause(err error) error { - return errors.Cause(err) -} - -func Is(err, target error) bool { - return errors.Is(err, target) -} - -func As(err error, target interface{}) bool { - return errors.As(err, target) -} - -func UnWrap(err error) error { - return errors.Unwrap(err) -} diff --git a/server/service/grpc.go b/pkg/service/grpc.go similarity index 52% rename from server/service/grpc.go rename to pkg/service/grpc.go index eb0c78b..7756dae 100644 --- a/server/service/grpc.go +++ b/pkg/service/grpc.go @@ -1,8 +1,11 @@ package service import ( + "context" + "crypto/tls" "log/slog" "net" + "strings" "time" "google.golang.org/grpc" @@ -16,6 +19,7 @@ import ( type GRPCService struct { addr net.Addr + cc *grpc.ClientConn server *grpc.Server pb.UnimplementedTunnelServer @@ -25,6 +29,71 @@ func init() { register(tunnel.GRT, &GRPCService{}) } +func (g GRPCService) Conn(ctx context.Context, t transfer.Type, sOpts ...Option) (net.Conn, error) { + var cs grpc.ClientStream + var srvOpts = &Options{} + var err error + + for _, o := range sOpts { + o(srvOpts) + } + + if strings.HasPrefix(srvOpts.addr, "grpc://") { + srvOpts.addr = strings.TrimPrefix(srvOpts.addr, "grpc://") + } + + nAddr, err := net.ResolveTCPAddr("tcp", srvOpts.addr) + if err != nil { + return nil, err + } + + if g.cc == nil { + // do connect + grpcOpts := []grpc.DialOption{ + //grpc.WithAuthority(host), + //grpc.WithConnectParams(grpc.ConnectParams{ + // Backoff: backoff.DefaultConfig, + //MinConnectTimeout: d.md.minConnectTimeout, + //}), + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: 10 * time.Second, // send pings every 10 seconds if there is no activity + Timeout: 3 * time.Second, // wait 1 second for ping ack before considering the c + PermitWithoutStream: false, // send pings even without active streams + }), + //grpc.FailOnNonTempDialError(true), + } + + //if !d.md.insecure { + // grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig))) + //} else { + //grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) + grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ + InsecureSkipVerify: true, + }))) + //} + g.cc, err = grpc.DialContext(ctx, srvOpts.addr, grpcOpts...) + if err != nil { + return nil, err + } + } + + client := pb.NewTunnelClient(g.cc) + + switch t { + case transfer.HTTP: + cs, err = client.Http(ctx) + case transfer.SOCKS5: + cs, err = client.Socks5(ctx) + } + + if err != nil { + return nil, err + } + + return tunnel.GRPCWrapConn(nAddr, cs), nil + +} + func (g GRPCService) Serve(ln net.Listener, srvOpt ...Option) error { var srvOpts = &Options{} for _, o := range srvOpt { diff --git a/server/service/options.go b/pkg/service/options.go similarity index 100% rename from server/service/options.go rename to pkg/service/options.go diff --git a/server/service/service.go b/pkg/service/service.go similarity index 65% rename from server/service/service.go rename to pkg/service/service.go index 7f2cb12..2825525 100644 --- a/server/service/service.go +++ b/pkg/service/service.go @@ -1,12 +1,15 @@ package service import ( + "context" "net" + "github.com/DVKunion/SeaMoon/pkg/transfer" "github.com/DVKunion/SeaMoon/pkg/tunnel" ) type Service interface { + Conn(ctx context.Context, t transfer.Type, sOpts ...Option) (net.Conn, error) Serve(ln net.Listener, srvOpt ...Option) error } diff --git a/server/service/websocket.go b/pkg/service/websocket.go similarity index 75% rename from server/service/websocket.go rename to pkg/service/websocket.go index 29a6a70..e6b0fb5 100644 --- a/server/service/websocket.go +++ b/pkg/service/websocket.go @@ -1,10 +1,12 @@ package service import ( + "context" "crypto/tls" "log/slog" "net" "net/http" + "path" "time" "github.com/gorilla/websocket" @@ -28,6 +30,37 @@ func init() { register(tunnel.WST, &WSService{}) } +func (s *WSService) Conn(ctx context.Context, t transfer.Type, sOpts ...Option) (net.Conn, error) { + // todo: useless ctx + var srvOpts = &Options{} + + for _, o := range sOpts { + o(srvOpts) + } + + wsDialer := &websocket.Dialer{ + HandshakeTimeout: defaultTimeout, + ReadBufferSize: defaultReadBufferSize, + WriteBufferSize: defaultReadBufferSize, + EnableCompression: true, + } + + if srvOpts.buffers != nil { + wsDialer.ReadBufferSize = srvOpts.buffers.ReadBufferSize + wsDialer.WriteBufferSize = srvOpts.buffers.WriteBufferSize + wsDialer.EnableCompression = srvOpts.buffers.EnableCompression + } + + url := path.Join(srvOpts.addr, t.String()) + + wsConn, _, err := wsDialer.Dial("ws://"+url, nil) + + if err != nil { + return nil, err + } + return tunnel.WsWrapConn(wsConn), nil +} + func (s *WSService) Serve(ln net.Listener, sOpts ...Option) error { var srvOpts = &Options{} diff --git a/pkg/transfer/socks5.go b/pkg/transfer/socks5.go index 8aaaf7c..fac18bc 100644 --- a/pkg/transfer/socks5.go +++ b/pkg/transfer/socks5.go @@ -77,7 +77,7 @@ func handleConnect(conn net.Conn, req *network.SOCKS5Request) { slog.Info(consts.SOCKS5_CONNECT_ESTAB, "src", conn.RemoteAddr(), "dest", req.Addr) if err := network.Transport(conn, destConn); err != nil { - slog.Error(consts.SOCKS5_CONNECT_TRANS_ERROR, err) + slog.Error(consts.CONNECT_TRANS_ERROR, "err", err) } slog.Info(consts.SOCKS5_CONNECT_DIS, "src", conn.RemoteAddr(), "dest", req.Addr) diff --git a/pkg/transfer/transfer.go b/pkg/transfer/transfer.go new file mode 100644 index 0000000..c7bf0e3 --- /dev/null +++ b/pkg/transfer/transfer.go @@ -0,0 +1,12 @@ +package transfer + +type Type string + +const ( + HTTP Type = "http" + SOCKS5 Type = "socks5" +) + +func (t Type) String() string { + return string(t) +} diff --git a/s.yaml b/s.yaml index 9c772d7..3c2e83a 100644 --- a/s.yaml +++ b/s.yaml @@ -16,7 +16,7 @@ actions: pre-deploy: - run: go mod tidy path: ./ - - run: GO111MODULE=on GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X github.com/DVKunion/SeaMoon/pkg/consts.Version=2.0.0-beta.1" -o seamoon main.go + - run: GO111MODULE=on GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X github.com/DVKunion/SeaMoon/pkg/consts.Version=2.0.0-beta.1" -o seamoon cmd/main.go path: ./ - run: chmod +x seamoon path: ./