mirror of
https://github.com/qdm12/gluetun.git
synced 2026-07-04 17:49:51 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d7892a2ffe | |||
| 52a41cb891 | |||
| 6c76273ef6 | |||
| 366062dc12 |
@@ -41,7 +41,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DOCKER_BUILDKIT: "1"
|
DOCKER_BUILDKIT: "1"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: reviewdog/action-misspell@v1
|
- uses: reviewdog/action-misspell@v1
|
||||||
with:
|
with:
|
||||||
@@ -79,7 +79,7 @@ jobs:
|
|||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
@@ -105,7 +105,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: secrets
|
environment: secrets
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- run: docker build -t qmcgaw/gluetun .
|
- run: docker build -t qmcgaw/gluetun .
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
@@ -183,7 +183,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: secrets
|
environment: secrets
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
# extract metadata (tags, labels) for Docker
|
# extract metadata (tags, labels) for Docker
|
||||||
# https://github.com/docker/metadata-action
|
# https://github.com/docker/metadata-action
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
- uses: crazy-max/ghaction-github-labeler@v6
|
- uses: crazy-max/ghaction-github-labeler@v6
|
||||||
with:
|
with:
|
||||||
yaml-file: .github/labels.yml
|
yaml-file: .github/labels.yml
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
environment: secrets
|
environment: secrets
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- uses: DavidAnson/markdownlint-cli2-action@v22
|
- uses: DavidAnson/markdownlint-cli2-action@v22
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ func streamLines(done chan<- struct{}, logger Logger,
|
|||||||
case line, ok := <-stdout:
|
case line, ok := <-stdout:
|
||||||
if ok {
|
if ok {
|
||||||
logger.Info(line)
|
logger.Info(line)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if stderr == nil {
|
if stderr == nil {
|
||||||
return
|
return
|
||||||
@@ -44,6 +45,7 @@ func streamLines(done chan<- struct{}, logger Logger,
|
|||||||
case line, ok := <-stderr:
|
case line, ok := <-stderr:
|
||||||
if ok {
|
if ok {
|
||||||
logger.Error(line)
|
logger.Error(line)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if stdout == nil {
|
if stdout == nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package socks5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand/v2"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Server_UDPResolution(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctx := t.Context()
|
||||||
|
|
||||||
|
server := newServer(Settings{
|
||||||
|
Address: "127.0.0.1:0",
|
||||||
|
Logger: noopLogger{},
|
||||||
|
})
|
||||||
|
runErr, err := server.Start(ctx)
|
||||||
|
require.NoError(t, err, "starting SOCKS5 server")
|
||||||
|
|
||||||
|
const timeout = 3 * time.Second
|
||||||
|
|
||||||
|
// Connect to the SOCKS5 server via TCP to negotiate UDP associate
|
||||||
|
dialer := &net.Dialer{Timeout: timeout}
|
||||||
|
tcpConn, err := dialer.DialContext(ctx, "tcp", server.listeningAddress().String())
|
||||||
|
require.NoError(t, err, "tcp connecting to SOCKS5 server")
|
||||||
|
t.Cleanup(func() { tcpConn.Close() })
|
||||||
|
|
||||||
|
negotiateSOCKS5(t, tcpConn, "", "")
|
||||||
|
|
||||||
|
// UDP Associate Command: [VERSION (5), CMD (3 = UDP ASSOC), RSV (0), ATYP (1 = IPv4), ADDR (0.0.0.0), PORT (0)]
|
||||||
|
_, err = tcpConn.Write([]byte{5, 3, 0, 1, 0, 0, 0, 0, 0, 0})
|
||||||
|
require.NoError(t, err, "sending UDP ASSOC request")
|
||||||
|
|
||||||
|
relayAddressString, err := readSOCKS5ResponseAddress(t, tcpConn)
|
||||||
|
require.NoError(t, err, "reading UDP ASSOC reply")
|
||||||
|
relayAddress, err := net.ResolveUDPAddr("udp", relayAddressString)
|
||||||
|
require.NoError(t, err, "resolving udp relay address")
|
||||||
|
|
||||||
|
// Dial the relay using IPv4 so source IP family matches the control connection.
|
||||||
|
udpConn, err := net.DialUDP("udp4", nil, relayAddress)
|
||||||
|
require.NoError(t, err, "dialing UDP relay")
|
||||||
|
t.Cleanup(func() { _ = udpConn.Close() })
|
||||||
|
|
||||||
|
queryID := uint16(rand.Uint32()) //nolint:gosec
|
||||||
|
dnsRequest := &dns.Msg{
|
||||||
|
MsgHdr: dns.MsgHdr{
|
||||||
|
Id: queryID,
|
||||||
|
RecursionDesired: true,
|
||||||
|
},
|
||||||
|
Question: []dns.Question{{
|
||||||
|
Name: dns.Fqdn("github.com"),
|
||||||
|
Qtype: dns.TypeA,
|
||||||
|
Qclass: dns.ClassINET,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
dnsQuery, err := dnsRequest.Pack()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Encapsulate DNS payload into SOCKS5 UDP Request Header
|
||||||
|
// [RSV (0,0), FRAG (0), ATYP (1 = IPv4), DST.ADDR (1.1.1.1), DST.PORT (53)]
|
||||||
|
packet := append([]byte{0, 0, 0, 1, 1, 1, 1, 1, 0, 53}, dnsQuery...)
|
||||||
|
|
||||||
|
// Send encapsulated packet to the proxy's UDP relay address
|
||||||
|
_, err = udpConn.Write(packet)
|
||||||
|
require.NoError(t, err, "sending UDP packet to relay")
|
||||||
|
|
||||||
|
// Read response from the proxy relay
|
||||||
|
err = udpConn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
require.NoError(t, err, "setting read deadline on UDP connection")
|
||||||
|
buffer := make([]byte, 2048)
|
||||||
|
n, err := udpConn.Read(buffer)
|
||||||
|
require.NoError(t, err, "receiving UDP response from relay")
|
||||||
|
const minimumHeaderSize = 10
|
||||||
|
require.GreaterOrEqual(t, n, minimumHeaderSize, "received UDP packet too short to contain valid SOCKS5 header")
|
||||||
|
|
||||||
|
// Verify header layout and slice out the raw DNS response
|
||||||
|
// Header format: RSV(2) FRAG(1) ATYP(1) DST.ADDR(variable) DST.PORT(2)
|
||||||
|
atyp := buffer[3]
|
||||||
|
var headerSize int
|
||||||
|
switch atyp {
|
||||||
|
case 1: // IPv4
|
||||||
|
headerSize = 10
|
||||||
|
case 3: // Domain name
|
||||||
|
headerSize = 4 + 1 + int(buffer[4]) + 2
|
||||||
|
case 4: // IPv6
|
||||||
|
headerSize = 22
|
||||||
|
default:
|
||||||
|
t.Fatalf("Unknown ATYP in SOCKS5 UDP header: %d", atyp)
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsResponse := new(dns.Msg)
|
||||||
|
err = dnsResponse.Unpack(buffer[headerSize:n])
|
||||||
|
require.NoError(t, err, "unpacking DNS response from SOCKS5 UDP packet")
|
||||||
|
|
||||||
|
assert.Equal(t, queryID, dnsResponse.Id, "DNS response ID should match query ID")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-runErr:
|
||||||
|
require.NoError(t, err, "SOCKS5 server run error")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
err = server.Stop()
|
||||||
|
require.NoError(t, err, "stopping SOCKS5 server")
|
||||||
|
}
|
||||||
@@ -76,7 +76,7 @@ func (r *udpRouter) registerAssociation(controlConn net.Conn, expectedAddrPort n
|
|||||||
r.mutex.Lock()
|
r.mutex.Lock()
|
||||||
defer r.mutex.Unlock()
|
defer r.mutex.Unlock()
|
||||||
|
|
||||||
const udpPacketChannelBuffer = 2
|
const udpPacketChannelBuffer = 64
|
||||||
associationID := r.nextAssociationID
|
associationID := r.nextAssociationID
|
||||||
r.nextAssociationID++
|
r.nextAssociationID++
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user