66 "errors"
77 "fmt"
88 "net"
9+ "sync"
910 "syscall"
11+ "time"
1012
1113 "github.com/LiamHaworth/go-tproxy"
1214 "github.com/go-log/log"
@@ -121,17 +123,15 @@ func (h *udpRedirectHandler) Init(options ...HandlerOption) {
121123 }
122124}
123125
124- func (h * udpRedirectHandler ) Handle (c net.Conn ) {
125- defer c .Close ()
126+ func (h * udpRedirectHandler ) Handle (conn net.Conn ) {
127+ defer conn .Close ()
126128
127- conn , ok := c .( * udpRedirectServerConn )
129+ raddr , ok := conn . LocalAddr ().( * net. UDPAddr )
128130 if ! ok {
129- log .Log ("wrong connection type" )
131+ log .Log ("[red-udp] wrong connection type" )
130132 return
131133 }
132134
133- raddr := conn .DstAddr ()
134-
135135 var cc net.Conn
136136 var err error
137137 if h .options .Chain .IsEmpty () {
@@ -167,11 +167,8 @@ func (h *udpRedirectHandler) Handle(c net.Conn) {
167167}
168168
169169type udpRedirectListener struct {
170- ln * net.UDPConn
171- connChan chan net.Conn
172- errChan chan error
173- connMap udpConnMap
174- config * UDPListenConfig
170+ * net.UDPConn
171+ config * UDPListenConfig
175172}
176173
177174// UDPRedirectListener creates a Listener for UDP transparent proxy server.
@@ -189,103 +186,72 @@ func UDPRedirectListener(addr string, cfg *UDPListenConfig) (Listener, error) {
189186 if cfg == nil {
190187 cfg = & UDPListenConfig {}
191188 }
189+ return & udpRedirectListener {
190+ UDPConn : ln ,
191+ config : cfg ,
192+ }, nil
193+ }
192194
193- backlog := cfg .Backlog
194- if backlog <= 0 {
195- backlog = defaultBacklog
196- }
195+ func (l * udpRedirectListener ) Accept () (conn net.Conn , err error ) {
196+ b := make ([]byte , mediumBufferSize )
197197
198- l := & udpRedirectListener {
199- ln : ln ,
200- connChan : make (chan net.Conn , backlog ),
201- errChan : make (chan error , 1 ),
202- config : cfg ,
198+ n , raddr , dstAddr , err := tproxy .ReadFromUDP (l .UDPConn , b )
199+ if err != nil {
200+ log .Logf ("[red-udp] %s : %s" , l .Addr (), err )
201+ return
203202 }
204- go l .listenLoop ()
205- return l , nil
206- }
203+ log .Logf ("[red-udp] %s: %s -> %s" , l .Addr (), raddr , dstAddr )
207204
208- func (l * udpRedirectListener ) listenLoop () {
209- for {
210- b := make ([]byte , mediumBufferSize )
211- n , raddr , dstAddr , err := tproxy .ReadFromUDP (l .ln , b )
212- if err != nil {
213- log .Logf ("[red-udp] peer -> %s : %s" , l .Addr (), err )
214- l .Close ()
215- l .errChan <- err
216- close (l .errChan )
217- return
218- }
219-
220- conn , ok := l .connMap .Get (raddr .String ())
221- if ! ok {
222- conn = newUDPServerConn (l .ln , raddr , & udpServerConnConfig {
223- ttl : l .config .TTL ,
224- qsize : l .config .QueueSize ,
225- onClose : func () {
226- l .connMap .Delete (raddr .String ())
227- log .Logf ("[red-udp] %s closed (%d)" , raddr , l .connMap .Size ())
228- },
229- })
230-
231- cc := udpRedirectServerConn {
232- udpServerConn : conn ,
233- dstAddr : dstAddr ,
234- }
235- select {
236- case l .connChan <- cc :
237- l .connMap .Set (raddr .String (), conn )
238- log .Logf ("[red-udp] %s -> %s (%d)" , raddr , l .Addr (), l .connMap .Size ())
239- default :
240- conn .Close ()
241- log .Logf ("[red-udp] %s - %s: connection queue is full (%d)" ,
242- raddr , l .Addr (), cap (l .connChan ))
243- }
244- }
205+ c , err := tproxy .DialUDP ("udp" , dstAddr , raddr )
206+ if err != nil {
207+ log .Logf ("[red-udp] %s -> %s : %s" , raddr , dstAddr , err )
208+ return
209+ }
245210
246- select {
247- case conn .rChan <- b [:n ]:
248- if Debug {
249- log .Logf ("[red-udp] %s >>> %s : length %d" , raddr , l .Addr (), n )
250- }
251- default :
252- log .Logf ("[red-udp] %s -> %s : recv queue is full (%d)" ,
253- raddr , l .Addr (), cap (conn .rChan ))
254- }
211+ ttl := l .config .TTL
212+ if ttl <= 0 {
213+ ttl = defaultTTL
255214 }
256- }
257215
258- func (l * udpRedirectListener ) Accept () (conn net.Conn , err error ) {
259- var ok bool
260- select {
261- case conn = <- l .connChan :
262- case err , ok = <- l .errChan :
263- if ! ok {
264- err = errors .New ("accpet on closed listener" )
265- }
216+ conn = & udpRedirectServerConn {
217+ Conn : c ,
218+ buf : b [:n ],
219+ ttl : ttl ,
266220 }
267221 return
268222}
269223
270224func (l * udpRedirectListener ) Addr () net.Addr {
271- return l .ln .LocalAddr ()
225+ return l .UDPConn .LocalAddr ()
272226}
273227
274- func (l * udpRedirectListener ) Close () error {
275- err := l .ln .Close ()
276- l .connMap .Range (func (k interface {}, v * udpServerConn ) bool {
277- v .Close ()
278- return true
279- })
280-
281- return err
228+ type udpRedirectServerConn struct {
229+ net.Conn
230+ buf []byte
231+ ttl time.Duration
232+ once sync.Once
282233}
283234
284- type udpRedirectServerConn struct {
285- * udpServerConn
286- dstAddr * net.UDPAddr
235+ func (c * udpRedirectServerConn ) Read (b []byte ) (n int , err error ) {
236+ if c .ttl > 0 {
237+ c .SetReadDeadline (time .Now ().Add (c .ttl ))
238+ defer c .SetReadDeadline (time.Time {})
239+ }
240+ c .once .Do (func () {
241+ n = copy (b , c .buf )
242+ c .buf = nil
243+ })
244+
245+ if n == 0 {
246+ n , err = c .Conn .Read (b )
247+ }
248+ return
287249}
288250
289- func (c * udpRedirectServerConn ) DstAddr () * net.UDPAddr {
290- return c .dstAddr
251+ func (c * udpRedirectServerConn ) Write (b []byte ) (n int , err error ) {
252+ if c .ttl > 0 {
253+ c .SetWriteDeadline (time .Now ().Add (c .ttl ))
254+ defer c .SetWriteDeadline (time.Time {})
255+ }
256+ return c .Conn .Write (b )
291257}
0 commit comments