github.com/ipfans/trojan-go@v0.11.0/tunnel/websocket/client.go (about) 1 package websocket 2 3 import ( 4 "context" 5 "strings" 6 7 "golang.org/x/net/websocket" 8 9 "github.com/ipfans/trojan-go/common" 10 "github.com/ipfans/trojan-go/config" 11 "github.com/ipfans/trojan-go/log" 12 "github.com/ipfans/trojan-go/tunnel" 13 ) 14 15 type Client struct { 16 underlay tunnel.Client 17 hostname string 18 path string 19 } 20 21 func (c *Client) DialConn(*tunnel.Address, tunnel.Tunnel) (tunnel.Conn, error) { 22 conn, err := c.underlay.DialConn(nil, &Tunnel{}) 23 if err != nil { 24 return nil, common.NewError("websocket cannot dial with underlying client").Base(err) 25 } 26 url := "wss://" + c.hostname + c.path 27 origin := "https://" + c.hostname 28 wsConfig, err := websocket.NewConfig(url, origin) 29 if err != nil { 30 return nil, common.NewError("invalid websocket config").Base(err) 31 } 32 wsConn, err := websocket.NewClient(wsConfig, conn) 33 if err != nil { 34 return nil, common.NewError("websocket failed to handshake with server").Base(err) 35 } 36 return &OutboundConn{ 37 Conn: wsConn, 38 tcpConn: conn, 39 }, nil 40 } 41 42 func (c *Client) DialPacket(tunnel.Tunnel) (tunnel.PacketConn, error) { 43 return nil, common.NewError("not supported by websocket") 44 } 45 46 func (c *Client) Close() error { 47 return c.underlay.Close() 48 } 49 50 func NewClient(ctx context.Context, underlay tunnel.Client) (*Client, error) { 51 cfg := config.FromContext(ctx, Name).(*Config) 52 if !strings.HasPrefix(cfg.Websocket.Path, "/") { 53 return nil, common.NewError("websocket path must start with \"/\"") 54 } 55 if cfg.Websocket.Host == "" { 56 cfg.Websocket.Host = cfg.RemoteHost 57 log.Warn("empty websocket hostname") 58 } 59 log.Debug("websocket client created") 60 return &Client{ 61 hostname: cfg.Websocket.Host, 62 path: cfg.Websocket.Path, 63 underlay: underlay, 64 }, nil 65 }