mirror of
				https://github.com/nadoo/glider.git
				synced 2025-11-04 07:42:38 +08:00 
			
		
		
		
	proxy: support server mode of PROXY protocol v1
This commit is contained in:
		
							parent
							
								
									32e1c37cfe
								
							
						
					
					
						commit
						7486373821
					
				@ -65,7 +65,8 @@ we can set up local listeners as proxy servers, and forward requests to internet
 | 
			
		||||
|Unix         |√|√|√|√|transport client & server
 | 
			
		||||
|Smux         |√| |√| |transport client & server
 | 
			
		||||
|Websocket(WS)|√| |√| |transport client & server
 | 
			
		||||
|WS Secure    |√| |√| |transport client & server
 | 
			
		||||
|WS Secure    |√| |√| |websocket secure (wss)
 | 
			
		||||
|Proxy Proto  |√| |√| |transport client & server
 | 
			
		||||
|Simple-Obfs  | | |√| |transport client only
 | 
			
		||||
|Redir        |√| | | |linux redirect proxy
 | 
			
		||||
|Redir6       |√| | | |linux redirect proxy(ipv6)
 | 
			
		||||
@ -182,8 +183,8 @@ glider -verbose -listen :8443 -forward SCHEME://HOST:PORT
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
Available schemes:
 | 
			
		||||
  listen: mixed ss socks5 http vless trojan trojanc redir redir6 tproxy tcp udp tls ws wss unix smux kcp
 | 
			
		||||
  forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws wss unix smux kcp simple-obfs
 | 
			
		||||
  listen: mixed ss socks5 http vless trojan trojanc redir redir6 tproxy tcp udp tls ws wss unix smux kcp pxyproto
 | 
			
		||||
  forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws wss unix smux kcp simple-obfs pxyproto
 | 
			
		||||
 | 
			
		||||
Socks5 scheme:
 | 
			
		||||
  socks://[user:pass@]host:port
 | 
			
		||||
@ -397,7 +398,7 @@ Examples:
 | 
			
		||||
  // _ "github.com/nadoo/glider/proxy/kcp"
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
3. Build it(requires **Go 1.16+** )
 | 
			
		||||
3. Build it(requires **Go 1.17+** )
 | 
			
		||||
  ```bash
 | 
			
		||||
  go build -v -ldflags "-s -w"
 | 
			
		||||
  ```
 | 
			
		||||
 | 
			
		||||
