From b33b81b46c3725ec6fc7a219f548e4eceb2a3539 Mon Sep 17 00:00:00 2001 From: phuslu Date: Sun, 7 Aug 2022 20:59:31 +0800 Subject: [PATCH] add HOST1 helper --- README.md | 4 ++-- handler.go | 7 +++++++ handler_test.go | 30 ++++++++++++++++++++++++++++++ record_be.go | 43 +++++++++++++++++++++++++++++++++++++++++++ record_le.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d33255b..929e2b6 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,11 @@ func (h *DNSHandler) ServeDNS(rw fastdns.ResponseWriter, req *fastdns.Message) { switch req.Question.Type { case fastdns.TypeA: - fastdns.HOST(rw, req, 60, []netip.Addr{netip.AddrFrom4([4]byte{8, 8, 8, 8})}) + fastdns.HOST1(rw, req, 60, netip.AddrFrom4([4]byte{8, 8, 8, 8})) case fastdns.TypeAAAA: fastdns.HOST(rw, req, 60, []netip.Addr{netip.MustParseAddr("2001:4860:4860::8888")}) case fastdns.TypeCNAME: - fastdns.CNAME(rw, req, 60, []string{"dns.google"}, []netip.Addr{netip.AddrFrom4([4]byte{8, 8, 4, 4})}) + fastdns.CNAME(rw, req, 60, []string{"dns.google"}, []netip.Addr{netip.MustParseAddr("8.8.8.8")}) case fastdns.TypeSRV: fastdns.SRV(rw, req, 60, []net.SRV{{"www.google.com", 443, 1000, 1000}}) case fastdns.TypeNS: diff --git a/handler.go b/handler.go index cddd81e..7f6ae6c 100644 --- a/handler.go +++ b/handler.go @@ -16,6 +16,13 @@ func Error(rw ResponseWriter, req *Message, rcode Rcode) { _, _ = rw.Write(req.Raw) } +// HOST1 replies to the request with the specified Host record. +func HOST1(rw ResponseWriter, req *Message, ttl uint32, ip netip.Addr) { + req.SetResponseHeader(RcodeNoError, 1) + req.Raw = AppendHOST1Record(req.Raw, req, ttl, ip) + _, _ = rw.Write(req.Raw) +} + // HOST replies to the request with the specified Host records. func HOST(rw ResponseWriter, req *Message, ttl uint32, ips []netip.Addr) { req.SetResponseHeader(RcodeNoError, uint16(len(ips))) diff --git a/handler_test.go b/handler_test.go index cab00b3..edf9554 100644 --- a/handler_test.go +++ b/handler_test.go @@ -47,6 +47,28 @@ func TestHandlerError(t *testing.T) { } } +func TestHandlerHost1(t *testing.T) { + var cases = []struct { + Hex string + IP netip.Addr + TTL uint32 + }{ + { + "00028180000100010000000002686b0470687573026c750000010001c00c000100010000012c000401020408", + netip.AddrFrom4([4]byte{1, 2, 4, 8}), + 300, + }, + } + + rw, req := &MemResponseWriter{}, mockMessage() + for _, c := range cases { + HOST1(rw, req, c.TTL, c.IP) + if got, want := hex.EncodeToString(rw.Data), c.Hex; got != want { + t.Errorf("HOST1(%v) error got=%#v want=%#v", c.IP, got, want) + } + } +} + func TestHandlerHost(t *testing.T) { var cases = []struct { Hex string @@ -243,6 +265,14 @@ func (rw *nilResponseWriter) LocalAddr() netip.AddrPort { return netip.AddrPort{ func (rw *nilResponseWriter) Write(p []byte) (n int, err error) { return len(p), nil } +func BenchmarkHOST1(b *testing.B) { + req := mockMessage() + ip := netip.AddrFrom4([4]byte{8, 8, 8, 8}) + for i := 0; i < b.N; i++ { + HOST1(&nilResponseWriter{}, req, 3000, ip) + } +} + func BenchmarkHOST(b *testing.B) { req := mockMessage() ips := []netip.Addr{netip.AddrFrom4([4]byte{8, 8, 8, 8})} diff --git a/record_be.go b/record_be.go index 3986731..6cc59c2 100644 --- a/record_be.go +++ b/record_be.go @@ -53,6 +53,49 @@ func AppendHOSTRecord(dst []byte, req *Message, ttl uint32, ips []netip.Addr) [] return dst } +// AppendHOST1Record appends a Host record to dst and returns the resulting dst. +func AppendHOST1Record(dst []byte, req *Message, ttl uint32, ip netip.Addr) []byte { + b := (*[16]byte)(unsafe.Pointer(&ip)) + if ip.Is4() { + answer := [...]byte{ + // NAME + 0xc0, 0x0c, + // TYPE + 0x00, byte(TypeA), + // CLASS + byte(req.Question.Class >> 8), byte(req.Question.Class), + // TTL + byte(ttl >> 24), byte(ttl >> 16), byte(ttl >> 8), byte(ttl), + // RDLENGTH + 0x00, 0x04, + // RDATA + b[8], b[9], b[10], b[11], + } + dst = append(dst, answer[:]...) + } else { + answer := [...]byte{ + // NAME + 0xc0, 0x0c, + // TYPE + 0x00, byte(TypeAAAA), + // CLASS + byte(req.Question.Class >> 8), byte(req.Question.Class), + // TTL + byte(ttl >> 24), byte(ttl >> 16), byte(ttl >> 8), byte(ttl), + // RDLENGTH + 0x00, 0x10, + // RDATA + b[8], b[9], b[10], b[11], + b[12], b[13], b[14], b[15], + b[0], b[1], b[2], b[3], + b[4], b[5], b[6], b[7], + } + dst = append(dst, answer[:]...) + } + + return dst +} + // AppendCNAMERecord appends the CNAME and Host records to dst and returns the resulting dst. func AppendCNAMERecord(dst []byte, req *Message, ttl uint32, cnames []string, ips []netip.Addr) []byte { offset := 0x0c diff --git a/record_le.go b/record_le.go index 9f39df6..b1769bf 100644 --- a/record_le.go +++ b/record_le.go @@ -8,6 +8,49 @@ import ( "unsafe" ) +// AppendHOST1Record appends a Host records to dst and returns the resulting dst. +func AppendHOST1Record(dst []byte, req *Message, ttl uint32, ip netip.Addr) []byte { + b := (*[16]byte)(unsafe.Pointer(&ip)) + if ip.Is4() { + answer := [...]byte{ + // NAME + 0xc0, 0x0c, + // TYPE + 0x00, byte(TypeA), + // CLASS + byte(req.Question.Class >> 8), byte(req.Question.Class), + // TTL + byte(ttl >> 24), byte(ttl >> 16), byte(ttl >> 8), byte(ttl), + // RDLENGTH + 0x00, 0x04, + // RDATA + b[11], b[10], b[9], b[8], + } + dst = append(dst, answer[:]...) + } else { + answer := [...]byte{ + // NAME + 0xc0, 0x0c, + // TYPE + 0x00, byte(TypeAAAA), + // CLASS + byte(req.Question.Class >> 8), byte(req.Question.Class), + // TTL + byte(ttl >> 24), byte(ttl >> 16), byte(ttl >> 8), byte(ttl), + // RDLENGTH + 0x00, 0x10, + // RDATA + b[7], b[6], b[5], b[4], + b[3], b[2], b[1], b[0], + b[15], b[14], b[13], b[12], + b[11], b[10], b[9], b[8], + } + dst = append(dst, answer[:]...) + } + + return dst +} + // AppendHOSTRecord appends the Host records to dst and returns the resulting dst. func AppendHOSTRecord(dst []byte, req *Message, ttl uint32, ips []netip.Addr) []byte { for _, ip := range ips {