From 22bc49c33307fed077eebcb0b416bc4b2cbbbb17 Mon Sep 17 00:00:00 2001 From: DVK Date: Mon, 15 Jan 2024 19:10:24 +0800 Subject: [PATCH] refactor: server code && upgrade go mod (#15) --- .github/conf/.goreleaser.yml | 2 +- .github/workflows/build.yml | 4 +- .github/workflows/release.yml | 2 +- .gitignore | 1 + CHANGELOG.md | 67 ++- Dockerfile | 16 + README.md | 12 +- cmd/aliyun_server.go | 16 - cmd/client.go | 51 --- docker/client/Dockerfile | 16 - docker/server/Dockerfile | 16 - package.json => docs/package.json | 4 +- .../01.feature.md" | 59 ++- .../02.SOCKS5.md" | 10 +- yarn.lock => docs/yarn.lock | 0 go.mod | 53 ++- go.sum | 153 +++---- main.go | 80 ++++ pkg/client/client.go | 6 +- pkg/client/config.go | 4 +- pkg/client/http.go | 16 +- pkg/client/socks.go | 68 +-- pkg/consts/log.go | 78 ++-- pkg/consts/version.go | 5 +- pkg/errors/errors.go | 49 +++ pkg/network/addr.go | 155 +++++++ pkg/{utils => network}/auth.go | 11 +- pkg/network/buffer.go | 123 ++++++ pkg/network/errors.go | 12 + pkg/{utils => network}/http.go | 2 +- pkg/{utils/socks.go => network/socks5.go} | 390 +++++------------- pkg/network/transport.go | 33 ++ pkg/server/http.go | 118 ------ pkg/server/server.go | 53 --- pkg/server/socks.go | 129 ------ pkg/server/websocket.go | 65 --- pkg/transfer/http.go | 67 +++ pkg/transfer/socks5.go | 58 +++ pkg/tunnel/tunnel.go | 30 ++ pkg/tunnel/websocket.go | 58 +++ s.yaml | 57 +-- server/options.go | 36 ++ server/server.go | 85 ++++ server/service/service.go | 17 + server/service/websocket.go | 88 ++++ 45 files changed, 1338 insertions(+), 1037 deletions(-) create mode 100644 Dockerfile delete mode 100644 cmd/aliyun_server.go delete mode 100644 cmd/client.go delete mode 100644 docker/client/Dockerfile delete mode 100644 docker/server/Dockerfile rename package.json => docs/package.json (86%) rename yarn.lock => docs/yarn.lock (100%) create mode 100644 main.go create mode 100644 pkg/errors/errors.go create mode 100644 pkg/network/addr.go rename pkg/{utils => network}/auth.go (88%) create mode 100644 pkg/network/buffer.go create mode 100644 pkg/network/errors.go rename pkg/{utils => network}/http.go (99%) rename pkg/{utils/socks.go => network/socks5.go} (56%) create mode 100644 pkg/network/transport.go delete mode 100644 pkg/server/http.go delete mode 100644 pkg/server/server.go delete mode 100644 pkg/server/socks.go delete mode 100644 pkg/server/websocket.go create mode 100644 pkg/transfer/http.go create mode 100644 pkg/transfer/socks5.go create mode 100644 pkg/tunnel/tunnel.go create mode 100644 pkg/tunnel/websocket.go create mode 100644 server/options.go create mode 100644 server/server.go create mode 100644 server/service/service.go create mode 100644 server/service/websocket.go diff --git a/.github/conf/.goreleaser.yml b/.github/conf/.goreleaser.yml index a4012ba..0bc5137 100644 --- a/.github/conf/.goreleaser.yml +++ b/.github/conf/.goreleaser.yml @@ -5,7 +5,7 @@ builds: - binary: client env: - CGO_ENABLED=0 - main: ./cmd/client.go + main: ./main.go goos: - linux - windows diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d11e5b..89059dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.18 + go-version: 1.21 - name: Build - run: go build --ldflags "-s -w -X github.com/DVKunion/SeaMoon/pkg/consts.Version=${{github.ref_name}}" cmd/client.go + run: go build --ldflags "-s -w -X github.com/DVKunion/SeaMoon/pkg/consts.Version=${{github.ref_name}}" main.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de51b9f..3f0c7d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.18 + go-version: 1.21 id: go - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 diff --git a/.gitignore b/.gitignore index 7037cc5..ebb1a72 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ *.key dist/ +web/ *.log *.toml .config diff --git a/CHANGELOG.md b/CHANGELOG.md index 37741d0..d17dc29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,72 @@ -# 1.1.0 (2022-09-27) +# CHANGELOG +## SeaMoon 1.1.3 -### Bug Fixes +### ❤️ What's New -* optimize connection ([70dfc5a](https://github.com/DVKunion/SeaMoon/commit/70dfc5ad4d25fd5b529097183c873d87ec37f126)) -* optimize connection ([2b416c0](https://github.com/DVKunion/SeaMoon/commit/2b416c0b106ad0a6a21aa3da838cf311061e9ef8)) +* 📝 docs: 增加手册页面sitemap站点地图(#7)(#8) +* ✨ feat(server): 修改了阿里云默认的部署资源类型(vcpu 0.1/mem 128),来降低普通用户使用的价格消费 (#10) +* ✨ feat(server): 增加了sealos部署方案,用更加便宜的价格使用seamoon (#11) +* ✨ feat(server): 增加了docker server, 现在可以通过docker来启动服务端 (#12) +* 🔧 fix(config): 用更友好的方式来使用config,不再单一的通过域名特征来判断服务端地址类型。(#13) + +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/1.1.2...1.1.3 + +* 41c5ce8 feat(docker): add docker server (#12) +* 1414293 feat: low cpu && mem cost (#10) +* 99c98fd fix(client): use more friendly config (#13) + +## SeaMoon 1.1.2 + +### ❤️ What's New + +* 🔧 fix(websocket): 修正了protocol error detect 时仍挂起gorouting导致卡死的问题 (#6) +* ✨ feat(dockerfile): 增加了docker client, 现在可以通过docker来启动客户端 (#6) + +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/1.1.1...1.1.2 + +## SeaMoon 1.1.1 +### ❤️ What's New +* 🔧 fix(websocket): 修正了 websocket 在超出 32768 slice导致的 panic。 (#4) +* 🔧 fix(websocket): 修整了 websocket 在 close 时写入 message 导致的 panic。 (#4) +* 🔧 fix(websocket): 忽略了大量 websocket 链接导致的 1006 abnormal close 报错。 (#4) +* 🔧 fix(s.yaml): 修整了 serverless-devs 工具编排文件,目前可以通过 serverless-devs 工具`s deploy`一件部署至阿里云。 (#4) +* 🔧 fix(ci): 修整了 go-releaser ci 配置 (#3) +* 🔧 fix(docs): 更新了 README.md 较为过时的使用手册。 -# 1.0.0 (2022-09-09) +### 🌈 Small Talk + +> Hi, 各位,SeaMoon成功挤入2023Kcon兵器谱,使得整个项目获得了一批关注;在此感谢大家对SeaMoon项目的浓厚兴趣与支持,谢谢各位🙏 +> 由于工作原因,以及个人的一些想法枯竭,项目于去年创建,直到现在目前也仅支持了阿里云一个demo QAQ,因此整体给人并不是一个较为完善的使用效果。1.1.1 版本后,我会尽量保证一些活跃性质的更新,以及一些比较有意思的想法demo迭代。 +> 也欢迎对serverless感兴趣的安全小伙伴留言来交个朋友~ + +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/1.1.0...1.1.1 + +* bc209a9 doc: update README.md +* a2e7360 fix: go-releaser ci config (#3) +* 8f51e63 fix: readme.md +* fe658ff fix: some websocket error optimization (#4) +* c316527 hotfix: some docs and code format + +## 1.1.0 (2022-09-27) + +### Bug Fixes + +* optimize connection ([70dfc5a](https://github.com/DVKunion/SeaMoon/commit/70dfc5ad4d25fd5b529097183c873d87ec37f126)) +* optimize connection ([2b416c0](https://github.com/DVKunion/SeaMoon/commit/2b416c0b106ad0a6a21aa3da838cf311061e9ef8)) +## 1.0.0 (2022-09-09) ### Features -* **ci:** add build client ([215400c](https://github.com/DVKunion/SeaMoon/commit/215400cb7a3ae6c3f5f12df6828c8735156b810b)) -* **pkg/socks5:** socks5 proxy beta version ([20d586c](https://github.com/DVKunion/SeaMoon/commit/20d586ce1ac36f143c1e340aa3bf9132e35af230)) -* **pkg/http:** http proxy beta version ([3b41846](https://github.com/DVKunion/SeaMoon/commit/3b41846f75fe6d9510a9d040d76f97b35ce8c494)) +* **ci:** add build + client ([215400c](https://github.com/DVKunion/SeaMoon/commit/215400cb7a3ae6c3f5f12df6828c8735156b810b)) +* **pkg/socks5:** socks5 proxy beta + version ([20d586c](https://github.com/DVKunion/SeaMoon/commit/20d586ce1ac36f143c1e340aa3bf9132e35af230)) +* **pkg/http:** http proxy beta + version ([3b41846](https://github.com/DVKunion/SeaMoon/commit/3b41846f75fe6d9510a9d040d76f97b35ce8c494)) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..11d4f21 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +# build stage +FROM golang:alpine AS build +ARG VERSION +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 chmod +x /tmp/seamoon +# run stage +FROM alpine:3.19 +LABEL maintainer="dvkunion@gamil.com" +WORKDIR /app +COPY --from=build /tmp/seamoon /app/seamoon +EXPOSE 1080,8080,7777,9000 +ENTRYPOINT ["/app/seamoon"] \ No newline at end of file diff --git a/README.md b/README.md index ad79267..e64ce45 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- logo + logo

Sea Moon

@@ -28,22 +28,22 @@ 直白来讲,月海其实就是一款利用云函数来代理/隐匿攻击行踪以及一些安全相关的匿名性对抗。 -想要了解更多,请移步[官方手册](https://seamoon.dvkunion.cn) +想要了解更多,请移步 [官方手册](https://seamoon.dvkunion.cn) 觉得项目不错的话,[还请给一个star ✨](https://github.com/DVKunion/SeaMoon), 你的支持是更新的最大动力~ ## 🔥 使用展示 -![](https://cdn.dvkunion.cn/seamoon/bf0f8d2fc5084c329f9638d5c3f0bf46.png) + ## 🕹 快速开始 -[快速开始](https://seamoon.dvkunion.cn/guide/start) +[⚡️ 快速开始](https://seamoon.dvkunion.cn/guide/start) -[🔥新增Sealos部署, 价格更低更实惠!](https://seamoon.dvkunion.cn/guide/deploy/sealos) +[✨ 新增Sealos部署, 价格更低更实惠!](https://seamoon.dvkunion.cn/guide/deploy/sealos) ## 💻 技术文档 -[技术文档](https://seamoon.dvkunion.cn/tech/feature) +[🧑‍💻 技术文档](https://seamoon.dvkunion.cn/tech/feature) ## ❗ 免责声明 diff --git a/cmd/aliyun_server.go b/cmd/aliyun_server.go deleted file mode 100644 index 5fbd6f7..0000000 --- a/cmd/aliyun_server.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "os" - - "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/server" -) - -func main() { - if consts.Version == "dev" { - server.NewServer("socks5", "0.0.0.0", "8888").Serve() - } else { - server.NewServer(os.Getenv("serverMod"), "0.0.0.0", "9000").Serve() - } -} diff --git a/cmd/client.go b/cmd/client.go deleted file mode 100644 index c453607..0000000 --- a/cmd/client.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "os" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - - "github.com/DVKunion/SeaMoon/pkg/client" - "github.com/DVKunion/SeaMoon/pkg/consts" -) - -var ( - debug bool - verbose bool - - rootCommand = &cobra.Command{ - Run: Client, - } - - clientCommand = &cobra.Command{ - Use: "client", - Short: "SeaMoon Client", - Run: Client, - } - - versionCommand = &cobra.Command{ - Use: "version", - Run: func(cmd *cobra.Command, args []string) { - log.Info(consts.Version) - }, - } -) - -func init() { - rootCommand.AddCommand(versionCommand) - clientCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "proxy detail log") - clientCommand.Flags().BoolVarP(&debug, "debug", "d", false, "proxy detail log") - - rootCommand.AddCommand(clientCommand) -} - -func Client(cmd *cobra.Command, args []string) { - client.Serve(cmd.Context(), verbose, debug) -} - -func main() { - if err := rootCommand.Execute(); err != nil { - os.Exit(1) - } -} diff --git a/docker/client/Dockerfile b/docker/client/Dockerfile deleted file mode 100644 index b2dbf01..0000000 --- a/docker/client/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -# build stage -FROM golang:alpine AS build -ARG VERSION -COPY ../.. /src -WORKDIR /src -ENV CGO_ENABLED 0 -ENV VERSION=${VERSION} -RUN go build --ldflags "-s -w -X github.com/DVKunion/SeaMoon/pkg/consts.Version=${VERSION}" -o /tmp/client cmd/client.go -RUN chmod +x /tmp/client -# run stage -FROM scratch -LABEL maintainer="dvkunion@gamil.com" -WORKDIR /app -COPY --from=build /tmp/client /app/client -EXPOSE 7777 1080 9000 -ENTRYPOINT ["/app/client"] \ No newline at end of file diff --git a/docker/server/Dockerfile b/docker/server/Dockerfile deleted file mode 100644 index fdf330f..0000000 --- a/docker/server/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -# build stage -FROM golang:alpine AS build -ARG VERSION -COPY ../.. /src -WORKDIR /src -ENV CGO_ENABLED 0 -ENV VERSION=${VERSION} -RUN go build -ldflags "-X github.com/DVKunion/SeaMoon/pkg/consts.Version=${VERSION}" -o /tmp/server cmd/aliyun_server.go -RUN chmod +x /tmp/server -# run stage -FROM scratch -LABEL maintainer="dvkunion@gamil.com" -WORKDIR /app -COPY --from=build /tmp/server /app/server -EXPOSE 9000 -ENTRYPOINT ["/app/server"] \ No newline at end of file diff --git a/package.json b/docs/package.json similarity index 86% rename from package.json rename to docs/package.json index 38ac102..6ad2e16 100644 --- a/package.json +++ b/docs/package.json @@ -6,8 +6,8 @@ "repository": "https://github.com/DVKunion/SeaMoon", "author": "DVKunion", "scripts": { - "dev": "vuepress dev docs", - "build": "vuepress build docs", + "dev": "vuepress dev .", + "build": "vuepress build .", "updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D", "editFm": "node utils/editFrontmatter.js" }, diff --git "a/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/01.feature.md" "b/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/01.feature.md" index 904df4c..50cd5e6 100644 --- "a/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/01.feature.md" +++ "b/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/01.feature.md" @@ -10,13 +10,14 @@ article: false ## SeaMoon 1.1.3 ### ❤️ What's New -* 🎡 docs: 增加手册页面sitemap站点地图(#7)(#8) -* 🔥 feat(server): 修改了阿里云默认的部署资源类型(vcpu 0.1/mem 128),来降低普通用户使用的价格消费 (#10) -* 🔥 feat(server): 增加了sealos部署方案,用更加便宜的价格使用seamoon (#11) -* 🔥 feat(server): 增加了docker server, 现在可以通过docker来启动服务端 (#12) -* 🔧 fix(config): 用更友好的方式来使用config,不再单一的通过域名特征来判断服务端地址类型。(#13) -[**Full Changelog**](https://github.com/DVKunion/SeaMoon/compare/1.1.2...1.1.3) +* 📝 docs: 增加手册页面sitemap站点地图(#7)(#8) +* ✨ feat(server): 修改了阿里云默认的部署资源类型(vcpu 0.1/mem 128),来降低普通用户使用的价格消费 (#10) +* ✨ feat(server): 增加了sealos部署方案,用更加便宜的价格使用seamoon (#11) +* ✨ feat(server): 增加了docker server, 现在可以通过docker来启动服务端 (#12) +* 🔧 fix(config): 用更友好的方式来使用config,不再单一的通过域名特征来判断服务端地址类型。(#13) + +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/1.1.2...1.1.3 * 41c5ce8 feat(docker): add docker server (#12) * 1414293 feat: low cpu && mem cost (#10) @@ -25,34 +26,54 @@ article: false ## SeaMoon 1.1.2 ### ❤️ What's New -* 🔧 fix(websocket): 修正了protocol error detect 时仍挂起gorouting导致卡死的问题 (#6) -* 🔥 feat(dockerfile): 增加了docker client, 现在可以通过docker来启动客户端 (#6) -[**Full Changelog**](https://github.com/DVKunion/SeaMoon/compare/1.1.1...1.1.2) +* 🔧 fix(websocket): 修正了protocol error detect 时仍挂起gorouting导致卡死的问题 (#6) +* ✨ feat(dockerfile): 增加了docker client, 现在可以通过docker来启动客户端 (#6) + +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/1.1.1...1.1.2 ## SeaMoon 1.1.1 ### ❤️ What's New -* 🔧 fix(websocket): 修正了websocket在超出32768slice导致的panic。 (#4) -* 🔧 fix(websocket): 修整了websocket在close时写入message导致的panic。 (#4) -* 🔧 fix(websocket): 忽略了大量websocket链接导致的1006 abnormal close报错。 (#4) -* 🔧 fix(s.yaml): 修整了serverless-devs工具编排文件,目前可以通过serverless-devs工具`s deploy`一件部署至阿里云。 (#4) -* 🔧 fix(ci): 修整了 go-releaser ci 配置 (#3) -* 🔧 fix(docs): 更新了 README.md 较为过时的使用手册。 + +* 🔧 fix(websocket): 修正了 websocket 在超出 32768 slice导致的 panic。 (#4) +* 🔧 fix(websocket): 修整了 websocket 在 close 时写入 message 导致的 panic。 (#4) +* 🔧 fix(websocket): 忽略了大量 websocket 链接导致的 1006 abnormal close 报错。 (#4) +* 🔧 fix(s.yaml): 修整了 serverless-devs 工具编排文件,目前可以通过 serverless-devs 工具`s deploy`一件部署至阿里云。 (#4) +* 🔧 fix(ci): 修整了 go-releaser ci 配置 (#3) +* 🔧 fix(docs): 更新了 README.md 较为过时的使用手册。 ### 🌈 Small Talk -> Hi, 各位,SeaMoon成功挤入2023 Kcon兵器谱,使得整个项目获得了一批关注;在此感谢大家对SeaMoon项目的浓厚兴趣与支持,谢谢各位🙏 -> 由于工作原因,以及个人的一些想法枯竭,项目于去年创建,直到现在目前也仅支持了阿里云一个demo QAQ,因此整体给人并不是一个较为完善的使用效果。 -> 1.1.1 版本后,我会尽量保证一些活跃性质的更新,以及一些比较有意思的想法demo迭代。 + +> Hi,各位,SeaMoon成功挤入2023Kcon兵器谱,使得整个项目获得了一批关注;在此感谢大家对SeaMoon项目的浓厚兴趣与支持,谢谢各位🙏 +> 由于工作原因,以及个人的一些想法枯竭,项目于去年创建,直到现在目前也仅支持了阿里云一个demo QAQ,因此整体给人并不是一个较为完善的使用效果。1.1.1 版本后,我会尽量保证一些活跃性质的更新,以及一些比较有意思的想法demo迭代。 > 也欢迎对serverless感兴趣的安全小伙伴留言来交个朋友~ -[**Full Changelog**](https://github.com/DVKunion/SeaMoon/compare/1.1.0...1.1.1) +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/1.1.0...1.1.1 + * bc209a9 doc: update README.md * a2e7360 fix: go-releaser ci config (#3) * 8f51e63 fix: readme.md * fe658ff fix: some websocket error optimization (#4) * c316527 hotfix: some docs and code format +## 1.1.0 (2022-09-27) + +### Bug Fixes + +* optimize connection ([70dfc5a](https://github.com/DVKunion/SeaMoon/commit/70dfc5ad4d25fd5b529097183c873d87ec37f126)) +* optimize connection ([2b416c0](https://github.com/DVKunion/SeaMoon/commit/2b416c0b106ad0a6a21aa3da838cf311061e9ef8)) + +## 1.0.0 (2022-09-09) + +### Features + +* **ci:** add build + client ([215400c](https://github.com/DVKunion/SeaMoon/commit/215400cb7a3ae6c3f5f12df6828c8735156b810b)) +* **pkg/socks5:** socks5 proxy beta + version ([20d586c](https://github.com/DVKunion/SeaMoon/commit/20d586ce1ac36f143c1e340aa3bf9132e35af230)) +* **pkg/http:** http proxy beta + version ([3b41846](https://github.com/DVKunion/SeaMoon/commit/3b41846f75fe6d9510a9d040d76f97b35ce8c494)) ## SeaMoon 1.1.0 diff --git "a/docs/tech/01.\347\275\221\347\273\234\345\261\202/02.SOCKS5.md" "b/docs/tech/01.\347\275\221\347\273\234\345\261\202/02.SOCKS5.md" index a3c76bf..fc8111a 100644 --- "a/docs/tech/01.\347\275\221\347\273\234\345\261\202/02.SOCKS5.md" +++ "b/docs/tech/01.\347\275\221\347\273\234\345\261\202/02.SOCKS5.md" @@ -76,12 +76,4 @@ FC的不成熟的确限制了大部分的玩法,比如触发器种类,比如 最后就是处理好断开连接问题,来防止异常断开导致的panic,和节约云函数计费成本。 -最终达成上图效果。 - -### SS - -待开发 - -### VMess - -待开发 \ No newline at end of file +最终达成上图效果。 \ No newline at end of file diff --git a/yarn.lock b/docs/yarn.lock similarity index 100% rename from yarn.lock rename to docs/yarn.lock diff --git a/go.mod b/go.mod index 6cb9112..c3d7b97 100644 --- a/go.mod +++ b/go.mod @@ -1,37 +1,46 @@ module github.com/DVKunion/SeaMoon -go 1.18 +go 1.21 require ( - github.com/BurntSushi/toml v0.3.1 - github.com/gin-gonic/gin v1.8.1 + 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.4.2 - github.com/sirupsen/logrus v1.9.0 - github.com/spf13/cobra v1.5.0 + 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 ) require ( github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.10.0 // indirect - github.com/goccy/go-json v0.9.7 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.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 - github.com/leodido/go-urn v1.2.1 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect - golang.org/x/text v0.3.6 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8e8a0ad..6b72fd1 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,19 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -15,20 +21,22 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= -github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -43,73 +51,78 @@ 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 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= 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= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +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= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tg123/go-htpasswd v1.2.0 h1:UKp34m9H467/xklxUxU15wKRru7fwXoTojtxg25ITF0= github.com/tg123/go-htpasswd v1.2.0/go.mod h1:h7IzlfpvIWnVJhNZ0nQ9HaFxHb7pn5uFJYLlEUJa2sM= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY= +github.com/xtaci/smux v1.5.24/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -119,31 +132,25 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r 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.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -169,18 +176,14 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/main.go b/main.go new file mode 100644 index 0000000..c8b702d --- /dev/null +++ b/main.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/DVKunion/SeaMoon/pkg/client" + "github.com/DVKunion/SeaMoon/pkg/consts" + "github.com/DVKunion/SeaMoon/server" +) + +var ( + debug bool + verbose bool + + // server params + addr string + port string + proto string + + rootCommand = &cobra.Command{} + + serverCommand = &cobra.Command{ + Use: "server", + Short: "seaMoon server mod", + RunE: Server, + } + + proxyCommand = &cobra.Command{ + Use: "proxy", + Short: "seaMoon proxy mod", + Run: Proxy, + } + + versionCommand = &cobra.Command{ + Use: "version", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(consts.Version) + }, + } +) + +func Proxy(cmd *cobra.Command, args []string) { + client.Serve(cmd.Context(), verbose, debug) +} + +func Server(cmd *cobra.Command, args []string) error { + s, err := server.New( + server.WithHost("0.0.0.0"), + server.WithPort(port), + server.WithProto(proto), + ) + + if err != nil { + return err + } + + return s.Serve(cmd.Context()) +} + +func init() { + proxyCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "proxy detail log") + proxyCommand.Flags().BoolVarP(&debug, "debug", "d", false, "proxy detail log") + + serverCommand.Flags().StringVarP(&addr, "addr", "a", "0.0.0.0", "server listen addr") + serverCommand.Flags().StringVarP(&port, "port", "p", "9000", "server listen port") + serverCommand.Flags().StringVarP(&proto, "proto", "t", "websocket", "server listen proto: (websocket/grpc)") + + rootCommand.AddCommand(versionCommand) + rootCommand.AddCommand(proxyCommand) + rootCommand.AddCommand(serverCommand) +} + +func main() { + if err := rootCommand.Execute(); err != nil { + os.Exit(1) + } +} diff --git a/pkg/client/client.go b/pkg/client/client.go index bff11a6..7e736b6 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -5,12 +5,12 @@ import ( "context" "html/template" "io" + "log/slog" "net" "net/http" "os" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" "github.com/DVKunion/SeaMoon/pkg/consts" "github.com/DVKunion/SeaMoon/static" @@ -45,7 +45,7 @@ func Serve(ctx context.Context, verbose bool, debug bool) { } func Controller(sg *SigGroup, verbose bool, debug bool) { - log.Infof(consts.CONTROLLER_START, Config().Control.ConfigAddr) + slog.Info(consts.CONTROLLER_START, "addr", Config().Control.ConfigAddr) if consts.Version != "dev" || !debug { gin.SetMode(gin.ReleaseMode) @@ -92,6 +92,6 @@ func Controller(sg *SigGroup, verbose bool, debug bool) { }) if err := server.Run(Config().Control.ConfigAddr); err != http.ErrServerClosed { - log.Error(err) + slog.Error("client running error", "err", err) } } diff --git a/pkg/client/config.go b/pkg/client/config.go index 7a99d0f..5fa836e 100644 --- a/pkg/client/config.go +++ b/pkg/client/config.go @@ -2,10 +2,10 @@ package client import ( "bytes" + "log/slog" "os" "github.com/BurntSushi/toml" - log "github.com/sirupsen/logrus" "github.com/DVKunion/SeaMoon/pkg/consts" ) @@ -86,7 +86,7 @@ func (c *clientConfig) Load(sg *SigGroup) error { // try first start err := toml.Unmarshal(data, c) if err != nil { - log.Debug(consts.CONFIG_NOT_FIND) + slog.Debug(consts.CONFIG_NOT_FIND) return err } sg.Detection() diff --git a/pkg/client/http.go b/pkg/client/http.go index c7f2b59..d3ec9b0 100644 --- a/pkg/client/http.go +++ b/pkg/client/http.go @@ -3,6 +3,7 @@ package client import ( "context" "crypto/tls" + "log/slog" "net" "net/http" "net/url" @@ -10,10 +11,9 @@ import ( "time" "github.com/google/martian/v3" - log "github.com/sirupsen/logrus" "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/utils" + "github.com/DVKunion/SeaMoon/pkg/network" ) func HttpController(ctx context.Context, sg *SigGroup) { @@ -24,7 +24,7 @@ func HttpController(ctx context.Context, sg *SigGroup) { case <-sg.HttpStartChannel: server, err := net.Listen("tcp", Config().Http.ListenAddr) if err != nil { - log.Errorf(consts.HTTP_LISTEN_ERROR, err) + slog.Error(consts.HTTP_LISTEN_ERROR, "err", err) return } var proxyAddr string @@ -36,7 +36,7 @@ func HttpController(ctx context.Context, sg *SigGroup) { } } if proxyAddr == "" { - log.Error(consts.PROXY_ADDR_ERROR) + slog.Error(consts.PROXY_ADDR_ERROR) break } sg.wg.Add(1) @@ -45,7 +45,7 @@ func HttpController(ctx context.Context, sg *SigGroup) { sg.wg.Done() }() case <-sg.HttpStopChannel: - log.Info(consts.HTTP_LISTEN_STOP) + slog.Info(consts.HTTP_LISTEN_STOP) cancel() } } @@ -65,14 +65,14 @@ func (r RequestModifier) ModifyRequest(req *http.Request) error { if req.Method == http.MethodConnect { return nil } - req.Header.Set("SM-Host", utils.GetUrl(req)) + 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) { - log.Infof(consts.HTTP_LISTEN_START, l.Addr()) + slog.Info(consts.HTTP_LISTEN_START, "addr", l.Addr()) p := martian.NewProxy() defer p.Close() tr := &http.Transport{ @@ -92,7 +92,7 @@ func NewHttpClient(ctx context.Context, l net.Listener, pAddr string) { go func() { if err := p.Serve(l); err != nil { - log.Error("server:", err) + slog.Error("client server error:", "err", err) } }() diff --git a/pkg/client/socks.go b/pkg/client/socks.go index c388d6d..3cce6c2 100644 --- a/pkg/client/socks.go +++ b/pkg/client/socks.go @@ -3,17 +3,17 @@ package client import ( "bufio" "context" + "log/slog" "net" "net/http" "strings" "sync" "github.com/gorilla/websocket" - log "github.com/sirupsen/logrus" "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/server" - "github.com/DVKunion/SeaMoon/pkg/utils" + "github.com/DVKunion/SeaMoon/pkg/network" + "github.com/DVKunion/SeaMoon/pkg/tunnel" ) type bufferedConn struct { @@ -34,7 +34,7 @@ func Socks5Controller(ctx context.Context, sg *SigGroup) { server, err := net.Listen("tcp", Config().Socks5.ListenAddr) if err != nil { - log.Errorf(consts.SOCKS5_LISTEN_ERROR, err) + slog.Error(consts.SOCKS5_LISTEN_ERROR, err) return } var proxyAddr string @@ -46,7 +46,7 @@ func Socks5Controller(ctx context.Context, sg *SigGroup) { } } if proxyAddr == "" { - log.Error(consts.PROXY_ADDR_ERROR) + slog.Error(consts.PROXY_ADDR_ERROR) break } sg.wg.Add(1) @@ -55,7 +55,7 @@ func Socks5Controller(ctx context.Context, sg *SigGroup) { sg.wg.Done() }() case <-sg.SocksStopChannel: - log.Info(consts.SOCKS5_LISTEN_STOP) + slog.Info(consts.SOCKS5_LISTEN_STOP) cancel() } } @@ -63,8 +63,8 @@ func Socks5Controller(ctx context.Context, sg *SigGroup) { func NewSocks5Client(ctx context.Context, server net.Listener, proxyAddr string) { var closeFlag = false - log.Infof(consts.SOCKS5_LISTEN_START, server.Addr()) - log.Debugf(consts.PROXY_ADDR, proxyAddr) + slog.Info(consts.SOCKS5_LISTEN_START, "addr", server.Addr()) + slog.Debug(consts.PROXY_ADDR, "proxy", proxyAddr) defer func() { closeFlag = true server.Close() @@ -74,11 +74,11 @@ func NewSocks5Client(ctx context.Context, server net.Listener, proxyAddr string) lock := &sync.Mutex{} conn, err := server.Accept() if err == nil { - log.Debugf(consts.SOCKS5_ACCEPT_START, conn.RemoteAddr()) + slog.Debug(consts.SOCKS5_ACCEPT_START, "addr", conn.RemoteAddr()) br := bufio.NewReader(conn) b, err := br.Peek(1) - if err != nil || b[0] != utils.Version { - log.Errorf(consts.CLIENT_PROTOCOL_UNSUPPORT_ERROR, err) + if err != nil || b[0] != network.SOCKS5Version { + slog.Error(consts.CLIENT_PROTOCOL_UNSUPPORT_ERROR, "err", err) } else { go Socks5Handler(&bufferedConn{conn, br}, proxyAddr, lock) } @@ -87,7 +87,7 @@ func NewSocks5Client(ctx context.Context, server net.Listener, proxyAddr string) // except close return } else { - log.Errorf(consts.SOCKS5_ACCEPT_ERROR, err) + slog.Error(consts.SOCKS5_ACCEPT_ERROR, "err", err) } } } @@ -97,46 +97,46 @@ func NewSocks5Client(ctx context.Context, server net.Listener, proxyAddr string) func Socks5Handler(conn net.Conn, raddr string, lock *sync.Mutex) { // select method - _, err := utils.ReadMethods(conn) + _, err := network.ReadMethods(conn) if err != nil { - log.Errorf(`[socks5] read methods failed: %s`, err) + slog.Error(`[socks5] read methods failed`, "err", err) return } // TODO AUTH - if err := utils.WriteMethod(utils.MethodNoAuth, conn); err != nil { + if err := network.WriteMethod(network.MethodNoAuth, conn); err != nil { if err != nil { - log.Errorf(`[socks5] write method failed: %s`, err) + slog.Error(`[socks5] write method failed`, "err", err) } else { - log.Errorf(`[socks5] methods is not acceptable`) + slog.Error(`[socks5] methods is not acceptable`) } return } // read command - request, err := utils.ReadRequest(conn) + request, err := network.ReadSOCKS5Request(conn) if err != nil { - log.Errorf(`[socks5] read command failed: %s`, err) + slog.Error(`[socks5] read command failed`, "err", err) return } switch request.Cmd { - case utils.CmdConnect: + case network.SOCKS5CmdConnect: handleConnect(conn, request, raddr, lock) break - case utils.CmdBind: - log.Error("not support cmd bind") + case network.SOCKS5CmdBind: + slog.Error("not support cmd bind") //handleBind(conn, request) break - case utils.CmdUDP: + case network.SOCKS5CmdUDPOverTCP: //handleUDP(conn, request) - log.Error("not support cmd upd") + slog.Error("not support cmd upd") break } } -func handleConnect(conn net.Conn, req *utils.Request, rAddr string, lock *sync.Mutex) { +func handleConnect(conn net.Conn, req *network.SOCKS5Request, rAddr string, lock *sync.Mutex) { - log.Infof(consts.SOCKS5_CONNECT_SERVER, req.Addr, conn.RemoteAddr()) + slog.Info(consts.SOCKS5_CONNECT_SERVER, "src", conn.RemoteAddr(), "dest", req.Addr) dialer := &websocket.Dialer{} s := http.Header{} @@ -145,24 +145,24 @@ func handleConnect(conn net.Conn, req *utils.Request, rAddr string, lock *sync.M wsConn, _, err := dialer.Dial(rAddr, s) if err != nil { - log.Errorf(consts.SOCKS_UPGRADE_ERROR, err) + slog.Error(consts.SOCKS_UPGRADE_ERROR, "err", err) return } - newConn := server.NewWebsocketServer(wsConn, lock) + newConn := tunnel.WsWrapConn(wsConn) defer newConn.Close() - if err := utils.NewReply(utils.Succeeded, nil).Write(conn); err != nil { - log.Errorf(consts.SOCKS5_CONNECT_WRITE_ERROR, err) + if err := network.NewReply(network.SOCKS5RespSucceeded, nil).Write(conn); err != nil { + slog.Error(consts.SOCKS5_CONNECT_WRITE_ERROR, "err", err) return } - log.Infof(consts.SOCKS5_CONNECT_ESTAB, conn.RemoteAddr(), req.Addr) + slog.Info(consts.SOCKS5_CONNECT_ESTAB, "src", conn.RemoteAddr(), "dest", req.Addr) - if err := utils.Transport(conn, newConn); err != nil { - log.Errorf(consts.SOCKS5_CONNECT_TRANS_ERROR, err) + if err := network.Transport(conn, newConn); err != nil { + slog.Error(consts.SOCKS5_CONNECT_TRANS_ERROR, "err", err) } - log.Infof(consts.SOCKS5_CONNECT_DIS, conn.RemoteAddr(), req.Addr) + 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 f60c83e..97244ea 100644 --- a/pkg/consts/log.go +++ b/pkg/consts/log.go @@ -4,56 +4,58 @@ package consts const ( PROXY_ADDR_ERROR string = "ProxyAddr Empty, Please Check Your Config File" CA_ERROR string = "CA Init Error" - DEFAULT_HTTP string = "SeaMoon Listening For The HTTP/S Request, %s" - DEFAULT_SOCKS string = "SeaMoon Listening For The SOCKS5 Request: %s" - HTTP_LISTEN_ERROR string = "[Http] Client Start Listen Error: %s" - HTTP_ACCEPT_ERROR string = "[Http] Server Accept Error: %s" - SOCKS5_LISTEN_ERROR string = "[Socks5] Client Start Listen Error: %s" - SOCKS5_ACCEPT_ERROR string = "[Socks5] Client Accept Error: %s" - SOCKS5_READ_METHOD_ERROR string = "[Socks5] Read Methods Failed: %s" - SOCKS5_WRITE_METHOD_ERROR string = "[Socks5] Write Method Failed: %s" + 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" + 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" + 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" - SOCKS5_READ_COMMAND_ERROR string = "[Socks5] Read Command Failed: %s" - SOCKS5_WRITE_COMMAND_ERROR string = "[Socks5] Write Command Replay Failed: %s" - SOCKS5_CONNECT_DIAL_ERROR string = "[Socks5] Connect Dial Remote Failed: %s" - SOCKS5_CONNECT_WRITE_ERROR string = "[Socks5] Connect Write Reply Failed: %s" - SOCKS5_CONNECT_TRANS_ERROR string = "[Socks5] Connect Transport Failed: %s" - SOCKS5_BIND_LISTEN_ERROR string = "[Socks5] Bind Failed On Listen: %s" - SOCKS5_BIND_WRITE_ERROR string = "[Socks5] Bind Write Reply Failed %s" - SOCKS5_BIND_ACCEPT_ERROR string = "[Socks5] Bind Failed On Accept: %s" - SOCKS5_BIND_TRANS_ERROR string = "[Socks5] Bind Transport Failed: %s" - SOCKS5_UDP2TCP_LISTEN_ERROR string = "[Socks5] Udp-Over-Tcp UDP Associate Failed On Listen: %s`" - SOCKS5_UDP2TCP_WRITE_ERROR string = "[Socks5] Udp-Over-Tcp Write Reply Failed %s`" - SOCKS_UDP2TCP_UDP_ERROR string = "[Socks5] Udp-Over-Tcp Tunnel UDP Failed: %s`" - SOCKS_UPGRADE_ERROR string = "[Socks5] WebSocket Upgrade error: %s " + SOCKS5_READ_COMMAND_ERROR string = "[Socks5] Read Command Failed" + 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" + 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" + SOCKS5_BIND_TRANS_ERROR string = "[Socks5] Bind Transport Failed" + SOCKS5_UDP2TCP_LISTEN_ERROR string = "[Socks5] Udp-Over-Tcp UDP Associate Failed On Listen" + SOCKS5_UDP2TCP_WRITE_ERROR string = "[Socks5] Udp-Over-Tcp Write Reply Failed " + SOCKS_UDP2TCP_UDP_ERROR string = "[Socks5] Udp-Over-Tcp Tunnel UDP Failed" + SOCKS_UPGRADE_ERROR string = "[Socks5] WebSocket Upgrade error:" - CLIENT_PROTOCOL_UNSUPPORT_ERROR string = "Protocol Not Support: %s" + FORWARD_ACTION_EMPTY string = "[Forward] Empty ACTION" + + CLIENT_PROTOCOL_UNSUPPORT_ERROR string = "Protocol Not Support" ) // Info Log const ( CA_NOT_EXIST string = "Ca Not Exists, Run Auto Generate" CA_LOAD_SUCCESS string = "Ca Loaded Success" - PROXY_ADDR string = "Proxy Addr: %s" - HTTP_LISTEN_START string = "[Http] Client Start Listen At: %s" + PROXY_ADDR string = "Proxy Addr" + HTTP_LISTEN_START string = "[Http] Client Start Listen At" HTTP_LISTEN_STOP string = "[Http] Client Stop Listen" - HTTP_ACCEPT_START string = "[Http] Server Accept Conn From: %s" + 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: %s" - SOCKS5_LISTEN_START string = "[Socks5] Client Start Listen At: %s" + HTTP_BODY_DIS string = "[Http] Server Conn Disconnected" + SOCKS5_LISTEN_START string = "[Socks5] Client Start Listen At" SOCKS5_LISTEN_STOP string = "[Socks5] Client Stop Listen" - SOCKS5_ACCEPT_START string = "[Socks5] Client Accept Conn From: %s" - SOCKS5_CONNECT_SERVER string = "[Socks5] Server Connect %s From %s" - SOCKS5_CONNECT_ESTAB string = "[Socks5] Connect Tunnel Established %s <-> %s" - SOCKS5_CONNECT_DIS string = "[Socks5] Connect Tunnel Disconnected %s >-< %s" - SOCKS5_BIND_SERVER string = "[Socks5] Bind For %s" - SOCKS5_BIND_ESTAB string = "[Socks5] Bind Tunnel Established %s <-> %s" - SOCKS5_BIND_DIS string = "[Socks5] Bind Tunnel Disconnected %s >-< %s" - SOCKS_UPD2TCP_SERVER string = "[Socks5] Udp-Over-Tcp Associate UDP For %s" - SOCKS5_UPD2TCP_ESTAB string = "[Socks5] Udp-Over-Tcp Tunnel Established %s <-> (UDP)%s" - SOCKS5_UPD2TCP_DIS string = "[Socks5] Udp-Over-Tcp Tunnel Disconnected %s >-< (UDP)%s" + SOCKS5_ACCEPT_START string = "[Socks5] Client Accept Conn From" + SOCKS5_CONNECT_SERVER string = "[Socks5] Server Connect" + SOCKS5_CONNECT_ESTAB string = "[Socks5] Connect Tunnel Established" + SOCKS5_CONNECT_DIS string = "[Socks5] Connect Tunnel Disconnected" + SOCKS5_BIND_SERVER string = "[Socks5] Bind For" + SOCKS5_BIND_ESTAB string = "[Socks5] Bind Tunnel Established" + SOCKS5_BIND_DIS string = "[Socks5] Bind Tunnel Disconnected" + SOCKS_UPD2TCP_SERVER string = "[Socks5] Udp-Over-Tcp Associate UDP For" + SOCKS5_UPD2TCP_ESTAB string = "[Socks5] Udp-Over-Tcp Tunnel Established" + SOCKS5_UPD2TCP_DIS string = "[Socks5] Udp-Over-Tcp Tunnel Disconnected" - CONTROLLER_START string = "[Control] start control service at : %s" + CONTROLLER_START string = "[Control] start control service at" ) // debug log diff --git a/pkg/consts/version.go b/pkg/consts/version.go index 29b2767..03df7a1 100644 --- a/pkg/consts/version.go +++ b/pkg/consts/version.go @@ -1,3 +1,6 @@ package consts -var Version string = "dev" +var ( + Version string = "dev" + Commit string = "" +) diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go new file mode 100644 index 0000000..6db4c53 --- /dev/null +++ b/pkg/errors/errors.go @@ -0,0 +1,49 @@ +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/pkg/network/addr.go b/pkg/network/addr.go new file mode 100644 index 0000000..064c6d2 --- /dev/null +++ b/pkg/network/addr.go @@ -0,0 +1,155 @@ +package network + +import ( + "encoding/binary" + "net" + "strconv" +) + +/* +Addr has following struct + + +------+----------+----------+ + | Type | ADDR | PORT | + +------+----------+----------+ + | 1 | Variable | 2 | + +------+----------+----------+ +*/ +type Addr struct { + Type uint8 + Host string + Port uint16 +} + +func IsIPv4(address string) bool { + return address != "" && address[0] != ':' && address[0] != '[' +} + +// NewAddr creates an address object +func NewAddr(sa string) (addr *Addr, err error) { + host, sport, err := net.SplitHostPort(sa) + if err != nil { + return nil, err + } + port, err := strconv.Atoi(sport) + if err != nil { + return nil, err + } + + addr = NewAddrFromPair(host, port) + return +} + +// NewAddrFromPair creates an address object from host and port pair +func NewAddrFromPair(host string, port int) (addr *Addr) { + addr = &Addr{ + Type: AddrDomain, + Host: host, + Port: uint16(port), + } + + if ip := net.ParseIP(host); ip != nil { + if ip.To4() != nil { + addr.Type = AddrIPv4 + } else { + addr.Type = AddrIPv6 + } + } + + return +} + +// NewAddrFromAddr creates an address object +func NewAddrFromAddr(ln, conn net.Addr) (addr *Addr, err error) { + _, sport, err := net.SplitHostPort(ln.String()) + if err != nil { + return nil, err + } + host, _, err := net.SplitHostPort(conn.String()) + if err != nil { + return nil, err + } + port, err := strconv.Atoi(sport) + if err != nil { + return nil, err + } + + addr = NewAddrFromPair(host, port) + return +} + +// Decode an address from the stream +func (addr *Addr) Decode(b []byte) error { + addr.Type = b[0] + pos := 1 + switch addr.Type { + case AddrIPv4: + addr.Host = net.IP(b[pos : pos+net.IPv4len]).String() + pos += net.IPv4len + case AddrIPv6: + addr.Host = net.IP(b[pos : pos+net.IPv6len]).String() + pos += net.IPv6len + case AddrDomain: + addrlen := int(b[pos]) + pos++ + addr.Host = string(b[pos : pos+addrlen]) + pos += addrlen + default: + return ErrBadAddrType + } + + addr.Port = binary.BigEndian.Uint16(b[pos:]) + + return nil +} + +// Encode an address to the stream +func (addr *Addr) Encode(b []byte) (int, error) { + b[0] = addr.Type + pos := 1 + switch addr.Type { + case AddrIPv4: + ip4 := net.ParseIP(addr.Host).To4() + if ip4 == nil { + ip4 = net.IPv4zero.To4() + } + pos += copy(b[pos:], ip4) + case AddrDomain: + b[pos] = byte(len(addr.Host)) + pos++ + pos += copy(b[pos:], []byte(addr.Host)) + case AddrIPv6: + ip16 := net.ParseIP(addr.Host).To16() + if ip16 == nil { + ip16 = net.IPv6zero.To16() + } + pos += copy(b[pos:], ip16) + default: + b[0] = AddrIPv4 + copy(b[pos:pos+4], net.IPv4zero.To4()) + pos += 4 + } + binary.BigEndian.PutUint16(b[pos:], addr.Port) + pos += 2 + + return pos, nil +} + +// Length of the address +func (addr *Addr) Length() (n int) { + switch addr.Type { + case AddrIPv4: + n = 10 + case AddrIPv6: + n = 22 + case AddrDomain: + n = 7 + len(addr.Host) + default: + n = 10 + } + return +} + +func (addr *Addr) String() string { + return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port))) +} diff --git a/pkg/utils/auth.go b/pkg/network/auth.go similarity index 88% rename from pkg/utils/auth.go rename to pkg/network/auth.go index f6d3b19..259f323 100644 --- a/pkg/utils/auth.go +++ b/pkg/network/auth.go @@ -1,11 +1,12 @@ -package utils +package network import ( "crypto/subtle" "encoding/base64" - log "github.com/sirupsen/logrus" - "github.com/tg123/go-htpasswd" + "log/slog" "strings" + + "github.com/tg123/go-htpasswd" ) // StrEQ returns whether s1 and s2 are equal @@ -34,11 +35,11 @@ func VerifyByMap(users map[string]string) func(string, string) bool { } } -// VerifyByHtpasswd returns an verifier that verify by a htpasswd file +// VerifyByHtpasswd returns a verifier that verify by a htpasswd file func VerifyByHtpasswd(users string) func(string, string) bool { f, err := htpasswd.New(users, htpasswd.DefaultSystems, nil) if err != nil { - log.Fatalf("Load htpasswd file failed: %s", err) + slog.Error("Load htpasswd file failed", "err", err) } return func(username, password string) bool { return f.Match(username, password) diff --git a/pkg/network/buffer.go b/pkg/network/buffer.go new file mode 100644 index 0000000..2e846e5 --- /dev/null +++ b/pkg/network/buffer.go @@ -0,0 +1,123 @@ +package network + +// fork from go-gost/core + +import "sync" + +var ( + pools = []struct { + size int + pool sync.Pool + }{ + { + size: 128, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 128) + return b + }, + }, + }, + { + size: 512, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 512) + return b + }, + }, + }, + { + size: 1024, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 1024) + return b + }, + }, + }, + { + size: 2048, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 2048) + return b + }, + }, + }, + { + size: 4096, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 4096) + return b + }, + }, + }, + { + size: 8192, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 8192) + return b + }, + }, + }, + { + size: 16 * 1024, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 16*1024) + return b + }, + }, + }, + { + size: 32 * 1024, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 32*1024) + return b + }, + }, + }, + { + size: 64 * 1024, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 64*1024) + return b + }, + }, + }, + { + size: 65 * 1024, + pool: sync.Pool{ + New: func() any { + b := make([]byte, 65*1024) + return b + }, + }, + }, + } +) + +// GetBuffer returns a buffer of specified size. +func GetBuffer(size int) []byte { + for i := range pools { + if size <= pools[i].size { + b := pools[i].pool.Get().([]byte) + return b[:size] + } + } + b := make([]byte, size) + return b +} + +func PutBuffer(b []byte) { + for i := range pools { + if cap(b) == pools[i].size { + pools[i].pool.Put(b) + } + } +} diff --git a/pkg/network/errors.go b/pkg/network/errors.go new file mode 100644 index 0000000..4e8ce07 --- /dev/null +++ b/pkg/network/errors.go @@ -0,0 +1,12 @@ +package network + +import "errors" + +var ( + ErrBadVersion = errors.New("Bad version") + ErrBadFormat = errors.New("Bad format") + ErrBadAddrType = errors.New("Bad address type") + ErrShortBuffer = errors.New("Short buffer") + ErrBadMethod = errors.New("Bad method") + ErrAuthFailure = errors.New("Auth failure") +) diff --git a/pkg/utils/http.go b/pkg/network/http.go similarity index 99% rename from pkg/utils/http.go rename to pkg/network/http.go index d8f4fad..fba2ae4 100644 --- a/pkg/utils/http.go +++ b/pkg/network/http.go @@ -1,4 +1,4 @@ -package utils +package network import ( "bytes" diff --git a/pkg/utils/socks.go b/pkg/network/socks5.go similarity index 56% rename from pkg/utils/socks.go rename to pkg/network/socks5.go index 0e40f7a..4cc5057 100644 --- a/pkg/utils/socks.go +++ b/pkg/network/socks5.go @@ -1,59 +1,26 @@ -package utils +package network // This file is modified version from https://github.com/ginuerzh/gosocks5/blob/master/socks5.go import ( "bytes" "encoding/binary" - "errors" "fmt" "io" "io/ioutil" - "net" - "strconv" - "sync" - - "github.com/gorilla/websocket" ) -// buffer pools -var ( - SPool = sync.Pool{ - New: func() interface{} { - return make([]byte, 576) - }, - } // small buff pool - LPool = sync.Pool{ - New: func() interface{} { - return make([]byte, 32768) - }, - } // large buff pool for udp +// Address types +const ( + AddrIPv4 uint8 = 1 + AddrDomain = 3 + AddrIPv6 = 4 ) -// Transport rw1 and rw2 -func Transport(rw1, rw2 io.ReadWriter) error { - errC := make(chan error, 1) - go func() { - _, err := io.CopyBuffer(rw1, rw2, nil) - errC <- err - }() - - go func() { - _, err := io.CopyBuffer(rw2, rw1, nil) - errC <- err - }() - - if err := <-errC; err != nil && err != io.EOF && !websocket.IsUnexpectedCloseError(err) { - return err - } - - return nil -} - -// Version = 5 +// SOCKS5 Version = 5 const ( - Version = 5 - UserPassVer = 1 + SOCKS5Version = 5 + SOCKS5UserPassVer = 1 ) // Methods @@ -64,64 +31,52 @@ const ( MethodNoAcceptable uint8 = 0xFF ) -// Commands +// SOCKS5 Commands const ( - CmdConnect uint8 = iota + 1 - CmdBind - CmdUDP - CmdUDPOverTCP + SOCKS5CmdConnect uint8 = iota + 1 + SOCKS5CmdBind + SOCKS5CmdUDP + SOCKS5CmdUDPOverTCP ) -// Address types +// SOCKS5 Response codes const ( - AddrIPv4 uint8 = 1 - AddrDomain = 3 - AddrIPv6 = 4 + SOCKS5RespSucceeded uint8 = iota + SOCKS5RespFailure + SOCKS5RespAllowed + SOCKS5RespNetUnreachable + SOCKS5RespHostUnreachable + SOCKS5RespConnRefused + SOCKS5RespTTLExpired + SOCKS5RespCmdUnsupported + SOCKS5RespAddrUnsupported ) -// Response codes const ( - Succeeded uint8 = iota - Failure - Allowed - NetUnreachable - HostUnreachable - ConnRefused - TTLExpired - CmdUnsupported - AddrUnsupported -) - -// Errors -var ( - ErrBadVersion = errors.New("Bad version") - ErrBadFormat = errors.New("Bad format") - ErrBadAddrType = errors.New("Bad address type") - ErrShortBuffer = errors.New("Short buffer") - ErrBadMethod = errors.New("Bad method") - ErrAuthFailure = errors.New("Auth failure") + smallSize = 576 + largeSize = 32 * 1024 ) /* ReadMethods returns methods Method selection - +----+----------+----------+ - |VER | NMETHODS | METHODS | - +----+----------+----------+ - | 1 | 1 | 1 to 255 | - +----+----------+----------+ + + +----+----------+----------+ + |VER | NMETHODS | METHODS | + +----+----------+----------+ + | 1 | 1 | 1 to 255 | + +----+----------+----------+ */ func ReadMethods(r io.Reader) ([]uint8, error) { - //b := make([]byte, 257) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) n, err := io.ReadAtLeast(r, b, 2) if err != nil { return nil, err } - if b[0] != Version { + if b[0] != SOCKS5Version { return nil, ErrBadVersion } @@ -144,14 +99,14 @@ func ReadMethods(r io.Reader) ([]uint8, error) { // WriteMethod send the selected method to the client func WriteMethod(method uint8, w io.Writer) error { - _, err := w.Write([]byte{Version, method}) + _, err := w.Write([]byte{SOCKS5Version, method}) return err } // WriteMethods send method select request to the server func WriteMethods(methods []uint8, w io.Writer) error { b := make([]byte, 2+len(methods)) - b[0] = Version + b[0] = SOCKS5Version b[1] = uint8(len(methods)) copy(b[2:], methods) @@ -160,12 +115,13 @@ func WriteMethods(methods []uint8, w io.Writer) error { } /* - Username/Password authentication request - +----+------+----------+------+----------+ - |VER | ULEN | UNAME | PLEN | PASSWD | - +----+------+----------+------+----------+ - | 1 | 1 | 1 to 255 | 1 | 1 to 255 | - +----+------+----------+------+----------+ +UserPassRequest Username/Password authentication request + + +----+------+----------+------+----------+ + |VER | ULEN | UNAME | PLEN | PASSWD | + +----+------+----------+------+----------+ + | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + +----+------+----------+------+----------+ */ type UserPassRequest struct { Version byte @@ -182,16 +138,15 @@ func NewUserPassRequest(ver byte, u, p string) *UserPassRequest { } func ReadUserPassRequest(r io.Reader) (*UserPassRequest, error) { - // b := make([]byte, 513) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) n, err := io.ReadAtLeast(r, b, 2) if err != nil { return nil, err } - if b[0] != UserPassVer { + if b[0] != SOCKS5UserPassVer { return nil, ErrBadVersion } @@ -223,8 +178,8 @@ func ReadUserPassRequest(r io.Reader) (*UserPassRequest, error) { func (req *UserPassRequest) Write(w io.Writer) error { // b := make([]byte, 513) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) b[0] = req.Version ulen := len(req.Username) @@ -248,12 +203,13 @@ func (req *UserPassRequest) String() string { } /* - Username/Password authentication response - +----+--------+ - |VER | STATUS | - +----+--------+ - | 1 | 1 | - +----+--------+ +UserPassResponse Username/Password authentication response + + +----+--------+ + |VER | STATUS | + +----+--------+ + | 1 | 1 | + +----+--------+ */ type UserPassResponse struct { Version byte @@ -269,14 +225,14 @@ func NewUserPassResponse(ver, status byte) *UserPassResponse { func ReadUserPassResponse(r io.Reader) (*UserPassResponse, error) { // b := make([]byte, 2) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) if _, err := io.ReadFull(r, b[:2]); err != nil { return nil, err } - if b[0] != UserPassVer { + if b[0] != SOCKS5UserPassVer { return nil, ErrBadVersion } @@ -299,186 +255,44 @@ func (res *UserPassResponse) String() string { } /* -Addr has following struct - +------+----------+----------+ - | ATYP | ADDR | PORT | - +------+----------+----------+ - | 1 | Variable | 2 | - +------+----------+----------+ -*/ -type Addr struct { - Type uint8 - Host string - Port uint16 -} - -// NewAddr creates an address object -func NewAddr(sa string) (addr *Addr, err error) { - host, sport, err := net.SplitHostPort(sa) - if err != nil { - return nil, err - } - port, err := strconv.Atoi(sport) - if err != nil { - return nil, err - } - - addr = NewAddrFromPair(host, port) - return -} - -// NewAddrFromPair creates an address object from host and port pair -func NewAddrFromPair(host string, port int) (addr *Addr) { - addr = &Addr{ - Type: AddrDomain, - Host: host, - Port: uint16(port), - } - - if ip := net.ParseIP(host); ip != nil { - if ip.To4() != nil { - addr.Type = AddrIPv4 - } else { - addr.Type = AddrIPv6 - } - } - - return -} - -// NewAddrFromAddr creates an address object -func NewAddrFromAddr(ln, conn net.Addr) (addr *Addr, err error) { - _, sport, err := net.SplitHostPort(ln.String()) - if err != nil { - return nil, err - } - host, _, err := net.SplitHostPort(conn.String()) - if err != nil { - return nil, err - } - port, err := strconv.Atoi(sport) - if err != nil { - return nil, err - } - - addr = NewAddrFromPair(host, port) - return -} - -// Decode an address from the stream -func (addr *Addr) Decode(b []byte) error { - addr.Type = b[0] - pos := 1 - switch addr.Type { - case AddrIPv4: - addr.Host = net.IP(b[pos : pos+net.IPv4len]).String() - pos += net.IPv4len - case AddrIPv6: - addr.Host = net.IP(b[pos : pos+net.IPv6len]).String() - pos += net.IPv6len - case AddrDomain: - addrlen := int(b[pos]) - pos++ - addr.Host = string(b[pos : pos+addrlen]) - pos += addrlen - default: - return ErrBadAddrType - } - - addr.Port = binary.BigEndian.Uint16(b[pos:]) - - return nil -} - -// Encode an address to the stream -func (addr *Addr) Encode(b []byte) (int, error) { - b[0] = addr.Type - pos := 1 - switch addr.Type { - case AddrIPv4: - ip4 := net.ParseIP(addr.Host).To4() - if ip4 == nil { - ip4 = net.IPv4zero.To4() - } - pos += copy(b[pos:], ip4) - case AddrDomain: - b[pos] = byte(len(addr.Host)) - pos++ - pos += copy(b[pos:], []byte(addr.Host)) - case AddrIPv6: - ip16 := net.ParseIP(addr.Host).To16() - if ip16 == nil { - ip16 = net.IPv6zero.To16() - } - pos += copy(b[pos:], ip16) - default: - b[0] = AddrIPv4 - copy(b[pos:pos+4], net.IPv4zero.To4()) - pos += 4 - } - binary.BigEndian.PutUint16(b[pos:], addr.Port) - pos += 2 - - return pos, nil -} - -// Length of the address -func (addr *Addr) Length() (n int) { - switch addr.Type { - case AddrIPv4: - n = 10 - case AddrIPv6: - n = 22 - case AddrDomain: - n = 7 + len(addr.Host) - default: - n = 10 - } - return -} - -func (addr *Addr) String() string { - return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port))) -} - -/* -Request represent a socks5 request +SOCKS5Request represent a socks5 request The SOCKSv5 request - +----+-----+-------+------+----------+----------+ - |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ + + +----+-----+-------+------+----------+----------+ + |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ */ -type Request struct { +type SOCKS5Request struct { Cmd uint8 Addr *Addr } -// NewRequest creates an request object -func NewRequest(cmd uint8, addr *Addr) *Request { - return &Request{ +// NewSOCKS5Request creates an request object +func NewSOCKS5Request(cmd uint8, addr *Addr) *SOCKS5Request { + return &SOCKS5Request{ Cmd: cmd, Addr: addr, } } -// ReadRequest reads request from the stream -func ReadRequest(r io.Reader) (*Request, error) { +// ReadSOCKS5Request reads request from the stream +func ReadSOCKS5Request(r io.Reader) (*SOCKS5Request, error) { // b := make([]byte, 262) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) n, err := io.ReadAtLeast(r, b, 5) if err != nil { return nil, err } - if b[0] != Version { + if b[0] != SOCKS5Version { return nil, ErrBadVersion } - request := &Request{ + request := &SOCKS5Request{ Cmd: b[1], } @@ -509,12 +323,12 @@ func ReadRequest(r io.Reader) (*Request, error) { return request, nil } -func (r *Request) Write(w io.Writer) (err error) { +func (r *SOCKS5Request) Write(w io.Writer) (err error) { //b := make([]byte, 262) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) - b[0] = Version + b[0] = SOCKS5Version b[1] = r.Cmd b[2] = 0 //rsv b[3] = AddrIPv4 // default @@ -530,7 +344,7 @@ func (r *Request) Write(w io.Writer) (err error) { return } -func (r *Request) String() string { +func (r *SOCKS5Request) String() string { addr := r.Addr if addr == nil { addr = &Addr{} @@ -541,11 +355,12 @@ func (r *Request) String() string { /* Reply is a SOCKSv5 reply - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ + + +----+-----+-------+------+----------+----------+ + |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | + +----+-----+-------+------+----------+----------+ + | 1 | 1 | X'00' | 1 | Variable | 2 | + +----+-----+-------+------+----------+----------+ */ type Reply struct { Rep uint8 @@ -563,15 +378,15 @@ func NewReply(rep uint8, addr *Addr) *Reply { // ReadReply reads a reply from the stream func ReadReply(r io.Reader) (*Reply, error) { // b := make([]byte, 262) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) n, err := io.ReadAtLeast(r, b, 5) if err != nil { return nil, err } - if b[0] != Version { + if b[0] != SOCKS5Version { return nil, ErrBadVersion } @@ -609,10 +424,10 @@ func ReadReply(r io.Reader) (*Reply, error) { func (r *Reply) Write(w io.Writer) (err error) { // b := make([]byte, 262) - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) - b[0] = Version + b[0] = SOCKS5Version b[1] = r.Rep b[2] = 0 //rsv b[3] = AddrIPv4 // default @@ -639,11 +454,12 @@ func (r *Reply) String() string { /* UDPHeader is the header of an UDP request - +----+------+------+----------+----------+----------+ - |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | - +----+------+------+----------+----------+----------+ - | 2 | 1 | 1 | Variable | 2 | Variable | - +----+------+------+----------+----------+----------+ + + +----+------+------+----------+----------+----------+ + |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | + +----+------+------+----------+----------+----------+ + | 2 | 1 | 1 | Variable | 2 | Variable | + +----+------+------+----------+----------+----------+ */ type UDPHeader struct { Rsv uint16 @@ -661,8 +477,8 @@ func NewUDPHeader(rsv uint16, frag uint8, addr *Addr) *UDPHeader { } func (h *UDPHeader) Write(w io.Writer) error { - b := SPool.Get().([]byte) - defer SPool.Put(b) + b := GetBuffer(smallSize) + defer PutBuffer(b) binary.BigEndian.PutUint16(b[:2], h.Rsv) b[2] = h.Frag @@ -698,8 +514,8 @@ func NewUDPDatagram(header *UDPHeader, data []byte) *UDPDatagram { // ReadUDPDatagram reads an UDPDatagram from the stream func ReadUDPDatagram(r io.Reader) (*UDPDatagram, error) { - b := LPool.Get().([]byte) - defer LPool.Put(b) + b := GetBuffer(largeSize) + defer PutBuffer(b) // when r is a streaming (such as TCP connection), we may read more than the required data, // but we don't know how to handle it. So we use io.ReadFull to instead of io.ReadAtLeast diff --git a/pkg/network/transport.go b/pkg/network/transport.go new file mode 100644 index 0000000..d07c968 --- /dev/null +++ b/pkg/network/transport.go @@ -0,0 +1,33 @@ +package network + +import ( + "io" +) + +const bufferSize = 64 * 1024 + +// Transport rw1 and rw2 +func Transport(rw1, rw2 io.ReadWriter) error { + errC := make(chan error, 1) + go func() { + errC <- CopyBuffer(rw1, rw2, bufferSize) + }() + + go func() { + errC <- CopyBuffer(rw2, rw1, bufferSize) + }() + + if err := <-errC; err != nil && err != io.EOF { + return err + } + + return nil +} + +func CopyBuffer(dst io.Writer, src io.Reader, bufSize int) error { + buf := GetBuffer(bufSize) + defer PutBuffer(buf) + + _, err := io.CopyBuffer(dst, src, buf) + return err +} diff --git a/pkg/server/http.go b/pkg/server/http.go deleted file mode 100644 index 85907d0..0000000 --- a/pkg/server/http.go +++ /dev/null @@ -1,118 +0,0 @@ -package server - -import ( - "errors" - "fmt" - "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/utils" - log "github.com/sirupsen/logrus" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -var HttpForwardHeader = map[string]string{"SM-HOST": "", "Proxy-Authenticate": "", "Proxy-Authorization": "", - "Connection": "", "Keep-Alive": "", - "Proxy-Connection": "", - "Te": "", "Trailer": "", "Transfer-Encoding": "", "Content-Encoding": ""} - -type HttpServer struct { - CloudServer - remoteUrl *url.URL - remoteHost string -} - -func (s *Server) HttpServerTransfer(r *http.Request) CloudServer { - return newHttpServer(r) -} - -func (s *HttpServer) Verification(w http.ResponseWriter) (bool, error) { - // forward host 不为空 - // 环路判断问题: 因为代理发出的请求是不带 SM-HOST 标识的,所以这个return会直接阻止了环路。 - // 也就是说,最多只会重复请求两次,即代理请求一次自己后,返回了此处的异常。 - if s.remoteHost == "" { - var errMsg = "no sm-ost in request" - utils.HealthResponse(fmt.Sprintf(consts.DEFAULT_HTTP, errMsg), w) - return false, errors.New(errMsg) - } - var err error - s.remoteUrl, err = url.Parse(s.remoteHost) - if err != nil { - utils.HealthResponse(consts.DEFAULT_HTTP, w) - return false, err - } - return true, nil -} - -func (s *HttpServer) Serve(w http.ResponseWriter, req *http.Request) { - conn := req.Header.Get("Proxy-Connection") - for key, _ := range HttpForwardHeader { - req.Header.Del(key) - } - req.Header.Set("Host", s.remoteHost) - if conn != "" { - req.Header.Set("Connection", conn) - } - req.URL = s.remoteUrl - req.Host = s.remoteUrl.Host - err := s.httpHandler(w, req) - if err != nil { - log.Error(err) - } -} - -func newHttpServer(r *http.Request) *HttpServer { - host := r.Header.Get("SM-HOST") - return &HttpServer{ - remoteHost: host, - } -} - -func (s *HttpServer) httpHandler(w http.ResponseWriter, req *http.Request) error { - log.Infof(consts.HTTP_ACCEPT_START, req.RemoteAddr) - proxyReq, err := http.NewRequest(req.Method, s.remoteHost, req.Body) - if err != nil { - return err - } - proxyReq.Header = req.Header - proxyReq.Proto = req.Proto - response, err := utils.DoHttp(proxyReq) - if err != nil { - utils.ErrorResponse("SeaMoon HTTP Error: "+err.Error(), http.StatusBadRequest, w) - log.Errorf(consts.HTTP_ACCEPT_ERROR, err.Error()) - return err - } else { - // head - for key, value := range response.Header { - for i := 0; i < len(value); i++ { - if _, ok := HttpForwardHeader[key]; ok { - continue - } - if key == "Content-Length" { - continue - } - w.Header().Add(key, value[i]) - } - } - // proto - w.WriteHeader(response.StatusCode) - - // body - body, errRead := ioutil.ReadAll(response.Body) - if errRead != nil { - return errRead - } - defer response.Body.Close() - - if strings.Contains(response.Header.Get("Content-Encoding"), "gzip") { - body = utils.UnGzip(body) - } - // write - if _, err := w.Write(body); err != nil { - return err - } - } - log.Infof(consts.HTTP_BODY_DIS, response.Request.Host) - return nil -} diff --git a/pkg/server/server.go b/pkg/server/server.go deleted file mode 100644 index 1698a2a..0000000 --- a/pkg/server/server.go +++ /dev/null @@ -1,53 +0,0 @@ -package server - -import ( - log "github.com/sirupsen/logrus" - "net/http" - "os" - "strings" -) - -type CloudServer interface { - Verification(http.ResponseWriter) (bool, error) - Serve(http.ResponseWriter, *http.Request) -} - -type Server struct { - proto string - host string - port string -} - -func NewServer(proto string, host string, port string) *Server { - return &Server{ - proto: proto, - host: host, - port: port, - } -} - -var protocol2Server = map[string]func(*Server, *http.Request) CloudServer{ - "http": (*Server).HttpServerTransfer, - "socks5": (*Server).SocksServerTransfer, -} - -func (s *Server) Serve() { - // http server - serverAddr := strings.Join(append([]string{s.host, s.port}), ":") - // http handler - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - transfer := protocol2Server[s.proto] - - service := transfer(s, r) - // do check - if ok, err := service.Verification(w); ok { - service.Serve(w, r) - } else { - log.Error(err) - } - }) - // http服务 - if err := http.ListenAndServe(serverAddr, nil); err != nil { - os.Exit(0) - } -} diff --git a/pkg/server/socks.go b/pkg/server/socks.go deleted file mode 100644 index dec7283..0000000 --- a/pkg/server/socks.go +++ /dev/null @@ -1,129 +0,0 @@ -package server - -import ( - "errors" - "net" - "net/http" - "strconv" - "strings" - "sync" - "time" - - "github.com/gorilla/websocket" - log "github.com/sirupsen/logrus" - - "github.com/DVKunion/SeaMoon/pkg/consts" - "github.com/DVKunion/SeaMoon/pkg/utils" -) - -type SocksServer struct { - CloudServer - request *utils.Request -} - -func (s *Server) SocksServerTransfer(r *http.Request) CloudServer { - return newSocksServer(r) -} - -func (s *SocksServer) Verification(w http.ResponseWriter) (bool, error) { - // check target && port - if s.request.Addr == nil || s.request.Cmd == 0 { - var errMsg = "socks remote error" - return false, errors.New(errMsg) - } - return true, nil -} - -func (s *SocksServer) Serve(w http.ResponseWriter, r *http.Request) { - lock := &sync.Mutex{} - // socks upgrade websocket - upGrader := websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - } - - conn, err := upGrader.Upgrade(w, r, nil) - if err != nil { - log.Errorf("websocket upgrade error: %s", err) - return - } - - wsConn := NewWebsocketServer(conn, lock) - defer wsConn.Close() - - switch s.request.Cmd { - case utils.CmdConnect: - s.handleConnect(wsConn) - case utils.CmdBind: - s.handleBind() - case utils.CmdUDPOverTCP: - s.handleUDPOverTCP() - default: - log.Errorf("UnSupport Command") - } -} - -func newSocksServer(r *http.Request) *SocksServer { - - var ss = &SocksServer{request: &utils.Request{}} - - cmd := r.Header.Get("SM-CMD") - target := r.Header.Get("SM-TARGET") - if target != "" && len(strings.Split(target, ":")) > 1 { - host := strings.Split(target, ":")[0] - port := strings.Split(target, ":")[1] - if reqPort, err := strconv.ParseUint(port, 10, 16); err == nil { - ss.request.Addr = &utils.Addr{ - Host: host, - Port: uint16(reqPort), - Type: utils.AddrDomain, - } - } else { - log.Error(err) - } - } - - transCommand := map[string]uint8{ - "CONNECT": utils.CmdConnect, - "BIND": utils.CmdBind, - "UDP": utils.CmdUDPOverTCP, - } - - if command, ok := transCommand[cmd]; ok { - ss.request.Cmd = command - } - - return ss -} - -func (s *SocksServer) handleConnect(conn net.Conn) { - log.Infof(consts.SOCKS5_CONNECT_SERVER, s.request.Addr, conn.RemoteAddr()) - // default socks timeout : 10 - dialer := net.Dialer{Timeout: 10 * time.Second} - newConn, err := dialer.Dial("tcp", s.request.Addr.String()) - - if err != nil { - log.Errorf(consts.SOCKS5_CONNECT_DIAL_ERROR, err) - return - } - - // if utils.Transport get out , then close conn of remote - defer newConn.Close() - - log.Infof(consts.SOCKS5_CONNECT_ESTAB, conn.RemoteAddr(), s.request.Addr) - - if err := utils.Transport(conn, newConn); err != nil { - log.Errorf(consts.SOCKS5_CONNECT_TRANS_ERROR, err) - } - - log.Infof(consts.SOCKS5_CONNECT_DIS, conn.RemoteAddr(), s.request.Addr) -} - -func (s *SocksServer) handleBind() { - // TODO -} - -func (s *SocksServer) handleUDPOverTCP() { - // TODO -} diff --git a/pkg/server/websocket.go b/pkg/server/websocket.go deleted file mode 100644 index 3030d6f..0000000 --- a/pkg/server/websocket.go +++ /dev/null @@ -1,65 +0,0 @@ -package server - -import ( - "io" - "net" - "sync" - - "github.com/gorilla/websocket" -) - -type WebsocketServer struct { - net.Conn - wConn *websocket.Conn - writeLock *sync.Mutex - - messageType int -} - -func NewWebsocketServer(wConn *websocket.Conn, lock *sync.Mutex) net.Conn { - return &WebsocketServer{ - wConn: wConn, - messageType: websocket.BinaryMessage, - writeLock: lock, - } -} - -func (ws *WebsocketServer) RemoteAddr() net.Addr { - return ws.wConn.RemoteAddr() -} - -func (ws *WebsocketServer) Close() error { - // ws need send close message first to avoid err : close 1006 (abnormal closure): unexpected EOF - err := ws.write(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "close")) - if err != nil { - return err - } - return ws.wConn.Close() -} - -func (ws *WebsocketServer) Write(b []byte) (n int, err error) { - err = ws.write(ws.messageType, b) - if err != nil { - return 0, err - } - return len(b), nil -} - -func (ws *WebsocketServer) write(messageType int, data []byte) error { - ws.writeLock.TryLock() - defer ws.writeLock.Unlock() - return ws.wConn.WriteMessage(messageType, data) -} - -func (ws *WebsocketServer) Read(b []byte) (n int, err error) { - mt, message, err := ws.wConn.ReadMessage() - if err != nil { - if wsErr, ok := err.(*websocket.CloseError); ok && wsErr.Code == websocket.CloseNormalClosure { - return 0, io.EOF - } - return 0, err - } - ws.messageType = mt - copy(b, message) - return len(message), nil -} diff --git a/pkg/transfer/http.go b/pkg/transfer/http.go new file mode 100644 index 0000000..3610209 --- /dev/null +++ b/pkg/transfer/http.go @@ -0,0 +1,67 @@ +package transfer + +import ( + "bufio" + "net" + "net/http" + + "github.com/DVKunion/SeaMoon/pkg/network" +) + +func HttpTransport(conn net.Conn) error { + defer conn.Close() + + // 接收客户端的连接,并从第一条消息中获取目标地址 + request, err := http.ReadRequest(bufio.NewReader(conn)) + if err != nil { + return err + } + + defer request.Body.Close() + + targetAddr := request.Host + + if targetAddr == "" || err != nil { + return err + } + + if _, port, _ := net.SplitHostPort(targetAddr); port == "" { + targetAddr = net.JoinHostPort(targetAddr, "80") + } + + // 连接到目标服务器 + destConn, err := net.Dial("tcp", targetAddr) + if err != nil { + return err + } + + defer destConn.Close() + + resp := &http.Response{ + ProtoMajor: 1, + ProtoMinor: 1, + } + if resp.Header == nil { + resp.Header = http.Header{} + } + + if request.Method == http.MethodConnect { + resp.StatusCode = http.StatusOK + resp.Status = "200 Connection established" + + if err = resp.Write(conn); err != nil { + return err + } + } else { + if err = request.Write(destConn); err != nil { + return err + } + } + + // 同时处理客户端到服务器和服务器到客户端的数据传输 + if err := network.Transport(destConn, conn); err != nil { + return err + } + + return nil +} diff --git a/pkg/transfer/socks5.go b/pkg/transfer/socks5.go new file mode 100644 index 0000000..4d992a1 --- /dev/null +++ b/pkg/transfer/socks5.go @@ -0,0 +1,58 @@ +package transfer + +import ( + "errors" + "log/slog" + "net" + "time" + + "github.com/DVKunion/SeaMoon/pkg/consts" + "github.com/DVKunion/SeaMoon/pkg/network" +) + +func Socks5Transport(conn net.Conn, req *network.SOCKS5Request) error { + switch req.Cmd { + case network.SOCKS5CmdConnect: + handleConnect(conn, req) + case network.SOCKS5CmdBind: + handleBind() + case network.SOCKS5CmdUDP: + handleUDPOverTCP() + case network.SOCKS5CmdUDPOverTCP: + handleUDPOverTCP() + default: + return errors.New("") + } + return errors.New("") +} + +func handleConnect(conn net.Conn, req *network.SOCKS5Request) { + slog.Info(consts.SOCKS5_CONNECT_SERVER, "src", conn.RemoteAddr(), "dest", req.Addr) + // default socks timeout : 10 + dialer := net.Dialer{Timeout: 10 * time.Second} + destConn, err := dialer.Dial("tcp", req.Addr.String()) + + if err != nil { + slog.Error(consts.SOCKS5_CONNECT_DIAL_ERROR, "err", err) + return + } + + // if utils.Transport get out , then close conn of remote + defer destConn.Close() + + 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.Info(consts.SOCKS5_CONNECT_DIS, "src", conn.RemoteAddr(), "dest", req.Addr) +} + +func handleBind() { + // TODO +} + +func handleUDPOverTCP() { + // TODO +} diff --git a/pkg/tunnel/tunnel.go b/pkg/tunnel/tunnel.go new file mode 100644 index 0000000..bdc38ef --- /dev/null +++ b/pkg/tunnel/tunnel.go @@ -0,0 +1,30 @@ +package tunnel + +import ( + "net" +) + +// Tunnel is a bridge implementation for data transmission +// tunnel 不应该解决如何处理流量信息,仅仅是一个桥梁,用于信道传输。 +type Tunnel interface { + net.Conn +} + +type Type string + +const ( + NULL = "unknown" + WST = "websocket-tunnel" + GRT = "grpc-tunnel" +) + +func TranType(t string) Type { + switch t { + case "websocket": + return WST + case "grpc": + return GRT + default: + return NULL + } +} diff --git a/pkg/tunnel/websocket.go b/pkg/tunnel/websocket.go new file mode 100644 index 0000000..69882b6 --- /dev/null +++ b/pkg/tunnel/websocket.go @@ -0,0 +1,58 @@ +package tunnel + +import ( + "sync" + "time" + + "github.com/gorilla/websocket" +) + +type websocketConn struct { + *websocket.Conn + rb []byte + mux sync.Mutex +} + +func WsWrapConn(conn *websocket.Conn) Tunnel { + return &websocketConn{ + Conn: conn, + } +} + +func (c *websocketConn) Read(b []byte) (n int, err error) { + if len(c.rb) == 0 { + _, c.rb, err = c.Conn.ReadMessage() + } + n = copy(b, c.rb) + c.rb = c.rb[n:] + return +} + +func (c *websocketConn) Write(b []byte) (n int, err error) { + err = c.WriteMessage(websocket.BinaryMessage, b) + n = len(b) + return +} + +func (c *websocketConn) WriteMessage(messageType int, data []byte) error { + c.mux.Lock() + defer c.mux.Unlock() + + return c.Conn.WriteMessage(messageType, data) +} + +func (c *websocketConn) SetDeadline(t time.Time) error { + c.mux.Lock() + defer c.mux.Unlock() + + if err := c.SetReadDeadline(t); err != nil { + return err + } + return c.SetWriteDeadline(t) +} + +func (c *websocketConn) SetWriteDeadline(t time.Time) error { + c.mux.Lock() + defer c.mux.Unlock() + return c.Conn.SetWriteDeadline(t) +} diff --git a/s.yaml b/s.yaml index 3cfd8d8..b07c808 100644 --- a/s.yaml +++ b/s.yaml @@ -16,25 +16,26 @@ 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=1.1.2" -o main cmd/aliyun_server.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 main.go path: ./ - - run: chmod +x main + - run: chmod +x seamoon path: ./ services: - SeaMoon-FC-HTTP-Proxy: + SeaMoon-WS-Node: component: fc props: region: ${vars.region} service: ${vars.service} function: - name: http-proxy # 请不要修改函数名,因为配置处需要使用磁名称来判断函数类型。 + name: ws-node # 请不要修改函数名,因为配置处需要使用磁名称来判断函数类型。 description: 'http-proxy' codeUri: './' customRuntimeConfig: command: - - ./main - environmentVariables: { serverMod: "http" } + - ./seamoon + args: + - "server" handler: main instanceConcurrency: 10 instanceType: e1 @@ -65,46 +66,4 @@ services: - POST - PUT - DELETE - - OPTIONS - SeaMoon-FC-Socks-Proxy: - component: fc - props: - region: ${vars.region} - service: ${vars.service} - function: - name: socks-proxy # 请不要修改函数名,因为配置处需要使用磁名称来判断函数类型。 - description: 'socks5-proxy' - codeUri: './' - customRuntimeConfig: - command: - - ./main - environmentVariables: { serverMod: "socks5" } - handler: main - instanceConcurrency: 10 - instanceType: e1 - cpu: 0.05 - diskSize: 512 - memorySize: 128 - runtime: custom - timeout: 300 - internetAccess: true - triggers: - - name: httpTrigger - type: http - config: - authType: anonymous - methods: - - GET - - POST - - PUT - - DELETE - customDomains: - - domainName: auto - protocol: HTTP - routeConfigs: - - path: /* - methods: - - GET - - POST - - PUT - - DELETE \ No newline at end of file + - OPTIONS \ No newline at end of file diff --git a/server/options.go b/server/options.go new file mode 100644 index 0000000..ff0de53 --- /dev/null +++ b/server/options.go @@ -0,0 +1,36 @@ +package server + +import "github.com/DVKunion/SeaMoon/pkg/tunnel" + +type Options struct { + host string // 监听地址 + port string // 监听端口 + proto tunnel.Type // 监听协议 +} + +type Option func(o *Options) (err error) + +func WithHost(host string) Option { + return func(o *Options) (err error) { + o.host = host + return + } +} + +func WithPort(port string) Option { + return func(o *Options) (err error) { + o.port = port + return + } +} + +func WithProto(t string) Option { + return func(o *Options) (err error) { + tt := tunnel.TranType(t) + if tt == tunnel.NULL { + // todo + } + o.proto = tt + return nil + } +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..c897f6f --- /dev/null +++ b/server/server.go @@ -0,0 +1,85 @@ +package server + +import ( + "context" + "errors" + "log/slog" + "net" + "net/http" + "strings" + "time" + + "github.com/DVKunion/SeaMoon/pkg/consts" + "github.com/DVKunion/SeaMoon/server/service" +) + +type Server struct { + srv service.Service + opts Options + + startAt time.Time +} + +func New(opts ...Option) (*Server, error) { + s := &Server{} + for _, o := range opts { + err := o(&s.opts) + if err != nil { + return s, err + } + } + // check + if srv, ok := service.Factory[s.opts.proto]; ok { + s.srv = srv + } + + if s.srv == nil { + return s, errors.New("xxxx") + } + + return s, nil +} + +func (s *Server) Serve(ctx context.Context) error { + // http server + serverAddr := strings.Join(append([]string{s.opts.host, s.opts.port}), ":") + + mux := http.NewServeMux() + + lc := net.ListenConfig{} + lc.SetMultipathTCP(true) + + ln, err := lc.Listen(ctx, "tcp", serverAddr) + + if err != nil { + return err + } + + server := &http.Server{ + Addr: serverAddr, + Handler: mux, + } + + s.srv.Handle(mux) + s.startAt = time.Now() + // inject + mux.HandleFunc("/_health", s.health) + + slog.Info("seamoon server start with", "options", s.opts) + // http服务 + if err := server.Serve(ln); err != nil { + slog.Error("server error", err) + return err + } + return nil +} + +func (s *Server) health(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte("OK\n" + s.startAt.Format("2006-01-02 15:04:05") + "\n" + consts.Version + "-" + consts.Commit)) + if err != nil { + slog.Error("server status error", "msg", err) + return + } +} diff --git a/server/service/service.go b/server/service/service.go new file mode 100644 index 0000000..872b08c --- /dev/null +++ b/server/service/service.go @@ -0,0 +1,17 @@ +package service + +import ( + "net/http" + + "github.com/DVKunion/SeaMoon/pkg/tunnel" +) + +type Service interface { + Handle(m *http.ServeMux) +} + +var Factory = map[tunnel.Type]Service{} + +func register(t tunnel.Type, s Service) { + Factory[t] = s +} diff --git a/server/service/websocket.go b/server/service/websocket.go new file mode 100644 index 0000000..72d3cee --- /dev/null +++ b/server/service/websocket.go @@ -0,0 +1,88 @@ +package service + +import ( + "log/slog" + "net/http" + "time" + + "github.com/gorilla/websocket" + + "github.com/DVKunion/SeaMoon/pkg/network" + "github.com/DVKunion/SeaMoon/pkg/transfer" + "github.com/DVKunion/SeaMoon/pkg/tunnel" +) + +const ( + defaultTimeout = 10 * time.Second + defaultReadBufferSize = 32 * 1024 +) + +type WSService struct { + upGrader *websocket.Upgrader +} + +func init() { + register(tunnel.WST, &WSService{}) +} + +func (s *WSService) Handle(m *http.ServeMux) { + s.upGrader = &websocket.Upgrader{ + HandshakeTimeout: defaultTimeout, + ReadBufferSize: defaultReadBufferSize, + WriteBufferSize: defaultReadBufferSize, + EnableCompression: true, + CheckOrigin: func(r *http.Request) bool { return true }, + } + // websocket http proxy handler + m.HandleFunc("/http", s.http) + + // websocket socks5 proxy handler + m.HandleFunc("/socks5", s.socks5) +} + +func (s *WSService) http(w http.ResponseWriter, r *http.Request) { + // means use http to connector + conn, err := s.upGrader.Upgrade(w, r, nil) + if err != nil { + return + } + t := tunnel.WsWrapConn(conn) + go func() { + if err := transfer.HttpTransport(t); err != nil { + slog.Error("connection error", "msg", err) + } + }() +} + +func (s *WSService) socks5(w http.ResponseWriter, r *http.Request) { + + cmd := r.Header.Get("SM-CMD") + target := r.Header.Get("SM-TARGET") + + addr, _ := network.NewAddr(target) + + request := &network.SOCKS5Request{ + Addr: addr, + } + + transCommand := map[string]uint8{ + "CONNECT": network.SOCKS5CmdConnect, + "BIND": network.SOCKS5CmdBind, + "UDP": network.SOCKS5CmdUDPOverTCP, + } + + if command, ok := transCommand[cmd]; ok { + request.Cmd = command + } + // means use socks5 to connector + conn, err := s.upGrader.Upgrade(w, r, nil) + if err != nil { + return + } + t := tunnel.WsWrapConn(conn) + go func() { + if err := transfer.Socks5Transport(t, request); err != nil { + slog.Error("connection error", "msg", err) + } + }() +}