diff --git a/.github/Dockerfile b/.github/Dockerfile new file mode 100644 index 00000000..3f0b9fc4 --- /dev/null +++ b/.github/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine +COPY chisel /app/ +ENTRYPOINT ["/app/chisel"] diff --git a/.github/goreleaser.yml b/.github/goreleaser.yml new file mode 100644 index 00000000..64cb3025 --- /dev/null +++ b/.github/goreleaser.yml @@ -0,0 +1,45 @@ +# test this goreleaser config with: +# - cd chisel +# - goreleaser --skip-publish --rm-dist --config .github/goreleaser.yml +builds: + - env: + - CGO_ENABLED=0 + ldflags: + - -s -w -X github.com/jpillora/chisel/share.BuildVersion={{.Version}} + flags: + - -trimpath + goos: + - linux + - darwin + - windows + goarch: + - 386 + - amd64 + - arm + - arm64 + - ppc64 + - ppc64le + - mips + - mipsle + - mips64 + - mips64le + - s390x + goarm: + - 6 + - 7 + gomips: + - hardfloat + - softfloat +archives: + - format: gz + files: + - none* +release: + draft: true + prerelease: auto +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83ecab03..a4950bc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,17 +1,18 @@ -on: [push, pull_request] name: CI +on: + pull_request: {} + push: {} +permissions: write-all jobs: # ================ - # TEST JOB - # runs on every push and PR - # runs 2x3 times (see matrix) + # BUILD AND TEST JOB # ================ test: - name: Test + name: Build & Test strategy: matrix: - go-version: [1.21.x] - platform: [ubuntu-latest] + go-version: [1.16.x, 1.17.x, 1.18.x, 1.19.x] + platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} steps: - name: Install Go @@ -23,4 +24,104 @@ jobs: - name: Build run: go build -v -o /dev/null . - name: Test - run: go test -v ./... \ No newline at end of file + run: go test -v ./... + # ================ + # RELEASE JOBS + # runs after a success test + # only runs on push "v*" tag + # ================ + release_binaries: + name: Release Binaries + needs: test + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: goreleaser + if: success() + uses: docker://goreleaser/goreleaser:latest + env: + GITHUB_USER: ${{ github.repository_owner }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: release --config .github/goreleaser.yml + # ================ + # RELEASE DOCKER IMAGES (on push "v*" tag) + # ================ + release_docker: + name: Release Docker Images + needs: test + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: jpillora + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: jpillora/chisel + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + file: .github/Dockerfile + platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/386,linux/arm/v7,linux/arm/v6 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: release --config .github/goreleaser.yml + release_docker: + name: Release Docker Images + needs: test + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v4 + with: + images: jpillora/chisel + tag-latest: true + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/386,linux/arm/v7,linux/arm/v6 + push: true + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} diff --git a/LICENSE b/LICENSE index 7ae236f7..08d56bd7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Jaime Pillora +Copyright (c) 2024 Jaime Pillora Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 3af60c8e..35a805af 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ sudo dnf -y install chisel ### Source ```sh -$ go install github.com/jpillora/chisel@latest +$ go install github.com/jpillora/chisel@latest -v ``` ## Demo @@ -104,7 +104,6 @@ $ chisel --help ``` - ``` plain $ chisel server --help @@ -210,7 +209,6 @@ $ chisel server --help ``` - ``` plain $ chisel client --help @@ -392,7 +390,6 @@ Internally, this is done using the _Password_ authentication method provided by 1. Now you have an encrypted, authenticated SOCKS5 connection over HTTP - #### Caveats Since WebSockets support is required: diff --git a/client/client.go b/client/client.go index c96edde6..59698be6 100644 --- a/client/client.go +++ b/client/client.go @@ -8,10 +8,10 @@ import ( "encoding/base64" "errors" "fmt" - "io/ioutil" "net" "net/http" "net/url" + "os" "regexp" "strings" "time" @@ -105,7 +105,7 @@ func NewClient(c *Config) (*Client, error) { tlsConfig: nil, } //set default log level - client.Logger.Info = true + client.Logger.Info = c.Verbose //configure tls if u.Scheme == "wss" { tc := &tls.Config{} @@ -118,7 +118,7 @@ func NewClient(c *Config) (*Client, error) { tc.InsecureSkipVerify = true } else if c.TLS.CA != "" { rootCAs := x509.NewCertPool() - if b, err := ioutil.ReadFile(c.TLS.CA); err != nil { + if b, err := os.ReadFile(c.TLS.CA); err != nil { return nil, fmt.Errorf("Failed to load file: %s", c.TLS.CA) } else if ok := rootCAs.AppendCertsFromPEM(b); !ok { return nil, fmt.Errorf("Failed to decode PEM: %s", c.TLS.CA) diff --git a/go.mod b/go.mod index 1c9259db..e699f502 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/jpillora/requestlog v1.0.0 github.com/jpillora/sizestr v1.0.0 - golang.org/x/crypto v0.13.0 - golang.org/x/net v0.15.0 + golang.org/x/crypto v0.12.0 + golang.org/x/net v0.14.0 golang.org/x/sync v0.3.0 ) @@ -18,8 +18,8 @@ require ( github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 // indirect github.com/jpillora/ansi v1.0.3 // indirect github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect ) -replace github.com/jpillora/chisel => ../chisel \ No newline at end of file +replace github.com/jpillora/chisel => ../chisel diff --git a/main.go b/main.go index f78ee156..525a2c7d 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "flag" "fmt" - "io/ioutil" "log" "net/http" "os" @@ -89,7 +88,7 @@ var commonHelp = ` func generatePidFile() { pid := []byte(strconv.Itoa(os.Getpid())) - if err := ioutil.WriteFile("chisel.pid", pid, 0644); err != nil { + if err := os.WriteFile("chisel.pid", pid, 0644); err != nil { log.Fatal(err) } } diff --git a/server/server_handler.go b/server/server_handler.go index 952aa4d8..a732e2b6 100644 --- a/server/server_handler.go +++ b/server/server_handler.go @@ -19,7 +19,7 @@ func (s *Server) handleClientHandler(w http.ResponseWriter, r *http.Request) { //websockets upgrade AND has chisel prefix upgrade := strings.ToLower(r.Header.Get("Upgrade")) protocol := r.Header.Get("Sec-WebSocket-Protocol") - if upgrade == "websocket" { + if upgrade == "websocket" { if protocol == chshare.ProtocolVersion { s.handleWebsocket(w, r) return @@ -101,13 +101,13 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, req *http.Request) { return } //print if client and server versions dont match - if c.Version != chshare.BuildVersion { - v := c.Version - if v == "" { - v = "" - } - l.Infof("Client version (%s) differs from server version (%s)", - v, chshare.BuildVersion) + cv := strings.TrimPrefix(c.Version, "v") + if cv == "" { + cv = "" + } + sv := strings.TrimPrefix(chshare.BuildVersion, "v") + if cv != sv { + l.Infof("Client version (%s) differs from server version (%s)", cv, sv) } //validate remotes for _, r := range c.Remotes { diff --git a/server/server_listen.go b/server/server_listen.go index a7dcfe84..f6eb1ffa 100644 --- a/server/server_listen.go +++ b/server/server_listen.go @@ -4,7 +4,6 @@ import ( "crypto/tls" "crypto/x509" "errors" - "io/ioutil" "net" "os" "os/user" @@ -116,7 +115,7 @@ func addCA(ca string, c *tls.Config) error { clientCAPool := x509.NewCertPool() if fileInfo.IsDir() { //this is a directory holding CA bundle files - files, err := ioutil.ReadDir(ca) + files, err := os.ReadDir(ca) if err != nil { return err } @@ -140,7 +139,7 @@ func addCA(ca string, c *tls.Config) error { } func addPEMFile(path string, pool *x509.CertPool) error { - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { return err } diff --git a/share/cio/stdio.go b/share/cio/stdio.go index 24798def..16327989 100644 --- a/share/cio/stdio.go +++ b/share/cio/stdio.go @@ -2,7 +2,6 @@ package cio import ( "io" - "io/ioutil" "os" ) @@ -11,6 +10,6 @@ var Stdio = &struct { io.ReadCloser io.Writer }{ - ioutil.NopCloser(os.Stdin), + io.NopCloser(os.Stdin), os.Stdout, } diff --git a/share/settings/users.go b/share/settings/users.go index ea57f280..a6f0a093 100644 --- a/share/settings/users.go +++ b/share/settings/users.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "os" "regexp" "sync" @@ -125,7 +125,7 @@ func (u *UserIndex) loadUserIndex() error { if u.configFile == "" { return errors.New("configuration file not set") } - b, err := ioutil.ReadFile(u.configFile) + b, err := os.ReadFile(u.configFile) if err != nil { return fmt.Errorf("Failed to read auth file: %s, error: %s", u.configFile, err) } diff --git a/share/tunnel/tunnel.go b/share/tunnel/tunnel.go index 1d80bd5b..7493a5ac 100644 --- a/share/tunnel/tunnel.go +++ b/share/tunnel/tunnel.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "errors" - "io/ioutil" + "io" "log" "os" "sync" @@ -57,7 +57,7 @@ func New(c Config) *Tunnel { //setup socks server (not listening on any port!) extra := "" if c.Socks { - sl := log.New(ioutil.Discard, "", 0) + sl := log.New(io.Discard, "", 0) if t.Logger.Debug { sl = log.New(os.Stdout, "[socks]", log.Ldate|log.Ltime) } diff --git a/test/bench/main.go b/test/bench/main.go index 091f2d5d..f47b10c1 100644 --- a/test/bench/main.go +++ b/test/bench/main.go @@ -17,7 +17,6 @@ import ( "flag" "fmt" "io" - "io/ioutil" "log" "net/http" "os" @@ -86,7 +85,7 @@ func testTunnel(port string, size int) { fatal(err) } - n, err := io.Copy(ioutil.Discard, resp.Body) + n, err := io.Copy(io.Discard, resp.Body) if err != nil { fatal(err) } diff --git a/test/e2e/setup_test.go b/test/e2e/setup_test.go index c6228757..c1611bfb 100644 --- a/test/e2e/setup_test.go +++ b/test/e2e/setup_test.go @@ -2,7 +2,7 @@ package e2e_test import ( "context" - "io/ioutil" + "io" "log" "net" "net/http" @@ -36,7 +36,7 @@ func (tl *testLayout) setup(t *testing.T) (server *chserver.Server, client *chcl fileAddr := "127.0.0.1:" + filePort f := http.Server{ Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - b, _ := ioutil.ReadAll(r.Body) + b, _ := io.ReadAll(r.Body) w.Write(append(b, '!')) }), } @@ -133,7 +133,7 @@ func post(url, body string) (string, error) { if err != nil { return "", err } - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return "", err }