@ -150,8 +150,8 @@ func usage() {
 | 
			
		||||
	fmt.Fprintf(w, "\n")
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(w, "Available schemes:\n")
 | 
			
		||||
	fmt.Fprintf(w, "  listen: mixed ss socks5 http vless trojan trojanc redir redir6 tproxy tcp udp tls ws wss unix smux kcp\n")
 | 
			
		||||
	fmt.Fprintf(w, "  forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws wss unix smux kcp simple-obfs\n")
 | 
			
		||||
	fmt.Fprintf(w, "  listen: mixed ss socks5 http vless trojan trojanc redir redir6 tproxy tcp udp tls ws wss unix smux kcp pxyproto\n")
 | 
			
		||||
	fmt.Fprintf(w, "  forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws wss unix smux kcp simple-obfs pxyproto\n")
 | 
			
		||||
	fmt.Fprintf(w, "\n")
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(w, "Socks5 scheme:\n")
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// UDPMaxLen is the max size of udp dns request.
 | 
			
		||||
// https://tools.ietf.org/html/rfc1035#section-4.2.1
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1035#section-4.2.1
 | 
			
		||||
// Messages carried by UDP are restricted to 512 bytes (not counting the IP
 | 
			
		||||
// or UDP headers).  Longer messages are truncated and the TC bit is set in
 | 
			
		||||
// the header.
 | 
			
		||||
@ -36,7 +36,7 @@ const (
 | 
			
		||||
const ClassINET uint16 = 1
 | 
			
		||||
 | 
			
		||||
// Message format:
 | 
			
		||||
// https://tools.ietf.org/html/rfc1035#section-4.1
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1
 | 
			
		||||
// All communications inside of the domain protocol are carried in a single
 | 
			
		||||
// format called a message.  The top level format of message is divided
 | 
			
		||||
// into 5 sections (some of which are empty in certain cases) shown below:
 | 
			
		||||
@ -165,7 +165,7 @@ func UnmarshalMessage(b []byte) (*Message, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Header format:
 | 
			
		||||
// https://tools.ietf.org/html/rfc1035#section-4.1.1
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1
 | 
			
		||||
// The header contains the following fields:
 | 
			
		||||
//
 | 
			
		||||
//                                     1  1  1  1  1  1
 | 
			
		||||
@ -244,7 +244,7 @@ func UnmarshalHeader(b []byte, h *Header) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Question format:
 | 
			
		||||
// https://tools.ietf.org/html/rfc1035#section-4.1.2
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.2
 | 
			
		||||
// The question section is used to carry the "question" in most queries,
 | 
			
		||||
// i.e., the parameters that define what is being asked.  The section
 | 
			
		||||
// contains QDCOUNT (usually 1) entries, each of the following format:
 | 
			
		||||
@ -322,8 +322,8 @@ func (m *Message) UnmarshalQuestion(b []byte, q *Question) (n int, err error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RR format:
 | 
			
		||||
// https://tools.ietf.org/html/rfc1035#section-3.2.1
 | 
			
		||||
// https://tools.ietf.org/html/rfc1035#section-4.1.3
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.3
 | 
			
		||||
// The answer, authority, and additional sections all share the same
 | 
			
		||||
// format: a variable number of resource records, where the number of
 | 
			
		||||
// records is specified in the corresponding count field in the header.
 | 
			
		||||
@ -479,7 +479,7 @@ func (m *Message) UnmarshalDomainTo(sb *strings.Builder, b []byte) (int, error)
 | 
			
		||||
	var idx, size int
 | 
			
		||||
 | 
			
		||||
	for len(b[idx:]) != 0 {
 | 
			
		||||
		// https://tools.ietf.org/html/rfc1035#section-4.1.4
 | 
			
		||||
		// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.4
 | 
			
		||||
		// "Message compression",
 | 
			
		||||
		// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 | 
			
		||||
		// | 1  1|                OFFSET                   |
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import (
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/kcp"
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/mixed"
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/obfs"
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/pxyproto"
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/reject"
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/smux"
 | 
			
		||||
	_ "github.com/nadoo/glider/proxy/socks4"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@ -9,8 +9,8 @@ require (
 | 
			
		||||
	github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152
 | 
			
		||||
	github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521 // indirect
 | 
			
		||||
	github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e
 | 
			
		||||
	github.com/klauspost/cpuid/v2 v2.0.8 // indirect
 | 
			
		||||
	github.com/klauspost/reedsolomon v1.9.12 // indirect
 | 
			
		||||
	github.com/klauspost/cpuid/v2 v2.0.9 // indirect
 | 
			
		||||
	github.com/klauspost/reedsolomon v1.9.13 // indirect
 | 
			
		||||
	github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect
 | 
			
		||||
	github.com/nadoo/conflag v0.2.3
 | 
			
		||||
	github.com/nadoo/ipset v0.3.0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
								
							@ -49,12 +49,12 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
 | 
			
		||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 | 
			
		||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
 | 
			
		||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.8 h1:bhR2mgIlno/Sfk4oUbH4sPlc83z1yGrN9bvqiq3C33I=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.8/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
 | 
			
		||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 | 
			
		||||
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
 | 
			
		||||
github.com/klauspost/reedsolomon v1.9.12 h1:EyOucRmcrLH+2hqKGdoA5SM8pwPKR6BJsf3r6zpYOA0=
 | 
			
		||||
github.com/klauspost/reedsolomon v1.9.12/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
 | 
			
		||||
github.com/klauspost/reedsolomon v1.9.13 h1:Xr0COKf7F0ACTXUNnz2ZFCWlUKlUTAUX3y7BODdUxqU=
 | 
			
		||||
github.com/klauspost/reedsolomon v1.9.13/go.mod h1:eqPAcE7xar5CIzcdfwydOEdcmchAKAP/qs14y4GCBOk=
 | 
			
		||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE=
 | 
			
		||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
 | 
			
		||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,12 @@ func (c *Conn) Peek(n int) ([]byte, error) { return c.r.Peek(n) }
 | 
			
		||||
// WriteTo implements io.WriterTo.
 | 
			
		||||
func (c *Conn) WriteTo(w io.Writer) (n int64, err error) { return c.r.WriteTo(w) }
 | 
			
		||||
 | 
			
		||||
// Close closes the Conn.
 | 
			
		||||
func (c *Conn) Close() error {
 | 
			
		||||
	pool.PutBufReader(c.r)
 | 
			
		||||
	return c.Conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Relay relays between left and right.
 | 
			
		||||
func Relay(left, right net.Conn) error {
 | 
			
		||||
	var err, err1 error
 | 
			
		||||
@ -73,12 +79,6 @@ func Relay(left, right net.Conn) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the Conn.
 | 
			
		||||
func (c *Conn) Close() error {
 | 
			
		||||
	pool.PutBufReader(c.r)
 | 
			
		||||
	return c.Conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy copies from src to dst.
 | 
			
		||||
func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
 | 
			
		||||
	dst = underlyingWriter(dst)
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ package http
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/textproto"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
@ -12,7 +12,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Methods are http methods from rfc.
 | 
			
		||||
// https://www.ietf.org/rfc/rfc2616.txt, http methods must be uppercase
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc2616, http methods must be uppercase
 | 
			
		||||
var Methods = [...][]byte{
 | 
			
		||||
	[]byte("GET"),
 | 
			
		||||
	[]byte("POST"),
 | 
			
		||||
@ -46,7 +46,7 @@ func parseRequest(r *bufio.Reader) (*request, error) {
 | 
			
		||||
 | 
			
		||||
	method, uri, proto, ok := parseStartLine(line)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.New("error in parseStartLine")
 | 
			
		||||
		return nil, fmt.Errorf("error in parseStartLine: %s", line)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	header, err := tpr.ReadMIMEHeader()
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,7 @@ func (s *HTTP) Serve(cc net.Conn) {
 | 
			
		||||
	c := proxy.NewConn(cc)
 | 
			
		||||
	req, err := parseRequest(c.Reader())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.F("[http] can not parse request from %s", c.RemoteAddr())
 | 
			
		||||
		log.F("[http] can not parse request from %s, error: %v", c.RemoteAddr(), err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
// https://www.ietf.org/rfc/rfc5246.txt
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc5246
 | 
			
		||||
// https://golang.org/src/crypto/tls/handshake_messages.go
 | 
			
		||||
 | 
			
		||||
// NOTE:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										134
									
								
								proxy/pxyproto/server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								proxy/pxyproto/server.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,134 @@
 | 
			
		||||
package pxyproto
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/nadoo/glider/log"
 | 
			
		||||
	"github.com/nadoo/glider/proxy"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	proxy.RegisterServer("pxyproto", NewPxyProtoServer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PxyProtoServer struct.
 | 
			
		||||
type PxyProtoServer struct {
 | 
			
		||||
	addr   string
 | 
			
		||||
	proxy  proxy.Proxy
 | 
			
		||||
	server proxy.Server
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewPxyProtoServer returns a PxyProtoServer struct.
 | 
			
		||||
func NewPxyProtoServer(s string, p proxy.Proxy) (proxy.Server, error) {
 | 
			
		||||
	schemes := strings.SplitN(s, ",", 2)
 | 
			
		||||
	u, err := url.Parse(schemes[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.F("[pxyproto] parse url err: %s", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t := &PxyProtoServer{proxy: p, addr: u.Host}
 | 
			
		||||
	if len(schemes) < 2 {
 | 
			
		||||
		return nil, errors.New("[pxyproto] you must use pxyproto with a proxy server, e.g: pxyproto://:1234,http://")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.server, err = proxy.ServerFromURL(schemes[1], p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenAndServe listens on server's addr and serves connections.
 | 
			
		||||
func (s *PxyProtoServer) ListenAndServe() {
 | 
			
		||||
	l, err := net.Listen("tcp", s.addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.F("[pxyproto] failed to listen on %s: %v", s.addr, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer l.Close()
 | 
			
		||||
 | 
			
		||||
	log.F("[pxyproto] listening TCP on %s", s.addr)
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		c, err := l.Accept()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.F("[pxyproto] failed to accept: %v", err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		go s.Serve(c)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serve serves a connection.
 | 
			
		||||
func (s *PxyProtoServer) Serve(cc net.Conn) {
 | 
			
		||||
	c, err := newServerConn(cc)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.F("[pxyproto] parse header failed, error: %v", err)
 | 
			
		||||
		cc.Close()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// log.F("[pxyproto] %s <-> %s <-> %s <-> %s",
 | 
			
		||||
	// c.RemoteAddr(), c.LocalAddr(), cc.RemoteAddr(), cc.LocalAddr())
 | 
			
		||||
 | 
			
		||||
	if s.server != nil {
 | 
			
		||||
		s.server.Serve(c)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type serverConn struct {
 | 
			
		||||
	*proxy.Conn
 | 
			
		||||
	src, dst net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newServerConn(c net.Conn) (*serverConn, error) {
 | 
			
		||||
	sc := &serverConn{
 | 
			
		||||
		Conn: proxy.NewConn(c),
 | 
			
		||||
		src:  c.RemoteAddr(),
 | 
			
		||||
		dst:  c.LocalAddr(),
 | 
			
		||||
	}
 | 
			
		||||
	return sc, sc.parseHeader()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "PROXY TCPx SRC_IP DST_IP SRC_PORT DST_PORT"
 | 
			
		||||
func (c *serverConn) parseHeader() error {
 | 
			
		||||
	line, err := c.Conn.Reader().ReadString('\n')
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	line = strings.ReplaceAll(line, "\r\n", "")
 | 
			
		||||
	// log.F("[pxyproto] req header: %s", line)
 | 
			
		||||
 | 
			
		||||
	header := strings.Split(line, " ")
 | 
			
		||||
	if len(header) != 6 {
 | 
			
		||||
		return fmt.Errorf("invalid header: %s", line)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if header[0] != "PROXY" {
 | 
			
		||||
		return fmt.Errorf("invalid header: %s", line)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.src, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(header[2], header[4]))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("parse header: %s, error: %v", line, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.dst, err = net.ResolveTCPAddr("tcp", net.JoinHostPort(header[3], header[5]))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("parse header: %s, error: %v", line, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *serverConn) LocalAddr() net.Addr  { return c.dst }
 | 
			
		||||
func (c *serverConn) RemoteAddr() net.Addr { return c.src }
 | 
			
		||||
@ -66,7 +66,7 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
 | 
			
		||||
		return n, raddr, errors.New("not enough size to get addr")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// https://tools.ietf.org/html/rfc1928#section-7
 | 
			
		||||
	// https://www.rfc-editor.org/rfc/rfc1928#section-7
 | 
			
		||||
	// +----+------+------+----------+----------+----------+
 | 
			
		||||
	// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
 | 
			
		||||
	// +----+------+------+----------+----------+----------+
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
// https://tools.ietf.org/html/rfc1928
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc1928
 | 
			
		||||
 | 
			
		||||
// socks5 client:
 | 
			
		||||
// https://github.com/golang/net/tree/master/proxy
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
// https://tools.ietf.org/html/rfc6455#section-5.2
 | 
			
		||||
// https://www.rfc-editor.org/rfc/rfc6455#section-5.2
 | 
			
		||||
//
 | 
			
		||||
// Frame Format
 | 
			
		||||
// 0                   1                   2                   3
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,12 @@
 | 
			
		||||
package rule
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/nadoo/glider/pool"
 | 
			
		||||
@ -71,12 +71,12 @@ func (c *httpChecker) Check(dialer proxy.Dialer) (time.Duration, error) {
 | 
			
		||||
	r := pool.GetBufReader(rc)
 | 
			
		||||
	defer pool.PutBufReader(r)
 | 
			
		||||
 | 
			
		||||
	line, _, err := r.ReadLine()
 | 
			
		||||
	line, err := r.ReadString('\n')
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !bytes.Contains(line, []byte(c.expect)) {
 | 
			
		||||
	if !strings.Contains(line, c.expect) {
 | 
			
		||||
		return 0, fmt.Errorf("expect: %s, got: %s", c.expect, line)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user