mirror of
https://github.com/go-gost/gost.git
synced 2026-10-08 20:15:46 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0793f4730f | ||
|
|
11220b15bb | ||
|
|
d7656ef3de | ||
|
|
7a220c6cd7 |
@@ -97,6 +97,10 @@ nfpms:
|
|||||||
dst: /usr/share/doc/gost/LICENSE
|
dst: /usr/share/doc/gost/LICENSE
|
||||||
- src: gost.yml
|
- src: gost.yml
|
||||||
dst: /usr/share/doc/gost/examples/gost.yml
|
dst: /usr/share/doc/gost/examples/gost.yml
|
||||||
|
- dst: /etc/gost
|
||||||
|
type: dir
|
||||||
|
file_info:
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ go 1.26.3
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-gost/core v0.6.1
|
github.com/go-gost/core v0.6.1
|
||||||
github.com/go-gost/x v0.17.2
|
github.com/go-gost/x v0.19.5
|
||||||
github.com/judwhite/go-svc v1.2.1
|
github.com/judwhite/go-svc v1.2.1
|
||||||
github.com/moby/moby/client v0.4.0
|
github.com/moby/moby/client v0.4.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
@@ -48,7 +48,7 @@ require (
|
|||||||
github.com/go-gost/go-shadowsocks2 v0.1.4 // indirect
|
github.com/go-gost/go-shadowsocks2 v0.1.4 // indirect
|
||||||
github.com/go-gost/gosocks4 v0.1.0 // indirect
|
github.com/go-gost/gosocks4 v0.1.0 // indirect
|
||||||
github.com/go-gost/gosocks5 v0.5.0 // indirect
|
github.com/go-gost/gosocks5 v0.5.0 // indirect
|
||||||
github.com/go-gost/plugin v0.8.0 // indirect
|
github.com/go-gost/plugin v0.8.1 // indirect
|
||||||
github.com/go-gost/quic-dissector v0.1.0 // indirect
|
github.com/go-gost/quic-dissector v0.1.0 // indirect
|
||||||
github.com/go-gost/relay v0.7.0 // indirect
|
github.com/go-gost/relay v0.7.0 // indirect
|
||||||
github.com/go-gost/tls-dissector v0.3.1 // indirect
|
github.com/go-gost/tls-dissector v0.3.1 // indirect
|
||||||
|
|||||||
@@ -88,16 +88,16 @@ github.com/go-gost/gosocks4 v0.1.0 h1:eAzev6qw4fzkFQKC9uCHLVNnnPdHyqCggbnfNN80Pm
|
|||||||
github.com/go-gost/gosocks4 v0.1.0/go.mod h1:hzVjwijJuZR1pp3GqpTj+AKcSGrx68RlWTrQMFMYBP0=
|
github.com/go-gost/gosocks4 v0.1.0/go.mod h1:hzVjwijJuZR1pp3GqpTj+AKcSGrx68RlWTrQMFMYBP0=
|
||||||
github.com/go-gost/gosocks5 v0.5.0 h1:YE37l1MJwde8diIQdynStqogMotG5enoTdborhA5yic=
|
github.com/go-gost/gosocks5 v0.5.0 h1:YE37l1MJwde8diIQdynStqogMotG5enoTdborhA5yic=
|
||||||
github.com/go-gost/gosocks5 v0.5.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
github.com/go-gost/gosocks5 v0.5.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
||||||
github.com/go-gost/plugin v0.8.0 h1:KL4vLck/yqY3+TSm6RMc07IuZe9nJIVzoGH0/or0ei4=
|
github.com/go-gost/plugin v0.8.1 h1:mZpLbzRZosHocaiZ4dYYqX8waLiavy/rsEWwqx5aluo=
|
||||||
github.com/go-gost/plugin v0.8.0/go.mod h1:48pqi8/zS5OhEEoFETYZCqu2sR59DX3QxG5SjGmPWcU=
|
github.com/go-gost/plugin v0.8.1/go.mod h1:48pqi8/zS5OhEEoFETYZCqu2sR59DX3QxG5SjGmPWcU=
|
||||||
github.com/go-gost/quic-dissector v0.1.0 h1:zOaw2XjKxMf6vVC1z4BHDKGHbCs4zrYU1Rxaz5d0TQU=
|
github.com/go-gost/quic-dissector v0.1.0 h1:zOaw2XjKxMf6vVC1z4BHDKGHbCs4zrYU1Rxaz5d0TQU=
|
||||||
github.com/go-gost/quic-dissector v0.1.0/go.mod h1:ar+I40Izq9ZT2k/aNnLFGEMvdeSOBLLKxhF/i3FSnQQ=
|
github.com/go-gost/quic-dissector v0.1.0/go.mod h1:ar+I40Izq9ZT2k/aNnLFGEMvdeSOBLLKxhF/i3FSnQQ=
|
||||||
github.com/go-gost/relay v0.7.0 h1:J8e3Sba6DtBJQotXY5j5EaZNWwtv6Z9CoCFQsnrHNcE=
|
github.com/go-gost/relay v0.7.0 h1:J8e3Sba6DtBJQotXY5j5EaZNWwtv6Z9CoCFQsnrHNcE=
|
||||||
github.com/go-gost/relay v0.7.0/go.mod h1:Dku0f5sfjOClrZFiDmQUrYYJ4uof7rnkCUBfsl0PSAI=
|
github.com/go-gost/relay v0.7.0/go.mod h1:Dku0f5sfjOClrZFiDmQUrYYJ4uof7rnkCUBfsl0PSAI=
|
||||||
github.com/go-gost/tls-dissector v0.3.1 h1:gvOteWog5pjY/HCpc8l+gngmSi8Q6zl5rRrfK8gwRKA=
|
github.com/go-gost/tls-dissector v0.3.1 h1:gvOteWog5pjY/HCpc8l+gngmSi8Q6zl5rRrfK8gwRKA=
|
||||||
github.com/go-gost/tls-dissector v0.3.1/go.mod h1:vGfog053fIm93iXBtvmVzMQqEJo5YwbbNaPNVDjbiOc=
|
github.com/go-gost/tls-dissector v0.3.1/go.mod h1:vGfog053fIm93iXBtvmVzMQqEJo5YwbbNaPNVDjbiOc=
|
||||||
github.com/go-gost/x v0.17.2 h1:w3SGNnMIETYKHsjfV0LKtB5+ogUwvoF7gmQ/3EMIRWg=
|
github.com/go-gost/x v0.19.5 h1:brbvQ6Pkq2pMr7k+IQvKB8dDdkt1D2IhURaVZZ5sicw=
|
||||||
github.com/go-gost/x v0.17.2/go.mod h1:Ckb10HVdIQf5DRXpbdLi+kv61mRmTyMhZbYbAwsz7tc=
|
github.com/go-gost/x v0.19.5/go.mod h1:YknNANia9Jzp5/TgPzGN6tcVir0WbapexBOird+4s0U=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ ExecStart=/usr/bin/gost -C /etc/gost/gost.yml
|
|||||||
ExecReload=/bin/kill -SIGHUP $MAINPID
|
ExecReload=/bin/kill -SIGHUP $MAINPID
|
||||||
|
|
||||||
DynamicUser=yes
|
DynamicUser=yes
|
||||||
|
ConfigurationDirectory=gost
|
||||||
RuntimeDirectory=gost
|
RuntimeDirectory=gost
|
||||||
LogsDirectory=gost
|
LogsDirectory=gost
|
||||||
TimeoutStopSec=5s
|
TimeoutStopSec=5s
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"github.com/testcontainers/testcontainers-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RUDPBindSuite reproduces go-gost/gost#911: concurrent UDP source sockets
|
||||||
|
// sharing ONE reverse UDP tunnel over a relay server.
|
||||||
|
//
|
||||||
|
// Topology (all three gost processes plus a UDP echo server):
|
||||||
|
//
|
||||||
|
// UDP source sockets (N) -> client udp service -> relay server
|
||||||
|
// -> reverse-bound UDP port -> host rudp listener (ONE shared stream)
|
||||||
|
// -> udp-echo
|
||||||
|
//
|
||||||
|
// A datagram frame is written to that shared stream as three separate Write
|
||||||
|
// calls (RSV/FRAG, SOCKS5 address, payload). Before the fix, with N endpoints
|
||||||
|
// writing concurrently, frames interleaved between those calls: replies came
|
||||||
|
// back corrupted, and a torn frame left half a header in the stream, which the
|
||||||
|
// far end read as "unexpected EOF" and answered by tearing down and rebinding
|
||||||
|
// the whole reverse tunnel every second.
|
||||||
|
//
|
||||||
|
// The host is the side that binds the tunnel, so its log is where a reset
|
||||||
|
// shows up as "unexpected EOF, retrying in 1s" followed by a rebind.
|
||||||
|
type RUDPBindSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
ctx context.Context
|
||||||
|
udpC testcontainers.Container
|
||||||
|
serverC testcontainers.Container
|
||||||
|
hostC testcontainers.Container
|
||||||
|
clientC testcontainers.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RUDPBindSuite) SetupSuite() {
|
||||||
|
s.ctx = context.Background()
|
||||||
|
|
||||||
|
udpC, err := RunUDPEchoContainer(s.ctx, SharedNetworkName)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.udpC = udpC
|
||||||
|
|
||||||
|
serverC, err := RunGostContainerWithOptions(s.ctx, SharedNetworkName,
|
||||||
|
"testdata/rudpbind/server.yaml", []string{"gost-server"}, []string{"8430/tcp"})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.serverC = serverC
|
||||||
|
|
||||||
|
// The host's rudp listener opens no local port, so it exposes a dummy TCP
|
||||||
|
// port (service-1) purely for the readiness wait.
|
||||||
|
hostC, err := RunGostContainerWithOptions(s.ctx, SharedNetworkName,
|
||||||
|
"testdata/rudpbind/host.yaml", []string{"gost-host"}, []string{"8431/tcp"})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.hostC = hostC
|
||||||
|
|
||||||
|
clientC, err := RunGostContainerWithFiles(s.ctx, SharedNetworkName,
|
||||||
|
"testdata/rudpbind/client.yaml",
|
||||||
|
[]testcontainers.ContainerFile{
|
||||||
|
{HostFilePath: "scripts/udp_rudp_concurrent.py", ContainerFilePath: "/scripts/udp_rudp_concurrent.py", FileMode: 0644},
|
||||||
|
})
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.clientC = clientC
|
||||||
|
|
||||||
|
// The reverse tunnel binds remotely on first traffic, not at startup.
|
||||||
|
up := assert.Eventually(s.T(), func() bool {
|
||||||
|
out := s.sendConcurrent(1, 1)
|
||||||
|
if !strings.Contains(out, "PASS") {
|
||||||
|
s.T().Logf("waiting for tunnel, sender said:\n%s", out)
|
||||||
|
}
|
||||||
|
return out != "" && strings.Contains(out, "PASS")
|
||||||
|
}, 30*time.Second, time.Second, "reverse UDP tunnel never came up")
|
||||||
|
if !up {
|
||||||
|
DumpLogs(s.T(), s.ctx, "host logs", s.hostC)
|
||||||
|
DumpLogs(s.T(), s.ctx, "server logs", s.serverC)
|
||||||
|
DumpLogs(s.T(), s.ctx, "client logs", s.clientC)
|
||||||
|
s.FailNow("reverse UDP tunnel never came up")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RUDPBindSuite) TearDownSuite() {
|
||||||
|
for _, c := range []testcontainers.Container{s.clientC, s.hostC, s.serverC, s.udpC} {
|
||||||
|
if c != nil {
|
||||||
|
c.Terminate(s.ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendConcurrent runs the concurrent sender inside the client container and
|
||||||
|
// returns its combined stdout+stderr.
|
||||||
|
func (s *RUDPBindSuite) sendConcurrent(endpoints, seconds int) string {
|
||||||
|
cmd := []string{
|
||||||
|
"python3", "/scripts/udp_rudp_concurrent.py",
|
||||||
|
// The client service listens in this same container, so loopback is the
|
||||||
|
// correct target — no network alias needed for the sender.
|
||||||
|
"127.0.0.1", "8432",
|
||||||
|
strconv.Itoa(endpoints), strconv.Itoa(seconds),
|
||||||
|
}
|
||||||
|
_, out, err := s.clientC.Exec(s.ctx, cmd)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var sb strings.Builder
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
for {
|
||||||
|
n, err := out.Read(buf)
|
||||||
|
sb.Write(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConcurrentEndpointsShareTunnel is the regression assertion: several UDP
|
||||||
|
// source sockets sharing one reverse tunnel must each get their own datagrams
|
||||||
|
// back unchanged, and the tunnel must not be rebuilt underneath them.
|
||||||
|
func (s *RUDPBindSuite) TestConcurrentEndpointsShareTunnel() {
|
||||||
|
out := s.sendConcurrent(4, 8)
|
||||||
|
s.T().Logf("concurrent send:\n%s", out)
|
||||||
|
|
||||||
|
if strings.Contains(out, "FAIL") {
|
||||||
|
DumpLogs(s.T(), s.ctx, "host logs", s.hostC)
|
||||||
|
DumpLogs(s.T(), s.ctx, "server logs", s.serverC)
|
||||||
|
}
|
||||||
|
s.Require().Contains(out, "PASS", "concurrent endpoints over one reverse tunnel failed:\n%s", out)
|
||||||
|
|
||||||
|
// Belt and braces: the host log is where the reset appears directly.
|
||||||
|
hostLogs, err := s.hostC.Logs(s.ctx)
|
||||||
|
if err == nil {
|
||||||
|
body, readErr := io.ReadAll(hostLogs)
|
||||||
|
hostLogs.Close()
|
||||||
|
if readErr == nil {
|
||||||
|
s.Require().NotContains(string(body), "unexpected EOF",
|
||||||
|
"reverse tunnel was torn down while endpoints were sending")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRUDPBindSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(RUDPBindSuite))
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
"""Concurrent UDP sender for the gost#911 reverse-tunnel regression test.
|
||||||
|
|
||||||
|
Each socket is an independent source endpoint sharing ONE reverse tunnel
|
||||||
|
stream. Every datagram is a run of its own endpoint id, so a reply that does
|
||||||
|
not match the id byte exactly is a frame corrupted by an interleaved writer
|
||||||
|
rather than plain loss.
|
||||||
|
|
||||||
|
Usage: udp_rudp_concurrent.py <host> <port> <count> <duration_seconds>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = sys.argv[1]
|
||||||
|
port = int(sys.argv[2])
|
||||||
|
count = int(sys.argv[3])
|
||||||
|
duration = float(sys.argv[4])
|
||||||
|
|
||||||
|
payload_len = 1200
|
||||||
|
end = time.monotonic() + duration
|
||||||
|
results = {}
|
||||||
|
lock = threading.Lock()
|
||||||
|
|
||||||
|
def endpoint(endpoint_id):
|
||||||
|
payload = bytes([endpoint_id]) * payload_len
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.bind(("0.0.0.0", 0))
|
||||||
|
sock.settimeout(0.2)
|
||||||
|
|
||||||
|
sent = received = damaged = 0
|
||||||
|
largest_gap = 0.0
|
||||||
|
last = time.monotonic()
|
||||||
|
|
||||||
|
while time.monotonic() < end:
|
||||||
|
try:
|
||||||
|
sock.sendto(payload, (host, port))
|
||||||
|
sent += 1
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
data, _ = sock.recvfrom(65535)
|
||||||
|
except socket.timeout:
|
||||||
|
break
|
||||||
|
except OSError:
|
||||||
|
break
|
||||||
|
received += 1
|
||||||
|
if data != payload:
|
||||||
|
damaged += 1
|
||||||
|
now = time.monotonic()
|
||||||
|
largest_gap = max(largest_gap, now - last)
|
||||||
|
last = now
|
||||||
|
|
||||||
|
largest_gap = max(largest_gap, time.monotonic() - last)
|
||||||
|
with lock:
|
||||||
|
results[endpoint_id] = (sent, received, damaged, round(largest_gap, 3))
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
threads = [
|
||||||
|
threading.Thread(target=endpoint, args=(i + 1,)) for i in range(count)
|
||||||
|
]
|
||||||
|
for t in threads:
|
||||||
|
t.start()
|
||||||
|
for t in threads:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
failures = []
|
||||||
|
for endpoint_id in sorted(results):
|
||||||
|
sent, received, damaged, gap = results[endpoint_id]
|
||||||
|
loss_pct = 100.0 * (1.0 - received / sent) if sent else 100.0
|
||||||
|
print(
|
||||||
|
f"endpoint {endpoint_id}: sent={sent} received={received} "
|
||||||
|
f"damaged={damaged} loss={loss_pct:.1f}% max_gap={gap}"
|
||||||
|
)
|
||||||
|
# Unsent datagrams are outside our control (the UDP socket's own
|
||||||
|
# buffer); anything that comes BACK must be byte-identical.
|
||||||
|
if damaged:
|
||||||
|
failures.append(
|
||||||
|
f"endpoint {endpoint_id}: {damaged} datagram(s) came back "
|
||||||
|
f"corrupted — frames interleaved on the shared tunnel stream"
|
||||||
|
)
|
||||||
|
# A torn frame makes the far end read io.ErrUnexpectedEOF, which
|
||||||
|
# rebuilds the whole reverse tunnel. That shows up as a receive gap of
|
||||||
|
# seconds, not milliseconds.
|
||||||
|
if gap >= 1.0:
|
||||||
|
failures.append(
|
||||||
|
f"endpoint {endpoint_id}: {gap}s receive gap — the reverse "
|
||||||
|
f"tunnel was torn down and rebound under active traffic"
|
||||||
|
)
|
||||||
|
|
||||||
|
if failures:
|
||||||
|
for f in failures:
|
||||||
|
print(f"FAIL: {f}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"PASS: {count} concurrent endpoints, no corruption, no tunnel reset")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
# Internal client behind NAT for gost#911: a UDP forward service that sends all
|
||||||
|
# traffic to the port the host bound through the reverse tunnel.
|
||||||
|
#
|
||||||
|
# The forwarder target is gost-server:8432 — that is where the reverse tunnel is
|
||||||
|
# actually bound (the host's rudp listener asked the relay server to bind it, so
|
||||||
|
# the port lives on the relay server, not on the host). Datagrams go there and
|
||||||
|
# are carried back to the internal host over the one shared tunnel stream.
|
||||||
|
services:
|
||||||
|
- name: service-0
|
||||||
|
addr: ":8432"
|
||||||
|
handler:
|
||||||
|
type: udp
|
||||||
|
listener:
|
||||||
|
type: udp
|
||||||
|
metadata:
|
||||||
|
keepalive: true
|
||||||
|
ttl: 5m
|
||||||
|
forwarder:
|
||||||
|
nodes:
|
||||||
|
- name: tunnel
|
||||||
|
addr: gost-server:8432
|
||||||
|
|
||||||
|
chains:
|
||||||
|
- name: chain-0
|
||||||
|
hops:
|
||||||
|
- nodes:
|
||||||
|
- addr: gost-server:8430
|
||||||
|
connector:
|
||||||
|
type: relay
|
||||||
|
dialer:
|
||||||
|
type: tcp
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: debug
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
# Internal host behind NAT for gost#911: binds a reverse UDP tunnel (rudp)
|
||||||
|
# through the relay server and forwards it to the local UDP echo server.
|
||||||
|
#
|
||||||
|
# The rudp listener opens no local port — it binds the UDP port remotely through
|
||||||
|
# the chain. service-1 is a dummy TCP listener purely so the e2e harness has a
|
||||||
|
# stable port to wait on for container readiness.
|
||||||
|
services:
|
||||||
|
- name: service-0
|
||||||
|
addr: "0.0.0.0:8432"
|
||||||
|
handler:
|
||||||
|
type: rudp
|
||||||
|
listener:
|
||||||
|
type: rudp
|
||||||
|
chain: chain-0
|
||||||
|
metadata:
|
||||||
|
ttl: 5m
|
||||||
|
forwarder:
|
||||||
|
nodes:
|
||||||
|
- name: echo
|
||||||
|
addr: udp-echo:5679
|
||||||
|
|
||||||
|
# Dummy TCP service on a fixed port: the rudp reverse-tunnel listener binds
|
||||||
|
# remotely through the chain and opens no local port, so this gives the e2e
|
||||||
|
# harness a stable port to wait on. Nothing ever targets it — the harness
|
||||||
|
# only opens and immediately closes the connection.
|
||||||
|
- name: service-1
|
||||||
|
addr: ":8431"
|
||||||
|
handler:
|
||||||
|
type: tcp
|
||||||
|
listener:
|
||||||
|
type: tcp
|
||||||
|
|
||||||
|
chains:
|
||||||
|
- name: chain-0
|
||||||
|
hops:
|
||||||
|
- nodes:
|
||||||
|
- addr: gost-server:8430
|
||||||
|
connector:
|
||||||
|
type: relay
|
||||||
|
dialer:
|
||||||
|
type: tcp
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: debug
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# Public-facing relay server for gost#911: allows UDP BIND so an internal host
|
||||||
|
# can bind a reverse UDP tunnel through it. The host asks the server to bind
|
||||||
|
# the tunnel's UDP port, so that port lives here — on the relay server, not on
|
||||||
|
# the host behind NAT.
|
||||||
|
services:
|
||||||
|
- name: service-0
|
||||||
|
addr: ":8430"
|
||||||
|
handler:
|
||||||
|
type: relay
|
||||||
|
metadata:
|
||||||
|
bind: true
|
||||||
|
listener:
|
||||||
|
type: tcp
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: debug
|
||||||
Reference in New Issue
Block a user