Skip to content

Commit

Permalink
feat: circuit knots, socks5 ssh and raw forward
Browse files Browse the repository at this point in the history
  • Loading branch information
shoriwe committed May 31, 2023
1 parent 5deda30 commit 28d4c17
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 0 deletions.
15 changes: 15 additions & 0 deletions circuit/dialer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package circuit

import (
"net"

"github.com/shoriwe/fullproxy/v3/utils/network"
)

type Dialer struct {
DialFunc network.DialFunc
}

func (d *Dialer) Dial(network, address string) (net.Conn, error) {
return d.DialFunc(network, address)
}
14 changes: 14 additions & 0 deletions circuit/dialer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package circuit

import (
"net"
"testing"

"github.com/stretchr/testify/assert"
)

func TestDialer_Dial(t *testing.T) {
d := &Dialer{DialFunc: net.Dial}
_, err := d.Dial("tcp", "1111111111111111111111")
assert.NotNil(t, err)
}
25 changes: 25 additions & 0 deletions circuit/forward.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package circuit

import (
"net"

"github.com/shoriwe/fullproxy/v3/utils/network"
)

type Forward struct {
Network string
Address string
}

func (f *Forward) Next(dial network.DialFunc) (closeFunc network.CloseFunc, newDial network.DialFunc, err error) {
closeFunc = network.NopClose
newDial = func(n, a string) (net.Conn, error) {
return dial(f.Network, f.Address)
}
return closeFunc, newDial, err
}

// newForward ensures compile time safety, should never be used
func newForward() Knot {
return &Forward{}
}
27 changes: 27 additions & 0 deletions circuit/forward_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package circuit

import (
"net"
"net/http"
"testing"

"github.com/stretchr/testify/assert"
)

func TestForward_Next(t *testing.T) {
t.Run("Basic", func(tt *testing.T) {
s := &Forward{
Network: "tcp",
Address: "127.0.0.1:8000",
}
closeFunc, dial, err := s.Next(net.Dial)
assert.Nil(tt, err)
defer closeFunc()
expect := newExpect(tt, "http://127.0.0.1:8000", dial)
expect.GET("/").Expect().Status(http.StatusOK).Body().Contains("ECHO")
})
}

func Test_newForward(t *testing.T) {
assert.NotNil(t, newForward())
}
9 changes: 9 additions & 0 deletions circuit/knot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package circuit

import (
"github.com/shoriwe/fullproxy/v3/utils/network"
)

type Knot interface {
Next(dial network.DialFunc) (network.CloseFunc, network.DialFunc, error)
}
27 changes: 27 additions & 0 deletions circuit/socks5.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package circuit

import (
"github.com/shoriwe/fullproxy/v3/utils/network"
"golang.org/x/net/proxy"
)

type Socks5 struct {
Network string
Address string
Auth *proxy.Auth
}

func (s *Socks5) Next(dial network.DialFunc) (closeFunc network.CloseFunc, newDial network.DialFunc, err error) {
var dialer proxy.Dialer
dialer, err = proxy.SOCKS5(s.Network, s.Address, s.Auth, &Dialer{DialFunc: dial})
if err == nil {
closeFunc = network.NopClose
newDial = dialer.Dial
}
return closeFunc, newDial, err
}

// newSocks5 ensures compile time safety, should never be used
func newSocks5() Knot {
return &Socks5{}
}
37 changes: 37 additions & 0 deletions circuit/socks5_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package circuit

import (
"net"
"net/http"
"testing"

"github.com/shoriwe/fullproxy/v3/proxies"
"github.com/shoriwe/fullproxy/v3/utils/network"
"github.com/stretchr/testify/assert"
)

func TestSocks5_Next(t *testing.T) {
listener := network.ListenAny()
defer listener.Close()
socks := proxies.Socks5{
Listener: listener,
Dial: net.Dial,
}
defer socks.Close()
go socks.Serve()
t.Run("Basic", func(tt *testing.T) {
s := &Socks5{
Network: listener.Addr().Network(),
Address: listener.Addr().String(),
}
closeFunc, dial, err := s.Next(net.Dial)
assert.Nil(tt, err)
defer closeFunc()
expect := newExpect(tt, "http://127.0.0.1:8000", dial)
expect.GET("/").Expect().Status(http.StatusOK).Body().Contains("ECHO")
})
}

func Test_newSocks5(t *testing.T) {
assert.NotNil(t, newSocks5())
}
44 changes: 44 additions & 0 deletions circuit/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package circuit

import (
"net"

"github.com/shoriwe/fullproxy/v3/sshd"
"github.com/shoriwe/fullproxy/v3/utils/network"
"golang.org/x/crypto/ssh"
)

type SSH struct {
Network string
Address string
Config ssh.ClientConfig
}

func (s *SSH) Next(dial network.DialFunc) (closeFunc network.CloseFunc, newDial network.DialFunc, err error) {
var (
conn net.Conn
sshConn ssh.Conn
newChannel <-chan ssh.NewChannel
requests <-chan *ssh.Request
client *ssh.Client
)
conn, err = dial(s.Network, s.Address)
if err == nil {
defer network.CloseOnError(&err, conn)
sshConn, newChannel, requests, err = ssh.NewClientConn(conn, "", &s.Config)
if err == nil {
go sshd.KeepAlive(client)
closeFunc = func() error {
return conn.Close()
}
client = ssh.NewClient(sshConn, newChannel, requests)
newDial = client.Dial
}
}
return closeFunc, newDial, err
}

// newSSH ensures compile time safety, should never be used
func newSSH() Knot {
return &SSH{}
}
29 changes: 29 additions & 0 deletions circuit/ssh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package circuit

import (
"net"
"net/http"
"testing"

"github.com/shoriwe/fullproxy/v3/sshd"
"github.com/stretchr/testify/assert"
)

func TestSSH_Next(t *testing.T) {
t.Run("Basic", func(tt *testing.T) {
s := &SSH{
Network: "tcp",
Address: "127.0.0.1:2222",
Config: *sshd.DefaultClientConfig(),
}
closeFunc, dial, err := s.Next(net.Dial)
assert.Nil(tt, err)
defer closeFunc()
expect := newExpect(tt, "http://echo:80", dial)
expect.GET("/").Expect().Status(http.StatusOK).Body().Contains("ECHO")
})
}

func TestSSH_newSSH(t *testing.T) {
assert.NotNil(t, newSSH())
}
25 changes: 25 additions & 0 deletions circuit/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package circuit

import (
"context"
"net"
"net/http"
"testing"

"github.com/gavv/httpexpect/v2"
"github.com/shoriwe/fullproxy/v3/utils/network"
)

func newExpect(t *testing.T, baseUrl string, dial network.DialFunc) *httpexpect.Expect {
return httpexpect.WithConfig(httpexpect.Config{
BaseURL: baseUrl,
Reporter: httpexpect.NewAssertReporter(t),
Client: &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dial(network, addr)
},
},
},
})
}

0 comments on commit 28d4c17

Please sign in to comment.