init
This commit is contained in:
51
shadow/client.go
Normal file
51
shadow/client.go
Normal file
@ -0,0 +1,51 @@
|
||||
package shadow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
ListenAddress string
|
||||
ServerAddress string
|
||||
FakeAddressSNI string
|
||||
}
|
||||
|
||||
func NewClient(listenAddress string, serverAddress string, fakeAddressSNI string) *Client {
|
||||
client := &Client{
|
||||
ListenAddress: listenAddress,
|
||||
ServerAddress: serverAddress,
|
||||
FakeAddressSNI: fakeAddressSNI,
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *Client) Start() {
|
||||
bridge := NewTLSBridge(c.ServerAddress, c.FakeAddressSNI)
|
||||
|
||||
listen, err := net.Listen("tcp", c.ListenAddress)
|
||||
if err != nil {
|
||||
fmt.Printf("[Client] Start client error: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer listen.Close()
|
||||
fmt.Printf("[Client] Listening at:%v\n", c.ListenAddress)
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
fmt.Printf("[Client] accept error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
stream := bridge.GetStream()
|
||||
if stream == nil {
|
||||
conn.Close()
|
||||
fmt.Printf("[Client] connect to server error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("[Client] New TCP connection: %v <-> %v \n", conn.LocalAddr().String(), conn.RemoteAddr().String())
|
||||
go io.Copy(conn, stream)
|
||||
go io.Copy(stream, conn)
|
||||
}
|
||||
}
|
128
shadow/client_test.go
Normal file
128
shadow/client_test.go
Normal file
@ -0,0 +1,128 @@
|
||||
package shadow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xtaci/smux"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
listen, err := net.Listen("tcp", "0.0.0.0:11222")
|
||||
if err != nil {
|
||||
fmt.Printf("Start server failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
defer listen.Close()
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
fmt.Printf("Accept error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
fmt.Println("A")
|
||||
go handler(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func handler(conn net.Conn) {
|
||||
|
||||
fakeConn, err := net.Dial("tcp", "127.0.0.1:5900")
|
||||
if err != nil {
|
||||
fmt.Printf("Dial fake failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go io.Copy(fakeConn, conn)
|
||||
go io.Copy(conn, fakeConn)
|
||||
}
|
||||
|
||||
func TestSmuxServer(t *testing.T) {
|
||||
listen, err := net.Listen("tcp", "0.0.0.0:7556")
|
||||
if err != nil {
|
||||
fmt.Printf("Start server failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
defer listen.Close()
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
fmt.Printf("Accept error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
session, err := smux.Server(conn, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("smux error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
fmt.Printf("AcceptStream error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
fmt.Println("A")
|
||||
go handlerMuxTest(stream)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSmuxClient(t *testing.T) {
|
||||
listen, err := net.Listen("tcp", "0.0.0.0:11222")
|
||||
if err != nil {
|
||||
fmt.Printf("Start server failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
defer listen.Close()
|
||||
|
||||
smuxConn, err := net.Dial("tcp", "127.0.0.1:7556")
|
||||
if err != nil {
|
||||
fmt.Printf("Start smuxConn failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
session, err := smux.Client(smuxConn, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("Start smux.Client failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
fmt.Printf("Accept error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
fmt.Println("A")
|
||||
|
||||
stream, err := session.OpenStream()
|
||||
if err != nil {
|
||||
fmt.Printf("OpenStream error: %v\n", err)
|
||||
continue
|
||||
|
||||
}
|
||||
go io.Copy(conn, stream)
|
||||
go io.Copy(stream, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func handlerMuxTest(conn *smux.Stream) {
|
||||
|
||||
fakeConn, err := net.Dial("tcp", "127.0.0.1:5900")
|
||||
if err != nil {
|
||||
fmt.Printf("Dial fake failed : %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("UUUUUUUUUUUUUU")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go io.Copy(fakeConn, conn)
|
||||
go io.Copy(conn, fakeConn)
|
||||
}
|
127
shadow/server.go
Normal file
127
shadow/server.go
Normal file
@ -0,0 +1,127 @@
|
||||
package shadow
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xtaci/smux"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
ListenAddress string
|
||||
TargetAddress string
|
||||
FakeAddress string
|
||||
}
|
||||
|
||||
func NewServer(listenAddress string, targetAddress string, fakeAddress string) *Server {
|
||||
server := &Server{
|
||||
ListenAddress: listenAddress,
|
||||
TargetAddress: targetAddress,
|
||||
FakeAddress: fakeAddress,
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
func (s *Server) Start() {
|
||||
listen, err := net.Listen("tcp", s.ListenAddress)
|
||||
if err != nil {
|
||||
fmt.Printf("[Server] Start server error: %v\n", err)
|
||||
return
|
||||
}
|
||||
defer listen.Close()
|
||||
fmt.Printf("[Server] Listening at:%v\n", s.ListenAddress)
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
fmt.Printf("[Server] Accept error: %v\n", err)
|
||||
continue
|
||||
}
|
||||
go handler(conn, s.TargetAddress, s.FakeAddress)
|
||||
}
|
||||
}
|
||||
|
||||
func handler(conn net.Conn, targetAddress string, fakeAddress string) {
|
||||
|
||||
//Process fake TLS handshake
|
||||
fmt.Println("[Server] Perform handshake")
|
||||
fakeConn, err := net.Dial("tcp", fakeAddress)
|
||||
if err != nil {
|
||||
fmt.Printf("[Server] Dial fake error : %v\n", err)
|
||||
return
|
||||
}
|
||||
waitCh := make(chan int, 2)
|
||||
|
||||
go processHandshake(conn, fakeConn, waitCh)
|
||||
go processHandshake(fakeConn, conn, waitCh)
|
||||
|
||||
<-waitCh
|
||||
<-waitCh
|
||||
|
||||
//Process real tcp connection
|
||||
session, err := smux.Server(conn, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("[Server] smux error: %v\n", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
fmt.Printf("[Server] AcceptStream error: %v\n", err)
|
||||
break
|
||||
}
|
||||
go handlerMux(stream, targetAddress)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func processHandshake(src net.Conn, dst net.Conn, waitCh chan int) {
|
||||
buf := make([]byte, 32*1024)
|
||||
for {
|
||||
nr, er := src.Read(buf)
|
||||
if nr > 0 {
|
||||
|
||||
header := ParseAndVerifyTLSHeader(buf[0:nr])
|
||||
nw, ew := dst.Write(buf[0:nr])
|
||||
if header != nil && header.Type == ChangeCipherSpec {
|
||||
fmt.Println("[Server] handshake complete")
|
||||
dst.Close()
|
||||
break
|
||||
}
|
||||
if nw < 0 || nr < nw {
|
||||
nw = 0
|
||||
if ew == nil {
|
||||
//fmt.Printf("ERR1 %v \n", ew)
|
||||
}
|
||||
}
|
||||
if ew != nil {
|
||||
//fmt.Printf("ERR2 %v \n", ew)
|
||||
break
|
||||
}
|
||||
if nr != nw {
|
||||
//fmt.Printf("ERR3 %v \n", "shortwrite")
|
||||
break
|
||||
}
|
||||
}
|
||||
if er != nil {
|
||||
if er != io.EOF {
|
||||
//fmt.Printf("ERR4 %v \n", er)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
waitCh <- 1
|
||||
}
|
||||
|
||||
func handlerMux(conn *smux.Stream, targetAddress string) {
|
||||
|
||||
realConnection, err := net.Dial("tcp", targetAddress)
|
||||
if err != nil {
|
||||
fmt.Printf("[Server] Dial target error : %v\n", err)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go io.Copy(realConnection, conn)
|
||||
go io.Copy(conn, realConnection)
|
||||
}
|
70
shadow/tls_bridge.go
Normal file
70
shadow/tls_bridge.go
Normal file
@ -0,0 +1,70 @@
|
||||
package shadow
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/xtaci/smux"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TLSBridge struct {
|
||||
session *smux.Session
|
||||
locker sync.Mutex
|
||||
serverAddress string
|
||||
fakeAddressSNI string
|
||||
}
|
||||
|
||||
func NewTLSBridge(serverAddress string, fakeAddressSNI string) *TLSBridge {
|
||||
t := &TLSBridge{
|
||||
session: nil,
|
||||
locker: sync.Mutex{},
|
||||
serverAddress: serverAddress,
|
||||
fakeAddressSNI: fakeAddressSNI,
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TLSBridge) dial() error {
|
||||
if t.session != nil {
|
||||
t.session.Close()
|
||||
}
|
||||
dial, err := tls.DialWithDialer(&net.Dialer{
|
||||
Timeout: time.Second * 5,
|
||||
}, "tcp", t.serverAddress, &tls.Config{
|
||||
ServerName: t.fakeAddressSNI,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dial.Handshake()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session, err := smux.Client(dial.NetConn(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.session = session
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TLSBridge) GetStream() *smux.Stream {
|
||||
t.locker.Lock()
|
||||
defer t.locker.Unlock()
|
||||
|
||||
if t.session == nil {
|
||||
err := t.dial()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
openStream, err := t.session.OpenStream()
|
||||
if err != nil {
|
||||
t.session.Close()
|
||||
t.session = nil
|
||||
}
|
||||
return openStream
|
||||
|
||||
}
|
87
shadow/tls_util.go
Normal file
87
shadow/tls_util.go
Normal file
@ -0,0 +1,87 @@
|
||||
package shadow
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
RecordHeaderLen = 5
|
||||
|
||||
ChangeCipherSpec = 0x14
|
||||
EncryptedAlert = 0x15
|
||||
Handshake = 0x16
|
||||
AppData = 0x17
|
||||
|
||||
VersionTLS10 = 0x0301
|
||||
VersionTLS11 = 0x0302
|
||||
VersionTLS12 = 0x0303
|
||||
VersionTLS13 = 0x0304
|
||||
|
||||
ServerHello = 2
|
||||
ClientHello = 1
|
||||
)
|
||||
|
||||
type TLSHeader struct {
|
||||
Type uint8
|
||||
Version uint16
|
||||
Length int
|
||||
HandshakeType uint8
|
||||
}
|
||||
|
||||
func (t *TLSHeader) toString() string {
|
||||
if t == nil {
|
||||
return "nul"
|
||||
}
|
||||
desc := ""
|
||||
switch t.Type {
|
||||
case Handshake:
|
||||
desc += "Type=handshake;"
|
||||
switch t.HandshakeType {
|
||||
case ClientHello:
|
||||
desc += "HandshakeType=ClientHello;"
|
||||
break
|
||||
case ServerHello:
|
||||
desc += "HandshakeType=ServerHello;"
|
||||
break
|
||||
}
|
||||
break
|
||||
case ChangeCipherSpec:
|
||||
desc += "Type=ChangeCipherSpec;"
|
||||
break
|
||||
case EncryptedAlert:
|
||||
desc += "Type=EncryptedAlert;"
|
||||
break
|
||||
case AppData:
|
||||
desc += "Type=AppData;"
|
||||
break
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
func ParseAndVerifyTLSHeader(data []byte) *TLSHeader {
|
||||
if len(data) < RecordHeaderLen {
|
||||
return nil
|
||||
}
|
||||
header := &TLSHeader{
|
||||
Type: data[0],
|
||||
Version: binary.BigEndian.Uint16(data[1:3]),
|
||||
Length: int(binary.BigEndian.Uint16(data[3:5])),
|
||||
}
|
||||
//Check type
|
||||
if header.Type != Handshake && header.Type != AppData && header.Type != EncryptedAlert && header.Type != ChangeCipherSpec {
|
||||
return nil
|
||||
}
|
||||
//Check version
|
||||
if header.Version != VersionTLS10 && header.Version != VersionTLS11 && header.Version != VersionTLS12 && header.Version != VersionTLS13 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if header.Type == Handshake {
|
||||
header.HandshakeType = data[5]
|
||||
//Check Handshake type
|
||||
if header.HandshakeType != ServerHello && header.HandshakeType != ClientHello {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return header
|
||||
}
|
Reference in New Issue
Block a user