GRONG is a DNS (Domain Name System) authoritative name server.It is more a research project than a production-ready program.

GRONG (Gross and ROugh Nameserver written in Go) is a DNS (Domain Name
System) authoritative name server. It is intended as a research
project and is not probably suitable for use on the wild Internet.

MAY NOT BE SUITABLE ON A PRODUCTION SITE. YOU HAVE BEEN WARNED!!!

Disclaimer: I've never been to this city
<http://en.wikipedia.org/wiki/Grong>

GRONG can only be used as an authoritative name server (like, for
instance, nsd), not as a recursive one.

GRONG provides a general DNS engine, the front-end, which receives
packets, parses them and sends a proper response, and several possible
back-ends (named "responders") which generates a response, given the
query. Some are provided with GRONG and you are welcome to write
others.

The official source is <http://github.com/bortzmeyer/grong>

Usage
*****

./grong [-address="[ADDRESS]:PORT"] [-debug=N] [-nodaemon] [-domain="DOMAIN NAME"]

Run with -help to see the defaults (and the other, less common, options)

The -address option takes either a port (in the syntax ":NNN"), in
that case GRONG listens on all IP addresses, or one address (in the
syntax "x.y.z.T:NNN" for IPv4 and "[xxxx:yyyy::zzzz]:NNN" for
IPv6). There is currently no way to listen on some (but not all) of the IP
addresses.

The -domain option takes a domain name, which will be the name of the
zone for which the name server will be authoritative for. Not all
responders use it.

The back-end is choosen at compile-time only (I have no idea about the
support for dynamic linking in Go)

Among the provided responders:
* rude-responder: responds REFUSED to every query
* reflector-responder: responds with the IP address of the client (for TXT 
  requests, in text form, for A or AAAA requests, as binary). -domain indicates 
  the zone name it uses (e.g. whoami.example.net)
* as112: an AS 112 name server (see <http://www.as112.net/>)

For the person who compiles
**************************

You need a working Go <http://golang.org> environment. Today, only the
gc compiler is supported.

To choose a responder (here, foobar-responder):

make clean
ln -sf foobar-responder.go responder.go
make
mv ./server /where/you/want/grong-foobar


For the person who writes a responder
************************************

The interface of the responder is:

It must be in package "responder" and imports package "types". Read
"types.go" first, it contains useful constants (named from the RFC
1035).

The front-end checks that the request is a query and, if so, calls the
responder. The prototype is:

func Respond(query types.DNSquery, config map[string]interface{}) types.DNSresponse 

To see what is available for you in the query, see the description of
type DNSquery. Important: the query name (Qname) is always in
lowercase, to ease comparisons.

In the DNSresponse, RRs (Resource Records) have to be in the wire
format (the front-end does not know the format of the RR, to keep it
generic). For instance, data in TXT RR has to be {length,
value}. There are some utilities functions in types to help you to do
so.

The map named "config" above gives you access to global variables. You
can never be sure what variables are defined so it is careful to test
their existence before using them. Typical variables (read the source
code of server.go to find others) are:
* debug: an integer for the debug level (0 = no debug, 1 = a bit of
  debug, etc). Always set.
* servername: if set, a string identifying this specific name server
  (for instance "cdg1.a.ns.example.net").
* zonename: if set, the name of the zone currently served (for instance 
  "myself.example.net")

Since the map stores various types (the "interface{}", which means the
empty interface, something which is fulfilled by every possible
object), you often have to convert data with the reflect package. For
instance, to get the integer value of debug:
debug, exists := myconfig["debug"]
if exists {
	debugi := reflect.NewValue(debug).(*reflect.IntValue).Get()
}

The responder must also provide a function:

func Init(firstoption int) 

which will be called at server startup and which can be used to
process additional command-line flags (see as112.go for a good
example) or any other stuff.

Implementation notes
********************

One goroutine is run for every DNS request. Makes the code much
simpler and easier to read but may explain the fact that performance
are behind BIND.

TODO
****

Finish the AS112 responder (SOA and NS records)

The ability to listen to more than one address (but not all). Can I
give several -address option to the flag module? If so, it probably
just means firing several udpListeners and several tcpListeners. Since
it interacts with the IPv4/IPv6 listening abilities, we may have to
wait for the solution of
<http://code.google.com/p/go/issues/detail?id=679>.

Debugging of Go runtime performance issues, hit it harder with
queryperf!

Test with gccgo

Implements version.server (and version.bind and hostname.bind ?)

See if we can replace a good part of package "types" by standard
package net/ <http://golang.org/src/pkg/net/dnsmsg.go> It does not
seem easy, the dns* files do not export anything outside of package
net, they are meant for internal use only.

Daemonizing seems very difficult with Go
<http://groups.google.com/group/golang-nuts/browse_thread/thread/2b29d93b90501a4b/95242bfb7ae0549e>
In the mean time, nohup + & + disown seems the only solution. Provide
an example at least for Debian, using start-stop-daemon?

A name server with data, for instance able to serve a zone with a
simple setup, one SOA, a few NS, and one A record for www.$ORIGIN. The
list of zones (all with identical data) and the IP address of the Web
server being taken from a file or on the command-line.

Configuration file. What is idiomatic in Go? .INI ?
<https://github.com/cthom06/go-rproxy> uses JSON.

Continue hardening against rogue packets. See the example
test-scapy.py in the distribution.

Michael Hoisie had a very good suggestion to turn GRONG into a
package. He plans:
1) all the source files should have a common package, like "grong".
there shouldn't be a main package
2) there could be a Responder interface, that looks like:
type Responder interface {
    Respond(query.DNSquery) DNSresponse
}
And all the various responders would implement this.
3) The Makefile would have a format like (except modified for Grong):
http://github.com/hoisie/web.go/blob/master/Makefile
4) Instead of main() method, there would be a method like Run( resp
Responder ) that takes a responder and starts the server

