From 5ed4702b62dddbab7614c4cbfb40bcbf913a91c9 Mon Sep 17 00:00:00 2001 From: "arraykeys@gmail.com" Date: Thu, 8 Mar 2018 11:51:34 +0800 Subject: [PATCH] add kcp config args Signed-off-by: arraykeys@gmail.com --- config.go | 74 ++++++++++++++++++++++++++++++++++++----- services/args.go | 18 +++++----- services/http.go | 5 ++- services/kcpcfg/args.go | 24 +++++++++++++ services/socks.go | 4 +-- services/sps.go | 5 ++- services/tcp.go | 5 ++- services/udp.go | 3 +- utils/functions.go | 21 ++++++++---- utils/serve-channel.go | 34 +++++++++++++++---- utils/structs.go | 54 ++++++++++++++++++++++++++---- 11 files changed, 198 insertions(+), 49 deletions(-) create mode 100644 services/kcpcfg/args.go diff --git a/config.go b/config.go index 04be4b2..cbf8452 100755 --- a/config.go +++ b/config.go @@ -2,14 +2,18 @@ package main import ( "bufio" + "crypto/sha1" "fmt" "log" "os" "os/exec" "snail007/proxy/services" + "snail007/proxy/services/kcpcfg" "snail007/proxy/utils" "time" + kcp "github.com/xtaci/kcp-go" + "golang.org/x/crypto/pbkdf2" kingpin "gopkg.in/alecthomas/kingpin.v2" ) @@ -40,6 +44,7 @@ func initConfig() (err error) { udpArgs := services.UDPArgs{} socksArgs := services.SocksArgs{} spsArgs := services.SPSArgs{} + kcpArgs := kcpcfg.KCPConfigArgs{} //build srvice args app = kingpin.New("proxy", "happy with proxy") app.Author("snail").Version(APP_VERSION) @@ -47,6 +52,23 @@ func initConfig() (err error) { daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool() forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool() logfile := app.Flag("log", "log file path").Default("").String() + kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String() + kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").String() + kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").String() + kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int() + kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int() + kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int() + kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int() + kcpArgs.ParityShard = app.Flag("kcp-ps", "set reed-solomon erasure coding - parityshard").Default("3").Int() + kcpArgs.DSCP = app.Flag("kcp-dscp", "set DSCP(6bit)").Default("0").Int() + kcpArgs.NoComp = app.Flag("kcp-nocomp", "disable compression").Default("false").Bool() + kcpArgs.AckNodelay = app.Flag("kcp-acknodelay", "be carefull! flush ack immediately when a packet is received").Default("true").Bool() + kcpArgs.NoDelay = app.Flag("kcp-nodelay", "be carefull!").Default("0").Int() + kcpArgs.Interval = app.Flag("kcp-interval", "be carefull!").Default("50").Int() + kcpArgs.Resend = app.Flag("kcp-resend", "be carefull!").Default("0").Int() + kcpArgs.NoCongestion = app.Flag("kcp-nc", "be carefull! no congestion").Default("0").Int() + kcpArgs.SockBuf = app.Flag("kcp-sockbuf", "be carefull!").Default("4194304").Int() + kcpArgs.KeepAlive = app.Flag("kcp-keepalive", "be carefull!").Default("10").Int() //########http######### http := app.Command("http", "proxy on http mode") @@ -70,8 +92,6 @@ func initConfig() (err error) { httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String() httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String() httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String() - httpArgs.KCPKey = http.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String() - httpArgs.KCPMethod = http.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String() httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings() httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String() httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int() @@ -91,8 +111,6 @@ func initConfig() (err error) { tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() - tcpArgs.KCPKey = tcp.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String() - tcpArgs.KCPMethod = tcp.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String() //########udp######### udp := app.Command("udp", "proxy on udp mode") @@ -178,8 +196,6 @@ func initConfig() (err error) { socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String() socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String() socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() - socksArgs.KCPKey = socks.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String() - socksArgs.KCPMethod = socks.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String() socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings() socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String() socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int() @@ -196,14 +212,56 @@ func initConfig() (err error) { spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type ").Short('T').Enum("tls", "tcp", "kcp") spsArgs.LocalType = sps.Flag("local-type", "local protocol type ").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String() - spsArgs.KCPKey = sps.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String() - spsArgs.KCPMethod = sps.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String() spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type ").Short('S').Enum("http", "socks") spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String() spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int() //parse args serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) + + //set kcp config + + switch *kcpArgs.Mode { + case "normal": + *kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 40, 2, 1 + case "fast": + *kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 30, 2, 1 + case "fast2": + *kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 20, 2, 1 + case "fast3": + *kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 10, 2, 1 + } + pass := pbkdf2.Key([]byte(*kcpArgs.Key), []byte("snail007-goproxy"), 4096, 32, sha1.New) + + switch *kcpArgs.Crypt { + case "sm4": + kcpArgs.Block, _ = kcp.NewSM4BlockCrypt(pass[:16]) + case "tea": + kcpArgs.Block, _ = kcp.NewTEABlockCrypt(pass[:16]) + case "xor": + kcpArgs.Block, _ = kcp.NewSimpleXORBlockCrypt(pass) + case "none": + kcpArgs.Block, _ = kcp.NewNoneBlockCrypt(pass) + case "aes-128": + kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:16]) + case "aes-192": + kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:24]) + case "blowfish": + kcpArgs.Block, _ = kcp.NewBlowfishBlockCrypt(pass) + case "twofish": + kcpArgs.Block, _ = kcp.NewTwofishBlockCrypt(pass) + case "cast5": + kcpArgs.Block, _ = kcp.NewCast5BlockCrypt(pass[:16]) + case "3des": + kcpArgs.Block, _ = kcp.NewTripleDESBlockCrypt(pass[:24]) + case "xtea": + kcpArgs.Block, _ = kcp.NewXTEABlockCrypt(pass[:16]) + case "salsa20": + kcpArgs.Block, _ = kcp.NewSalsa20BlockCrypt(pass) + default: + *kcpArgs.Crypt = "aes" + kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass) + } flags := log.Ldate if *debug { flags |= log.Lshortfile | log.Lmicroseconds diff --git a/services/args.go b/services/args.go index 7dfa671..73f263a 100644 --- a/services/args.go +++ b/services/args.go @@ -1,6 +1,10 @@ package services -import "golang.org/x/crypto/ssh" +import ( + "snail007/proxy/services/kcpcfg" + + "golang.org/x/crypto/ssh" +) // tcp := app.Command("tcp", "proxy on tcp mode") // t := tcp.Flag("tcp-timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int() @@ -102,8 +106,7 @@ type TCPArgs struct { Timeout *int PoolSize *int CheckParentInterval *int - KCPMethod *string - KCPKey *string + KCP kcpcfg.KCPConfigArgs } type HTTPArgs struct { @@ -135,8 +138,7 @@ type HTTPArgs struct { SSHUser *string SSHKeyBytes []byte SSHAuthMethod ssh.AuthMethod - KCPMethod *string - KCPKey *string + KCP kcpcfg.KCPConfigArgs LocalIPS *[]string DNSAddress *string DNSTTL *int @@ -179,8 +181,7 @@ type SocksArgs struct { AuthURLOkCode *int AuthURLTimeout *int AuthURLRetry *int - KCPMethod *string - KCPKey *string + KCP kcpcfg.KCPConfigArgs UDPParent *string UDPLocal *string LocalIPS *[]string @@ -197,8 +198,7 @@ type SPSArgs struct { ParentType *string LocalType *string Timeout *int - KCPMethod *string - KCPKey *string + KCP kcpcfg.KCPConfigArgs ParentServiceType *string DNSAddress *string DNSTTL *int diff --git a/services/http.go b/services/http.go index 2693417..8621a8a 100644 --- a/services/http.go +++ b/services/http.go @@ -130,7 +130,7 @@ func (s *HTTP) Start(args interface{}) (err error) { } else if *s.cfg.LocalType == TYPE_TLS { err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) } else if *s.cfg.LocalType == TYPE_KCP { - err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) + err = sc.ListenKCP(s.cfg.KCP, s.callback) } if err != nil { return @@ -320,8 +320,7 @@ func (s *HTTP) InitOutConnPool() { s.outPool = utils.NewOutPool( *s.cfg.CheckParentInterval, *s.cfg.ParentType, - *s.cfg.KCPMethod, - *s.cfg.KCPKey, + s.cfg.KCP, s.cfg.CertBytes, s.cfg.KeyBytes, s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, diff --git a/services/kcpcfg/args.go b/services/kcpcfg/args.go new file mode 100644 index 0000000..5d3b67c --- /dev/null +++ b/services/kcpcfg/args.go @@ -0,0 +1,24 @@ +package kcpcfg + +import kcp "github.com/xtaci/kcp-go" + +type KCPConfigArgs struct { + Key *string + Crypt *string + Mode *string + MTU *int + SndWnd *int + RcvWnd *int + DataShard *int + ParityShard *int + DSCP *int + NoComp *bool + AckNodelay *bool + NoDelay *int + Interval *int + Resend *int + NoCongestion *int + SockBuf *int + KeepAlive *int + Block kcp.BlockCrypt +} diff --git a/services/socks.go b/services/socks.go index c123c17..b69ed91 100644 --- a/services/socks.go +++ b/services/socks.go @@ -140,7 +140,7 @@ func (s *Socks) Start(args interface{}) (err error) { } else if *s.cfg.LocalType == TYPE_TLS { err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback) } else if *s.cfg.LocalType == TYPE_KCP { - err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.socksConnCallback) + err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback) } if err != nil { return @@ -474,7 +474,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n _outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes) outConn = net.Conn(&_outConn) } else if *s.cfg.ParentType == "kcp" { - outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), *s.cfg.KCPMethod, *s.cfg.KCPKey) + outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), s.cfg.KCP) } else { outConn, err = utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout) } diff --git a/services/sps.go b/services/sps.go index fa62ff5..1e4e4a5 100644 --- a/services/sps.go +++ b/services/sps.go @@ -46,8 +46,7 @@ func (s *SPS) InitOutConnPool() { s.outPool = utils.NewOutPool( 0, *s.cfg.ParentType, - *s.cfg.KCPMethod, - *s.cfg.KCPKey, + s.cfg.KCP, s.cfg.CertBytes, s.cfg.KeyBytes, *s.cfg.Parent, *s.cfg.Timeout, @@ -78,7 +77,7 @@ func (s *SPS) Start(args interface{}) (err error) { } else if *s.cfg.LocalType == TYPE_TLS { err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) } else if *s.cfg.LocalType == TYPE_KCP { - err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) + err = sc.ListenKCP(s.cfg.KCP, s.callback) } if err != nil { return diff --git a/services/tcp.go b/services/tcp.go index 019c410..85136a2 100644 --- a/services/tcp.go +++ b/services/tcp.go @@ -58,7 +58,7 @@ func (s *TCP) Start(args interface{}) (err error) { } else if *s.cfg.LocalType == TYPE_TLS { err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) } else if *s.cfg.LocalType == TYPE_KCP { - err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) + err = sc.ListenKCP(s.cfg.KCP, s.callback) } if err != nil { return @@ -171,8 +171,7 @@ func (s *TCP) InitOutConnPool() { s.outPool = utils.NewOutPool( *s.cfg.CheckParentInterval, *s.cfg.ParentType, - *s.cfg.KCPMethod, - *s.cfg.KCPKey, + s.cfg.KCP, s.cfg.CertBytes, s.cfg.KeyBytes, *s.cfg.Parent, *s.cfg.Timeout, diff --git a/services/udp.go b/services/udp.go index 39a8000..6f63f0d 100644 --- a/services/udp.go +++ b/services/udp.go @@ -8,6 +8,7 @@ import ( "log" "net" "runtime/debug" + "snail007/proxy/services/kcpcfg" "snail007/proxy/utils" "strconv" "strings" @@ -208,7 +209,7 @@ func (s *UDP) InitOutConnPool() { s.outPool = utils.NewOutPool( *s.cfg.CheckParentInterval, *s.cfg.ParentType, - "", "", + kcpcfg.KCPConfigArgs{}, s.cfg.CertBytes, s.cfg.KeyBytes, *s.cfg.Parent, *s.cfg.Timeout, diff --git a/utils/functions.go b/utils/functions.go index ae6a349..3927909 100755 --- a/utils/functions.go +++ b/utils/functions.go @@ -18,6 +18,7 @@ import ( "net/http" "os" "os/exec" + "snail007/proxy/services/kcpcfg" "golang.org/x/crypto/pbkdf2" @@ -147,17 +148,23 @@ func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) { conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond) return } -func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) { - kcpconn, err := kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3) +func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.Conn, err error) { + kcpconn, err := kcp.DialWithOptions(hostAndPort, config.Block, *config.DataShard, *config.ParityShard) if err != nil { return } - kcpconn.SetNoDelay(1, 10, 2, 1) - kcpconn.SetWindowSize(1024, 1024) - kcpconn.SetMtu(1400) - kcpconn.SetACKNoDelay(false) - return kcpconn, err + kcpconn.SetStreamMode(true) + kcpconn.SetWriteDelay(true) + kcpconn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion) + kcpconn.SetMtu(*config.MTU) + kcpconn.SetWindowSize(*config.SndWnd, *config.RcvWnd) + kcpconn.SetACKNoDelay(*config.AckNodelay) + if *config.NoComp { + return kcpconn, err + } + return NewCompStream(kcpconn), err } + func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) { block, _ := pem.Decode(certBytes) if block == nil { diff --git a/utils/serve-channel.go b/utils/serve-channel.go index c023518..25e0a7e 100644 --- a/utils/serve-channel.go +++ b/utils/serve-channel.go @@ -5,6 +5,7 @@ import ( "log" "net" "runtime/debug" + "snail007/proxy/services/kcpcfg" "strconv" kcp "github.com/xtaci/kcp-go" @@ -138,11 +139,19 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne } return } -func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (err error) { - var l net.Listener - l, err = kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), GetKCPBlock(method, key), 10, 3) +func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn)) (err error) { + lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard) if err == nil { - sc.Listener = &l + if err := lis.SetDSCP(*config.DSCP); err != nil { + log.Println("SetDSCP:", err) + } + if err := lis.SetReadBuffer(*config.SockBuf); err != nil { + log.Println("SetReadBuffer:", err) + } + if err := lis.SetWriteBuffer(*config.SockBuf); err != nil { + log.Println("SetWriteBuffer:", err) + } + *sc.Listener = lis go func() { defer func() { if e := recover(); e != nil { @@ -150,8 +159,8 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) ( } }() for { - var conn net.Conn - conn, err = (*sc.Listener).Accept() + //var conn net.Conn + conn, err := lis.AcceptKCP() if err == nil { go func() { defer func() { @@ -159,7 +168,18 @@ func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) ( log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) } }() - fn(conn) + conn.SetStreamMode(true) + conn.SetWriteDelay(true) + conn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion) + conn.SetMtu(*config.MTU) + conn.SetWindowSize(*config.SndWnd, *config.RcvWnd) + conn.SetACKNoDelay(*config.AckNodelay) + if *config.NoComp { + fn(conn) + } else { + cconn := NewCompStream(conn) + fn(cconn) + } }() } else { sc.errAcceptHandler(err) diff --git a/utils/structs.go b/utils/structs.go index fe22c47..a88e75c 100644 --- a/utils/structs.go +++ b/utils/structs.go @@ -12,11 +12,13 @@ import ( "log" "net" "net/url" + "snail007/proxy/services/kcpcfg" "snail007/proxy/utils/sni" "strings" "sync" "time" + "github.com/golang/snappy" "github.com/miekg/dns" ) @@ -494,20 +496,18 @@ type OutPool struct { typ string certBytes []byte keyBytes []byte - kcpMethod string - kcpKey string + kcp kcpcfg.KCPConfigArgs address string timeout int } -func NewOutPool(dur int, typ, kcpMethod, kcpKey string, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) { +func NewOutPool(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) { op = OutPool{ dur: dur, typ: typ, certBytes: certBytes, keyBytes: keyBytes, - kcpMethod: kcpMethod, - kcpKey: kcpKey, + kcp: kcp, address: address, timeout: timeout, } @@ -548,7 +548,7 @@ func (op *OutPool) getConn() (conn interface{}, err error) { conn = net.Conn(&_conn) } } else if op.typ == "kcp" { - conn, err = ConnectKCPHost(op.address, op.kcpMethod, op.kcpKey) + conn, err = ConnectKCPHost(op.address, op.kcp) } else { conn, err = ConnectHost(op.address, op.timeout) } @@ -924,3 +924,45 @@ func (a *DomainResolver) PrintData() { fmt.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt) } } +func NewCompStream(conn net.Conn) *CompStream { + c := new(CompStream) + c.conn = conn + c.w = snappy.NewBufferedWriter(conn) + c.r = snappy.NewReader(conn) + return c +} + +type CompStream struct { + conn net.Conn + w *snappy.Writer + r *snappy.Reader +} + +func (c *CompStream) Read(p []byte) (n int, err error) { + return c.r.Read(p) +} + +func (c *CompStream) Write(p []byte) (n int, err error) { + n, err = c.w.Write(p) + err = c.w.Flush() + return n, err +} + +func (c *CompStream) Close() error { + return c.conn.Close() +} +func (c *CompStream) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} +func (c *CompStream) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} +func (c *CompStream) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} +func (c *CompStream) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} +func (c *CompStream) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +}