mirror of
				https://github.com/nadoo/glider.git
				synced 2025-11-04 15:52:38 +08:00 
			
		
		
		
	ss: support udp in server mode
This commit is contained in:
		
							parent
							
								
									3c53bd9727
								
							
						
					
					
						commit
						6e3423588a
					
				
							
								
								
									
										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
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								dns.go
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								dns.go
									
									
									
									
									
								
							@ -138,10 +138,15 @@ func (s *DNS) ListenAndServe() {
 | 
				
			|||||||
			// length is not needed in udp dns response. (2 bytes)
 | 
								// length is not needed in udp dns response. (2 bytes)
 | 
				
			||||||
			// SEE RFC1035, section 4.2.2 TCP: The message is prefixed with a two byte length field which gives the message length, excluding the two byte length field.
 | 
								// SEE RFC1035, section 4.2.2 TCP: The message is prefixed with a two byte length field which gives the message length, excluding the two byte length field.
 | 
				
			||||||
			if respLen > 0 {
 | 
								if respLen > 0 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// run handle functions before send to client so RULE and IPSET can take effect
 | 
				
			||||||
 | 
									// TODO: add PRE_HANDLERS
 | 
				
			||||||
				query := parseQuery(respMsg)
 | 
									query := parseQuery(respMsg)
 | 
				
			||||||
				if (query.QueryType == DNSQueryTypeA || query.QueryType == DNSQueryTypeAAAA) &&
 | 
									if (query.QueryType == DNSQueryTypeA || query.QueryType == DNSQueryTypeAAAA) &&
 | 
				
			||||||
					len(respMsg) > query.Offset {
 | 
										len(respMsg) > query.Offset {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					answers := parseAnswers(respMsg[query.Offset:])
 | 
										answers := parseAnswers(respMsg[query.Offset:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					for _, answer := range answers {
 | 
										for _, answer := range answers {
 | 
				
			||||||
						if answer.IP != "" {
 | 
											if answer.IP != "" {
 | 
				
			||||||
							ip += answer.IP + ","
 | 
												ip += answer.IP + ","
 | 
				
			||||||
@ -150,9 +155,7 @@ func (s *DNS) ListenAndServe() {
 | 
				
			|||||||
						for _, h := range s.answerHandlers {
 | 
											for _, h := range s.answerHandlers {
 | 
				
			||||||
							h(query.DomainName, answer.IP)
 | 
												h(query.DomainName, answer.IP)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				_, err = c.WriteTo(respMsg, clientAddr)
 | 
									_, err = c.WriteTo(respMsg, clientAddr)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								main.go
									
									
									
									
									
								
							@ -13,20 +13,20 @@ const VERSION = "0.4.3"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func dialerFromConf() Dialer {
 | 
					func dialerFromConf() Dialer {
 | 
				
			||||||
	// global forwarders in xx.conf
 | 
						// global forwarders in xx.conf
 | 
				
			||||||
	var forwarders []Dialer
 | 
						var fwdrs []Dialer
 | 
				
			||||||
	for _, chain := range conf.Forward {
 | 
						for _, chain := range conf.Forward {
 | 
				
			||||||
		var forward Dialer
 | 
							var fwdr Dialer
 | 
				
			||||||
		var err error
 | 
							var err error
 | 
				
			||||||
		for _, url := range strings.Split(chain, ",") {
 | 
							for _, url := range strings.Split(chain, ",") {
 | 
				
			||||||
			forward, err = DialerFromURL(url, forward)
 | 
								fwdr, err = DialerFromURL(url, fwdr)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				log.Fatal(err)
 | 
									log.Fatal(err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		forwarders = append(forwarders, forward)
 | 
							fwdrs = append(fwdrs, fwdr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NewStrategyDialer(conf.Strategy, forwarders, conf.CheckWebSite, conf.CheckDuration)
 | 
						return NewStrategyDialer(conf.Strategy, fwdrs, conf.CheckWebSite, conf.CheckDuration)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
@ -55,10 +55,10 @@ func main() {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// rule
 | 
							// rule
 | 
				
			||||||
		for _, frwder := range conf.rules {
 | 
							for _, fwdr := range conf.rules {
 | 
				
			||||||
			for _, domain := range frwder.Domain {
 | 
								for _, domain := range fwdr.Domain {
 | 
				
			||||||
				if len(frwder.DNSServer) > 0 {
 | 
									if len(fwdr.DNSServer) > 0 {
 | 
				
			||||||
					dns.SetServer(domain, frwder.DNSServer[0])
 | 
										dns.SetServer(domain, fwdr.DNSServer[0])
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								rule.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								rule.go
									
									
									
									
									
								
							@ -21,20 +21,20 @@ func NewRuleDialer(rules []*RuleConf, gDialer Dialer) *RuleDialer {
 | 
				
			|||||||
	rd := &RuleDialer{gDialer: gDialer}
 | 
						rd := &RuleDialer{gDialer: gDialer}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, r := range rules {
 | 
						for _, r := range rules {
 | 
				
			||||||
		var forwarders []Dialer
 | 
							var fwdrs []Dialer
 | 
				
			||||||
		for _, chain := range r.Forward {
 | 
							for _, chain := range r.Forward {
 | 
				
			||||||
			var forward Dialer
 | 
								var fwdr Dialer
 | 
				
			||||||
			var err error
 | 
								var err error
 | 
				
			||||||
			for _, url := range strings.Split(chain, ",") {
 | 
								for _, url := range strings.Split(chain, ",") {
 | 
				
			||||||
				forward, err = DialerFromURL(url, forward)
 | 
									fwdr, err = DialerFromURL(url, fwdr)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					log.Fatal(err)
 | 
										log.Fatal(err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			forwarders = append(forwarders, forward)
 | 
								fwdrs = append(fwdrs, fwdr)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sDialer := NewStrategyDialer(r.Strategy, forwarders, r.CheckWebSite, r.CheckDuration)
 | 
							sDialer := NewStrategyDialer(r.Strategy, fwdrs, r.CheckWebSite, r.CheckDuration)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, domain := range r.Domain {
 | 
							for _, domain := range r.Domain {
 | 
				
			||||||
			rd.domainMap.Store(domain, sDialer)
 | 
								rd.domainMap.Store(domain, sDialer)
 | 
				
			||||||
@ -123,7 +123,7 @@ func (rd *RuleDialer) AddDomainIP(domain, ip string) error {
 | 
				
			|||||||
			// find in domainMap
 | 
								// find in domainMap
 | 
				
			||||||
			if dialer, ok := rd.domainMap.Load(pDomain); ok {
 | 
								if dialer, ok := rd.domainMap.Load(pDomain); ok {
 | 
				
			||||||
				rd.ipMap.Store(ip, dialer)
 | 
									rd.ipMap.Store(ip, dialer)
 | 
				
			||||||
				logf("rule add `ip=%s`, based on rule: `domain=%s`, domain/ip: %s/%s\n", ip, pDomain, domain, ip)
 | 
									logf("rule add ip=%s, based on rule: domain=%s & domain/ip: %s/%s\n", ip, pDomain, domain, ip)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -126,7 +126,7 @@ func (s *SOCKS5) Serve(c net.Conn) {
 | 
				
			|||||||
		if err, ok := err.(net.Error); ok && err.Timeout() {
 | 
							if err, ok := err.(net.Error); ok && err.Timeout() {
 | 
				
			||||||
			return // ignore i/o timeout
 | 
								return // ignore i/o timeout
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		logf("relay error: %v", err)
 | 
							logf("proxy-socks5 relay error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										85
									
								
								ss.go
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								ss.go
									
									
									
									
									
								
							@ -5,6 +5,8 @@ import (
 | 
				
			|||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/shadowsocks/go-shadowsocks2/core"
 | 
						"github.com/shadowsocks/go-shadowsocks2/core"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -37,6 +39,12 @@ func NewSS(addr, method, pass string, cDialer Dialer, sDialer Dialer) (*SS, erro
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ListenAndServe serves ss requests.
 | 
					// 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("proxy-ss failed to listen on %s: %v", s.addr, err)
 | 
							logf("proxy-ss failed to listen on %s: %v", s.addr, err)
 | 
				
			||||||
@ -51,12 +59,12 @@ func (s *SS) ListenAndServe() {
 | 
				
			|||||||
			logf("proxy-ss 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 serves tcp ss requests.
 | 
				
			||||||
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 {
 | 
				
			||||||
@ -125,7 +133,76 @@ func (s *SS) Serve(c net.Conn) {
 | 
				
			|||||||
		if err, ok := err.(net.Error); ok && err.Timeout() {
 | 
							if err, ok := err.(net.Error); ok && err.Timeout() {
 | 
				
			||||||
			return // ignore i/o timeout
 | 
								return // ignore i/o timeout
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		logf("relay error: %v", err)
 | 
							logf("proxy-ss relay error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListenAndServeUDP serves udp ss requests.
 | 
				
			||||||
 | 
					// TODO: Forwarder chain not supported now.
 | 
				
			||||||
 | 
					func (s *SS) ListenAndServeUDP() {
 | 
				
			||||||
 | 
						c, err := net.ListenPacket("udp", s.addr)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logf("proxy-ss-udp failed to listen on %s: %v", s.addr, err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer c.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logf("proxy-ss-udp 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("proxy-ss-udp remote read error: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tgtAddr := SplitAddr(buf[:n])
 | 
				
			||||||
 | 
							if tgtAddr == nil {
 | 
				
			||||||
 | 
								logf("proxy-ss-udp failed to split target address from packet: %q", buf[:n])
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tgtUDPAddr, err := net.ResolveUDPAddr("udp", tgtAddr.String())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logf("proxy-ss-udp failed to resolve target UDP address: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							logf("proxy-ss-udp %s <-> %s", raddr, tgtAddr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							payload := buf[len(tgtAddr):n]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var pc net.PacketConn
 | 
				
			||||||
 | 
							v, ok := nm.Load(raddr.String())
 | 
				
			||||||
 | 
							if !ok && v == nil {
 | 
				
			||||||
 | 
								pc, err = net.ListenPacket("udp", "")
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									logf("proxy-ss-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())
 | 
				
			||||||
 | 
								}()
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pc = v.(net.PacketConn)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							_, err = pc.WriteTo(payload, tgtUDPAddr) // accept only UDPAddr despite the signature
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logf("proxy-ss-udp remote write error: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user