Skip to content

Commit

Permalink
feat: circuit support
Browse files Browse the repository at this point in the history
  • Loading branch information
shoriwe committed May 31, 2023
1 parent e4e1ba5 commit 34954aa
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
97 changes: 97 additions & 0 deletions circuit/circuit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package circuit

import (
"net"

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

/*
Circuit are reduced to forwarding a end of chain service over multiple proxies
For example:
## The user knows these proxy servers
- Server 1: SOCKS-5
- Server 2: Forward
- Server 3: HTTP
- Server 4: Forward
- Server 5: SSH
- Server 6: SOCKS-5
- Service
## The user then design a circuit to connect to a service that is only accesible by "Server 6"
Client -> Server 1 -> Server 2 -> Server 3 -> Server 4 -> Server 5 -> Server 6 -> Service
# This way the user end Pivoting over the entire proxy chain to finally arrive it's requested service
## Server accesibility
# To allow Randomness and unpredictibility in the proxy chain outgoing connections, it is also possible to set Server accesibility
# Using the previus chain, but adding accesible annotation
- Server 1: SOCKS-5
-- accessible:
--- Server 3
--- Server 5
--- Server 6
- Server 2: Forward
- Server 3: HTTP
-- accessible:
--- Server 1
--- Server 5
--- Server 6
- Server 4: Forward
- Server 5: SSH
-- accessible:
--- Server 1
--- Server 3
--- Server 6
- Server 6: SOCKS-5
-- accessible:
--- Server 1
--- Server 5
- Service
-- accessible:
--- Server 1
--- Server 3
--- Server 5
--- Server 6
# Now the chain will be reconstructed every accepted connection, ensuring randomness in the knots
# First connection
Client -> Server 1 -> Server 2 -> Server 3 -> Server 4 -> Server 5 -> Server 6 -> Service
# Second connection
Client -> Server 3 -> Server 1 -> Server 4 -> Server 6 -> Server 2 -> Server 5 -> Service
*/
type Circuit struct {
Chain []Knot
}

func (c *Circuit) Dial(n, addr string) (net.Conn, error) {
var (
result = &Conn{
CloseFunctions: make([]network.CloseFunc, 0, len(c.Chain)),
}
closeFunc network.CloseFunc
dial network.DialFunc = net.Dial
err error
)
defer network.CloseOnError(&err, result)
for _, knot := range c.Chain {
closeFunc, dial, err = knot.Next(dial)
if err != nil {
return nil, err
}
result.CloseFunctions = append(result.CloseFunctions, closeFunc)
}
result.Conn, err = dial(n, addr)
return result, err
}
54 changes: 54 additions & 0 deletions circuit/circuit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package circuit

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

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

func TestCircuit_Dial(t *testing.T) {
// Prepare Socks5
listener := network.ListenAny()
defer listener.Close()
socks := proxies.Socks5{
Listener: listener,
Dial: net.Dial,
}
defer socks.Close()
go socks.Serve()
// Prepare chain
chain := []Knot{
&Socks5{
Network: listener.Addr().Network(),
Address: listener.Addr().String(),
},
&SSH{
Network: "tcp",
Address: "127.0.0.1:2222",
Config: *sshd.DefaultClientConfig(),
},
}
// Run Tests
t.Run("Basic", func(tt *testing.T) {
circuit := &Circuit{
Chain: chain,
}
expect := newExpect(tt, "http://echo:80", circuit.Dial)
expect.GET("/").Expect().Status(http.StatusOK).Body().Contains("ECHO")
})
t.Run("Invalid Knot", func(tt *testing.T) {
circuit := &Circuit{
Chain: []Knot{&SSH{
Network: "tcp",
Address: "127.0.0.1:2222",
}},
}
_, err := circuit.Dial("tcp", "echo:80")
assert.NotNil(tt, err)
})
}

0 comments on commit 34954aa

Please sign in to comment.