diff --git a/client.go b/client.go index d34ddb7..03ea503 100644 --- a/client.go +++ b/client.go @@ -93,6 +93,18 @@ func (tr *tcpTransporter) Multiplex() bool { type DialOptions struct { Timeout time.Duration Chain *Chain + IPs []string + // count uint32 +} + +func (o *DialOptions) getIP() string { + n := len(o.IPs) + if n == 0 { + return "" + } + return o.IPs[int(time.Now().Nanosecond())%n] + // count := atomic.AddUint32(&o.count, 1) + //return o.IPs[int(count)%n] } // DialOption allows a common way to set dial options. @@ -110,6 +122,12 @@ func ChainDialOption(chain *Chain) DialOption { } } +func IPDialOption(ips ...string) DialOption { + return func(opts *DialOptions) { + opts.IPs = ips + } +} + // HandshakeOptions describes the options for handshake. type HandshakeOptions struct { Addr string diff --git a/cmd/gost/main.go b/cmd/gost/main.go index cb32082..38eb325 100644 --- a/cmd/gost/main.go +++ b/cmd/gost/main.go @@ -112,6 +112,11 @@ func initChain() (*gost.Chain, error) { wsOpts.UserAgent = node.Values.Get("agent") tr = gost.WSTransporter(wsOpts) case "wss": + ips := strings.Split(node.Values.Get("ip"), ",") + node.DialOptions = append(node.DialOptions, + gost.IPDialOption(ips...), + ) + wsOpts := &gost.WSOptions{} wsOpts.EnableCompression = toBool(node.Values.Get("compression")) wsOpts.ReadBufferSize, _ = strconv.Atoi(node.Values.Get("rbuf")) diff --git a/ws.go b/ws.go index 69be7dc..fda58a7 100644 --- a/ws.go +++ b/ws.go @@ -139,6 +139,24 @@ func WSSTransporter(opts *WSOptions) Transporter { } } +func (tr *wssTransporter) Dial(addr string, options ...DialOption) (net.Conn, error) { + opts := &DialOptions{} + for _, option := range options { + option(opts) + } + if ip := opts.getIP(); ip != "" { + _, sport, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + addr = ip + ":" + sport + } + if opts.Chain == nil { + return net.DialTimeout("tcp", addr, opts.Timeout) + } + return opts.Chain.Dial(addr) +} + func (tr *wssTransporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) { opts := &HandshakeOptions{} for _, option := range options {