package shadow import ( "fmt" "github.com/refraction-networking/utls" "io" "net" "time" ) 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() { 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 } go handlerClient(conn, c.ServerAddress, c.FakeAddressSNI) } } func handlerClient(conn net.Conn, serverAddress string, fakeAddressSNI string) { config := &tls.Config{ ServerName: fakeAddressSNI, } if HandshakePassword != "" { config.Rand = RandReaderObj } rawConn, err := net.DialTimeout("tcp", serverAddress, time.Second*5) if err != nil { fmt.Printf("[Client] Dial server error: %v\n", err) return } dial := tls.UClient(rawConn, config, tls.HelloChrome_102) err = dial.Handshake() if err != nil { fmt.Printf("[Client] Handshake error: %v\n", err) return } //dial.GetUnderlyingConn().SetDeadline(time.Now()) //dial.GetUnderlyingConn().SetDeadline(time.Time{}) p := &PackAppData{Conn: dial.GetUnderlyingConn()} defer p.Close() defer conn.Close() exitCh := make(chan int, 1) go MyCopy(conn, p, exitCh) go MyCopy(p, conn, exitCh) <-exitCh } func MyCopy(src io.ReadWriteCloser, dst io.ReadWriteCloser, ch chan int) { buf := make([]byte, 32*1024) for { nr, er := src.Read(buf) if er != nil { if er == io.EOF { break } else { fmt.Printf("Read err: %v\n", er) break } } else { nw, ew := dst.Write(buf[0:nr]) if ew != nil { fmt.Printf("Write error:%v\n", ew) break } if nr != nw { fmt.Printf("Write less then buffered \n") break } } } ch <- 1 }