github.com/phuslu/fastdns@v0.8.3-0.20240310041952-69506fc67dd1/server_test.go (about)

     1  package fastdns
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"net"
     8  	"net/netip"
     9  	"os"
    10  	"runtime"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  func allocAddr() string {
    16  	for i := 20001; i < 50000; i++ {
    17  		addr := fmt.Sprintf("127.0.0.1:%d", i)
    18  		conn, err := net.Listen("tcp", addr)
    19  		if err == nil {
    20  			conn.Close()
    21  			return addr
    22  		}
    23  	}
    24  	return ""
    25  }
    26  
    27  type mockServerHandler struct{}
    28  
    29  func (h *mockServerHandler) ServeDNS(rw ResponseWriter, req *Message) {
    30  	log.Printf("%s] %s: TYPE %s", rw.RemoteAddr(), req.Domain, req.Question.Type)
    31  	HOST(rw, req, 300, []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})})
    32  }
    33  
    34  func TestServerHost(t *testing.T) {
    35  	if runtime.GOOS == "windows" {
    36  		// On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
    37  		return
    38  	}
    39  
    40  	s := &Server{
    41  		Handler:  &mockServerHandler{},
    42  		ErrorLog: log.Default(),
    43  		MaxProcs: 1,
    44  	}
    45  
    46  	addr := allocAddr()
    47  	if addr == "" {
    48  		t.Errorf("allocAddr() failed.")
    49  	}
    50  
    51  	go func() {
    52  		err := s.ListenAndServe(addr)
    53  		if err != nil {
    54  			t.Errorf("listen %+v error: %+v", addr, err)
    55  		}
    56  	}()
    57  
    58  	time.Sleep(100 * time.Millisecond)
    59  
    60  	resolver := &net.Resolver{
    61  		PreferGo: true,
    62  		Dial: func(context.Context, string, string) (net.Conn, error) {
    63  			return net.Dial("udp", addr)
    64  		},
    65  	}
    66  
    67  	ips, err := resolver.LookupHost(context.Background(), "example.org")
    68  	if err != nil {
    69  		t.Errorf("LookupHost return error: %+v", err)
    70  	}
    71  	if ips[0] != "1.1.1.1" {
    72  		t.Errorf("LookupHost return mismatched reply: %+v", ips)
    73  	}
    74  }
    75  
    76  func TestServerListenError(t *testing.T) {
    77  	s := &Server{
    78  		Handler:  &mockServerHandler{},
    79  		ErrorLog: log.Default(),
    80  		MaxProcs: 1,
    81  		index:    1,
    82  	}
    83  
    84  	const addr = "127.0.1.1:-1"
    85  
    86  	err := s.ListenAndServe(addr)
    87  	if err == nil {
    88  		t.Errorf("listen %+v shall return error but empty", addr)
    89  	}
    90  }
    91  
    92  func TestServerParseMessageError(t *testing.T) {
    93  	if runtime.GOOS == "windows" {
    94  		// On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
    95  		return
    96  	}
    97  
    98  	s := &Server{
    99  		Handler:  &mockServerHandler{},
   100  		ErrorLog: log.Default(),
   101  		MaxProcs: 1,
   102  	}
   103  
   104  	addr := allocAddr()
   105  	if addr == "" {
   106  		t.Errorf("allocAddr() failed.")
   107  	}
   108  
   109  	go func() {
   110  		err := s.ListenAndServe(addr)
   111  		if err != nil {
   112  			t.Errorf("listen %+v error: %+v", addr, err)
   113  		}
   114  	}()
   115  
   116  	time.Sleep(100 * time.Millisecond)
   117  
   118  	conn, err := net.Dial("udp", addr)
   119  	if err != nil {
   120  		t.Errorf("dial to %+v return error: %+v", addr, err)
   121  	}
   122  
   123  	_, _ = conn.Write([]byte{0x00, 0x02, 0x01, 0x00, 0x00, 0x00})
   124  }
   125  
   126  func TestServerForkHost(t *testing.T) {
   127  	if runtime.GOOS == "windows" {
   128  		// On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
   129  		return
   130  	}
   131  
   132  	os.Setenv("FASTDNS_CHILD_INDEX", "1")
   133  
   134  	s := &ForkServer{
   135  		Handler:  &mockServerHandler{},
   136  		ErrorLog: log.Default(),
   137  		MaxProcs: 1,
   138  	}
   139  
   140  	addr := allocAddr()
   141  	if addr == "" {
   142  		t.Errorf("allocAddr() failed.")
   143  	}
   144  
   145  	go func() {
   146  		err := s.ListenAndServe(addr)
   147  		if err != nil {
   148  			t.Errorf("listen %+v error: %+v", addr, err)
   149  		}
   150  	}()
   151  
   152  	time.Sleep(100 * time.Millisecond)
   153  
   154  	resolver := &net.Resolver{
   155  		PreferGo: true,
   156  		Dial: func(context.Context, string, string) (net.Conn, error) {
   157  			return net.Dial("udp", addr)
   158  		},
   159  	}
   160  
   161  	ips, err := resolver.LookupHost(context.Background(), "example.org")
   162  	if err != nil {
   163  		t.Errorf("LookupHost return error: %+v", err)
   164  	}
   165  	if ips[0] != "1.1.1.1" {
   166  		t.Errorf("LookupHost return mismatched reply: %+v", ips)
   167  	}
   168  }
   169  
   170  func TestServerForkParseMessageError(t *testing.T) {
   171  	if runtime.GOOS == "windows" {
   172  		// On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
   173  		return
   174  	}
   175  
   176  	os.Setenv("FASTDNS_CHILD_INDEX", "1")
   177  
   178  	s := &ForkServer{
   179  		Handler:  &mockServerHandler{},
   180  		ErrorLog: log.Default(),
   181  		MaxProcs: 1,
   182  	}
   183  
   184  	addr := allocAddr()
   185  	if addr == "" {
   186  		t.Errorf("allocAddr() failed.")
   187  	}
   188  
   189  	go func() {
   190  		err := s.ListenAndServe(addr)
   191  		if err != nil {
   192  			t.Errorf("listen %+v error: %+v", addr, err)
   193  		}
   194  	}()
   195  
   196  	time.Sleep(100 * time.Millisecond)
   197  
   198  	conn, err := net.Dial("udp", addr)
   199  	if err != nil {
   200  		t.Errorf("dial to %+v return error: %+v", addr, err)
   201  	}
   202  
   203  	_, _ = conn.Write([]byte{0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
   204  }