diff --git a/conf.go b/conf.go index baed0a1..5bf9e4b 100644 --- a/conf.go +++ b/conf.go @@ -191,10 +191,9 @@ func usage() { fmt.Fprintf(os.Stderr, " lha: Latency based High Availability mode\n") fmt.Fprintf(os.Stderr, "\n") - fmt.Fprintf(os.Stderr, "Forwarder option scheme: FORWARD_URL[#OPTIONS]\n") - fmt.Fprintf(os.Stderr, " Available options for forwarders:\n") - fmt.Fprintf(os.Stderr, " priority: set the priority of that forwarder, default:0\n") - fmt.Fprintf(os.Stderr, " Examples:\n") + fmt.Fprintf(os.Stderr, "Forwarder option scheme: FORWARD_URL#OPTIONS\n") + fmt.Fprintf(os.Stderr, " priority: set the priority of that forwarder, default:0\n") + fmt.Fprintf(os.Stderr, " e.g.:\n") fmt.Fprintf(os.Stderr, " socks5://1.1.1.1:1080#priority=100\n") fmt.Fprintf(os.Stderr, " vmess://[security:]uuid@host:port?alterID=num#priority=200\n") fmt.Fprintf(os.Stderr, "\n") diff --git a/dns/client.go b/dns/client.go index 690e0bb..81049c6 100644 --- a/dns/client.go +++ b/dns/client.go @@ -129,7 +129,7 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (server // if we are resolving the dialer's domain, then use Direct to avoid denpency loop if strings.Contains(dialer.Addr(), qname) { - dialer = proxy.Direct + dialer = proxy.Default } // If client uses udp and no forwarders specified, use udp diff --git a/proxy/dialer.go b/proxy/dialer.go index 7762b5b..5e665e1 100644 --- a/proxy/dialer.go +++ b/proxy/dialer.go @@ -45,7 +45,7 @@ func DialerFromURL(s string, dialer Dialer) (Dialer, error) { } if dialer == nil { - dialer = Direct + dialer = Default } c, ok := dialerMap[strings.ToLower(u.Scheme)] diff --git a/proxy/direct.go b/proxy/direct.go index 719a731..bf553eb 100644 --- a/proxy/direct.go +++ b/proxy/direct.go @@ -6,20 +6,33 @@ import ( "github.com/nadoo/glider/common/log" ) -// direct proxy -type direct struct{} - // Direct proxy -var Direct = &direct{} +type Direct struct { + *net.Dialer +} -func (d *direct) Addr() string { return "DIRECT" } +// Default dialer +var Default = &Direct{Dialer: &net.Dialer{}} -func (d *direct) Dial(network, addr string) (net.Conn, error) { +// NewDirect returns a Direct dialer +func NewDirect(localip string) *Direct { + d := &net.Dialer{LocalAddr: &net.TCPAddr{ + IP: net.ParseIP(localip), + Port: 0, + }} + return &Direct{Dialer: d} +} + +// Addr returns forwarder's address +func (d *Direct) Addr() string { return "DIRECT" } + +// Dial connects to the address addr on the network net +func (d *Direct) Dial(network, addr string) (net.Conn, error) { if network == "uot" { network = "udp" } - c, err := net.Dial(network, addr) + c, err := d.Dialer.Dial(network, addr) if err != nil { return nil, err } @@ -31,8 +44,9 @@ func (d *direct) Dial(network, addr string) (net.Conn, error) { return c, err } -func (d *direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - pc, err := net.ListenPacket(network, "") +// DialUDP connects to the given address +func (d *Direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { + pc, err := net.ListenPacket(network, d.Dialer.LocalAddr.String()) if err != nil { log.F("ListenPacket error: %s", err) return nil, nil, err @@ -42,4 +56,5 @@ func (d *direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) return pc, uAddr, err } -func (d *direct) NextDialer(dstAddr string) Dialer { return d } +// NextDialer returns the next dialer +func (d *Direct) NextDialer(dstAddr string) Dialer { return d } diff --git a/proxy/forwarder.go b/proxy/forwarder.go index f1e5a82..6249d65 100644 --- a/proxy/forwarder.go +++ b/proxy/forwarder.go @@ -19,12 +19,19 @@ type Forwarder struct { failures uint32 MaxFailures uint32 //maxfailures to set to Disabled latency int64 + localip string // local ip address } // ForwarderFromURL parses `forward=` command value and returns a new forwarder func ForwarderFromURL(s string) (f *Forwarder, err error) { + f = &Forwarder{} + ss := strings.Split(s, "#") - var d Dialer + if len(ss) > 1 { + err = f.parseOption(ss[1]) + } + + var d Dialer = NewDirect(f.localip) for _, url := range strings.Split(ss[0], ",") { d, err = DialerFromURL(url, d) if err != nil { @@ -32,19 +39,12 @@ func ForwarderFromURL(s string) (f *Forwarder, err error) { } } - f = NewForwarder(d) - if len(ss) > 1 { - err = f.parseOption(ss[1]) - } + f.Dialer = d + f.addr = d.Addr() return f, err } -// NewForwarder returns a new forwarder -func NewForwarder(dialer Dialer) *Forwarder { - return &Forwarder{Dialer: dialer, addr: dialer.Addr()} -} - func (f *Forwarder) parseOption(option string) error { query, err := url.ParseQuery(option) if err != nil { @@ -58,6 +58,8 @@ func (f *Forwarder) parseOption(option string) error { } f.Priority = int(priority) + f.localip = query.Get("localip") + return err } diff --git a/proxy/server.go b/proxy/server.go index 4bc4e1d..ad77eef 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -39,7 +39,7 @@ func ServerFromURL(s string, dialer Dialer) (Server, error) { } if dialer == nil { - dialer = Direct + dialer = Default } c, ok := serverMap[strings.ToLower(u.Scheme)] diff --git a/strategy/strategy.go b/strategy/strategy.go index e47611b..73f6451 100644 --- a/strategy/strategy.go +++ b/strategy/strategy.go @@ -38,7 +38,7 @@ func NewDialer(s []string, c *Config) proxy.Dialer { } if len(fwdrs) == 0 { - return proxy.Direct + return proxy.Default } if len(fwdrs) == 1 {