diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..2ba857d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,17 @@ +{ + "name": "slrp dev", + "image": "mcr.microsoft.com/devcontainers/go:1-1.20-bookworm", + "postCreateCommand": ".devcontainer/postcreate.sh", + "remoteUser": "root", + "customizations": { + "vscode": { + "extensions": [ + "foxundermoon.shell-format", + "GitHub.copilot", + "eamodio.gitlens", + "ms-vscode.makefile-tools", + "ms-azuretools.vscode-docker" + ] + } + } +} \ No newline at end of file diff --git a/.devcontainer/postcreate.sh b/.devcontainer/postcreate.sh new file mode 100755 index 0000000..a56d458 --- /dev/null +++ b/.devcontainer/postcreate.sh @@ -0,0 +1,35 @@ +#!/bin/bash +NVM_VERSION="0.38.0" +NODE_VERSION="20" + +# # If you're developing in a container behind a VPNed/MDM-managed machine you might get "self signed certs in chain" error. +# # This snippet below bypasses that (ssl is required later for nvm installation) +# apt update && apt install -y git +# git config --global http.sslVerify false + +echo "[ + ] Running post-create script. Installing the following:" +echo "[ + ] NVM version: $NVM_VERSION" +echo "[ + ] NodeJS version: $NODE_VERSION" +echo "[ + ] ==============================" + +# Check if we don't have nvm, if no - install it +echo "[ + ] Installing nvm at v$NVM_VERSION" + +curl -k -o- https://raw.githubusercontent.com/nvm-sh/nvm/v$NVM_VERSION/install.sh | bash +# Activate nvm +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +# Refresh bash +source ~/.bashrc + +# Install node at a set versions +echo "[ + ] Installing NodeJS at v$NODE_VERSION" +nvm install $NODE_VERSION && nvm use $NODE_VERSION + +echo "[ + ] Installing UI dependencies and building..." +# Change to the "ui" directory +cd ui && npm install && cd ../ + +echo "[ + ] Installing Go dependencies and building..." +make build diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5f83604 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + // Run the main.go program + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}/main.go", + "env": {}, + "args": [] + }, + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 31104fb..cd333c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,34 @@ -FROM alpine +# Install node and deps to build the frontend +FROM node:20.11-bookworm AS NODE_INSTALL +WORKDIR /app +COPY . . +RUN npm --prefix ui install && \ + npm --prefix ui run build -ENV PWD="/app" +# Install go and deps to build the backend +FROM golang:1.20.13-bookworm AS BUILD +WORKDIR /app +COPY --from=NODE_INSTALL /app . +RUN make build-go-for-docker +# Final image +FROM alpine:latest # SLRP configuration environment variables -ENV SLRP_APP_STATE="$PWD/.slrp/data" -ENV SLRP_APP_SYNC="1m" -ENV SLRP_LOG_LEVEL="info" -ENV SLRP_LOG_FORMAT="pretty" -ENV SLRP_SERVER_ADDR="0.0.0.0:8089" -ENV SLRP_SERVER_READ_TIMEOUT="15s" -ENV SLRP_MITM_ADDR="0.0.0.0:8090" -ENV SLRP_MITM_READ_TIMEOUT="15s" -ENV SLRP_MITM_IDLE_TIMEOUT="15s" -ENV SLRP_MITM_WRITE_TIMEOUT="15s" -ENV SLRP_CHECKER_TIMEOUT="5s" -ENV SLRP_CHECKER_STRATEGY="simple" -ENV SLRP_HISTORY_LIMIT="1000" - -WORKDIR $PWD -COPY slrp $PWD - -RUN mkdir ./.slrp - +ENV SLRP_APP_STATE="/opt/.slrp/data" \ + SLRP_APP_SYNC="1m" \ + SLRP_LOG_LEVEL="info" \ + SLRP_LOG_FORMAT="pretty" \ + SLRP_SERVER_ADDR="0.0.0.0:8089" \ + SLRP_SERVER_READ_TIMEOUT="15s" \ + SLRP_MITM_ADDR="0.0.0.0:8090" \ + SLRP_MITM_READ_TIMEOUT="15s" \ + SLRP_MITM_IDLE_TIMEOUT="15s" \ + SLRP_MITM_WRITE_TIMEOUT="15s" \ + SLRP_CHECKER_TIMEOUT="5s" \ + SLRP_CHECKER_STRATEGY="simple" \ + SLRP_HISTORY_LIMIT="1000" +WORKDIR /opt +COPY --from=BUILD /app/main /opt/slrp +RUN mkdir -p ./.slrp/data EXPOSE 8089 8090 - -CMD ["./slrp"] +CMD ["/opt/slrp"] \ No newline at end of file diff --git a/Makefile b/Makefile index 870b62d..6bd3dc8 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,14 @@ build: build-ui go mod vendor go build -ldflags "-s -w" main.go +# When running inside Alpine images there are no classic OS packages/binaries enabled, hence - we compile statically (CGO) +build-go-for-docker: + go mod vendor + CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags "-s -w" -o main main.go + +docker: + docker build -t slrp:latest . + quick: go build diff --git a/README.md b/README.md index 48117f3..360b03c 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,17 @@ SLRP - rotating open proxy multiplexer * Packaged as a single executable binary, that also includes Web UI # Usage +For all methods, wait couple of minutes for the pool to pick up. Check the dashboard at [http://localhost:8089/](http://localhost:8089/) for progress. -Download service, start it up, wait couple of minutes for the pool to pick up. Now run `curl --proxy-insecure -D - -x http://127.0.0.1:8090 -k http://httpbin.org/get` couple of times and see different origins and user agent headers. +## Via binary +Download the binary from the releases, which can be found [here](https://github.com/nfx/slrp/releases) + +## Via Docker +> Assuming you have docker and make present +Run `make docker`. Once done, invoke with `docker run -p 8089:8089 -p 8090:8090 -v $HOME/.slrp/data:/data nfx/slrp:latest` + +Once running, you can access the UI at [http://localhost:8089/](http://localhost:8089/) and the proxy at [http://localhost:8090/](http://localhost:8090/) +Test using a simple curl command `curl --proxy-insecure -D - -x "https://127.0.0.1:8090" "https://httpbin.org/get"` couple of times and see different origins and user agent headers. # Concepts diff --git a/pmux/proxy.go b/pmux/proxy.go index 48d9a55..bd22e33 100644 --- a/pmux/proxy.go +++ b/pmux/proxy.go @@ -247,8 +247,18 @@ func NewProxyFromURL(url string) Proxy { } func NewProxy(addr string, t string) Proxy { + // Check if the address is valid or contains "[::]"; This happens when running inside a docker container + // It means that the address is listening on all interfaces but via IPv6, which is not supported by the + // proxy package(or so). Hence we replace it with 0.0.0.0 + if strings.Contains(addr, "[::]") { + // Set it to 0.0.0.0 but maintain the port + log.Info().Str("ip address", addr).Msg("encountered [::]: in address, replacing with 0.0.0.0") + addr = strings.Replace(addr, "[::]", "0.0.0.0", 1) + } + addrPort, err := netip.ParseAddrPort(addr) if err != nil { + log.Err(fmt.Errorf("error parsing address")).Str("ip address", addr).Msg("") return 0 } p, ok := protoMap[t] diff --git a/sources/try_test.go b/sources/try_test.go index d2b5473..d66662e 100644 --- a/sources/try_test.go +++ b/sources/try_test.go @@ -113,7 +113,7 @@ func Test_mergeSrc_Len(t *testing.T) { case pmux.HttpProxy("127.0.0.1:2048"): canAssertB <- true } - t.Logf("received: %s", v) + t.Logf("received: %v", v) } }()