commit 5ad15c3c93d6996c9742cfd72f6dbbbcb3305abb Author: Samuel Huang Date: Mon Aug 16 00:48:32 2021 +1000 Init import diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9b754f7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +# Ignore all +** + +# Allow only docker duild files +!Dockerfile.* +!*.sh \ No newline at end of file diff --git a/.github/workflows/docker-buildx-dev.yml b/.github/workflows/docker-buildx-dev.yml new file mode 100644 index 0000000..d7557ea --- /dev/null +++ b/.github/workflows/docker-buildx-dev.yml @@ -0,0 +1,84 @@ +name: docker-buildx-dev + +on: + push: + branches: dev + +jobs: + multi-arch-dev: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.ref }} + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + with: + platforms: all + - + name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + with: + version: latest + - + name: Available platforms + run: echo ${{ steps.buildx.outputs.platforms }} + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push multi-arch dev + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.amd64 + platforms: | + linux/amd64 + linux/arm64 + linux/arm/v7 + linux/arm/v6 + push: true + tags: ${{ github.repository }}:dev + - + name: Build and push AMD64 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.amd64 + platforms: linux/amd64 + push: true + tags: ${{ github.repository }}:amd64dev + - + name: Build and push ARM64v8 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.arm64 + platforms: linux/arm64 + push: true + tags: ${{ github.repository }}:arm64dev + - + name: Build and push ARM32v7 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.arm + platforms: linux/arm/v7 + push: true + tags: ${{ github.repository }}:armv7dev + - + name: Build and push ARM32v6 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.arm + platforms: linux/arm/v6 + push: true + tags: ${{ github.repository }}:armdev diff --git a/.github/workflows/docker-buildx-latest.yml b/.github/workflows/docker-buildx-latest.yml new file mode 100644 index 0000000..ac8b96c --- /dev/null +++ b/.github/workflows/docker-buildx-latest.yml @@ -0,0 +1,84 @@ +name: docker-buildx-latest + +on: + push: + branches: master + +jobs: + multi-arch-latest: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.ref }} + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + with: + platforms: all + - + name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v1 + with: + version: latest + - + name: Available platforms + run: echo ${{ steps.buildx.outputs.platforms }} + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push multi-arch latest + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.amd64 + platforms: | + linux/amd64 + linux/arm64 + linux/arm/v7 + linux/arm/v6 + push: true + tags: ${{ github.repository }}:latest + - + name: Build and push AMD64 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.amd64 + platforms: linux/amd64 + push: true + tags: ${{ github.repository }}:amd64 + - + name: Build and push ARM64v8 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.arm64 + platforms: linux/arm64 + push: true + tags: ${{ github.repository }}:arm64 + - + name: Build and push ARM32v7 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.arm + platforms: linux/arm/v7 + push: true + tags: ${{ github.repository }}:armv7 + - + name: Build and push ARM32v6 + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.arm + platforms: linux/arm/v6 + push: true + tags: ${{ github.repository }}:arm diff --git a/Dockerfile.amd64 b/Dockerfile.amd64 new file mode 100644 index 0000000..7a73882 --- /dev/null +++ b/Dockerfile.amd64 @@ -0,0 +1,41 @@ +FROM golang:1.16-alpine as builder + +ARG XRAYVER='v1.4.2' + +RUN apk add --no-cache bash git build-base + +WORKDIR /go/src/XTLS/Xray-core +RUN git clone https://github.com/XTLS/Xray-core.git . && \ + git checkout ${XRAYVER} && \ + go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main + + +FROM alpine:3.14 + +COPY --from=builder /go/src/XTLS/Xray-core/xray /usr/local/bin/ + +RUN apk update && apk add bash openssl curl jq moreutils \ + bind-tools whois dnscrypt-proxy ca-certificates proxychains-ng npm +RUN npm config set unsafe-perm true +RUN npm install -g qrcode-terminal + +ENV DNSPORT="53" + +RUN sed -i "s/^listen_addresses = .*/listen_addresses = \[\'0.0.0.0:$DNSPORT\'\]/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^dnscrypt_servers = .*/dnscrypt_servers = false/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^doh_servers = .*/doh_servers = true/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^socks4.*/socks5\t127.0.0.1 1080/g" /etc/proxychains/proxychains.conf + +ADD run.sh /run.sh +ADD proxy-ltx.sh /proxy-ltx.sh +ADD proxy-ltt.sh /proxy-ltt.sh +ADD proxy-lttw.sh /proxy-lttw.sh +ADD proxy-mtt.sh /proxy-mtt.sh +ADD proxy-mttw.sh /proxy-mttw.sh +ADD proxy-ttt.sh /proxy-ttt.sh +ADD proxy-tttw.sh /proxy-tttw.sh +ADD status.sh /status.sh + +RUN chmod 755 /*.sh + +ENTRYPOINT ["/run.sh"] diff --git a/Dockerfile.arm b/Dockerfile.arm new file mode 100644 index 0000000..9bca3bb --- /dev/null +++ b/Dockerfile.arm @@ -0,0 +1,41 @@ +FROM arm32v6/golang:1.16-alpine as builder + +ARG XRAYVER='v1.4.2' + +RUN apk add --no-cache bash git build-base + +WORKDIR /go/src/XTLS/Xray-core +RUN git clone https://github.com/XTLS/Xray-core.git . && \ + git checkout ${XRAYVER} && \ + go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main + + +FROM arm32v6/alpine:3.14 + +COPY --from=builder /go/src/XTLS/Xray-core/xray /usr/local/bin/ + +RUN apk update && apk add bash openssl curl jq moreutils \ + bind-tools whois dnscrypt-proxy ca-certificates proxychains-ng npm +RUN npm config set unsafe-perm true +RUN npm install -g qrcode-terminal + +ENV DNSPORT="53" + +RUN sed -i "s/^listen_addresses = .*/listen_addresses = \[\'0.0.0.0:$DNSPORT\'\]/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^dnscrypt_servers = .*/dnscrypt_servers = false/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^doh_servers = .*/doh_servers = true/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^socks4.*/socks5\t127.0.0.1 1080/g" /etc/proxychains/proxychains.conf + +ADD run.sh /run.sh +ADD proxy-ltx.sh /proxy-ltx.sh +ADD proxy-ltt.sh /proxy-ltt.sh +ADD proxy-lttw.sh /proxy-lttw.sh +ADD proxy-mtt.sh /proxy-mtt.sh +ADD proxy-mttw.sh /proxy-mttw.sh +ADD proxy-ttt.sh /proxy-ttt.sh +ADD proxy-tttw.sh /proxy-tttw.sh +ADD status.sh /status.sh + +RUN chmod 755 /*.sh + +ENTRYPOINT ["/run.sh"] diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 new file mode 100644 index 0000000..cfe03ab --- /dev/null +++ b/Dockerfile.arm64 @@ -0,0 +1,41 @@ +FROM arm64v8/golang:1.16-alpine as builder + +ARG XRAYVER='v1.4.2' + +RUN apk add --no-cache bash git build-base + +WORKDIR /go/src/XTLS/Xray-core +RUN git clone https://github.com/XTLS/Xray-core.git . && \ + git checkout ${XRAYVER} && \ + go build -o xray -trimpath -ldflags "-s -w -buildid=" ./main + + +FROM arm64v8/alpine:3.14 + +COPY --from=builder /go/src/XTLS/Xray-core/xray /usr/local/bin/ + +RUN apk update && apk add bash openssl curl jq moreutils \ + bind-tools whois dnscrypt-proxy ca-certificates proxychains-ng npm +RUN npm config set unsafe-perm true +RUN npm install -g qrcode-terminal + +ENV DNSPORT="53" + +RUN sed -i "s/^listen_addresses = .*/listen_addresses = \[\'0.0.0.0:$DNSPORT\'\]/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^dnscrypt_servers = .*/dnscrypt_servers = false/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^doh_servers = .*/doh_servers = true/g" /etc/dnscrypt-proxy/dnscrypt-proxy.toml +RUN sed -i "s/^socks4.*/socks5\t127.0.0.1 1080/g" /etc/proxychains/proxychains.conf + +ADD run.sh /run.sh +ADD proxy-ltx.sh /proxy-ltx.sh +ADD proxy-ltt.sh /proxy-ltt.sh +ADD proxy-lttw.sh /proxy-lttw.sh +ADD proxy-mtt.sh /proxy-mtt.sh +ADD proxy-mttw.sh /proxy-mttw.sh +ADD proxy-ttt.sh /proxy-ttt.sh +ADD proxy-tttw.sh /proxy-tttw.sh +ADD status.sh /status.sh + +RUN chmod 755 /*.sh + +ENTRYPOINT ["/run.sh"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4077a25 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Samuel Huang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2dbcc68 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# proxy-xray + +Xray client container with SOCKS5/HTTP/DNS proxy and QR code support. Running on x86 and arm/arm64 (Raspberry Pi). + +![docker-build](https://github.com/samuelhbne/proxy-xray/workflows/docker-buildx-latest/badge.svg) + +## [Optional] How to build proxy-xray docker image + +```shell +$ git clone https://github.com/samuelhbne/proxy-xray.git +$ cd proxy-xray +$ docker build -t samuelhbne/proxy-xray:amd64 -f Dockerfile.amd64 . +... +``` + +### NOTE1 + +- Please replace Dockerfile.amd64 with the Dockerfile.ARCH match your server accordingly. For example: Dockerfile.arm for 32bit Raspbian, Dockerfile.arm64 for 64bit Ubuntu for Raspberry Pi. + +## How to start proxy-xray container + +```shell +$ docker run --rm -it samuelhbne/proxy-xray:amd64 +proxy-xray -- [options] + --ltx uuid@xray-host:port + --ltt uuid@xray-host:port + --lttw uuid@xray-host:port:/webpath + --mtt uuid@xray-host:port + --mttw uuid@xray-host:port:/webpath + --ttt password@xray-host:port + --tttw password@xray-host:port:/webpath + --stdin Read XRay config from stdin instead of auto generation + +$ docker run --name proxy-xray -p 21080:1080 -p 65353:53/udp -p 28123:8123 -d samuelhbne/proxy-xray:amd64 --ltx bec24d96-410f-4723-8b3b-46987a1d9ed8@mydomain.duckdns.org:443 +... +``` + +### NOTE2 + +- Please replace "amd64" with the arch match the current box accordingly. For example: "arm64" for AWS ARM64 platform like A1, t4g instance or 64bit Ubuntu on Raspberry Pi. "arm" for 32bit Raspbian. +- Please replace "mydomain.duckdns.org" with the Xray server hotsname you want to connect +- Please replace 21080 with the port number you want for SOCKS5 proxy TCP listerning. +- Please replace 28123 with the port number you want for HTTP proxy TCP listerning. +- Please replace 65353 with the port number you want for DNS UDP listerning. +- Please replace "bec24d96-410f-4723-8b3b-46987a1d9ed8" with the uuid you want to set for Xray server access. + +## How to verify if proxy tunnel is working properly + +```shell +$ curl -sSx socks5h://127.0.0.1:21080 http://ifconfig.co +12.34.56.78 + +$ curl -sSx http://127.0.0.1:28123 http://ifconfig.co +12.34.56.78 + +$ dig +short @127.0.0.1 -p 65353 twitter.com +104.244.42.193 +104.244.42.129 + +$ docker exec -it proxy-xray proxychains whois 104.244.42.193|grep OrgId +[proxychains] config file found: /etc/proxychains/proxychains.conf +[proxychains] preloading /usr/lib/libproxychains4.so +[proxychains] DLL init: proxychains-ng 4.14 +[proxychains] Strict chain ... 127.0.0.1:1080 ... whois.arin.net:43 ... OK +OrgId: TWITT +``` + +### NOTE3 + +- curl should return the VPN server address given above if SOCKS5/HTTP proxy works properly. +- dig should return resolved IP recorders of twitter.com if DNS server works properly. +- Whois should return "OrgId: TWITT". That means the IP address returned from dig query belongs to twitter.com indeed, hence untaminated. +- Whois was actually running inside the proxy container through the proxy tunnel to avoid potential access blocking. +- Please have a look over the sibling project [server-xray](https://github.com/samuelhbne/server-xray) if you'd like to set a Xray server. + +## How to get the XRay QR code for mobile connection + +```shell +$ docker exec -it proxy-xray /status.sh +VPS-Server: mydomain.duckdns.org +Xray-URL: vless://bec24d96-410f-4723-8b3b-46987a1d9ed8@mydomain.duckdns.org:443?security=xtls&type=tcp&flow=xtls-rprx-direct#mydomain.duckdns.org:443 +``` + +![QR code example](https://github.com/samuelhbne/proxy-xray/blob/master/images/qr-xray.png) + +## How to stop and remove the running container + +```shell +$ docker stop proxy-xray +... +$ docker rm proxy-xray +... +``` diff --git a/proxy-ltt.sh b/proxy-ltt.sh new file mode 100755 index 0000000..1562af6 --- /dev/null +++ b/proxy-ltt.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-ltt " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# uuid@domain0.com:443 +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" + +if [ -z "${id}" ]; then + >&2 echo "Error: uuid undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jusers=`echo '{}' |jq --arg uuid "${id}" '. += {"id":$uuid, "encryption":"none", "level":0}'` + +Jvnext=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --argjson juser "${Jusers}" \ +'. += {"address":$host, "port":($port | tonumber), "users":[$juser]}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" \ +'. += {"network":"tcp", "security":"tls", "tlsSettings":{"serverName":$host}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jvnext "${Jvnext}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"vless", "settings":{"vnext":[$jvnext]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/proxy-lttw.sh b/proxy-lttw.sh new file mode 100755 index 0000000..c6a72a6 --- /dev/null +++ b/proxy-lttw.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-lttw " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# uuid@domain0.com:443:/websocket +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" +path="${options[2]}" + +if [ -z "${id}" ]; then + >&2 echo "Error: uuid undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jusers=`echo '{}' |jq --arg uuid "${id}" '. += {"id":$uuid, "encryption":"none", "level":0}'` + +Jvnext=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --argjson juser "${Jusers}" \ +'. += {"address":$host, "port":($port | tonumber), "users":[$juser]}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" --arg path "${path}" \ +'. += {"network":"ws", "security":"tls", "tlsSettings":{"serverName":$host}, "wsSettings":{"path":$path}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jvnext "${Jvnext}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"vless", "settings":{"vnext":[$jvnext]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/proxy-ltx.sh b/proxy-ltx.sh new file mode 100755 index 0000000..49646b6 --- /dev/null +++ b/proxy-ltx.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-ltx " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# uuid@domain0.com:443 +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" + +if [ -z "${id}" ]; then + >&2 echo "Error: uuid undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jusers=`echo '{}' |jq --arg uuid "${id}" '. += {"id":$uuid, "flow":"xtls-rprx-direct", "encryption":"none", "level":0}'` + +Jvnext=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --argjson juser "${Jusers}" \ +'. += {"address":$host, "port":($port | tonumber), "users":[$juser]}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" \ +'. += {"network":"tcp", "security":"xtls", "xtlsSettings":{"serverName":$host}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jvnext "${Jvnext}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"vless", "settings":{"vnext":[$jvnext]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/proxy-mtt.sh b/proxy-mtt.sh new file mode 100755 index 0000000..cef4724 --- /dev/null +++ b/proxy-mtt.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-mtt " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# password:method@domain0.com:443/websocket +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr '/' ' '`) +path="${options[1]}" +temp="${options[0]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" +temp=$id +options=(`echo $temp |tr ':' ' '`) +passwd="${options[0]}" +method="${options[2]}" + +if [ -z "${id}" ]; then + >&2 echo "Error: uuid undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jusers=`echo '{}' |jq --arg uuid "${id}" '. += {"id":$uuid, "encryption":"none", "level":0}'` + +Jvnext=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --argjson juser "${Jusers}" \ +'. += {"address":$host, "port":($port | tonumber), "users":[$juser]}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" \ +'. += {"network":"tcp", "security":"tls", "tlsSettings":{"serverName":$host}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jvnext "${Jvnext}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"vmess", "settings":{"vnext":[$jvnext]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/proxy-mttw.sh b/proxy-mttw.sh new file mode 100755 index 0000000..54e8ccf --- /dev/null +++ b/proxy-mttw.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-mttw " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# uuid@domain0.com:443:/websocket +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" +path="${options[2]}" + +if [ -z "${id}" ]; then + >&2 echo "Error: uuid undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jusers=`echo '{}' |jq --arg uuid "${id}" '. += {"id":$uuid, "encryption":"none", "level":0}'` + +Jvnext=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --argjson juser "${Jusers}" \ +'. += {"address":$host, "port":($port | tonumber), "users":[$juser]}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" --arg path "${path}" \ +'. += {"network":"ws", "security":"tls", "tlsSettings":{"serverName":$host}, "wsSettings":{"path":$path}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jvnext "${Jvnext}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"vmess", "settings":{"vnext":[$jvnext]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/proxy-ttt.sh b/proxy-ttt.sh new file mode 100755 index 0000000..f37475f --- /dev/null +++ b/proxy-ttt.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-ttt " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# password:method@domain0.com:443:/websocket +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" +path="${options[2]}" + +temp=$id +options=(`echo $temp |tr ':' ' '`) +passwd="${options[0]}" +method="${options[1]}" + +if [ -z "${passwd}" ]; then + >&2 echo "Error: passwd undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jservers=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --arg passwd "${passwd}" \ +'. += {"address":$host, "port":($port | tonumber), "password":$passwd}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" \ +'. += {"network":"tcp", "security":"tls", "tlsSettings":{"serverName":$host}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jservers "${Jservers}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"trojan", "settings":{"servers":[$jservers]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/proxy-tttw.sh b/proxy-tttw.sh new file mode 100755 index 0000000..73fcf60 --- /dev/null +++ b/proxy-tttw.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +usage() { + >&2 echo "Usage: proxy-tttw " +} + +if [ -z "$1" ]; then + >&2 echo "Missing options" + usage + exit 1 +fi + +# password:method@domain0.com:443:/websocket +temp=$1 +options=(`echo $temp |tr '@' ' '`) +id="${options[0]}" +temp="${options[1]}" +options=(`echo $temp |tr ':' ' '`) +host="${options[0]}" +port="${options[1]}" +path="${options[2]}" + +temp=$id +options=(`echo $temp |tr ':' ' '`) +passwd="${options[0]}" +method="${options[1]}" + +if [ -z "${passwd}" ]; then + >&2 echo "Error: passwd undefined." + usage + exit 1 +fi + +if [ -z "${host}" ]; then + >&2 echo "Error: destination host undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +Jservers=`echo '{}' | jq --arg host "${host}" --arg port "${port}" --arg passwd "${passwd}" \ +'. += {"address":$host, "port":($port | tonumber), "password":$passwd}' ` + +JstreamSettings=`echo '{}' | jq --arg host "${host}" --arg path "${path}" \ +'. += {"network":"ws", "security":"tls", "tlsSettings":{"serverName":$host}, "wsSettings":{"path":$path}}' ` + +Joutbounds=`echo '{}' | jq --arg host "${host}" --argjson jservers "${Jservers}" --argjson jstreamSettings "${JstreamSettings}" \ +'. += { "protocol":"trojan", "settings":{"servers":[$jservers]}, "streamSettings":$jstreamSettings }' ` + +JibSOCKS=`echo '{}' | jq '. +={"port":1080, "listen":"0.0.0.0", "protocol":"socks", "settings":{"udp":true}}' ` +JibHTTP=`echo '{}' | jq '. +={"port":8123, "listen":"0.0.0.0", "protocol":"http"}' ` + +jroot=`echo '{}' | jq --argjson jibsocks "${JibSOCKS}" --argjson jibhttp "${JibHTTP}" --argjson joutbounds "${Joutbounds}" \ +'. += {"log":{"loglevel":"warning"}, "inbounds":[$jibsocks, $jibhttp], "outbounds":[$joutbounds]}' ` + +echo "$jroot" +exit 0 diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..de595d9 --- /dev/null +++ b/run.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +DIR=`dirname $0` +DIR="$(cd $DIR; pwd)" +XCONF=/tmp/proxy-xray.json + +usage() { + echo "proxy-xray -- [options]" + echo " --ltx uuid@xray-host:port" + echo " --ltt uuid@xray-host:port" + echo " --lttw uuid@xray-host:port:/webpath" + echo " --mtt uuid@xray-host:port" + echo " --mttw uuid@xray-host:port:/webpath" + echo " --ttt password@xray-host:port" + echo " --tttw password@xray-host:port:/webpath" +# echo " --ssa password:method@xray-host:port" +# echo " --sst password:method@xray-host:port" + echo " --stdin Read XRay config from stdin instead of auto generation" +} + +TEMP=`getopt -o d --long ltx:,ltt:,lttw:,mtt:,mttw:,ttt:,tttw:,ssa:,sst:stdin,debug -n "$0" -- $@` +if [ $? != 0 ] ; then usage; exit 1 ; fi + +eval set -- "$TEMP" +while true ; do + case "$1" in + --ltx|--ltt|--lttw|--mtt|--mttw|--ttt|--tttw|--ssa|--sst) + subcmd=`echo "$1"|tr -d "\-\-"` + echo "$DIR/proxy-${subcmd}.sh $2 >$XCONF" + $DIR/proxy-${subcmd}.sh $2 >$XCONF + if [ $? != 0 ]; then + echo "${subcmd} Config failed: $DIR/proxy-${subcmd}.sh $2" + exit 2 + else + XRAY=1 + fi + shift 2 + ;; + --stdin) + STDINCONF=1 + shift 1 + ;; + -d|--debug) + DEBUG=1 + shift 1 + ;; + --) + shift + break + ;; + *) + usage; + exit 1 + ;; + esac +done + +/usr/bin/dnscrypt-proxy -config /etc/dnscrypt-proxy/dnscrypt-proxy.toml & + +if [ "${STDINCONF}" = "1" ]; then + exec /usr/local/bin/xray +else + if [ "${XRAY}" = "1" ]; then + if [ "${DEBUG}" = "1" ]; then + cat $XCONF |jq '.log.loglevel |="debug"' |sponge $XCONF + echo + cat $XCONF + echo + fi + exec /usr/local/bin/xray -c $XCONF + else + usage + exit 1 + fi +fi diff --git a/status.sh b/status.sh new file mode 100755 index 0000000..d4b7099 --- /dev/null +++ b/status.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +XCONF=/tmp/proxy-xray.json + +urlencode() { + # urlencode + old_lc_collate=$LC_COLLATE + LC_COLLATE=C + local length="${#1}" + for (( i = 0; i < length; i++ )); do + local c="${1:$i:1}" + case $c in + [a-zA-Z0-9.~_-]) printf '%s' "$c" ;; + *) printf '%%%02X' "'$c" ;; + esac + done + LC_COLLATE=$old_lc_collate +} + +PROTOCOL=`cat $XCONF | jq -r '.outbounds[0].protocol'` +case "${PROTOCOL}" in + vless) + XHOST=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].address'` + XPORT=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].port'` + WPATH=`cat $XCONF | jq -r '.outbounds[0].streamSettings.wsSettings.path'` + UUID=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].users[0].id'` + XENCRYPT=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].users[0].encryption'` + XSEC=`cat $XCONF | jq -r '.outbounds[0].streamSettings.security'` + XNETWORK=`cat $XCONF | jq -r '.outbounds[0].streamSettings.network'` + XFLOW=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].users[0].flow'` + XURL="${PROTOCOL}://${UUID}@${XHOST}:${XPORT}?security=${XSEC}&type=${XNETWORK}" + if [ "${XFLOW}" != "null" ]; then XURL="${XURL}&flow=${XFLOW}"; fi + if [ "${WPATH}" != "null" ]; then XURL="${XURL}&path=$(urlencode ${WPATH})"; fi + XURL="${XURL}#${XHOST}:${XPORT}" + ;; + vmess) + XHOST=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].address'` + XPORT=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].port'` + WPATH=`cat $XCONF | jq -r '.outbounds[0].streamSettings.wsSettings.path'` + UUID=`cat $XCONF | jq -r '.outbounds[0].settings.vnext[0].users[0].id'` + XNETWORK=`cat $XCONF | jq -r '.outbounds[0].streamSettings.network'` + JXURL=`echo '{}' |jq --arg xhost "${XHOST}" --arg xport "${XPORT}" '. += {"v":2, "add":$xhost, "port":$xport}' ` + JXURL=`echo ${JXURL} | jq --arg uuid "${UUID}" --arg network "${XNETWORK}" '. += {"id":$uuid, "net":$network}' ` + JXURL=`echo ${JXURL} | jq '. += {"scy":"auto", "tls":"tls"}' ` + if [ "${WPATH}" != "null" ]; then + JXURL=`echo ${JXURL} | jq --arg wpath "${WPATH}" '. += {"path":$wpath}' ` + fi + JXURL=`echo ${JXURL} |jq --arg xhost "${XHOST}" --arg xport "${XPORT}" '. += {"ps":($xhost+":"+$xport)}' ` + XURL=`echo $JXURL|jq -c|base64|tr -d '\n'` + XURL="${PROTOCOL}://${XURL}" + ;; + trojan) + XHOST=`cat $XCONF | jq -r '.outbounds[0].settings.servers[0].address'` + XPORT=`cat $XCONF | jq -r '.outbounds[0].settings.servers[0].port'` + XPASS=`cat $XCONF | jq -r '.outbounds[0].settings.servers[0].password'` + WPATH=`cat $XCONF | jq -r '.outbounds[0].streamSettings.wsSettings.path'` + XURL="${PROTOCOL}://${XPASS}@${XHOST}:${XPORT}" + if [ "${WPATH}" != "null" ]; then + XURL="${XURL}/?type=ws&path=$(urlencode ${WPATH})" + fi + XURL="${XURL}#${XHOST}:${XPORT}" + ;; + *) + echo "Unknown protocol: ${PROTOCOL}" + echo "Abort" + exit 2 + ;; +esac + +echo "VPS-Server: ${XHOST}" +echo "Xray-URL: ${XURL}" +qrcode-terminal "${XURL}" +exit 0 + + +