From 6943010274f03661b99c19f82aa1284996c6ed02 Mon Sep 17 00:00:00 2001 From: lucus Date: Sun, 22 Jan 2017 05:20:06 +0900 Subject: [PATCH 1/4] Fix typos. --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4d5ecc4a..5e25e8ea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,9 @@ 1.2.0 (2017-01-20) - * Support UDP reley on server side, and OTA + * Support UDP relay on server side, and OTA * Support "aes-[128/192/256]-ctr" encryption method (Thanks for @slurin) * Support "chacha20-ietf" encryption method * Improve performance of "chacha20" encryption method - * Corrently close connection if handshake failed + * Correctly close connection if handshake failed 1.1.5 (2016-05-04) * Support OTA (Thanks for @ayanamist for implementing this feature) From 789556a3039b5272cebc1183da2a96fd355c9a83 Mon Sep 17 00:00:00 2001 From: lucus Date: Sun, 22 Jan 2017 03:20:39 +0900 Subject: [PATCH 2/4] Refine the UDP OTA code. --- shadowsocks/udp.go | 22 ++-------------- shadowsocks/udprelay.go | 57 ++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 49 deletions(-) diff --git a/shadowsocks/udp.go b/shadowsocks/udp.go index 058e93e1..898092da 100644 --- a/shadowsocks/udp.go +++ b/shadowsocks/udp.go @@ -129,24 +129,6 @@ func (c *SecurePacketConn) IsOta() bool { return c.ota } -func (c *SecurePacketConn) ForceOTAWriteTo(b []byte, dst net.Addr) (n int, err error) { - cipher := c.Copy() - iv, err := cipher.initEncrypt() - if err != nil { - return - } - packetLen := len(b) + len(iv) - - packetLen += lenHmacSha1 - key := cipher.key - actualHmacSha1Buf := HmacSha1(append(iv, key...), b) - b = append(b, actualHmacSha1Buf...) - - cipherData := make([]byte, packetLen) - copy(cipherData, iv) - - cipher.encrypt(cipherData[len(iv):], b) - n, err = c.PacketConn.WriteTo(cipherData, dst) - n -= lenHmacSha1 - return +func (c *SecurePacketConn) ForceOTA() net.PacketConn { + return NewSecurePacketConn(c.PacketConn, c.Cipher.Copy(), true) } diff --git a/shadowsocks/udprelay.go b/shadowsocks/udprelay.go index c38dbe0a..37f48589 100644 --- a/shadowsocks/udprelay.go +++ b/shadowsocks/udprelay.go @@ -43,14 +43,15 @@ func newNatTable() *natTable { return &natTable{conns: map[string]net.PacketConn{}} } -func (table *natTable) DeleteAndClose(index string) { +func (table *natTable) Delete(index string) net.PacketConn { table.Lock() defer table.Unlock() c, ok := table.conns[index] if ok { - c.Close() delete(table.conns, index) + return c } + return nil } func (table *natTable) Get(index string) (c net.PacketConn, ok bool, err error) { @@ -67,13 +68,13 @@ func (table *natTable) Get(index string) (c net.PacketConn, ok bool, err error) return } -type ReqList struct { +type requestHeaderList struct { sync.Mutex List map[string]([]byte) } -func newReqList() *ReqList { - ret := &ReqList{List: map[string]([]byte){}} +func newReqList() *requestHeaderList { + ret := &requestHeaderList{List: map[string]([]byte){}} go func() { for { time.Sleep(reqListRefreshTime) @@ -83,7 +84,7 @@ func newReqList() *ReqList { return ret } -func (r *ReqList) Refresh() { +func (r *requestHeaderList) Refresh() { r.Lock() defer r.Unlock() for k, _ := range r.List { @@ -91,21 +92,21 @@ func (r *ReqList) Refresh() { } } -func (r *ReqList) Get(dstaddr string) (req []byte, ok bool) { +func (r *requestHeaderList) Get(dstaddr string) (req []byte, ok bool) { r.Lock() defer r.Unlock() req, ok = r.List[dstaddr] return } -func (r *ReqList) Put(dstaddr string, req []byte) { +func (r *requestHeaderList) Put(dstaddr string, req []byte) { r.Lock() defer r.Unlock() r.List[dstaddr] = req return } -func ParseHeader(addr net.Addr) ([]byte, int) { +func parseHeaderFromAddr(addr net.Addr) ([]byte, int) { // if the request address type is domain, it cannot be reverselookuped ip, port, err := net.SplitHostPort(addr.String()) if err != nil { @@ -129,13 +130,13 @@ func ParseHeader(addr net.Addr) ([]byte, int) { return buf[:1+iplen+2], 1 + iplen + 2 } -func Pipeloop(ss *SecurePacketConn, addr net.Addr, in net.PacketConn, compatiblemode bool) { +func Pipeloop(write net.PacketConn, writeAddr net.Addr, readClose net.PacketConn) { buf := leakyBuf.Get() defer leakyBuf.Put(buf) - defer in.Close() + defer readClose.Close() for { - in.SetDeadline(time.Now().Add(udpTimeout)) - n, raddr, err := in.ReadFrom(buf) + readClose.SetDeadline(time.Now().Add(udpTimeout)) + n, raddr, err := readClose.ReadFrom(buf) if err != nil { if ne, ok := err.(*net.OpError); ok { if ne.Err == syscall.EMFILE || ne.Err == syscall.ENFILE { @@ -144,24 +145,15 @@ func Pipeloop(ss *SecurePacketConn, addr net.Addr, in net.PacketConn, compatible Debug.Println("[udp]read error:", err) } } - Debug.Printf("[udp]closed pipe %s<-%s\n", addr, in.LocalAddr()) + Debug.Printf("[udp]closed pipe %s<-%s\n", writeAddr, readClose.LocalAddr()) return } // need improvement here if req, ok := reqList.Get(raddr.String()); ok { - if compatiblemode { - ss.ForceOTAWriteTo(append(req, buf[:n]...), addr) - } else { - ss.WriteTo(append(req, buf[:n]...), addr) - } + write.WriteTo(append(req, buf[:n]...), writeAddr) } else { - header, hlen := ParseHeader(raddr) - if compatiblemode { - ss.ForceOTAWriteTo(append(header[:hlen], buf[:n]...), addr) - } else { - ss.WriteTo(append(header[:hlen], buf[:n]...), addr) - } - + header, hlen := parseHeaderFromAddr(raddr) + write.WriteTo(append(header[:hlen], buf[:n]...), writeAddr) } } } @@ -229,8 +221,13 @@ func handleUDPConnection(handle *SecurePacketConn, n int, src net.Addr, receive if !exist { Debug.Printf("[udp]new client %s->%s via %s ota=%v\n", src, dst, remote.LocalAddr(), ota) go func() { - Pipeloop(handle, src, remote, compatiblemode) - natlist.DeleteAndClose(src.String()) + if compatiblemode { + Pipeloop(handle.ForceOTA(), src, remote) + } else { + Pipeloop(handle, src, remote) + } + + natlist.Delete(src.String()) }() } else { Debug.Printf("[udp]using cached client %s->%s via %s ota=%v\n", src, dst, remote.LocalAddr(), ota) @@ -248,7 +245,9 @@ func handleUDPConnection(handle *SecurePacketConn, n int, src net.Addr, receive } else { Debug.Println("[udp]error connecting to:", dst, err) } - natlist.DeleteAndClose(src.String()) + if conn := natlist.Delete(src.String()); conn != nil { + conn.Close() + } } // Pipeloop return From 0e4e35a508994820876562ddf083bfc2190a8046 Mon Sep 17 00:00:00 2001 From: lucus Date: Sun, 22 Jan 2017 05:31:42 +0900 Subject: [PATCH 3/4] Fix bug handling UDP OTA. --- shadowsocks/udp.go | 1 + shadowsocks/udprelay.go | 1 + 2 files changed, 2 insertions(+) diff --git a/shadowsocks/udp.go b/shadowsocks/udp.go index 898092da..62a55d84 100644 --- a/shadowsocks/udp.go +++ b/shadowsocks/udp.go @@ -92,6 +92,7 @@ func (c *SecurePacketConn) WriteTo(b []byte, dst net.Addr) (n int, err error) { packetLen := len(b) + len(iv) if c.ota { + b[idType] |= OneTimeAuthMask packetLen += lenHmacSha1 key := cipher.key actualHmacSha1Buf := HmacSha1(append(iv, key...), b) diff --git a/shadowsocks/udprelay.go b/shadowsocks/udprelay.go index 37f48589..727efb67 100644 --- a/shadowsocks/udprelay.go +++ b/shadowsocks/udprelay.go @@ -168,6 +168,7 @@ func handleUDPConnection(handle *SecurePacketConn, n int, src net.Addr, receive if addrType&OneTimeAuthMask > 0 { ota = true } + receive[idType] &= ^OneTimeAuthMask compatiblemode := !handle.IsOta() && ota switch addrType & AddrMask { From 9b9860fed36451fa7842da1d9220f75c63eae447 Mon Sep 17 00:00:00 2001 From: lucus Date: Sun, 22 Jan 2017 05:33:13 +0900 Subject: [PATCH 4/4] Bump to 1.2.1 --- CHANGELOG | 3 +++ README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 5e25e8ea..dca89d19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +1.2.1 (2017-01-22) + * Fix bug in handling of UDP OTA packets + 1.2.0 (2017-01-20) * Support UDP relay on server side, and OTA * Support "aes-[128/192/256]-ctr" encryption method (Thanks for @slurin) diff --git a/README.md b/README.md index 2d926906..9b54b1dc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # shadowsocks-go -Current version: 1.2.0 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png?branch=develop)](https://travis-ci.org/shadowsocks/shadowsocks-go) +Current version: 1.2.1 [![Build Status](https://travis-ci.org/shadowsocks/shadowsocks-go.png?branch=develop)](https://travis-ci.org/shadowsocks/shadowsocks-go) shadowsocks-go is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks).