diff --git a/dialer.go b/dialer.go index d792700..4b8b66c 100644 --- a/dialer.go +++ b/dialer.go @@ -44,8 +44,7 @@ func DialerFromURL(s string, cDialer Dialer) (Dialer, error) { case "socks5": return NewSOCKS5(addr, user, pass, cDialer, nil) case "ss": - p, err := NewSS(addr, user, pass, cDialer, nil) - return p, err + return NewSS(addr, user, pass, cDialer, nil) } return nil, errors.New("unknown schema '" + u.Scheme + "'") diff --git a/dns.go b/dns.go index cb0ebc1..859908d 100644 --- a/dns.go +++ b/dns.go @@ -77,21 +77,27 @@ func NewDNS(addr, raddr string, sDialer Dialer) (*DNS, error) { // ListenAndServe . func (s *DNS) ListenAndServe() { + go s.ListenAndServeTCP() + s.ListenAndServeUDP() +} + +// ListenAndServeUDP . +func (s *DNS) ListenAndServeUDP() { c, err := net.ListenPacket("udp", s.addr) if err != nil { - logf("failed to listen on %s: %v", s.addr, err) + logf("proxy-dns failed to listen on %s: %v", s.addr, err) return } defer c.Close() - logf("listening UDP on %s", s.addr) + logf("proxy-dns listening UDP on %s", s.addr) for { data := make([]byte, DNSUDPMaxLen) n, clientAddr, err := c.ReadFrom(data) if err != nil { - logf("DNS local read error: %v", err) + logf("proxy-dns DNS local read error: %v", err) continue } @@ -101,11 +107,14 @@ func (s *DNS) ListenAndServe() { query := parseQuery(data) domain := query.DomainName - dnsServer := s.GetServer(domain) + dnsServer := s.dnsServer + if dnsServer == "" { + dnsServer = s.GetServer(domain) + } rc, err := s.sDialer.NextDialer(domain+":53").Dial("tcp", dnsServer) if err != nil { - logf("failed to connect to server %v: %v", dnsServer, err) + logf("proxy-dns failed to connect to server %v: %v", dnsServer, err) return } defer rc.Close() @@ -170,6 +179,105 @@ func (s *DNS) ListenAndServe() { } } +// ListenAndServeTCP . +func (s *DNS) ListenAndServeTCP() { + l, err := net.Listen("tcp", s.addr) + if err != nil { + logf("proxy-dns-tcp error: %v", err) + return + } + + logf("proxy-dns-tcp listening TCP on %s", s.addr) + + for { + c, err := l.Accept() + if err != nil { + logf("proxy-dns-tcp error: failed to accept: %v", err) + continue + } + go s.ServeTCP(c) + } +} + +// ServeTCP . +func (s *DNS) ServeTCP(c net.Conn) { + defer c.Close() + + if c, ok := c.(*net.TCPConn); ok { + c.SetKeepAlive(true) + } + + var reqLen uint16 + if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil { + logf("proxy-dns-tcp failed to read request length: %v", err) + return + } + + reqMsg := make([]byte, reqLen) + _, err := io.ReadFull(c, reqMsg) + if err != nil { + logf("proxy-dns-tcp error in read reqMsg %s\n", err) + return + } + + query := parseQuery(reqMsg) + domain := query.DomainName + + dnsServer := s.dnsServer + if dnsServer == "" { + dnsServer = s.GetServer(domain) + } + + rc, err := s.sDialer.NextDialer(domain+":53").Dial("tcp", dnsServer) + if err != nil { + logf("proxy-dns failed to connect to server %v: %v", dnsServer, err) + return + } + defer rc.Close() + + binary.Write(rc, binary.BigEndian, reqLen) + binary.Write(rc, binary.BigEndian, reqMsg) + + var respLen uint16 + if err := binary.Read(rc, binary.BigEndian, &respLen); err != nil { + logf("proxy-dns-tcp failed to read response length: %v", err) + return + } + + respMsg := make([]byte, respLen) + _, err = io.ReadFull(rc, respMsg) + if err != nil { + logf("proxy-dns-tcp error in read respMsg %s\n", err) + return + } + + var ip string + if respLen > 0 { + query := parseQuery(respMsg) + if (query.QueryType == DNSQueryTypeA || query.QueryType == DNSQueryTypeAAAA) && + len(respMsg) > query.Offset { + + answers := parseAnswers(respMsg[query.Offset:]) + + for _, answer := range answers { + if answer.IP != "" { + ip += answer.IP + "," + } + + for _, h := range s.answerHandlers { + h(query.DomainName, answer.IP) + } + } + } + + binary.Write(c, binary.BigEndian, respLen) + binary.Write(c, binary.BigEndian, respMsg) + } + + logf("proxy-dns-tcp %s <-> %s, type: %d, %s: %s", c.RemoteAddr(), dnsServer, query.QueryType, domain, ip) + +} + // SetServer . func (s *DNS) SetServer(domain, server string) { s.dnsServerMap[domain] = server diff --git a/dnstun.go b/dnstun.go index 2c0c04c..be6de21 100644 --- a/dnstun.go +++ b/dnstun.go @@ -9,7 +9,7 @@ type DNSTun struct { raddr string - udp *DNS + dns *DNS tcp *TCPTun } @@ -22,19 +22,14 @@ func NewDNSTun(addr, raddr string, sDialer Dialer) (*DNSTun, error) { raddr: raddr, } - s.udp, _ = NewDNS(addr, raddr, sDialer) - s.tcp, _ = NewTCPTun(addr, raddr, sDialer) + s.dns, _ = NewDNS(addr, raddr, sDialer) return s, nil } // ListenAndServe . func (s *DNSTun) ListenAndServe() { - if s.udp != nil { - go s.udp.ListenAndServe() - } - - if s.tcp != nil { - s.tcp.ListenAndServe() + if s.dns != nil { + go s.dns.ListenAndServe() } } diff --git a/server.go b/server.go index e0a3907..426af03 100644 --- a/server.go +++ b/server.go @@ -44,8 +44,7 @@ func ServerFromURL(s string, sDialer Dialer) (Server, error) { case "socks5": return NewSOCKS5(addr, user, pass, nil, sDialer) case "ss": - p, err := NewSS(addr, user, pass, nil, sDialer) - return p, err + return NewSS(addr, user, pass, nil, sDialer) case "redir": return NewRedirProxy(addr, sDialer) case "tcptun":