miekg / dns

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

dns.RR - JSON Unmarshal #650

Open Neo-Desktop opened 6 years ago

Neo-Desktop commented 6 years ago

Hello!

I'm attempting to populate record data from JSON. Marshaling RRs -to- JSON has been handled by the language already. Unmarshaling back to the requisite resource types is another matter entirely.

I believe this functionality is best handled by the package owner where it can be available to all.

Please implement the Unmarshaler interface for dns.RR()

Many Thanks!

miekg commented 6 years ago

[ Quoting notifications@github.com in "[miekg/dns] dns.RR - JSON Unmarshal..." ]

Hello!

I'm attempting to populate record data from JSON. Marshaling RRs -to- JSON has been handled by the language already. Unmarshaling back to the requisite resource types is another matter entirely.

I believe this functionality is best handled by the package owner where it can be available to all.

Please implement the Unmarshaler interface for dns.RR()

Where is this interface defined?

The various Pack/Unpack methods are available for this.

Neo-Desktop commented 6 years ago

Where is this interface defined?

https://github.com/miekg/dns/blob/master/dns.go#L28 I'm referencing the generic RR interface which indeed does implement a pack() function Unfortunately, this doesn't do any good when storing data as a JSON object i.e. calling json.Marshal() or json.Unmarshal() on a dns.RR{}

I would like to store records as JSON due to its ubiquity and nearly every programming language can manipulate it with ease, unlike RFC 3597

miekg commented 6 years ago

[ Quoting notifications@github.com in "Re: [miekg/dns] dns.RR - JSON Unmar..." ]

Where is this interface defined?

https://github.com/miekg/dns/blob/master/dns.go#L28 I'm referencing the generic RR interface which indeed does implement a pack() function Unfortunately, this doesn't do any good when storing data as a JSON object i.e. calling json.Marshal() or json.Unmarshal() on a dns.RR{}

I would like to store records as JSON due to its ubiquity and nearly every programming language can manipulate it with ease, unlike RFC 3597

You're going to have a hard time doing that, because json is not a good fit for DNS data, see https://miek.nl/2017/november/17/switching-to-vodafone-uncovered-a-bug/ for a fun bug.

What do you want to store the binary or some kind of text representation?

Even so this library is not a good place for having json marshal functions.

/Miek

-- Miek Gieben

Neo-Desktop commented 6 years ago

What do you want to store the binary or some kind of text representation? I'm attempting to use JSON as a common interchange format

Clearly, Google is using it already, it's unfortunate that the embedded quotes are being stripped somewhere along the lines.

To clarify: I would like to store the JSON representation of a master zone in something like a redis/mongo/some NoSQL backend.

It would be invaluable to turn the JSON representation of a Resource Record, as defined by the package's dns.RR{} interface, back into the corresponding object type. (probably like switching on Hdr.Rrtype)

Running:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"

    "github.com/coredns/coredns/plugin/file"
)

func main() {

    zone, err := file.Parse(strings.NewReader(ZONEFILE), "neo.yt.", "stdin", 0)
    if err != nil {
        log.Println("Error encountered during Parse")
        log.Fatal(err)
    }

    output, err := json.Marshal(zone.All())
    if err != nil {
        log.Println("Error encountered during Marshal")
        log.Fatal(err)
    }

    fmt.Println(string(output))
}

const ZONEFILE = `
; neo.yt Dumped Mon Mar 19 04:23:10 2018
;
neo.yt. 86400   IN  SOA ns1.he.net. hostmaster.he.net. (
                    2018022702  ;serial
                    10800       ;refresh
                    1800        ;retry
                    604800      ;expire
                    86400   )   ;minimum
neo.yt. 300 IN  A   104.168.144.17
neo.yt. 300 IN  AAAA    2001:470:8269::1
`

already correctly yields

[{
    "Hdr": {
        "Name": "neo.yt.",
        "Rrtype": 6,
        "Class": 1,
        "Ttl": 86400,
        "Rdlength": 0
    },
    "Ns": "ns1.he.net.",
    "Mbox": "hostmaster.he.net.",
    "Serial": 2018022702,
    "Refresh": 10800,
    "Retry": 1800,
    "Expire": 604800,
    "Minttl": 86400
}, {
    "Hdr": {
        "Name": "neo.yt.",
        "Rrtype": 1,
        "Class": 1,
        "Ttl": 300,
        "Rdlength": 0
    },
    "A": "104.168.144.17"
}, {
    "Hdr": {
        "Name": "neo.yt.",
        "Rrtype": 28,
        "Class": 1,
        "Ttl": 300,
        "Rdlength": 0
    },
    "AAAA": "2001:470:8269::1"
}]

Turning the marshaled JSON representation as displayed above back into the dns.SOA and dns.A, etc... records respectively are what I'm asking to have implemented.

To clarify again, this "zone format" is really just a snapshot of the Go structures in use. Working directly with the underlying structures is the path of least resistance and will provide the greatest accuracy for anyone importing a zone via JSON for use with this library

miekg commented 6 years ago

[ Quoting notifications@github.com in "Re: [miekg/dns] dns.RR - JSON Unmar..." ]

What do you want to store the binary or some kind of text representation? I'm attempting to use JSON as a common interchange format

Clearly, Google is using it already, it's unfortunate that the embedded quotes are being stripped somewhere along the lines.

To clarify: I would like to store the JSON representation of a master zone in something like a redis/mongo/some NoSQL backend.

It would be invaluable to turn the JSON representation of a Resource Record, as defined by the package's dns.RR{} interface, back into the corresponding object type. (probably like switching on Hdr.Rrtype)

Fair enough, but until the IETF comes out with an RFC describing how things should be encoded in json I'm not going to burn any cycles on it. Are NULL bytes allowed in json?

Neo-Desktop commented 6 years ago

Are NULL bytes allowed in json?

Yes, escaped \u0000 is always allowed, or simply a null object depending on what you're trying to do.

the JSON standard is available here http://www.json.org/

miekg commented 5 years ago

Please see https://tools.ietf.org/html/rfc8427

yan-foto commented 4 months ago

Just to make sure that I get it right:

Even so this library is not a good place for having json marshal functions.

There is not going to be a JSON marshaller built into this library?

  • Fair enough, but until the IETF comes out with an RFC describing how things should be encoded in json I'm not going to burn any cycles on it.
  • Please see https://tools.ietf.org/html/rfc8427

This RFC is still not mature enough (informational?) we need to wait for a proper standard?

llorllale commented 3 weeks ago

We make heavy use of this library and are looking to support RFC8427; having this support baked in would be a tremendous help.

miekg commented 3 weeks ago

coming back to this, why not?

looks most of it can be generated, just like the rest. Depends a bit on how large the actually PR would be. But as RFC 8427 exists.... why not?

paulehoffman commented 3 weeks ago

In response to This RFC is still not mature enough (informational?) we need to wait for a proper standard?, it will never be a standard, for the reasons stated in the RFC itself. There are too many competing choices for a desired syntax for a particular program. The RFC was published so that someone like @miekg could pick and choose which parts they want for marshalling and/or unmarshalling, with no expectation of interoperability with other applications.