支持 KCP 协议
Some checks failed
Go / build (.exe, 386, windows, windows-386) (push) Has been cancelled
Go / build (.exe, amd64, windows, windows-amd64) (push) Has been cancelled
Go / build (.exe, arm64, windows, windows-arm64) (push) Has been cancelled
Go / build (386, freebsd, freebsd-386) (push) Has been cancelled
Go / build (386, linux, linux-386) (push) Has been cancelled
Go / build (386, netbsd, netbsd-386) (push) Has been cancelled
Go / build (386, openbsd, openbsd-386) (push) Has been cancelled
Go / build (386, plan9, plan9-386) (push) Has been cancelled
Go / build (amd64, darwin, darwin-amd64) (push) Has been cancelled
Go / build (amd64, dragonfly, dragonfly-amd64) (push) Has been cancelled
Go / build (amd64, freebsd, freebsd-amd64) (push) Has been cancelled
Go / build (amd64, illumos, illumos-amd64) (push) Has been cancelled
Go / build (amd64, linux, linux-amd64) (push) Has been cancelled
Go / build (amd64, netbsd, netbsd-amd64) (push) Has been cancelled
Go / build (amd64, openbsd, openbsd-amd64) (push) Has been cancelled
Go / build (amd64, plan9, plan9-amd64) (push) Has been cancelled
Go / build (amd64, solaris, solaris-amd64) (push) Has been cancelled
Go / build (arm, 6, linux, linux-armv6) (push) Has been cancelled
Go / build (arm, 7, linux, linux-armv7) (push) Has been cancelled
Go / build (arm, freebsd, freebsd-arm) (push) Has been cancelled
Go / build (arm, netbsd, netbsd-arm) (push) Has been cancelled
Go / build (arm, openbsd, openbsd-arm) (push) Has been cancelled
Go / build (arm, plan9, plan9-arm) (push) Has been cancelled
Go / build (arm64, darwin, darwin-arm64) (push) Has been cancelled
Go / build (arm64, freebsd, freebsd-arm64) (push) Has been cancelled
Go / build (arm64, linux, linux-arm64) (push) Has been cancelled
Go / build (arm64, netbsd, netbsd-arm64) (push) Has been cancelled
Go / build (arm64, openbsd, openbsd-arm64) (push) Has been cancelled
Go / build (loong64, linux, linux-loong64) (push) Has been cancelled
Go / build (mips, linux, linux-mips) (push) Has been cancelled
Go / build (mips64, linux, linux-mips64) (push) Has been cancelled
Go / build (mips64le, linux, linux-mips64le) (push) Has been cancelled
Go / build (mipsle, linux, linux-mipsle) (push) Has been cancelled
Go / build (ppc64, aix, aix-ppc64) (push) Has been cancelled
Go / build (ppc64, linux, linux-ppc64) (push) Has been cancelled
Go / build (ppc64, openbsd, openbsd-ppc64) (push) Has been cancelled
Go / build (ppc64le, linux, linux-ppc64le) (push) Has been cancelled
Go / build (riscv64, freebsd, freebsd-riscv64) (push) Has been cancelled
Go / build (riscv64, linux, linux-riscv64) (push) Has been cancelled
Go / build (riscv64, openbsd, openbsd-riscv64) (push) Has been cancelled
Go / build (s390x, linux, linux-s390x) (push) Has been cancelled
Go / merge-artifacts (push) Has been cancelled
Some checks failed
Go / build (.exe, 386, windows, windows-386) (push) Has been cancelled
Go / build (.exe, amd64, windows, windows-amd64) (push) Has been cancelled
Go / build (.exe, arm64, windows, windows-arm64) (push) Has been cancelled
Go / build (386, freebsd, freebsd-386) (push) Has been cancelled
Go / build (386, linux, linux-386) (push) Has been cancelled
Go / build (386, netbsd, netbsd-386) (push) Has been cancelled
Go / build (386, openbsd, openbsd-386) (push) Has been cancelled
Go / build (386, plan9, plan9-386) (push) Has been cancelled
Go / build (amd64, darwin, darwin-amd64) (push) Has been cancelled
Go / build (amd64, dragonfly, dragonfly-amd64) (push) Has been cancelled
Go / build (amd64, freebsd, freebsd-amd64) (push) Has been cancelled
Go / build (amd64, illumos, illumos-amd64) (push) Has been cancelled
Go / build (amd64, linux, linux-amd64) (push) Has been cancelled
Go / build (amd64, netbsd, netbsd-amd64) (push) Has been cancelled
Go / build (amd64, openbsd, openbsd-amd64) (push) Has been cancelled
Go / build (amd64, plan9, plan9-amd64) (push) Has been cancelled
Go / build (amd64, solaris, solaris-amd64) (push) Has been cancelled
Go / build (arm, 6, linux, linux-armv6) (push) Has been cancelled
Go / build (arm, 7, linux, linux-armv7) (push) Has been cancelled
Go / build (arm, freebsd, freebsd-arm) (push) Has been cancelled
Go / build (arm, netbsd, netbsd-arm) (push) Has been cancelled
Go / build (arm, openbsd, openbsd-arm) (push) Has been cancelled
Go / build (arm, plan9, plan9-arm) (push) Has been cancelled
Go / build (arm64, darwin, darwin-arm64) (push) Has been cancelled
Go / build (arm64, freebsd, freebsd-arm64) (push) Has been cancelled
Go / build (arm64, linux, linux-arm64) (push) Has been cancelled
Go / build (arm64, netbsd, netbsd-arm64) (push) Has been cancelled
Go / build (arm64, openbsd, openbsd-arm64) (push) Has been cancelled
Go / build (loong64, linux, linux-loong64) (push) Has been cancelled
Go / build (mips, linux, linux-mips) (push) Has been cancelled
Go / build (mips64, linux, linux-mips64) (push) Has been cancelled
Go / build (mips64le, linux, linux-mips64le) (push) Has been cancelled
Go / build (mipsle, linux, linux-mipsle) (push) Has been cancelled
Go / build (ppc64, aix, aix-ppc64) (push) Has been cancelled
Go / build (ppc64, linux, linux-ppc64) (push) Has been cancelled
Go / build (ppc64, openbsd, openbsd-ppc64) (push) Has been cancelled
Go / build (ppc64le, linux, linux-ppc64le) (push) Has been cancelled
Go / build (riscv64, freebsd, freebsd-riscv64) (push) Has been cancelled
Go / build (riscv64, linux, linux-riscv64) (push) Has been cancelled
Go / build (riscv64, openbsd, openbsd-riscv64) (push) Has been cancelled
Go / build (s390x, linux, linux-s390x) (push) Has been cancelled
Go / merge-artifacts (push) Has been cancelled
This commit is contained in:
214
.github/workflows/build.yml
vendored
Normal file
214
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Linux builds
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
name: linux-amd64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
name: linux-arm64
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
name: linux-armv7
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: 6
|
||||
name: linux-armv6
|
||||
- goos: linux
|
||||
goarch: 386
|
||||
name: linux-386
|
||||
- goos: linux
|
||||
goarch: loong64
|
||||
name: linux-loong64
|
||||
- goos: linux
|
||||
goarch: mips
|
||||
name: linux-mips
|
||||
- goos: linux
|
||||
goarch: mips64
|
||||
name: linux-mips64
|
||||
- goos: linux
|
||||
goarch: mips64le
|
||||
name: linux-mips64le
|
||||
- goos: linux
|
||||
goarch: mipsle
|
||||
name: linux-mipsle
|
||||
- goos: linux
|
||||
goarch: ppc64
|
||||
name: linux-ppc64
|
||||
- goos: linux
|
||||
goarch: ppc64le
|
||||
name: linux-ppc64le
|
||||
- goos: linux
|
||||
goarch: riscv64
|
||||
name: linux-riscv64
|
||||
- goos: linux
|
||||
goarch: s390x
|
||||
name: linux-s390x
|
||||
|
||||
# Windows builds
|
||||
- goos: windows
|
||||
goarch: amd64
|
||||
name: windows-amd64
|
||||
ext: .exe
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
name: windows-arm64
|
||||
ext: .exe
|
||||
- goos: windows
|
||||
goarch: 386
|
||||
name: windows-386
|
||||
ext: .exe
|
||||
|
||||
# macOS builds
|
||||
- goos: darwin
|
||||
goarch: amd64
|
||||
name: darwin-amd64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
name: darwin-arm64
|
||||
|
||||
# FreeBSD builds
|
||||
- goos: freebsd
|
||||
goarch: amd64
|
||||
name: freebsd-amd64
|
||||
- goos: freebsd
|
||||
goarch: arm64
|
||||
name: freebsd-arm64
|
||||
- goos: freebsd
|
||||
goarch: 386
|
||||
name: freebsd-386
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
name: freebsd-arm
|
||||
- goos: freebsd
|
||||
goarch: riscv64
|
||||
name: freebsd-riscv64
|
||||
|
||||
- goos: aix
|
||||
goarch: ppc64
|
||||
name: aix-ppc64
|
||||
- goos: dragonfly
|
||||
goarch: amd64
|
||||
name: dragonfly-amd64
|
||||
- goos: illumos
|
||||
goarch: amd64
|
||||
name: illumos-amd64
|
||||
- goos: netbsd
|
||||
goarch: 386
|
||||
name: netbsd-386
|
||||
- goos: netbsd
|
||||
goarch: amd64
|
||||
name: netbsd-amd64
|
||||
- goos: netbsd
|
||||
goarch: arm
|
||||
name: netbsd-arm
|
||||
- goos: netbsd
|
||||
goarch: arm64
|
||||
name: netbsd-arm64
|
||||
- goos: openbsd
|
||||
goarch: 386
|
||||
name: openbsd-386
|
||||
- goos: openbsd
|
||||
goarch: amd64
|
||||
name: openbsd-amd64
|
||||
- goos: openbsd
|
||||
goarch: arm
|
||||
name: openbsd-arm
|
||||
- goos: openbsd
|
||||
goarch: arm64
|
||||
name: openbsd-arm64
|
||||
- goos: openbsd
|
||||
goarch: ppc64
|
||||
name: openbsd-ppc64
|
||||
- goos: openbsd
|
||||
goarch: riscv64
|
||||
name: openbsd-riscv64
|
||||
- goos: plan9
|
||||
goarch: 386
|
||||
name: plan9-386
|
||||
- goos: plan9
|
||||
goarch: amd64
|
||||
name: plan9-amd64
|
||||
- goos: plan9
|
||||
goarch: arm
|
||||
name: plan9-arm
|
||||
- goos: solaris
|
||||
goarch: amd64
|
||||
name: solaris-amd64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23.1'
|
||||
|
||||
- name: Build Gateway
|
||||
run: go build -ldflags="-s -w" -o gateway-${{ matrix.name }}${{ matrix.ext }} ./cmd/gateway
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
|
||||
- name: Build KCP
|
||||
run: go build -ldflags="-s -w" -o kcp-${{ matrix.name }}${{ matrix.ext }} ./cmd/kcp
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
|
||||
- name: Build QUIC
|
||||
run: go build -ldflags="-s -w" -o quic-${{ matrix.name }}${{ matrix.ext }} ./cmd/quic
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
|
||||
- name: Upload artifacts artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: binaries-${{ matrix.name }}
|
||||
path: |
|
||||
gateway-${{ matrix.name }}${{ matrix.ext }}
|
||||
kcp-${{ matrix.name }}${{ matrix.ext }}
|
||||
quic-${{ matrix.name }}${{ matrix.ext }}
|
||||
|
||||
# 合并所有构建产物
|
||||
merge-artifacts:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./artifacts
|
||||
merge-multiple: true # 合并所有 artifacts
|
||||
|
||||
- name: Display structure
|
||||
run: ls -la ./artifacts
|
||||
|
||||
- name: Upload merged artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mc-gateway-all-platforms
|
||||
path: ./artifacts/*
|
||||
retention-days: 30
|
||||
28
.github/workflows/go.yml
vendored
28
.github/workflows/go.yml
vendored
@@ -1,28 +0,0 @@
|
||||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23.1'
|
||||
|
||||
- name: Build
|
||||
run: go build -ldflags="-s -w" -v ./...
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./...
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.vscode
|
||||
|
||||
config.json
|
||||
config.toml
|
||||
/gateway
|
||||
/logs/
|
||||
|
||||
76
README.md
76
README.md
@@ -1,2 +1,76 @@
|
||||
# mc-gateway
|
||||
This project is a Minecraft game server gateway. It allows you to access multiple game servers through different hostnames, using the same port.
|
||||
|
||||
一个简易的 Minecraft 网关,通过 host 将客户端的流量转发到对应的后端 Minecraft 服务器。
|
||||
|
||||
## 配置
|
||||
|
||||
目前 mc-gateway 只支持读取当前目录的 `config.toml` 作为配置。在 `config.toml` 被修改时,可以自动加载并更新部分配置,以达到不停机修改配置的效果。支持热加载的配置有:
|
||||
|
||||
- hosts
|
||||
- log
|
||||
- KCP 的 data_shards 和 parity_Shards
|
||||
- QUIC 的 application_protocols
|
||||
|
||||
### hosts
|
||||
|
||||
hosts 使用期望的 host 做 key,转发的目的地址为 value。参考`config.example.toml`。
|
||||
|
||||
### log
|
||||
|
||||
| 配置 | 类型 | 备注 |
|
||||
| ----- | ------ | -------- |
|
||||
| level | Level | 日志等级 |
|
||||
| file | string | 日志文件 |
|
||||
|
||||
> 日志适配 logrotate,可以使用 logrotate 进行日志分片、压缩等日常运维操作,参考配置:
|
||||
|
||||
```logrotate
|
||||
/var/log/mc-gateway.log {
|
||||
copytruncate
|
||||
daily
|
||||
missingok
|
||||
rotate 14
|
||||
compress
|
||||
compresscmd /usr/bin/zstd
|
||||
compressext .zst
|
||||
compressoptions -T0 --long
|
||||
uncompresscmd /usr/bin/unzstd
|
||||
notifempty
|
||||
delaycompress
|
||||
dateext
|
||||
postrotate
|
||||
# 向程序发送 SIGHUP 信号
|
||||
# mc-gateway 默认会将当前进程的 pid 写入 /var/run/mc-gateway.pid
|
||||
if [ -f /var/run/mc-gateway.pid ]; then
|
||||
kill -SIGHUP $(cat /var/run/mc-gateway.pid)
|
||||
fi
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
### TCP
|
||||
|
||||
| 配置 | 类型 | 备注 |
|
||||
| ------ | ---- | -------- |
|
||||
| enable | bool | 是否启用 |
|
||||
| port | int | 端口 |
|
||||
|
||||
### KCP
|
||||
|
||||
| 配置 | 类型 | 备注 |
|
||||
| ------------- | ---- | -------- |
|
||||
| enable | bool | 是否启用 |
|
||||
| port | int | 端口 |
|
||||
| data_shards | int | 数据分片 |
|
||||
| parity_Shards | int | 校验分片 |
|
||||
|
||||
### QUIC
|
||||
|
||||
| 配置 | 类型 | 备注 |
|
||||
| --------------------- | -------- | ------------ |
|
||||
| enable | bool | 是否启用 |
|
||||
| port | int | 端口 |
|
||||
| application_protocols | []string | 应用协议列表 |
|
||||
|
||||
> application_protocols 只要客户端与服务端有一个能够对应上就可以成功连接
|
||||
> 默认值为 ["minecraft", "quic", "raw", "h3"]
|
||||
|
||||
123
cmd/gateway/config.go
Normal file
123
cmd/gateway/config.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
configFile = "config.toml"
|
||||
|
||||
config Config
|
||||
currentLogFile string
|
||||
configLoadLock sync.Mutex
|
||||
)
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
Tcp ProtocolConfig `toml:"tcp"`
|
||||
Quic QuicConfig `toml:"quic"`
|
||||
Kcp KcpConfig `toml:"kcp"`
|
||||
Hosts map[string]string `toml:"hosts"`
|
||||
Log LogConfig `toml:"log"`
|
||||
}
|
||||
|
||||
ProtocolConfig struct {
|
||||
Enable bool `toml:"enable"`
|
||||
Port int `toml:"port"`
|
||||
}
|
||||
|
||||
KcpConfig struct {
|
||||
Enable bool `toml:"enable"`
|
||||
Port int `toml:"port"`
|
||||
DataShards int `toml:"data_shards"`
|
||||
ParityShards int `toml:"parity_Shards"`
|
||||
}
|
||||
|
||||
QuicConfig struct {
|
||||
Enable bool `toml:"enable"`
|
||||
Port int `toml:"port"`
|
||||
ApplicionProtocols []string `toml:"application_protocols"`
|
||||
}
|
||||
|
||||
LogConfig struct {
|
||||
Level string `toml:"level"`
|
||||
File string `toml:"file"`
|
||||
}
|
||||
)
|
||||
|
||||
func loadConfig() error {
|
||||
configLoadLock.Lock()
|
||||
defer configLoadLock.Unlock()
|
||||
|
||||
file, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
byteValue, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := toml.Unmarshal(byteValue, &config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return loadLogger()
|
||||
}
|
||||
|
||||
func watchConfig() *fsnotify.Watcher {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Minute)
|
||||
if err := loadConfig(); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to reload config")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to create config watcher")
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
log.Error().Msg("watcher.Events channel closed")
|
||||
return
|
||||
}
|
||||
if !strings.HasSuffix(event.Name, configFile) {
|
||||
continue
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
log.Error().Msg("watcher.Errors channel closed")
|
||||
return
|
||||
}
|
||||
log.Error().Err(err).Msg("watcher error")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info().Msg("reload config")
|
||||
if err := loadConfig(); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to reload config")
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err = watcher.Add("."); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to watch config file")
|
||||
}
|
||||
|
||||
return watcher
|
||||
}
|
||||
41
cmd/gateway/kcp.go
Normal file
41
cmd/gateway/kcp.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/xtaci/kcp-go"
|
||||
)
|
||||
|
||||
func runKcp(wg *sync.WaitGroup) {
|
||||
if wg != nil {
|
||||
defer wg.Done()
|
||||
}
|
||||
|
||||
listener, err := kcp.ListenWithOptions(fmt.Sprintf(":%d", config.Kcp.Port), nil, config.Kcp.DataShards, config.Kcp.ParityShards)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Int("port", config.Kcp.Port).
|
||||
Msg("Failed to listen on KCP port")
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
log.Info().Int("port", config.Kcp.Port).Msg("KCP server is listening")
|
||||
|
||||
for {
|
||||
conn, err := listener.AcceptKCP()
|
||||
if err != nil {
|
||||
log.Err(err).
|
||||
Msg("Failed to accept KCP connection")
|
||||
continue
|
||||
}
|
||||
log.Info().
|
||||
Str("remote_addr", conn.RemoteAddr().String()).
|
||||
Msg("Accepted KCP connection")
|
||||
|
||||
conn.SetACKNoDelay(true)
|
||||
|
||||
go handleRequest(conn)
|
||||
}
|
||||
}
|
||||
70
cmd/gateway/log.go
Normal file
70
cmd/gateway/log.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func loadLogger() error {
|
||||
level, err := zerolog.ParseLevel(config.Log.Level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logger = log.Logger.Level(level)
|
||||
|
||||
if config.Log.File != "" && currentLogFile != config.Log.File {
|
||||
if err := os.MkdirAll(filepath.Dir(config.Log.File), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logFile, err := os.OpenFile(config.Log.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logger = log.Logger.Output(io.MultiWriter(os.Stdout, logFile))
|
||||
|
||||
currentLogFile = config.Log.File
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleLogRotate() {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, syscall.SIGHUP)
|
||||
|
||||
for range signalChan {
|
||||
log.Info().Msg("Received SIGHUP, reopening log file")
|
||||
if err := reopenLogFile(); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to reopen log file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reopenLogFile() error {
|
||||
configLoadLock.Lock()
|
||||
defer configLoadLock.Unlock()
|
||||
|
||||
if config.Log.File == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 重新打开日志文件
|
||||
logFile, err := os.OpenFile(config.Log.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logger = log.Logger.Output(io.MultiWriter(os.Stdout, logFile))
|
||||
currentLogFile = config.Log.File
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,142 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/tursom/mc-gateway/protocol"
|
||||
)
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
Port int `json:"port"`
|
||||
Tcp bool `json:"tcp"`
|
||||
Quic bool `json:"quic"`
|
||||
Hosts map[string]string `json:"hosts"`
|
||||
Default string `json:"default"`
|
||||
Log LogConfig `json:"log"`
|
||||
}
|
||||
|
||||
LogConfig struct {
|
||||
Level string `json:"level"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
configFile = "config.json"
|
||||
|
||||
config Config
|
||||
currentLogFile string
|
||||
configLoadLock sync.Mutex
|
||||
)
|
||||
|
||||
func loadConfig() error {
|
||||
configLoadLock.Lock()
|
||||
defer configLoadLock.Unlock()
|
||||
|
||||
file, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
byteValue, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(byteValue, &config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return loadLogger()
|
||||
}
|
||||
|
||||
func loadLogger() error {
|
||||
level, err := zerolog.ParseLevel(config.Log.Level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logger = log.Logger.Level(level)
|
||||
|
||||
if config.Log.File != "" && currentLogFile != config.Log.File {
|
||||
if err := os.MkdirAll(filepath.Dir(config.Log.File), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logFile, err := os.OpenFile(config.Log.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logger = log.Logger.Output(io.MultiWriter(os.Stdout, logFile))
|
||||
|
||||
currentLogFile = config.Log.File
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func watchConfig() *fsnotify.Watcher {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Minute)
|
||||
if err := loadConfig(); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to reload config")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to create config watcher")
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
log.Error().Msg("watcher.Events channel closed")
|
||||
return
|
||||
}
|
||||
if !strings.HasSuffix(event.Name, configFile) {
|
||||
continue
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
log.Error().Msg("watcher.Errors channel closed")
|
||||
return
|
||||
}
|
||||
log.Error().Err(err).Msg("watcher error")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info().Msg("reload config")
|
||||
if err := loadConfig(); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to reload config")
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err = watcher.Add("."); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to watch config file")
|
||||
}
|
||||
|
||||
return watcher
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := writePIDFile(); err != nil {
|
||||
panic(fmt.Sprintf("Failed to write PID file: %v", err))
|
||||
@@ -156,13 +30,18 @@ func main() {
|
||||
defer wg.Wait()
|
||||
|
||||
// 启动QUIC服务
|
||||
if config.Quic {
|
||||
if config.Quic.Enable {
|
||||
wg.Add(1)
|
||||
go runQuic(&wg)
|
||||
}
|
||||
|
||||
if config.Kcp.Enable {
|
||||
wg.Add(1)
|
||||
go runKcp(&wg)
|
||||
}
|
||||
|
||||
// 监听TCP端口
|
||||
if config.Tcp {
|
||||
if config.Tcp.Enable {
|
||||
wg.Add(1)
|
||||
go runTcp(&wg)
|
||||
}
|
||||
@@ -173,15 +52,15 @@ func runTcp(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", config.Port))
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", config.Tcp.Port))
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Int("port", config.Port).
|
||||
Int("port", config.Tcp.Port).
|
||||
Msg("Failed to listen on port")
|
||||
}
|
||||
defer listener.Close()
|
||||
log.Info().
|
||||
Int("port", config.Port).
|
||||
Int("port", config.Tcp.Port).
|
||||
Msg("Listening for TCP connections")
|
||||
|
||||
for {
|
||||
@@ -233,10 +112,10 @@ func handleRequest(conn net.Conn) {
|
||||
Msg("Error: buffer is empty")
|
||||
return
|
||||
}
|
||||
mc_host := getMcHost(buf[:n])
|
||||
mc_host := protocol.GetMcHost(buf[:n])
|
||||
host, ok := config.Hosts[mc_host]
|
||||
if !ok {
|
||||
host = config.Default
|
||||
host = config.Hosts["default"]
|
||||
}
|
||||
if host == "" {
|
||||
log.Err(errEmptyBuffer).
|
||||
@@ -248,6 +127,7 @@ func handleRequest(conn net.Conn) {
|
||||
|
||||
log.Info().
|
||||
Str("client", conn.RemoteAddr().String()).
|
||||
Str("host", mc_host).
|
||||
Str("mc", host).
|
||||
Msg("map to host")
|
||||
|
||||
@@ -257,6 +137,7 @@ func handleRequest(conn net.Conn) {
|
||||
return
|
||||
}
|
||||
defer client.Close()
|
||||
setSocketOptions(client)
|
||||
|
||||
client.Write(buf[:n])
|
||||
// 不需要 buf 了,释放掉
|
||||
@@ -295,26 +176,6 @@ func handleWrite(srv, cli net.Conn, wg *sync.WaitGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
func getMcHost(buf []byte) string {
|
||||
if len(buf) < 5 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf = buf[4:]
|
||||
host_len := buf[0]
|
||||
if len(buf) < int(host_len)+1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
host := string(buf[1 : host_len+1])
|
||||
|
||||
if spliterIndex := strings.IndexRune(host, 0); spliterIndex != -1 {
|
||||
return host[0:spliterIndex]
|
||||
} else {
|
||||
return host
|
||||
}
|
||||
}
|
||||
|
||||
func setSocketOptions(conn net.Conn) {
|
||||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||||
tcpConn.SetNoDelay(true) // 禁用 Nagle 算法
|
||||
@@ -322,35 +183,3 @@ func setSocketOptions(conn net.Conn) {
|
||||
tcpConn.SetKeepAlivePeriod(30 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func handleLogRotate() {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, syscall.SIGHUP)
|
||||
|
||||
for range signalChan {
|
||||
log.Info().Msg("Received SIGHUP, reopening log file")
|
||||
if err := reopenLogFile(); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to reopen log file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reopenLogFile() error {
|
||||
configLoadLock.Lock()
|
||||
defer configLoadLock.Unlock()
|
||||
|
||||
if config.Log.File == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 重新打开日志文件
|
||||
logFile, err := os.OpenFile(config.Log.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logger = log.Logger.Output(io.MultiWriter(os.Stdout, logFile))
|
||||
currentLogFile = config.Log.File
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// pid_unix.go
|
||||
//go:build unix || plan9
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -1,3 +1,6 @@
|
||||
// pid_windows.go
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
func writePIDFile() error {
|
||||
|
||||
@@ -28,7 +28,7 @@ func runQuic(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
}
|
||||
|
||||
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: config.Port})
|
||||
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: config.Quic.Port})
|
||||
if err != nil {
|
||||
log.Panic().Err(err).Msg("Failed to listen UDP")
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func runQuic(wg *sync.WaitGroup) {
|
||||
if err != nil {
|
||||
log.Panic().Err(err).Msg("Failed to listen QUIC")
|
||||
}
|
||||
log.Info().Int("port", config.Port).Msg("Listening for QUIC connections")
|
||||
log.Info().Int("port", config.Quic.Port).Msg("Listening for QUIC connections")
|
||||
|
||||
for {
|
||||
conn, err := ln.Accept(context.Background())
|
||||
@@ -52,6 +52,9 @@ func runQuic(wg *sync.WaitGroup) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Str("client", conn.RemoteAddr().String()).
|
||||
Msg("Accepted QUIC connection")
|
||||
go handleQuicRequest(conn)
|
||||
}
|
||||
}
|
||||
@@ -115,8 +118,14 @@ func generateTLSConfig() (*tls.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nextProtos := config.Quic.ApplicionProtocols
|
||||
if len(nextProtos) == 0 {
|
||||
nextProtos = []string{"minecraft", "quic", "raw", "h3"} // 默认协议
|
||||
}
|
||||
|
||||
// 返回 tls.Config
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
NextProtos: nextProtos,
|
||||
}, nil
|
||||
}
|
||||
|
||||
123
cmd/kcp/main.go
Normal file
123
cmd/kcp/main.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/tursom/mc-gateway/protocol"
|
||||
"github.com/xtaci/kcp-go"
|
||||
)
|
||||
|
||||
var (
|
||||
localPort = 25565
|
||||
|
||||
mcHost = "bh.mc.tursom.cn"
|
||||
mcPort = 25566
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
mcHost = os.Args[1]
|
||||
}
|
||||
|
||||
// 监听TCP端口
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", localPort))
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Int("port", localPort).
|
||||
Msg("Failed to listen on port")
|
||||
}
|
||||
defer listener.Close()
|
||||
log.Info().
|
||||
Int("port", localPort).
|
||||
Msg("Listening for TCP connections")
|
||||
|
||||
for {
|
||||
// 接受传入的连接
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Error accepting")
|
||||
continue
|
||||
}
|
||||
log.Info().
|
||||
Str("client", conn.RemoteAddr().String()).
|
||||
Int("port", localPort).
|
||||
Msg("Accepted connection")
|
||||
// 处理连接
|
||||
go handlerConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func handlerConn(client net.Conn) {
|
||||
defer client.Close()
|
||||
setSocketOptions(client)
|
||||
|
||||
conn, err := kcp.DialWithOptions(fmt.Sprintf("%s:%d", mcHost, mcPort), nil, 10, 5)
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
Msg("Failed to dial KCP server")
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetACKNoDelay(true)
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
n, err := client.Read(buf)
|
||||
if err != nil {
|
||||
log.Err(err).
|
||||
Str("client", client.RemoteAddr().String()).
|
||||
Msg("Error reading hostname")
|
||||
return
|
||||
}
|
||||
if n == 0 {
|
||||
log.Err(errors.New("empty buffer")).
|
||||
Str("client", client.RemoteAddr().String()).
|
||||
Msg("Error: buffer is empty")
|
||||
return
|
||||
}
|
||||
buf = buf[:n]
|
||||
|
||||
buf = protocol.ReplaceMcHost(buf, mcHost)
|
||||
_, err = conn.Write(buf) // 写入数据到 QUIC 流
|
||||
if err != nil {
|
||||
log.Err(err).
|
||||
Str("client", client.RemoteAddr().String()).
|
||||
Str("host", mcHost).
|
||||
Int("port", mcPort).
|
||||
Msg("Error writing to QUIC stream")
|
||||
return
|
||||
}
|
||||
// 释放 buf
|
||||
buf = nil
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go copyData(conn, client, &wg)
|
||||
copyData(client, conn, nil)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func copyData(src io.Reader, dst io.Writer, wg *sync.WaitGroup) {
|
||||
if wg != nil {
|
||||
defer wg.Done()
|
||||
}
|
||||
|
||||
_, err := io.Copy(dst, src)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Err(err).Msg("Error copying data")
|
||||
}
|
||||
}
|
||||
|
||||
func setSocketOptions(conn net.Conn) {
|
||||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||||
tcpConn.SetNoDelay(true) // 禁用 Nagle 算法
|
||||
tcpConn.SetKeepAlive(true)
|
||||
tcpConn.SetKeepAlivePeriod(30 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
@@ -9,12 +8,12 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/tursom/mc-gateway/protocol"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -60,8 +59,11 @@ func main() {
|
||||
func handlerConn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
setSocketOptions(conn)
|
||||
|
||||
tlsConf := &tls.Config{
|
||||
InsecureSkipVerify: true, // 跳过证书检查
|
||||
NextProtos: []string{"minecraft", "quic", "raw", "h3"},
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 3s handshake timeout
|
||||
@@ -100,8 +102,8 @@ func handlerConn(conn net.Conn) {
|
||||
}
|
||||
buf = buf[:n]
|
||||
|
||||
new_buf := replaceMcHost(buf, mcHost)
|
||||
_, err = stream.Write(new_buf) // 写入数据到 QUIC 流
|
||||
buf = protocol.ReplaceMcHost(buf, mcHost)
|
||||
_, err = stream.Write(buf) // 写入数据到 QUIC 流
|
||||
if err != nil {
|
||||
log.Err(err).
|
||||
Str("client", conn.RemoteAddr().String()).
|
||||
@@ -110,6 +112,8 @@ func handlerConn(conn net.Conn) {
|
||||
Msg("Error writing to QUIC stream")
|
||||
return
|
||||
}
|
||||
// 释放 buf
|
||||
buf = nil
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
@@ -129,33 +133,10 @@ func copyData(src io.Reader, dst io.Writer, wg *sync.WaitGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
func replaceMcHost(buf []byte, host string) []byte {
|
||||
if len(buf) < 5 {
|
||||
return nil
|
||||
func setSocketOptions(conn net.Conn) {
|
||||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||||
tcpConn.SetNoDelay(true) // 禁用 Nagle 算法
|
||||
tcpConn.SetKeepAlive(true)
|
||||
tcpConn.SetKeepAlivePeriod(30 * time.Second)
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
head := buf[:4]
|
||||
|
||||
buf = buf[4:]
|
||||
host_len := buf[0]
|
||||
if len(buf) < int(host_len)+1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
raw_host := string(buf[1 : host_len+1])
|
||||
if spliterIndex := strings.IndexRune(raw_host, 0); spliterIndex != -1 {
|
||||
host = host + raw_host[spliterIndex:]
|
||||
}
|
||||
|
||||
// 修改标识数据包长度的字节
|
||||
head[0] += byte(len(host) - len(raw_host))
|
||||
|
||||
out.Write(head) // 保留前四个字节
|
||||
out.WriteByte(byte(len(host))) // 写入主机名长度
|
||||
out.Write([]byte(host)) // 写入主机名
|
||||
|
||||
out.Write(buf[host_len+1:]) // 写入剩余数据
|
||||
|
||||
return out.Bytes()
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "warn",
|
||||
"file": "logs/mc1.log"
|
||||
},
|
||||
"port": 25565,
|
||||
"default": "mc1:25565",
|
||||
"hosts": {
|
||||
"dev": "mc1:25565",
|
||||
"dev.lan": "mc1:25568"
|
||||
}
|
||||
}
|
||||
19
config.example.toml
Normal file
19
config.example.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[log]
|
||||
level = "warn"
|
||||
file = "logs/mc1.log"
|
||||
|
||||
[tcp]
|
||||
enable = true
|
||||
port = 25565
|
||||
|
||||
[quic]
|
||||
enable = true
|
||||
port = 25565
|
||||
|
||||
[kcp]
|
||||
enable = true
|
||||
port = 25566
|
||||
|
||||
[hosts]
|
||||
dev = "mc1:25565"
|
||||
"dev.lan" = "mc1:25568"
|
||||
11
go.mod
11
go.mod
@@ -3,22 +3,31 @@ module github.com/tursom/mc-gateway
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||
github.com/klauspost/reedsolomon v1.12.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.23.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
)
|
||||
|
||||
91
go.sum
91
go.sum
@@ -1,10 +1,20 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
@@ -12,13 +22,32 @@ github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
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=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/reedsolomon v1.12.4 h1:5aDr3ZGoJbgu/8+j45KtUJxzYm8k08JGtB9Wx1VQ4OA=
|
||||
github.com/klauspost/reedsolomon v1.12.4/go.mod h1:d3CzOMOt0JXGIFZm1StgkyF14EYr3xneR2rNWo7NcMU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
@@ -28,9 +57,11 @@ github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
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/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
@@ -40,29 +71,85 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI=
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
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=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
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/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
|
||||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
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=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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=
|
||||
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=
|
||||
|
||||
60
protocol/mc.go
Normal file
60
protocol/mc.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ReplaceMcHost 替换 Minecraft 主机名
|
||||
// 必须是连接的第一个数据包
|
||||
func ReplaceMcHost(buf []byte, host string) []byte {
|
||||
if len(buf) < 5 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
head := buf[:4]
|
||||
|
||||
buf = buf[4:]
|
||||
host_len := buf[0]
|
||||
if len(buf) < int(host_len)+1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
raw_host := string(buf[1 : host_len+1])
|
||||
if spliterIndex := strings.IndexRune(raw_host, 0); spliterIndex != -1 {
|
||||
host = host + raw_host[spliterIndex:]
|
||||
}
|
||||
|
||||
// 修改标识数据包长度的字节
|
||||
head[0] += byte(len(host) - len(raw_host))
|
||||
|
||||
out.Write(head) // 保留前四个字节
|
||||
out.WriteByte(byte(len(host))) // 写入主机名长度
|
||||
out.Write([]byte(host)) // 写入主机名
|
||||
|
||||
out.Write(buf[host_len+1:]) // 写入剩余数据
|
||||
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
// GetMcHost 通过第一个数据包获取 Minecraft 主机名
|
||||
func GetMcHost(buf []byte) string {
|
||||
if len(buf) < 5 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf = buf[4:]
|
||||
host_len := buf[0]
|
||||
if len(buf) < int(host_len)+1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
host := string(buf[1 : host_len+1])
|
||||
|
||||
if spliterIndex := strings.IndexRune(host, 0); spliterIndex != -1 {
|
||||
return host[0:spliterIndex]
|
||||
} else {
|
||||
return host
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user