Rewrite a good part of Grong to use Go DNS? https://github.com/miekg/godns

DNSSEC (no, I'm joking)


Author
******

Stéphane Bortzmeyer <[email protected]>


License
*******

This is free software. Free as in free speech, not as in free beer.

See the actual license in LICENSE
Owner
Comments
  • AS112 responder answers for names it is not authoritative for

    AS112 responder answers for names it is not authoritative for

    The regular expression used to determine if a name is part of AS112 is too weak. For it marks 110.in-addr.arpa as part of AS112 while it should not.

    The obvious fix, prependinging a "." to as112Regexp does not work either because the expression trigger a bug in Go's regexp library (http://code.google.com/p/go/issues/detail?id=596).

  • AS112 responder does not preserve owner name case

    AS112 responder does not preserve owner name case

    The AS112 responder downcases the owner names in the RRs it replies with. While this is probably conformant to the DNS standard, it is still not very nice of it.

    ; <<>> DiG 9.5.1-P3 <<>> @localhost HOSTNAME.AS112.NET SOA ; (1 server found) ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42086 ;; flags: qr; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

    ;; QUESTION SECTION: ;HOSTNAME.AS112.NET. IN SOA

    ;; ANSWER SECTION: hostname.as112.net. 3600 IN SOA NOT-CONFIGURED.as112.example.net. UNKNOWN.as112.example.net. 2003030100 3600 600 2592000 15

  • GRONG should be case-insensitive

    GRONG should be case-insensitive

    Requests to hostname.BIND does not work because GRONG does not canonicalize the Qname. Either lowercase everything at the beginning (but preserving the case could be interesting in some case) or use only case-insensitive comparisons, not ==

  • Malformed response when the QNAME is empty (only . )

    Malformed response when the QNAME is empty (only . )

    dig reports:

    ;; Warning: Message parser reports malformed message packet. ;; WARNING: Messages has 27 extra bytes at end

    When the QNAME is the empty label (the root, the single dot)

  • Crash when using queryperf with a strong degree of parallelism

    Crash when using queryperf with a strong degree of parallelism

    queryperf with only one or to client threads work fine but GRONG crashes when the parallelism is higher. So, there is not only a problem with invalid packets but also some form of race condition.

  • Patch for recent Go versions?

    Patch for recent Go versions?

    http://pastebin.com/QdpM46iP

    diff --git a/myflag.go b/myflag.go index d92aa49..29be758 100644 --- a/myflag.go +++ b/myflag.go @@ -153,15 +153,15 @@ func (s *stringValue) Set(val string) bool { func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }

    // -- Float Value -type floatValue float +type floatValue float32

    -func newFloatValue(val float, p _float) *floatValue { +func newFloatValue(val float32, p *float32) *floatValue { *p = val return (_floatValue)(p) }

    func (f *floatValue) Set(s string) bool {

    •   v, err := strconv.Atof(s)
      
    •   v, err := strconv.Atof32(s)
      *f = floatValue(v)
      return err == nil
      

      } @@ -378,14 +378,14 @@ func String(name, value string, usage string) *string {

      // FloatVar defines a float flag with specified name, default value, and usage string. // The argument p points to a float variable in which to store the value of the flag. -func FloatVar(p *float, name string, value float, usage string) { +func FloatVar(p *float32, name string, value float32, usage string) { Var(newFloatValue(value, p), name, usage) }

      // Float defines a float flag with specified name, default value, and usage string. // The return value is the address of a float variable that stores the value of the flag. -func Float(name string, value float, usage string) *float {

    •   p := new(float)
      

      +func Float(name string, value float32, usage string) *float32 {

    •   p := new(float32)
      FloatVar(p, name, value, usage)
      return p
      

      } diff --git a/reflector-responder.go b/reflector-responder.go index 4a3b933..38d947b 100644 --- a/reflector-responder.go +++ b/reflector-responder.go @@ -27,7 +27,7 @@ const includesPort = false // If false, sends only the address for TXT queries. func txtRecord(client net.Addr) []byte { sclient := client.String() if !includesPort {

    •           tcpAddr, _ := net.ResolveTCPAddr(sclient)
      
    •           tcpAddr, _ := net.ResolveTCPAddr("tcp", sclient)
              sclient = tcpAddr.IP.String()
      }
      return types.ToTXT(sclient)
      

      @@ -65,12 +65,12 @@ func Respond(query types.DNSquery, config map[string]interface{}) types.DNSrespo result types.DNSresponse ) result.Ansection = nil

    •   tcpAddr, _ := net.ResolveTCPAddr(query.Client.String())
      
    •   tcpAddr, _ := net.ResolveTCPAddr("tcp", query.Client.String())
      ipaddressV4 := tcpAddr.IP.To4()
      zonei, zoneset := config["zonename"]
      zone := ""
      if zoneset {
      
    •           zone = reflect.NewValue(zonei).(*reflect.StringValue).Get()
      
    •           zone = reflect.ValueOf(zonei).String()
      }
      switch {
      case query.Qclass != types.IN:
      

      diff --git a/server.go b/server.go index 30b9eb4..ded6d42 100644 --- a/server.go +++ b/server.go @@ -35,7 +35,7 @@ var ( )

      func fatal(msg string) {

    •   crisislogger.Logf("%s\n", msg)
      
    •   crisislogger.Printf("%s\n", msg)
      os.Exit(1)
      

      }

    @@ -110,7 +110,7 @@ func serialize(packet types.DNSpacket) []byte { binary.BigEndian.PutUint32(result[last+5:last+9], 0) servernamei, nameexists := globalConfig["servername"] if nameexists {

    •                   servername := reflect.NewValue(servernamei).(*reflect.StringValue).Get()
      
    •                   servername := reflect.ValueOf(servernamei).String()
                      if packet.Nsid {
                              binary.BigEndian.PutUint16(result[last+9:last+11],
                                      uint16(4+len(servername)))
      

      @@ -137,7 +137,7 @@ func readShortInteger(buf *bytes.Buffer) (uint16, bool) { n, error := buf.Read(slice[0:2]) if error != nil || n != 2 { if debug > 2 {

    •                   debuglogger.Logf("Error in Read of an int16: %s (%d bytes read)\n", error, n)
      
    •                   debuglogger.Printf("Error in Read of an int16: %s (%d bytes read)\n", error, n)
              }
              return 0, false
      }
      

      @@ -149,7 +149,7 @@ func readInteger(buf *bytes.Buffer) (uint32, bool) { n, error := buf.Read(slice[0:4]) if error != nil || n != 4 { if debug > 2 {

    •                   debuglogger.Logf("Error in Read of an int32: %s (%d bytes read)\n", error, n)
      
    •                   debuglogger.Printf("Error in Read of an int32: %s (%d bytes read)\n", error, n)
              }
              return 0, false
      }
      

      @@ -219,7 +219,7 @@ func parse(buf *bytes.Buffer) (types.DNSpacket, bool) { return packet, false } else { if debug > 2 {

    •                                   debuglogger.Logf("Error in ReadByte: %s\n", error)
      
    •                                   debuglogger.Printf("Error in ReadByte: %s\n", error)
                              }
                              return packet, false
                      }
      

      @@ -236,7 +236,7 @@ func parse(buf *bytes.Buffer) (types.DNSpacket, bool) { return packet, false } else { if debug > 2 {

    •                                   debuglogger.Logf("Error in Read %d bytes: %s\n", n, error)
      
    •                                   debuglogger.Printf("Error in Read %d bytes: %s\n", n, error)
                              }
                              return packet, false
                      }
      

      @@ -266,14 +266,14 @@ func parse(buf *bytes.Buffer) (types.DNSpacket, bool) { return packet, false } else { if debug > 2 {

    •                                   debuglogger.Logf("Error in ReadByte: %s\n", error)
      
    •                                   debuglogger.Printf("Error in ReadByte: %s\n", error)
                              }
                              return packet, false
                      }
              }
              if labelsize != 0 {
                      if debug > 2 {
      
    •                           debuglogger.Logf("Additional section with non-empty name\n")
      
    •                           debuglogger.Printf("Additional section with non-empty name\n")
                      }
                      return packet, false
              }
      

      @@ -304,7 +304,7 @@ func parse(buf *bytes.Buffer) (types.DNSpacket, bool) { return packet, false } else { if debug > 2 {

    •                                                   debuglogger.Logf("Error in Read %d bytes: %s\n", n, error)
      
    •                                                   debuglogger.Printf("Error in Read %d bytes: %s\n", n, error)
                                              }
                                              return packet, false
                                      }
      

      @@ -328,22 +328,22 @@ func parse(buf *bytes.Buffer) (types.DNSpacket, bool) { over = true } if debug > 3 {

    •                                           debuglogger.Logf("EDNS option code %d\n", optcode)
      
    •                                           debuglogger.Printf("EDNS option code %d\n", optcode)
                                      }
      
                              }
                      }
                      if debug > 2 {
      
    •                           debuglogger.Logf("EDNS0 found, buffer size is %d, extended rcode is %d, ", packet.EdnsBufferSize, extrcode)
      
    •                           debuglogger.Printf("EDNS0 found, buffer size is %d, extended rcode is %d, ", packet.EdnsBufferSize, extrcode)
                              if ednslength > 0 {
      
    •                                   debuglogger.Logf("length of options is %d\n", ednslength)
      
    •                                   debuglogger.Printf("length of options is %d\n", ednslength)
                              } else {
      
    •                                   debuglogger.Logf("no options\n")
      
    •                                   debuglogger.Printf("no options\n")
                              }
                      }
              } else {
                      if debug > 2 {
      
    •                           debuglogger.Logf("Ignore additional section if not EDNS")
      
    •                           debuglogger.Printf("Ignore additional section if not EDNS")
                      }
              }
      }
      

      @@ -359,16 +359,16 @@ func generichandle(buf *bytes.Buffer, remaddr net.Addr) (response types.DNSpacke packet, valid := parse(buf) if !valid { // Invalid packet or client too impatient if debug > 3 {

    •                   debuglogger.Logf("Invalid packet received\n")
      
    •                   debuglogger.Printf("Invalid packet received\n")
              }
              return
      }
      if debug > 2 {
      
    •           debuglogger.Logf("%s\n", packet)
      
    •           debuglogger.Printf("%s\n", packet)
      }
      if packet.Query && packet.Opcode == types.STDQUERY {
              if debug > 2 {
      
    •                   debuglogger.Logf("Replying with ID %d...\n", packet.Id)
      
    •                   debuglogger.Printf("Replying with ID %d...\n", packet.Id)
              }
              noresponse = false
              response.Id = packet.Id
      

      @@ -396,7 +396,7 @@ func generichandle(buf *bytes.Buffer, remaddr net.Addr) (response types.DNSpacke if query.Qclass == types.CH && query.Qtype == types.TXT && (query.Qname == "hostname.bind" || query.Qname == "id.server") && nameexists {

    •                   servername := reflect.NewValue(servernamei).(*reflect.StringValue).Get()
      
    •                   servername := reflect.ValueOf(servernamei).String()
                      desiredresponse.Responsecode = types.NOERROR
                      desiredresponse.Ansection = make([]types.RR, 1)
                      desiredresponse.Ansection[0] = types.RR{
      

      @@ -423,7 +423,7 @@ func generichandle(buf *bytes.Buffer, remaddr net.Addr) (response types.DNSpacke func udphandle(conn *net.UDPConn, remaddr net.Addr, buf *bytes.Buffer) { var response types.DNSpacket if debug > 1 {

    •           debuglogger.Logf("%d bytes packet from %s\n", buf.Len(), remaddr)
      
    •           debuglogger.Printf("%d bytes packet from %s\n", buf.Len(), remaddr)
      }
      response, noresponse := generichandle(buf, remaddr)
      if !noresponse {
      

      @@ -431,7 +431,7 @@ func udphandle(conn *net.UDPConn, remaddr net.Addr, buf *bytes.Buffer) { _, error := conn.WriteTo(binaryresponse, remaddr) if error != nil { if debug > 2 {

    •                           debuglogger.Logf("Error in Write: %s\n", error)
      
    •                           debuglogger.Printf("Error in Write: %s\n", error)
                              return
                      }
              }
      

      @@ -441,13 +441,13 @@ func udphandle(conn *net.UDPConn, remaddr net.Addr, buf *bytes.Buffer) {

      func tcphandle(connection net.Conn) { if debug > 1 {

    •           debuglogger.Logf("TCP connection accepted from %s\n", connection.RemoteAddr())
      
    •           debuglogger.Printf("TCP connection accepted from %s\n", connection.RemoteAddr())
      }
      smallbuf := make([]byte, 2)
      n, error := connection.Read(smallbuf)
      if error != nil {
              if debug > 2 {
      
    •                   debuglogger.Logf("Cannot read message length from TCP connection: %s\n", error)
      
    •                   debuglogger.Printf("Cannot read message length from TCP connection: %s\n", error)
                      return
              }
      }
      

      @@ -456,12 +456,12 @@ func tcphandle(connection net.Conn) { n, error = connection.Read(message) if error != nil { if debug > 2 {

    •                   debuglogger.Logf("Cannot read message from TCP connection with %s: %s\n", connection.RemoteAddr(), error)
      
    •                   debuglogger.Printf("Cannot read message from TCP connection with %s: %s\n", connection.RemoteAddr(), error)
                      return
              }
      }
      if debug > 1 {
      
    •           debuglogger.Logf("%d bytes read from %s\n", n, connection.RemoteAddr())
      
    •           debuglogger.Printf("%d bytes read from %s\n", n, connection.RemoteAddr())
      }
      response, noresponse := generichandle(bytes.NewBuffer(message), connection.RemoteAddr())
      if !noresponse {
      

      @@ -471,14 +471,14 @@ func tcphandle(connection net.Conn) { n, error := connection.Write(shortbuf) if n != 2 || error != nil { if debug > 2 {

    •                           debuglogger.Logf("Error in TCP message length Write: %s\n", error)
      
    •                           debuglogger.Printf("Error in TCP message length Write: %s\n", error)
                              return
                      }
              }
              n, error = connection.Write(binaryresponse)
              if error != nil {
                      if debug > 2 {
      
    •                           debuglogger.Logf("Error in TCP message Write: %s\n", error)
      
    •                           debuglogger.Printf("Error in TCP message Write: %s\n", error)
                              return
                      }
              }
      

      @@ -493,7 +493,7 @@ func tcpListener(address *net.TCPAddr, comm chan bool) { connection, error := listener.Accept() if error != nil { if debug > 1 {

    •                           debuglogger.Logf("Cannot accept TCP connection: %s\n", error)
      
    •                           debuglogger.Printf("Cannot accept TCP connection: %s\n", error)
                              continue
                      }
              }
      

      @@ -512,7 +512,7 @@ func udpListener(address *net.UDPAddr, comm chan bool) { n, remaddr, error := listener.ReadFrom(message) if error != nil { if debug > 1 {

    •                           debuglogger.Logf("Cannot read UDP from %s: %s\n", remaddr.String(), error)
      
    •                           debuglogger.Printf("Cannot read UDP from %s: %s\n", remaddr.String(), error)
                              continue
                      }
              }
      

      @@ -554,10 +554,10 @@ func main() { debug = _debugptr globalConfig["debug"] = *debugptr globalConfig["daemon"] = !_nodaemonptr

    •   daemon = !reflect.NewValue(_nodaemonptr).(_reflect.BoolValue).Get()
      
    •   udpaddr, error := net.ResolveUDPAddr(*listen)
      
    •   daemon = !reflect.ValueOf(*nodaemonptr).Bool()
      
    •   udpaddr, error := net.ResolveUDPAddr("udp", *listen)
      checkError(fmt.Sprintf("Cannot parse \"%s\": %s\n", *listen), error)
      
    •   tcpaddr, error := net.ResolveTCPAddr(*listen)
      
    •   tcpaddr, error := net.ResolveTCPAddr("tcp", *listen)
      checkError(fmt.Sprintf("Cannot parse \"%s\": %s\n", *listen), error)
      if daemon {
              debuglogger = syslog.NewLogger(syslog.LOG_DEBUG,
      

      @@ -567,15 +567,15 @@ func main() { crisislogger = syslog.NewLogger(syslog.LOG_CRIT, loggerOptions) } else {

    •           debuglogger = log.New(os.Stderr, nil, "[DEBUG] ",
      
    •           debuglogger = log.New(os.Stderr, "[DEBUG] ",
                      loggerOptions)
      
    •           infologger = log.New(os.Stderr, nil, "[INFO] ",
      
    •           infologger = log.New(os.Stderr, "[INFO] ",
                      loggerOptions)
      
    •           crisislogger = log.New(os.Stderr, nil, "[FATAL] ",
      
    •           crisislogger = log.New(os.Stderr, "[FATAL] ",
                      loggerOptions)
      }
      responder.Init(flag.LastOption())
      
    •   infologger.Logf("%s", fmt.Sprintf("Starting%s%s...", namemsg, zonemsg))
      
    •   infologger.Printf("%s", fmt.Sprintf("Starting%s%s...", namemsg, zonemsg))
      udpchan := make(chan bool)
      go udpListener(udpaddr, udpchan)
      tcpchan := make(chan bool)
      

      @@ -584,5 +584,5 @@ func main() { <-udpchan // Just to wait the listener, otherwise, the Go runtime ends // even if there are live goroutines <-tcpchan

    •   infologger.Logf("%s", "Terminating...")
      
    •   infologger.Printf("%s", "Terminating...")
      

      } diff --git a/types.go b/types.go index ddca35e..79d99fd 100644 --- a/types.go +++ b/types.go @@ -10,7 +10,6 @@ import ( "net" "strings" "fmt"

    •   "bytes"
      "encoding/binary"
      

      )

    @@ -145,7 +144,7 @@ func Encode(name string) []byte { ) labels := make([]string, 0) if name != "." { // The root is a special case. See issue #4

    •           labels = strings.Split(name, ".", -1)
      
    •           labels = strings.SplitN(name, ".", -1)
      }
      totallength := 0
      totalresult = make([]byte, 256) // TODO what a waste
      
      @@ -177,18 +176,18 @@ func EncodeSOA(soa SOArecord) []byte { length = length + (5 * 4) // Five 32-bits counter at the end /* "It's probably cleaner to write to a bytes.Buffer than to repeatedly call bytes.Add." Russ Cox, go-nuts ML */
    •   result = bytes.Add(result, mname)
      
    •   result = bytes.Add(result, rname)
      
    •   result = append(result, mname...)
      
    •   result = append(result, rname...)
      temp32 = make([]byte, 4)
      binary.BigEndian.PutUint32(temp32, soa.Serial)
      
    •   result = bytes.Add(result, temp32)
      
    •   result = append(result, temp32...)
      binary.BigEndian.PutUint32(temp32, soa.Refresh)
      
    •   result = bytes.Add(result, temp32)
      
    •   result = append(result, temp32...)
      binary.BigEndian.PutUint32(temp32, soa.Retry)
      
    •   result = bytes.Add(result, temp32)
      
    •   result = append(result, temp32...)
      binary.BigEndian.PutUint32(temp32, soa.Expire)
      
    •   result = bytes.Add(result, temp32)
      
    •   result = append(result, temp32...)
      binary.BigEndian.PutUint32(temp32, soa.Minimum)
      
    •   result = bytes.Add(result, temp32)
      
    •   result = append(result, temp32...)
      return result[0:length]
      
      }
Related tags
cert-manager webhook & CoreDNS plugin for solving DNS01 challenge on self-hosted authoritative DNS server.
cert-manager webhook & CoreDNS plugin for solving DNS01 challenge on self-hosted authoritative DNS server.

cert-manager webhook & CoreDNS plugin This repo exists for a niche case scenario in which we are running cert-manager on one or multiple Kubernetes cl

Feb 4, 2022
DNS server using miekg/dns offering dynamic subdomains, time-over-dns, and standard zone file support.

dns-go DNS server using miekg/dns offering dynamic subdomains, time-over-dns, and standard zone file support. dynamic subdomains web.myapp.192.168.1.1

Dec 14, 2021
A minimalist-configuration reverse DNS name server

autoreverse autoreverse is a specialized authoritative DNS server whose goal is to make it as easy as possible to auto-answer reverse queries without

Feb 14, 2022
Finally a simple, modern and open source interface for domain name.

happyDNS Finally a simple, modern and open source interface for domain name. It consists of a HTTP REST API written in Golang (primarily based on http

May 24, 2022
A smol DNS server (<100 loc) that's configured with a static JSON file. Useful for split-dns.

A smol DNS server (<100 loc) that's configured with a static JSON file. Useful for split-dns.

Jul 27, 2022
Are you forwarding DNS traffic to another server for some reason, but want to make sure only queries for certain names are passed? Say no more.

DNSFWD Redirect DNS traffic to an upstream. Get Latest: wget https://github.com/C-Sto/dnsfwd/releases/latest/download/dnsfwd_linux (replace linux with

Dec 16, 2022
A DNS client in Go that supports Google DNS over HTTPS

dingo A DNS client (stub resolver) implemented in Go for the Google DNS-over-HTTPS. It effectively encrypts all your DNS traffic. It also supports Ope

Nov 9, 2022
dnscrypt-proxy 2 - A flexible DNS proxy, with support for encrypted DNS protocols.
dnscrypt-proxy 2 - A flexible DNS proxy, with support for encrypted DNS protocols.

Overview A flexible DNS proxy, with support for modern encrypted DNS protocols such as DNSCrypt v2, DNS-over-HTTPS and Anonymized DNSCrypt. dnscrypt-p

Jan 3, 2023
CUP - Cloudflare (DNS) Updater Program

CUP The Cloudflare (DNS) Updater CUP is a tool to turn CloudFlare DNS into a Dynamic DNS service. Documentation Documentation can be found in the docs

Jun 6, 2022
DNS server with per-client targeted responses

GeoDNS servers This is the DNS server powering the NTP Pool system and other similar services. Questions or suggestions? For bug reports or feature re

Dec 15, 2022
CoreDNS is a DNS server that chains plugins
CoreDNS is a DNS server that chains plugins

CoreDNS is a DNS server/forwarder, written in Go, that chains plugins. Each plugin performs a (DNS) function. CoreDNS is a Cloud Native Computing Foun

Jan 3, 2023
Free and open source, powerful network-wide ads & trackers blocking DNS server
Free and open source, powerful network-wide ads & trackers blocking DNS server

Privacy protection center for you and your devices Free and open source, powerful network-wide ads & trackers blocking DNS server. AdGuard.com | Wiki

Nov 20, 2021
DNS Server

运行: nohup ./server serve -c ../conf/confile 2<&1 & 使用: 修改dns-client的dns服务器地址为dns-server的ip即可 部署目录结构描述: . ├── bin │   ├── nohup.out │   └── server //二进

Dec 2, 2021
DNS server with Redis-cache

GoNS DNS server for home usage. Can resolve by global DNS (external dns) and internal by searching in private_domains list. Also, GoNS can use redis-c

Dec 28, 2021
Simple application written in Go that combines two wordlists and a list of TLDs to form domain names and check if they are already registered.

Domainerator Domainerator was my first Go application. It combines two wordlists (prefixes and suffixes) and a list of TLDs to form domain names and c

Sep 16, 2022
DNS library in Go

Alternative (more granular) approach to a DNS library Less is more. Complete and usable DNS library. All Resource Records are supported, including the

Dec 26, 2022
DNS over HTTPS [mirror]

dnss dnss is a daemon for using DNS over HTTPS. It can act as a proxy, receiving DNS requests and resolving them using DNS-over-HTTPs (DoH). This can

Dec 26, 2022
Multicast DNS library for Go

Introduction This package allows Go processes to publish multicast DNS style records onto their local network segment. For more information about mDNS

Oct 23, 2022
Resolver (DNS) cache daemon.
Resolver (DNS) cache daemon.

RESCACHED(1) Manual Page NAME rescached - DNS resolver cache daemon. Table of Contents SYNOPSIS OPTIONS DESCRIPTION FEATURES BEHIND THE DNS HOW CACHE

Nov 17, 2022