miekg / dns

DNS library in Go
https://miek.nl/2014/august/16/go-dns-package
BSD 3-Clause "New" or "Revised" License
8.03k stars 1.14k forks source link

[ Addition ] Add support for custom DNS RR types #1591

Closed Sharaf5 closed 2 months ago

Sharaf5 commented 2 months ago

Tring to build a custom package for CoreDNS I was successful for every emplemented RR type any other type I define is really created however the writer somehow put extra data in the additional field This behavior is the same for both forwarded request and internal data

What I'm asking for is a way to implement custom types that are not covered by the package

Note1 : I'm building with the aide of chatGPT trying to learn go, so I may be the one who not understand what to do, but it's been 8 days trying to implement those types into the plugin after finding they are not supported, so I'm here

Note2 :

  • your package could test for these types : None A NS MD MF CNAME SOA MB MG MR NULL PTR HINFO MINFO MX TXT RP AFSDB X25 ISDN RT NSAPPTR SIG KEY PX GPOS AAAA LOC NXT EID NIMLOC SRV ATMA NAPTR KX CERT DNAME OPT APL DS SSHFP IPSECKEY RRSIG NSEC DNSKEY DHCID NSEC3 NSEC3PARAM TLSA SMIMEA HIP NINFO RKEY TALINK CDS CDNSKEY OPENPGPKEY CSYNC ZONEMD SVCB HTTPS SPF UINFO UID GID UNSPEC NID L32 L64 LP EUI48 EUI64 NXNAME URI CAA AVC AMTRELAY TKEY TSIG alid IXFR AXFR MAILB MAILA ANY TA DLV Reserved
  • but seem to support reponding correctly only to those types : A, AAAA, CNAME, MX, TXT, SRV, NS, PTR, CAA, TLSA, NAPTR, DNSKEY, DS, NSEC, RRSIG, TSIG, HINFO, RP, TKEY, URI, SVCB, DHCID, SOA

Example ( HTTPS RR type )

Dig, logs and tcpdump showning the same 73 bytes response but dig complains ( about additional section )

(0)  dig @x.x.x.x HTTPS google.com;
;; Warning: Message parser reports malformed message packet.

; <<>> DiG 9.18.28-0ubuntu0.22.04.1-Ubuntu <<>> @x.x.x.x HTTPS google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4590
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; WARNING: Message has 23 extra bytes at end

;; QUESTION SECTION:
;google.com.                    IN      HTTPS

;; Query time: 134 msec
;; SERVER: x.x.x.x#53(x.x.x.x) (UDP)
;; WHEN: Thu Aug 08 03:51:39 EEST 2024
;; MSG SIZE  rcvd: 73
captive  | [Dbg] generateDNSMessage: | 73
captive  | ;; opcode: QUERY, status: NOERROR, id: 4590
captive  | ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
captive  | 
captive  | ;; OPT PSEUDOSECTION:
captive  | ; EDNS: version 0; flags:; udp: 1232
captive  | ; COOKIE: 73dd773ee76cc371
captive  | 
captive  | ;; QUESTION SECTION:
captive  | ;google.com. IN       HTTPS
captive  | 
captive  | ;; ANSWER SECTION:
captive  | google.com.  0       IN      HTTPS    1 . alpn="h2,h3"
captive  | 
captive  | [INFO] x.x.x.x:51714 - 4590 "HTTPS IN google.com. udp 51 false 1232" NOERROR qr,aa,rd 50 0.133482233s
(0)  sudo tcpdump -i dbr_static -s 0 -w dns_capture.pcap port 53;
tcpdump: listening on dbr_static, link-type EN10MB (Ethernet), snapshot length 262144 bytes
^C2 packets captured
2 packets received by filter
0 packets dropped by kernel

