-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ec17483
Showing
6 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
name: Build Docker images | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
docker: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v3 | ||
- name: Set up Docker Buildx | ||
uses: docker/setup-buildx-action@v3 | ||
- name: Login to Docker Hub | ||
uses: docker/login-action@v3 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
- name: Set outputs | ||
id: vars | ||
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT | ||
- name: Build and push | ||
uses: docker/build-push-action@v5 | ||
with: | ||
context: . | ||
platforms: linux/amd64,linux/arm64 | ||
push: true | ||
tags: | | ||
${{ secrets.DOCKERHUB_USERNAME }}/xray-checker:latest | ||
${{ secrets.DOCKERHUB_USERNAME }}/xray-checker:${{ steps.vars.outputs.sha_short }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
all/ | ||
configs/* | ||
build/ | ||
xray-checker |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.21 as builder | ||
|
||
ARG TARGETPLATFORM | ||
ARG BUILDPLATFORM | ||
ARG TARGETOS | ||
ARG TARGETARCH | ||
ARG GIT_TAG | ||
ARG GIT_COMMIT | ||
|
||
ENV CGO_ENABLED=0 | ||
ENV GO111MODULE=on | ||
|
||
WORKDIR /go/src/github.com/kutovoys/xray-checker | ||
|
||
# Cache the download before continuing | ||
COPY go.mod go.mod | ||
COPY go.sum go.sum | ||
RUN go mod download | ||
|
||
COPY . . | ||
|
||
RUN CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ | ||
go build -a -installsuffix cgo -o /usr/bin/xray-checker . | ||
|
||
FROM --platform=${BUILDPLATFORM:-linux/amd64} teddysun/xray:1.8.23 | ||
|
||
LABEL org.opencontainers.image.source=https://github.com/kutovoys/xray-checker | ||
|
||
WORKDIR / | ||
COPY --from=builder /usr/bin/xray-checker /checker/xray-checker | ||
# USER nonroot:nonroot | ||
|
||
CMD ["/checker/xray-checker"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module xray-checker | ||
|
||
go 1.21.5 | ||
|
||
require ( | ||
github.com/go-co-op/gocron v1.37.0 | ||
golang.org/x/net v0.28.0 | ||
) | ||
|
||
require ( | ||
github.com/google/uuid v1.4.0 // indirect | ||
github.com/robfig/cron/v3 v3.0.1 // indirect | ||
go.uber.org/atomic v1.9.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||
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= | ||
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= | ||
github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= | ||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= | ||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||
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/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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | ||
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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= | ||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= | ||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= | ||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= | ||
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.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.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= | ||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= | ||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= | ||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= | ||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= | ||
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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | ||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"strings" | ||
"sync" | ||
"time" | ||
|
||
"github.com/go-co-op/gocron" | ||
"golang.org/x/net/proxy" | ||
) | ||
|
||
type Config struct { | ||
Log map[string]interface{} `json:"log"` | ||
Inbounds []struct { | ||
Listen string `json:"listen"` | ||
Port int `json:"port"` | ||
Protocol string `json:"protocol"` | ||
Sniffing struct { | ||
Enabled bool `json:"enabled"` | ||
DestOverride []string `json:"destOverride"` | ||
RouteOnly bool `json:"routeOnly"` | ||
} `json:"sniffing"` | ||
} `json:"inbounds"` | ||
Outbounds []map[string]interface{} `json:"outbounds"` | ||
Webhook string `json:"webhook"` | ||
} | ||
|
||
type LogData struct { | ||
ConfigFile string | ||
SourceIP string | ||
VPNIP string | ||
WebhookURL string | ||
ProxyAddress string | ||
Status string | ||
Error error | ||
} | ||
|
||
func getIP(url string, client *http.Client) (string, error) { | ||
resp, err := client.Get(url) | ||
if err != nil { | ||
return "", err | ||
} | ||
defer resp.Body.Close() | ||
|
||
ip, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return "", err | ||
} | ||
return strings.TrimSpace(string(ip)), nil | ||
} | ||
|
||
func runXray(configPath string) (*exec.Cmd, error) { | ||
cmd := exec.Command("xray", "-c", configPath) | ||
err := cmd.Start() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return cmd, nil | ||
} | ||
|
||
func killXray(cmd *exec.Cmd) error { | ||
return cmd.Process.Kill() | ||
} | ||
|
||
func createProxyClient(proxyAddress string) (*http.Client, error) { | ||
proxyURL, err := url.Parse(proxyAddress) | ||
if err != nil { | ||
return nil, fmt.Errorf("неправильный формат прокси: %v", err) | ||
} | ||
|
||
dialer, err := proxy.FromURL(proxyURL, proxy.Direct) | ||
if err != nil { | ||
return nil, fmt.Errorf("ошибка создания прокси-диалера: %v", err) | ||
} | ||
|
||
transport := &http.Transport{ | ||
Dial: dialer.Dial, | ||
} | ||
|
||
client := &http.Client{ | ||
Transport: transport, | ||
} | ||
|
||
return client, nil | ||
} | ||
|
||
func processConfigFile(configPath string) { | ||
logData := LogData{ConfigFile: configPath} | ||
|
||
configData, err := os.ReadFile(configPath) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка чтения конфигурационного файла: %v", err) | ||
logResult(logData) | ||
return | ||
} | ||
|
||
var config Config | ||
err = json.Unmarshal(configData, &config) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка парсинга конфигурационного файла: %v", err) | ||
logResult(logData) | ||
return | ||
} | ||
|
||
logData.WebhookURL = config.Webhook | ||
if logData.WebhookURL == "" { | ||
logData.Error = fmt.Errorf("webhook URL не найден в конфигурационном файле") | ||
logResult(logData) | ||
return | ||
} | ||
|
||
ipCheckURL := "https://ifconfig.io" | ||
logData.SourceIP, err = getIP(ipCheckURL, &http.Client{}) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка получения исходного IP: %v", err) | ||
logResult(logData) | ||
return | ||
} | ||
|
||
listen := config.Inbounds[0].Listen | ||
port := config.Inbounds[0].Port | ||
logData.ProxyAddress = fmt.Sprintf("socks5://%s:%d", listen, port) | ||
|
||
cmd, err := runXray(configPath) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка запуска Xray: %v", err) | ||
logResult(logData) | ||
return | ||
} | ||
defer killXray(cmd) | ||
time.Sleep(2 * time.Second) | ||
|
||
proxyClient, err := createProxyClient(logData.ProxyAddress) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка создания прокси-клиента: %v", err) | ||
logResult(logData) | ||
return | ||
} | ||
|
||
logData.VPNIP, err = getIP(ipCheckURL, proxyClient) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка получения VPN IP через прокси: %v", err) | ||
logResult(logData) | ||
return | ||
} | ||
|
||
if logData.VPNIP != logData.SourceIP { | ||
_, err = http.Get(logData.WebhookURL) | ||
if err != nil { | ||
logData.Error = fmt.Errorf("ошибка отправки статуса: %v", err) | ||
logData.Status = "Не удалось отправить статус" | ||
} else { | ||
logData.Status = "Статус отправлен успешно" | ||
} | ||
} else { | ||
logData.Status = "IP-адреса совпадают, статус не отправлен" | ||
} | ||
|
||
logResult(logData) | ||
} | ||
|
||
func logResult(logData LogData) { | ||
var logMsg string | ||
|
||
if logData.Error != nil { | ||
logMsg = fmt.Sprintf("Error: %v | Config: %s | Source IP: %s | VPN IP: %s", | ||
logData.Error, logData.ConfigFile, logData.SourceIP, logData.VPNIP) | ||
} else { | ||
logMsg = fmt.Sprintf("Status: %s | Config: %s | Source IP: %s | VPN IP: %s", | ||
logData.Status, logData.ConfigFile, logData.SourceIP, logData.VPNIP) | ||
} | ||
|
||
log.Println(logMsg) | ||
} | ||
|
||
func scheduleConfigs(configDir string, scheduler *gocron.Scheduler) { | ||
files, err := os.ReadDir(configDir) | ||
if err != nil { | ||
fmt.Println("Ошибка чтения директории:", err) | ||
return | ||
} | ||
|
||
for _, file := range files { | ||
if filepath.Ext(file.Name()) == ".json" { | ||
configPath := filepath.Join(configDir, file.Name()) | ||
// Запускаем задачу в шедулере каждые 10 секунд | ||
scheduler.Every(40).Seconds().Do(func() { | ||
processConfigFile(configPath) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
func main() { | ||
configDir := "./configs" // директория с конфигурационными файлами | ||
var wg sync.WaitGroup | ||
|
||
// Создаем новый шедулер | ||
scheduler := gocron.NewScheduler(time.UTC) | ||
|
||
// Планируем обработку конфигурационных файлов | ||
scheduleConfigs(configDir, scheduler) | ||
|
||
// Запускаем шедулер в отдельной горутине | ||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
scheduler.StartBlocking() | ||
}() | ||
|
||
// Ожидаем завершения работы | ||
wg.Wait() | ||
} |