github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/services/sps/ssudp.go (about) 1 package sps 2 3 import ( 4 "bytes" 5 "fmt" 6 "net" 7 "runtime/debug" 8 "time" 9 10 "github.com/AntonOrnatskyi/goproxy/utils" 11 goaes "github.com/AntonOrnatskyi/goproxy/utils/aes" 12 "github.com/AntonOrnatskyi/goproxy/utils/socks" 13 ) 14 15 func (s *SPS) RunSSUDP(addr string) (err error) { 16 a, _ := net.ResolveUDPAddr("udp", addr) 17 listener, err := net.ListenUDP("udp", a) 18 if err != nil { 19 s.log.Printf("ss udp bind error %s", err) 20 return 21 } 22 s.log.Printf("ss udp on %s", listener.LocalAddr()) 23 s.udpRelatedPacketConns.Set(addr, listener) 24 go func() { 25 defer func() { 26 if e := recover(); e != nil { 27 s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack())) 28 } 29 }() 30 buf := utils.LeakyBuffer.Get() 31 defer utils.LeakyBuffer.Put(buf) 32 for { 33 n, srcAddr, err := listener.ReadFrom(buf) 34 if err != nil { 35 s.log.Printf("read from client error %s", err) 36 if utils.IsNetClosedErr(err) { 37 return 38 } 39 continue 40 } 41 var ( 42 inconnRemoteAddr = srcAddr.String() 43 outUDPConn *net.UDPConn 44 outconn net.Conn 45 outconnLocalAddr string 46 destAddr *net.UDPAddr 47 clean = func(msg, err string) { 48 raddr := "" 49 if outUDPConn != nil { 50 raddr = outUDPConn.RemoteAddr().String() 51 outUDPConn.Close() 52 } 53 if msg != "" { 54 if raddr != "" { 55 s.log.Printf("%s , %s , %s -> %s", msg, err, inconnRemoteAddr, raddr) 56 } else { 57 s.log.Printf("%s , %s , from : %s", msg, err, inconnRemoteAddr) 58 } 59 } 60 s.userConns.Remove(inconnRemoteAddr) 61 if outconn != nil { 62 outconn.Close() 63 } 64 if outconnLocalAddr != "" { 65 s.userConns.Remove(outconnLocalAddr) 66 } 67 } 68 ) 69 defer clean("", "") 70 71 raw := new(bytes.Buffer) 72 raw.Write([]byte{0x00, 0x00, 0x00}) 73 raw.Write(s.localCipher.Decrypt(buf[:n])) 74 socksPacket := socks.NewPacketUDP() 75 err = socksPacket.Parse(raw.Bytes()) 76 raw = nil 77 if err != nil { 78 s.log.Printf("udp parse error %s", err) 79 return 80 } 81 82 if v, ok := s.udpRelatedPacketConns.Get(inconnRemoteAddr); !ok { 83 //socks client 84 lbAddr := s.lb.Select(inconnRemoteAddr, *s.cfg.LoadBalanceOnlyHA) 85 outconn, err := s.GetParentConn(lbAddr) 86 if err != nil { 87 clean("connnect fail", fmt.Sprintf("%s", err)) 88 return 89 } 90 91 client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", socksPacket.Addr(), socks.Auth{}, true) 92 if err != nil { 93 clean("handshake fail", fmt.Sprintf("%s", err)) 94 return 95 } 96 97 outconnLocalAddr = outconn.LocalAddr().String() 98 s.userConns.Set(outconnLocalAddr, &outconn) 99 go func() { 100 defer func() { 101 if e := recover(); e != nil { 102 s.log.Printf("udp related parent tcp conn read crashed:\n%s\n%s", e, string(debug.Stack())) 103 } 104 }() 105 buf := make([]byte, 1) 106 outconn.SetReadDeadline(time.Time{}) 107 if _, err := outconn.Read(buf); err != nil { 108 clean("udp parent tcp conn disconnected", fmt.Sprintf("%s", err)) 109 } 110 }() 111 destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) 112 localZeroAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} 113 outUDPConn, err = net.DialUDP("udp", localZeroAddr, destAddr) 114 if err != nil { 115 s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr) 116 return 117 } 118 s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn) 119 utils.UDPCopy(listener, outUDPConn, srcAddr, time.Second*5, func(data []byte) []byte { 120 //forward to local 121 var v []byte 122 //convert parent data to raw 123 if len(s.udpParentKey) > 0 { 124 v, err = goaes.Decrypt(s.udpParentKey, data) 125 if err != nil { 126 s.log.Printf("udp outconn parse packet fail, %s", err.Error()) 127 return []byte{} 128 } 129 } else { 130 v = data 131 } 132 return s.localCipher.Encrypt(v[3:]) 133 }, func(err interface{}) { 134 s.udpRelatedPacketConns.Remove(srcAddr.String()) 135 if err != nil { 136 s.log.Printf("udp out->local io copy crashed:\n%s\n%s", err, string(debug.Stack())) 137 } 138 }) 139 } else { 140 outUDPConn = v.(*net.UDPConn) 141 } 142 //forward to parent 143 //p is raw, now convert it to parent 144 var v []byte 145 if len(s.udpParentKey) > 0 { 146 v, _ = goaes.Encrypt(s.udpParentKey, socksPacket.Bytes()) 147 } else { 148 v = socksPacket.Bytes() 149 } 150 _, err = outUDPConn.Write(v) 151 socksPacket = socks.PacketUDP{} 152 if err != nil { 153 if utils.IsNetClosedErr(err) { 154 return 155 } 156 s.log.Printf("send out udp data fail , %s , from : %s", err, srcAddr) 157 } 158 } 159 }() 160 return 161 }