mirror of
				https://github.com/nadoo/glider.git
				synced 2025-11-04 15:52:38 +08:00 
			
		
		
		
	ss: add udp support as server mode
This commit is contained in:
		
							parent
							
								
									8bc8ee3876
								
							
						
					
					
						commit
						30f340dc86
					
				
							
								
								
									
										27
									
								
								conn.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								conn.go
									
									
									
									
									
								
							@ -52,3 +52,30 @@ func relay(left, right net.Conn) (int64, int64, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return n, rs.N, err
 | 
						return n, rs.N, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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, raddr, err := src.ReadFrom(buf)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if srcIncluded { // server -> client: add original packet source
 | 
				
			||||||
 | 
								srcAddr := 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 := SplitAddr(buf[:n])
 | 
				
			||||||
 | 
								_, err = dst.WriteTo(buf[len(srcAddr):n], target)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								socks5.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								socks5.go
									
									
									
									
									
								
							@ -326,7 +326,7 @@ func (s *SOCKS5) handshake(rw io.ReadWriter) (Addr, error) {
 | 
				
			|||||||
func (a Addr) String() string {
 | 
					func (a Addr) String() string {
 | 
				
			||||||
	var host, port string
 | 
						var host, port string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch a[0] { // address type
 | 
						switch ATYP(a[0]) { // address type
 | 
				
			||||||
	case socks5Domain:
 | 
						case socks5Domain:
 | 
				
			||||||
		host = string(a[2 : 2+int(a[1])])
 | 
							host = string(a[2 : 2+int(a[1])])
 | 
				
			||||||
		port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1]))
 | 
							port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1]))
 | 
				
			||||||
@ -341,6 +341,16 @@ func (a Addr) String() string {
 | 
				
			|||||||
	return net.JoinHostPort(host, port)
 | 
						return net.JoinHostPort(host, port)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UoT udp over tcp
 | 
				
			||||||
 | 
					func UoT(b byte) bool {
 | 
				
			||||||
 | 
						return b&0x8 == 0x8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ATYP return the address type
 | 
				
			||||||
 | 
					func ATYP(b byte) int {
 | 
				
			||||||
 | 
						return int(b &^ 0x8)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func readAddr(r io.Reader, b []byte) (Addr, error) {
 | 
					func readAddr(r io.Reader, b []byte) (Addr, error) {
 | 
				
			||||||
	if len(b) < MaxAddrLen {
 | 
						if len(b) < MaxAddrLen {
 | 
				
			||||||
		return nil, io.ErrShortBuffer
 | 
							return nil, io.ErrShortBuffer
 | 
				
			||||||
@ -350,7 +360,7 @@ func readAddr(r io.Reader, b []byte) (Addr, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch b[0] {
 | 
						switch ATYP(b[0]) {
 | 
				
			||||||
	case socks5Domain:
 | 
						case socks5Domain:
 | 
				
			||||||
		_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
 | 
							_, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@ -381,7 +391,7 @@ func SplitAddr(b []byte) Addr {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch b[0] {
 | 
						switch ATYP(b[0]) {
 | 
				
			||||||
	case socks5Domain:
 | 
						case socks5Domain:
 | 
				
			||||||
		if len(b) < 2 {
 | 
							if len(b) < 2 {
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										99
									
								
								ss.go
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								ss.go
									
									
									
									
									
								
							@ -5,16 +5,21 @@ import (
 | 
				
			|||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/shadowsocks/go-shadowsocks2/core"
 | 
						"github.com/shadowsocks/go-shadowsocks2/core"
 | 
				
			||||||
 | 
						"github.com/shadowsocks/go-shadowsocks2/socks"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const udpBufSize = 64 * 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SS .
 | 
					// SS .
 | 
				
			||||||
type SS struct {
 | 
					type SS struct {
 | 
				
			||||||
	*Forwarder
 | 
						*Forwarder
 | 
				
			||||||
	sDialer Dialer
 | 
						sDialer Dialer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	core.StreamConnCipher
 | 
						core.Cipher
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewSS returns a shadowsocks proxy.
 | 
					// NewSS returns a shadowsocks proxy.
 | 
				
			||||||
@ -27,51 +32,57 @@ func NewSS(addr, method, pass string, cDialer Dialer, sDialer Dialer) (*SS, erro
 | 
				
			|||||||
	s := &SS{
 | 
						s := &SS{
 | 
				
			||||||
		Forwarder: NewForwarder(addr, cDialer),
 | 
							Forwarder: NewForwarder(addr, cDialer),
 | 
				
			||||||
		sDialer:   sDialer,
 | 
							sDialer:   sDialer,
 | 
				
			||||||
		StreamConnCipher: ciph,
 | 
							Cipher:    ciph,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return s, nil
 | 
						return s, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListenAndServe shadowsocks requests as a server.
 | 
					// ListenAndServe serves ss requests.
 | 
				
			||||||
func (s *SS) ListenAndServe() {
 | 
					func (s *SS) ListenAndServe() {
 | 
				
			||||||
 | 
						go s.ListenAndServeUDP()
 | 
				
			||||||
 | 
						s.ListenAndServeTCP()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListenAndServeTCP serves tcp ss requests.
 | 
				
			||||||
 | 
					func (s *SS) ListenAndServeTCP() {
 | 
				
			||||||
	l, err := net.Listen("tcp", s.addr)
 | 
						l, err := net.Listen("tcp", s.addr)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logf("failed to listen on %s: %v", s.addr, err)
 | 
							logf("proxy-ss failed to listen on %s: %v", s.addr, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	logf("listening TCP on %s", s.addr)
 | 
						logf("proxy-ss listening TCP on %s", s.addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		c, err := l.Accept()
 | 
							c, err := l.Accept()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			logf("failed to accept: %v", err)
 | 
								logf("proxy-ss failed to accept: %v", err)
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		go s.Serve(c)
 | 
							go s.ServeTCP(c)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Serve .
 | 
					// ServeTCP .
 | 
				
			||||||
func (s *SS) Serve(c net.Conn) {
 | 
					func (s *SS) ServeTCP(c net.Conn) {
 | 
				
			||||||
	defer c.Close()
 | 
						defer c.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if c, ok := c.(*net.TCPConn); ok {
 | 
						if c, ok := c.(*net.TCPConn); ok {
 | 
				
			||||||
		c.SetKeepAlive(true)
 | 
							c.SetKeepAlive(true)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c = s.StreamConnCipher.StreamConn(c)
 | 
						c = s.StreamConn(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tgt, err := ReadAddr(c)
 | 
						tgt, err := ReadAddr(c)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logf("failed to get target address: %v", err)
 | 
							logf("proxy-ss failed to get target address: %v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc, err := s.sDialer.Dial("tcp", tgt.String())
 | 
						rc, err := s.sDialer.Dial("tcp", tgt.String())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logf("failed to connect to target: %v", err)
 | 
							logf("proxy-ss failed to connect to target: %v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer rc.Close()
 | 
						defer rc.Close()
 | 
				
			||||||
@ -88,6 +99,70 @@ func (s *SS) Serve(c net.Conn) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListenAndServeUDP serves udp ss requests.
 | 
				
			||||||
 | 
					func (s *SS) ListenAndServeUDP() {
 | 
				
			||||||
 | 
						c, err := net.ListenPacket("udp", s.addr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logf("proxy-ss failed to listen on %s: %v", s.addr, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer c.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logf("proxy-ss listening UDP on %s", s.addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c = s.PacketConn(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var nm sync.Map
 | 
				
			||||||
 | 
						buf := make([]byte, udpBufSize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							n, raddr, err := c.ReadFrom(buf)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logf("UDP remote read error: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tgtAddr := socks.SplitAddr(buf[:n])
 | 
				
			||||||
 | 
							if tgtAddr == nil {
 | 
				
			||||||
 | 
								logf("failed to split target address from packet: %q", buf[:n])
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tgtUDPAddr, err := net.ResolveUDPAddr("udp", tgtAddr.String())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logf("failed to resolve target UDP address: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							payload := buf[len(tgtAddr):n]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pc net.PacketConn
 | 
				
			||||||
 | 
							v, _ := nm.Load(raddr.String())
 | 
				
			||||||
 | 
							if v == nil {
 | 
				
			||||||
 | 
								pc, err = net.ListenPacket("udp", "")
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									logf("UDP remote listen error: %v", err)
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								nm.Store(raddr.String(), pc)
 | 
				
			||||||
 | 
								go func() {
 | 
				
			||||||
 | 
									timedCopy(c, raddr, pc, 5*time.Minute, true)
 | 
				
			||||||
 | 
									pc.Close()
 | 
				
			||||||
 | 
									nm.Delete(raddr.String())
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pc = pc.(net.PacketConn)
 | 
				
			||||||
 | 
							_, err = pc.WriteTo(payload, tgtUDPAddr) // accept only UDPAddr despite the signature
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logf("UDP remote write error: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Dial connects to the address addr on the network net via the proxy.
 | 
					// Dial connects to the address addr on the network net via the proxy.
 | 
				
			||||||
func (s *SS) Dial(network, addr string) (net.Conn, error) {
 | 
					func (s *SS) Dial(network, addr string) (net.Conn, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ type TCPTun struct {
 | 
				
			|||||||
	raddr string
 | 
						raddr string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewTCPTun returns a redirect proxy.
 | 
					// NewTCPTun returns a tcptun proxy.
 | 
				
			||||||
func NewTCPTun(addr, raddr string, sDialer Dialer) (*TCPTun, error) {
 | 
					func NewTCPTun(addr, raddr string, sDialer Dialer) (*TCPTun, error) {
 | 
				
			||||||
	s := &TCPTun{
 | 
						s := &TCPTun{
 | 
				
			||||||
		Forwarder: NewForwarder(addr, nil),
 | 
							Forwarder: NewForwarder(addr, nil),
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user