diff --git a/README.md b/README.md index 7d9b844..6a31388 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ we can set up local listeners as proxy servers, and forward requests to internet ## Features - Act as both proxy client and proxy server - Flexible proxy & protocol chains -- Multiple forwarders support with the following scheduling algorithm: +- Load balancing with the following scheduling algorithm: - rr: round robin - ha: high availability - lha: latency based high availability @@ -73,7 +73,6 @@ sudo pacman -S glider ## Usage -help: ```bash glider -h ``` @@ -347,7 +346,7 @@ forward=tls://1.1.1.1:443,ws://,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?al - Chain protocols and servers: ``` bash -forward=socks5://1.1.1.1:1080,tls://2.2.2.2:443,ws://,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?alterID=2 +forward=socks5://1.1.1.1:1080,tls://2.2.2.2:443,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?alterID=2 ``` - Chain protocols in listener: https proxy server diff --git a/dns/client.go b/dns/client.go index 18a738d..0ef42c1 100644 --- a/dns/client.go +++ b/dns/client.go @@ -89,8 +89,22 @@ func (c *Client) Exchange(reqBytes []byte, clientAddr string, preferTCP bool) ([ return respBytes, err } + ips, ttl := c.extractAnswer(resp) + + // add to cache only when there's a valid ip address + if len(ips) != 0 && ttl > 0 { + c.cache.Put(getKey(resp.Question), respBytes, ttl) + } + + log.F("[dns] %s <-> %s(%s) via %s, type: %d, %s: %s", + clientAddr, dnsServer, network, dialerAddr, resp.Question.QTYPE, resp.Question.QNAME, strings.Join(ips, ",")) + + return respBytes, nil +} + +func (c *Client) extractAnswer(resp *Message) ([]string, int) { + var ips []string ttl := c.config.MinTTL - ips := []string{} for _, answer := range resp.Answers { if answer.TYPE == QTypeA || answer.TYPE == QTypeAAAA { for _, h := range c.handlers { @@ -111,15 +125,7 @@ func (c *Client) Exchange(reqBytes []byte, clientAddr string, preferTCP bool) ([ ttl = c.config.MinTTL } - // add to cache only when there's a valid ip address - if len(ips) != 0 && ttl > 0 { - c.cache.Put(getKey(resp.Question), respBytes, ttl) - } - - log.F("[dns] %s <-> %s(%s) via %s, type: %d, %s: %s", - clientAddr, dnsServer, network, dialerAddr, resp.Question.QTYPE, resp.Question.QNAME, strings.Join(ips, ",")) - - return respBytes, nil + return ips, ttl } // exchange choose a upstream dns server based on qname, communicate with it on the network. diff --git a/dns/server.go b/dns/server.go index d46dc58..acec2fc 100644 --- a/dns/server.go +++ b/dns/server.go @@ -24,12 +24,15 @@ type Server struct { // NewServer returns a new dns server. func NewServer(addr string, p proxy.Proxy, config *Config) (*Server, error) { c, err := NewClient(p, config) + if err != nil { + return nil, err + } + s := &Server{ addr: addr, Client: c, } - - return s, err + return s, nil } // Start starts the dns forwarding server. diff --git a/proxy/trojan/packet.go b/proxy/trojan/packet.go index db57018..7485e67 100644 --- a/proxy/trojan/packet.go +++ b/proxy/trojan/packet.go @@ -1,10 +1,3 @@ -// https://trojan-gfw.github.io/trojan/protocol -// If the connection is a UDP ASSOCIATE, then each UDP packet has the following format: -// +------+----------+----------+--------+---------+----------+ -// | ATYP | DST.ADDR | DST.PORT | Length | CRLF | Payload | -// +------+----------+----------+--------+---------+----------+ -// | 1 | Variable | 2 | 2 | X'0D0A' | Variable | -// +------+----------+----------+--------+---------+----------+ package trojan import ( @@ -25,6 +18,7 @@ type PktConn struct { tgtAddr socks.Addr } +// NewPktConn returns a PktConn. func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn { pc := &PktConn{ Conn: c, @@ -33,6 +27,7 @@ func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn { return pc } +// ReadFrom implements the necessary function of net.PacketConn. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { // ATYP, DST.ADDR, DST.PORT _, err := socks.ReadAddr(pc.Conn) @@ -65,6 +60,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { return n, nil, err } +// ReadFrom implements the necessary function of net.PacketConn. func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { var buf bytes.Buffer buf.Write(pc.tgtAddr) diff --git a/proxy/trojan/trojan.go b/proxy/trojan/trojan.go index b54fe9f..3849ee7 100644 --- a/proxy/trojan/trojan.go +++ b/proxy/trojan/trojan.go @@ -1,29 +1,5 @@ // protocol spec: // https://trojan-gfw.github.io/trojan/protocol -// +-----------------------+---------+----------------+---------+----------+ -// | hex(SHA224(password)) | CRLF | Trojan Request | CRLF | Payload | -// +-----------------------+---------+----------------+---------+----------+ -// | 56 | X'0D0A' | Variable | X'0D0A' | Variable | -// +-----------------------+---------+----------------+---------+----------+ - -// where Trojan Request is a SOCKS5-like request: - -// +-----+------+----------+----------+ -// | CMD | ATYP | DST.ADDR | DST.PORT | -// +-----+------+----------+----------+ -// | 1 | 1 | Variable | 2 | -// +-----+------+----------+----------+ - -// where: -// o CMD -// o CONNECT X'01' -// o UDP ASSOCIATE X'03' -// o ATYP address type of following address -// o IP V4 address: X'01' -// o DOMAINNAME: X'03' -// o IP V6 address: X'04' -// o DST.ADDR desired destination address -// o DST.PORT desired destination port in network octet order package trojan @@ -91,7 +67,7 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) { t.tlsConfig = &tls.Config{ ServerName: t.serverName, InsecureSkipVerify: t.skipVerify, - NextProtos: []string{"http/1.1"}, + NextProtos: []string{"http/1.1", "h2"}, ClientSessionCache: tls.NewLRUClientSessionCache(64), MinVersion: tls.VersionTLS10, }