mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-09 20:29:23 +02:00
feat(protonvpn): port forwarding support with NAT-PMP (#1543)
Co-authored-by: Nicholas Xavier <nicho@nicho.dev>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
package natpmp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type udpExchange struct {
|
||||
request []byte
|
||||
response []byte
|
||||
close bool // to trigger a client error
|
||||
}
|
||||
|
||||
// launchUDPServer launches an UDP server which will expect
|
||||
// the requests precised in each of the given exchanges,
|
||||
// and respond the given corresponding response.
|
||||
// The server shuts down gracefully at the end of the test.
|
||||
// The remote address (127.0.0.1:port) is returned, where
|
||||
// port is dynamically assigned by the OS so calling tests
|
||||
// can run in parallel.
|
||||
func launchUDPServer(t *testing.T, exchanges []udpExchange) (
|
||||
remoteAddress *net.UDPAddr) {
|
||||
t.Helper()
|
||||
|
||||
conn, err := net.ListenUDP("udp", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
listeningAddress, ok := conn.LocalAddr().(*net.UDPAddr)
|
||||
require.True(t, ok, "listening address is not UDP")
|
||||
remoteAddress = &net.UDPAddr{
|
||||
IP: net.IPv4(127, 0, 0, 1),
|
||||
Port: listeningAddress.Port,
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
t.Cleanup(func() {
|
||||
err := conn.Close()
|
||||
if !errors.Is(err, net.ErrClosed) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
<-done
|
||||
})
|
||||
|
||||
var maxBufferSize int
|
||||
for _, exchange := range exchanges {
|
||||
if len(exchange.request) > maxBufferSize {
|
||||
maxBufferSize = len(exchange.request)
|
||||
}
|
||||
}
|
||||
|
||||
buffer := make([]byte, maxBufferSize)
|
||||
|
||||
ready := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
close(ready)
|
||||
for _, exchange := range exchanges {
|
||||
n, clientAddress, err := conn.ReadFromUDP(buffer)
|
||||
if errors.Is(err, net.ErrClosed) {
|
||||
t.Error("at least one exchange is missing")
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, len(exchange.request), n,
|
||||
"request message size is unexpected")
|
||||
if n > 0 {
|
||||
assert.Equal(t, exchange.request, buffer[:n],
|
||||
"request message is unexpected")
|
||||
}
|
||||
|
||||
if exchange.close {
|
||||
err = conn.Close()
|
||||
if !errors.Is(err, net.ErrClosed) {
|
||||
// connection might be already closed by client production code
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_, err = conn.WriteToUDP(exchange.response, clientAddress)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
err := conn.Close()
|
||||
if !errors.Is(err, net.ErrClosed) {
|
||||
// The connection closing can be raced by the test
|
||||
// cleanup function defined above.
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}()
|
||||
<-ready
|
||||
|
||||
return remoteAddress
|
||||
}
|
||||
Reference in New Issue
Block a user