/mnt/data/Projects/Prog/0/core
(0)  sudo tcpdump -r dns_capture.pcap -X -s 0;             
reading from file dns_capture.pcap, link-type EN10MB (Ethernet), snapshot length 262144
03:53:12.045655 IP localhost.46752 > x.x.x.x.domain: 9307+ [1au] Type65? google.com. (51)
        0x0000:  4500 004f dee5 0000 4011 8677 0a05 0001  E..O....@..w....
        0x0010:  0a05 0137 b6a0 0035 003b 158e 245b 0120  ...7...5.;..$[..
        0x0020:  0001 0000 0000 0001 0667 6f6f 676c 6503  .........google.
        0x0030:  636f 6d00 0041 0001 0000 2904 d000 0000  com..A....).....
        0x0040:  0000 0c00 0a00 08bb dbc6 de7c 370d 71    ...........|7.q
03:53:12.097785 IP x.x.x.x.domain > Smart.46752: 9307*- 1/0/1 Type65 (73)
        0x0000:  4500 0065 7c3f 4000 4011 a907 0a05 0137  E..e|?@.@......7
        0x0010:  0a05 0001 0035 b6a0 0051 15a4 245b 8500  .....5...Q..$[..
        0x0020:  0001 0001 0000 0001 0667 6f6f 676c 6503  .........google.
        0x0030:  636f 6d00 0041 0001 0667 6f6f 676c 6503  com..A...google.
        0x0040:  636f 6d00 0041 0001 0000 0000 0000 0000  com..A..........
        0x0050:  2904 d000 0000 0000 0c00 0a00 08bb dbc6  )...............
        0x0060:  de7c 370d 71                             .|7.q

where we define a new type

package captive

import (
    "fmt"
    "github.com/miekg/dns"
)

// HTTPS represents a DNS HTTPS record.
type HTTPS struct {
    dns.RR_Header
    Priority uint16
    Target   string
    Params   string
}

// String returns the string representation of the HTTPS record.
func (rr *HTTPS) String() string {
    return fmt.Sprintf("%s %d %s %s", rr.RR_Header.String(), rr.Priority, rr.Target, rr.Params)
}

// Len returns the length of the DNS message for this record.
func (rr *HTTPS) len() int {
    return len(rr.String())
    // return len(rr.RR_Header.Name) + 12 + len(rr.Target) + len(rr.Params)
}

// pack and unpack method has no effect on the behavior and even no logs from it when defined

where we call the new type

    case dns.TypeHTTPS:
        priority, ok := opt["priority"].(float64)
        if !ok {
            return nil, fmt.Errorf("invalid HTTPS record format: missing priority field")
        }
        params, ok := opt["params"].(string)
        if !ok {
            return nil, fmt.Errorf("invalid HTTPS record format: missing params field")
        }
        rr = &HTTPS{
            RR_Header: dns.RR_Header{
                Name:  name,
                Rrtype: dns.TypeHTTPS,
                Class: dns.ClassINET,
                Ttl:   uint32(ttl),
            },
            Priority: uint16(priority),
            Target:   content,
            Params:   params,
        }

response writer :

func (c *Captive) generateDNSMessage(w dns.ResponseWriter, r *dns.Msg, records []dns.RR, q ...[]dns.Question) (int, error) {
    msg := new(dns.Msg)
    msg.SetReply(r)
    if len(q) > 0 { msg.Question = q[0] }
    msg.Answer = records
    msg.Authoritative = true
    // msg.Compress = false

    var additional []dns.RR
    for _, rr := range r.Extra {
        if rr.Header().Rrtype != dns.TypeOPT {
            additional = append(additional, rr)
        }
    }
    msg.Extra = additional

    err := w.WriteMsg(msg)
    if err != nil {
        c.logMsg("generateDNSMessage", "Err25", err)
        return dns.RcodeServerFailure, err
    }
    c.logMsg("generateDNSMessage", "Dbg", msg.Len(), "\n", msg)

    return dns.RcodeSuccess, nil
}
miekg commented 2 months ago

I don't understand exactly what you want, but custom RRs with custom code points are supported by the PrivateRR type. Think there are tests that show how to use it.

Sharaf5 commented 2 months ago

will try it thanks