Skip to content

Commit

Permalink
Bugfix: correctly handle relayed UDP packets
Browse files Browse the repository at this point in the history
Relayed UDP packets should be prefixed with original source address according to RFC 1928 section 7.
  • Loading branch information
riobard committed Feb 19, 2017
1 parent e6d8579 commit 0b73e7a
Showing 1 changed file with 17 additions and 8 deletions.
25 changes: 17 additions & 8 deletions udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func udpLocal(laddr, server, target string, ciph core.PacketConnCipher) {
}

pc = ciph.PacketConn(pc)
nm.Add(raddr, c, pc)
nm.Add(raddr, c, pc, false)
}

_, err = pc.WriteTo(buf[:len(tgt)+n], srvAddr)
Expand Down Expand Up @@ -109,7 +109,7 @@ func udpRemote(addr string, ciph core.PacketConnCipher) {
continue
}

nm.Add(raddr, c, pc)
nm.Add(raddr, c, pc, true)
}

_, err = pc.WriteTo(payload, tgtUDPAddr) // accept only UDPAddr despite the signature
Expand Down Expand Up @@ -159,29 +159,38 @@ func (m *natmap) Del(key string) net.PacketConn {
return nil
}

func (m *natmap) Add(peer net.Addr, dst, src net.PacketConn) {
func (m *natmap) Add(peer net.Addr, dst, src net.PacketConn, srcIncluded bool) {
m.Set(peer.String(), src)

go func() {
timedCopy(dst, peer, src, m.timeout)
timedCopy(dst, peer, src, m.timeout, srcIncluded)
if pc := m.Del(peer.String()); pc != nil {
pc.Close()
}
}()
}

// copy from src to dst with addr with read timeout
func timedCopy(dst net.PacketConn, addr net.Addr, src net.PacketConn, timeout time.Duration) error {
// copy from src to dst at target with read timeout
func timedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout time.Duration, srcIncluded bool) error {
buf := make([]byte, udpBufSize)

for {
src.SetReadDeadline(time.Now().Add(timeout))
n, _, err := src.ReadFrom(buf)
n, raddr, err := src.ReadFrom(buf)
if err != nil {
return err
}

_, err = dst.WriteTo(buf[:n], addr)
if srcIncluded { // server -> client: add original packet source
srcAddr := socks.ParseAddr(raddr.String())
copy(buf[len(srcAddr):], buf[:n])
copy(buf, srcAddr)
_, err = dst.WriteTo(buf[:len(srcAddr)+n], target)
} else { // client -> user: strip original packet source
srcAddr := socks.SplitAddr(buf[:n])
_, err = dst.WriteTo(buf[len(srcAddr):n], target)
}

if err != nil {
return err
}
Expand Down

0 comments on commit 0b73e7a

Please sign in to comment.