mirror of
https://github.com/netbirdio/ice.git
synced 2026-05-22 17:10:58 -07:00
Add proxy dialer interface
Enable user to implement the golang.org/x/net/proxy dialer interface in order to have a customized dialer. The customized dialer could be one that connect through a corporate HTTP/HTTPS proxy. Resolves #284
This commit is contained in:
@@ -59,6 +59,7 @@ Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contribu
|
||||
* [JooYoung Lim](https://github.com/DevRockstarZ)
|
||||
* [Kory Miller](https://github.com/korymiller1489)
|
||||
* [ZHENK](https://github.com/scorpionknifes)
|
||||
* [Assad Obaid](https://github.com/assadobaid)
|
||||
|
||||
### License
|
||||
MIT License - see [LICENSE](LICENSE) for full text
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/pion/stun"
|
||||
"github.com/pion/transport/packetio"
|
||||
"github.com/pion/transport/vnet"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
type bindingRequest struct {
|
||||
@@ -126,6 +127,8 @@ type Agent struct {
|
||||
interfaceFilter func(string) bool
|
||||
|
||||
insecureSkipVerify bool
|
||||
|
||||
proxyDialer proxy.Dialer
|
||||
}
|
||||
|
||||
type task struct {
|
||||
@@ -292,6 +295,7 @@ func NewAgent(config *AgentConfig) (*Agent, error) { //nolint:gocognit
|
||||
loggerFactory: loggerFactory,
|
||||
log: log,
|
||||
net: config.Net,
|
||||
proxyDialer: config.ProxyDialer,
|
||||
|
||||
mDNSMode: mDNSMode,
|
||||
mDNSName: mDNSName,
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/pion/logging"
|
||||
"github.com/pion/transport/vnet"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -143,6 +144,10 @@ type AgentConfig struct {
|
||||
// Currently only passive candidates are supported. This functionality is
|
||||
// experimental and the API might change in the future.
|
||||
TCPMux TCPMux
|
||||
|
||||
// Proxy Dialer is a dialer that should be implemented by the user based on golang.org/x/net/proxy
|
||||
// dial interface in order to support corporate proxies
|
||||
ProxyDialer proxy.Dialer
|
||||
}
|
||||
|
||||
// initWithDefaults populates an agent and falls back to defaults if fields are unset
|
||||
|
||||
+1
-2
@@ -19,8 +19,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type mockPacketConn struct {
|
||||
}
|
||||
type mockPacketConn struct{}
|
||||
|
||||
func (m *mockPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { return 0, nil, nil }
|
||||
func (m *mockPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { return 0, nil }
|
||||
|
||||
@@ -369,6 +369,18 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
|
||||
|
||||
RelAddr = locConn.LocalAddr().(*net.UDPAddr).IP.String()
|
||||
RelPort = locConn.LocalAddr().(*net.UDPAddr).Port
|
||||
case a.proxyDialer != nil && url.Proto == ProtoTypeTCP &&
|
||||
(url.Scheme == SchemeTypeTURN || url.Scheme == SchemeTypeTURNS):
|
||||
conn, connectErr := a.proxyDialer.Dial(NetworkTypeTCP4.String(), TURNServerAddr)
|
||||
if connectErr != nil {
|
||||
a.log.Warnf("Failed to Dial TCP Addr %s via proxy dialer: %v\n", TURNServerAddr, connectErr)
|
||||
return
|
||||
}
|
||||
|
||||
RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String()
|
||||
RelPort = conn.LocalAddr().(*net.TCPAddr).Port
|
||||
locConn = turn.NewSTUNConn(conn)
|
||||
|
||||
case url.Proto == ProtoTypeTCP && url.Scheme == SchemeTypeTURN:
|
||||
tcpAddr, connectErr := net.ResolveTCPAddr(NetworkTypeTCP4.String(), TURNServerAddr)
|
||||
if connectErr != nil {
|
||||
|
||||
+73
-1
@@ -5,7 +5,9 @@ package ice
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -19,6 +21,7 @@ import (
|
||||
"github.com/pion/turn/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
func TestListenUDP(t *testing.T) {
|
||||
@@ -197,7 +200,7 @@ func TestTURNConcurrency(t *testing.T) {
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
Proto: protocol,
|
||||
Port: serverPort + 1,
|
||||
Port: serverPort + 1 + i,
|
||||
})
|
||||
}
|
||||
urls = append(urls, &URL{
|
||||
@@ -412,3 +415,72 @@ func TestCloseConnLog(t *testing.T) {
|
||||
|
||||
assert.NoError(t, a.Close())
|
||||
}
|
||||
|
||||
type mockProxy struct {
|
||||
proxyWasDialed func()
|
||||
}
|
||||
|
||||
type mockConn struct{}
|
||||
|
||||
func (m *mockConn) Read(b []byte) (n int, err error) { return 0, io.EOF }
|
||||
func (m *mockConn) Write(b []byte) (int, error) { return 0, io.EOF }
|
||||
func (m *mockConn) Close() error { return io.EOF }
|
||||
func (m *mockConn) LocalAddr() net.Addr { return &net.TCPAddr{} }
|
||||
func (m *mockConn) RemoteAddr() net.Addr { return &net.TCPAddr{} }
|
||||
func (m *mockConn) SetDeadline(t time.Time) error { return io.EOF }
|
||||
func (m *mockConn) SetReadDeadline(t time.Time) error { return io.EOF }
|
||||
func (m *mockConn) SetWriteDeadline(t time.Time) error { return io.EOF }
|
||||
|
||||
func (m *mockProxy) Dial(network, addr string) (net.Conn, error) {
|
||||
m.proxyWasDialed()
|
||||
return &mockConn{}, nil
|
||||
}
|
||||
|
||||
func TestTURNProxyDialer(t *testing.T) {
|
||||
report := test.CheckRoutines(t)
|
||||
defer report()
|
||||
|
||||
lim := test.TimeOut(time.Second * 30)
|
||||
defer lim.Stop()
|
||||
|
||||
proxyWasDialed, proxyWasDialedFunc := context.WithCancel(context.Background())
|
||||
proxy.RegisterDialerType("tcp", func(*url.URL, proxy.Dialer) (proxy.Dialer, error) {
|
||||
return &mockProxy{proxyWasDialedFunc}, nil
|
||||
})
|
||||
|
||||
tcpProxyURI, err := url.Parse("tcp://fakeproxy:3128")
|
||||
assert.NoError(t, err)
|
||||
|
||||
proxyDialer, err := proxy.FromURL(tcpProxyURI, proxy.Direct)
|
||||
assert.NoError(t, err)
|
||||
|
||||
a, err := NewAgent(&AgentConfig{
|
||||
CandidateTypes: []CandidateType{CandidateTypeRelay},
|
||||
NetworkTypes: supportedNetworkTypes(),
|
||||
Urls: []*URL{
|
||||
{
|
||||
Scheme: SchemeTypeTURN,
|
||||
Host: "127.0.0.1",
|
||||
Username: "username",
|
||||
Password: "password",
|
||||
Proto: ProtoTypeTCP,
|
||||
Port: 5000,
|
||||
},
|
||||
},
|
||||
ProxyDialer: proxyDialer,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
candidateGatherFinish, candidateGatherFinishFunc := context.WithCancel(context.Background())
|
||||
assert.NoError(t, a.OnCandidate(func(c Candidate) {
|
||||
if c == nil {
|
||||
candidateGatherFinishFunc()
|
||||
}
|
||||
}))
|
||||
|
||||
assert.NoError(t, a.GatherCandidates())
|
||||
<-candidateGatherFinish.Done()
|
||||
<-proxyWasDialed.Done()
|
||||
|
||||
assert.NoError(t, a.Close())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user